mirror of
https://github.com/espressif/esp-idf.git
synced 2024-10-05 20:47:46 -04:00
Merge branch 'feature/esp32p4_sdmmc_on_real_chip' into 'master'
sdmmc: p4 sdmmc on real chip (relies ldo on real chip) Closes IDF-6502 See merge request espressif/esp-idf!27762
This commit is contained in:
commit
dbe1df8cde
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
@ -19,6 +19,7 @@
|
||||
#include "driver/gpio.h"
|
||||
#include "driver/sdmmc_host.h"
|
||||
#include "esp_private/periph_ctrl.h"
|
||||
#include "esp_private/esp_ldo.h"
|
||||
#include "sdmmc_private.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/semphr.h"
|
||||
@ -54,6 +55,7 @@ typedef struct slot_ctx_t {
|
||||
size_t slot_width;
|
||||
sdmmc_slot_io_info_t slot_gpio_num;
|
||||
bool use_gpio_matrix;
|
||||
esp_ldo_unit_handle_t ldo_unit;
|
||||
} slot_ctx_t;
|
||||
|
||||
/**
|
||||
@ -662,6 +664,21 @@ esp_err_t sdmmc_host_init_slot(int slot, const sdmmc_slot_config_t *slot_config)
|
||||
if (ret != ESP_OK) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
#if SOC_MULTI_USAGE_LDO_SUPPORTED
|
||||
esp_ldo_unit_init_cfg_t init_ldo_cfg = {
|
||||
.unit_id = LDO_UNIT_4,
|
||||
.cfg = {
|
||||
.voltage_mv = 3300,
|
||||
},
|
||||
.flags.shared_ldo = true,
|
||||
};
|
||||
esp_ldo_unit_handle_t ldo_unit = NULL;
|
||||
ESP_RETURN_ON_ERROR(esp_ldo_init_unit(&init_ldo_cfg, &ldo_unit), TAG, "LDO init failed");
|
||||
ESP_RETURN_ON_ERROR(esp_ldo_enable_unit(ldo_unit), TAG, "LDO enable failed");
|
||||
s_host_ctx.slot_ctx[slot].ldo_unit = ldo_unit;
|
||||
#endif
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
@ -683,6 +700,16 @@ esp_err_t sdmmc_host_deinit(void)
|
||||
sdmmc_ll_enable_bus_clock(s_host_ctx.hal.dev, false);
|
||||
}
|
||||
|
||||
#if SOC_MULTI_USAGE_LDO_SUPPORTED
|
||||
for (int i = 0; i < SOC_SDMMC_NUM_SLOTS; i++) {
|
||||
if (s_host_ctx.slot_ctx[i].ldo_unit) {
|
||||
ESP_RETURN_ON_ERROR(esp_ldo_disable_unit(s_host_ctx.slot_ctx[i].ldo_unit), TAG, "LDO disable failed");
|
||||
ESP_RETURN_ON_ERROR(esp_ldo_deinit_unit(s_host_ctx.slot_ctx[i].ldo_unit), TAG, "LDO deinit failed");
|
||||
s_host_ctx.slot_ctx[i].ldo_unit = NULL;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
@ -69,41 +69,54 @@ esp_err_t esp_dma_calloc(size_t n, size_t size, uint32_t flags, void **out_ptr,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static bool s_buf_in_region(const void *ptr, size_t size, esp_dma_buf_location_t location, uint32_t *in_out_flags)
|
||||
{
|
||||
bool found = false;
|
||||
if (location == ESP_DMA_BUF_LOCATION_INTERNAL) {
|
||||
if (esp_ptr_dma_capable(ptr) && esp_ptr_dma_capable(ptr + size - 1)) {
|
||||
found = true;
|
||||
}
|
||||
} else if (location == ESP_DMA_BUF_LOCATION_PSRAM) {
|
||||
#if SOC_PSRAM_DMA_CAPABLE
|
||||
if (esp_ptr_external_ram(ptr) && esp_ptr_external_ram(ptr + size - 1)) {
|
||||
*in_out_flags |= ESP_DMA_MALLOC_FLAG_PSRAM;
|
||||
found = true;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
return found;
|
||||
}
|
||||
|
||||
bool esp_dma_is_buffer_aligned(const void *ptr, size_t size, esp_dma_buf_location_t location)
|
||||
{
|
||||
assert(ptr);
|
||||
uint32_t flags = ESP_CACHE_MALLOC_FLAG_DMA;
|
||||
|
||||
if (location == ESP_DMA_BUF_LOCATION_INTERNAL) {
|
||||
if (!esp_ptr_dma_capable(ptr) || !esp_ptr_dma_capable(ptr + size - 1)) {
|
||||
return false;
|
||||
bool found = false;
|
||||
if (location == ESP_DMA_BUF_LOCATION_AUTO) {
|
||||
for (int i = ESP_DMA_BUF_LOCATION_INTERNAL; i < ESP_DMA_BUF_LOCATION_AUTO; i++) {
|
||||
if (s_buf_in_region(ptr, size, i, &flags)) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if (location == ESP_DMA_BUF_LOCATION_INTERNAL) {
|
||||
found = s_buf_in_region(ptr, size, ESP_DMA_BUF_LOCATION_INTERNAL, &flags);
|
||||
} else {
|
||||
#if !SOC_PSRAM_DMA_CAPABLE
|
||||
found = s_buf_in_region(ptr, size, ESP_DMA_BUF_LOCATION_PSRAM, &flags);
|
||||
}
|
||||
if (!found) {
|
||||
return false;
|
||||
#endif
|
||||
if (!esp_ptr_external_ram(ptr) || !esp_ptr_external_ram(ptr + size - 1)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
flags |= ESP_DMA_MALLOC_FLAG_PSRAM;
|
||||
}
|
||||
|
||||
bool is_aligned = false;
|
||||
|
||||
#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE
|
||||
size_t dma_alignment = 0;
|
||||
size_t cache_alignment = 0;
|
||||
size_t alignment = 0;
|
||||
esp_err_t ret = esp_cache_get_alignment(flags, &cache_alignment);
|
||||
assert(ret == ESP_OK);
|
||||
if (((intptr_t)ptr % cache_alignment == 0) && (size % cache_alignment == 0)) {
|
||||
is_aligned = true;
|
||||
}
|
||||
#else
|
||||
(void)size;
|
||||
if ((intptr_t)ptr % 4 == 0) {
|
||||
is_aligned = true;
|
||||
}
|
||||
#endif
|
||||
alignment = MAX(dma_alignment, cache_alignment);
|
||||
is_aligned = ((intptr_t)ptr % alignment == 0) && (size % alignment == 0);
|
||||
|
||||
return is_aligned;
|
||||
}
|
||||
|
@ -59,6 +59,7 @@ esp_err_t esp_dma_calloc(size_t n, size_t size, uint32_t flags, void **out_ptr,
|
||||
typedef enum {
|
||||
ESP_DMA_BUF_LOCATION_INTERNAL, ///< DMA buffer is in internal memory
|
||||
ESP_DMA_BUF_LOCATION_PSRAM, ///< DMA buffer is in PSRAM
|
||||
ESP_DMA_BUF_LOCATION_AUTO, ///< Auto detect buffer location, under this condition API will loop to search the buffer location
|
||||
} esp_dma_buf_location_t;
|
||||
|
||||
/**
|
||||
|
@ -9,16 +9,12 @@
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "esp_err.h"
|
||||
#include "hal/ldo_types.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define ESP_LDO_ID_1 0 ///< See datasheet `VFB/VO1`
|
||||
#define ESP_LDO_ID_2 1 ///< See datasheet `VFB/VO2`
|
||||
#define ESP_LDO_ID_3 2 ///< See datasheet `VFB/VO3`
|
||||
#define ESP_LDO_ID_4 3 ///< See datasheet `VFB/VO4`
|
||||
|
||||
/**
|
||||
* @brief Type of LDO unit handle
|
||||
*/
|
||||
|
@ -15,7 +15,7 @@
|
||||
TEST_CASE("LDO unit early / normal allocation", "[LDO]")
|
||||
{
|
||||
esp_ldo_unit_init_cfg_t init_early_unit_cfg = {
|
||||
.unit_id = ESP_LDO_ID_3,
|
||||
.unit_id = LDO_UNIT_3,
|
||||
.cfg = {
|
||||
.voltage_mv = 1800,
|
||||
},
|
||||
@ -27,7 +27,7 @@ TEST_CASE("LDO unit early / normal allocation", "[LDO]")
|
||||
|
||||
esp_ldo_unit_handle_t unit = NULL;
|
||||
esp_ldo_unit_init_cfg_t init_unit_cfg = {
|
||||
.unit_id = ESP_LDO_ID_4,
|
||||
.unit_id = LDO_UNIT_4,
|
||||
.cfg = {
|
||||
.voltage_mv = 2500,
|
||||
},
|
||||
@ -48,7 +48,7 @@ TEST_CASE("LDO unit early / normal allocation", "[LDO]")
|
||||
TEST_CASE("LDO unit output", "[LDO][mannual][ignore]")
|
||||
{
|
||||
esp_ldo_unit_init_cfg_t early_unit_cfg = {
|
||||
.unit_id = ESP_LDO_ID_2,
|
||||
.unit_id = LDO_UNIT_2,
|
||||
.cfg = {
|
||||
.voltage_mv = 2500,
|
||||
},
|
||||
@ -57,12 +57,12 @@ TEST_CASE("LDO unit output", "[LDO][mannual][ignore]")
|
||||
esp_ldo_unit_handle_t early_unit2 = esp_ldo_init_unit_early(&early_unit_cfg);
|
||||
assert(early_unit2);
|
||||
|
||||
early_unit_cfg.unit_id = ESP_LDO_ID_3;
|
||||
early_unit_cfg.unit_id = LDO_UNIT_3;
|
||||
early_unit_cfg.cfg.voltage_mv = 3300;
|
||||
esp_ldo_unit_handle_t early_unit3 = esp_ldo_init_unit_early(&early_unit_cfg);
|
||||
assert(early_unit3);
|
||||
|
||||
early_unit_cfg.unit_id = ESP_LDO_ID_4;
|
||||
early_unit_cfg.unit_id = LDO_UNIT_4;
|
||||
early_unit_cfg.cfg.voltage_mv = 1100;
|
||||
esp_ldo_unit_handle_t early_unit4 = esp_ldo_init_unit_early(&early_unit_cfg);
|
||||
assert(early_unit4);
|
||||
|
@ -31,7 +31,6 @@ extern "C" {
|
||||
/**
|
||||
* SDMMC capabilities
|
||||
*/
|
||||
#define SDMMC_LL_MAX_FREQ_KHZ_FPGA (4*1000)
|
||||
#define SDMMC_LL_SLOT_SUPPORT_GPIO_MATRIX(SLOT_ID) ((SLOT_ID == 0) ? 0 : 1)
|
||||
|
||||
#define SDMMC_LL_IOMUX_FUNC 0
|
||||
|
28
components/hal/include/hal/ldo_types.h
Normal file
28
components/hal/include/hal/ldo_types.h
Normal file
@ -0,0 +1,28 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2020-2023 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief LDO Unit
|
||||
*
|
||||
* @note See datasheet to know LDO, alias includes but not least to `VFB/VOn`
|
||||
*/
|
||||
typedef enum {
|
||||
LDO_UNIT_1, ///< LDO 1
|
||||
LDO_UNIT_2, ///< LDO 2
|
||||
LDO_UNIT_3, ///< LDO 3
|
||||
LDO_UNIT_4, ///< LDO 4
|
||||
} ldo_unit_t;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
@ -11,4 +11,4 @@ idf_component_register(SRCS "sdmmc_cmd.c"
|
||||
"sdmmc_mmc.c"
|
||||
"sdmmc_sd.c"
|
||||
INCLUDE_DIRS include
|
||||
PRIV_REQUIRES soc esp_timer)
|
||||
PRIV_REQUIRES soc esp_timer esp_mm)
|
||||
|
@ -17,6 +17,7 @@
|
||||
|
||||
#include <inttypes.h>
|
||||
#include "esp_timer.h"
|
||||
#include "esp_cache.h"
|
||||
#include "sdmmc_common.h"
|
||||
|
||||
static const char* TAG = "sdmmc_sd";
|
||||
@ -191,12 +192,14 @@ esp_err_t sdmmc_send_cmd_switch_func(sdmmc_card_t* card,
|
||||
uint32_t other_func_mask = (0x00ffffff & ~(0xf << group_shift));
|
||||
uint32_t func_val = (function << group_shift) | other_func_mask;
|
||||
|
||||
size_t datalen = sizeof(sdmmc_switch_func_rsp_t);
|
||||
sdmmc_command_t cmd = {
|
||||
.opcode = MMC_SWITCH,
|
||||
.flags = SCF_CMD_ADTC | SCF_CMD_READ | SCF_RSP_R1,
|
||||
.blklen = sizeof(sdmmc_switch_func_rsp_t),
|
||||
.data = resp->data,
|
||||
.datalen = sizeof(sdmmc_switch_func_rsp_t),
|
||||
.datalen = datalen,
|
||||
.buflen = datalen,
|
||||
.arg = (!!mode << 31) | func_val
|
||||
};
|
||||
|
||||
@ -233,13 +236,16 @@ esp_err_t sdmmc_enable_hs_mode(sdmmc_card_t* card)
|
||||
((card->csd.card_command_class & SD_CSD_CCC_SWITCH) == 0)) {
|
||||
return ESP_ERR_NOT_SUPPORTED;
|
||||
}
|
||||
sdmmc_switch_func_rsp_t* response = (sdmmc_switch_func_rsp_t*)
|
||||
heap_caps_malloc(sizeof(*response), MALLOC_CAP_DMA);
|
||||
if (response == NULL) {
|
||||
return ESP_ERR_NO_MEM;
|
||||
|
||||
size_t actual_size = 0;
|
||||
sdmmc_switch_func_rsp_t *response = NULL;
|
||||
esp_err_t err = esp_dma_malloc(sizeof(*response), 0, (void *)&response, &actual_size);
|
||||
assert(actual_size == sizeof(*response));
|
||||
if (err != ESP_OK) {
|
||||
return err;
|
||||
}
|
||||
|
||||
esp_err_t err = sdmmc_send_cmd_switch_func(card, 0, SD_ACCESS_MODE, 0, response);
|
||||
err = sdmmc_send_cmd_switch_func(card, 0, SD_ACCESS_MODE, 0, response);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGD(TAG, "%s: sdmmc_send_cmd_switch_func (1) returned 0x%x", __func__, err);
|
||||
goto out;
|
||||
|
@ -76,6 +76,7 @@ Overview
|
||||
- :c:macro:`SDMMC_HOST_SLOT_1` is routed via GPIO Matrix. This means that any GPIO may be used for each of the SD card signals. It is for non UHS-I usage.
|
||||
- :c:macro:`SDMMC_HOST_SLOT_0` is dedicated to UHS-I mode, which is not yet supported in the driver.
|
||||
|
||||
Currently SDMMC host driver is using the on-chip LDO 4 as the default power supply. SDMMC power control driver is not supported yet. If you buy the ESP32P4 chip itself and plan to use SDMMC peripheral, make sure the VDDPST_5 pin is connected to the on-chip LDO 4 or correct external power supply.
|
||||
|
||||
Supported Speed Modes
|
||||
---------------------
|
||||
|
Loading…
Reference in New Issue
Block a user