| /* |
| * cc_pal.c - CC32xx Host Driver Implementation |
| * |
| * Copyright (C) 2017 Texas Instruments Incorporated - http://www.ti.com/ |
| * |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions |
| * are met: |
| * |
| * Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * |
| * Redistributions in binary form must reproduce the above copyright |
| * notice, this list of conditions and the following disclaimer in the |
| * documentation and/or other materials provided with the |
| * distribution. |
| * |
| * Neither the name of Texas Instruments Incorporated nor the names of |
| * its contributors may be used to endorse or promote products derived |
| * from this software without specific prior written permission. |
| * |
| * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
| * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
| * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| * |
| */ |
| /****************************************************************************** |
| * cc_pal.c |
| * |
| * SimpleLink Wi-Fi abstraction file for CC3220 |
| ******************************************************************************/ |
| |
| /* Board includes */ |
| #include <ti/drivers/net/wifi/simplelink.h> |
| #include <ti/drivers/net/wifi/porting/cc_pal.h> |
| #include <ti/drivers/dpl/HwiP.h> |
| #include <ti/drivers/SPI.h> |
| |
| #include <ti/devices/cc32xx/inc/hw_ints.h> |
| #include <ti/devices/cc32xx/inc/hw_udma.h> |
| #include <ti/devices/cc32xx/inc/hw_types.h> |
| #include <ti/devices/cc32xx/inc/hw_memmap.h> |
| #include <ti/devices/cc32xx/inc/hw_mcspi.h> |
| #include <ti/devices/cc32xx/inc/hw_common_reg.h> |
| #include <ti/devices/cc32xx/inc/hw_ocp_shared.h> |
| #include <ti/devices/cc32xx/inc/hw_apps_rcm.h> |
| #include <ti/devices/cc32xx/inc/hw_gprcm.h> |
| #include <ti/devices/cc32xx/inc/hw_hib1p2.h> |
| #include "ti/devices/cc32xx/driverlib/rom.h" |
| #include "ti/devices/cc32xx/driverlib/rom_map.h" |
| #include <ti/devices/cc32xx/driverlib/interrupt.h> |
| #include <ti/devices/cc32xx/driverlib/prcm.h> |
| #include <ti/devices/cc32xx/driverlib/timer.h> |
| #include <ti/drivers/net/wifi/source/driver.h> |
| |
| /* NWP_SPARE_REG_5 - (OCP_SHARED_BASE + OCP_SHARED_O_SPARE_REG_5) |
| - Bits 31:02 - Reserved |
| - Bits 01 - SLSTOP1 - NWP in Reset, Power Domain Down |
| - Bits 00 - Reserved |
| */ |
| #define NWP_SPARE_REG_5 (OCP_SHARED_BASE + OCP_SHARED_O_SPARE_REG_5) |
| #define NWP_SPARE_REG_5_SLSTOP (0x00000002) |
| |
| /* ANA_DCDC_PARAMS0 - (HIB1P2_BASE + HIB1P2_O_ANA_DCDC_PARAMETERS0) |
| - Bits 31:28 - Reserved |
| - Bits 27 - Override PWM mode (==> PFM) |
| - Bits 26:00 - Reserved |
| */ |
| #define ANA_DCDC_PARAMS0 (HIB1P2_BASE + HIB1P2_O_ANA_DCDC_PARAMETERS0) |
| #define ANA_DCDC_PARAMS0_PWMOVERRIDE (0x08000000) |
| |
| /* WAKENWP - (ARCM_BASE + APPS_RCM_O_APPS_TO_NWP_WAKE_REQUEST) |
| - Bits 31:01 - Reserved |
| - Bits 00 - Wake Request to NWP |
| */ |
| #define WAKENWP (ARCM_BASE + APPS_RCM_O_APPS_TO_NWP_WAKE_REQUEST) |
| #define WAKENWP_WAKEREQ (APPS_RCM_APPS_TO_NWP_WAKE_REQUEST_APPS_TO_NWP_WAKEUP_REQUEST) |
| |
| /* NWP_PWR_STATE - (GPRCM_BASE + GPRCM_O_NWP_PWR_STATE) |
| - Bits 31:12 - Reserved |
| - Bits 11:08 - Active (0x3) |
| - Bits 07:00 - Reserved |
| */ |
| #define NWP_PWR_STATE (GPRCM_BASE + GPRCM_O_NWP_PWR_STATE) |
| #define NWP_PWR_STATE_PWRMASK (0x00000F00) |
| #define NWP_PWR_STATE_PWRACTIVE (0x00000300) |
| |
| /* NWP_LPDS_WAKEUPCFG - (GPRCM_BASE + GPRCM_O_NWP_LPDS_WAKEUP_CFG) |
| - Bits 31:08 - Reserved |
| - Bits 07:00 - WakeUp Config AppsToNwp Wake (0x20) - reset condition |
| */ |
| #define NWP_LPDS_WAKEUPCFG (GPRCM_BASE + GPRCM_O_NWP_LPDS_WAKEUP_CFG) |
| #define NWP_LPDS_WAKEUPCFG_APPS2NWP (0x00000020) |
| #define NWP_LPDS_WAKEUPCFG_TIMEOUT_MSEC (600) |
| |
| /* N2A_INT_MASK_SET - (COMMON_REG_BASE + COMMON_REG_O_NW_INT_MASK_SET) */ |
| #define N2A_INT_MASK_SET (COMMON_REG_BASE + COMMON_REG_O_NW_INT_MASK_SET) |
| /* N2A_INT_MASK_CLR - (COMMON_REG_BASE + COMMON_REG_O_NW_INT_MASK_CLR) */ |
| #define N2A_INT_MASK_CLR (COMMON_REG_BASE + COMMON_REG_O_NW_INT_MASK_CLR) |
| /* N2A_INT_ACK - (COMMON_REG_BASE + COMMON_REG_O_NW_INT_ACK) */ |
| #define N2A_INT_ACK (COMMON_REG_BASE + COMMON_REG_O_NW_INT_ACK) |
| #define NWP_N2A_INT_ACK_TIMEOUT_MSEC (3000) |
| |
| /* A2N_INT_STS_CLR - (COMMON_REG_BASE + COMMON_REG_O_APPS_INT_STS_CLR) */ |
| #define A2N_INT_STS_CLR (COMMON_REG_BASE + COMMON_REG_O_APPS_INT_STS_CLR) |
| /* A2N_INT_TRIG - (COMMON_REG_BASE + COMMON_REG_O_APPS_INT_TRIG) */ |
| #define A2N_INT_TRIG (COMMON_REG_BASE + COMMON_REG_O_APPS_INT_TRIG) |
| /* A2N_INT_STS_RAW - (COMMON_REG_BASE + COMMON_REG_O_APPS_INT_STS_RAW) */ |
| #define A2N_INT_STS_RAW (COMMON_REG_BASE + COMMON_REG_O_APPS_INT_STS_RAW) |
| |
| #define uSEC_DELAY(x) (ROM_UtilsDelayDirect(x*80/3)) |
| #define MAX_DMA_RECV_TRANSACTION_SIZE (4096) |
| #define SPI_RATE_20M (20000000) |
| |
| HwiP_Handle g_intHandle = 0; |
| |
| //**************************************************************************** |
| // LOCAL FUNCTIONS |
| //**************************************************************************** |
| |
| Fd_t spi_Open(char *ifName, unsigned long flags) |
| { |
| void *lspi_hndl; |
| unsigned int lspi_index; |
| SPI_Params SPI_Config; |
| SPI_Params_init(&SPI_Config); |
| |
| /* configure the SPI settings */ |
| SPI_Config.transferMode = SPI_MODE_BLOCKING; |
| SPI_Config.mode = SPI_MASTER; |
| SPI_Config.bitRate = SPI_RATE_20M; |
| SPI_Config.dataSize = 32; |
| SPI_Config.frameFormat = SPI_POL0_PHA0; |
| |
| /* index of the link SPI initialization configuration in the SPI_Config table */ |
| lspi_index = 0; |
| lspi_hndl = SPI_open(lspi_index, &SPI_Config); |
| if(NULL == lspi_hndl) |
| { |
| return -1; |
| } |
| else |
| { |
| return (Fd_t)lspi_hndl; |
| } |
| } |
| |
| |
| int spi_Close(Fd_t fd) |
| { |
| SPI_close((void *)fd); |
| return 0; |
| } |
| |
| |
| int spi_Read(Fd_t fd, unsigned char *pBuff, int len) |
| { |
| SPI_Transaction transact_details; |
| int read_size = 0; |
| |
| /* check if the link SPI has been initialized successfully */ |
| if(fd < 0) |
| { |
| return -1; |
| } |
| |
| transact_details.txBuf = NULL; |
| transact_details.arg = NULL; |
| while(len > 0) |
| { |
| /* DMA can transfer upto a maximum of 1024 words in one go. So, if |
| the data to be read is more than 1024 words, it will be done in |
| parts */ |
| /* length is received in bytes, should be specified in words for the |
| * SPI driver. |
| */ |
| if(len > MAX_DMA_RECV_TRANSACTION_SIZE) |
| { |
| transact_details.count = (MAX_DMA_RECV_TRANSACTION_SIZE +3)>>2; |
| transact_details.rxBuf = (void*)(pBuff + read_size); |
| if(SPI_transfer((SPI_Handle)fd, &transact_details)) |
| { |
| read_size += MAX_DMA_RECV_TRANSACTION_SIZE; |
| len = len - MAX_DMA_RECV_TRANSACTION_SIZE; |
| } |
| else |
| { |
| return -1; |
| } |
| |
| } |
| else |
| { |
| transact_details.count = (len+3)>>2; |
| transact_details.rxBuf = (void*)(pBuff + read_size); |
| if(SPI_transfer((SPI_Handle)fd, &transact_details)) |
| { |
| read_size += len; |
| len = 0; |
| return read_size; |
| } |
| else |
| { |
| return -1; |
| } |
| } |
| } |
| |
| return(read_size); |
| } |
| |
| |
| int spi_Write(Fd_t fd, unsigned char *pBuff, int len) |
| { |
| SPI_Transaction transact_details; |
| int write_size = 0; |
| |
| /* check if the link SPI has been initialized successfully */ |
| if(fd < 0) |
| { |
| return -1; |
| } |
| |
| transact_details.rxBuf = NULL; |
| transact_details.arg = NULL; |
| while(len > 0) |
| { |
| /* configure the transaction details. |
| * length is received in bytes, should be specified in words for the SPI |
| * driver. |
| */ |
| if(len > MAX_DMA_RECV_TRANSACTION_SIZE) |
| { |
| transact_details.count = (MAX_DMA_RECV_TRANSACTION_SIZE +3)>>2; |
| transact_details.txBuf = (void*)(pBuff + write_size); |
| if(SPI_transfer((SPI_Handle)fd, &transact_details)) |
| { |
| write_size += MAX_DMA_RECV_TRANSACTION_SIZE; |
| len = len - MAX_DMA_RECV_TRANSACTION_SIZE; |
| } |
| else |
| { |
| return -1; |
| } |
| } |
| else |
| { |
| transact_details.count = (len+3)>>2; |
| transact_details.txBuf = (void*)(pBuff + write_size); |
| if(SPI_transfer((SPI_Handle)fd, &transact_details)) |
| { |
| write_size += len; |
| len = 0; |
| return write_size; |
| } |
| else |
| { |
| return -1; |
| } |
| } |
| } |
| |
| return(write_size); |
| } |
| |
| |
| int NwpRegisterInterruptHandler(P_EVENT_HANDLER InterruptHdl , void* pValue) |
| { |
| |
| HwiP_Params nwp_iParams; |
| |
| HwiP_Params_init(&nwp_iParams); |
| |
| HwiP_clearInterrupt(INT_NWPIC); |
| |
| if(!InterruptHdl) |
| { |
| HwiP_delete(g_intHandle); |
| return OS_OK; |
| } |
| else |
| { |
| nwp_iParams.priority = INT_PRIORITY_LVL_1 ; |
| |
| } |
| g_intHandle = HwiP_create(INT_NWPIC , (HwiP_Fxn)(InterruptHdl) , &nwp_iParams); |
| |
| if(!g_intHandle) |
| { |
| return -1; |
| } |
| else |
| { |
| return OS_OK ; |
| } |
| } |
| |
| |
| void NwpMaskInterrupt() |
| { |
| (*(unsigned long *)N2A_INT_MASK_SET) = 0x1; |
| } |
| |
| |
| void NwpUnMaskInterrupt() |
| { |
| (*(unsigned long *)N2A_INT_MASK_CLR) = 0x1; |
| } |
| |
| |
| void NwpPowerOn(void) |
| { |
| /* bring the 1.32 eco out of reset */ |
| HWREG(NWP_SPARE_REG_5) &= ~NWP_SPARE_REG_5_SLSTOP; |
| |
| /* Clear host IRQ indication */ |
| HWREG(N2A_INT_ACK) = 1; |
| |
| /* NWP Wake-up */ |
| HWREG(WAKENWP) = WAKENWP_WAKEREQ; |
| |
| //UnMask Host Interrupt |
| NwpUnMaskInterrupt(); |
| } |
| |
| |
| void NwpPowerOff(void) |
| { |
| |
| volatile unsigned long apps_int_sts_raw; |
| volatile unsigned long sl_stop_ind = HWREG(NWP_SPARE_REG_5); |
| volatile unsigned long nwp_lpds_wake_cfg = HWREG(NWP_LPDS_WAKEUPCFG); |
| _SlTimeoutParams_t SlTimeoutInfo = {0}; |
| |
| if((nwp_lpds_wake_cfg != NWP_LPDS_WAKEUPCFG_APPS2NWP) && /* Check for NWP POR condition - APPS2NWP is reset condition */ |
| !(sl_stop_ind & NWP_SPARE_REG_5_SLSTOP)) /* Check if sl_stop was executed */ |
| { |
| HWREG(0xE000E104) = 0x200; /* Enable the out of band interrupt, this is not a wake-up source*/ |
| HWREG(A2N_INT_TRIG) = 0x1; /* Trigger out of band interrupt */ |
| HWREG(WAKENWP) = WAKENWP_WAKEREQ; /* Wake-up the NWP */ |
| |
| _SlDrvStartMeasureTimeout(&SlTimeoutInfo, NWP_N2A_INT_ACK_TIMEOUT_MSEC); |
| |
| /* Wait for the A2N_INT_TRIG to be cleared by the NWP to indicate it's awake and ready for shutdown. |
| * poll until APPs->NWP interrupt is cleared or timeout : |
| * for service pack 3.1.99.1 or higher, this condition is fulfilled in less than 1 mSec. |
| * Otherwise, in some cases it may require up to 3000 mSec of waiting. */ |
| |
| apps_int_sts_raw = HWREG(A2N_INT_STS_RAW); |
| while(!(apps_int_sts_raw & 0x1)) |
| { |
| if(_SlDrvIsTimeoutExpired(&SlTimeoutInfo)) |
| { |
| break; |
| } |
| apps_int_sts_raw = HWREG(A2N_INT_STS_RAW); |
| } |
| |
| WAIT_NWP_SHUTDOWN_READY; |
| } |
| |
| /* Clear Out of band interrupt, Acked by the NWP */ |
| HWREG(A2N_INT_STS_CLR) = 0x1; |
| |
| /* Mask Host Interrupt */ |
| NwpMaskInterrupt(); |
| |
| /* Switch to PFM Mode */ |
| HWREG(ANA_DCDC_PARAMS0) &= ~ANA_DCDC_PARAMS0_PWMOVERRIDE; |
| |
| /* sl_stop ECO for PG1.32 devices */ |
| HWREG(NWP_SPARE_REG_5) |= NWP_SPARE_REG_5_SLSTOP; |
| |
| /* Wait for 20 uSec, which is the minimal time between on-off cycle */ |
| uSEC_DELAY(20); |
| } |
| |
| |
| int Semaphore_create_handle(SemaphoreP_Handle* pSemHandle) |
| { |
| SemaphoreP_Params params; |
| |
| SemaphoreP_Params_init(¶ms); |
| |
| params.mode = SemaphoreP_Mode_BINARY; |
| |
| #ifndef SL_PLATFORM_MULTI_THREADED |
| params.callback = tiDriverSpawnCallback; |
| #endif |
| (*(pSemHandle)) = SemaphoreP_create(1, ¶ms); |
| |
| if(!(*(pSemHandle))) |
| { |
| return SemaphoreP_FAILURE ; |
| } |
| |
| return SemaphoreP_OK; |
| } |
| |
| int SemaphoreP_delete_handle(SemaphoreP_Handle* pSemHandle) |
| { |
| SemaphoreP_delete(*(pSemHandle)); |
| return SemaphoreP_OK; |
| } |
| |
| int SemaphoreP_post_handle(SemaphoreP_Handle* pSemHandle) |
| { |
| SemaphoreP_post(*(pSemHandle)); |
| return SemaphoreP_OK; |
| } |
| |
| |
| int Mutex_create_handle(MutexP_Handle* pMutexHandle) |
| { |
| MutexP_Params params; |
| |
| MutexP_Params_init(¶ms); |
| #ifndef SL_PLATFORM_MULTI_THREADED |
| params.callback = tiDriverSpawnCallback; |
| #endif |
| |
| (*(pMutexHandle)) = MutexP_create(¶ms); |
| |
| if(!(*(pMutexHandle))) |
| { |
| return MutexP_FAILURE ; |
| } |
| |
| return MutexP_OK; |
| } |
| |
| int MutexP_delete_handle(MutexP_Handle* pMutexHandle) |
| { |
| MutexP_delete(*(pMutexHandle)); |
| return(MutexP_OK); |
| } |
| |
| int Mutex_unlock(MutexP_Handle pMutexHandle) |
| { |
| MutexP_unlock(pMutexHandle, 0); |
| return(MutexP_OK); |
| } |
| |
| |
| int Mutex_lock(MutexP_Handle pMutexHandle) |
| { |
| MutexP_lock(pMutexHandle); |
| return(MutexP_OK); |
| } |
| |
| |
| unsigned long TimerGetCurrentTimestamp() |
| { |
| return (ClockP_getSystemTicks()); |
| } |
| |
| |
| void NwpWaitForShutDownInd() |
| { |
| volatile unsigned long nwp_wakup_ind = HWREG(NWP_LPDS_WAKEUPCFG); |
| _SlTimeoutParams_t SlTimeoutInfo = {0}; |
| |
| _SlDrvStartMeasureTimeout(&SlTimeoutInfo, NWP_LPDS_WAKEUPCFG_TIMEOUT_MSEC); |
| |
| while(nwp_wakup_ind != NWP_LPDS_WAKEUPCFG_APPS2NWP) |
| { |
| if(_SlDrvIsTimeoutExpired(&SlTimeoutInfo)) |
| { |
| return; |
| } |
| nwp_wakup_ind = HWREG(NWP_LPDS_WAKEUPCFG); |
| } |
| |
| return ; |
| } |