From 56f909d9d66bf6467e5f4dec8c94ca5ca94b14bb Mon Sep 17 00:00:00 2001 From: Bjarki Arge Andreasen Date: Tue, 3 Dec 2024 12:38:04 +0100 Subject: [PATCH 1/3] [nrf fromtree] drivers: clock_control: nrf: add zero-latency-isr safe APIs Add zero latency interrupt safe APIs to allow requesting and releasing HFXO. These will be used from components running in zero latency interrupt context, like the bluetooth stack. Co-authored-by: Piotr Pryga Signed-off-by: Bjarki Arge Andreasen Signed-off-by: Piotr Pryga (cherry picked from commit 2aec438b437d79e59278bec26428bb58b3d41c3c) Signed-off-by: Piotr Pryga --- .../drivers/clock_control/nrf_clock_control.h | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/include/zephyr/drivers/clock_control/nrf_clock_control.h b/include/zephyr/drivers/clock_control/nrf_clock_control.h index 27ab518920f..8d9bcbe3441 100644 --- a/include/zephyr/drivers/clock_control/nrf_clock_control.h +++ b/include/zephyr/drivers/clock_control/nrf_clock_control.h @@ -317,6 +317,30 @@ int nrf_clock_control_cancel_or_release(const struct device *dev, return api->cancel_or_release(dev, spec, cli); } +/** @brief Request the HFXO from Zero Latency Interrupt context. + * + * Function is optimized for use in Zero Latency Interrupt context. + * It does not give notification when the HFXO is ready, so each + * user must put the request early enough to make sure the HFXO + * ramp-up has finished on time. + * + * This function uses reference counting so the caller must ensure + * that every nrf_clock_control_hfxo_request() call has a matching + * nrf_clock_control_hfxo_release() call. + */ +void nrf_clock_control_hfxo_request(void); + +/** @brief Release the HFXO from Zero Latency Interrupt context. + * + * Function is optimized for use in Zero Latency Interrupt context. + * + * Calls to this function must be coupled with prior calls + * to nrf_clock_control_hfxo_request(), because it uses basic + * reference counting to make sure the HFXO is released when + * there are no more pending requests. + */ +void nrf_clock_control_hfxo_release(void); + #endif /* defined(CONFIG_CLOCK_CONTROL_NRF2) */ /** @brief Get clock frequency that is used for the given node. From 685ec072ad442f77aeef2f639c8a6d87b581336a Mon Sep 17 00:00:00 2001 From: Bjarki Arge Andreasen Date: Tue, 3 Dec 2024 12:39:45 +0100 Subject: [PATCH 2/3] [nrf fromtree] drivers: clock_control: nrf: hfxo: impl zero-latency isr API Implement the zero latency interrupt safe APIs to the HFXO clock commonly used by the bluetooth stach from zero latency interrupt context. Co-authored-by: Piotr Pryga Signed-off-by: Bjarki Arge Andreasen Signed-off-by: Piotr Pryga (cherry picked from commit 73a45a70126df8145a00d2e3adb1dad60818dde0) Signed-off-by: Piotr Pryga --- .../clock_control/clock_control_nrf2_hfxo.c | 111 +++++++++++++++++- 1 file changed, 105 insertions(+), 6 deletions(-) diff --git a/drivers/clock_control/clock_control_nrf2_hfxo.c b/drivers/clock_control/clock_control_nrf2_hfxo.c index 977c0aaa0d6..43998427f8b 100644 --- a/drivers/clock_control/clock_control_nrf2_hfxo.c +++ b/drivers/clock_control/clock_control_nrf2_hfxo.c @@ -21,6 +21,9 @@ struct dev_data_hfxo { onoff_notify_fn notify; struct k_timer timer; sys_snode_t hfxo_node; +#if defined(CONFIG_ZERO_LATENCY_IRQS) + uint16_t request_count; +#endif /* CONFIG_ZERO_LATENCY_IRQS */ }; struct dev_config_hfxo { @@ -29,6 +32,31 @@ struct dev_config_hfxo { k_timeout_t start_up_time; }; +#if defined(CONFIG_ZERO_LATENCY_IRQS) +static uint32_t full_irq_lock(void) +{ + uint32_t mcu_critical_state; + + if (IS_ENABLED(CONFIG_ZERO_LATENCY_IRQS)) { + mcu_critical_state = __get_PRIMASK(); + __disable_irq(); + } else { + mcu_critical_state = irq_lock(); + } + + return mcu_critical_state; +} + +static void full_irq_unlock(uint32_t mcu_critical_state) +{ + if (IS_ENABLED(CONFIG_ZERO_LATENCY_IRQS)) { + __set_PRIMASK(mcu_critical_state); + } else { + irq_unlock(mcu_critical_state); + } +} +#endif /* CONFIG_ZERO_LATENCY_IRQS */ + static void hfxo_start_up_timer_handler(struct k_timer *timer) { struct dev_data_hfxo *dev_data = @@ -48,6 +76,40 @@ static void hfxo_start_up_timer_handler(struct k_timer *timer) } } +static void start_hfxo(struct dev_data_hfxo *dev_data) +{ + nrf_lrcconf_event_clear(NRF_LRCCONF010, NRF_LRCCONF_EVENT_HFXOSTARTED); + soc_lrcconf_poweron_request(&dev_data->hfxo_node, NRF_LRCCONF_POWER_MAIN); + nrf_lrcconf_task_trigger(NRF_LRCCONF010, NRF_LRCCONF_TASK_REQHFXO); +} + +static void request_hfxo(struct dev_data_hfxo *dev_data) +{ +#if defined(CONFIG_ZERO_LATENCY_IRQS) + unsigned int key; + + key = full_irq_lock(); + if (dev_data->request_count == 0) { + start_hfxo(dev_data); + } + + dev_data->request_count++; + full_irq_unlock(key); +#else + start_hfxo(dev_data); +#endif /* CONFIG_ZERO_LATENCY_IRQS */ +} + +#if IS_ENABLED(CONFIG_ZERO_LATENCY_IRQS) +void nrf_clock_control_hfxo_request(void) +{ + const struct device *dev = DEVICE_DT_INST_GET(0); + struct dev_data_hfxo *dev_data = dev->data; + + request_hfxo(dev_data); +} +#endif /* CONFIG_ZERO_LATENCY_IRQS */ + static void onoff_start_hfxo(struct onoff_manager *mgr, onoff_notify_fn notify) { struct dev_data_hfxo *dev_data = @@ -56,10 +118,7 @@ static void onoff_start_hfxo(struct onoff_manager *mgr, onoff_notify_fn notify) const struct dev_config_hfxo *dev_config = dev->config; dev_data->notify = notify; - - nrf_lrcconf_event_clear(NRF_LRCCONF010, NRF_LRCCONF_EVENT_HFXOSTARTED); - soc_lrcconf_poweron_request(&dev_data->hfxo_node, NRF_LRCCONF_POWER_MAIN); - nrf_lrcconf_task_trigger(NRF_LRCCONF010, NRF_LRCCONF_TASK_REQHFXO); + request_hfxo(dev_data); /* Due to a hardware issue, the HFXOSTARTED event is currently * unreliable. Hence the timer is used to simply wait the expected @@ -68,13 +127,53 @@ static void onoff_start_hfxo(struct onoff_manager *mgr, onoff_notify_fn notify) k_timer_start(&dev_data->timer, dev_config->start_up_time, K_NO_WAIT); } +static void stop_hfxo(struct dev_data_hfxo *dev_data) +{ + nrf_lrcconf_task_trigger(NRF_LRCCONF010, NRF_LRCCONF_TASK_STOPREQHFXO); + soc_lrcconf_poweron_release(&dev_data->hfxo_node, NRF_LRCCONF_POWER_MAIN); +} + +static void release_hfxo(struct dev_data_hfxo *dev_data) +{ +#if IS_ENABLED(CONFIG_ZERO_LATENCY_IRQS) + unsigned int key; + + key = full_irq_lock(); + if (dev_data->request_count < 1) { + full_irq_unlock(key); + /* Misuse of the API, release without request? */ + __ASSERT_NO_MSG(false); + /* In case asserts are disabled early return due to no requests pending */ + return; + } + + dev_data->request_count--; + if (dev_data->request_count < 1) { + stop_hfxo(dev_data); + } + + full_irq_unlock(key); +#else + stop_hfxo(dev_data); +#endif /* CONFIG_ZERO_LATENCY_IRQS */ +} + +#if IS_ENABLED(CONFIG_ZERO_LATENCY_IRQS) +void nrf_clock_control_hfxo_release(void) +{ + const struct device *dev = DEVICE_DT_INST_GET(0); + struct dev_data_hfxo *dev_data = dev->data; + + release_hfxo(dev_data); +} +#endif /* IS_ENABLED(CONFIG_ZERO_LATENCY_IRQS) */ + static void onoff_stop_hfxo(struct onoff_manager *mgr, onoff_notify_fn notify) { struct dev_data_hfxo *dev_data = CONTAINER_OF(mgr, struct dev_data_hfxo, mgr); - nrf_lrcconf_task_trigger(NRF_LRCCONF010, NRF_LRCCONF_TASK_STOPREQHFXO); - soc_lrcconf_poweron_release(&dev_data->hfxo_node, NRF_LRCCONF_POWER_MAIN); + release_hfxo(dev_data); notify(mgr, 0); } From 08623489c42ce5f16c20745449afda3f43061069 Mon Sep 17 00:00:00 2001 From: Piotr Pryga Date: Sat, 14 Dec 2024 19:15:37 +0100 Subject: [PATCH 3/3] [nrf fromtree] drivers: clock_control: nrf: hfxo: Remove redundad code There were redundant code in full_irq_lock(), full_irq_unlock() functions that supposed to be used when ZLI IRQs are disabled. These functions are compiled in only when CONFIG_ZERO_LATENCY_IRQS is set, hence the non-ZLI execution path was never included in final binaries. Signed-off-by: Piotr Pryga (cherry picked from commit 233095c3f452c05683f0410140e737d89567d927) Signed-off-by: Piotr Pryga --- drivers/clock_control/clock_control_nrf2_hfxo.c | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/drivers/clock_control/clock_control_nrf2_hfxo.c b/drivers/clock_control/clock_control_nrf2_hfxo.c index 43998427f8b..eae419f18bb 100644 --- a/drivers/clock_control/clock_control_nrf2_hfxo.c +++ b/drivers/clock_control/clock_control_nrf2_hfxo.c @@ -37,23 +37,15 @@ static uint32_t full_irq_lock(void) { uint32_t mcu_critical_state; - if (IS_ENABLED(CONFIG_ZERO_LATENCY_IRQS)) { - mcu_critical_state = __get_PRIMASK(); - __disable_irq(); - } else { - mcu_critical_state = irq_lock(); - } + mcu_critical_state = __get_PRIMASK(); + __disable_irq(); return mcu_critical_state; } static void full_irq_unlock(uint32_t mcu_critical_state) { - if (IS_ENABLED(CONFIG_ZERO_LATENCY_IRQS)) { - __set_PRIMASK(mcu_critical_state); - } else { - irq_unlock(mcu_critical_state); - } + __set_PRIMASK(mcu_critical_state); } #endif /* CONFIG_ZERO_LATENCY_IRQS */