/* * 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 CC32xx ******************************************************************************/ /* Board includes */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "ti/devices/cc32xx/driverlib/rom.h" #include "ti/devices/cc32xx/driverlib/rom_map.h" #include #include #include #include /* 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) #define SPI_RATE_30M (30000000) 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; /* Check NWP generation */ if((HWREG(GPRCM_BASE + GPRCM_O_GPRCM_DIEID_READ_REG4) >> 24) & 0x02) { SPI_Config.bitRate = SPI_RATE_30M; } else { 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); } #if defined(SL_PLATFORM_MULTI_THREADED) int Semaphore_pend_handle(sem_t* pSemHandle, uint32_t timeout) { if (OS_WAIT_FOREVER == timeout) { return sem_wait(pSemHandle); } else { struct timespec abstime; abstime.tv_nsec = 0; abstime.tv_sec = 0; /* Since POSIX timeout are relative and not absolute, * take the current timestamp. */ clock_gettime(CLOCK_REALTIME, &abstime); if(abstime.tv_nsec < 0) { abstime.tv_sec = timeout; return (sem_timedwait(pSemHandle, &abstime)); } /* Add the amount of time to wait */ abstime.tv_sec += timeout / 1000; abstime.tv_nsec += (timeout % 1000) * 1000000; abstime.tv_sec += (abstime.tv_nsec / 1000000000); abstime.tv_nsec = abstime.tv_nsec % 1000000000; /* Call the semaphore wait API */ return(sem_timedwait(pSemHandle, &abstime)); } } int Mutex_create_handle(pthread_mutex_t *pMutexHandle) { pthread_mutexattr_t attr; pthread_mutexattr_init(&attr); pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); if (pthread_mutex_init(pMutexHandle, &attr) < 0) { return Mutex_FAILURE ; } return Mutex_OK; } #else int Mutex_create_handle(MutexP_Handle* pMutexHandle) { MutexP_Params params; MutexP_Params_init(¶ms); params.callback = tiDriverSpawnCallback; (*(pMutexHandle)) = MutexP_create(¶ms); if(!(*(pMutexHandle))) { return Mutex_FAILURE ; } return Mutex_OK; } int MutexP_delete_handle(MutexP_Handle* pMutexHandle) { MutexP_delete(*(pMutexHandle)); return(Mutex_OK); } int Mutex_unlock(MutexP_Handle pMutexHandle) { MutexP_unlock(pMutexHandle, 0); return(Mutex_OK); } int Mutex_lock(MutexP_Handle pMutexHandle) { MutexP_lock(pMutexHandle); return(Mutex_OK); } int SemaphoreP_create_handle(SemaphoreP_Handle* pSemHandle) { SemaphoreP_Params params; SemaphoreP_Params_init(¶ms); params.mode = SemaphoreP_Mode_BINARY; params.callback = tiDriverSpawnCallback; (*(pSemHandle)) = SemaphoreP_create(1, ¶ms); if(!(*(pSemHandle))) { return Semaphore_FAILURE ; } return Semaphore_OK; } int SemaphoreP_delete_handle(SemaphoreP_Handle* pSemHandle) { SemaphoreP_delete(*(pSemHandle)); return Semaphore_OK; } int SemaphoreP_post_handle(SemaphoreP_Handle* pSemHandle) { SemaphoreP_post(*(pSemHandle)); return Semaphore_OK; } #endif 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 ; }