Skip to content

Commit

Permalink
fix(dma): abort the axi dma gracefully on CPU SW reset
Browse files Browse the repository at this point in the history
  • Loading branch information
suda-morris committed Jan 9, 2025
1 parent e44c525 commit fbcbefe
Show file tree
Hide file tree
Showing 8 changed files with 119 additions and 20 deletions.
34 changes: 31 additions & 3 deletions components/esp_system/port/soc/esp32p4/system_internal.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
Expand Down Expand Up @@ -28,6 +28,10 @@
#include "soc/hp_sys_clkrst_reg.h"
#include "soc/lp_clkrst_reg.h"
#include "soc/hp_system_reg.h"
#include "hal/gdma_ll.h"
#include "hal/axi_dma_ll.h"
#include "hal/dw_gdma_ll.h"
#include "hal/dma2d_ll.h"

void IRAM_ATTR esp_system_reset_modules_on_exit(void)
{
Expand All @@ -38,6 +42,32 @@ void IRAM_ATTR esp_system_reset_modules_on_exit(void)
}
}

// Note: AXI bus doesn't allow an undergoing transaction to be interrupted in the middle
// If you want to reset a AXI master, you should make sure that the master is in IDLE first
if (gdma_ll_is_bus_clock_enabled(1)) {
for (int i = 0; i < GDMA_LL_AXI_PAIRS_PER_GROUP; i++) {
axi_dma_ll_tx_abort(AXI_DMA_LL_GET_HW(0), i, true);
axi_dma_ll_rx_abort(AXI_DMA_LL_GET_HW(0), i, true);
while (!axi_dma_ll_tx_is_reset_avail(AXI_DMA_LL_GET_HW(0), i));
while (!axi_dma_ll_rx_is_reset_avail(AXI_DMA_LL_GET_HW(0), i));
}
}
if (dma2d_ll_is_bus_clock_enabled(0)) {
for (int i = 0; i < SOC_DMA2D_RX_CHANNELS_PER_GROUP; i++) {
dma2d_ll_rx_abort(DMA2D_LL_GET_HW(0), i, true);
while (!dma2d_ll_rx_is_reset_avail(DMA2D_LL_GET_HW(0), i));
}
for (int i = 0; i < SOC_DMA2D_TX_CHANNELS_PER_GROUP; i++) {
dma2d_ll_tx_abort(DMA2D_LL_GET_HW(0), i, true);
while (!dma2d_ll_tx_is_reset_avail(DMA2D_LL_GET_HW(0), i));
}
}
if (dw_gdma_ll_is_bus_clock_enabled(0)) {
for (int i = 0; i < DW_GDMA_LL_CHANNELS_PER_GROUP; i++) {
dw_gdma_ll_channel_abort(DW_GDMA_LL_GET_HW(0), i);
}
}

// Set Peripheral clk rst
SET_PERI_REG_MASK(HP_SYS_CLKRST_HP_RST_EN1_REG, HP_SYS_CLKRST_REG_RST_EN_TIMERGRP1);
SET_PERI_REG_MASK(HP_SYS_CLKRST_HP_RST_EN1_REG, HP_SYS_CLKRST_REG_RST_EN_STIMER);
Expand All @@ -48,7 +78,6 @@ void IRAM_ATTR esp_system_reset_modules_on_exit(void)
SET_PERI_REG_MASK(HP_SYS_CLKRST_HP_RST_EN1_REG, HP_SYS_CLKRST_REG_RST_EN_UART2_CORE);
SET_PERI_REG_MASK(HP_SYS_CLKRST_HP_RST_EN1_REG, HP_SYS_CLKRST_REG_RST_EN_UART3_CORE);
SET_PERI_REG_MASK(HP_SYS_CLKRST_HP_RST_EN1_REG, HP_SYS_CLKRST_REG_RST_EN_UART4_CORE);
SET_PERI_REG_MASK(HP_SYS_CLKRST_HP_RST_EN0_REG, HP_SYS_CLKRST_REG_RST_EN_GDMA);
SET_PERI_REG_MASK(HP_SYS_CLKRST_HP_RST_EN2_REG, HP_SYS_CLKRST_REG_RST_EN_ADC);

