From 78e47e3ebf84856cb1e167e969e517af41b1b1e4 Mon Sep 17 00:00:00 2001 From: Chen Jichang Date: Tue, 28 Apr 2026 15:30:51 +0800 Subject: [PATCH] feat(parlio): support parlio on s31 --- .../esp32s31/parlio_retention.c | 38 + components/esp_driver_parlio/src/parlio_rx.c | 4 - components/esp_driver_parlio/src/parlio_tx.c | 4 - .../test_apps/parlio/README.md | 4 +- .../test_apps/parlio/main/test_board.h | 20 + .../test_apps/parlio/main/test_parlio_sleep.c | 4 +- .../parlio/sdkconfig.defaults.esp32s31 | 3 + .../esp32s31/include/hal/parlio_ll.h | 754 ++++++++++++++++++ .../esp_hal_parlio/esp32s31/parlio_periph.c | 66 ++ .../esp_lcd/test_apps/parlio_lcd/README.md | 4 +- .../parlio_lcd/main/test_parlio_board.h | 14 + .../esp32s31/include/soc/Kconfig.soc_caps.in | 36 + .../soc/esp32s31/include/soc/clk_tree_defs.h | 18 + .../soc/esp32s31/include/soc/soc_caps.h | 12 +- .../soc/esp32s31/register/soc/parl_io_reg.h | 2 + .../esp32s31/register/soc/parl_io_struct.h | 8 +- .../peripherals/lcd/parlio_simulate/README.md | 4 +- .../sdkconfig.defaults.esp32s31 | 18 + .../parlio/parlio_rx/logic_analyzer/README.md | 4 +- .../advanced_rgb_led_matrix/README.md | 4 +- .../pytest_advanced_rgb_led_matrix.py | 2 +- .../sdkconfig.defaults.esp32s31 | 13 + .../parlio_tx/simple_rgb_led_matrix/README.md | 4 +- .../sdkconfig.defaults.esp32s31 | 13 + 24 files changed, 1027 insertions(+), 26 deletions(-) create mode 100644 components/esp_driver_parlio/esp32s31/parlio_retention.c create mode 100644 components/esp_driver_parlio/test_apps/parlio/sdkconfig.defaults.esp32s31 create mode 100644 components/esp_hal_parlio/esp32s31/include/hal/parlio_ll.h create mode 100644 components/esp_hal_parlio/esp32s31/parlio_periph.c create mode 100644 examples/peripherals/lcd/parlio_simulate/sdkconfig.defaults.esp32s31 create mode 100644 examples/peripherals/parlio/parlio_tx/advanced_rgb_led_matrix/sdkconfig.defaults.esp32s31 create mode 100644 examples/peripherals/parlio/parlio_tx/simple_rgb_led_matrix/sdkconfig.defaults.esp32s31 diff --git a/components/esp_driver_parlio/esp32s31/parlio_retention.c b/components/esp_driver_parlio/esp32s31/parlio_retention.c new file mode 100644 index 00000000000..25059e32683 --- /dev/null +++ b/components/esp_driver_parlio/esp32s31/parlio_retention.c @@ -0,0 +1,38 @@ +/* + * SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "parlio_priv.h" + +/** + * PARLIO Registers to be saved during sleep retention + * - Tx Configuration registers, e.g.: PARL_IO_TX_DATA_CFG_REG, PARL_IO_TX_GENRL_CFG_REG + * - Rx Configuration registers, e.g.: PARL_IO_RX_MODE_CFG_REG, PARL_IO_RX_DATA_CFG_REG, PARL_IO_RX_GENRL_CFG_REG + * - CLK Configuration registers, e.g.: PARL_IO_RX_CLK_CFG_REG, PARL_IO_TX_CLK_CFG_REG + * - Interrupt enable registers, e.g.: PARL_IO_INT_ENA_REG + */ +#define PARLIO_RETENTION_REGS_CNT 8 +#define PARLIO_RETENTION_REGS_BASE (DR_REG_PARL_IO_BASE + 0x0) +static const uint32_t parlio_regs_map[4] = {0x60457, 0x0, 0x0, 0x0}; +static const regdma_entries_config_t parlio_regs_retention[] = { + // backup stage: save configuration registers + // restore stage: restore the configuration registers + [0] = { + .config = REGDMA_LINK_ADDR_MAP_INIT(REGDMA_PARLIO_LINK(0x00), + PARLIO_RETENTION_REGS_BASE, PARLIO_RETENTION_REGS_BASE, + PARLIO_RETENTION_REGS_CNT, 0, 0, + parlio_regs_map[0], parlio_regs_map[1], + parlio_regs_map[2], parlio_regs_map[3]), + .owner = ENTRY(0) | ENTRY(2) + }, +}; + +const parlio_retention_desc_t parlio_retention_infos[1] = { + [0] = { + .regdma_entry_array = parlio_regs_retention, + .array_size = ARRAY_SIZE(parlio_regs_retention), + .retention_module = SLEEP_RETENTION_MODULE_PARLIO0 + }, +}; diff --git a/components/esp_driver_parlio/src/parlio_rx.c b/components/esp_driver_parlio/src/parlio_rx.c index 30723a7456e..4bc92783a37 100644 --- a/components/esp_driver_parlio/src/parlio_rx.c +++ b/components/esp_driver_parlio/src/parlio_rx.c @@ -10,7 +10,6 @@ #include "driver/gpio.h" #include "driver/parlio_rx.h" #include "parlio_priv.h" -#include "esp_sleep.h" #define ALIGN_UP(num, align) (((num) + ((align) - 1)) & ~((align) - 1)) @@ -615,9 +614,6 @@ esp_err_t parlio_new_rx_unit(const parlio_rx_unit_config_t *config, parlio_rx_un #if !SOC_PARLIO_SUPPORT_SLEEP_RETENTION ESP_RETURN_ON_FALSE(config->flags.allow_pd == 0, ESP_ERR_NOT_SUPPORTED, TAG, "register back up is not supported"); -#if SOC_PM_SUPPORT_TOP_PD - esp_sleep_pd_config(ESP_PD_DOMAIN_TOP, ESP_PD_OPTION_ON); //IDF-15645 -#endif #endif // SOC_PARLIO_SUPPORT_SLEEP_RETENTION /* Allocate unit memory */ diff --git a/components/esp_driver_parlio/src/parlio_tx.c b/components/esp_driver_parlio/src/parlio_tx.c index f7cdb133695..f8f37672b3a 100644 --- a/components/esp_driver_parlio/src/parlio_tx.c +++ b/components/esp_driver_parlio/src/parlio_tx.c @@ -9,7 +9,6 @@ #include "driver/gpio.h" #include "driver/parlio_tx.h" #include "parlio_priv.h" -#include "esp_sleep.h" #if SOC_PARLIO_TX_SUPPORT_LOOP_TRANSMISSION static bool parlio_tx_gdma_eof_callback(gdma_channel_handle_t dma_chan, gdma_event_data_t *event_data, void *user_data); @@ -274,9 +273,6 @@ esp_err_t parlio_new_tx_unit(const parlio_tx_unit_config_t *config, parlio_tx_un #if !SOC_PARLIO_SUPPORT_SLEEP_RETENTION ESP_RETURN_ON_FALSE(config->flags.allow_pd == 0, ESP_ERR_NOT_SUPPORTED, TAG, "register back up is not supported"); -#if SOC_PM_SUPPORT_TOP_PD - esp_sleep_pd_config(ESP_PD_DOMAIN_TOP, ESP_PD_OPTION_ON); //IDF-15645 -#endif #endif // SOC_PARLIO_SUPPORT_SLEEP_RETENTION // allocate unit from internal memory because it contains atomic member diff --git a/components/esp_driver_parlio/test_apps/parlio/README.md b/components/esp_driver_parlio/test_apps/parlio/README.md index bb8242f6792..62aa0e31fe7 100644 --- a/components/esp_driver_parlio/test_apps/parlio/README.md +++ b/components/esp_driver_parlio/test_apps/parlio/README.md @@ -1,2 +1,2 @@ -| Supported Targets | ESP32-C5 | ESP32-C6 | ESP32-H2 | ESP32-H21 | ESP32-H4 | ESP32-P4 | -| ----------------- | -------- | -------- | -------- | --------- | -------- | -------- | +| Supported Targets | ESP32-C5 | ESP32-C6 | ESP32-H2 | ESP32-H21 | ESP32-H4 | ESP32-P4 | ESP32-S31 | +| ----------------- | -------- | -------- | -------- | --------- | -------- | -------- | --------- | diff --git a/components/esp_driver_parlio/test_apps/parlio/main/test_board.h b/components/esp_driver_parlio/test_apps/parlio/main/test_board.h index 181daa05ca8..beb4e936da8 100644 --- a/components/esp_driver_parlio/test_apps/parlio/main/test_board.h +++ b/components/esp_driver_parlio/test_apps/parlio/main/test_board.h @@ -80,6 +80,26 @@ extern "C" { #define TEST_DATA5_GPIO 5 #define TEST_DATA6_GPIO 13 #define TEST_DATA7_GPIO 14 +#elif CONFIG_IDF_TARGET_ESP32S31 +#define TEST_CLK_GPIO 15 +#define TEST_EXT_CLK_GPIO 16 +#define TEST_VALID_GPIO 17 +#define TEST_DATA0_GPIO 0 +#define TEST_DATA1_GPIO 1 +#define TEST_DATA2_GPIO 2 +#define TEST_DATA3_GPIO 3 +#define TEST_DATA4_GPIO 4 +#define TEST_DATA5_GPIO 5 +#define TEST_DATA6_GPIO 13 +#define TEST_DATA7_GPIO 14 +#define TEST_DATA8_GPIO 18 +#define TEST_DATA9_GPIO 19 +#define TEST_DATA10_GPIO 34 +#define TEST_DATA11_GPIO 35 +#define TEST_DATA12_GPIO 36 +#define TEST_DATA13_GPIO 37 +#define TEST_DATA14_GPIO 38 +#define TEST_DATA15_GPIO 39 #elif CONFIG_IDF_TARGET_ESP32P4 #define TEST_CLK_GPIO 33 #define TEST_EXT_CLK_GPIO 34 diff --git a/components/esp_driver_parlio/test_apps/parlio/main/test_parlio_sleep.c b/components/esp_driver_parlio/test_apps/parlio/main/test_parlio_sleep.c index 67058c58a8e..64117ae0821 100644 --- a/components/esp_driver_parlio/test_apps/parlio/main/test_parlio_sleep.c +++ b/components/esp_driver_parlio/test_apps/parlio/main/test_parlio_sleep.c @@ -133,7 +133,7 @@ static void test_parlio_sleep_retention(bool allow_pd) printf("check if the sleep happened as expected\r\n"); TEST_ASSERT_EQUAL(0, sleep_ctx.sleep_request_result); -#if SOC_PARLIO_SUPPORT_SLEEP_RETENTION +#if SOC_PARLIO_SUPPORT_SLEEP_RETENTION && SOC_GDMA_SUPPORT_SLEEP_RETENTION // check if the power domain also is powered down TEST_ASSERT_EQUAL(allow_pd ? PMU_SLEEP_PD_TOP : 0, (sleep_ctx.sleep_flags) & PMU_SLEEP_PD_TOP); #endif @@ -162,7 +162,7 @@ static void test_parlio_sleep_retention(bool allow_pd) TEST_CASE("parlio light sleep", "[parlio]") { test_parlio_sleep_retention(false); -#if SOC_PARLIO_SUPPORT_SLEEP_RETENTION +#if SOC_PARLIO_SUPPORT_SLEEP_RETENTION && SOC_GDMA_SUPPORT_SLEEP_RETENTION test_parlio_sleep_retention(true); #endif } diff --git a/components/esp_driver_parlio/test_apps/parlio/sdkconfig.defaults.esp32s31 b/components/esp_driver_parlio/test_apps/parlio/sdkconfig.defaults.esp32s31 new file mode 100644 index 00000000000..4f908a3127b --- /dev/null +++ b/components/esp_driver_parlio/test_apps/parlio/sdkconfig.defaults.esp32s31 @@ -0,0 +1,3 @@ +CONFIG_SPIRAM=y +CONFIG_SPIRAM_SPEED_250M=y +CONFIG_SPIRAM_MALLOC_ALWAYSINTERNAL=0 diff --git a/components/esp_hal_parlio/esp32s31/include/hal/parlio_ll.h b/components/esp_hal_parlio/esp32s31/include/hal/parlio_ll.h new file mode 100644 index 00000000000..98559a9c84b --- /dev/null +++ b/components/esp_hal_parlio/esp32s31/include/hal/parlio_ll.h @@ -0,0 +1,754 @@ +/* + * SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +// Note that most of the register operations in this layer are non-atomic operations. + +#pragma once + +#include +#include +#include "hal/assert.h" +#include "hal/misc.h" +#include "hal/hal_utils.h" +#include "soc/hp_alive_sys_struct.h" +#include "soc/hp_sys_clkrst_struct.h" +#include "soc/hp_sys_clkrst_reg.h" +#include "soc/parl_io_struct.h" +#include "soc/parl_io_reg.h" +#include "hal/parlio_types.h" + +#define PARLIO_LL_GET(attr) (PARLIO_LL_ ## attr) +#define PARLIO_LL_SUPPORT(feat) (PARLIO_LL_SUPPORT_ ## feat) +#define PARLIO_LL_INST_NUM 1 /*!< Number of parallel IO peripherals */ +#define PARLIO_LL_TX_UNITS_PER_INST 1 /*!< number of TX units in each instance */ +#define PARLIO_LL_RX_UNITS_PER_INST 1 /*!< number of RX units in each instance */ +#define PARLIO_LL_SUPPORT_RX_CLK_OUTPUT 1 /*!< Support output RX clock to a GPIO */ +#define PARLIO_LL_SUPPORT_TRANS_BIT_ALIGN 1 /*!< Support bit alignment in transaction */ +#define PARLIO_LL_SUPPORT_TX_EOF_FROM_DMA 1 /*!< Support to treat DMA EOF as TX unit EOF */ + +#define PARLIO_LL_RX_MAX_BYTES_PER_FRAME (PARL_IO_RX_BITLEN_V / 8) +#define PARLIO_LL_RX_MAX_CLK_INT_DIV (HP_SYS_CLKRST_REG_PARLIO_RX_CLK_DIV_NUM_V + 1) +#define PARLIO_LL_RX_MAX_CLK_FRACT_DIV (HP_SYS_CLKRST_REG_PARLIO_RX_CLK_DIV_DENOMINATOR_V + 1) +#define PARLIO_LL_RX_MAX_TIMEOUT PARL_IO_RX_TIMEOUT_THRES_V + +#define PARLIO_LL_TX_MAX_BITS_PER_FRAME PARL_IO_TX_BITLEN_V +#define PARLIO_LL_TX_MAX_CLK_INT_DIV (HP_SYS_CLKRST_REG_PARLIO_TX_CLK_DIV_NUM_V + 1) +#define PARLIO_LL_TX_MAX_CLK_FRACT_DIV (HP_SYS_CLKRST_REG_PARLIO_TX_CLK_DIV_DENOMINATOR_V + 1) + +#define PARLIO_LL_EVENT_TX_FIFO_EMPTY (1 << 0) +#define PARLIO_LL_EVENT_RX_FIFO_FULL (1 << 1) +#define PARLIO_LL_EVENT_TX_EOF (1 << 2) +#define PARLIO_LL_EVENT_TX_MASK (PARLIO_LL_EVENT_TX_FIFO_EMPTY | PARLIO_LL_EVENT_TX_EOF) +#define PARLIO_LL_EVENT_RX_MASK (PARLIO_LL_EVENT_RX_FIFO_FULL) + +#define PARLIO_LL_TX_DATA_LINE_AS_CLK_GATE 15 // TXD[15] can be used as clock gate signal +#define PARLIO_LL_TX_VALID_MAX_START_DELAY PARL_IO_TX_CS_START_DELAY_V +#define PARLIO_LL_TX_VALID_MAX_STOP_DELAY PARL_IO_TX_CS_STOP_DELAY_V +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum { + PARLIO_LL_RX_EOF_COND_RX_FULL, /*!< RX unit generates EOF event when it receives enough data */ + PARLIO_LL_RX_EOF_COND_EN_INACTIVE, /*!< RX unit generates EOF event when the external enable signal becomes inactive */ +} parlio_ll_rx_eof_cond_t; + +typedef enum { + PARLIO_LL_TX_EOF_COND_DATA_LEN, /*!< TX unit generates EOF event when it transmits particular data bit length that specified in `tx_bitlen`. */ + PARLIO_LL_TX_EOF_COND_DMA_EOF, /*!< TX unit generates EOF event when the DMA EOF takes place */ +} parlio_ll_tx_eof_cond_t; + +/** + * @brief Enable or disable the parlio peripheral APB clock + * + * @param group_id The group id of the parlio module + * @param enable Set true to enable, false to disable + */ +static inline void parlio_ll_enable_bus_clock(int group_id, bool enable) +{ + (void)group_id; + HP_SYS_CLKRST.parlio_ctrl0.reg_parlio_sys_clk_en = enable; + HP_SYS_CLKRST.parlio_ctrl0.reg_parlio_apb_clk_en = enable; +} + +/** + * @brief Reset the parlio module + * + * @param group_id The group id of the parlio module + */ +static inline void parlio_ll_reset_register(int group_id) +{ + (void)group_id; + HP_SYS_CLKRST.parlio_ctrl0.reg_parlio_rst_en = 1; + HP_SYS_CLKRST.parlio_ctrl0.reg_parlio_rst_en = 0; +} + +///////////////////////////////////////RX Unit/////////////////////////////////////// + +/** + * @brief Set the clock source for the RX unit + * + * @param dev Parallel IO register base address + * @param src Clock source + */ +static inline void _parlio_ll_rx_set_clock_source(parl_io_dev_t *dev, parlio_clock_source_t src) +{ + (void)dev; + uint32_t clk_sel = 0; + switch (src) { + case PARLIO_CLK_SRC_XTAL: + clk_sel = 0; + break; + case PARLIO_CLK_SRC_RC_FAST: + clk_sel = 1; + break; + case PARLIO_CLK_SRC_PLL_F160M: + clk_sel = 2; + break; + case PARLIO_CLK_SRC_EXTERNAL: + clk_sel = 3; + break; + + default: // unsupported clock source + HAL_ASSERT(false); + break; + } + HP_ALIVE_SYS.hp_pad_parlio_ctrl.hp_pad_parlio_rx_clk_en = (src == PARLIO_CLK_SRC_EXTERNAL); + HP_SYS_CLKRST.parlio_rx_ctrl0.reg_parlio_rx_clk_src_sel = clk_sel; +} + +/// 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 parlio_ll_rx_set_clock_source(...) do { \ + (void)__DECLARE_RCC_ATOMIC_ENV; \ + _parlio_ll_rx_set_clock_source(__VA_ARGS__); \ + } while(0) + +/** + * @brief Set the clock divider for the RX unit + * + * @param dev Parallel IO register base address + * @param clk_div Clock division with integral and decimal parts + */ +static inline void parlio_ll_rx_set_clock_div(parl_io_dev_t *dev, const hal_utils_clk_div_t *clk_div) +{ + (void)dev; + HAL_ASSERT(clk_div->integer > 0 && clk_div->integer <= PARLIO_LL_RX_MAX_CLK_INT_DIV); + HAL_FORCE_MODIFY_U32_REG_FIELD(HP_SYS_CLKRST.parlio_rx_ctrl0, reg_parlio_rx_clk_div_num, clk_div->integer - 1); + HAL_FORCE_MODIFY_U32_REG_FIELD(HP_SYS_CLKRST.parlio_rx_ctrl0, reg_parlio_rx_clk_div_denominator, clk_div->denominator); + HAL_FORCE_MODIFY_U32_REG_FIELD(HP_SYS_CLKRST.parlio_rx_ctrl0, reg_parlio_rx_clk_div_numerator, clk_div->numerator); +} + +/** + * @brief Reset the RX unit Core clock domain + * + * @param dev Parallel IO register base address + */ +static inline void parlio_ll_rx_reset_clock(parl_io_dev_t *dev) +{ + (void)dev; + HP_SYS_CLKRST.parlio_rx_ctrl0.reg_parlio_rx_rst_en = 1; + HP_SYS_CLKRST.parlio_rx_ctrl0.reg_parlio_rx_rst_en = 0; +} + +/** + * @brief Enable the RX unit Core clock domain + * + * @param dev Parallel IO register base address + * @param en True to enable, False to disable + */ +__attribute__((always_inline)) +static inline void parlio_ll_rx_enable_clock(parl_io_dev_t *dev, bool en) +{ + (void)dev; + HP_SYS_CLKRST.parlio_rx_ctrl0.reg_parlio_rx_clk_en = en; +} + +/** + * @brief Set the condition to generate the RX EOF event + * + * @param dev Parallel IO register base address + * @param cond RX EOF condition + */ +__attribute__((always_inline)) +static inline void parlio_ll_rx_set_eof_condition(parl_io_dev_t *dev, parlio_ll_rx_eof_cond_t cond) +{ + dev->rx_genrl_cfg.rx_eof_gen_sel = cond; +} + +/** + * @brief Start RX unit to sample the input data + * + * @param dev Parallel IO register base address + * @param en True to start, False to stop + */ +__attribute__((always_inline)) +static inline void parlio_ll_rx_start(parl_io_dev_t *dev, bool en) +{ + dev->rx_start_cfg.rx_start = en; +} + +/** + * @brief Set the receive length + * + * @note The receive length can be used to generate DMA EOF signal, or to work as a frame end delimiter + * + * @param dev Parallel IO register base address + * @param bitlen Number of bits to receive in the next transaction, bitlen must be a multiple of 8 + */ +__attribute__((always_inline)) +static inline void parlio_ll_rx_set_recv_bit_len(parl_io_dev_t *dev, uint32_t bitlen) +{ + dev->rx_data_cfg.rx_bitlen = bitlen; +} + +/** + * @brief Set the sub mode of the level controlled receive mode + * + * @param dev Parallel IO register base address + * @param active_low_en Level of the external enable signal, true for active low, false for active high + */ +__attribute__((always_inline)) +static inline void parlio_ll_rx_set_level_recv_mode(parl_io_dev_t *dev, bool active_low_en) +{ + dev->rx_mode_cfg.rx_smp_mode_sel = 0; + dev->rx_mode_cfg.rx_ext_en_inv = active_low_en; +} + +/** + * @brief Set the sub mode of the pulse controlled receive mode + * + * @param dev Parallel IO register base address + * @param start_inc Whether the start pulse is counted + * @param end_inc Whether the end pulse is counted + * @param end_by_len Whether to use the frame length to determine the end of the frame + * @param pulse_inv Whether the pulse is inverted + */ +__attribute__((always_inline)) +static inline void parlio_ll_rx_set_pulse_recv_mode(parl_io_dev_t *dev, bool start_inc, bool end_inc, bool end_by_len, bool pulse_inv) +{ + uint32_t submode = 0; + uint32_t step = 1; + if (end_by_len) { + submode += 4; + } else { // end by pulse + step = 2; + if (!end_inc) { + submode += 1; + } + } + if (!start_inc) { + submode += step; + } + dev->rx_mode_cfg.rx_smp_mode_sel = 1; + dev->rx_mode_cfg.rx_pulse_submode_sel = submode; + dev->rx_mode_cfg.rx_ext_en_inv = pulse_inv; +} + +/** + * @brief Set the receive mode to software controlled receive mode + * + * @param dev Parallel IO register base address + */ +__attribute__((always_inline)) +static inline void parlio_ll_rx_set_soft_recv_mode(parl_io_dev_t *dev) +{ + dev->rx_mode_cfg.rx_smp_mode_sel = 2; +} + +/** + * @brief Whether to start the software controlled receive mode + * + * @param dev Parallel IO register base address + * @param en True to enable, False to disable + */ +static inline void parlio_ll_rx_start_soft_recv(parl_io_dev_t *dev, bool en) +{ + dev->rx_mode_cfg.rx_sw_en = en; +} + +/** + * @brief Set the sample clock edge + * + * @param dev Parallel IO register base address + * @param edge Sample clock edge + */ +__attribute__((always_inline)) +static inline void parlio_ll_rx_set_sample_clock_edge(parl_io_dev_t *dev, parlio_sample_edge_t edge) +{ + bool invert = edge == PARLIO_SAMPLE_EDGE_NEG; + dev->rx_clk_cfg.rx_clk_i_inv = invert; + dev->rx_clk_cfg.rx_clk_o_inv = invert; +} + +/** + * @brief Set the order to pack bits into one byte + * + * @param dev Parallel IO register base address + * @param order Packing order + */ +__attribute__((always_inline)) +static inline void parlio_ll_rx_set_bit_pack_order(parl_io_dev_t *dev, parlio_bit_pack_order_t order) +{ + dev->rx_data_cfg.rx_data_order_inv = order; +} + +/** + * @brief Set the bus width of the RX unit + * + * @param dev Parallel IO register base address + * @param width Bus width + */ +static inline void parlio_ll_rx_set_bus_width(parl_io_dev_t *dev, uint32_t width) +{ + uint32_t width_sel = 0; + switch (width) { + case 16: + width_sel = 4; + break; + case 8: + width_sel = 3; + break; + case 4: + width_sel = 2; + break; + case 2: + width_sel = 1; + break; + case 1: + width_sel = 0; + break; + default: + HAL_ASSERT(false); + } + dev->rx_data_cfg.rx_bus_wid_sel = width_sel; +} + +/** + * @brief Reset RX Async FIFO + * + * @note During the reset of the asynchronous FIFO, it takes two clock cycles to synchronize within AHB clock domain (GDMA) and Core clock domain. + * The reset synchronization must be performed two clock cycles in advance. + * @note If the next frame transfer needs to be reset, you need to first switch to the internal free-running clock, + * and then switch to the actual clock after the reset is completed. + * + * @param dev Parallel IO register base address + */ +static inline void parlio_ll_rx_reset_fifo(parl_io_dev_t *dev) +{ + dev->fifo_cfg.rx_fifo_srst = 1; + dev->fifo_cfg.rx_fifo_srst = 0; +} + +/** + * @brief Set which data line as the enable signal + * + * @param dev Parallel IO register base address + * @param line_num Data line number (0-15) + */ +__attribute__((always_inline)) +static inline void parlio_ll_rx_treat_data_line_as_en(parl_io_dev_t *dev, uint32_t line_num) +{ + dev->rx_mode_cfg.rx_ext_en_sel = line_num; +} + +/** + * @brief Whether to enable the RX clock gating + * + * @param dev Parallel IO register base address + * @param en True to enable, False to disable + */ +static inline void parlio_ll_rx_enable_clock_gating(parl_io_dev_t *dev, bool en) +{ + dev->rx_genrl_cfg.rx_gating_en = en; +} + +/** + * @brief Enable RX timeout feature + * + * @param dev Parallel IO register base address + * @param en True to enable, False to disable + */ +__attribute__((always_inline)) +static inline void parlio_ll_rx_enable_timeout(parl_io_dev_t *dev, bool en) +{ + dev->rx_genrl_cfg.rx_timeout_en = en; +} + +/** + * @brief Set the threshold of RX timeout + * + * @param dev Parallel IO register base address + * @param thres Threshold of RX timeout + */ +__attribute__((always_inline)) +static inline void parlio_ll_rx_set_timeout_thres(parl_io_dev_t *dev, uint32_t thres) +{ + HAL_FORCE_MODIFY_U32_REG_FIELD(dev->rx_genrl_cfg, rx_timeout_thres, thres); +} + +/** + * @brief Update the RX configuration, to make the new configuration take effect + * + * @param dev Parallel IO register base address + */ +__attribute__((always_inline)) +static inline void parlio_ll_rx_update_config(parl_io_dev_t *dev) +{ + dev->reg_update.rx_reg_update = 1; + while (dev->reg_update.rx_reg_update); +} + +/** + * @brief Get the RX fifo cycle count + * + * @param dev Parallel IO register base address + * @return + * - RX fifo cycle count + */ +static inline uint32_t parlio_ll_rx_get_fifo_cycle_cnt(parl_io_dev_t *dev) +{ + return dev->rx_st0.rx_cnt; +} + +///////////////////////////////////TX Unit/////////////////////////////////////// + +/** + * @brief Set the clock source for the TX unit + * + * @param dev Parallel IO register base address + * @param src Clock source + */ +__attribute__((always_inline)) +static inline void _parlio_ll_tx_set_clock_source(parl_io_dev_t *dev, parlio_clock_source_t src) +{ + (void)dev; + uint32_t clk_sel = 0; + switch (src) { + case PARLIO_CLK_SRC_XTAL: + clk_sel = 0; + break; + case PARLIO_CLK_SRC_RC_FAST: + clk_sel = 1; + break; + case PARLIO_CLK_SRC_PLL_F160M: + clk_sel = 2; + break; + case PARLIO_CLK_SRC_EXTERNAL: + clk_sel = 3; + break; + + default: // unsupported clock source + HAL_ASSERT(false); + break; + } + HP_ALIVE_SYS.hp_pad_parlio_ctrl.hp_pad_parlio_tx_clk_en = (src == PARLIO_CLK_SRC_EXTERNAL); + HP_SYS_CLKRST.parlio_tx_ctrl0.reg_parlio_tx_clk_src_sel = clk_sel; +} + +/// 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 parlio_ll_tx_set_clock_source(...) do { \ + (void)__DECLARE_RCC_ATOMIC_ENV; \ + _parlio_ll_tx_set_clock_source(__VA_ARGS__); \ + } while(0) + +/** + * @brief Set the clock divider for the TX unit + * + * @param dev Parallel IO register base address + * @param clk_div Clock division with integral and decimal parts + */ +static inline void parlio_ll_tx_set_clock_div(parl_io_dev_t *dev, const hal_utils_clk_div_t *clk_div) +{ + (void)dev; + HAL_ASSERT(clk_div->integer > 0 && clk_div->integer <= PARLIO_LL_RX_MAX_CLK_INT_DIV); + HAL_FORCE_MODIFY_U32_REG_FIELD(HP_SYS_CLKRST.parlio_tx_ctrl0, reg_parlio_tx_clk_div_num, clk_div->integer - 1); + HAL_FORCE_MODIFY_U32_REG_FIELD(HP_SYS_CLKRST.parlio_tx_ctrl0, reg_parlio_tx_clk_div_denominator, clk_div->denominator); + HAL_FORCE_MODIFY_U32_REG_FIELD(HP_SYS_CLKRST.parlio_tx_ctrl0, reg_parlio_tx_clk_div_numerator, clk_div->numerator); +} + +/** + * @brief Reset the TX unit Core clock domain + * + * @param dev Parallel IO register base address + */ +__attribute__((always_inline)) +static inline void parlio_ll_tx_reset_clock(parl_io_dev_t *dev) +{ + (void)dev; + HP_SYS_CLKRST.parlio_tx_ctrl0.reg_parlio_tx_rst_en = 1; + HP_SYS_CLKRST.parlio_tx_ctrl0.reg_parlio_tx_rst_en = 0; +} + +/** + * @brief Enable the TX unit Core clock domain + * + * @param dev Parallel IO register base address + * @param en True to enable, False to disable + */ +__attribute__((always_inline)) +static inline void parlio_ll_tx_enable_clock(parl_io_dev_t *dev, bool en) +{ + (void)dev; + HP_SYS_CLKRST.parlio_tx_ctrl0.reg_parlio_tx_clk_en = en; +} + +/** + * @brief Set the data length to be transmitted + * + * @param dev Parallel IO register base address + * @param bitlen Data length in bits, must be a multiple of 8 + */ +__attribute__((always_inline)) +static inline void parlio_ll_tx_set_trans_bit_len(parl_io_dev_t *dev, uint32_t bitlen) +{ + dev->tx_data_cfg.tx_bitlen = bitlen; +} + +/** + * @brief Check if tx size can be determined by DMA + * + * @param dev Parallel IO register base address (not used) + */ +static inline bool parlio_ll_tx_support_dma_eof(parl_io_dev_t *dev) +{ + (void)dev; + return true; +} + +/** + * @brief Set the condition to generate the TX EOF event + * + * @param dev Parallel IO register base address + * @param cond TX EOF condition + */ +__attribute__((always_inline)) +static inline void parlio_ll_tx_set_eof_condition(parl_io_dev_t *dev, parlio_ll_tx_eof_cond_t cond) +{ + dev->tx_genrl_cfg.tx_eof_gen_sel = cond; +} + +/** + * @brief Whether to enable the TX clock gating + * + * @note The MSB of TXD will be taken as the gating enable signal + * + * @param dev Parallel IO register base address + * @param en True to enable, False to disable + */ +static inline void parlio_ll_tx_enable_clock_gating(parl_io_dev_t *dev, bool en) +{ + dev->tx_genrl_cfg.tx_gating_en = en; +} + +/** + * @brief Start TX unit to transmit data + * + * @note The hardware monitors the rising edge of tx_start as the trigger signal. + * Once the transmission starts, it cannot be stopped by clearing tx_start. + * + * @param dev Parallel IO register base address + * @param en True to start, False to reset the reg state (not meaning the TX unit will be stopped) + */ +__attribute__((always_inline)) +static inline void parlio_ll_tx_start(parl_io_dev_t *dev, bool en) +{ + dev->tx_start_cfg.tx_start = en; +} + +/** + * @brief Set the clock gating from the valid signal + * + * @param dev Parallel IO register base address + * @param en If set to true, the clock is gated by the valid signal, otherwise it is gated by the MSB of the data line. + */ +static inline void parlio_ll_tx_clock_gating_from_valid(parl_io_dev_t *dev, bool en) +{ + dev->tx_genrl_cfg.tx_valid_output_en = en; +} + +/** + * @brief Set TX valid signal delay + * + * @param dev Parallel IO register base address + * @param start_delay Number of clock cycles to delay + * @param stop_delay Number of clock cycles to delay + * @return true: success, false: valid delay is not supported + */ +static inline bool parlio_ll_tx_set_valid_delay(parl_io_dev_t *dev, uint32_t start_delay, uint32_t stop_delay) +{ + if (start_delay > PARLIO_LL_TX_VALID_MAX_START_DELAY || stop_delay > PARLIO_LL_TX_VALID_MAX_STOP_DELAY) { + return false; + } + HAL_FORCE_MODIFY_U32_REG_FIELD(dev->tx_cs_cfg, tx_cs_start_delay, start_delay); + HAL_FORCE_MODIFY_U32_REG_FIELD(dev->tx_cs_cfg, tx_cs_stop_delay, stop_delay); + return true; +} + +/** + * @brief Set the shift clock edge + * + * @param dev Parallel IO register base address + * @param edge Shift clock edge + */ +static inline void parlio_ll_tx_set_shift_clock_edge(parl_io_dev_t *dev, parlio_shift_edge_t edge) +{ + dev->tx_clk_cfg.tx_clk_i_inv = edge; + dev->tx_clk_cfg.tx_clk_o_inv = edge; +} + +/** + * @brief Set the order to unpack bits from a byte + * + * @param dev Parallel IO register base address + * @param order Packing order + */ +static inline void parlio_ll_tx_set_bit_pack_order(parl_io_dev_t *dev, parlio_bit_pack_order_t order) +{ + dev->tx_data_cfg.tx_data_order_inv = order; +} + +/** + * @brief Set the bus width of the TX unit + * + * @param dev Parallel IO register base address + * @param width Bus width + */ +static inline void parlio_ll_tx_set_bus_width(parl_io_dev_t *dev, uint32_t width) +{ + uint32_t width_sel = 0; + switch (width) { + case 16: + width_sel = 4; + break; + case 8: + width_sel = 3; + break; + case 4: + width_sel = 2; + break; + case 2: + width_sel = 1; + break; + case 1: + width_sel = 0; + break; + default: + HAL_ASSERT(false); + } + dev->tx_data_cfg.tx_bus_wid_sel = width_sel; +} + +/** + * @brief Reset TX Async FIFO + * + * @note During the reset of the asynchronous FIFO, it takes two clock cycles to synchronize within AHB clock domain (GDMA) and Core clock domain. + * The reset synchronization must be performed two clock cycles in advance. + * @note If the next frame transfer needs to be reset, you need to first switch to the internal free-running clock, + * and then switch to the actual clock after the reset is completed. + * + * @param dev Parallel IO register base address + */ +__attribute__((always_inline)) +static inline void parlio_ll_tx_reset_fifo(parl_io_dev_t *dev) +{ + dev->fifo_cfg.tx_fifo_srst = 1; + dev->fifo_cfg.tx_fifo_srst = 0; +} + +/** + * @brief Set the value to output on the TXD when the TX unit is in IDLE state + * + * @param dev Parallel IO register base address + * @param value Value to output + */ +__attribute__((always_inline)) +static inline void parlio_ll_tx_set_idle_data_value(parl_io_dev_t *dev, uint32_t value) +{ + HAL_FORCE_MODIFY_U32_REG_FIELD(dev->tx_genrl_cfg, tx_idle_value, value); +} + +/** + * @brief Check whether the TX unit is ready + * + * @param dev Parallel IO register base address + * @return true: ready, false: busy + */ +__attribute__((always_inline)) +static inline bool parlio_ll_tx_is_ready(parl_io_dev_t *dev) +{ + return dev->st.tx_ready; +} + +////////////////////////////////////Interrupt//////////////////////////////////////////////// + +/** + * @brief Enable Parallel IO interrupt for specific event mask + * + * @param dev Parallel IO register base address + * @param mask Event mask + * @param enable True to enable, False to disable + */ +static inline void parlio_ll_enable_interrupt(parl_io_dev_t *dev, uint32_t mask, bool enable) +{ + if (enable) { + dev->int_ena.val |= mask; + } else { + dev->int_ena.val &= ~mask; + } +} + +/** + * @brief Get interrupt status for TX unit + * + * @param dev Parallel IO register base address + * @return Interrupt status + */ +__attribute__((always_inline)) +static inline uint32_t parlio_ll_tx_get_interrupt_status(parl_io_dev_t *dev) +{ + return dev->int_st.val & PARLIO_LL_EVENT_TX_MASK; +} + +/** + * @brief Get interrupt status for RX unit + * + * @param dev Parallel IO register base address + * @return Interrupt status + */ +__attribute__((always_inline)) +static inline uint32_t parlio_ll_rx_get_interrupt_status(parl_io_dev_t *dev) +{ + return dev->int_st.val & PARLIO_LL_EVENT_RX_MASK; +} + +/** + * @brief Clear Parallel IO interrupt status by mask + * + * @param dev Parallel IO register base address + * @param mask Interrupt status mask + */ +__attribute__((always_inline)) +static inline void parlio_ll_clear_interrupt_status(parl_io_dev_t *dev, uint32_t mask) +{ + dev->int_clr.val = mask; +} + +/** + * @brief Get interrupt status register address + * + * @param dev Parallel IO register base address + * @return Register address + */ +static inline volatile void *parlio_ll_get_interrupt_status_reg(parl_io_dev_t *dev) +{ + return &dev->int_st; +} + +#ifdef __cplusplus +} +#endif diff --git a/components/esp_hal_parlio/esp32s31/parlio_periph.c b/components/esp_hal_parlio/esp32s31/parlio_periph.c new file mode 100644 index 00000000000..d41a28e00b9 --- /dev/null +++ b/components/esp_hal_parlio/esp32s31/parlio_periph.c @@ -0,0 +1,66 @@ +/* + * SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "hal/parlio_periph.h" +#include "soc/gpio_sig_map.h" +#include "soc/interrupts.h" + +const soc_parlio_signal_desc_t soc_parlio_signals[1] = { + [0] = { + .module_name = "PARLIO0", + .tx_irq_id = ETS_HP_PARLIO_TX_INTR_SOURCE, + .rx_irq_id = ETS_HP_PARLIO_RX_INTR_SOURCE, + .tx_units = { + [0] = { + .data_sigs = { + PARLIO_TX_DATA0_PAD_OUT_IDX, + PARLIO_TX_DATA1_PAD_OUT_IDX, + PARLIO_TX_DATA2_PAD_OUT_IDX, + PARLIO_TX_DATA3_PAD_OUT_IDX, + PARLIO_TX_DATA4_PAD_OUT_IDX, + PARLIO_TX_DATA5_PAD_OUT_IDX, + PARLIO_TX_DATA6_PAD_OUT_IDX, + PARLIO_TX_DATA7_PAD_OUT_IDX, + PARLIO_TX_DATA8_PAD_OUT_IDX, + PARLIO_TX_DATA9_PAD_OUT_IDX, + PARLIO_TX_DATA10_PAD_OUT_IDX, + PARLIO_TX_DATA11_PAD_OUT_IDX, + PARLIO_TX_DATA12_PAD_OUT_IDX, + PARLIO_TX_DATA13_PAD_OUT_IDX, + PARLIO_TX_DATA14_PAD_OUT_IDX, + PARLIO_TX_DATA15_PAD_OUT_IDX, + }, + .clk_out_sig = PARLIO_TX_CLK_PAD_OUT_IDX, + .clk_in_sig = PARLIO_TX_CLK_PAD_IN_IDX, + .cs_sig = PARLIO_TX_CS_PAD_OUT_IDX, + } + }, + .rx_units = { + [0] = { + .data_sigs = { + PARLIO_RX_DATA0_PAD_IN_IDX, + PARLIO_RX_DATA1_PAD_IN_IDX, + PARLIO_RX_DATA2_PAD_IN_IDX, + PARLIO_RX_DATA3_PAD_IN_IDX, + PARLIO_RX_DATA4_PAD_IN_IDX, + PARLIO_RX_DATA5_PAD_IN_IDX, + PARLIO_RX_DATA6_PAD_IN_IDX, + PARLIO_RX_DATA7_PAD_IN_IDX, + PARLIO_RX_DATA8_PAD_IN_IDX, + PARLIO_RX_DATA9_PAD_IN_IDX, + PARLIO_RX_DATA10_PAD_IN_IDX, + PARLIO_RX_DATA11_PAD_IN_IDX, + PARLIO_RX_DATA12_PAD_IN_IDX, + PARLIO_RX_DATA13_PAD_IN_IDX, + PARLIO_RX_DATA14_PAD_IN_IDX, + PARLIO_RX_DATA15_PAD_IN_IDX, + }, + .clk_out_sig = PARLIO_RX_CLK_PAD_OUT_IDX, + .clk_in_sig = PARLIO_RX_CLK_PAD_IN_IDX, + } + } + } +}; diff --git a/components/esp_lcd/test_apps/parlio_lcd/README.md b/components/esp_lcd/test_apps/parlio_lcd/README.md index b1154bec8d2..c272a671896 100644 --- a/components/esp_lcd/test_apps/parlio_lcd/README.md +++ b/components/esp_lcd/test_apps/parlio_lcd/README.md @@ -1,4 +1,4 @@ -| Supported Targets | ESP32-C5 | ESP32-H2 | ESP32-H21 | ESP32-H4 | ESP32-P4 | -| ----------------- | -------- | -------- | --------- | -------- | -------- | +| Supported Targets | ESP32-C5 | ESP32-H2 | ESP32-H21 | ESP32-H4 | ESP32-P4 | ESP32-S31 | +| ----------------- | -------- | -------- | --------- | -------- | -------- | --------- | This test app is used to test LCDs with intel 8080 interface. diff --git a/components/esp_lcd/test_apps/parlio_lcd/main/test_parlio_board.h b/components/esp_lcd/test_apps/parlio_lcd/main/test_parlio_board.h index 9730dbd8657..dec9e1a1c8b 100644 --- a/components/esp_lcd/test_apps/parlio_lcd/main/test_parlio_board.h +++ b/components/esp_lcd/test_apps/parlio_lcd/main/test_parlio_board.h @@ -61,6 +61,20 @@ extern "C" { #define TEST_LCD_DATA5_GPIO (35) #define TEST_LCD_DATA6_GPIO (19) #define TEST_LCD_DATA7_GPIO (34) +#elif CONFIG_IDF_TARGET_ESP32S31 +#define TEST_LCD_BK_LIGHT_GPIO (13) +#define TEST_LCD_RST_GPIO (39) +#define TEST_LCD_PCLK_GPIO (15) +#define TEST_LCD_CS_GPIO (14) +#define TEST_LCD_DC_GPIO (38) +#define TEST_LCD_DATA0_GPIO (16) +#define TEST_LCD_DATA1_GPIO (37) +#define TEST_LCD_DATA2_GPIO (17) +#define TEST_LCD_DATA3_GPIO (36) +#define TEST_LCD_DATA4_GPIO (18) +#define TEST_LCD_DATA5_GPIO (35) +#define TEST_LCD_DATA6_GPIO (19) +#define TEST_LCD_DATA7_GPIO (34) #elif CONFIG_IDF_TARGET_ESP32H21 #define TEST_LCD_BK_LIGHT_GPIO (6) #define TEST_LCD_RST_GPIO (2) diff --git a/components/soc/esp32s31/include/soc/Kconfig.soc_caps.in b/components/soc/esp32s31/include/soc/Kconfig.soc_caps.in index 58208f4ee2d..d931420739a 100644 --- a/components/soc/esp32s31/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32s31/include/soc/Kconfig.soc_caps.in @@ -91,6 +91,14 @@ config SOC_ETM_SUPPORTED bool default y +config SOC_PARLIO_SUPPORTED + bool + default y + +config SOC_PARLIO_LCD_SUPPORTED + bool + default y + config SOC_ASYNC_MEMCPY_SUPPORTED bool default y @@ -871,6 +879,34 @@ config SOC_TWAI_SUPPORT_SLEEP_RETENTION bool default y +config SOC_PARLIO_TX_UNIT_MAX_DATA_WIDTH + int + default 16 + +config SOC_PARLIO_RX_UNIT_MAX_DATA_WIDTH + int + default 16 + +config SOC_PARLIO_TX_CLK_SUPPORT_GATING + bool + default y + +config SOC_PARLIO_RX_CLK_SUPPORT_GATING + bool + default y + +config SOC_PARLIO_TX_SUPPORT_LOOP_TRANSMISSION + bool + default y + +config SOC_PARLIO_SUPPORT_SLEEP_RETENTION + bool + default y + +config SOC_PARLIO_SUPPORT_I80_LCD + bool + default y + config SOC_AES_GDMA bool default y diff --git a/components/soc/esp32s31/include/soc/clk_tree_defs.h b/components/soc/esp32s31/include/soc/clk_tree_defs.h index 961f0130c88..b346cdb77a3 100644 --- a/components/soc/esp32s31/include/soc/clk_tree_defs.h +++ b/components/soc/esp32s31/include/soc/clk_tree_defs.h @@ -530,6 +530,24 @@ typedef enum { I2S_CLK_SRC_EXTERNAL = -1, /*!< Select external clock as source clock */ } soc_periph_i2s_clk_src_t; +//////////////////////////////////////////////////PARLIO//////////////////////////////////////////////////////////////// + +/** + * @brief Array initializer for all supported clock sources of PARLIO + */ +#define SOC_PARLIO_CLKS {SOC_MOD_CLK_XTAL, SOC_MOD_CLK_RC_FAST, SOC_MOD_CLK_PLL_F160M} + +/** + * @brief PARLIO clock source + */ +typedef enum { + PARLIO_CLK_SRC_XTAL = SOC_MOD_CLK_XTAL, /*!< Select XTAL as the source clock */ + PARLIO_CLK_SRC_RC_FAST = SOC_MOD_CLK_RC_FAST, /*!< Select RC_FAST as the source clock */ + PARLIO_CLK_SRC_PLL_F160M = SOC_MOD_CLK_PLL_F160M, /*!< Select PLL_F160M as the source clock */ + PARLIO_CLK_SRC_EXTERNAL = -1, /*!< Select EXTERNAL clock as the source clock */ + PARLIO_CLK_SRC_DEFAULT = SOC_MOD_CLK_PLL_F160M, /*!< Select PLL_F160M as the default clock choice */ +} soc_periph_parlio_clk_src_t; + //////////////////////////////////////////////CLOCK OUTPUT/////////////////////////////////////////////////////////// typedef enum { CLKOUT_SIG_MPLL_500M = 0, /*!< MPLL output at 500MHz */ diff --git a/components/soc/esp32s31/include/soc/soc_caps.h b/components/soc/esp32s31/include/soc/soc_caps.h index cb2314abf09..bae1b010997 100644 --- a/components/soc/esp32s31/include/soc/soc_caps.h +++ b/components/soc/esp32s31/include/soc/soc_caps.h @@ -45,7 +45,8 @@ #define SOC_TWAI_SUPPORTED 1 #define SOC_TWAI_FD_SUPPORTED 1 #define SOC_ETM_SUPPORTED 1 -// #define SOC_PARLIO_SUPPORTED 1 // TODO: [ESP32S31] IDF-14711 +#define SOC_PARLIO_SUPPORTED 1 +#define SOC_PARLIO_LCD_SUPPORTED 1 #define SOC_ASYNC_MEMCPY_SUPPORTED 1 #define SOC_USB_OTG_SUPPORTED 1 // #define SOC_USB_SERIAL_JTAG_SUPPORTED 1 // TODO: [ESP32S31] IDF-14788 @@ -343,6 +344,15 @@ #define SOC_TWAI_RANGE_FILTER_NUM 1U #define SOC_TWAI_SUPPORT_SLEEP_RETENTION 1 +/*-------------------------- PARLIO CAPS --------------------------------------*/ +#define SOC_PARLIO_TX_UNIT_MAX_DATA_WIDTH 16 /*!< Number of data lines of the TX unit */ +#define SOC_PARLIO_RX_UNIT_MAX_DATA_WIDTH 16 /*!< Number of data lines of the RX unit */ +#define SOC_PARLIO_TX_CLK_SUPPORT_GATING 1 /*!< Support gating TX clock */ +#define SOC_PARLIO_RX_CLK_SUPPORT_GATING 1 /*!< Support gating RX clock */ +#define SOC_PARLIO_TX_SUPPORT_LOOP_TRANSMISSION 1 /*!< Support loop transmission */ +#define SOC_PARLIO_SUPPORT_SLEEP_RETENTION 1 /*!< Support back up registers before sleep */ +#define SOC_PARLIO_SUPPORT_I80_LCD 1 /*!< Support to drive I80 interfaced LCD */ + /*-------------------------- AES CAPS ----------------------------------------*/ #define SOC_AES_GDMA (1) #define SOC_AES_SUPPORT_DMA (1) diff --git a/components/soc/esp32s31/register/soc/parl_io_reg.h b/components/soc/esp32s31/register/soc/parl_io_reg.h index 9132fd692ac..ff769fa2704 100644 --- a/components/soc/esp32s31/register/soc/parl_io_reg.h +++ b/components/soc/esp32s31/register/soc/parl_io_reg.h @@ -83,6 +83,7 @@ extern "C" { * 1: bus width is 2. * 2: bus width is 4. * 3: bus width is 8. + * 4: bus width is 16. */ #define PARL_IO_RX_BUS_WID_SEL 0x00000007U #define PARL_IO_RX_BUS_WID_SEL_M (PARL_IO_RX_BUS_WID_SEL_V << PARL_IO_RX_BUS_WID_SEL_S) @@ -159,6 +160,7 @@ extern "C" { * 1: bus width is 2. * 2: bus width is 4. * 3: bus width is 8. + * 4: bus width is 16. */ #define PARL_IO_TX_BUS_WID_SEL 0x00000007U #define PARL_IO_TX_BUS_WID_SEL_M (PARL_IO_TX_BUS_WID_SEL_V << PARL_IO_TX_BUS_WID_SEL_S) diff --git a/components/soc/esp32s31/register/soc/parl_io_struct.h b/components/soc/esp32s31/register/soc/parl_io_struct.h index 8397c4bd630..fb459a949c4 100644 --- a/components/soc/esp32s31/register/soc/parl_io_struct.h +++ b/components/soc/esp32s31/register/soc/parl_io_struct.h @@ -1,5 +1,5 @@ /** - * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2025-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 OR MIT */ @@ -72,6 +72,7 @@ typedef union { * 1: bus width is 2. * 2: bus width is 4. * 3: bus width is 8. + * 4: bus width is 16. */ uint32_t rx_bus_wid_sel:3; }; @@ -146,6 +147,7 @@ typedef union { * 1: bus width is 2. * 2: bus width is 4. * 3: bus width is 8. + * 4: bus width is 16. */ uint32_t tx_bus_wid_sel:3; }; @@ -487,7 +489,7 @@ typedef union { } parl_io_version_reg_t; -typedef struct { +typedef struct parl_io_dev_t { volatile parl_io_rx_mode_cfg_reg_t rx_mode_cfg; volatile parl_io_rx_data_cfg_reg_t rx_data_cfg; volatile parl_io_rx_genrl_cfg_reg_t rx_genrl_cfg; @@ -514,6 +516,8 @@ typedef struct { volatile parl_io_version_reg_t version; } parl_io_dev_t; +extern parl_io_dev_t PARL_IO; + #ifndef __cplusplus _Static_assert(sizeof(parl_io_dev_t) == 0x400, "Invalid size of parl_io_dev_t structure"); diff --git a/examples/peripherals/lcd/parlio_simulate/README.md b/examples/peripherals/lcd/parlio_simulate/README.md index 4e37445a4d5..edc20ce497f 100644 --- a/examples/peripherals/lcd/parlio_simulate/README.md +++ b/examples/peripherals/lcd/parlio_simulate/README.md @@ -1,5 +1,5 @@ -| Supported Targets | ESP32-C5 | ESP32-H2 | ESP32-H21 | ESP32-H4 | ESP32-P4 | -| ----------------- | -------- | -------- | --------- | -------- | -------- | +| Supported Targets | ESP32-C5 | ESP32-H2 | ESP32-H21 | ESP32-H4 | ESP32-P4 | ESP32-S31 | +| ----------------- | -------- | -------- | --------- | -------- | -------- | --------- | # Parallel IO simulation of SPI or I80 Interfaced LCD example diff --git a/examples/peripherals/lcd/parlio_simulate/sdkconfig.defaults.esp32s31 b/examples/peripherals/lcd/parlio_simulate/sdkconfig.defaults.esp32s31 new file mode 100644 index 00000000000..49e1883889a --- /dev/null +++ b/examples/peripherals/lcd/parlio_simulate/sdkconfig.defaults.esp32s31 @@ -0,0 +1,18 @@ +CONFIG_SPIRAM=y +# Enabling the following configurations can help increase the PCLK frequency in the case when +# the Frame Buffer is allocated from the PSRAM and fetched by EDMA +CONFIG_SPIRAM_XIP_FROM_PSRAM=y + +CONFIG_EXAMPLE_PIN_NUM_BK_LIGHT=1 +CONFIG_EXAMPLE_PIN_NUM_RST=56 +CONFIG_EXAMPLE_PIN_NUM_CS=2 +CONFIG_EXAMPLE_PIN_NUM_DC=54 +CONFIG_EXAMPLE_PIN_NUM_PCLK=5 +CONFIG_EXAMPLE_PIN_NUM_DATA0=11 +CONFIG_EXAMPLE_PIN_NUM_DATA1=52 +CONFIG_EXAMPLE_PIN_NUM_DATA2=8 +CONFIG_EXAMPLE_PIN_NUM_DATA3=50 +CONFIG_EXAMPLE_PIN_NUM_DATA4=6 +CONFIG_EXAMPLE_PIN_NUM_DATA5=48 +CONFIG_EXAMPLE_PIN_NUM_DATA6=13 +CONFIG_EXAMPLE_PIN_NUM_DATA7=46 diff --git a/examples/peripherals/parlio/parlio_rx/logic_analyzer/README.md b/examples/peripherals/parlio/parlio_rx/logic_analyzer/README.md index b8acc9cff94..acf981a4fdb 100644 --- a/examples/peripherals/parlio/parlio_rx/logic_analyzer/README.md +++ b/examples/peripherals/parlio/parlio_rx/logic_analyzer/README.md @@ -1,5 +1,5 @@ -| Supported Targets | ESP32-C5 | ESP32-C6 | ESP32-H2 | ESP32-H21 | ESP32-H4 | ESP32-P4 | -| ----------------- | -------- | -------- | -------- | --------- | -------- | -------- | +| Supported Targets | ESP32-C5 | ESP32-C6 | ESP32-H2 | ESP32-H21 | ESP32-H4 | ESP32-P4 | ESP32-S31 | +| ----------------- | -------- | -------- | -------- | --------- | -------- | -------- | --------- | # Logic Analyzer Example diff --git a/examples/peripherals/parlio/parlio_tx/advanced_rgb_led_matrix/README.md b/examples/peripherals/parlio/parlio_tx/advanced_rgb_led_matrix/README.md index 37863b3c4c7..26e7d45de9a 100644 --- a/examples/peripherals/parlio/parlio_tx/advanced_rgb_led_matrix/README.md +++ b/examples/peripherals/parlio/parlio_tx/advanced_rgb_led_matrix/README.md @@ -1,5 +1,5 @@ -| Supported Targets | ESP32-P4 | -| ----------------- | -------- | +| Supported Targets | ESP32-P4 | ESP32-S31 | +| ----------------- | -------- | --------- | # Parallel IO TX Example: Advancde RGB LED Matrix diff --git a/examples/peripherals/parlio/parlio_tx/advanced_rgb_led_matrix/pytest_advanced_rgb_led_matrix.py b/examples/peripherals/parlio/parlio_tx/advanced_rgb_led_matrix/pytest_advanced_rgb_led_matrix.py index e8cbe8c33d7..ce3fda99b58 100644 --- a/examples/peripherals/parlio/parlio_tx/advanced_rgb_led_matrix/pytest_advanced_rgb_led_matrix.py +++ b/examples/peripherals/parlio/parlio_tx/advanced_rgb_led_matrix/pytest_advanced_rgb_led_matrix.py @@ -6,7 +6,7 @@ from pytest_embedded_idf.utils import idf_parametrize @pytest.mark.generic -@idf_parametrize('target', ['esp32p4'], indirect=['target']) +@idf_parametrize('target', ['esp32p4', 'esp32s31'], indirect=['target']) def test_advanced_rgb_led_matrix_example(dut: Dut) -> None: dut.expect_exact('example: Install parallel IO TX unit') dut.expect_exact('example: Initialize LVGL library') diff --git a/examples/peripherals/parlio/parlio_tx/advanced_rgb_led_matrix/sdkconfig.defaults.esp32s31 b/examples/peripherals/parlio/parlio_tx/advanced_rgb_led_matrix/sdkconfig.defaults.esp32s31 new file mode 100644 index 00000000000..d0b7d84a9d5 --- /dev/null +++ b/examples/peripherals/parlio/parlio_tx/advanced_rgb_led_matrix/sdkconfig.defaults.esp32s31 @@ -0,0 +1,13 @@ +CONFIG_EXAMPLE_PIN_NUM_R1=14 +CONFIG_EXAMPLE_PIN_NUM_G1=8 +CONFIG_EXAMPLE_PIN_NUM_B1=12 +CONFIG_EXAMPLE_PIN_NUM_R2=7 +CONFIG_EXAMPLE_PIN_NUM_G2=11 +CONFIG_EXAMPLE_PIN_NUM_B2=9 +CONFIG_EXAMPLE_PIN_NUM_LATCH=1 +CONFIG_EXAMPLE_PIN_NUM_OE=0 +CONFIG_EXAMPLE_PIN_NUM_PCLK=3 +CONFIG_EXAMPLE_PIN_NUM_A=10 +CONFIG_EXAMPLE_PIN_NUM_B=5 +CONFIG_EXAMPLE_PIN_NUM_C=4 +CONFIG_EXAMPLE_PIN_NUM_D=2 diff --git a/examples/peripherals/parlio/parlio_tx/simple_rgb_led_matrix/README.md b/examples/peripherals/parlio/parlio_tx/simple_rgb_led_matrix/README.md index 20895d5a47a..9f8dc45f910 100644 --- a/examples/peripherals/parlio/parlio_tx/simple_rgb_led_matrix/README.md +++ b/examples/peripherals/parlio/parlio_tx/simple_rgb_led_matrix/README.md @@ -1,5 +1,5 @@ -| Supported Targets | ESP32-C5 | ESP32-C6 | ESP32-H2 | ESP32-H21 | ESP32-H4 | ESP32-P4 | -| ----------------- | -------- | -------- | -------- | --------- | -------- | -------- | +| Supported Targets | ESP32-C5 | ESP32-C6 | ESP32-H2 | ESP32-H21 | ESP32-H4 | ESP32-P4 | ESP32-S31 | +| ----------------- | -------- | -------- | -------- | --------- | -------- | -------- | --------- | # Parallel IO TX Example: Simple RGB LED Matrix diff --git a/examples/peripherals/parlio/parlio_tx/simple_rgb_led_matrix/sdkconfig.defaults.esp32s31 b/examples/peripherals/parlio/parlio_tx/simple_rgb_led_matrix/sdkconfig.defaults.esp32s31 new file mode 100644 index 00000000000..d0b7d84a9d5 --- /dev/null +++ b/examples/peripherals/parlio/parlio_tx/simple_rgb_led_matrix/sdkconfig.defaults.esp32s31 @@ -0,0 +1,13 @@ +CONFIG_EXAMPLE_PIN_NUM_R1=14 +CONFIG_EXAMPLE_PIN_NUM_G1=8 +CONFIG_EXAMPLE_PIN_NUM_B1=12 +CONFIG_EXAMPLE_PIN_NUM_R2=7 +CONFIG_EXAMPLE_PIN_NUM_G2=11 +CONFIG_EXAMPLE_PIN_NUM_B2=9 +CONFIG_EXAMPLE_PIN_NUM_LATCH=1 +CONFIG_EXAMPLE_PIN_NUM_OE=0 +CONFIG_EXAMPLE_PIN_NUM_PCLK=3 +CONFIG_EXAMPLE_PIN_NUM_A=10 +CONFIG_EXAMPLE_PIN_NUM_B=5 +CONFIG_EXAMPLE_PIN_NUM_C=4 +CONFIG_EXAMPLE_PIN_NUM_D=2