diff --git a/hw/drivers/ipc_cmac/include/ipc_cmac/shm.h b/hw/drivers/ipc_cmac/include/ipc_cmac/shm.h index 376095366f..a438d54f5b 100644 --- a/hw/drivers/ipc_cmac/include/ipc_cmac/shm.h +++ b/hw/drivers/ipc_cmac/include/ipc_cmac/shm.h @@ -38,8 +38,9 @@ extern "C" { #define CMAC_SHM_CB_MAGIC 0xc3ac -#define CMAC_SHM_CB_PENDING_OP_LP_CLK 0x0001 -#define CMAC_SHM_CB_PENDING_OP_RF_CAL 0x0002 +#define CMAC_SHM_CB_PENDING_OP_LPCLK_UPDATE 0x0001 +#define CMAC_SHM_CB_PENDING_OP_WAKEUP_UPDATE 0x0002 +#define CMAC_SHM_CB_PENDING_OP_RF_CAL 0x0004 #define CMAC_SHM_VECT_MAGIC 0xc3ac0001 #define CMAC_SHM_VECT_CRASHINFO 0x00000001 @@ -58,8 +59,8 @@ struct cmac_shm_config { struct cmac_shm_ctrl { uint16_t magic; uint16_t pending_ops; - uint16_t lp_clock_freq; - uint16_t xtal32m_settle_us; + uint16_t lpclk_freq; + uint16_t wakeup_time_us; }; struct cmac_shm_mbox { diff --git a/hw/drivers/ipc_cmac/include/ipc_cmac/shm_hs.h b/hw/drivers/ipc_cmac/include/ipc_cmac/shm_hs.h index 1de158a94d..068a81df07 100644 --- a/hw/drivers/ipc_cmac/include/ipc_cmac/shm_hs.h +++ b/hw/drivers/ipc_cmac/include/ipc_cmac/shm_hs.h @@ -38,6 +38,9 @@ extern volatile struct cmac_shm_debugdata *g_cmac_shm_debugdata; void cmac_host_init(void); void cmac_host_signal2cmac(void); + +void cmac_host_lpclk_update(uint32_t freq); +void cmac_host_wakeup_update(uint32_t wakeup_time_us); void cmac_host_rf_calibrate(void); #ifdef __cplusplus diff --git a/hw/drivers/ipc_cmac/src/shm_hs.c b/hw/drivers/ipc_cmac/src/shm_hs.c index 444de258a5..2d6380d6ef 100644 --- a/hw/drivers/ipc_cmac/src/shm_hs.c +++ b/hw/drivers/ipc_cmac/src/shm_hs.c @@ -199,17 +199,7 @@ cmac_host_rand_chk_fill(void) static void cmac_host_lpclk_cb(uint32_t freq) { - /* No need to wakeup CMAC if LP clock frequency did not change */ - if (g_cmac_shm_ctrl->lp_clock_freq == freq) { - return; - } - - cmac_shm_lock(); - g_cmac_shm_ctrl->lp_clock_freq = freq; - g_cmac_shm_ctrl->pending_ops |= CMAC_SHM_CB_PENDING_OP_LP_CLK; - cmac_shm_unlock(); - - cmac_host_signal2cmac(); + cmac_host_lpclk_update(freq); } static void @@ -234,8 +224,7 @@ shm_configure(void) struct cmac_shm_trim *trim; uint32_t *trim_data; - g_cmac_shm_ctrl->xtal32m_settle_us = - MYNEWT_VAL(MCU_CLOCK_XTAL32M_SETTLE_TIME_US); + g_cmac_shm_ctrl->wakeup_time_us = 0; trim = (struct cmac_shm_trim *)g_cmac_shm_trim; trim_data = trim->data; @@ -444,6 +433,7 @@ cmac_host_init(void) cmac_start(); da1469x_lpclk_register_cmac_cb(cmac_host_lpclk_cb); + cmac_host_wakeup_update(da1469x_sleep_wakeup_time_us_get()); #if MYNEWT_VAL(CMAC_DEBUG_HOST_PRINT_ENABLE) && MYNEWT_VAL(CMAC_DEBUG_DATA_ENABLE) /* Trim values are calculated on RF init, so are valid after synced with CMAC */ @@ -462,6 +452,36 @@ cmac_host_signal2cmac(void) da1469x_pdc_set(g_cmac_host_pdc_sys2cmac); } +void +cmac_host_lpclk_update(uint32_t freq) +{ + if (g_cmac_shm_ctrl->lpclk_freq == freq) { + return; + } + + cmac_shm_lock(); + g_cmac_shm_ctrl->lpclk_freq = freq; + g_cmac_shm_ctrl->pending_ops |= CMAC_SHM_CB_PENDING_OP_LPCLK_UPDATE; + cmac_shm_unlock(); + + cmac_host_signal2cmac(); +} + +void +cmac_host_wakeup_update(uint32_t wakeup_time_us) +{ + if (g_cmac_shm_ctrl->wakeup_time_us == wakeup_time_us) { + return; + } + + cmac_shm_lock(); + g_cmac_shm_ctrl->wakeup_time_us = wakeup_time_us; + g_cmac_shm_ctrl->pending_ops |= CMAC_SHM_CB_PENDING_OP_WAKEUP_UPDATE; + cmac_shm_unlock(); + + cmac_host_signal2cmac(); +} + void cmac_host_rf_calibrate(void) { diff --git a/hw/mcu/dialog/cmac/include/mcu/cmac_timer.h b/hw/mcu/dialog/cmac/include/mcu/cmac_timer.h index 0c12647336..88e27b0cd6 100644 --- a/hw/mcu/dialog/cmac/include/mcu/cmac_timer.h +++ b/hw/mcu/dialog/cmac/include/mcu/cmac_timer.h @@ -35,7 +35,8 @@ extern struct cmac_timer_ctrl g_cmac_timer_ctrl; void cmac_timer_init(void); void cmac_timer_slp_enable(uint32_t ticks); void cmac_timer_slp_disable(uint32_t exp_ticks); -bool cmac_timer_slp_update(void); + +void cmac_timer_slp_update(uint16_t lpclk_freq); bool cmac_timer_slp_is_ready(void); #if MYNEWT_VAL(MCU_SLP_TIMER_32K_ONLY) static inline uint32_t diff --git a/hw/mcu/dialog/cmac/src/cmac_isr.c b/hw/mcu/dialog/cmac/src/cmac_isr.c index a460687d3c..53bc584cd1 100644 --- a/hw/mcu/dialog/cmac/src/cmac_isr.c +++ b/hw/mcu/dialog/cmac/src/cmac_isr.c @@ -17,8 +17,10 @@ * under the License. */ +#include #include #include +#include #include #include #include @@ -40,8 +42,13 @@ SYS2CMAC_IRQHandler(void) cmac_mbox_read(); cmac_rand_read(); - if (pending_ops & CMAC_SHM_CB_PENDING_OP_LP_CLK) { - cmac_sleep_recalculate(); + if (pending_ops & CMAC_SHM_CB_PENDING_OP_LPCLK_UPDATE) { + cmac_timer_slp_update(g_cmac_shm_ctrl.lpclk_freq); + cmac_sleep_wakeup_time_update(g_cmac_shm_ctrl.wakeup_time_us); + } + + if (pending_ops & CMAC_SHM_CB_PENDING_OP_WAKEUP_UPDATE) { + cmac_sleep_wakeup_time_update(g_cmac_shm_ctrl.wakeup_time_us); } if (pending_ops & CMAC_SHM_CB_PENDING_OP_RF_CAL) { diff --git a/hw/mcu/dialog/cmac/src/cmac_priv.h b/hw/mcu/dialog/cmac/src/cmac_priv.h index 45edf43daf..054c040cc2 100644 --- a/hw/mcu/dialog/cmac/src/cmac_priv.h +++ b/hw/mcu/dialog/cmac/src/cmac_priv.h @@ -30,7 +30,7 @@ extern "C" { extern int8_t g_cmac_pdc_cmac2sys; void cmac_sleep(void); -void cmac_sleep_recalculate(void); +void cmac_sleep_wakeup_time_update(uint16_t wakeup_time_us); #ifdef __cplusplus } diff --git a/hw/mcu/dialog/cmac/src/cmac_sleep.c b/hw/mcu/dialog/cmac/src/cmac_sleep.c index cc78f70471..de87991ded 100644 --- a/hw/mcu/dialog/cmac/src/cmac_sleep.c +++ b/hw/mcu/dialog/cmac/src/cmac_sleep.c @@ -72,10 +72,10 @@ static uint32_t g_retained_regs_val[ ARRAY_SIZE(retained_regs) ]; static uint32_t g_mcu_wait_for_swd_start; /* Minimum time required to go to sleep (until switch to SLP) and then wake up */ -static uint32_t g_mcu_wakeup_usecs_min; +static uint32_t g_mcu_sleep_time_us_min; -static bool -cmac_sleep_is_switch_allowed(void) +static inline bool +cmac_sleep_is_slp_allowed(void) { return (ble_phy_xcvr_state_get() == 0) && !os_arch_cmac_pending_irq() && @@ -98,6 +98,10 @@ sub27(uint32_t x, uint32_t y) static bool cmac_sleep_is_deep_sleep_allowed(void) { + if (g_mcu_sleep_time_us_min == 0) { + return false; + } + /* * We wait for SWD attach until high part of LL Timer increases by 2 which * is anywhere in 1-2ms range which is enough. @@ -170,42 +174,31 @@ cmac_sleep_wait4xtal(void) #define T_USEC(_t) (_t) #define T_LPTICK(_t) ((_t) * cmac_timer_slp_tick_us()) -#define T_LPTICK_U(_t) (T_LPTICK(_t) * 15 / 10) -static void -cmac_sleep_calculate_wakeup_time(void) +void +cmac_sleep_wakeup_time_update(uint16_t wakeup_time_us) { - assert(g_cmac_shm_ctrl.xtal32m_settle_us); + if (wakeup_time_us == 0) { + g_mcu_sleep_time_us_min = 0; + return; + } - g_mcu_wakeup_usecs_min = + g_mcu_sleep_time_us_min = /* - * We need ~12us to prepare for sleep before starting switch to SLP. + * We need ~15us to prepare for sleep before starting switch to SLP. * Switch to SLP is done by switching SLP clock to LPCLK first and then * enabling SLP. The former has to be synchronized with negative edge of * LPCLK and the latter happens on positive edge of LPCLK so we just * assume 2 LPCLK ticks in worst case. */ - T_USEC(12) + T_LPTICK(2) + + T_USEC(15) + T_LPTICK(2) + /* - * On wake up we assume fast wake up mode which has 3 phases that take - * up to 2, 2 and 3 LPCLK ticks respectively (need to add some margin - * here for worst-worst case). XTAL32M is started at 3rd phase and we - * need to wait for it to settle before switch back to LLT. This is done - * by disabling SLP and then switching SLP clock to PCLK. Both actions - * are synchronized with LPCLK negative edge so take 2 LPCLK ticks in - * worst case. Finally, LLP compensation takes around 50us. + * After wakeup (this includes XTAL32M settling) we need to switch back + * to LLT. This is done by disabling SLP and then switching SLP clock to + * PCLK. Both actions are synchronized with LPCLK negative edge so take + * 2 LPCLK ticks in worst case. Finally, LLT compensation takes ~50us. */ - T_LPTICK_U(2) + T_LPTICK_U(2) + - max(T_LPTICK_U(3), T_USEC(g_cmac_shm_ctrl.xtal32m_settle_us)) + - T_LPTICK(2) + T_USEC(50); -} - -void -cmac_sleep_recalculate(void) -{ - if (cmac_timer_slp_update()) { - cmac_sleep_calculate_wakeup_time(); - } + T_USEC(wakeup_time_us) + T_LPTICK(2) + T_USEC(50); } extern bool ble_rf_try_recalibrate(uint32_t idle_time_us); @@ -234,7 +227,7 @@ cmac_sleep(void) * happen so need to make sure we can be up and running on time. */ - sleep_usecs = wakeup_at - cmac_timer_read32() - g_mcu_wakeup_usecs_min; + sleep_usecs = wakeup_at - cmac_timer_read32() - g_mcu_sleep_time_us_min; if ((int32_t)sleep_usecs <= 0) { switch_to_slp = false; deep_sleep = false; @@ -245,14 +238,15 @@ cmac_sleep(void) goto skip_sleep; } - sleep_lp_ticks = cmac_timer_usecs_to_lp_ticks(sleep_usecs); - if (sleep_lp_ticks <= 1) { + /* XXX off by one? */ + sleep_lp_ticks = cmac_timer_usecs_to_lp_ticks(sleep_usecs) - 1; + if ((int32_t)sleep_lp_ticks <= 1) { switch_to_slp = false; deep_sleep = false; goto do_sleep; } - if (!cmac_sleep_is_switch_allowed()) { + if (!cmac_sleep_is_slp_allowed()) { switch_to_slp = false; deep_sleep = false; } else if (!cmac_sleep_is_deep_sleep_allowed()) { diff --git a/hw/mcu/dialog/cmac/src/cmac_timer.c b/hw/mcu/dialog/cmac/src/cmac_timer.c index 1820362eee..0a52ad534a 100644 --- a/hw/mcu/dialog/cmac/src/cmac_timer.c +++ b/hw/mcu/dialog/cmac/src/cmac_timer.c @@ -32,7 +32,7 @@ (CMAC_CM_EV_LATCHED_REG_EV1C_CLK_1US_X1_Msk << ((_num) - 1))) struct cmac_timer_slp { - uint32_t freq; + uint16_t lpclk_freq; #if !MYNEWT_VAL(MCU_SLP_TIMER_32K_ONLY) uint32_t conv; uint32_t tick_ns; @@ -334,36 +334,30 @@ cmac_timer_slp_disable(uint32_t exp_ticks) assert(CMAC->CM_LL_INT_STAT_REG == 0); } -bool -cmac_timer_slp_update(void) +void +cmac_timer_slp_update(uint16_t lpclk_freq) { - uint32_t lp_clock_freq; - - lp_clock_freq = g_cmac_shm_ctrl.lp_clock_freq; - - if (lp_clock_freq == g_cmac_timer_slp.freq) { - return false; + if (lpclk_freq == g_cmac_timer_slp.lpclk_freq) { + return; } - g_cmac_timer_slp.freq = lp_clock_freq; + g_cmac_timer_slp.lpclk_freq = lpclk_freq; #if !MYNEWT_VAL(MCU_SLP_TIMER_32K_ONLY) - if (g_cmac_timer_slp.freq) { - g_cmac_timer_slp.conv = g_cmac_timer_slp.freq * 32768 / 1000000; - g_cmac_timer_slp.tick_ns = 1000000000 / g_cmac_timer_slp.freq; + if (g_cmac_timer_slp.lpclk_freq) { + g_cmac_timer_slp.conv = g_cmac_timer_slp.lpclk_freq * 32768 / 1000000; + g_cmac_timer_slp.tick_ns = 1000000000 / g_cmac_timer_slp.lpclk_freq; } #endif - - return true; } bool cmac_timer_slp_is_ready(void) { #if MYNEWT_VAL(MCU_SLP_TIMER_32K_ONLY) - return g_cmac_timer_slp.freq == 32768; + return g_cmac_timer_slp.lpclk_freq == 32768; #else - return g_cmac_timer_slp.freq; + return g_cmac_timer_slp.lpclk_freq != 0; #endif }