// Clear Peripheral clk rst
Expand All @@ -61,7 +90,6 @@ void IRAM_ATTR esp_system_reset_modules_on_exit(void)
CLEAR_PERI_REG_MASK(HP_SYS_CLKRST_HP_RST_EN1_REG, HP_SYS_CLKRST_REG_RST_EN_UART2_CORE);
CLEAR_PERI_REG_MASK(HP_SYS_CLKRST_HP_RST_EN1_REG, HP_SYS_CLKRST_REG_RST_EN_UART3_CORE);
CLEAR_PERI_REG_MASK(HP_SYS_CLKRST_HP_RST_EN1_REG, HP_SYS_CLKRST_REG_RST_EN_UART4_CORE);
CLEAR_PERI_REG_MASK(HP_SYS_CLKRST_HP_RST_EN0_REG, HP_SYS_CLKRST_REG_RST_EN_GDMA);
CLEAR_PERI_REG_MASK(HP_SYS_CLKRST_HP_RST_EN2_REG, HP_SYS_CLKRST_REG_RST_EN_ADC);

#if CONFIG_ESP32P4_REV_MIN_FULL <= 100
Expand Down
10 changes: 5 additions & 5 deletions components/hal/dma2d_hal.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
Expand All @@ -14,16 +14,16 @@ void dma2d_hal_init(dma2d_hal_context_t *hal, int group_id)

void dma2d_hal_tx_reset_channel(dma2d_hal_context_t *hal, uint32_t channel)
{
dma2d_ll_tx_disable_cmd(hal->dev, channel, true);
dma2d_ll_tx_abort(hal->dev, channel, true);
while (!dma2d_ll_tx_is_reset_avail(hal->dev, channel));
dma2d_ll_tx_reset_channel(hal->dev, channel);
dma2d_ll_tx_disable_cmd(hal->dev, channel, false);
dma2d_ll_tx_abort(hal->dev, channel, false);
}

void dma2d_hal_rx_reset_channel(dma2d_hal_context_t *hal, uint32_t channel)
{
dma2d_ll_rx_disable_cmd(hal->dev, channel, true);
dma2d_ll_rx_abort(hal->dev, channel, true);
while (!dma2d_ll_rx_is_reset_avail(hal->dev, channel));
dma2d_ll_rx_reset_channel(hal->dev, channel);
dma2d_ll_rx_disable_cmd(hal->dev, channel, false);
dma2d_ll_rx_abort(hal->dev, channel, false);
}
2 changes: 1 addition & 1 deletion components/hal/dw_gdma_hal.c
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@

void dw_gdma_hal_init(dw_gdma_hal_context_t *hal, const dw_gdma_hal_config_t *config)
{
hal->dev = DW_GDMA_LL_GET_HW();
hal->dev = DW_GDMA_LL_GET_HW(0);
dw_gdma_ll_reset(hal->dev);
dw_gdma_ll_enable_controller(hal->dev, true);
dw_gdma_ll_enable_intr_global(hal->dev, true);
Expand Down
38 changes: 37 additions & 1 deletion components/hal/esp32p4/include/hal/axi_dma_ll.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
Expand Down Expand Up @@ -195,6 +195,15 @@ static inline void axi_dma_ll_rx_stop(axi_dma_dev_t *dev, uint32_t channel)
dev->in[channel].conf.in_link1.inlink_stop_chn = 1;
}

/**
* @brief Abort the RX channel, stop the undergoing transfer immediately
*/
__attribute__((always_inline))
static inline void axi_dma_ll_rx_abort(axi_dma_dev_t *dev, uint32_t channel, bool abort)
{
dev->in[channel].conf.in_conf0.in_cmd_disable_chn = abort;
}

/**
* @brief Restart a new inlink right after the last descriptor
*/
Expand Down Expand Up @@ -291,6 +300,15 @@ static inline void axi_dma_ll_rx_enable_ext_mem_ecc_aes_access(axi_dma_dev_t *de
dev->in[channel].conf.in_conf0.in_ecc_aes_en_chn = enable;
}

/**
* @brief Return if the channel is ready to be reset
*/
__attribute__((always_inline))
static inline bool axi_dma_ll_rx_is_reset_avail(axi_dma_dev_t *dev, uint32_t channel)
{
return dev->in_reset_avail_chn[channel].in_reset_avail_chn;
}

///////////////////////////////////// TX /////////////////////////////////////////
/**
* @brief Get DMA TX channel interrupt status word
Expand Down Expand Up @@ -429,6 +447,15 @@ static inline void axi_dma_ll_tx_stop(axi_dma_dev_t *dev, uint32_t channel)
dev->out[channel].conf.out_link1.outlink_stop_chn = 1;
}

/**
* @brief Abort the TX channel, stop the undergoing transfer immediately
*/
__attribute__((always_inline))
static inline void axi_dma_ll_tx_abort(axi_dma_dev_t *dev, uint32_t channel, bool abort)
{
dev->out[channel].conf.out_conf0.out_cmd_disable_chn = abort;
}

/**
* @brief Restart a new outlink right after the last descriptor
*/
Expand Down Expand Up @@ -507,6 +534,15 @@ static inline void axi_dma_ll_tx_enable_ext_mem_ecc_aes_access(axi_dma_dev_t *de
dev->out[channel].conf.out_conf0.out_ecc_aes_en_chn = enable;
}

/**
* @brief Return if the channel is ready to be reset
*/
__attribute__((always_inline))
static inline bool axi_dma_ll_tx_is_reset_avail(axi_dma_dev_t *dev, uint32_t channel)
{
return dev->out_reset_avail_chn[channel].out_reset_avail_chn;
}

///////////////////////////////////// CRC-TX /////////////////////////////////////////

/**
Expand Down
16 changes: 13 additions & 3 deletions components/hal/esp32p4/include/hal/dma2d_ll.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
Expand Down Expand Up @@ -105,6 +105,16 @@ static inline void dma2d_ll_reset_register(int group_id)
/// the critical section needs to declare the __DECLARE_RCC_ATOMIC_ENV variable in advance
#define dma2d_ll_reset_register(...) (void)__DECLARE_RCC_ATOMIC_ENV; dma2d_ll_reset_register(__VA_ARGS__)

/**
* @brief Check if the bus clock is enabled for the DMA module
*/
__attribute__((always_inline))
static inline bool dma2d_ll_is_bus_clock_enabled(int group_id)
{
(void) group_id;
return HP_SYS_CLKRST.soc_clk_ctrl1.reg_dma2d_sys_clk_en;
}

