diff --git a/modules/hal_nordic/nrf_802154/sl_opensource/platform/nrf_802154_clock_zephyr.c b/modules/hal_nordic/nrf_802154/sl_opensource/platform/nrf_802154_clock_zephyr.c index 1dcf724b0e5..ee3a589bd23 100644 --- a/modules/hal_nordic/nrf_802154/sl_opensource/platform/nrf_802154_clock_zephyr.c +++ b/modules/hal_nordic/nrf_802154/sl_opensource/platform/nrf_802154_clock_zephyr.c @@ -13,8 +13,35 @@ #include #include #include +#include + +/** + * The implementation uses EGU to de-escalate execution context from ZLI to a regular interrupt + * to ensure that Zephyr APIs can be used safely. + * + * Both the nrf_802154_clock_hfclk_start() and nrf_802154_clock_hfclk_stop() can potentially be + * called from ZLI and non-ZLI contexts and consecutive calls are not guaranteed to be alternating. + * + * For example, it is possible that _stop() may be called multiple times in succession and the + * same thing applies to _start(). What is known however is that the last call always takes + * the precedence. + */ + +#define SWI_INT NRFX_CONCAT_2(NRF_EGU_INT_TRIGGERED, NRF_802154_SL_EGU_CLOCK_CHANNEL_NO) +#define SWI_TASK NRFX_CONCAT_2(NRF_EGU_TASK_TRIGGER, NRF_802154_SL_EGU_CLOCK_CHANNEL_NO) +#define SWI_EVENT NRFX_CONCAT_2(NRF_EGU_EVENT_TRIGGERED, NRF_802154_SL_EGU_CLOCK_CHANNEL_NO) + +#define CLOCK_NONE 0u +#define CLOCK_REQUEST 1u +#define CLOCK_RELEASE 2u static bool hfclk_is_running; +static bool enabled; +static atomic_t request = CLOCK_NONE; + +/* Forward declarations. */ +static void hfclk_start(void); +static void hfclk_stop(void); void nrf_802154_clock_init(void) { @@ -23,11 +50,13 @@ void nrf_802154_clock_init(void) nrf_802154_clock_hfclk_latency_set(clock_latency_us); #endif + + nrf_egu_int_enable(NRF_802154_EGU_INSTANCE, SWI_INT); } void nrf_802154_clock_deinit(void) { - /* Intentionally empty. */ + nrf_egu_int_disable(NRF_802154_EGU_INSTANCE, SWI_INT); } bool nrf_802154_clock_hfclk_is_running(void) @@ -47,8 +76,44 @@ static void hfclk_on_callback(struct onoff_manager *mgr, nrf_802154_clock_hfclk_ready(); } -#if defined(CONFIG_CLOCK_CONTROL_NRF) +void nrf_802154_sl_clock_swi_irq_handler(void) +{ + if (nrf_egu_event_check(NRF_802154_EGU_INSTANCE, SWI_EVENT)) { + nrf_egu_event_clear(NRF_802154_EGU_INSTANCE, SWI_EVENT); + + atomic_val_t previous = atomic_set(&request, CLOCK_NONE); + + __ASSERT_NO_MSG(previous == CLOCK_REQUEST || previous == CLOCK_RELEASE); + + switch (previous) { + case CLOCK_REQUEST: + hfclk_start(); + break; + + case CLOCK_RELEASE: + hfclk_stop(); + break; + + default: + break; + } + } +} + void nrf_802154_clock_hfclk_start(void) +{ + atomic_set(&request, CLOCK_REQUEST); + nrf_egu_task_trigger(NRF_802154_EGU_INSTANCE, SWI_TASK); +} + +void nrf_802154_clock_hfclk_stop(void) +{ + atomic_set(&request, CLOCK_RELEASE); + nrf_egu_task_trigger(NRF_802154_EGU_INSTANCE, SWI_TASK); +} + +#if defined(CONFIG_CLOCK_CONTROL_NRF) +static void hfclk_start(void) { struct onoff_manager *mgr = z_nrf_clock_control_get_onoff(CLOCK_CONTROL_NRF_SUBSYS_HF); @@ -57,56 +122,91 @@ void nrf_802154_clock_hfclk_start(void) sys_notify_init_callback(&hfclk_cli.notify, hfclk_on_callback); - /* - * todo: replace constlat request with PM policy API when - * controlling the event latency becomes possible. - */ - if (IS_ENABLED(CONFIG_NRF_802154_CONSTLAT_CONTROL)) { - nrf_sys_event_request_global_constlat(); + if (!enabled) { + unsigned int key = irq_lock(); + + /* + * todo: replace constlat request with PM policy API when + * controlling the event latency becomes possible. + */ + if (IS_ENABLED(CONFIG_NRF_802154_CONSTLAT_CONTROL)) { + nrf_sys_event_request_global_constlat(); + } + + int ret = onoff_request(mgr, &hfclk_cli); + + __ASSERT_NO_MSG(ret >= 0); + (void)ret; + + irq_unlock(key); } - int ret = onoff_request(mgr, &hfclk_cli); - __ASSERT_NO_MSG(ret >= 0); - (void)ret; + enabled = true; } -void nrf_802154_clock_hfclk_stop(void) +static void hfclk_stop(void) { struct onoff_manager *mgr = z_nrf_clock_control_get_onoff(CLOCK_CONTROL_NRF_SUBSYS_HF); __ASSERT_NO_MSG(mgr != NULL); - int ret = onoff_cancel_or_release(mgr, &hfclk_cli); - __ASSERT_NO_MSG(ret >= 0); - (void)ret; + if (enabled) { + unsigned int key = irq_lock(); + + int ret = onoff_cancel_or_release(mgr, &hfclk_cli); + + __ASSERT_NO_MSG(ret >= 0); + (void)ret; + + if (IS_ENABLED(CONFIG_NRF_802154_CONSTLAT_CONTROL)) { + nrf_sys_event_release_global_constlat(); + } + + hfclk_is_running = false; - if (IS_ENABLED(CONFIG_NRF_802154_CONSTLAT_CONTROL)) { - nrf_sys_event_release_global_constlat(); + irq_unlock(key); } - hfclk_is_running = false; + enabled = false; } #elif DT_NODE_HAS_STATUS(DT_NODELABEL(hfxo), okay) && \ DT_NODE_HAS_COMPAT(DT_NODELABEL(hfxo), nordic_nrf54h_hfxo) -void nrf_802154_clock_hfclk_start(void) +static void hfclk_start(void) { - sys_notify_init_callback(&hfclk_cli.notify, hfclk_on_callback); - int ret = nrf_clock_control_request(DEVICE_DT_GET(DT_NODELABEL(hfxo)), NULL, &hfclk_cli); + if (!enabled) { + unsigned int key = irq_lock(); + + sys_notify_init_callback(&hfclk_cli.notify, hfclk_on_callback); + int ret = nrf_clock_control_request(DEVICE_DT_GET(DT_NODELABEL(hfxo)), + NULL, &hfclk_cli); + + __ASSERT_NO_MSG(ret >= 0); + (void)ret; + + irq_unlock(key); + } - __ASSERT_NO_MSG(ret >= 0); - (void)ret; + enabled = true; } -void nrf_802154_clock_hfclk_stop(void) +static void hfclk_stop(void) { - int ret = nrf_clock_control_cancel_or_release(DEVICE_DT_GET(DT_NODELABEL(hfxo)), - NULL, &hfclk_cli); + if (enabled) { + unsigned int key = irq_lock(); + + int ret = nrf_clock_control_cancel_or_release(DEVICE_DT_GET(DT_NODELABEL(hfxo)), + NULL, &hfclk_cli); + + __ASSERT_NO_MSG(ret >= 0); + (void)ret; + + irq_unlock(key); + } - __ASSERT_NO_MSG(ret >= 0); - (void)ret; + enabled = false; } #endif diff --git a/west.yml b/west.yml index 853d84113a6..cce707f4bed 100644 --- a/west.yml +++ b/west.yml @@ -200,7 +200,7 @@ manifest: groups: - hal - name: hal_nordic - revision: 2f5d4e5868ab573eac932fa4bc142565073c3c04 + revision: 9e1bc32436a71adf1aa55937046d659a2db9e74f path: modules/hal/nordic groups: - hal