From 38ce2b3ac29abc243fa93fce818a71293464f6a8 Mon Sep 17 00:00:00 2001 From: Andrzej Kuros Date: Mon, 26 Aug 2024 13:07:29 +0200 Subject: [PATCH] debug: ppi_trace: use nrfx_gppi to support nRF54L This commit changes implementation of the ppi_trace module so that it is based on nrfx_gppi as provided since nrfx 3.8.0. The functions provided by nrfx_gppi library on the nRF54L devices provide ability to connect events and tasks which cross the power domains through PPIB bridges. Most of the functions simply use the nrfx_gppi API, but `ppi_trace_dppi_ch_trace` is a special one. The nRF54L devices have multiple DPPIC controllers, so the function `ppi_trace_dppi_ch_trace` is given an additional parameter that identifies the DPPIC controller. The channel number is not enough. The function prototype must now be provided conditionally only for SoCs equipped with DPPI. GPIOTE can directly subscribe only to DPPI channels of this DPPIC controller which is in the same power domain. Neither Device Tree nor nrfx provide such information. That's why `get_dppic_for_gpiote` function is used internally. It allows handling the case within `ppi_trace_dppi_ch_trace` function where GPIOTE can subscribe to DPPI channel directly. The nrfx_gppi API cannot be used for this purpose. Signed-off-by: Andrzej Kuros --- include/debug/ppi_trace.h | 13 +- subsys/debug/ppi_trace/Kconfig | 7 +- subsys/debug/ppi_trace/ppi_trace.c | 281 +++++++++++++++-------------- 3 files changed, 161 insertions(+), 140 deletions(-) diff --git a/include/debug/ppi_trace.h b/include/debug/ppi_trace.h index 9e73893c4dc4..561c83cf18ca 100644 --- a/include/debug/ppi_trace.h +++ b/include/debug/ppi_trace.h @@ -8,6 +8,11 @@ #define __PPI_TRACE_H #include +#include + +#if defined(DPPI_PRESENT) +#include +#endif #ifdef __cplusplus extern "C" { @@ -48,6 +53,8 @@ void *ppi_trace_config(uint32_t pin, uint32_t evt); */ void *ppi_trace_pair_config(uint32_t pin, uint32_t start_evt, uint32_t stop_evt); +#if defined(DPPI_PRESENT) + /** @brief Configure and enable a PPI trace pin for tracing a DPPI channel. * * This function allows to trace DPPI triggers without knowing any events being the source of the @@ -60,12 +67,16 @@ void *ppi_trace_pair_config(uint32_t pin, uint32_t start_evt, uint32_t stop_evt) * * @param pin Pin to use for tracing. * @param dppi_ch DPPI channel number to be traced on the pin. + * @param dppic Identifies the instance of DPPIC controller that the @c dppi_ch channel + * belongs to. * * @retval 0 The configuration succeeded. * @retval -ENOMEM The configuration failed, due to lack of necessary resources. * @retval -ENOTSUP The function is not supported on current hardware platform. */ -int ppi_trace_dppi_ch_trace(uint32_t pin, uint32_t dppi_ch); +int ppi_trace_dppi_ch_trace(uint32_t pin, uint32_t dppi_ch, const nrfx_dppi_t *dppic); + +#endif /* DPPI_PRESENT */ /** @brief Enable PPI trace pin. * diff --git a/subsys/debug/ppi_trace/Kconfig b/subsys/debug/ppi_trace/Kconfig index 24cdf50949bb..88c89baf96c2 100644 --- a/subsys/debug/ppi_trace/Kconfig +++ b/subsys/debug/ppi_trace/Kconfig @@ -7,8 +7,13 @@ config PPI_TRACE bool "Enable PPI trace" select NRFX_GPIOTE + select NRFX_GPPI select NRFX_PPI if HAS_HW_NRF_PPI - select NRFX_DPPI if HAS_HW_NRF_DPPIC + select NRFX_DPPI0 if SOC_SERIES_NRF53X + select NRFX_DPPI00 if SOC_SERIES_NRF54LX + select NRFX_DPPI10 if SOC_SERIES_NRF54LX + select NRFX_DPPI20 if SOC_SERIES_NRF54LX + select NRFX_DPPI30 if SOC_SERIES_NRF54LX help Enable PPI trace module which enables forwarding hardware events to GPIOs. diff --git a/subsys/debug/ppi_trace/ppi_trace.c b/subsys/debug/ppi_trace/ppi_trace.c index 6ac5c178c2b7..56fbf3307bf4 100644 --- a/subsys/debug/ppi_trace/ppi_trace.c +++ b/subsys/debug/ppi_trace/ppi_trace.c @@ -8,20 +8,14 @@ #include #ifdef DPPI_PRESENT #include -#else -#include #endif +#include + #include #include LOG_MODULE_REGISTER(ppi_trace, CONFIG_PPI_TRACE_LOG_LEVEL); -/* Convert task address to associated subscribe register */ -#define SUBSCRIBE_ADDR(task) (volatile uint32_t *)(task + 0x80) - -/* Convert event address to associated publish register */ -#define PUBLISH_ADDR(evt) (volatile uint32_t *)(evt + 0x80) - /* Handle which is used by the user to enable and disable the trace pin is * encapsulating ppi channel(s). Bit 31 is set to indicate that handle is * valid. Bit 30 is set to indicate that handle contains pair of PPI channels. @@ -55,6 +49,11 @@ LOG_MODULE_REGISTER(ppi_trace, CONFIG_PPI_TRACE_LOG_LEVEL); (NRFX_GPIOTE_INSTANCE(DT_PROP(GPIOTE_NODE(gpio_node), instance))), \ (INVALID_NRFX_GPIOTE_INSTANCE)), +typedef struct { + const nrfx_gpiote_t *gpiote; + uint8_t gpiote_channel; +} ppi_trace_gpiote_pin_t; + static const nrfx_gpiote_t *get_gpiote(nrfx_gpiote_pin_t pin) { static const nrfx_gpiote_t gpiote[GPIO_COUNT] = { @@ -63,190 +62,196 @@ static const nrfx_gpiote_t *get_gpiote(nrfx_gpiote_pin_t pin) const nrfx_gpiote_t *result = &gpiote[pin >> 5]; - __ASSERT(result->p_reg != NULL, "The pin=%u nas no GPIOTE", pin); + if (result->p_reg == NULL) { + /* On given pin's port there is no GPIOTE. */ + result = NULL; + } return result; } -/** @brief Allocate (D)PPI channel. */ -static nrfx_err_t ppi_alloc(uint8_t *ch, uint32_t evt) +static bool ppi_trace_gpiote_pin_init( + ppi_trace_gpiote_pin_t *ppi_trace_gpiote_pin, nrfx_gpiote_pin_t pin) { - nrfx_err_t err; -#ifdef DPPI_PRESENT - nrfx_dppi_t dppi = NRFX_DPPI_INSTANCE(0); - - if (*PUBLISH_ADDR(evt) != 0) { - /* Use mask of one of subscribe registers in the system, - * assuming that all subscribe registers has the same mask for - * channel id. - */ - *ch = *PUBLISH_ADDR(evt) & DPPIC_SUBSCRIBE_CHG_EN_CHIDX_Msk; - err = NRFX_SUCCESS; - } else { - err = nrfx_dppi_channel_alloc(&dppi, ch); + ppi_trace_gpiote_pin->gpiote = get_gpiote(pin); + if (ppi_trace_gpiote_pin->gpiote == NULL) { + LOG_ERR("Given GPIO pin has no associated GPIOTE."); + return false; } -#else - err = nrfx_ppi_channel_alloc((nrf_ppi_channel_t *)ch); -#endif - return err; -} - -/** @brief Set task and event on (D)PPI channel. */ -static void ppi_assign(uint8_t ch, uint32_t evt, uint32_t task) -{ -#ifdef DPPI_PRESENT - /* Use mask of one of subscribe registers in the system, assuming that - * all subscribe registers has the same mask for enabling channel. - */ - *SUBSCRIBE_ADDR(task) = DPPIC_SUBSCRIBE_CHG_EN_EN_Msk | (uint32_t)ch; - *PUBLISH_ADDR(evt) = DPPIC_SUBSCRIBE_CHG_EN_EN_Msk | (uint32_t)ch; -#else - (void)nrfx_ppi_channel_assign(ch, evt, task); -#endif -} -/** @brief Enable (D)PPI channels. */ -static void ppi_enable(uint32_t channel_mask) -{ -#ifdef DPPI_PRESENT - nrf_dppi_channels_enable(NRF_DPPIC, channel_mask); -#else - nrf_ppi_channels_enable(NRF_PPI, channel_mask); -#endif -} - -/** @brief Disable (D)PPI channels. */ -static void ppi_disable(uint32_t channel_mask) -{ -#ifdef DPPI_PRESENT - nrf_dppi_channels_disable(NRF_DPPIC, channel_mask); -#else - nrf_ppi_channels_disable(NRF_PPI, channel_mask); -#endif -} - -/** @brief Allocate GPIOTE channel. - * - * @param pin Pin. - * - * @return Allocated channel or -1 if failed to allocate. - */ -static int gpiote_channel_alloc(uint32_t pin) -{ - uint8_t channel; - const nrfx_gpiote_t *gpiote = get_gpiote(pin); - - if (nrfx_gpiote_channel_alloc(gpiote, &channel) != NRFX_SUCCESS) { - return -1; + if (nrfx_gpiote_channel_alloc(ppi_trace_gpiote_pin->gpiote, + &ppi_trace_gpiote_pin->gpiote_channel) != NRFX_SUCCESS) { + LOG_ERR("Failed to allocate GPIOTE channel."); + return false; } - nrf_gpiote_task_configure(gpiote->p_reg, channel, pin, + nrf_gpiote_task_configure(ppi_trace_gpiote_pin->gpiote->p_reg, + ppi_trace_gpiote_pin->gpiote_channel, + pin, NRF_GPIOTE_POLARITY_TOGGLE, NRF_GPIOTE_INITIAL_VALUE_LOW); - nrf_gpiote_task_enable(gpiote->p_reg, channel); + nrf_gpiote_task_enable(ppi_trace_gpiote_pin->gpiote->p_reg, + ppi_trace_gpiote_pin->gpiote_channel); - return channel; + return true; } void *ppi_trace_config(uint32_t pin, uint32_t evt) { - int err; - uint32_t task; - int gpiote_ch; - nrf_gpiote_task_t task_id; - uint8_t ppi_ch; - - err = ppi_alloc(&ppi_ch, evt); - if (err != NRFX_SUCCESS) { - LOG_ERR("Failed to allocate PPI channel."); + uint8_t gppi_ch = UINT8_MAX; + + if (NRFX_SUCCESS != nrfx_gppi_channel_alloc(&gppi_ch)) { + LOG_ERR("Failed to allocate GPPI channel."); return NULL; } - gpiote_ch = gpiote_channel_alloc(pin); - if (gpiote_ch < 0) { - LOG_ERR("Failed to allocate GPIOTE channel."); + ppi_trace_gpiote_pin_t ppi_trace_gpiote_pin = {}; + + if (!ppi_trace_gpiote_pin_init(&ppi_trace_gpiote_pin, pin)) { + nrfx_gppi_channel_free(gppi_ch); return NULL; } - task_id = offsetof(NRF_GPIOTE_Type, TASKS_OUT[gpiote_ch]); - task = nrf_gpiote_task_address_get(get_gpiote(pin)->p_reg, task_id); - ppi_assign(ppi_ch, evt, task); + uint32_t tep = nrf_gpiote_task_address_get(ppi_trace_gpiote_pin.gpiote->p_reg, + nrf_gpiote_out_task_get(ppi_trace_gpiote_pin.gpiote_channel)); + nrfx_gppi_channel_endpoints_setup(gppi_ch, evt, tep); - return HANDLE_ENCODE(ppi_ch); + return HANDLE_ENCODE(gppi_ch); } void *ppi_trace_pair_config(uint32_t pin, uint32_t start_evt, uint32_t stop_evt) { - int err; - uint32_t task; - uint8_t start_ch; - uint8_t stop_ch; - int gpiote_ch; - nrf_gpiote_task_t task_set_id; - nrf_gpiote_task_t task_clr_id; - #if !defined(GPIOTE_FEATURE_SET_PRESENT) || \ !defined(GPIOTE_FEATURE_CLR_PRESENT) __ASSERT(0, "Function not supported on this platform."); return NULL; #else + uint8_t gppi_ch_start_evt = UINT8_MAX; - err = ppi_alloc(&start_ch, start_evt); - if (err != NRFX_SUCCESS) { - LOG_ERR("Failed to allocate PPI channel."); + if (NRFX_SUCCESS != nrfx_gppi_channel_alloc(&gppi_ch_start_evt)) { + LOG_ERR("Failed to allocate GPPI channel."); return NULL; } - err = ppi_alloc(&stop_ch, stop_evt); - if (err != NRFX_SUCCESS) { - LOG_ERR("Failed to allocate PPI channel."); + uint8_t gppi_ch_stop_evt = UINT8_MAX; + + if (NRFX_SUCCESS != nrfx_gppi_channel_alloc(&gppi_ch_stop_evt)) { + LOG_ERR("Failed to allocate GPPI channel."); + nrfx_gppi_channel_free(gppi_ch_start_evt); return NULL; } - gpiote_ch = gpiote_channel_alloc(pin); - if (gpiote_ch < 0) { - LOG_ERR("Failed to allocate GPIOTE channel."); + ppi_trace_gpiote_pin_t ppi_trace_gpiote_pin = {}; + + if (!ppi_trace_gpiote_pin_init(&ppi_trace_gpiote_pin, pin)) { + nrfx_gppi_channel_free(gppi_ch_stop_evt); + nrfx_gppi_channel_free(gppi_ch_start_evt); return NULL; } - task_set_id = offsetof(NRF_GPIOTE_Type, TASKS_SET[gpiote_ch]); - task_clr_id = offsetof(NRF_GPIOTE_Type, TASKS_CLR[gpiote_ch]); + uint32_t tep; - task = nrf_gpiote_task_address_get(get_gpiote(pin)->p_reg, task_set_id); - ppi_assign(start_ch, start_evt, task); - task = nrf_gpiote_task_address_get(get_gpiote(pin)->p_reg, task_clr_id); - ppi_assign(stop_ch, stop_evt, task); + tep = nrf_gpiote_task_address_get(ppi_trace_gpiote_pin.gpiote->p_reg, + nrf_gpiote_set_task_get(ppi_trace_gpiote_pin.gpiote_channel)); + nrfx_gppi_channel_endpoints_setup(gppi_ch_start_evt, start_evt, tep); - return HANDLE_ENCODE(PACK_CHANNELS(start_ch, stop_ch)); + tep = nrf_gpiote_task_address_get(ppi_trace_gpiote_pin.gpiote->p_reg, + nrf_gpiote_clr_task_get(ppi_trace_gpiote_pin.gpiote_channel)); + nrfx_gppi_channel_endpoints_setup(gppi_ch_stop_evt, stop_evt, tep); + + return HANDLE_ENCODE(PACK_CHANNELS(gppi_ch_start_evt, gppi_ch_stop_evt)); #endif } -int ppi_trace_dppi_ch_trace(uint32_t pin, uint32_t dppi_ch) +#if defined(DPPI_PRESENT) + +static const nrfx_dppi_t *get_dppic_for_gpiote(const nrfx_gpiote_t *gpiote) { -#ifdef DPPI_PRESENT - uint32_t task; - int gpiote_ch; - nrf_gpiote_task_t task_id; + /* The Device Tree does not provide information about the DPPIC controller for which + * the given GPIOTE instance can subscribe to. That's why we need to provide the + * matching DPPIC instance ourselves. + */ - gpiote_ch = gpiote_channel_alloc(pin); - if (gpiote_ch < 0) { - LOG_ERR("Failed to allocate GPIOTE channel."); +#if (!defined(DPPIC_COUNT) || (DPPIC_COUNT == 1)) + static const nrfx_dppi_t dppic = NRFX_DPPI_INSTANCE(0); + + return &dppic; +#elif defined(CONFIG_SOC_SERIES_NRF54LX) + if (gpiote->p_reg == NRF_GPIOTE20) { + static const nrfx_dppi_t dppic20 = NRFX_DPPI_INSTANCE(20); + + return &dppic20; + } else if (gpiote->p_reg == NRF_GPIOTE30) { + static const nrfx_dppi_t dppic30 = NRFX_DPPI_INSTANCE(30); + + return &dppic30; + } else { + return NULL; + } +#else +#error Unsupported SoC series + return NULL; +#endif +} + +int ppi_trace_dppi_ch_trace(uint32_t pin, uint32_t dppi_ch, const nrfx_dppi_t *dppic) +{ + ppi_trace_gpiote_pin_t ppi_trace_gpiote_pin = {}; + + if (!ppi_trace_gpiote_pin_init(&ppi_trace_gpiote_pin, pin)) { return -ENOMEM; } - task_id = offsetof(NRF_GPIOTE_Type, TASKS_OUT[gpiote_ch]); - task = nrf_gpiote_task_address_get(NRF_GPIOTE, task_id); + const nrfx_dppi_t *dppic_for_gpiote = get_dppic_for_gpiote(ppi_trace_gpiote_pin.gpiote); - *SUBSCRIBE_ADDR(task) = DPPIC_SUBSCRIBE_CHG_EN_EN_Msk | dppi_ch; + if (dppic_for_gpiote == NULL) { + LOG_ERR("For given GPIO pin, the GPIOTE has no associated DPPIC."); + return -ENOMEM; + } - return 0; -#else - (void)pin; - (void)dppi_ch; + if (dppic_for_gpiote->p_reg == dppic->p_reg) { + /* The GPIOTE can directly subscribe to DPPI channels of `dppic` */ + nrf_gpiote_subscribe_set(ppi_trace_gpiote_pin.gpiote->p_reg, + nrf_gpiote_out_task_get(ppi_trace_gpiote_pin.gpiote_channel), + dppi_ch); + } else { + /* Let the GPIOTE channel subscribe to a local dppi_channel_for_gpiote of + * ppi_trace_gpiote_pin.dppic first. + */ + uint8_t dppi_channel_for_gpiote = UINT8_MAX; - return -ENOTSUP; -#endif + if (nrfx_dppi_channel_alloc(dppic_for_gpiote, + &dppi_channel_for_gpiote) != NRFX_SUCCESS) { + return -ENOMEM; + } + + nrf_gpiote_subscribe_set(ppi_trace_gpiote_pin.gpiote->p_reg, + nrf_gpiote_out_task_get(ppi_trace_gpiote_pin.gpiote_channel), + dppi_channel_for_gpiote); + + (void)nrfx_dppi_channel_enable(dppic_for_gpiote, dppi_channel_for_gpiote); + + /* Then, let the dppi_ch channel of dppic controller passed by parameters + * trigger the local dppi_channel_for_gpiote. + */ + uint8_t gppi_ch = UINT8_MAX; + + if (NRFX_SUCCESS != nrfx_gppi_channel_alloc(&gppi_ch)) { + LOG_ERR("Failed to allocate GPPI channel."); + return -ENOMEM; + } + + if (NRFX_SUCCESS != nrfx_gppi_edge_connection_setup(gppi_ch, + dppic, dppi_ch, dppic_for_gpiote, dppi_channel_for_gpiote)) { + LOG_ERR("Failed to setup a GPPI edge connection."); + return -ENOMEM; + } + + nrfx_gppi_channels_enable(1U << gppi_ch); + } + return 0; } +#endif /* defined(DPPI_PRESENT) */ static uint32_t ppi_channel_mask_get(void *handle) { @@ -257,10 +262,10 @@ static uint32_t ppi_channel_mask_get(void *handle) void ppi_trace_enable(void *handle) { - ppi_enable(ppi_channel_mask_get(handle)); + nrfx_gppi_channels_enable(ppi_channel_mask_get(handle)); } void ppi_trace_disable(void *handle) { - ppi_disable(ppi_channel_mask_get(handle)); + nrfx_gppi_channels_disable(ppi_channel_mask_get(handle)); }