/**
* @brief Enable 2D-DMA module
*/
Expand Down Expand Up @@ -278,7 +288,7 @@ static inline bool dma2d_ll_rx_is_reset_avail(dma2d_dev_t *dev, uint32_t channel
* @brief Disable 2D-DMA RX channel via a command
*/
__attribute__((always_inline))
static inline void dma2d_ll_rx_disable_cmd(dma2d_dev_t *dev, uint32_t channel, bool disable)
static inline void dma2d_ll_rx_abort(dma2d_dev_t *dev, uint32_t channel, bool disable)
{
volatile dma2d_in_conf0_chn_reg_t *reg = (volatile dma2d_in_conf0_chn_reg_t *)DMA2D_LL_IN_CHANNEL_GET_REG_ADDR(dev, channel, in_conf0);
reg->in_cmd_disable_chn = disable;
Expand Down Expand Up @@ -811,7 +821,7 @@ static inline bool dma2d_ll_tx_is_reset_avail(dma2d_dev_t *dev, uint32_t channel
* @brief Disable 2D-DMA TX channel via a command
*/
__attribute__((always_inline))
static inline void dma2d_ll_tx_disable_cmd(dma2d_dev_t *dev, uint32_t channel, bool disable)
static inline void dma2d_ll_tx_abort(dma2d_dev_t *dev, uint32_t channel, bool disable)
{
dev->out_channel[channel].out_conf0.out_cmd_disable_chn = disable;
}
Expand Down
20 changes: 16 additions & 4 deletions components/hal/esp32p4/include/hal/dw_gdma_ll.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
Expand All @@ -15,7 +15,7 @@
#include "soc/hp_sys_clkrst_struct.h"
#include "soc/reg_base.h"

#define DW_GDMA_LL_GET_HW() (&DW_GDMA)
#define DW_GDMA_LL_GET_HW(id) (((id) == 0) ? (&DW_GDMA) : NULL)

#define DW_GDMA_LL_GROUPS 1 // there's one DW-GDMA instance connected to the AXI bus
#define DW_GDMA_LL_CHANNELS_PER_GROUP 4 // there are 4 independent channels in the DW-GDMA
Expand Down Expand Up @@ -101,7 +101,7 @@ static inline void dw_gdma_ll_enable_bus_clock(int group_id, bool enable)
/**
* @brief Reset the DMA module
*/
static inline void dw_gdma_ll_reset_register(int group_id)
static inline void _dw_gdma_ll_reset_register(int group_id)
{
(void)group_id;
HP_SYS_CLKRST.hp_rst_en0.reg_rst_en_gdma = 1;
Expand All @@ -110,7 +110,17 @@ static inline void dw_gdma_ll_reset_register(int group_id)

/// use a macro to wrap the function, force the caller to use it in a critical section
/// the critical section needs to declare the __DECLARE_RCC_ATOMIC_ENV variable in advance
#define dw_gdma_ll_reset_register(...) (void)__DECLARE_RCC_ATOMIC_ENV; dw_gdma_ll_reset_register(__VA_ARGS__)
#define dw_gdma_ll_reset_register(...) (void)__DECLARE_RCC_ATOMIC_ENV; _dw_gdma_ll_reset_register(__VA_ARGS__)

/**
* @brief Check if the bus clock is enabled for the DMA module
*/
__attribute__((always_inline))
static inline bool dw_gdma_ll_is_bus_clock_enabled(int group_id)
{
(void) group_id;
return HP_SYS_CLKRST.soc_clk_ctrl1.reg_gdma_sys_clk_en && HP_SYS_CLKRST.soc_clk_ctrl0.reg_gdma_cpu_clk_en;
}

/**
* @brief Reset the DMA controller by software
Expand Down Expand Up @@ -320,10 +330,12 @@ static inline void dw_gdma_ll_channel_suspend(dw_gdma_dev_t *dev, uint8_t channe
* @param dev Pointer to the DW_GDMA registers
* @param channel Channel number
*/
__attribute__((always_inline))
static inline void dw_gdma_ll_channel_abort(dw_gdma_dev_t *dev, uint8_t channel)
{
// the abort bit clears itself after the abort is done
dev->chen1.val = 0x101 << channel;
while (dev->chen1.val & (0x101 << channel));
}

/**
Expand Down
15 changes: 14 additions & 1 deletion components/hal/esp32p4/include/hal/gdma_ll.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
Expand Down Expand Up @@ -108,6 +108,19 @@ static inline void _gdma_ll_enable_bus_clock(int group_id, bool enable)
/// the critical section needs to declare the __DECLARE_RCC_ATOMIC_ENV variable in advance
#define gdma_ll_enable_bus_clock(...) (void)__DECLARE_RCC_ATOMIC_ENV; _gdma_ll_enable_bus_clock(__VA_ARGS__)

/**
* @brief Check if the bus clock is enabled for the DMA module
*/
__attribute__((always_inline))
static inline bool gdma_ll_is_bus_clock_enabled(int group_id)
{
if (group_id == 0) {
return HP_SYS_CLKRST.soc_clk_ctrl1.reg_ahb_pdma_sys_clk_en;
} else {
return HP_SYS_CLKRST.soc_clk_ctrl1.reg_axi_pdma_sys_clk_en;
}
}

/**
* @brief Reset the DMA module
*/
Expand Down
4 changes: 2 additions & 2 deletions components/hal/esp32p4/include/hal/lcd_ll.h
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ static inline void lcd_ll_enable_bus_clock(int group_id, bool enable)
*
* @param group_id Group ID
*/
static inline void lcd_ll_reset_register(int group_id)
static inline void _lcd_ll_reset_register(int group_id)
{
(void)group_id;
HP_SYS_CLKRST.hp_rst_en2.reg_rst_en_lcdcam = 1;
Expand All @@ -72,7 +72,7 @@ static inline void lcd_ll_reset_register(int group_id)

/// use a macro to wrap the function, force the caller to use it in a critical section
/// the critical section needs to declare the __DECLARE_RCC_RC_ATOMIC_ENV variable in advance
#define lcd_ll_reset_register(...) (void)__DECLARE_RCC_RC_ATOMIC_ENV; lcd_ll_reset_register(__VA_ARGS__)
#define lcd_ll_reset_register(...) (void)__DECLARE_RCC_RC_ATOMIC_ENV; _lcd_ll_reset_register(__VA_ARGS__)

/**
* @brief Enable clock gating
Expand Down

0 comments on commit fbcbefe

Please sign in to comment.