Skip to content

Commit bab289c

Browse files
committed
Merge branch 'fix/sdio_slave_add_pm_lock_v5.4' into 'release/v5.4'
fix(sdio_slave): fix issue that auto light sleep can happen SDIO slave enabled (v5.4) See merge request espressif/esp-idf!34646
2 parents 81020a3 + 3e06117 commit bab289c

File tree

26 files changed

+374
-51
lines changed

26 files changed

+374
-51
lines changed

components/esp_driver_sdio/src/sdio_slave.c

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -76,20 +76,24 @@ The driver of FIFOs works as below:
7676
*/
7777

7878
#include <string.h>
79-
#include "driver/sdio_slave.h"
80-
#include "soc/sdio_slave_periph.h"
81-
#include "esp_log.h"
82-
#include "esp_intr_alloc.h"
83-
#include "freertos/FreeRTOS.h"
79+
8480
#include "soc/soc_memory_layout.h"
8581
#include "soc/gpio_periph.h"
8682
#include "soc/soc_caps.h"
83+
#include "soc/sdio_slave_periph.h"
8784
#include "esp_cpu.h"
85+
#include "esp_intr_alloc.h"
86+
#include "esp_log.h"
87+
#include "hal/sdio_slave_hal.h"
88+
#include "hal/gpio_hal.h"
89+
#include "freertos/FreeRTOS.h"
8890
#include "freertos/semphr.h"
8991
#include "esp_private/periph_ctrl.h"
92+
#if CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP
93+
#include "esp_private/sleep_retention.h"
94+
#endif
9095
#include "driver/gpio.h"
91-
#include "hal/sdio_slave_hal.h"
92-
#include "hal/gpio_hal.h"
96+
#include "driver/sdio_slave.h"
9397

9498
#define SDIO_SLAVE_CHECK(res, str, ret_val) do { if(!(res)){\
9599
SDIO_SLAVE_LOGE("%s", str);\
@@ -365,6 +369,13 @@ esp_err_t sdio_slave_initialize(sdio_slave_config_t *config)
365369
}
366370
context.intr_handle = intr_handle;
367371

