feat(lcd): support i80 lcd sleep retention on p4

This commit is contained in:
Chen Jichang
2026-01-30 11:41:04 +08:00
committed by Chen Ji Chang
parent de94a9d2f3
commit 3dccd4b740
16 changed files with 324 additions and 6 deletions

View File

@@ -294,6 +294,10 @@ bool peripheral_domain_pd_allowed(void)
mask.bitmap[SLEEP_RETENTION_MODULE_MCPWM0 >> 5] |= BIT(SLEEP_RETENTION_MODULE_MCPWM0 % 32);
#endif
#if SOC_LCDCAM_LCD_SUPPORT_SLEEP_RETENTION
mask.bitmap[SLEEP_RETENTION_MODULE_LCDCAM >> 5] |= BIT(SLEEP_RETENTION_MODULE_LCDCAM % 32);
#endif
const sleep_retention_module_bitmap_t peripheral_domain_inited_modules = sleep_retention_module_bitmap_and(inited_modules, mask);
const sleep_retention_module_bitmap_t peripheral_domain_created_modules = sleep_retention_module_bitmap_and(created_modules, mask);
return sleep_retention_module_bitmap_eq(peripheral_domain_inited_modules, peripheral_domain_created_modules);

View File

@@ -43,6 +43,10 @@
#include "hal/lcd_hal.h"
#include "hal/cache_ll.h"
#include "hal/cache_hal.h"
#include "esp_private/sleep_retention.h"
// Use retention link only when the target supports sleep retention is enabled
#define I80_USE_RETENTION_LINK (SOC_LCDCAM_LCD_SUPPORT_SLEEP_RETENTION && CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP)
#if defined(SOC_GDMA_TRIG_PERIPH_LCD0_BUS) && (SOC_GDMA_TRIG_PERIPH_LCD0_BUS == SOC_GDMA_BUS_AHB)
#define LCD_GDMA_NEW_CHANNEL gdma_new_ahb_channel
@@ -66,6 +70,11 @@ typedef struct esp_lcd_i80_bus_t esp_lcd_i80_bus_t;
typedef struct lcd_panel_io_i80_t lcd_panel_io_i80_t;
typedef struct lcd_i80_trans_descriptor_t lcd_i80_trans_descriptor_t;
#if I80_USE_RETENTION_LINK
static esp_err_t lcd_i80_create_sleep_retention_link_cb(void *arg);
static void lcd_i80_create_retention_module(esp_lcd_i80_bus_t *bus);
#endif // I80_USE_RETENTION_LINK
static esp_err_t panel_io_i80_tx_param(esp_lcd_panel_io_t *io, int lcd_cmd, const void *param, size_t param_size);
static esp_err_t panel_io_i80_tx_color(esp_lcd_panel_io_t *io, int lcd_cmd, const void *color, size_t color_size);
static esp_err_t panel_io_i80_del(esp_lcd_panel_io_t *io);
@@ -153,6 +162,10 @@ esp_err_t esp_lcd_new_i80_bus(const esp_lcd_i80_bus_config_t *bus_config, esp_lc
// although LCD_CAM can support up to 24 data lines, we restrict users to only use 8 or 16 bit width
ESP_RETURN_ON_FALSE(bus_config->bus_width == 8 || bus_config->bus_width == 16, ESP_ERR_INVALID_ARG,
TAG, "invalid bus width:%d", bus_config->bus_width);
#if !SOC_LCDCAM_LCD_SUPPORT_SLEEP_RETENTION
ESP_RETURN_ON_FALSE(bus_config->flags.allow_pd == 0, ESP_ERR_NOT_SUPPORTED, TAG, "register back up is not supported");
#endif // SOC_LCDCAM_LCD_SUPPORT_SLEEP_RETENTION
// allocate i80 bus memory
bus = heap_caps_calloc(1, sizeof(esp_lcd_i80_bus_t), LCD_I80_MEM_ALLOC_CAPS);
ESP_GOTO_ON_FALSE(bus, ESP_ERR_NO_MEM, err, TAG, "no mem for i80 bus");
@@ -179,6 +192,26 @@ esp_err_t esp_lcd_new_i80_bus(const esp_lcd_i80_bus_config_t *bus_config, esp_lc
lcd_ll_reset_register(bus_id);
}
}
#if I80_USE_RETENTION_LINK
// no need to acquire mutex, because the bus is exclusive
sleep_retention_module_t module_id = soc_i80_lcd_retention_info[bus_id].retention_module;
sleep_retention_module_init_param_t init_param = {
.cbs = {
.create = {
.handle = lcd_i80_create_sleep_retention_link_cb,
.arg = bus,
},
},
.depends = RETENTION_MODULE_BITMAP_INIT(CLOCK_SYSTEM)
};
if (sleep_retention_module_init(module_id, &init_param) != ESP_OK) {
// even though the sleep retention module init failed, LCD driver should still work, so just warning here
ESP_LOGW(TAG, "init sleep retention failed, power domain may be turned off during sleep");
}
if (bus_config->flags.allow_pd) {
lcd_i80_create_retention_module(bus);
}
#endif // I80_USE_RETENTION_LINK
// initialize HAL layer, so we can call LL APIs later
lcd_hal_init(&bus->hal, bus_id);
LCD_CLOCK_SRC_ATOMIC() {
@@ -269,6 +302,16 @@ esp_err_t esp_lcd_del_i80_bus(esp_lcd_i80_bus_handle_t bus)
ESP_GOTO_ON_FALSE(bus, ESP_ERR_INVALID_ARG, err, TAG, "invalid argument");
ESP_GOTO_ON_FALSE(LIST_EMPTY(&bus->device_list), ESP_ERR_INVALID_STATE, err, TAG, "device list not empty");
int bus_id = bus->bus_id;
#if I80_USE_RETENTION_LINK
const periph_retention_module_t module_id = soc_i80_lcd_retention_info[bus_id].retention_module;
if (sleep_retention_is_module_created(module_id)) {
assert(sleep_retention_is_module_inited(module_id));
sleep_retention_module_free(module_id);
}
if (sleep_retention_is_module_inited(module_id)) {
sleep_retention_module_deinit(module_id);
}
#endif // I80_USE_RETENTION_LINK
lcd_com_remove_device(LCD_COM_DEVICE_TYPE_I80, bus_id);
PERIPH_RCC_RELEASE_ATOMIC(lcd_periph_i80_signals.buses[bus_id].module, ref_count) {
if (ref_count == 0) {
@@ -572,6 +615,33 @@ static esp_err_t panel_io_i80_tx_color(esp_lcd_panel_io_t *io, int lcd_cmd, cons
return ESP_OK;
}
#if I80_USE_RETENTION_LINK
static esp_err_t lcd_i80_create_sleep_retention_link_cb(void *arg)
{
esp_lcd_i80_bus_t *bus = (esp_lcd_i80_bus_t *)arg;
int bus_id = bus->bus_id;
sleep_retention_module_t module_id = soc_i80_lcd_retention_info[bus_id].retention_module;
esp_err_t err = sleep_retention_entries_create(soc_i80_lcd_retention_info[bus_id].regdma_entry_array,
soc_i80_lcd_retention_info[bus_id].array_size,
REGDMA_LINK_PRI_LCDCAM, module_id);
ESP_RETURN_ON_ERROR(err, TAG, "create retention link failed");
return ESP_OK;
}
static void lcd_i80_create_retention_module(esp_lcd_i80_bus_t *bus)
{
int bus_id = bus->bus_id;
sleep_retention_module_t module_id = soc_i80_lcd_retention_info[bus_id].retention_module;
if (sleep_retention_is_module_inited(module_id) && !sleep_retention_is_module_created(module_id)) {
if (sleep_retention_module_allocate(module_id) != ESP_OK) {
// even though the sleep retention module create failed, LCD driver should still work, so just warning here
ESP_LOGW(TAG, "create retention module failed, power domain can't turn off");
}
}
}
#endif // I80_USE_RETENTION_LINK
static esp_err_t lcd_i80_select_periph_clock(esp_lcd_i80_bus_handle_t bus, lcd_clock_source_t clk_src)
{
// get clock source frequency

View File

@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2021-2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -34,6 +34,11 @@ typedef struct {
size_t dma_burst_size; /*!< DMA burst size, in bytes */
};
size_t sram_trans_align __attribute__((deprecated)); /*!< DMA transfer alignment for data allocated from SRAM */
/// Extra configuration flags for I80 bus
struct extra_i80_bus_flags {
uint32_t allow_pd: 1; /*!< If set, driver allows the power domain to be powered off when system enters sleep mode.
This can save power, but at the expense of more RAM being consumed to save register context. */
} flags; /*!< Extra bus config flags */
} esp_lcd_i80_bus_config_t;
/**
@@ -71,19 +76,21 @@ typedef struct {
void *user_ctx; /*!< User private data, passed directly to on_color_trans_done's user_ctx */
int lcd_cmd_bits; /*!< Bit-width of LCD command */
int lcd_param_bits; /*!< Bit-width of LCD parameter */
struct {
/// D/C line levels configuration
struct i80_panel_io_dc_levels {
unsigned int dc_idle_level: 1; /*!< Level of DC line in IDLE phase */
unsigned int dc_cmd_level: 1; /*!< Level of DC line in CMD phase */
unsigned int dc_dummy_level: 1; /*!< Level of DC line in DUMMY phase */
unsigned int dc_data_level: 1; /*!< Level of DC line in DATA phase */
} dc_levels; /*!< Each i80 device might have its own D/C control logic */
struct {
/// Extra configuration flags for I80 panel IO
struct extra_i80_panel_io_flags {
unsigned int cs_active_high: 1; /*!< If set, a high level of CS line will select the device, otherwise, CS line is low level active */
unsigned int reverse_color_bits: 1; /*!< Reverse the data bits, D[N:0] -> D[0:N] */
unsigned int swap_color_bytes: 1; /*!< Swap adjacent two color bytes */
unsigned int pclk_active_neg: 1; /*!< The display will write data lines when there's a falling edge on WR signal (a.k.a the PCLK) */
unsigned int pclk_idle_low: 1; /*!< The WR signal (a.k.a the PCLK) stays at low level in IDLE phase */
} flags; /*!< Panel IO config flags */
} flags; /*!< Extra panel IO config flags */
} esp_lcd_panel_io_i80_config_t;
/**

View File

@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2021-2025 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2021-2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -47,6 +47,7 @@
#include "hal/cache_hal.h"
#include "hal/cache_ll.h"
#include "rgb_lcd_rotation_sw.h"
#include "esp_private/sleep_retention.h"
// hardware issue workaround
#if CONFIG_IDF_TARGET_ESP32S3
@@ -250,6 +251,9 @@ static esp_err_t lcd_rgb_panel_destroy(esp_rgb_panel_t *rgb_panel)
esp_pm_lock_release(rgb_panel->pm_lock);
esp_pm_lock_delete(rgb_panel->pm_lock);
}
#if CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP
sleep_retention_power_lock_release();
#endif
free(rgb_panel);
return ESP_OK;
}
@@ -300,6 +304,11 @@ esp_err_t esp_lcd_new_rgb_panel(const esp_lcd_rgb_panel_config_t *rgb_panel_conf
expect_bb_eof_count = fb_size / bb_size;
}
#if CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP
// acquire the retention power lock to prevent the power domain from being turned off during light sleep
sleep_retention_power_lock_acquire();
#endif
// calculate the number of DMA descriptors
size_t num_dma_nodes = 0;
// allocate memory for rgb panel
@@ -334,6 +343,7 @@ esp_err_t esp_lcd_new_rgb_panel(const esp_lcd_rgb_panel_config_t *rgb_panel_conf
// set clock source
ret = lcd_rgb_panel_select_clock_src(rgb_panel, rgb_panel_config->clk_src);
ESP_GOTO_ON_ERROR(ret, err, TAG, "set source clock failed");
// reset peripheral and FIFO after we select a correct clock source
lcd_ll_fifo_reset(rgb_panel->hal.dev);
lcd_ll_reset(rgb_panel->hal.dev);

View File

@@ -1,6 +1,10 @@
set(srcs "test_app_main.c"
"test_i80_lcd_panel.c")
if(CONFIG_SOC_LIGHT_SLEEP_SUPPORTED AND CONFIG_PM_ENABLE)
list(APPEND srcs "test_i80_lcd_panel_sleep.c")
endif()
# In order for the cases defined by `TEST_CASE` to be linked into the final elf,
# the component can be registered as WHOLE_ARCHIVE
idf_component_register(SRCS ${srcs}

View File

@@ -0,0 +1,153 @@
/*
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: CC0-1.0
*/
#include <stdio.h>
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "unity.h"
#include "esp_random.h"
#include "esp_lcd_panel_io.h"
#include "esp_lcd_panel_vendor.h"
#include "esp_lcd_panel_ops.h"
#include "esp_lcd_panel_commands.h"
#include "soc/soc_caps.h"
#include "driver/gpio.h"
#include "test_i80_board.h"
#include "esp_private/sleep_cpu.h"
#include "esp_private/esp_sleep_internal.h"
#include "esp_private/esp_pmu.h"
static void test_i80_lcd_sleep_retention(bool allow_pd)
{
#define TEST_IMG_SIZE (100 * 100 * sizeof(uint16_t))
uint8_t *img = heap_caps_malloc(TEST_IMG_SIZE, MALLOC_CAP_DMA);
TEST_ASSERT_NOT_NULL(img);
gpio_config_t bk_gpio_config = {
.mode = GPIO_MODE_OUTPUT,
.pin_bit_mask = 1ULL << TEST_LCD_BK_LIGHT_GPIO
};
TEST_ESP_OK(gpio_config(&bk_gpio_config));
esp_lcd_i80_bus_handle_t i80_bus = NULL;
esp_lcd_i80_bus_config_t bus_config = {
.dc_gpio_num = TEST_LCD_DC_GPIO,
.wr_gpio_num = TEST_LCD_PCLK_GPIO,
.clk_src = LCD_CLK_SRC_DEFAULT,
.data_gpio_nums = {
TEST_LCD_DATA0_GPIO,
TEST_LCD_DATA1_GPIO,
TEST_LCD_DATA2_GPIO,
TEST_LCD_DATA3_GPIO,
TEST_LCD_DATA4_GPIO,
TEST_LCD_DATA5_GPIO,
TEST_LCD_DATA6_GPIO,
TEST_LCD_DATA7_GPIO,
},
.bus_width = 8,
.max_transfer_bytes = TEST_IMG_SIZE + 10,
.flags = {
.allow_pd = allow_pd,
},
};
TEST_ESP_OK(esp_lcd_new_i80_bus(&bus_config, &i80_bus));
esp_lcd_panel_io_handle_t io_handle = NULL;
esp_lcd_panel_io_i80_config_t io_config = {
.cs_gpio_num = TEST_LCD_CS_GPIO,
.pclk_hz = 8000000, // 8MHz
.trans_queue_depth = 10,
.dc_levels = {
.dc_idle_level = 0,
.dc_cmd_level = 0,
.dc_dummy_level = 0,
.dc_data_level = 1,
},
.lcd_cmd_bits = 8,
.lcd_param_bits = 8,
};
TEST_ESP_OK(esp_lcd_new_panel_io_i80(i80_bus, &io_config, &io_handle));
esp_lcd_panel_handle_t panel_handle = NULL;
esp_lcd_panel_dev_config_t panel_config = {
.reset_gpio_num = TEST_LCD_RST_GPIO,
.rgb_ele_order = LCD_RGB_ELEMENT_ORDER_RGB,
.bits_per_pixel = 16,
};
TEST_ESP_OK(esp_lcd_new_panel_st7789(io_handle, &panel_config, &panel_handle));
// turn off backlight
gpio_set_level(TEST_LCD_BK_LIGHT_GPIO, 0);
esp_lcd_panel_reset(panel_handle);
esp_lcd_panel_init(panel_handle);
esp_lcd_panel_invert_color(panel_handle, true);
// the gap is LCD panel specific, even panels with the same driver IC, can have different gap value
esp_lcd_panel_set_gap(panel_handle, 0, 20);
// turn on display
esp_lcd_panel_disp_on_off(panel_handle, true);
// turn on backlight
gpio_set_level(TEST_LCD_BK_LIGHT_GPIO, 1);
for (int i = 0; i < 200; i++) {
uint8_t color_byte = esp_random() & 0xFF;
int x_start = esp_random() % (TEST_LCD_H_RES - 100);
int y_start = esp_random() % (TEST_LCD_V_RES - 100);
memset(img, color_byte, TEST_IMG_SIZE);
esp_lcd_panel_draw_bitmap(panel_handle, x_start, y_start, x_start + 100, y_start + 100, img);
}
// turn off screen
esp_lcd_panel_disp_on_off(panel_handle, false);
// go to sleep
esp_sleep_context_t sleep_ctx;
esp_sleep_set_sleep_context(&sleep_ctx);
printf("go to light sleep for 2 seconds\r\n");
#if ESP_SLEEP_POWER_DOWN_CPU
TEST_ESP_OK(sleep_cpu_configure(true));
#endif
TEST_ESP_OK(esp_sleep_enable_timer_wakeup(2 * 1000 * 1000));
TEST_ESP_OK(esp_light_sleep_start());
printf("Waked up! Let's see if I80 LCD driver can still work...\r\n");
#if ESP_SLEEP_POWER_DOWN_CPU
TEST_ESP_OK(sleep_cpu_configure(false));
#endif
printf("check if the sleep happened as expected\r\n");
TEST_ASSERT_EQUAL(0, sleep_ctx.sleep_request_result);
#if SOC_LCDCAM_LCD_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
esp_sleep_set_sleep_context(NULL);
// turn on screen
esp_lcd_panel_disp_on_off(panel_handle, true);
printf("Testing I80 LCD after sleep...\n");
for (int i = 0; i < 200; i++) {
uint8_t color_byte = esp_random() & 0xFF;
int x_start = esp_random() % (TEST_LCD_H_RES - 100);
int y_start = esp_random() % (TEST_LCD_V_RES - 100);
memset(img, color_byte, TEST_IMG_SIZE);
esp_lcd_panel_draw_bitmap(panel_handle, x_start, y_start, x_start + 100, y_start + 100, img);
}
TEST_ESP_OK(esp_lcd_panel_del(panel_handle));
TEST_ESP_OK(esp_lcd_panel_io_del(io_handle));
TEST_ESP_OK(esp_lcd_del_i80_bus(i80_bus));
TEST_ESP_OK(gpio_reset_pin(TEST_LCD_BK_LIGHT_GPIO));
free(img);
#undef TEST_IMG_SIZE
}
TEST_CASE("i80_lcd light sleep", "[lcd]")
{
test_i80_lcd_sleep_retention(false);
#if SOC_LCDCAM_LCD_SUPPORT_SLEEP_RETENTION
test_i80_lcd_sleep_retention(true);
#endif
}

View File

@@ -1,4 +1,5 @@
CONFIG_PM_ENABLE=y
CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP=y
CONFIG_FREERTOS_USE_TICKLESS_IDLE=y
CONFIG_COMPILER_OPTIMIZATION_SIZE=y
CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_SIZE=y

View File

@@ -3,3 +3,6 @@
#
# CONFIG_ESP_TASK_WDT_INIT is not set
CONFIG_FREERTOS_HZ=1000
# primitives for checking sleep internal state
CONFIG_ESP_SLEEP_DEBUG=y

View File

@@ -2291,6 +2291,10 @@ config SOC_LCDCAM_CAM_DATA_WIDTH_MAX
int
default 16
config SOC_LCDCAM_LCD_SUPPORT_SLEEP_RETENTION
bool
default y
config SOC_I3C_MASTER_PERIPH_NUM
bool
default y

View File

@@ -60,6 +60,7 @@ typedef enum periph_retention_module {
SLEEP_RETENTION_MODULE_MCPWM0 = 34,
SLEEP_RETENTION_MODULE_MCPWM1 = 35,
SLEEP_RETENTION_MODULE_PCNT0 = 36,
SLEEP_RETENTION_MODULE_LCDCAM = 39,
SLEEP_RETENTION_MODULE_MAX = SOC_PM_RETENTION_MODULE_NUM - 1
} periph_retention_module_t;
@@ -102,6 +103,7 @@ typedef enum periph_retention_module {
: ((m) == SLEEP_RETENTION_MODULE_MCPWM0) ? true \
: ((m) == SLEEP_RETENTION_MODULE_MCPWM1) ? true \
: ((m) == SLEEP_RETENTION_MODULE_PCNT0) ? true \
: ((m) == SLEEP_RETENTION_MODULE_LCDCAM) ? true \
: false)
#ifdef __cplusplus

View File

@@ -847,6 +847,9 @@
#define SOC_LCDCAM_CAM_PERIPH_NUM (1U)
#define SOC_LCDCAM_CAM_DATA_WIDTH_MAX (16U)
/*--------------------------- LCD ---------------------------------*/
#define SOC_LCDCAM_LCD_SUPPORT_SLEEP_RETENTION (1) /*!< Support back up registers before sleep */
/*--------------------------- I3C ---------------------------------*/
#define SOC_I3C_MASTER_PERIPH_NUM (1)
#define SOC_I3C_MASTER_ADDRESS_TABLE_NUM (12)

View File

@@ -88,3 +88,39 @@ const lcd_rgb_signal_conn_t lcd_periph_rgb_signals = {
}
};
#endif // SOC_LCDCAM_RGB_LCD_SUPPORTED
/**
* LCD_CAM Registers to be saved during sleep retention
* - LCD Clock Configuration registers: LCDCAM_LCD_CLOCK_REG (0x0)
* - LCD RGB/YUV Configuration registers: LCDCAM_LCD_RGB_YUV_REG (0x10)
* - LCD User Configuration registers: LCDCAM_LCD_USER_REG (0x14), LCDCAM_LCD_MISC_REG (0x18)
* - LCD Control registers: LCDCAM_LCD_CTRL_REG (0x1c), LCDCAM_LCD_CTRL1_REG (0x20), LCDCAM_LCD_CTRL2_REG (0x24)
* - LCD Command Value registers: LCDCAM_LCD_FIRST_CMD_VAL_REG (0x28), LCDCAM_LCD_LATTER_CMD_VAL_REG (0x2c)
* - LCD Delay Mode Configuration registers: LCDCAM_LCD_DLY_MODE_CFG1_REG (0x30), LCDCAM_LCD_DLY_MODE_CFG2_REG (0x38)
* - LCD DMA Interrupt Enable register: LCDCAM_LC_DMA_INT_ENA_REG (0x64)
*
* NOTE: Only I80 LCD supports sleep retention, not RGB LCD.
*/
#define LCD_RETENTION_REGS_CNT 12
#define LCD_RETENTION_REGS_BASE (DR_REG_LCDCAM_BASE + 0x0)
static const uint32_t lcd_cam_regs_map[4] = {0x2005ff1, 0x0, 0x0, 0x0};
static const regdma_entries_config_t lcd_regs_retention[] = {
// backup stage: save configuration registers
// restore stage: restore the configuration registers
[0] = {
.config = REGDMA_LINK_ADDR_MAP_INIT(REGDMA_LCDCAM_LINK(0x00),
LCD_RETENTION_REGS_BASE, LCD_RETENTION_REGS_BASE,
LCD_RETENTION_REGS_CNT, 0, 0,
lcd_cam_regs_map[0], lcd_cam_regs_map[1],
lcd_cam_regs_map[2], lcd_cam_regs_map[3]),
.owner = ENTRY(0),
},
};
const soc_i80_lcd_retention_info_t soc_i80_lcd_retention_info[1] = {
[0] = {
.regdma_entry_array = lcd_regs_retention,
.array_size = ARRAY_SIZE(lcd_regs_retention),
.retention_module = SLEEP_RETENTION_MODULE_LCDCAM
},
};

View File

@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2021-2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -8,6 +8,12 @@
#include "soc/soc_caps.h"
#include "soc/periph_defs.h"
#include "soc/regdma.h"
#if SOC_LCDCAM_LCD_SUPPORT_SLEEP_RETENTION
#include "soc/retention_periph_defs.h"
#include "soc/lcd_cam_reg.h"
#endif
#ifdef __cplusplus
extern "C" {
@@ -58,6 +64,17 @@ typedef struct {
extern const lcd_i2s_signal_conn_t lcd_periph_i2s_signals;
#endif // SOC_I2S_SUPPORTS_LCD_CAMERA
#if SOC_PAU_SUPPORTED && SOC_LCDCAM_I80_LCD_SUPPORTED
// Only LCDCAM I80 LCD supports sleep retention
typedef struct {
const periph_retention_module_t retention_module;
const regdma_entries_config_t *regdma_entry_array;
uint32_t array_size;
} soc_i80_lcd_retention_info_t;
extern const soc_i80_lcd_retention_info_t soc_i80_lcd_retention_info[SOC_LCDCAM_I80_NUM_BUSES];
#endif // SOC_PAU_SUPPORTED && SOC_LCDCAM_I80_LCD_SUPPORTED
#ifdef __cplusplus
}
#endif

View File

@@ -64,6 +64,7 @@ extern "C" {
#define REGDMA_LEDC_LINK(_pri) ((0x24 << 8) | _pri)
#define REGDMA_PCNT_LINK(_pri) ((0x25 << 8) | _pri)
#define REGDMA_MCPWM_LINK(_pri) ((0x26 << 8) | _pri)
#define REGDMA_LCDCAM_LINK(_pri) ((0x29 << 8) | _pri)
#define REGDMA_MODEM_FE_LINK(_pri) ((0xFF << 8) | _pri)
@@ -91,6 +92,7 @@ extern "C" {
#define REGDMA_LINK_PRI_GPSPI REGDMA_LINK_PRI_GENERAL_PERIPH
#define REGDMA_LINK_PRI_LEDC REGDMA_LINK_PRI_GENERAL_PERIPH
#define REGDMA_LINK_PRI_MCPWM REGDMA_LINK_PRI_GENERAL_PERIPH
#define REGDMA_LINK_PRI_LCDCAM REGDMA_LINK_PRI_GENERAL_PERIPH
typedef enum {
REGDMA_LINK_PRI_0 = 0,

View File

@@ -170,6 +170,7 @@ The following peripheral drivers are not aware of DFS yet. Applications need to
:SOC_TWAI_SUPPORT_SLEEP_RETENTION: - All TWAIs
:SOC_PARLIO_SUPPORT_SLEEP_RETENTION: - PARL_IO
:SOC_SPI_SUPPORT_SLEEP_RETENTION: - All GPSPIs
:SOC_LCDCAM_LCD_SUPPORT_SLEEP_RETENTION: - I80 LCD
Some peripherals haven't support Light-sleep context retention, or it cannot survive from the register lose. They will prevent the power-down of peripherals even when the feature is enabled.

View File

@@ -170,6 +170,7 @@ ESP-IDF 中集成的电源管理算法可以根据应用程序组件的需求,
:SOC_TWAI_SUPPORT_SLEEP_RETENTION: - All TWAIs
:SOC_PARLIO_SUPPORT_SLEEP_RETENTION: - PARL_IO
:SOC_SPI_SUPPORT_SLEEP_RETENTION: - All GPSPIs
:SOC_LCDCAM_LCD_SUPPORT_SLEEP_RETENTION: - I80 LCD
一些外设尚未支持睡眠上下文恢复,或者寄存器丢失后根本无法恢复。即使外设下电功能被启用,它们也会阻止外设下电的发生: