diff options
Diffstat (limited to 'cc3200/mods/pybsleep.c')
-rw-r--r-- | cc3200/mods/pybsleep.c | 1076 |
1 files changed, 360 insertions, 716 deletions
diff --git a/cc3200/mods/pybsleep.c b/cc3200/mods/pybsleep.c index 8e94100a91..833c5882f1 100644 --- a/cc3200/mods/pybsleep.c +++ b/cc3200/mods/pybsleep.c @@ -30,13 +30,41 @@ #include "py/mpstate.h" #include MICROPY_HAL_H -#include "hw_types.h" +#include "py/runtime.h" +#include "inc/hw_types.h" +#include "inc/hw_ints.h" +#include "inc/hw_nvic.h" +#include "inc/hw_common_reg.h" +#include "inc/hw_memmap.h" +#include "cc3200_asm.h" +#include "rom_map.h" +#include "interrupt.h" +#include "systick.h" +#include "prcm.h" +#include "spi.h" +#include "pin.h" #include "pybsleep.h" - -/* Storage memory for Cortex M4 registers. To make implementation independent of - CPU, register specific constructs must be made part of platform services. -*/ - +#include "pybpin.h" +#include "simplelink.h" +#include "modwlan.h" +#include "osi.h" +#include "debug.h" +#include "mpexception.h" +#include "mpcallback.h" +#include "mperror.h" +#include "sleeprestore.h" + +/****************************************************************************** + DECLARE PRIVATE CONSTANTS + ******************************************************************************/ +#define SPIFLASH_INSTR_READ_STATUS (0x05) +#define SPIFLASH_INSTR_DEEP_POWER_DOWN (0xB9) +#define SPIFLASH_STATUS_BUSY (0x01) + +/****************************************************************************** + DECLARE PRIVATE TYPES + ******************************************************************************/ +// storage memory for Cortex M4 registers typedef struct { uint32_t msp; uint32_t psp; @@ -45,189 +73,132 @@ typedef struct { uint32_t faultmask; uint32_t basepri; uint32_t control; -}arm_cm4_core_regs; - -//static arm_cm4_core_regs vault_arm_registers; - - -#define BACK_UP_ARM_REGISTERS() { \ - __asm(" push {r0-r12, LR} \n" \ - " ldr r1, pxVaultRegistersSave \n" \ - " mrs r0, msp \n" \ - " str r0, [r1] \n" \ - " mrs r0, psp \n" \ - " str r0, [r1, #4] \n" \ - " mrs r0, primask \n" \ - " str r0, [r1, #12] \n" \ - " mrs r0, faultmask \n" \ - " str r0, [r1, #16] \n" \ - " mrs r0, basepri \n" \ - " str r0, [r1, #20] \n" \ - " mrs r0, control \n" \ - " str r0, [r1, #24] \n" \ - "pxVaultRegistersSave: .word vault_arm_registers \n"); \ -} +} arm_cm4_core_regs_t; -#define RESTORE_ARM_REGISTERS() { \ - __asm(" ldr r1, pxVaultRegistersLoad \n" \ - " ldr r0, [r1, #24] \n" \ - " msr control, r0 \n" \ - " ldr r0, [r1] \n" \ - " msr msp, r0 \n" \ - " ldr r0, [r1,#4] \n" \ - " msr psp, r0 \n" \ - " ldr r0, [r1, #12] \n" \ - " msr primask, r0 \n" \ - " ldr r0, [r1, #16] \n" \ - " msr faultmask, r0 \n" \ - " ldr r0, [r1, #20] \n" \ - " msr basepri, r0 \n" \ - " pop {r0-r12, LR} \n" \ - "pxVaultRegistersLoad: .word vault_arm_registers \n"); \ -} +// storage memory for the NVIC registers +typedef struct { + uint32_t vector_table; // Vector Table Offset + uint32_t aux_ctrl; // Auxiliary control register + uint32_t int_ctrl_state; // Interrupt Control and State + uint32_t app_int; // Application Interrupt Reset control + uint32_t sys_ctrl; // System control + uint32_t config_ctrl; // Configuration control + uint32_t sys_pri_1; // System Handler Priority 1 + uint32_t sys_pri_2; // System Handler Priority 2 + uint32_t sys_pri_3; // System Handler Priority 3 + uint32_t sys_hcrs; // System Handler control and state register + uint32_t systick_ctrl; // SysTick Control Status + uint32_t systick_reload; // SysTick Reload + uint32_t systick_calib; // SysTick Calibration + uint32_t int_en[6]; // Interrupt set enable + uint32_t int_priority[49]; // Interrupt priority +} nvic_reg_store_t; -#if 0 -/* Called directly by boot ROM after waking from S3 state */ -void resume_from_S3(void) -{ - /* Jump from ROM context hence introduce the sync barriers */ - INTRODUCE_SYNC_BARRIER(); /* Data and instruction sync barriers */ +typedef struct { + mp_obj_base_t base; + mp_obj_t obj; + WakeUpCB_t wakeup; +} pybsleep_obj_t; - RESTORE_ARM_REGISTERS(); /* Core registers and code is in assembly */ +typedef struct { + mp_obj_t wlan_wake_cb; + mp_obj_t timer_wake_cb; + mp_obj_t gpio_wake_cb; +} pybsleep_wake_cb_t; + +/****************************************************************************** + DECLARE PRIVATE DATA + ******************************************************************************/ +STATIC const mp_obj_type_t pybsleep_type; +STATIC nvic_reg_store_t *nvic_reg_store; +STATIC pybsleep_wake_cb_t pybsleep_wake_cb; +volatile arm_cm4_core_regs_t vault_arm_registers; + +/****************************************************************************** + DECLARE PRIVATE FUNCTIONS + ******************************************************************************/ +STATIC pybsleep_obj_t *pybsleep_find (mp_obj_t obj); +STATIC void pybsleep_flash_powerdown (void); +STATIC NORETURN void pybsleep_suspend_enter (void); +void pybsleep_suspend_exit (void); +STATIC void pybsleep_obj_wakeup (void); +STATIC void PRCMInterruptHandler (void); +STATIC void pybsleep_iopark (void); + +/****************************************************************************** + DEFINE PUBLIC FUNCTIONS + ******************************************************************************/ +void pyblsleep_init0 (void) { + // initialize the sleep objects list + mp_obj_list_init(&MP_STATE_PORT(pybsleep_obj_list), 0); - INTRODUCE_SYNC_BARRIER(); /* Data and instruction sync barriers */ + // allocate memory for nvic registers vault + ASSERT ((nvic_reg_store = mem_Malloc(sizeof(nvic_reg_store_t))) != NULL); - pform->pm_ops->restore_soc_data(); - make_modules_to_M0_no_irq(pform->used_list_len); /* Wake up all */ - pform->pm_ops->handle_S3_wakeup(); /* Should be last statement */ - return; + // enable and register the PRCM interrupt + osi_InterruptRegister(INT_PRCM, (P_OSI_INTR_ENTRY)PRCMInterruptHandler, INT_PRIORITY_LVL_1); + MAP_IntPendClear(INT_PRCM); + MAP_PRCMIntEnable(PRCM_INT_SLOW_CLK_CTR); } -static void enter_into_S3(void) -{ - pform->pm_ops->back_up_soc_data(); - - INTRODUCE_SYNC_BARRIER(); /* Data and instruction sync barriers */ - - BACK_UP_ARM_REGISTERS(); /* Core registers and code is in assembly */ - - cc_enter_S3(resume_from_S3, vault_arm_registers.psp/*save_restore[1]*/); - - /* Introducing delays to facilitate CPU to fade away ........ */ - asm(" NOP"); asm(" NOP"); asm(" NOP"); asm(" NOP"); asm(" NOP"); - asm(" NOP"); asm(" NOP"); asm(" NOP"); asm(" NOP"); asm(" NOP"); - asm(" NOP"); asm(" NOP"); asm(" NOP"); asm(" NOP"); asm(" NOP"); +void pybsleep_add (const mp_obj_t obj, WakeUpCB_t wakeup) { + pybsleep_obj_t * sleep_obj = m_new_obj(pybsleep_obj_t); + sleep_obj->base.type = &pybsleep_type; + sleep_obj->obj = obj; + sleep_obj->wakeup = wakeup; + // only add objects once + if (!pybsleep_find(sleep_obj)) { + mp_obj_list_append(&MP_STATE_PORT(pybsleep_obj_list), sleep_obj); + } } -static void apply_io_park(u8 pin_num, - enum io_park_state park_value) -{ - u32 pin_strength, pin_type; - - if(DONT_CARE != park_value) { - /* Change the pin mode to GPIO to be safe */ - //MAP_PinModeSet(pin_num, PIN_MODE_0); - - /* First apply PullUp/PullDn (or no pull) according - to the default levels specified in the user supplied - parking table */ - MAP_PinConfigGet(pin_num, &pin_strength, &pin_type); - - if(NO_PULL_HIZ != park_value) { - MAP_PinConfigSet(pin_num, pin_strength, park_value); - } else { - MAP_PinConfigSet(pin_num, pin_strength, PIN_TYPE_STD); - } - - /* One by one HiZ all the IOs, - by writing the register that drives IOEN_N control - pin of the IOs. This register and the signal path is - always-on and hence not get lost during True-LPDS */ - MAP_PinDirModeSet(pin_num, PIN_DIR_MODE_IN); - - /* Once all the digital IOs has been made HiZ, - the desired default PAD levels would be held by - the weak-pulls. Input buffers would be alive - (such as auto-SPI or wake-GPIOs) and would not - have Iddq issue since pulls are present. */ - } - return; +void pybsleep_remove (const mp_obj_t obj) { + pybsleep_obj_t *sleep_obj; + if ((sleep_obj = pybsleep_find(obj))) { + mp_obj_list_remove(&MP_STATE_PORT(pybsleep_obj_list), sleep_obj); + } } -i32 cc_io_park_safe(struct soc_io_park *io_park_choice, - u8 num_pins) -{ - i32 loopcnt; - - if(NULL == io_park_choice) { - return -1; - } +void pybsleep_set_wlan_wake_callback (mp_obj_t cb_obj) { + if (cb_obj) { + MAP_PRCMLPDSWakeupSourceEnable (PRCM_LPDS_HOST_IRQ); + } + else { + MAP_PRCMLPDSWakeupSourceDisable (PRCM_LPDS_HOST_IRQ); + } + pybsleep_wake_cb.wlan_wake_cb = cb_obj; +} - /* Park the IOs safely as specified by the application */ - for(loopcnt = 0; loopcnt < num_pins; loopcnt++) { - switch(io_park_choice[loopcnt].pin_num) { - /* Shared SPI pins for SFLASH */ - case PIN_11: - case PIN_12: - case PIN_13: - case PIN_14: -#ifdef DEBUG_MODE - /* JTAG pins */ - case PIN_16: - case PIN_17: - case PIN_19: - case PIN_20: -#endif - /* Do not park these pins as they may - have external dependencies */ - break; - default: - /* Apply the specified IO parking scheme */ - apply_io_park(io_park_choice[loopcnt].pin_num, - io_park_choice[loopcnt].park_val); +void pybsleep_set_gpio_wake_callback (mp_obj_t cb_obj) { + pybsleep_wake_cb.gpio_wake_cb = cb_obj; +} - } +void pybsleep_set_timer_wake_callback (mp_obj_t cb_obj) { + pybsleep_wake_cb.timer_wake_cb = cb_obj; +} +/****************************************************************************** + DEFINE PRIVATE FUNCTIONS + ******************************************************************************/ +STATIC pybsleep_obj_t *pybsleep_find (mp_obj_t obj) { + for (mp_uint_t i = 0; i < MP_STATE_PORT(pybsleep_obj_list).len; i++) { + // search for the object and then remove it + pybsleep_obj_t *sleep_obj = ((pybsleep_obj_t *)(MP_STATE_PORT(pybsleep_obj_list).items[i])); + if (sleep_obj->obj == obj) { + return sleep_obj; } - - /* parking the SFLASH IOs */ - HWREG(0x4402E0E8) &= ~(0x3 << 8); - HWREG(0x4402E0E8) |= (0x2 << 8); - HWREG(0x4402E0EC) &= ~(0x3 << 8); - HWREG(0x4402E0EC) |= (0x2 << 8); - HWREG(0x4402E0F0) &= ~(0x3 << 8); - HWREG(0x4402E0F0) |= (0x2 << 8); - HWREG(0x4402E0F4) &= ~(0x3 << 8); - HWREG(0x4402E0F4) |= (0x1 << 8); - - return 0; + } + return NULL; } - - -#define INSTR_READ_STATUS 0x05 -#define INSTR_DEEP_POWER_DOWN 0xB9 -#define STATUS_BUSY 0x01 -//**************************************************************************** -// -//! Put SPI flash into Deep Power Down mode -//! -//! Note:SPI flash is a shared resource between MCU and Network processing -//! units. This routine should only be exercised after all the network -//! processing has been stopped. To stop network processing use sl_stop API -//! \param None -//! -//! \return Status, 0:Pass, -1:Fail -// -//**************************************************************************** -void SpiFlashDeepPowerDown(void) { +STATIC void pybsleep_flash_powerdown (void) { uint32_t status; // Enable clock for SSPI module - MAP_PRCMPeripheralClkEnable(PRCM_SSPI, PRCM_RUN_MODE_CLK); + MAP_PRCMPeripheralClkEnable(PRCM_SSPI, PRCM_RUN_MODE_CLK | PRCM_SLP_MODE_CLK); // Reset SSPI at PRCM level and wait for reset to complete MAP_PRCMPeripheralReset(PRCM_SSPI); - while(!MAP_PRCMPeripheralStatusGet(PRCM_SSPI); + while(!MAP_PRCMPeripheralStatusGet(PRCM_SSPI)); // Reset SSPI at module level MAP_SPIReset(SSPI_BASE); @@ -247,599 +218,272 @@ void SpiFlashDeepPowerDown(void) { // Wait for the spi flash do { // Send the status register read instruction and read back a dummy byte. - MAP_SPIDataPut(SSPI_BASE, INSTR_READ_STATUS); + MAP_SPIDataPut(SSPI_BASE, SPIFLASH_INSTR_READ_STATUS); MAP_SPIDataGet(SSPI_BASE, &status); // Write a dummy byte then read back the actual status. MAP_SPIDataPut(SSPI_BASE, 0xFF); MAP_SPIDataGet(SSPI_BASE, &status); - } while ((status & 0xFF) == STATUS_BUSY); + } while ((status & 0xFF) == SPIFLASH_STATUS_BUSY); // Disable chip select for the spi flash. MAP_SPICSDisable(SSPI_BASE); // Start another CS enable sequence for Power down command. MAP_SPICSEnable(SSPI_BASE); // Send Deep Power Down command to spi flash - MAP_SPIDataPut(SSPI_BASE, INSTR_DEEP_POWER_DOWN); + MAP_SPIDataPut(SSPI_BASE, SPIFLASH_INSTR_DEEP_POWER_DOWN); // Disable chip select for the spi flash. MAP_SPICSDisable(SSPI_BASE); } +STATIC NORETURN void pybsleep_suspend_enter (void) { + // enable full RAM retention + MAP_PRCMSRAMRetentionEnable(PRCM_SRAM_COL_1 | PRCM_SRAM_COL_2 | PRCM_SRAM_COL_3 | PRCM_SRAM_COL_4, PRCM_SRAM_LPDS_RET); + + // save the NVIC control registers + nvic_reg_store->vector_table = HWREG(NVIC_VTABLE); + nvic_reg_store->aux_ctrl = HWREG(NVIC_ACTLR); + nvic_reg_store->int_ctrl_state = HWREG(NVIC_INT_CTRL); + nvic_reg_store->app_int = HWREG(NVIC_APINT); + nvic_reg_store->sys_ctrl = HWREG(NVIC_SYS_CTRL); + nvic_reg_store->config_ctrl = HWREG(NVIC_CFG_CTRL); + nvic_reg_store->sys_pri_1 = HWREG(NVIC_SYS_PRI1); + nvic_reg_store->sys_pri_2 = HWREG(NVIC_SYS_PRI2); + nvic_reg_store->sys_pri_3 = HWREG(NVIC_SYS_PRI3); + nvic_reg_store->sys_hcrs = HWREG(NVIC_SYS_HND_CTRL); + + // save the systick registers + nvic_reg_store->systick_ctrl = HWREG(NVIC_ST_CTRL); + nvic_reg_store->systick_reload = HWREG(NVIC_ST_RELOAD); + nvic_reg_store->systick_calib = HWREG(NVIC_ST_CAL); + + // save the interrupt enable registers + uint32_t *base_reg_addr = (uint32_t *)NVIC_EN0; + for(int32_t i = 0; i < (sizeof(nvic_reg_store->int_en) / 4); i++) { + nvic_reg_store->int_en[i] = base_reg_addr[i]; + } -#define DBG_PRINT Report -#define NUM_NVIC_PEND_REG 6 -#define ERR_TIMER_TO_WAKE (-2) -#define MAX_GPIO_WAKESOURCE 6 - -struct { - u32 vector_table; // Vector Table Offset - u32 aux_ctrl; // Auxiliary control register - u32 int_ctrl_state; // Interrupt Control and State - u32 app_int; // Application Interrupt Reset control - u32 sys_ctrl; // System control - u32 config_ctrl; // Configuration control - u32 sys_pri_1; // System Handler Priority 1 - u32 sys_pri_2; // System Handler Priority 2 - u32 sys_pri_3; // System Handler Priority 3 - u32 sys_hcrs; // System Handler control and state register - u32 systick_ctrl; // SysTick Control Status - u32 systick_reload; // SysTick Reload - u32 systick_calib; // SysTick Calibration - u32 int_en[6]; // Interrupt set enable - u32 int_priority[49]; // Interrupt priority -} nvic_reg_store; - -u8 gpio_wake_src[] = {2, 4, 13, 17, 11, 24}; -u8 gpio_lpds_inttype[] = {1, 1, 2, 0xFF, 3, 0xFF, 0}; -u8 gpio_hib_inttype[] = {2, 2, 0, 0xFF, 3, 0xFF, 1}; - -u32 nvic_int_mask[] = {NVIC_PEND0_MASK, NVIC_PEND1_MASK, NVIC_PEND2_MASK, - NVIC_PEND3_MASK, NVIC_PEND4_MASK, NVIC_PEND5_MASK}; - -volatile i32 debug = 0; - - -/* Network (Host IRQ) based wakeup from S3(LPDS) */ -static i32 setup_S3_wakeup_from_nw() -{ -#define IS_NWPIC_INTR_SET() (HWREG(NVIC_EN5) & (1 << ((INT_NWPIC - 16) & 31))) - - /* Check if the NWP->APPs interrupt is enabled */ - if(IS_NWPIC_INTR_SET()) { - /* Set LPDS Wakeup source as NWP request */ - MAP_PRCMLPDSWakeupSourceEnable(PRCM_LPDS_HOST_IRQ); - return 0; - } else { - return -1; - } -} - - - -/* GPIO based wakeup from S3(LPDS) */ -static i32 check_n_setup_S3_wakeup_from_gpio() -{ - i32 retval, indx; - u8 gpio_num[MAX_GPIO_WAKESOURCE]; - u8 int_type[MAX_GPIO_WAKESOURCE]; - - /* Check for any special purpose GPIO usage */ - retval = cc_gpio_get_spl_purpose(&gpio_num[0], - &int_type[0], - MAX_GPIO_WAKESOURCE); - - if(retval > 0) { - for(indx = 0; indx < sizeof(gpio_wake_src); indx++) { - if(gpio_wake_src[indx] == gpio_num[0]) { - /* Setup the GPIO to be the wake source */ - MAP_PRCMLPDSWakeUpGPIOSelect( - indx, gpio_lpds_inttype[int_type[0]]); - MAP_PRCMLPDSWakeupSourceEnable(PRCM_LPDS_GPIO); - /* Save the GPIO number wake from LPDS */ - cc_pm_ctrl.spl_gpio_wakefrom_lpds = gpio_num[0]; - break; - } - } - } else { - return -1; - } + // save the interrupt priority registers + base_reg_addr = (uint32_t *)NVIC_PRI0; + for(int32_t i = 0; i < (sizeof(nvic_reg_store->int_priority) / 4); i++) { + nvic_reg_store->int_priority[i] = base_reg_addr[i]; + } - return 0; -} + // park the io pins + pybsleep_iopark(); + + sleep_store(); + + // save the restore info and enter LPDS + MAP_PRCMLPDSRestoreInfoSet(vault_arm_registers.psp, (uint32_t)sleep_restore); + MAP_PRCMLPDSEnter(); + + // let the cpu fade away... + for ( ; ; ); +} + +void pybsleep_suspend_exit (void) { + // take the I2C semaphore + uint32_t reg = HWREG(COMMON_REG_BASE + COMMON_REG_O_I2C_Properties_Register); + reg = (reg & ~0x3) | 0x1; + HWREG(COMMON_REG_BASE + COMMON_REG_O_I2C_Properties_Register) = reg; + + // take the GPIO semaphore + reg = HWREG(COMMON_REG_BASE + COMMON_REG_O_GPIO_properties_register); + reg = (reg & ~0x3FF) | 0x155; + HWREG(COMMON_REG_BASE + COMMON_REG_O_GPIO_properties_register) = reg; + + // restore de NVIC control registers + HWREG(NVIC_VTABLE) = nvic_reg_store->vector_table; + HWREG(NVIC_ACTLR) = nvic_reg_store->aux_ctrl; + HWREG(NVIC_INT_CTRL) = nvic_reg_store->int_ctrl_state; + HWREG(NVIC_APINT) = nvic_reg_store->app_int; + HWREG(NVIC_SYS_CTRL) = nvic_reg_store->sys_ctrl; + HWREG(NVIC_CFG_CTRL) = nvic_reg_store->config_ctrl; + HWREG(NVIC_SYS_PRI1) = nvic_reg_store->sys_pri_1; + HWREG(NVIC_SYS_PRI2) = nvic_reg_store->sys_pri_2; + HWREG(NVIC_SYS_PRI3) = nvic_reg_store->sys_pri_3; + HWREG(NVIC_SYS_HND_CTRL) = nvic_reg_store->sys_hcrs; + + // restore the systick register + HWREG(NVIC_ST_CTRL) = nvic_reg_store->systick_ctrl; + HWREG(NVIC_ST_RELOAD) = nvic_reg_store->systick_reload; + HWREG(NVIC_ST_CAL) = nvic_reg_store->systick_calib; + + // restore the interrupt priority registers + uint32_t *base_reg_addr = (uint32_t *)NVIC_PRI0; + for (uint32_t i = 0; i < (sizeof(nvic_reg_store->int_priority) / 4); i++) { + base_reg_addr[i] = nvic_reg_store->int_priority[i]; + } -/* Timer based wakeup from S3 (LPDS) */ -static i32 check_n_setup_S3_wakeup_from_timer() -{ - u64 scc_match, scc_curr, scc_remaining; - - /* Check if there is an alarm set */ - if(cc_rtc_has_alarm()) { - /* Get the time remaining for the RTC timer to expire */ - scc_match = MAP_PRCMSlowClkCtrMatchGet(); - scc_curr = MAP_PRCMSlowClkCtrGet(); - - if(scc_match > scc_curr) { - /* Get the time remaining in terms of slow clocks */ - scc_remaining = (scc_match - scc_curr); - if(scc_remaining > WAKEUP_TIME_LPDS) { - /* Subtract the time it takes for wakeup - from S3 (LPDS) */ - scc_remaining -= WAKEUP_TIME_LPDS; - scc_remaining = (scc_remaining > 0xFFFFFFFF)? - 0xFFFFFFFF: scc_remaining; - /* Setup the LPDS wake time */ - MAP_PRCMLPDSIntervalSet( - (u32)scc_remaining); - /* Enable the wake source to be timer */ - MAP_PRCMLPDSWakeupSourceEnable( - PRCM_LPDS_TIMER); - } else { - /* Cannot enter LPDS */ - return ERR_TIMER_TO_WAKE; - } - } else { - return ERR_TIMER_TO_WAKE; - } - } else { - /* Disable timer as the wake source */ - MAP_PRCMLPDSWakeupSourceDisable(PRCM_LPDS_TIMER); - return -1; - } + // restore the interrupt enable registers + base_reg_addr = (uint32_t *)NVIC_EN0; + for(uint32_t i = 0; i < (sizeof(nvic_reg_store->int_en) / 4); i++) { + base_reg_addr[i] = nvic_reg_store->int_en[i]; + } - return 0; -} + HAL_INTRODUCE_SYNC_BARRIER(); -/* Setup the HIBernate wakr source as apecified GPIO */ -static void setup_hib_gpio_wake(u32 gpio_num, - u32 gpio_wake_type) -{ - MAP_PRCMHibernateWakeUpGPIOSelect(gpio_num, gpio_wake_type); - MAP_PRCMHibernateWakeupSourceEnable(gpio_num); + // ungate the clock to the shared spi bus + MAP_PRCMPeripheralClkEnable(PRCM_SSPI, PRCM_RUN_MODE_CLK | PRCM_SLP_MODE_CLK); + MAP_PRCMIntEnable (PRCM_INT_SLOW_CLK_CTR); - return; -} + // reinitialize simplelink's bus + sl_IfOpen (NULL, 0); -/* GPIO based wakeup from S4 (HIB) */ -static i32 check_n_setup_S4_wakeup_from_gpio() -{ - i32 retval, indx; - u8 gpio_num[MAX_GPIO_WAKESOURCE]; - u8 int_type[MAX_GPIO_WAKESOURCE]; - - /* Check for any special purpose GPIO usage */ - retval = cc_gpio_get_spl_purpose(&gpio_num[0], - &int_type[0], - MAX_GPIO_WAKESOURCE); - - if(retval > 0) { - for(indx = 0; indx < retval; indx++) { - switch(gpio_num[indx]) { - case 2: - setup_hib_gpio_wake(PRCM_HIB_GPIO2, - gpio_hib_inttype[int_type[indx]]); - break; - case 4: - setup_hib_gpio_wake(PRCM_HIB_GPIO4, - gpio_hib_inttype[int_type[indx]]); - break; - case 13: - setup_hib_gpio_wake(PRCM_HIB_GPIO13, - gpio_hib_inttype[int_type[indx]]); - break; - case 17: - setup_hib_gpio_wake(PRCM_HIB_GPIO17, - gpio_hib_inttype[int_type[indx]]); - - break; - case 11: - setup_hib_gpio_wake(PRCM_HIB_GPIO11, - gpio_hib_inttype[int_type[indx]]); - break; - case 24: - setup_hib_gpio_wake(PRCM_HIB_GPIO24, - gpio_hib_inttype[int_type[indx]]); - break; - default: - break; - } - } - } else { - return -1; - } + // initialize the system led + mperror_init0(); - return 0; -} + // restore the configuration of all active peripherals + pybsleep_obj_wakeup(); -/* Timer based wakeup from S4 (HIB) */ -static i32 check_n_setup_S4_wakeup_from_timer() -{ - u64 scc_match, scc_curr, scc_remaining; - - /* Check if there is an alarm set */ - if(cc_rtc_has_alarm()) { - /* Get the time remaining for the RTC timer to expire */ - scc_match = MAP_PRCMSlowClkCtrMatchGet(); - scc_curr = MAP_PRCMSlowClkCtrGet(); - - if(scc_match > scc_curr) { - /* Get the time remaining in terms of slow clocks */ - scc_remaining = (scc_match - scc_curr); - if(scc_remaining > WAKEUP_TIME_HIB) { - /* Subtract the time it takes for wakeup - from S4 (HIB) */ - scc_remaining -= WAKEUP_TIME_HIB; - /* Setup the HIB wake time */ - MAP_PRCMHibernateIntervalSet(scc_remaining); - /* Enable the wake source to be RTC */ - MAP_PRCMHibernateWakeupSourceEnable( - PRCM_HIB_SLOW_CLK_CTR); - } else { - /* Cannot enter HIB */ - return ERR_TIMER_TO_WAKE; - } - } else { - return -1; - } - } else { - /* Disable Timer as wake source */ - MAP_PRCMHibernateWakeupSourceDisable(PRCM_HIB_SLOW_CLK_CTR); - return -1; - } + // trigger a sw interrupt + MAP_IntPendSet(INT_PRCM); - return 0; + // force an exception to go back to the point where suspend mode was entered + nlr_raise(mp_obj_new_exception(&mp_type_SystemExit)); } -/* Sets up wake-up sources for indicated power mode */ -i32 cc_set_up_wkup_srcs(enum soc_pm target) -{ - i32 nw_ret = -1, gpio_ret = -1, timer_ret = -1; - switch(target) { - case e_pm_S0: - case e_pm_S1: - case e_pm_S2: - /* These handle the cases of run, sleep, deepsleep. - Wake source is configured outside this scope in - individual peripherals */ - break; - case e_pm_S3: - /* Low power deep sleep condition */ - /* Network (Host IRQ) based wakeup is always enabled */ - nw_ret = setup_S3_wakeup_from_nw(); - /* Check and enable GPIO based wakeup */ - gpio_ret = check_n_setup_S3_wakeup_from_gpio(); - /* Check and enable LRT based wakeup */ - timer_ret = check_n_setup_S3_wakeup_from_timer(); - break; - case e_pm_S4: - /* Hibernate condition */ - /* Check and enable GPIO based wakeup */ - gpio_ret = check_n_setup_S4_wakeup_from_gpio(); - /* Check and enable LRT based wakeup */ - timer_ret = check_n_setup_S4_wakeup_from_timer(); - break; - default: - break; - } - - if(ERR_TIMER_TO_WAKE == timer_ret) { - return -1; +STATIC void PRCMInterruptHandler (void) { + // reading the interrupt status automatically clears the interrupt + if (PRCM_INT_SLOW_CLK_CTR == MAP_PRCMIntStatus()) { + if (pybsleep_wake_cb.timer_wake_cb) { + mpcallback_handler(pybsleep_wake_cb.timer_wake_cb); } - if((nw_ret < 0) && (gpio_ret < 0) && (timer_ret < 0)) { - return -1; - } - else if((gpio_ret < 0) && (timer_ret < 0)) { - /* Setup the LPDS wake time */ - MAP_PRCMLPDSIntervalSet(LPDS_WDOG_TIME); - /* Enable the wake source to be timer */ - MAP_PRCMLPDSWakeupSourceEnable( - PRCM_LPDS_TIMER); - } - return 0; -} - -/* LPDS wake SW interrupt handler */ -void wake_interrupt_handler() -{ - i32 wake_source; - - /* Identify the wakeup source */ - wake_source = MAP_PRCMLPDSWakeupCauseGet(); - - switch(wake_source) { + } + else { + switch (MAP_PRCMLPDSWakeupCauseGet()) { case PRCM_LPDS_HOST_IRQ: - break; + if (pybsleep_wake_cb.wlan_wake_cb) { + mpcallback_handler(pybsleep_wake_cb.wlan_wake_cb); + } + break; case PRCM_LPDS_GPIO: - /* Invoke the callback with the last GPIO num - used to enter LPDS (S3) */ - gpio_wake_interrupt_handler( - &cc_pm_ctrl.spl_gpio_wakefrom_lpds); - break; + if (pybsleep_wake_cb.gpio_wake_cb) { + mpcallback_handler(pybsleep_wake_cb.gpio_wake_cb); + } + break; case PRCM_LPDS_TIMER: - break; - } - - return; -} - -/* Process events that have woken up system from S3 (LPDS) */ -i32 cc_handle_S3_wakeup() -{ - /* Trigger the SW interrupt */ - MAP_IntPendSet(INT_PRCM); - return 0; -} - -/* Are there interrupts pending in system? TRUE -> yes else no */ -bool cc_are_irqs_pending(void) -{ - i32 indx = 0; - u32 *base_reg_addr; - - /* Check if there are any interrupts pending */ - base_reg_addr = (u32 *)NVIC_PEND0; - for(indx = 0; indx < NUM_NVIC_PEND_REG; indx++) { - if(base_reg_addr[indx] & nvic_int_mask[indx]) { - return true; - } + if (pybsleep_wake_cb.timer_wake_cb) { + mpcallback_handler(pybsleep_wake_cb.timer_wake_cb); + } + break; + default: + break; } - - return false; -} - -/* Must push system to low power state of S4 (Hibernate) */ -i32 cc_enter_S4(void) -{ - /* Invoke the driverlib API to enter HIBernate */ - MAP_PRCMHibernateEnter(); - - return 0; -} - -/* Must push system to low power state of S3 (LPDS) */ -i32 cc_enter_S3(void(*resume_fn)(void), u32 stack_ptr) -{ - MAP_PRCMLPDSRestoreInfoSet(stack_ptr, (u32)resume_fn); - - /* Enter LPDS */ - MAP_PRCMLPDSEnter(); - return 0; -} - -/* Must push system to low power state of S2 (Deepsleep) */ -i32 cc_enter_S2(void) -{ - /* Enter deepsleep */ - //MAP_PRCMDeepSleepEnter(); - - return 0; -} -volatile i32 sleep_count = 0; -/* Must push system to low power state of S1 */ -i32 cc_enter_S1(void) -{ - //MAP_PRCMSleepEnter(); - return 0; -} - -/* Save the NVIC registers */ -void back_up_nvic_regs() -{ - i32 indx = 0; - u32 *base_reg_addr; - /* Save the NVIC control registers */ - nvic_reg_store.vector_table = HWREG(NVIC_VTABLE); - nvic_reg_store.aux_ctrl = HWREG(NVIC_ACTLR); - nvic_reg_store.int_ctrl_state = HWREG(NVIC_INT_CTRL); - nvic_reg_store.app_int = HWREG(NVIC_APINT); - nvic_reg_store.sys_ctrl = HWREG(NVIC_SYS_CTRL); - nvic_reg_store.config_ctrl = HWREG(NVIC_CFG_CTRL); - nvic_reg_store.sys_pri_1 = HWREG(NVIC_SYS_PRI1); - nvic_reg_store.sys_pri_2 = HWREG(NVIC_SYS_PRI2); - nvic_reg_store.sys_pri_3 = HWREG(NVIC_SYS_PRI3); - nvic_reg_store.sys_hcrs = HWREG(NVIC_SYS_HND_CTRL); - - /* Systick registers */ - nvic_reg_store.systick_ctrl = HWREG(NVIC_ST_CTRL); - nvic_reg_store.systick_reload = HWREG(NVIC_ST_RELOAD); - nvic_reg_store.systick_calib = HWREG(NVIC_ST_CAL); - - /* Save the interrupt enable registers */ - base_reg_addr = (u32 *)NVIC_EN0; - for(indx = 0; indx < (sizeof(nvic_reg_store.int_en) / 4); indx++) { - nvic_reg_store.int_en[indx] = base_reg_addr[indx]; - } - - /* Save the interrupt priority registers */ - base_reg_addr = (u32 *)NVIC_PRI0; - for(indx = 0; indx < (sizeof(nvic_reg_store.int_priority) / 4); indx++) { - nvic_reg_store.int_priority[indx] = base_reg_addr[indx]; - } - - return; -} - -/* Reestore the NVIC registers */ -void restore_nvic_regs() -{ - i32 indx = 0; - u32 *base_reg_addr; - - /* Restore the NVIC control registers */ - HWREG(NVIC_VTABLE) = nvic_reg_store.vector_table; - HWREG(NVIC_ACTLR) = nvic_reg_store.aux_ctrl; - HWREG(NVIC_APINT) = nvic_reg_store.app_int; - HWREG(NVIC_SYS_CTRL) = nvic_reg_store.sys_ctrl; - HWREG(NVIC_CFG_CTRL) = nvic_reg_store.config_ctrl; - HWREG(NVIC_SYS_PRI1) = nvic_reg_store.sys_pri_1; - HWREG(NVIC_SYS_PRI2) = nvic_reg_store.sys_pri_2; - HWREG(NVIC_SYS_PRI3) = nvic_reg_store.sys_pri_3; - HWREG(NVIC_SYS_HND_CTRL) = nvic_reg_store.sys_hcrs; - - /* Systick registers */ - HWREG(NVIC_ST_CTRL) = nvic_reg_store.systick_ctrl; - HWREG(NVIC_ST_RELOAD) = nvic_reg_store.systick_reload; - HWREG(NVIC_ST_CAL) = nvic_reg_store.systick_calib; - - /* Restore the interrupt priority registers */ - base_reg_addr = (u32 *)NVIC_PRI0; - for(indx = 0; indx < (sizeof(nvic_reg_store.int_priority) / 4); indx++) { - base_reg_addr[indx] = nvic_reg_store.int_priority[indx]; - } - - /* Restore the interrupt enable registers */ - base_reg_addr = (u32 *)NVIC_EN0; - for(indx = 0; indx < (sizeof(nvic_reg_store.int_en) / 4); indx++) { - base_reg_addr[indx] = nvic_reg_store.int_en[indx]; - } - - INTRODUCE_SYNC_BARRIER(); /* Data and instruction sync barriers */ - - return; -} - -/* S3 (LPDS): Back-up system regs & data */ -void cc_back_up_soc_data(void) { - /* Enable the RAM retention */ - MAP_PRCMSRAMRetentionEnable(PRCM_SRAM_COL_1 | PRCM_SRAM_COL_2 | PRCM_SRAM_COL_3 | PRCM_SRAM_COL_4, PRCM_SRAM_LPDS_RET); - /* Store the NVIC registers */ - back_up_nvic_regs(); - - // Park all IO pins - - // Park antenna selection pins - HWREG(0x4402E108) = 0x00000E61; - HWREG(0x4402E10C) = 0x00000E61; - - INTRODUCE_SYNC_BARRIER(); /* Data and instruction sync barriers */ - - BACK_UP_ARM_REGISTERS(); /* Core registers and code is in assembly */ - - return; -} - -/* S3 (LPDS): Restore system regs & data */ -void cc_restore_soc_data(void) -{ - uint32_t reg; - /* Check if any of the registers/data need to be restored */ - /* Take I2C semaphore */ - reg = HWREG(COMMON_REG_BASE + COMMON_REG_O_I2C_Properties_Register); - reg = (reg & ~0x3) | 0x1; - HWREG(COMMON_REG_BASE + COMMON_REG_O_I2C_Properties_Register) = reg; - - /* Take GPIO semaphore */ - reg = HWREG(COMMON_REG_BASE + COMMON_REG_O_GPIO_properties_register); - reg = (reg & ~0x3FF) | 0x155; - HWREG(COMMON_REG_BASE + COMMON_REG_O_GPIO_properties_register) = reg; - - /* Restore the NVIC registers */ - restore_nvic_regs(); - - /* ungates the clk for the shared SPI*/ - MAP_PRCMPeripheralClkEnable(PRCM_SSPI, PRCM_RUN_MODE_CLK | PRCM_SLP_MODE_CLK); - MAP_PRCMIntEnable (PRCM_INT_SLOW_CLK_CTR); - - return; + } } - -void prcm_interrupt_handler(void *intr_param) -{ - int status; - - /* Read the interrupt status, also clears the status */ - status = MAP_PRCMIntStatus(); - - if((PRCM_INT_SLOW_CLK_CTR == status) || (sw_simulate_rtc)) { - sw_simulate_rtc = 0; - /* Invoke the RTC interrupt handler */ - cc_rtc_isr(); - } else if(0 == status) { - /* Invoke the wake from LPDS interrupt handler */ - wake_interrupt_handler(); - } else { - } +STATIC void pybsleep_obj_wakeup (void) { + for (mp_uint_t i = 0; i < MP_STATE_PORT(pybsleep_obj_list).len; i++) { + pybsleep_obj_t *sleep_obj = ((pybsleep_obj_t *)MP_STATE_PORT(pybsleep_obj_list).items[i]); + sleep_obj->wakeup(sleep_obj->obj); + } } -/* LPDS wake SW interrupt handler */ -void wake_interrupt_handler() -{ - i32 wake_source; - - /* Identify the wakeup source */ - wake_source = MAP_PRCMLPDSWakeupCauseGet(); - - switch(wake_source) { - case PRCM_LPDS_HOST_IRQ: - break; - case PRCM_LPDS_GPIO: - /* Invoke the callback with the last GPIO num - used to enter LPDS (S3) */ - gpio_wake_interrupt_handler( - &cc_pm_ctrl.spl_gpio_wakefrom_lpds); - break; - case PRCM_LPDS_TIMER: - break; +STATIC void pybsleep_iopark (void) { + mp_map_t *named_map = mp_obj_dict_get_map((mp_obj_t)&pin_cpu_pins_locals_dict); + for (uint i = 0; i < named_map->used; i++) { + pin_obj_t * pin = (pin_obj_t *)named_map->table[i].value; + // skip the sflash pins since these are shared with the network processor + switch (pin->pin_num) { + case PIN_11: + case PIN_12: + case PIN_13: + case PIN_14: +#ifdef DEBUG + // also skip the JTAG pins + case PIN_16: + case PIN_17: + case PIN_19: + case PIN_20: +#endif + break; + default: + if (!pin->used) { + // enable the pull-down in unused pins + MAP_PinConfigSet(pin->pin_num, pin->strength, PIN_TYPE_STD_PD); + } + // make the pin an input + MAP_PinDirModeSet(pin->pin_num, PIN_DIR_MODE_IN); + break; } + } - return; -} - -/* Invoked in interrupt context */ -void cc_rtc_isr(void) { - struct u64_time alarm, value; - u32 status; - - /* Read the interrupt status, also clears the status */ - status = MAP_PRCMIntStatus(); + // park the sflash pins + HWREG(0x4402E0E8) &= ~(0x3 << 8); + HWREG(0x4402E0E8) |= (0x2 << 8); + HWREG(0x4402E0EC) &= ~(0x3 << 8); + HWREG(0x4402E0EC) |= (0x2 << 8); + HWREG(0x4402E0F0) &= ~(0x3 << 8); + HWREG(0x4402E0F0) |= (0x2 << 8); + HWREG(0x4402E0F4) &= ~(0x3 << 8); + HWREG(0x4402E0F4) |= (0x1 << 8); + + // park the antenna selection pins + HWREG(0x4402E108) = 0x00000E61; + HWREG(0x4402E10C) = 0x00000E61; +} + +/******************************************************************************/ +// Micro Python bindings; Sleep class + +/// \function idle() +/// Gates the processor clock until an interrupt is triggered +STATIC mp_obj_t pyb_sleep_idle (mp_obj_t self_in) { + __WFI(); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_sleep_idle_obj, pyb_sleep_idle); + +/// \function suspend() +/// Enters suspended mode. Wake up sources should have been enable prior to +// calling this method. +STATIC mp_obj_t pyb_sleep_suspend (mp_obj_t self_in) { + nlr_buf_t nlr; + + // entering and exiting suspend mode must be an atomic operation + // therefore interrupts must be disabled + uint primsk = disable_irq(); + if (nlr_push(&nlr) == 0) { + pybsleep_suspend_enter(); + nlr_pop(); + } + // an exception is always raised when exiting suspend mode + enable_irq(primsk); - // call the python RTC callback interrupt handler + return mp_const_none; } -#endif - - -typedef struct { - mp_obj_t obj; - WakeUpCB_t wakeup; -}pybsleep_obj_t; +STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_sleep_suspend_obj, pyb_sleep_suspend); - -STATIC pybsleep_obj_t * pybsleep_find (mp_obj_t obj) { - for (mp_uint_t i = 0; i < MP_STATE_PORT(pybsleep_obj_list).len; i++) { - // search for the object and then remove it - pybsleep_obj_t *sleep_obj = ((pybsleep_obj_t *)MP_STATE_PORT(pybsleep_obj_list).items[i]); - if (sleep_obj->obj == obj) { - return sleep_obj; - } - } - return NULL; +/// \function hibernate() +/// Enters hibernate mode. Wake up sources should have been enable prior to +// calling this method. +STATIC mp_obj_t pyb_sleep_hibernate (mp_obj_t self_in) { + wlan_stop(); + pybsleep_flash_powerdown(); + MAP_PRCMHibernateEnter(); + return mp_const_none; } +STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_sleep_hibernate_obj, pyb_sleep_hibernate); -void pyblsleep_init0 (void) { - mp_obj_list_init(&MP_STATE_PORT(pybsleep_obj_list), 0); -} +STATIC const mp_map_elem_t pybsleep_locals_dict_table[] = { + // instance methods + { MP_OBJ_NEW_QSTR(MP_QSTR_idle), (mp_obj_t)&pyb_sleep_idle_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_suspend), (mp_obj_t)&pyb_sleep_suspend_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_hibernate), (mp_obj_t)&pyb_sleep_hibernate_obj }, -void pybsleep_add (mp_obj_t obj, WakeUpCB_t wakeup) { - pybsleep_obj_t * sleep_obj = m_new_obj(pybsleep_obj_t); - sleep_obj->obj = obj; - sleep_obj->wakeup = wakeup; - // only add objects once - if (!pybsleep_find(sleep_obj)) { - mp_obj_list_append(&MP_STATE_PORT(pybsleep_obj_list), sleep_obj); - } -} + // class constants + { MP_OBJ_NEW_QSTR(MP_QSTR_SUSPENDED), MP_OBJ_NEW_SMALL_INT(PYB_PWR_MODE_LPDS) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_HIBERNATING), MP_OBJ_NEW_SMALL_INT(PYB_PWR_MODE_HIBERNATE) }, +}; -void pybsleep_remove (mp_obj_t obj) { - pybsleep_obj_t *sleep_obj; - if ((sleep_obj = pybsleep_find(obj))) { - mp_obj_list_remove(&MP_STATE_PORT(pybsleep_obj_list), sleep_obj); - } -} +STATIC MP_DEFINE_CONST_DICT(pybsleep_locals_dict, pybsleep_locals_dict_table); -void pybsleep_wakeup (void) { - for (mp_uint_t i = 0; i < MP_STATE_PORT(pybsleep_obj_list).len; i++) { - pybsleep_obj_t *sleep_obj = ((pybsleep_obj_t *)MP_STATE_PORT(pybsleep_obj_list).items[i]); - sleep_obj->wakeup(sleep_obj->obj); - } -} +STATIC const mp_obj_type_t pybsleep_type = { + { &mp_type_type }, + .name = MP_QSTR_sleep, + .locals_dict = (mp_obj_t)&pybsleep_locals_dict, +}; +const mp_obj_base_t pyb_sleep_obj = {&pybsleep_type}; |