372+
#if CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP
373+
r = sleep_retention_power_lock_acquire();
374+
if (r != ESP_OK) {
375+
return r;
376+
}
377+
#endif
378+
368379
r = sdio_slave_hw_init(config);
369380
if (r != ESP_OK) {
370381
return r;
@@ -378,6 +389,11 @@ void sdio_slave_deinit(void)
378389
{
379390
sdio_slave_hw_deinit();
380391

392+
#if CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP
393+
esp_err_t r = sleep_retention_power_lock_release();
394+
assert(r == ESP_OK);
395+
#endif
396+
381397
//unregister all buffers registered but returned (not loaded)
382398
recv_desc_t *temp_desc;
383399
recv_desc_t *desc;

components/esp_driver_sdio/test_apps/.build-test-rules.yml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,17 @@
11
components/esp_driver_sdio/test_apps/sdio/sdio_common_tests/host_sdmmc:
22
enable:
33
- if: IDF_TARGET == "esp32"
4-
temporary: false
54
reason: always use ESP32 SDMMC as host
65
depends_components:
76
- sdmmc
87
- esp_driver_sdmmc
98
- esp_driver_sdio
109

1110
components/esp_driver_sdio/test_apps/sdio/sdio_common_tests/sdio:
11+
enable:
12+
# There is no retention support for SDIO slave, just build and test if driver can forbid from auto light sleep.
13+
- if: CONFIG_NAME == "sleep_retention" and SOC_PAU_SUPPORTED == 1
14+
- if: CONFIG_NAME != "sleep_retention"
1215
disable:
1316
- if: SOC_SDIO_SLAVE_SUPPORTED != 1
1417
depends_components:

components/esp_driver_sdio/test_apps/sdio/sdio_common_tests/host_sdmmc/main/test_sdio_sdhost.c

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -418,6 +418,20 @@ TEST_CASE("SDIO_SDMMC: test to host", "[sdio]")
418418
test_to_host(true);
419419
}
420420

421+
TEST_CASE("SDIO_SDMMC: test sleep retention", "[sdio_retention]")
422+
{
423+
essl_handle_t handle = NULL;
424+
test_sdio_param_t test_param = {
425+
.host_flags = SDMMC_HOST_FLAG_4BIT | SDMMC_HOST_FLAG_ALLOC_ALIGNED_BUF,
426+
.max_freq_khz = SDMMC_FREQ_HIGHSPEED,
427+
};
428+
//essl init and sdmmc init
429+
s_master_init(&test_param, &handle, NULL);
430+
431+
s_send_finish_test(handle);
432+
s_master_deinit();
433+
}
434+
421435
TEST_CASE("SDIO_SDMMC: test to host (Performance)", "[sdio_speed]")
422436
{
423437
test_to_host(false);

components/esp_driver_sdio/test_apps/sdio/sdio_common_tests/pytest_sdio.py

Lines changed: 46 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,30 @@
1-
# SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
1+
# SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD
22
# SPDX-License-Identifier: CC0-1.0
3-
43
import os.path
4+
from typing import List
55
from typing import Tuple
66

77
import pytest
88
from pytest_embedded_idf import IdfDut
99

1010

11+
def parameter_expand(existing_parameters: List[List[str]], value_list: List[str]) -> List[List[str]]:
12+
ret = []
13+
for param in existing_parameters:
14+
ret.extend([param + [value] for value in value_list])
15+
16+
return ret
17+
18+
19+
esp32_32_param = [[f'{os.path.join(os.path.dirname(__file__), "host_sdmmc")}|{os.path.join(os.path.dirname(__file__), "sdio")}', 'esp32|esp32']]
20+
esp32_c6_param = [[f'{os.path.join(os.path.dirname(__file__), "host_sdmmc")}|{os.path.join(os.path.dirname(__file__), "sdio")}', 'esp32|esp32c6']]
21+
22+
esp32_param_default = [pytest.param(*param) for param in parameter_expand(esp32_32_param, ['default|default'])]
23+
c6_param_default = [pytest.param(*param) for param in parameter_expand(esp32_c6_param, ['default|default'])]
24+
25+
c6_param_retention = [pytest.param(*param) for param in parameter_expand(esp32_c6_param, ['default|sleep_retention'])]
26+
27+
1128
# Normal tests
1229
def test_sdio_flow(dut:Tuple[IdfDut, IdfDut]) -> None:
1330
dut[1].expect('Press ENTER to see the list of tests')
@@ -24,23 +41,15 @@ def test_sdio_flow(dut:Tuple[IdfDut, IdfDut]) -> None:
2441
@pytest.mark.esp32c6
2542
@pytest.mark.sdio_multidev_32_c6
2643
@pytest.mark.parametrize('count', [2,], indirect=True)
27-
@pytest.mark.parametrize('app_path, target', [
28-
pytest.param(
29-
f'{os.path.join(os.path.dirname(__file__), "host_sdmmc")}|{os.path.join(os.path.dirname(__file__), "sdio")}',
30-
'esp32|esp32c6'),
31-
], indirect=True)
44+
@pytest.mark.parametrize('app_path, target, config', c6_param_default, indirect=True)
3245
def test_sdio_esp32_esp32c6(dut:Tuple[IdfDut, IdfDut]) -> None:
3346
test_sdio_flow(dut)
3447

3548

3649
@pytest.mark.esp32
3750
@pytest.mark.sdio_master_slave
3851
@pytest.mark.parametrize('count', [2,], indirect=True)
39-
@pytest.mark.parametrize('app_path, target', [
40-
pytest.param(
41-
f'{os.path.join(os.path.dirname(__file__), "host_sdmmc")}|{os.path.join(os.path.dirname(__file__), "sdio")}',
42-
'esp32|esp32'),
43-
], indirect=True)
52+
@pytest.mark.parametrize('app_path, target, config', esp32_param_default, indirect=True)
4453
def test_sdio_esp32_esp32(dut:Tuple[IdfDut, IdfDut]) -> None:
4554
test_sdio_flow(dut)
4655

@@ -68,23 +77,15 @@ def test_sdio_speed_frhost_flow(dut:Tuple[IdfDut, IdfDut], expected_4b_speed:int
6877
@pytest.mark.esp32c6
6978
@pytest.mark.sdio_multidev_32_c6
7079
@pytest.mark.parametrize('count', [2,], indirect=True)
71-
@pytest.mark.parametrize('app_path, target', [
72-
pytest.param(
73-
f'{os.path.join(os.path.dirname(__file__), "host_sdmmc")}|{os.path.join(os.path.dirname(__file__), "sdio")}',
74-
'esp32|esp32c6'),
75-
], indirect=True)
80+
@pytest.mark.parametrize('app_path, target, config', c6_param_default, indirect=True)
7681
def test_sdio_speed_frhost_esp32_esp32c6(dut:Tuple[IdfDut, IdfDut]) -> None:
7782
test_sdio_speed_frhost_flow(dut, 10000, 4000)
7883

7984

8085
@pytest.mark.esp32
8186
@pytest.mark.sdio_master_slave
8287
@pytest.mark.parametrize('count', [2,], indirect=True)
83-
@pytest.mark.parametrize('app_path, target', [
84-
pytest.param(
85-
f'{os.path.join(os.path.dirname(__file__), "host_sdmmc")}|{os.path.join(os.path.dirname(__file__), "sdio")}',
86-
'esp32|esp32'),
87-
], indirect=True)
88+
@pytest.mark.parametrize('app_path, target, config', esp32_param_default, indirect=True)
8889
def test_sdio_speed_frhost_esp32_esp32(dut:Tuple[IdfDut, IdfDut]) -> None:
8990
test_sdio_speed_frhost_flow(dut, 12200, 4000)
9091

@@ -112,22 +113,35 @@ def test_sdio_speed_tohost_flow(dut:Tuple[IdfDut, IdfDut], expected_4b_speed:int
112113
@pytest.mark.esp32c6
113114
@pytest.mark.sdio_multidev_32_c6
114115
@pytest.mark.parametrize('count', [2,], indirect=True)
115-
@pytest.mark.parametrize('app_path, target', [
116-
pytest.param(
117-
f'{os.path.join(os.path.dirname(__file__), "host_sdmmc")}|{os.path.join(os.path.dirname(__file__), "sdio")}',
118-
'esp32|esp32c6'),
119-
], indirect=True)
116+
@pytest.mark.parametrize('app_path, target, config', c6_param_default, indirect=True)
120117
def test_sdio_speed_tohost_esp32_esp32c6(dut:Tuple[IdfDut, IdfDut]) -> None:
121118
test_sdio_speed_tohost_flow(dut, 9000, 4000)
122119

123120

124121
@pytest.mark.esp32
125122
@pytest.mark.sdio_master_slave
126123
@pytest.mark.parametrize('count', [2,], indirect=True)
127-
@pytest.mark.parametrize('app_path, target', [
128-
pytest.param(
129-
f'{os.path.join(os.path.dirname(__file__), "host_sdmmc")}|{os.path.join(os.path.dirname(__file__), "sdio")}',
130-
'esp32|esp32'),
131-
], indirect=True)
124+
@pytest.mark.parametrize('app_path, target, config', esp32_param_default, indirect=True)
132125
def test_sdio_speed_tohost_esp32_esp32(dut:Tuple[IdfDut, IdfDut]) -> None:
133126
test_sdio_speed_tohost_flow(dut, 12200, 4000)
127+
128+
129+
# Retention tests
130+
def test_sdio_retention(dut:Tuple[IdfDut, IdfDut]) -> None:
131+
dut[1].expect('Press ENTER to see the list of tests')
132+
dut[1].write('[sdio_retention]')
133+
dut[1].expect('test_sdio: slave ready')
134+
135+
dut[0].expect('Press ENTER to see the list of tests')
136+
dut[0].write('[sdio_retention]')
137+
138+
dut[1].expect_unity_test_output()
139+
dut[0].expect_unity_test_output()
140+
141+
142+
@pytest.mark.esp32c6
143+
@pytest.mark.sdio_multidev_32_c6
144+
@pytest.mark.parametrize('count', [2,], indirect=True)
145+
@pytest.mark.parametrize('app_path, target, config', c6_param_retention, indirect=True)
146+
def test_sdio_retention_esp32_esp32c6(dut:Tuple[IdfDut, IdfDut]) -> None:
147+
test_sdio_retention(dut)

components/esp_driver_sdio/test_apps/sdio/sdio_common_tests/sdio/main/CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,5 @@ set(srcs "test_app_main.c"
22
"test_sdio_slave.c")
33

44
idf_component_register(SRCS ${srcs}
5-
PRIV_REQUIRES test_driver_utils driver
5+
PRIV_REQUIRES test_driver_utils driver esp_hw_support
66
WHOLE_ARCHIVE)

components/esp_driver_sdio/test_apps/sdio/sdio_common_tests/sdio/main/test_sdio_slave.c

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -305,6 +305,31 @@ TEST_CASE("SDIO_Slave: test to host", "[sdio]")
305305
test_to_host();
306306
}
307307

308+
#if SOC_PAU_SUPPORTED
309+
#include "esp_private/sleep_sys_periph.h"
310+
#include "esp_private/sleep_retention.h"
311+
312+
TEST_CASE("SDIO_Slave: test sleep retention", "[sdio_retention]")
313+
{
314+
TEST_ASSERT_EQUAL_INT32(true, peripheral_domain_pd_allowed());
315+
sleep_retention_dump_modules(stdout);
316+
317+
s_slave_init(SDIO_SLAVE_SEND_STREAM);
318+
TEST_ESP_OK(sdio_slave_start());
319+
ESP_LOGI(TAG, "slave ready");
320+
321+
TEST_ASSERT_EQUAL_INT32(false, peripheral_domain_pd_allowed());
322+
sleep_retention_dump_modules(stdout);
323+
324+
wait_for_finish(&s_test_slv_ctx);
325+
326+
sdio_slave_stop();
327+
sdio_slave_deinit();
328+
329+
TEST_ASSERT_EQUAL_INT32(true, peripheral_domain_pd_allowed());
330+
}
331+
#endif
332+
308333
TEST_CASE("SDIO_Slave: test to host (Performance)", "[sdio_speed]")
309334
{
310335
test_to_host();
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
CONFIG_PM_ENABLE=y
2+
CONFIG_PM_POWER_DOWN_CPU_IN_LIGHT_SLEEP=y
3+
CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP=y
4+
CONFIG_FREERTOS_USE_TICKLESS_IDLE=y

components/esp_hw_support/include/esp_private/sleep_retention.h

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,11 @@ typedef enum {
5959
*/
6060
esp_err_t sleep_retention_entries_create(const sleep_retention_entries_config_t retent[], int num, regdma_link_priority_t priority, sleep_retention_module_t module);
6161

62+
/**
63+
* @brief Dump the initialization status of all modules.
64+
*/
65+
void sleep_retention_dump_modules(FILE *out);
66+
6267
/**
6368
* @brief Dump all runtime sleep retention linked lists
6469
*/
@@ -139,6 +144,23 @@ esp_err_t sleep_retention_module_allocate(sleep_retention_module_t module);
139144
*/
140145
esp_err_t sleep_retention_module_free(sleep_retention_module_t module);
141146

147+
/**
148+
* @brief Force take the power lock so that during sleep the power domain won't be powered off.
149+
*
150+
* @return
151+
* - ESP_OK if success
152+
* - other value when the internal `sleep_retention_module_init` fails.
153+
*/
154+
esp_err_t sleep_retention_power_lock_acquire(void);
155+
156+
/**
157+
* @brief Release the power lock so that the peripherals' power domain can be powered off.
158+
* Please note that there is an internal reference counter and the power domain will be kept on until same number
159+
* of `sleep_retention_power_lock_release` is called as `sleep_retention_power_lock_acquire`.
160+
* @return always ESP_OK
161+
*/
162+
esp_err_t sleep_retention_power_lock_release(void);
163+
142164
/**
143165
* @brief Get all initialized modules that require sleep retention
144166
*

components/esp_hw_support/sleep_retention.c

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@
2929
#endif
3030

3131
static __attribute__((unused)) const char *TAG = "sleep";
32+
static int acquire_cnt; //for the force acquire lock
33+
3234

3335
struct sleep_retention_module_object {
3436
sleep_retention_module_callbacks_t cbs; /* A callback list that can extend more sleep retention event callbacks */
@@ -319,6 +321,23 @@ static void sleep_retention_entries_stats(void)
319321
_lock_release_recursive(&s_retention.lock);
320322
}
321323

324+
void sleep_retention_dump_modules(FILE *out)
325+
{
326+
uint32_t inited_modules = sleep_retention_get_inited_modules();
327+
uint32_t created_modules = sleep_retention_get_created_modules();
328+
for (int i = SLEEP_RETENTION_MODULE_MIN; i <= SLEEP_RETENTION_MODULE_MAX; i++) {
329+
bool inited = (inited_modules & BIT(i)) != 0;
330+
bool created = (created_modules & BIT(i)) != 0;
331+
bool is_top = (TOP_DOMAIN_PERIPHERALS_BM & BIT(i)) != 0;
332+
333+
const char* status = !inited? "-":
334+
created? "CREATED":
335+
"INITED";
336+
const char* domain = is_top? "TOP": "-";
337+
fprintf(out, "%2d: %4s %8s\n", i, domain, status);
338+
}
339+
}
340+
322341
void sleep_retention_dump_entries(FILE *out)
323342
{
324343
_lock_acquire_recursive(&s_retention.lock);
@@ -820,6 +839,42 @@ esp_err_t sleep_retention_module_free(sleep_retention_module_t module)
820839
return err;
821840
}
822841

842+
static esp_err_t empty_create(void *args)
843+
{
844+
return ESP_OK;
845+
}
846+
847+
esp_err_t sleep_retention_power_lock_acquire(void)
848+
{
849+
_lock_acquire_recursive(&s_retention.lock);
850+
if (acquire_cnt == 0) {
851+
sleep_retention_module_init_param_t init_param = {
852+
.cbs = { .create = {.handle = empty_create},},
853+
};
854+
esp_err_t ret = sleep_retention_module_init(SLEEP_RETENTION_MODULE_NULL, &init_param);
855+
if (ret != ESP_OK) {
856+
_lock_release_recursive(&s_retention.lock);
857+
return ret;
858+
}
859+
}
860+
acquire_cnt++;
861+
_lock_release_recursive(&s_retention.lock);
862+
return ESP_OK;
863+
}
864+
865+
esp_err_t sleep_retention_power_lock_release(void)
866+
{
867+
esp_err_t ret = ESP_OK;
868+
_lock_acquire_recursive(&s_retention.lock);
869+
acquire_cnt--;
870+
assert(acquire_cnt >= 0);
871+
if (acquire_cnt == 0) {
872+
ret = sleep_retention_module_deinit(SLEEP_RETENTION_MODULE_NULL);
873+
}
874+
_lock_release_recursive(&s_retention.lock);
875+
return ret;
876+
}
877+
823878
void IRAM_ATTR sleep_retention_do_extra_retention(bool backup_or_restore)
824879
{
825880
if (s_retention.highpri < SLEEP_RETENTION_REGDMA_LINK_HIGHEST_PRIORITY ||

components/esp_hw_support/test_apps/.build-test-rules.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,11 @@ components/esp_hw_support/test_apps/rtc_power_modes:
4242
temporary: true
4343
reason: the other targets are not tested yet
4444

45+
components/esp_hw_support/test_apps/sleep_retention:
46+
enable:
47+
- if: SOC_PAU_SUPPORTED == 1 and CONFIG_NAME != "xip_psram"
48+
- if: SOC_PAU_SUPPORTED == 1 and (SOC_SPIRAM_XIP_SUPPORTED == 1 and CONFIG_NAME == "xip_psram")
49+
4550
components/esp_hw_support/test_apps/vad_wakeup:
4651
disable:
4752
- if: SOC_LP_VAD_SUPPORTED != 1

0 commit comments

Comments
 (0)