mirror of
https://github.com/espressif/esp-idf.git
synced 2024-10-05 20:47:46 -04:00
feat(sdmmc): supported sd2.0 on esp32p4
This commit is contained in:
parent
1685dbc985
commit
70314b56d5
112
components/driver/sdmmc/include/driver/sdmmc_default_configs.h
Normal file
112
components/driver/sdmmc/include/driver/sdmmc_default_configs.h
Normal file
@ -0,0 +1,112 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "sdkconfig.h"
|
||||||
|
#include "sdmmc_types.h"
|
||||||
|
#include "soc/soc_caps.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define SDMMC_HOST_SLOT_0 0 ///< SDMMC slot 0
|
||||||
|
#define SDMMC_HOST_SLOT_1 1 ///< SDMMC slot 1
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Default sdmmc_host_t structure initializer for SDMMC peripheral
|
||||||
|
*
|
||||||
|
* Uses SDMMC peripheral, with 4-bit mode enabled, and max frequency set to 20MHz
|
||||||
|
*/
|
||||||
|
#define SDMMC_HOST_DEFAULT() {\
|
||||||
|
.flags = SDMMC_HOST_FLAG_8BIT | \
|
||||||
|
SDMMC_HOST_FLAG_4BIT | \
|
||||||
|
SDMMC_HOST_FLAG_1BIT | \
|
||||||
|
SDMMC_HOST_FLAG_DDR, \
|
||||||
|
.slot = SDMMC_HOST_SLOT_1, \
|
||||||
|
.max_freq_khz = SDMMC_FREQ_DEFAULT, \
|
||||||
|
.io_voltage = 3.3f, \
|
||||||
|
.init = &sdmmc_host_init, \
|
||||||
|
.set_bus_width = &sdmmc_host_set_bus_width, \
|
||||||
|
.get_bus_width = &sdmmc_host_get_slot_width, \
|
||||||
|
.set_bus_ddr_mode = &sdmmc_host_set_bus_ddr_mode, \
|
||||||
|
.set_card_clk = &sdmmc_host_set_card_clk, \
|
||||||
|
.set_cclk_always_on = &sdmmc_host_set_cclk_always_on, \
|
||||||
|
.do_transaction = &sdmmc_host_do_transaction, \
|
||||||
|
.deinit = &sdmmc_host_deinit, \
|
||||||
|
.io_int_enable = sdmmc_host_io_int_enable, \
|
||||||
|
.io_int_wait = sdmmc_host_io_int_wait, \
|
||||||
|
.command_timeout_ms = 0, \
|
||||||
|
.get_real_freq = &sdmmc_host_get_real_freq, \
|
||||||
|
.input_delay_phase = SDMMC_DELAY_PHASE_0, \
|
||||||
|
.set_input_delay = &sdmmc_host_set_input_delay \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define SDMMC_SLOT_NO_CD GPIO_NUM_NC ///< indicates that card detect line is not used
|
||||||
|
#define SDMMC_SLOT_NO_WP GPIO_NUM_NC ///< indicates that write protect line is not used
|
||||||
|
#define SDMMC_SLOT_WIDTH_DEFAULT 0 ///< use the maximum possible width for the slot
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#if SOC_SDMMC_USE_IOMUX && !SOC_SDMMC_USE_GPIO_MATRIX
|
||||||
|
/**
|
||||||
|
* Macro defining default configuration of SDMMC host slot
|
||||||
|
*/
|
||||||
|
#define SDMMC_SLOT_CONFIG_DEFAULT() {\
|
||||||
|
.cd = SDMMC_SLOT_NO_CD, \
|
||||||
|
.wp = SDMMC_SLOT_NO_WP, \
|
||||||
|
.width = SDMMC_SLOT_WIDTH_DEFAULT, \
|
||||||
|
.flags = 0, \
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Macro defining default configuration of SDMMC host slot
|
||||||
|
*/
|
||||||
|
#if CONFIG_IDF_TARGET_ESP32P4
|
||||||
|
#define SDMMC_SLOT_CONFIG_DEFAULT() {\
|
||||||
|
.clk = GPIO_NUM_43, \
|
||||||
|
.cmd = GPIO_NUM_44, \
|
||||||
|
.d0 = GPIO_NUM_39, \
|
||||||
|
.d1 = GPIO_NUM_40, \
|
||||||
|
.d2 = GPIO_NUM_41, \
|
||||||
|
.d3 = GPIO_NUM_42, \
|
||||||
|
.d4 = GPIO_NUM_45, \
|
||||||
|
.d5 = GPIO_NUM_46, \
|
||||||
|
.d6 = GPIO_NUM_47, \
|
||||||
|
.d7 = GPIO_NUM_48, \
|
||||||
|
.cd = SDMMC_SLOT_NO_CD, \
|
||||||
|
.wp = SDMMC_SLOT_NO_WP, \
|
||||||
|
.width = SDMMC_SLOT_WIDTH_DEFAULT, \
|
||||||
|
.flags = 0, \
|
||||||
|
}
|
||||||
|
|
||||||
|
#elif CONFIG_IDF_TARGET_ESP32S3
|
||||||
|
#define SDMMC_SLOT_CONFIG_DEFAULT() {\
|
||||||
|
.clk = GPIO_NUM_14, \
|
||||||
|
.cmd = GPIO_NUM_15, \
|
||||||
|
.d0 = GPIO_NUM_2, \
|
||||||
|
.d1 = GPIO_NUM_4, \
|
||||||
|
.d2 = GPIO_NUM_12, \
|
||||||
|
.d3 = GPIO_NUM_13, \
|
||||||
|
.d4 = GPIO_NUM_33, \
|
||||||
|
.d5 = GPIO_NUM_34, \
|
||||||
|
.d6 = GPIO_NUM_35, \
|
||||||
|
.d7 = GPIO_NUM_36, \
|
||||||
|
.cd = SDMMC_SLOT_NO_CD, \
|
||||||
|
.wp = SDMMC_SLOT_NO_WP, \
|
||||||
|
.width = SDMMC_SLOT_WIDTH_DEFAULT, \
|
||||||
|
.flags = 0, \
|
||||||
|
}
|
||||||
|
#endif // GPIO Matrix chips
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
|
* SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*/
|
*/
|
||||||
@ -13,44 +13,13 @@
|
|||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include "esp_err.h"
|
#include "esp_err.h"
|
||||||
#include "sdmmc_types.h"
|
#include "sdmmc_types.h"
|
||||||
|
#include "driver/sdmmc_default_configs.h"
|
||||||
#include "driver/gpio.h"
|
#include "driver/gpio.h"
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define SDMMC_HOST_SLOT_0 0 ///< SDMMC slot 0
|
|
||||||
#define SDMMC_HOST_SLOT_1 1 ///< SDMMC slot 1
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Default sdmmc_host_t structure initializer for SDMMC peripheral
|
|
||||||
*
|
|
||||||
* Uses SDMMC peripheral, with 4-bit mode enabled, and max frequency set to 20MHz
|
|
||||||
*/
|
|
||||||
#define SDMMC_HOST_DEFAULT() {\
|
|
||||||
.flags = SDMMC_HOST_FLAG_8BIT | \
|
|
||||||
SDMMC_HOST_FLAG_4BIT | \
|
|
||||||
SDMMC_HOST_FLAG_1BIT | \
|
|
||||||
SDMMC_HOST_FLAG_DDR, \
|
|
||||||
.slot = SDMMC_HOST_SLOT_1, \
|
|
||||||
.max_freq_khz = SDMMC_FREQ_DEFAULT, \
|
|
||||||
.io_voltage = 3.3f, \
|
|
||||||
.init = &sdmmc_host_init, \
|
|
||||||
.set_bus_width = &sdmmc_host_set_bus_width, \
|
|
||||||
.get_bus_width = &sdmmc_host_get_slot_width, \
|
|
||||||
.set_bus_ddr_mode = &sdmmc_host_set_bus_ddr_mode, \
|
|
||||||
.set_card_clk = &sdmmc_host_set_card_clk, \
|
|
||||||
.set_cclk_always_on = &sdmmc_host_set_cclk_always_on, \
|
|
||||||
.do_transaction = &sdmmc_host_do_transaction, \
|
|
||||||
.deinit = &sdmmc_host_deinit, \
|
|
||||||
.io_int_enable = sdmmc_host_io_int_enable, \
|
|
||||||
.io_int_wait = sdmmc_host_io_int_wait, \
|
|
||||||
.command_timeout_ms = 0, \
|
|
||||||
.get_real_freq = &sdmmc_host_get_real_freq, \
|
|
||||||
.input_delay_phase = SDMMC_DELAY_PHASE_0, \
|
|
||||||
.set_input_delay = &sdmmc_host_set_input_delay \
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Extra configuration for SDMMC peripheral slot
|
* Extra configuration for SDMMC peripheral slot
|
||||||
*/
|
*/
|
||||||
@ -89,46 +58,6 @@ typedef struct {
|
|||||||
*/
|
*/
|
||||||
} sdmmc_slot_config_t;
|
} sdmmc_slot_config_t;
|
||||||
|
|
||||||
#define SDMMC_SLOT_NO_CD GPIO_NUM_NC ///< indicates that card detect line is not used
|
|
||||||
#define SDMMC_SLOT_NO_WP GPIO_NUM_NC ///< indicates that write protect line is not used
|
|
||||||
#define SDMMC_SLOT_WIDTH_DEFAULT 0 ///< use the maximum possible width for the slot
|
|
||||||
|
|
||||||
#ifdef SOC_SDMMC_USE_GPIO_MATRIX
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Macro defining default configuration of SDMMC host slot
|
|
||||||
*/
|
|
||||||
#define SDMMC_SLOT_CONFIG_DEFAULT() {\
|
|
||||||
.clk = GPIO_NUM_14, \
|
|
||||||
.cmd = GPIO_NUM_15, \
|
|
||||||
.d0 = GPIO_NUM_2, \
|
|
||||||
.d1 = GPIO_NUM_4, \
|
|
||||||
.d2 = GPIO_NUM_12, \
|
|
||||||
.d3 = GPIO_NUM_13, \
|
|
||||||
.d4 = GPIO_NUM_33, \
|
|
||||||
.d5 = GPIO_NUM_34, \
|
|
||||||
.d6 = GPIO_NUM_35, \
|
|
||||||
.d7 = GPIO_NUM_36, \
|
|
||||||
.cd = SDMMC_SLOT_NO_CD, \
|
|
||||||
.wp = SDMMC_SLOT_NO_WP, \
|
|
||||||
.width = SDMMC_SLOT_WIDTH_DEFAULT, \
|
|
||||||
.flags = 0, \
|
|
||||||
}
|
|
||||||
|
|
||||||
#else // SOC_SDMMC_USE_GPIO_MATRIX
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Macro defining default configuration of SDMMC host slot
|
|
||||||
*/
|
|
||||||
#define SDMMC_SLOT_CONFIG_DEFAULT() {\
|
|
||||||
.cd = SDMMC_SLOT_NO_CD, \
|
|
||||||
.wp = SDMMC_SLOT_NO_WP, \
|
|
||||||
.width = SDMMC_SLOT_WIDTH_DEFAULT, \
|
|
||||||
.flags = 0, \
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif // SOC_SDMMC_USE_GPIO_MATRIX
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Initialize SDMMC host peripheral
|
* @brief Initialize SDMMC host peripheral
|
||||||
*
|
*
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
*
|
*
|
||||||
* SPDX-License-Identifier: ISC
|
* SPDX-License-Identifier: ISC
|
||||||
*
|
*
|
||||||
* SPDX-FileContributor: 2016-2021 Espressif Systems (Shanghai) CO LTD
|
* SPDX-FileContributor: 2016-2023 Espressif Systems (Shanghai) CO LTD
|
||||||
*/
|
*/
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2006 Uwe Stuehler <uwe@openbsd.org>
|
* Copyright (c) 2006 Uwe Stuehler <uwe@openbsd.org>
|
||||||
@ -114,7 +114,8 @@ typedef struct {
|
|||||||
uint32_t arg; /*!< SD/MMC command argument */
|
uint32_t arg; /*!< SD/MMC command argument */
|
||||||
sdmmc_response_t response; /*!< response buffer */
|
sdmmc_response_t response; /*!< response buffer */
|
||||||
void* data; /*!< buffer to send or read into */
|
void* data; /*!< buffer to send or read into */
|
||||||
size_t datalen; /*!< length of data buffer */
|
size_t datalen; /*!< length of data in the buffer */
|
||||||
|
size_t buflen; /*!< length of the buffer */
|
||||||
size_t blklen; /*!< block length */
|
size_t blklen; /*!< block length */
|
||||||
int flags; /*!< see below */
|
int flags; /*!< see below */
|
||||||
/** @cond */
|
/** @cond */
|
||||||
|
@ -26,49 +26,46 @@
|
|||||||
#include "soc/sdmmc_periph.h"
|
#include "soc/sdmmc_periph.h"
|
||||||
#include "soc/soc_caps.h"
|
#include "soc/soc_caps.h"
|
||||||
#include "hal/gpio_hal.h"
|
#include "hal/gpio_hal.h"
|
||||||
|
#include "hal/sdmmc_hal.h"
|
||||||
|
#include "hal/sdmmc_ll.h"
|
||||||
|
|
||||||
#define SDMMC_EVENT_QUEUE_LENGTH 32
|
#define SDMMC_EVENT_QUEUE_LENGTH 32
|
||||||
|
#define SDMMC_CLK_NEEDS_RCC CONFIG_IDF_TARGET_ESP32P4
|
||||||
|
|
||||||
|
#if SDMMC_CLK_NEEDS_RCC
|
||||||
|
// Reset and Clock Control registers are mixing with other peripherals, so we need to use a critical section
|
||||||
|
#define SDMMC_RCC_ATOMIC() PERIPH_RCC_ATOMIC()
|
||||||
|
#else
|
||||||
|
#define SDMMC_RCC_ATOMIC()
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static const char *TAG = "sdmmc_periph";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Slot contexts
|
||||||
|
*/
|
||||||
|
typedef struct slot_ctx_t {
|
||||||
|
size_t slot_width;
|
||||||
|
sdmmc_slot_io_info_t slot_gpio_num;
|
||||||
|
bool use_gpio_matrix;
|
||||||
|
} slot_ctx_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Host contexts
|
||||||
|
*/
|
||||||
|
typedef struct host_ctx_t {
|
||||||
|
intr_handle_t intr_handle;
|
||||||
|
QueueHandle_t event_queue;
|
||||||
|
SemaphoreHandle_t io_intr_event;
|
||||||
|
sdmmc_hal_context_t hal;
|
||||||
|
slot_ctx_t slot_ctx[SOC_SDMMC_NUM_SLOTS];
|
||||||
|
} host_ctx_t;
|
||||||
|
|
||||||
|
static host_ctx_t s_host_ctx;
|
||||||
|
|
||||||
|
|
||||||
static void sdmmc_isr(void *arg);
|
static void sdmmc_isr(void *arg);
|
||||||
static void sdmmc_host_dma_init(void);
|
static void sdmmc_host_dma_init(void);
|
||||||
|
|
||||||
static const char *TAG = "sdmmc_periph";
|
|
||||||
static intr_handle_t s_intr_handle;
|
|
||||||
static QueueHandle_t s_event_queue;
|
|
||||||
static SemaphoreHandle_t s_io_intr_event;
|
|
||||||
|
|
||||||
static size_t s_slot_width[2] = {1, 1};
|
|
||||||
|
|
||||||
/* The following definitions are used to simplify GPIO configuration in the driver,
|
|
||||||
* whether IOMUX or GPIO Matrix is used by the chip.
|
|
||||||
* Two simple "APIs" are provided to the driver code:
|
|
||||||
* - configure_pin(name, slot, mode): Configures signal "name" for the given slot and mode.
|
|
||||||
* - GPIO_NUM(slot, name): Returns the GPIO number of signal "name" for the given slot.
|
|
||||||
*
|
|
||||||
* To make this work, configure_pin is defined as a macro that picks the parameters required
|
|
||||||
* for configuring GPIO matrix or IOMUX from relevant arrays, and passes them to either of
|
|
||||||
* configure_pin_gpio_matrix, configure_pin_iomux functions.
|
|
||||||
* Likewise, GPIO_NUM is a macro that picks the pin number from one of the two structures.
|
|
||||||
*
|
|
||||||
* Macros are used rather than inline functions to look up members of different structures
|
|
||||||
* with same names. E.g. the number of pin d3 is obtained either from .d3 member of
|
|
||||||
* sdmmc_slot_gpio_num array (for IOMUX) or from .d3 member of s_sdmmc_slot_gpio_num array
|
|
||||||
* (for GPIO matrix).
|
|
||||||
*/
|
|
||||||
#ifdef SOC_SDMMC_USE_GPIO_MATRIX
|
|
||||||
static void configure_pin_gpio_matrix(uint8_t gpio_num, uint8_t gpio_matrix_sig, gpio_mode_t mode, const char *name);
|
|
||||||
#define configure_pin(name, slot, mode) \
|
|
||||||
configure_pin_gpio_matrix(s_sdmmc_slot_gpio_num[slot].name, sdmmc_slot_gpio_sig[slot].name, mode, #name)
|
|
||||||
static sdmmc_slot_io_info_t s_sdmmc_slot_gpio_num[SOC_SDMMC_NUM_SLOTS];
|
|
||||||
#define GPIO_NUM(slot, name) s_sdmmc_slot_gpio_num[slot].name
|
|
||||||
|
|
||||||
#elif SOC_SDMMC_USE_IOMUX
|
|
||||||
static void configure_pin_iomux(uint8_t gpio_num);
|
|
||||||
#define configure_pin(name, slot, mode) configure_pin_iomux(sdmmc_slot_gpio_num[slot].name)
|
|
||||||
#define GPIO_NUM(slot, name) sdmmc_slot_gpio_num[slot].name
|
|
||||||
|
|
||||||
#endif // SOC_SDMMC_USE_GPIO_MATRIX
|
|
||||||
|
|
||||||
static esp_err_t sdmmc_host_pullup_en_internal(int slot, int width);
|
static esp_err_t sdmmc_host_pullup_en_internal(int slot, int width);
|
||||||
|
|
||||||
esp_err_t sdmmc_host_reset(void)
|
esp_err_t sdmmc_host_reset(void)
|
||||||
@ -120,74 +117,18 @@ esp_err_t sdmmc_host_reset(void)
|
|||||||
* Of the second stage dividers, div0 is used for card 0, and div1 is used
|
* Of the second stage dividers, div0 is used for card 0, and div1 is used
|
||||||
* for card 1.
|
* for card 1.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static void sdmmc_host_set_clk_div(int div)
|
static void sdmmc_host_set_clk_div(int div)
|
||||||
{
|
{
|
||||||
/**
|
SDMMC_RCC_ATOMIC() {
|
||||||
* Set frequency to 160MHz / div
|
sdmmc_ll_set_clock_div(s_host_ctx.hal.dev, div);
|
||||||
*
|
sdmmc_ll_select_clk_source(s_host_ctx.hal.dev, SDMMC_CLK_SRC_DEFAULT);
|
||||||
* n: counter resets at div_factor_n.
|
sdmmc_ll_init_phase_delay(s_host_ctx.hal.dev);
|
||||||
* l: negedge when counter equals div_factor_l.
|
}
|
||||||
* h: posedge when counter equals div_factor_h.
|
|
||||||
*
|
|
||||||
* We set the duty cycle to 1/2
|
|
||||||
*/
|
|
||||||
#if CONFIG_IDF_TARGET_ESP32
|
|
||||||
assert (div > 1 && div <= 16);
|
|
||||||
int h = div - 1;
|
|
||||||
int l = div / 2 - 1;
|
|
||||||
|
|
||||||
SDMMC.clock.div_factor_h = h;
|
|
||||||
SDMMC.clock.div_factor_l = l;
|
|
||||||
SDMMC.clock.div_factor_n = h;
|
|
||||||
|
|
||||||
// Set phases for in/out clocks
|
|
||||||
// 180 degree phase on input and output clocks
|
|
||||||
SDMMC.clock.phase_dout = 4;
|
|
||||||
SDMMC.clock.phase_din = 4;
|
|
||||||
SDMMC.clock.phase_core = 0;
|
|
||||||
|
|
||||||
#elif CONFIG_IDF_TARGET_ESP32S3
|
|
||||||
assert (div > 1 && div <= 16);
|
|
||||||
int l = div - 1;
|
|
||||||
int h = div / 2 - 1;
|
|
||||||
|
|
||||||
SDMMC.clock.div_factor_h = h;
|
|
||||||
SDMMC.clock.div_factor_l = l;
|
|
||||||
SDMMC.clock.div_factor_n = l;
|
|
||||||
|
|
||||||
// Make sure SOC_MOD_CLK_PLL_F160M (160 MHz) source clock is used
|
|
||||||
#if SOC_SDMMC_SUPPORT_XTAL_CLOCK
|
|
||||||
SDMMC.clock.clk_sel = 1;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
SDMMC.clock.phase_core = 0;
|
|
||||||
/* 90 deg. delay for cclk_out to satisfy large hold time for SDR12 (up to 25MHz) and SDR25 (up to 50MHz) modes.
|
|
||||||
* Whether this delayed clock will be used depends on use_hold_reg bit in CMD structure,
|
|
||||||
* determined when sending out the command.
|
|
||||||
*/
|
|
||||||
SDMMC.clock.phase_dout = 1;
|
|
||||||
SDMMC.clock.phase_din = 0;
|
|
||||||
#endif //CONFIG_IDF_TARGET_ESP32S3
|
|
||||||
|
|
||||||
// Wait for the clock to propagate
|
// Wait for the clock to propagate
|
||||||
esp_rom_delay_us(10);
|
esp_rom_delay_us(10);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int s_get_host_clk_div(void)
|
|
||||||
{
|
|
||||||
#if CONFIG_IDF_TARGET_ESP32
|
|
||||||
return SDMMC.clock.div_factor_h + 1;
|
|
||||||
#elif CONFIG_IDF_TARGET_ESP32S3
|
|
||||||
return SDMMC.clock.div_factor_l + 1;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
static void sdmmc_host_input_clk_disable(void)
|
|
||||||
{
|
|
||||||
SDMMC.clock.val = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static esp_err_t sdmmc_host_clock_update_command(int slot)
|
static esp_err_t sdmmc_host_clock_update_command(int slot)
|
||||||
{
|
{
|
||||||
// Clock update command (not a real command; just updates CIU registers)
|
// Clock update command (not a real command; just updates CIU registers)
|
||||||
@ -232,12 +173,18 @@ static esp_err_t sdmmc_host_clock_update_command(int slot)
|
|||||||
return ESP_OK;
|
return ESP_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
void sdmmc_host_get_clk_dividers(const uint32_t freq_khz, int *host_div, int *card_div)
|
void sdmmc_host_get_clk_dividers(uint32_t freq_khz, int *host_div, int *card_div)
|
||||||
{
|
{
|
||||||
uint32_t clk_src_freq_hz = 0;
|
uint32_t clk_src_freq_hz = 0;
|
||||||
esp_clk_tree_src_get_freq_hz(SDMMC_CLK_SRC_DEFAULT, ESP_CLK_TREE_SRC_FREQ_PRECISION_CACHED, &clk_src_freq_hz);
|
esp_clk_tree_src_get_freq_hz(SDMMC_CLK_SRC_DEFAULT, ESP_CLK_TREE_SRC_FREQ_PRECISION_CACHED, &clk_src_freq_hz);
|
||||||
assert(clk_src_freq_hz == (160 * 1000 * 1000));
|
assert(clk_src_freq_hz == (160 * 1000 * 1000));
|
||||||
|
|
||||||
|
#if SDMMC_LL_MAX_FREQ_KHZ_FPGA
|
||||||
|
if (freq_khz >= SDMMC_LL_MAX_FREQ_KHZ_FPGA) {
|
||||||
|
ESP_LOGW(TAG, "working on FPGA, fallback to use the %d KHz", SDMMC_LL_MAX_FREQ_KHZ_FPGA);
|
||||||
|
freq_khz = SDMMC_LL_MAX_FREQ_KHZ_FPGA;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
// Calculate new dividers
|
// Calculate new dividers
|
||||||
if (freq_khz >= SDMMC_FREQ_HIGHSPEED) {
|
if (freq_khz >= SDMMC_FREQ_HIGHSPEED) {
|
||||||
*host_div = 4; // 160 MHz / 4 = 40 MHz
|
*host_div = 4; // 160 MHz / 4 = 40 MHz
|
||||||
@ -282,7 +229,7 @@ esp_err_t sdmmc_host_set_card_clk(int slot, uint32_t freq_khz)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Disable clock first
|
// Disable clock first
|
||||||
SDMMC.clkena.cclk_enable &= ~BIT(slot);
|
sdmmc_ll_enable_card_clock(s_host_ctx.hal.dev, slot, false);
|
||||||
esp_err_t err = sdmmc_host_clock_update_command(slot);
|
esp_err_t err = sdmmc_host_clock_update_command(slot);
|
||||||
if (err != ESP_OK) {
|
if (err != ESP_OK) {
|
||||||
ESP_LOGE(TAG, "disabling clk failed");
|
ESP_LOGE(TAG, "disabling clk failed");
|
||||||
@ -297,17 +244,8 @@ esp_err_t sdmmc_host_set_card_clk(int slot, uint32_t freq_khz)
|
|||||||
int real_freq = sdmmc_host_calc_freq(host_div, card_div);
|
int real_freq = sdmmc_host_calc_freq(host_div, card_div);
|
||||||
ESP_LOGD(TAG, "slot=%d host_div=%d card_div=%d freq=%dkHz (max %" PRIu32 "kHz)", slot, host_div, card_div, real_freq, freq_khz);
|
ESP_LOGD(TAG, "slot=%d host_div=%d card_div=%d freq=%dkHz (max %" PRIu32 "kHz)", slot, host_div, card_div, real_freq, freq_khz);
|
||||||
|
|
||||||
// Program CLKDIV and CLKSRC, send them to the CIU
|
// Program card clock settings, send them to the CIU
|
||||||
switch(slot) {
|
sdmmc_ll_set_card_clock_div(s_host_ctx.hal.dev, slot, card_div);
|
||||||
case 0:
|
|
||||||
SDMMC.clksrc.card0 = 0;
|
|
||||||
SDMMC.clkdiv.div0 = card_div;
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
SDMMC.clksrc.card1 = 1;
|
|
||||||
SDMMC.clkdiv.div1 = card_div;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
sdmmc_host_set_clk_div(host_div);
|
sdmmc_host_set_clk_div(host_div);
|
||||||
err = sdmmc_host_clock_update_command(slot);
|
err = sdmmc_host_clock_update_command(slot);
|
||||||
if (err != ESP_OK) {
|
if (err != ESP_OK) {
|
||||||
@ -317,8 +255,8 @@ esp_err_t sdmmc_host_set_card_clk(int slot, uint32_t freq_khz)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Re-enable clocks
|
// Re-enable clocks
|
||||||
SDMMC.clkena.cclk_enable |= BIT(slot);
|
sdmmc_ll_enable_card_clock(s_host_ctx.hal.dev, slot, true);
|
||||||
SDMMC.clkena.cclk_low_power |= BIT(slot);
|
sdmmc_ll_enable_card_clock_low_power(s_host_ctx.hal.dev, slot, true);
|
||||||
err = sdmmc_host_clock_update_command(slot);
|
err = sdmmc_host_clock_update_command(slot);
|
||||||
if (err != ESP_OK) {
|
if (err != ESP_OK) {
|
||||||
ESP_LOGE(TAG, "re-enabling clk failed");
|
ESP_LOGE(TAG, "re-enabling clk failed");
|
||||||
@ -329,13 +267,10 @@ esp_err_t sdmmc_host_set_card_clk(int slot, uint32_t freq_khz)
|
|||||||
// set data timeout
|
// set data timeout
|
||||||
const uint32_t data_timeout_ms = 100;
|
const uint32_t data_timeout_ms = 100;
|
||||||
uint32_t data_timeout_cycles = data_timeout_ms * freq_khz;
|
uint32_t data_timeout_cycles = data_timeout_ms * freq_khz;
|
||||||
const uint32_t data_timeout_cycles_max = 0xffffff;
|
sdmmc_ll_set_data_timeout(s_host_ctx.hal.dev, data_timeout_cycles);
|
||||||
if (data_timeout_cycles > data_timeout_cycles_max) {
|
|
||||||
data_timeout_cycles = data_timeout_cycles_max;
|
|
||||||
}
|
|
||||||
SDMMC.tmout.data = data_timeout_cycles;
|
|
||||||
// always set response timeout to highest value, it's small enough anyway
|
// always set response timeout to highest value, it's small enough anyway
|
||||||
SDMMC.tmout.response = 255;
|
sdmmc_ll_set_response_timeout(s_host_ctx.hal.dev, 255);
|
||||||
|
|
||||||
return ESP_OK;
|
return ESP_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -348,8 +283,8 @@ esp_err_t sdmmc_host_get_real_freq(int slot, int *real_freq_khz)
|
|||||||
return ESP_ERR_INVALID_ARG;
|
return ESP_ERR_INVALID_ARG;
|
||||||
}
|
}
|
||||||
|
|
||||||
int host_div = s_get_host_clk_div();
|
int host_div = sdmmc_ll_get_clock_div(s_host_ctx.hal.dev);
|
||||||
int card_div = slot == 0 ? SDMMC.clkdiv.div0 : SDMMC.clkdiv.div1;
|
int card_div = sdmmc_ll_get_card_clock_div(s_host_ctx.hal.dev, slot);
|
||||||
*real_freq_khz = sdmmc_host_calc_freq(host_div, card_div);
|
*real_freq_khz = sdmmc_host_calc_freq(host_div, card_div);
|
||||||
|
|
||||||
return ESP_OK;
|
return ESP_OK;
|
||||||
@ -371,26 +306,31 @@ esp_err_t sdmmc_host_set_input_delay(int slot, sdmmc_delay_phase_t delay_phase)
|
|||||||
|
|
||||||
//Now we're in high speed. Note ESP SDMMC Host HW only supports integer divider.
|
//Now we're in high speed. Note ESP SDMMC Host HW only supports integer divider.
|
||||||
int delay_phase_num = 0;
|
int delay_phase_num = 0;
|
||||||
|
sdmmc_ll_delay_phase_t phase = SDMMC_LL_DELAY_PHASE_0;
|
||||||
switch (delay_phase) {
|
switch (delay_phase) {
|
||||||
case SDMMC_DELAY_PHASE_1:
|
case SDMMC_DELAY_PHASE_1:
|
||||||
SDMMC.clock.phase_din = 0x1;
|
phase = SDMMC_LL_DELAY_PHASE_1;
|
||||||
delay_phase_num = 1;
|
delay_phase_num = 1;
|
||||||
break;
|
break;
|
||||||
case SDMMC_DELAY_PHASE_2:
|
case SDMMC_DELAY_PHASE_2:
|
||||||
SDMMC.clock.phase_din = 0x4;
|
phase = SDMMC_LL_DELAY_PHASE_2;
|
||||||
delay_phase_num = 2;
|
delay_phase_num = 2;
|
||||||
break;
|
break;
|
||||||
case SDMMC_DELAY_PHASE_3:
|
case SDMMC_DELAY_PHASE_3:
|
||||||
SDMMC.clock.phase_din = 0x6;
|
phase = SDMMC_LL_DELAY_PHASE_3;
|
||||||
delay_phase_num = 3;
|
delay_phase_num = 3;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
SDMMC.clock.phase_din = 0x0;
|
phase = SDMMC_LL_DELAY_PHASE_0;
|
||||||
|
delay_phase_num = 0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
SDMMC_RCC_ATOMIC() {
|
||||||
|
sdmmc_ll_set_din_delay(s_host_ctx.hal.dev, phase);
|
||||||
|
}
|
||||||
|
|
||||||
int src_clk_period_ps = (1 * 1000 * 1000) / (clk_src_freq_hz / (1 * 1000 * 1000));
|
int src_clk_period_ps = (1 * 1000 * 1000) / (clk_src_freq_hz / (1 * 1000 * 1000));
|
||||||
int phase_diff_ps = src_clk_period_ps * (SDMMC.clock.div_factor_n + 1) / SOC_SDMMC_DELAY_PHASE_NUM;
|
int phase_diff_ps = src_clk_period_ps * sdmmc_ll_get_clock_div(s_host_ctx.hal.dev) / SOC_SDMMC_DELAY_PHASE_NUM;
|
||||||
ESP_LOGD(TAG, "difference between input delay phases is %d ps", phase_diff_ps);
|
ESP_LOGD(TAG, "difference between input delay phases is %d ps", phase_diff_ps);
|
||||||
ESP_LOGI(TAG, "host sampling edge is delayed by %d ps", phase_diff_ps * delay_phase_num);
|
ESP_LOGI(TAG, "host sampling edge is delayed by %d ps", phase_diff_ps * delay_phase_num);
|
||||||
#endif
|
#endif
|
||||||
@ -403,10 +343,10 @@ esp_err_t sdmmc_host_start_command(int slot, sdmmc_hw_cmd_t cmd, uint32_t arg)
|
|||||||
if (!(slot == 0 || slot == 1)) {
|
if (!(slot == 0 || slot == 1)) {
|
||||||
return ESP_ERR_INVALID_ARG;
|
return ESP_ERR_INVALID_ARG;
|
||||||
}
|
}
|
||||||
if ((SDMMC.cdetect.cards & BIT(slot)) != 0) {
|
if (!sdmmc_ll_is_card_detected(s_host_ctx.hal.dev, slot)) {
|
||||||
return ESP_ERR_NOT_FOUND;
|
return ESP_ERR_NOT_FOUND;
|
||||||
}
|
}
|
||||||
if (cmd.data_expected && cmd.rw && (SDMMC.wrtprt.cards & BIT(slot)) != 0) {
|
if (cmd.data_expected && cmd.rw && sdmmc_ll_is_card_write_protected(s_host_ctx.hal.dev, slot)) {
|
||||||
return ESP_ERR_INVALID_STATE;
|
return ESP_ERR_INVALID_STATE;
|
||||||
}
|
}
|
||||||
/* Outputs should be synchronized to cclk_out */
|
/* Outputs should be synchronized to cclk_out */
|
||||||
@ -434,12 +374,23 @@ esp_err_t sdmmc_host_start_command(int slot, sdmmc_hw_cmd_t cmd, uint32_t arg)
|
|||||||
|
|
||||||
esp_err_t sdmmc_host_init(void)
|
esp_err_t sdmmc_host_init(void)
|
||||||
{
|
{
|
||||||
if (s_intr_handle) {
|
if (s_host_ctx.intr_handle) {
|
||||||
return ESP_ERR_INVALID_STATE;
|
return ESP_ERR_INVALID_STATE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//enable bus clock for registers
|
||||||
|
#if SDMMC_CLK_NEEDS_RCC
|
||||||
|
SDMMC_RCC_ATOMIC() {
|
||||||
|
sdmmc_ll_enable_bus_clock(s_host_ctx.hal.dev, true);
|
||||||
|
sdmmc_ll_reset_register(s_host_ctx.hal.dev);
|
||||||
|
}
|
||||||
|
#else
|
||||||
periph_module_reset(PERIPH_SDMMC_MODULE);
|
periph_module_reset(PERIPH_SDMMC_MODULE);
|
||||||
periph_module_enable(PERIPH_SDMMC_MODULE);
|
periph_module_enable(PERIPH_SDMMC_MODULE);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//hal context init
|
||||||
|
sdmmc_hal_init(&s_host_ctx.hal);
|
||||||
|
|
||||||
// Enable clock to peripheral. Use smallest divider first.
|
// Enable clock to peripheral. Use smallest divider first.
|
||||||
sdmmc_host_set_clk_div(2);
|
sdmmc_host_set_clk_div(2);
|
||||||
@ -451,7 +402,7 @@ esp_err_t sdmmc_host_init(void)
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
ESP_LOGD(TAG, "peripheral version %"PRIx32", hardware config %08"PRIx32, SDMMC.verid, SDMMC.hcon);
|
ESP_LOGD(TAG, "peripheral version %"PRIx32", hardware config %08"PRIx32, SDMMC.verid, SDMMC.hcon.val);
|
||||||
|
|
||||||
// Clear interrupt status and set interrupt mask to known state
|
// Clear interrupt status and set interrupt mask to known state
|
||||||
SDMMC.rintsts.val = 0xffffffff;
|
SDMMC.rintsts.val = 0xffffffff;
|
||||||
@ -459,23 +410,23 @@ esp_err_t sdmmc_host_init(void)
|
|||||||
SDMMC.ctrl.int_enable = 0;
|
SDMMC.ctrl.int_enable = 0;
|
||||||
|
|
||||||
// Allocate event queue
|
// Allocate event queue
|
||||||
s_event_queue = xQueueCreate(SDMMC_EVENT_QUEUE_LENGTH, sizeof(sdmmc_event_t));
|
s_host_ctx.event_queue = xQueueCreate(SDMMC_EVENT_QUEUE_LENGTH, sizeof(sdmmc_event_t));
|
||||||
if (!s_event_queue) {
|
if (!s_host_ctx.event_queue) {
|
||||||
return ESP_ERR_NO_MEM;
|
return ESP_ERR_NO_MEM;
|
||||||
}
|
}
|
||||||
s_io_intr_event = xSemaphoreCreateBinary();
|
s_host_ctx.io_intr_event = xSemaphoreCreateBinary();
|
||||||
if (!s_io_intr_event) {
|
if (!s_host_ctx.io_intr_event) {
|
||||||
vQueueDelete(s_event_queue);
|
vQueueDelete(s_host_ctx.event_queue);
|
||||||
s_event_queue = NULL;
|
s_host_ctx.event_queue = NULL;
|
||||||
return ESP_ERR_NO_MEM;
|
return ESP_ERR_NO_MEM;
|
||||||
}
|
}
|
||||||
// Attach interrupt handler
|
// Attach interrupt handler
|
||||||
esp_err_t ret = esp_intr_alloc(ETS_SDIO_HOST_INTR_SOURCE, 0, &sdmmc_isr, s_event_queue, &s_intr_handle);
|
esp_err_t ret = esp_intr_alloc(ETS_SDIO_HOST_INTR_SOURCE, 0, &sdmmc_isr, s_host_ctx.event_queue, &s_host_ctx.intr_handle);
|
||||||
if (ret != ESP_OK) {
|
if (ret != ESP_OK) {
|
||||||
vQueueDelete(s_event_queue);
|
vQueueDelete(s_host_ctx.event_queue);
|
||||||
s_event_queue = NULL;
|
s_host_ctx.event_queue = NULL;
|
||||||
vSemaphoreDelete(s_io_intr_event);
|
vSemaphoreDelete(s_host_ctx.io_intr_event);
|
||||||
s_io_intr_event = NULL;
|
s_host_ctx.io_intr_event = NULL;
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
// Enable interrupts
|
// Enable interrupts
|
||||||
@ -498,23 +449,21 @@ esp_err_t sdmmc_host_init(void)
|
|||||||
// Initialize transaction handler
|
// Initialize transaction handler
|
||||||
ret = sdmmc_host_transaction_handler_init();
|
ret = sdmmc_host_transaction_handler_init();
|
||||||
if (ret != ESP_OK) {
|
if (ret != ESP_OK) {
|
||||||
vQueueDelete(s_event_queue);
|
vQueueDelete(s_host_ctx.event_queue);
|
||||||
s_event_queue = NULL;
|
s_host_ctx.event_queue = NULL;
|
||||||
vSemaphoreDelete(s_io_intr_event);
|
vSemaphoreDelete(s_host_ctx.io_intr_event);
|
||||||
s_io_intr_event = NULL;
|
s_host_ctx.io_intr_event = NULL;
|
||||||
esp_intr_free(s_intr_handle);
|
esp_intr_free(s_host_ctx.intr_handle);
|
||||||
s_intr_handle = NULL;
|
s_host_ctx.intr_handle = NULL;
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
return ESP_OK;
|
return ESP_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef SOC_SDMMC_USE_IOMUX
|
|
||||||
|
|
||||||
static void configure_pin_iomux(uint8_t gpio_num)
|
static void configure_pin_iomux(uint8_t gpio_num)
|
||||||
{
|
{
|
||||||
const int sdmmc_func = 3;
|
const int sdmmc_func = SDMMC_LL_IOMUX_FUNC;
|
||||||
const int drive_strength = 3;
|
const int drive_strength = 3;
|
||||||
assert(gpio_num != (uint8_t) GPIO_NUM_NC);
|
assert(gpio_num != (uint8_t) GPIO_NUM_NC);
|
||||||
gpio_pulldown_dis(gpio_num);
|
gpio_pulldown_dis(gpio_num);
|
||||||
@ -526,8 +475,6 @@ static void configure_pin_iomux(uint8_t gpio_num)
|
|||||||
PIN_SET_DRV(reg, drive_strength);
|
PIN_SET_DRV(reg, drive_strength);
|
||||||
}
|
}
|
||||||
|
|
||||||
#elif SOC_SDMMC_USE_GPIO_MATRIX
|
|
||||||
|
|
||||||
static void configure_pin_gpio_matrix(uint8_t gpio_num, uint8_t gpio_matrix_sig, gpio_mode_t mode, const char *name)
|
static void configure_pin_gpio_matrix(uint8_t gpio_num, uint8_t gpio_matrix_sig, gpio_mode_t mode, const char *name)
|
||||||
{
|
{
|
||||||
assert (gpio_num != (uint8_t) GPIO_NUM_NC);
|
assert (gpio_num != (uint8_t) GPIO_NUM_NC);
|
||||||
@ -543,11 +490,30 @@ static void configure_pin_gpio_matrix(uint8_t gpio_num, uint8_t gpio_matrix_sig,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // SOC_SDMMC_USE_{IOMUX,GPIO_MATRIX}
|
static void configure_pin(uint8_t gpio_num, uint8_t gpio_matrix_sig, gpio_mode_t mode, const char *name, bool use_gpio_matrix)
|
||||||
|
{
|
||||||
|
if (use_gpio_matrix) {
|
||||||
|
configure_pin_gpio_matrix(gpio_num, gpio_matrix_sig, mode, name);
|
||||||
|
} else {
|
||||||
|
configure_pin_iomux(gpio_num);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//True: pins are all not set; False: one or more pins are set
|
||||||
|
static bool s_check_pin_not_set(const sdmmc_slot_config_t *slot_config)
|
||||||
|
{
|
||||||
|
#if SOC_SDMMC_USE_GPIO_MATRIX
|
||||||
|
bool pin_not_set = !slot_config->clk && !slot_config->cmd && !slot_config->d0 && !slot_config->d1 && !slot_config->d2 &&
|
||||||
|
!slot_config->d3 && !slot_config->d4 && !slot_config->d5 && !slot_config->d6 && !slot_config->d7;
|
||||||
|
return pin_not_set;
|
||||||
|
#else
|
||||||
|
return true;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
esp_err_t sdmmc_host_init_slot(int slot, const sdmmc_slot_config_t *slot_config)
|
esp_err_t sdmmc_host_init_slot(int slot, const sdmmc_slot_config_t *slot_config)
|
||||||
{
|
{
|
||||||
if (!s_intr_handle) {
|
if (!s_host_ctx.intr_handle) {
|
||||||
return ESP_ERR_INVALID_STATE;
|
return ESP_ERR_INVALID_STATE;
|
||||||
}
|
}
|
||||||
if (!(slot == 0 || slot == 1)) {
|
if (!(slot == 0 || slot == 1)) {
|
||||||
@ -569,57 +535,87 @@ esp_err_t sdmmc_host_init_slot(int slot, const sdmmc_slot_config_t *slot_config)
|
|||||||
} else if (slot_width > slot_info->width) {
|
} else if (slot_width > slot_info->width) {
|
||||||
return ESP_ERR_INVALID_ARG;
|
return ESP_ERR_INVALID_ARG;
|
||||||
}
|
}
|
||||||
s_slot_width[slot] = slot_width;
|
s_host_ctx.slot_ctx[slot].slot_width = slot_width;
|
||||||
|
|
||||||
|
bool pin_not_set = s_check_pin_not_set(slot_config);
|
||||||
|
//SD driver behaviour is: all pins not defined == using iomux
|
||||||
|
bool use_gpio_matrix = !pin_not_set;
|
||||||
|
|
||||||
|
if (slot == 0) {
|
||||||
|
#if !SDMMC_LL_SLOT_SUPPORT_GPIO_MATRIX(0)
|
||||||
|
ESP_RETURN_ON_FALSE(!use_gpio_matrix, ESP_ERR_INVALID_ARG, TAG, "doesn't support routing from GPIO matrix, driver uses dedicated IOs");
|
||||||
|
#endif
|
||||||
|
} else {
|
||||||
|
#if !SDMMC_LL_SLOT_SUPPORT_GPIO_MATRIX(1)
|
||||||
|
ESP_RETURN_ON_FALSE(!use_gpio_matrix, ESP_ERR_INVALID_ARG, TAG, "doesn't support routing from GPIO matrix, driver uses dedicated IOs");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
s_host_ctx.slot_ctx[slot].use_gpio_matrix = use_gpio_matrix;
|
||||||
|
|
||||||
#if SOC_SDMMC_USE_GPIO_MATRIX
|
#if SOC_SDMMC_USE_GPIO_MATRIX
|
||||||
|
if (use_gpio_matrix) {
|
||||||
/* Save pin configuration for this slot */
|
/* Save pin configuration for this slot */
|
||||||
s_sdmmc_slot_gpio_num[slot].clk = slot_config->clk;
|
s_host_ctx.slot_ctx[slot].slot_gpio_num.clk = slot_config->clk;
|
||||||
s_sdmmc_slot_gpio_num[slot].cmd = slot_config->cmd;
|
s_host_ctx.slot_ctx[slot].slot_gpio_num.cmd = slot_config->cmd;
|
||||||
s_sdmmc_slot_gpio_num[slot].d0 = slot_config->d0;
|
s_host_ctx.slot_ctx[slot].slot_gpio_num.d0 = slot_config->d0;
|
||||||
/* Save d1 even in 1-line mode, it might be needed for SDIO INT line */
|
/* Save d1 even in 1-line mode, it might be needed for SDIO INT line */
|
||||||
s_sdmmc_slot_gpio_num[slot].d1 = slot_config->d1;
|
s_host_ctx.slot_ctx[slot].slot_gpio_num.d1 = slot_config->d1;
|
||||||
if (slot_width >= 4) {
|
if (slot_width >= 4) {
|
||||||
s_sdmmc_slot_gpio_num[slot].d2 = slot_config->d2;
|
s_host_ctx.slot_ctx[slot].slot_gpio_num.d2 = slot_config->d2;
|
||||||
}
|
}
|
||||||
/* Save d3 even for 1-line mode, as it needs to be set high */
|
/* Save d3 even for 1-line mode, as it needs to be set high */
|
||||||
s_sdmmc_slot_gpio_num[slot].d3 = slot_config->d3;
|
s_host_ctx.slot_ctx[slot].slot_gpio_num.d3 = slot_config->d3;
|
||||||
if (slot_width >= 8) {
|
if (slot_width >= 8) {
|
||||||
s_sdmmc_slot_gpio_num[slot].d4 = slot_config->d4;
|
s_host_ctx.slot_ctx[slot].slot_gpio_num.d4 = slot_config->d4;
|
||||||
s_sdmmc_slot_gpio_num[slot].d5 = slot_config->d5;
|
s_host_ctx.slot_ctx[slot].slot_gpio_num.d5 = slot_config->d5;
|
||||||
s_sdmmc_slot_gpio_num[slot].d6 = slot_config->d6;
|
s_host_ctx.slot_ctx[slot].slot_gpio_num.d6 = slot_config->d6;
|
||||||
s_sdmmc_slot_gpio_num[slot].d7 = slot_config->d7;
|
s_host_ctx.slot_ctx[slot].slot_gpio_num.d7 = slot_config->d7;
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
#endif //#if SOC_SDMMC_USE_GPIO_MATRIX
|
||||||
|
{
|
||||||
|
/* init pin configuration for this slot */
|
||||||
|
s_host_ctx.slot_ctx[slot].slot_gpio_num.clk = sdmmc_slot_gpio_num[slot].clk;
|
||||||
|
s_host_ctx.slot_ctx[slot].slot_gpio_num.cmd = sdmmc_slot_gpio_num[slot].cmd;
|
||||||
|
s_host_ctx.slot_ctx[slot].slot_gpio_num.d0 = sdmmc_slot_gpio_num[slot].d0;
|
||||||
|
s_host_ctx.slot_ctx[slot].slot_gpio_num.d1 = sdmmc_slot_gpio_num[slot].d1;
|
||||||
|
s_host_ctx.slot_ctx[slot].slot_gpio_num.d2 = sdmmc_slot_gpio_num[slot].d2;
|
||||||
|
s_host_ctx.slot_ctx[slot].slot_gpio_num.d3 = sdmmc_slot_gpio_num[slot].d3;
|
||||||
|
s_host_ctx.slot_ctx[slot].slot_gpio_num.d4 = sdmmc_slot_gpio_num[slot].d4;
|
||||||
|
s_host_ctx.slot_ctx[slot].slot_gpio_num.d5 = sdmmc_slot_gpio_num[slot].d5;
|
||||||
|
s_host_ctx.slot_ctx[slot].slot_gpio_num.d6 = sdmmc_slot_gpio_num[slot].d6;
|
||||||
|
s_host_ctx.slot_ctx[slot].slot_gpio_num.d7 = sdmmc_slot_gpio_num[slot].d7;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
bool pullup = slot_config->flags & SDMMC_SLOT_FLAG_INTERNAL_PULLUP;
|
bool pullup = slot_config->flags & SDMMC_SLOT_FLAG_INTERNAL_PULLUP;
|
||||||
if (pullup) {
|
if (pullup) {
|
||||||
sdmmc_host_pullup_en_internal(slot, slot_config->width);
|
sdmmc_host_pullup_en_internal(slot, slot_config->width);
|
||||||
}
|
}
|
||||||
|
|
||||||
configure_pin(clk, slot, GPIO_MODE_OUTPUT);
|
configure_pin(s_host_ctx.slot_ctx[slot].slot_gpio_num.clk, sdmmc_slot_gpio_sig[slot].clk, GPIO_MODE_OUTPUT, "clk", use_gpio_matrix);
|
||||||
configure_pin(cmd, slot, GPIO_MODE_INPUT_OUTPUT);
|
configure_pin(s_host_ctx.slot_ctx[slot].slot_gpio_num.cmd, sdmmc_slot_gpio_sig[slot].cmd, GPIO_MODE_INPUT_OUTPUT, "cmd", use_gpio_matrix);
|
||||||
configure_pin(d0, slot, GPIO_MODE_INPUT_OUTPUT);
|
configure_pin(s_host_ctx.slot_ctx[slot].slot_gpio_num.d0, sdmmc_slot_gpio_sig[slot].d0, GPIO_MODE_INPUT_OUTPUT, "d0", use_gpio_matrix);
|
||||||
|
|
||||||
if (slot_width >= 4) {
|
if (slot_width >= 4) {
|
||||||
configure_pin(d1, slot, GPIO_MODE_INPUT_OUTPUT);
|
configure_pin(s_host_ctx.slot_ctx[slot].slot_gpio_num.d1, sdmmc_slot_gpio_sig[slot].d1, GPIO_MODE_INPUT_OUTPUT, "d1", use_gpio_matrix);
|
||||||
configure_pin(d2, slot, GPIO_MODE_INPUT_OUTPUT);
|
configure_pin(s_host_ctx.slot_ctx[slot].slot_gpio_num.d2, sdmmc_slot_gpio_sig[slot].d2, GPIO_MODE_INPUT_OUTPUT, "d2", use_gpio_matrix);
|
||||||
// Force D3 high to make slave enter SD mode.
|
// Force D3 high to make slave enter SD mode.
|
||||||
// Connect to peripheral after width configuration.
|
// Connect to peripheral after width configuration.
|
||||||
gpio_config_t gpio_conf = {
|
gpio_config_t gpio_conf = {
|
||||||
.pin_bit_mask = BIT64(GPIO_NUM(slot, d3)),
|
.pin_bit_mask = BIT64(s_host_ctx.slot_ctx[slot].slot_gpio_num.d3),
|
||||||
.mode = GPIO_MODE_OUTPUT,
|
.mode = GPIO_MODE_OUTPUT,
|
||||||
.pull_up_en = 0,
|
.pull_up_en = 0,
|
||||||
.pull_down_en = 0,
|
.pull_down_en = 0,
|
||||||
.intr_type = GPIO_INTR_DISABLE,
|
.intr_type = GPIO_INTR_DISABLE,
|
||||||
};
|
};
|
||||||
gpio_config(&gpio_conf);
|
gpio_config(&gpio_conf);
|
||||||
gpio_set_level(GPIO_NUM(slot, d3), 1);
|
gpio_set_level(s_host_ctx.slot_ctx[slot].slot_gpio_num.d3, 1);
|
||||||
}
|
}
|
||||||
if (slot_width == 8) {
|
if (slot_width == 8) {
|
||||||
configure_pin(d4, slot, GPIO_MODE_INPUT_OUTPUT);
|
configure_pin(s_host_ctx.slot_ctx[slot].slot_gpio_num.d4, sdmmc_slot_gpio_sig[slot].d4, GPIO_MODE_INPUT_OUTPUT, "d4", use_gpio_matrix);
|
||||||
configure_pin(d5, slot, GPIO_MODE_INPUT_OUTPUT);
|
configure_pin(s_host_ctx.slot_ctx[slot].slot_gpio_num.d5, sdmmc_slot_gpio_sig[slot].d5, GPIO_MODE_INPUT_OUTPUT, "d5", use_gpio_matrix);
|
||||||
configure_pin(d6, slot, GPIO_MODE_INPUT_OUTPUT);
|
configure_pin(s_host_ctx.slot_ctx[slot].slot_gpio_num.d6, sdmmc_slot_gpio_sig[slot].d6, GPIO_MODE_INPUT_OUTPUT, "d6", use_gpio_matrix);
|
||||||
configure_pin(d7, slot, GPIO_MODE_INPUT_OUTPUT);
|
configure_pin(s_host_ctx.slot_ctx[slot].slot_gpio_num.d7, sdmmc_slot_gpio_sig[slot].d7, GPIO_MODE_INPUT_OUTPUT, "d7", use_gpio_matrix);
|
||||||
}
|
}
|
||||||
|
|
||||||
// SDIO slave interrupt is edge sensitive to ~(int_n | card_int | card_detect)
|
// SDIO slave interrupt is edge sensitive to ~(int_n | card_int | card_detect)
|
||||||
@ -671,18 +667,26 @@ esp_err_t sdmmc_host_init_slot(int slot, const sdmmc_slot_config_t *slot_config)
|
|||||||
|
|
||||||
esp_err_t sdmmc_host_deinit(void)
|
esp_err_t sdmmc_host_deinit(void)
|
||||||
{
|
{
|
||||||
if (!s_intr_handle) {
|
if (!s_host_ctx.intr_handle) {
|
||||||
return ESP_ERR_INVALID_STATE;
|
return ESP_ERR_INVALID_STATE;
|
||||||
}
|
}
|
||||||
esp_intr_free(s_intr_handle);
|
esp_intr_free(s_host_ctx.intr_handle);
|
||||||
s_intr_handle = NULL;
|
s_host_ctx.intr_handle = NULL;
|
||||||
vQueueDelete(s_event_queue);
|
vQueueDelete(s_host_ctx.event_queue);
|
||||||
s_event_queue = NULL;
|
s_host_ctx.event_queue = NULL;
|
||||||
vQueueDelete(s_io_intr_event);
|
vQueueDelete(s_host_ctx.io_intr_event);
|
||||||
s_io_intr_event = NULL;
|
s_host_ctx.io_intr_event = NULL;
|
||||||
sdmmc_host_input_clk_disable();
|
sdmmc_ll_deinit_clk(s_host_ctx.hal.dev);
|
||||||
sdmmc_host_transaction_handler_deinit();
|
sdmmc_host_transaction_handler_deinit();
|
||||||
|
#if SDMMC_CLK_NEEDS_RCC
|
||||||
|
//disable bus clock for registers
|
||||||
|
SDMMC_RCC_ATOMIC() {
|
||||||
|
sdmmc_ll_enable_bus_clock(s_host_ctx.hal.dev, false);
|
||||||
|
}
|
||||||
|
#else
|
||||||
periph_module_disable(PERIPH_SDMMC_MODULE);
|
periph_module_disable(PERIPH_SDMMC_MODULE);
|
||||||
|
#endif
|
||||||
|
|
||||||
return ESP_OK;
|
return ESP_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -691,10 +695,10 @@ esp_err_t sdmmc_host_wait_for_event(int tick_count, sdmmc_event_t *out_event)
|
|||||||
if (!out_event) {
|
if (!out_event) {
|
||||||
return ESP_ERR_INVALID_ARG;
|
return ESP_ERR_INVALID_ARG;
|
||||||
}
|
}
|
||||||
if (!s_event_queue) {
|
if (!s_host_ctx.event_queue) {
|
||||||
return ESP_ERR_INVALID_STATE;
|
return ESP_ERR_INVALID_STATE;
|
||||||
}
|
}
|
||||||
int ret = xQueueReceive(s_event_queue, out_event, tick_count);
|
int ret = xQueueReceive(s_host_ctx.event_queue, out_event, tick_count);
|
||||||
if (ret == pdFALSE) {
|
if (ret == pdFALSE) {
|
||||||
return ESP_ERR_TIMEOUT;
|
return ESP_ERR_TIMEOUT;
|
||||||
}
|
}
|
||||||
@ -717,11 +721,11 @@ esp_err_t sdmmc_host_set_bus_width(int slot, size_t width)
|
|||||||
SDMMC.ctype.card_width_8 &= ~mask;
|
SDMMC.ctype.card_width_8 &= ~mask;
|
||||||
SDMMC.ctype.card_width |= mask;
|
SDMMC.ctype.card_width |= mask;
|
||||||
// D3 was set to GPIO high to force slave into SD mode, until 4-bit mode is set
|
// D3 was set to GPIO high to force slave into SD mode, until 4-bit mode is set
|
||||||
configure_pin(d3, slot, GPIO_MODE_INPUT_OUTPUT);
|
configure_pin(s_host_ctx.slot_ctx[slot].slot_gpio_num.d3, sdmmc_slot_gpio_sig[slot].d3, GPIO_MODE_INPUT_OUTPUT, "d3", s_host_ctx.slot_ctx[slot].use_gpio_matrix);
|
||||||
} else if (width == 8) {
|
} else if (width == 8) {
|
||||||
SDMMC.ctype.card_width_8 |= mask;
|
SDMMC.ctype.card_width_8 |= mask;
|
||||||
// D3 was set to GPIO high to force slave into SD mode, until 4-bit mode is set
|
// D3 was set to GPIO high to force slave into SD mode, until 4-bit mode is set
|
||||||
configure_pin(d3, slot, GPIO_MODE_INPUT_OUTPUT);
|
configure_pin(s_host_ctx.slot_ctx[slot].slot_gpio_num.d3, sdmmc_slot_gpio_sig[slot].d3, GPIO_MODE_INPUT_OUTPUT, "d3", s_host_ctx.slot_ctx[slot].use_gpio_matrix);
|
||||||
} else {
|
} else {
|
||||||
return ESP_ERR_INVALID_ARG;
|
return ESP_ERR_INVALID_ARG;
|
||||||
}
|
}
|
||||||
@ -732,7 +736,7 @@ esp_err_t sdmmc_host_set_bus_width(int slot, size_t width)
|
|||||||
size_t sdmmc_host_get_slot_width(int slot)
|
size_t sdmmc_host_get_slot_width(int slot)
|
||||||
{
|
{
|
||||||
assert( slot == 0 || slot == 1 );
|
assert( slot == 0 || slot == 1 );
|
||||||
return s_slot_width[slot];
|
return s_host_ctx.slot_ctx[slot].slot_width;
|
||||||
}
|
}
|
||||||
|
|
||||||
esp_err_t sdmmc_host_set_bus_ddr_mode(int slot, bool ddr_enabled)
|
esp_err_t sdmmc_host_set_bus_ddr_mode(int slot, bool ddr_enabled)
|
||||||
@ -740,19 +744,13 @@ esp_err_t sdmmc_host_set_bus_ddr_mode(int slot, bool ddr_enabled)
|
|||||||
if (!(slot == 0 || slot == 1)) {
|
if (!(slot == 0 || slot == 1)) {
|
||||||
return ESP_ERR_INVALID_ARG;
|
return ESP_ERR_INVALID_ARG;
|
||||||
}
|
}
|
||||||
if (s_slot_width[slot] == 8 && ddr_enabled) {
|
if (s_host_ctx.slot_ctx[slot].slot_width == 8 && ddr_enabled) {
|
||||||
ESP_LOGW(TAG, "DDR mode with 8-bit bus width is not supported yet");
|
ESP_LOGW(TAG, "DDR mode with 8-bit bus width is not supported yet");
|
||||||
// requires reconfiguring controller clock for 2x card frequency
|
// requires reconfiguring controller clock for 2x card frequency
|
||||||
return ESP_ERR_NOT_SUPPORTED;
|
return ESP_ERR_NOT_SUPPORTED;
|
||||||
}
|
}
|
||||||
uint32_t mask = BIT(slot);
|
|
||||||
if (ddr_enabled) {
|
sdmmc_ll_enable_ddr_mode(s_host_ctx.hal.dev, slot, ddr_enabled);
|
||||||
SDMMC.uhs.ddr |= mask;
|
|
||||||
SDMMC.emmc_ddr_reg |= mask;
|
|
||||||
} else {
|
|
||||||
SDMMC.uhs.ddr &= ~mask;
|
|
||||||
SDMMC.emmc_ddr_reg &= ~mask;
|
|
||||||
}
|
|
||||||
ESP_LOGD(TAG, "slot=%d ddr=%d", slot, ddr_enabled ? 1 : 0);
|
ESP_LOGD(TAG, "slot=%d ddr=%d", slot, ddr_enabled ? 1 : 0);
|
||||||
return ESP_OK;
|
return ESP_OK;
|
||||||
}
|
}
|
||||||
@ -763,9 +761,9 @@ esp_err_t sdmmc_host_set_cclk_always_on(int slot, bool cclk_always_on)
|
|||||||
return ESP_ERR_INVALID_ARG;
|
return ESP_ERR_INVALID_ARG;
|
||||||
}
|
}
|
||||||
if (cclk_always_on) {
|
if (cclk_always_on) {
|
||||||
SDMMC.clkena.cclk_low_power &= ~BIT(slot);
|
sdmmc_ll_enable_card_clock_low_power(s_host_ctx.hal.dev, slot, false);
|
||||||
} else {
|
} else {
|
||||||
SDMMC.clkena.cclk_low_power |= BIT(slot);
|
sdmmc_ll_enable_card_clock_low_power(s_host_ctx.hal.dev, slot, true);
|
||||||
}
|
}
|
||||||
sdmmc_host_clock_update_command(slot);
|
sdmmc_host_clock_update_command(slot);
|
||||||
return ESP_OK;
|
return ESP_OK;
|
||||||
@ -792,21 +790,18 @@ void sdmmc_host_dma_stop(void)
|
|||||||
void sdmmc_host_dma_prepare(sdmmc_desc_t *desc, size_t block_size, size_t data_size)
|
void sdmmc_host_dma_prepare(sdmmc_desc_t *desc, size_t block_size, size_t data_size)
|
||||||
{
|
{
|
||||||
// Set size of data and DMA descriptor pointer
|
// Set size of data and DMA descriptor pointer
|
||||||
SDMMC.bytcnt = data_size;
|
sdmmc_ll_set_data_transfer_len(s_host_ctx.hal.dev, data_size);
|
||||||
SDMMC.blksiz = block_size;
|
sdmmc_ll_set_block_size(s_host_ctx.hal.dev, block_size);
|
||||||
SDMMC.dbaddr = desc;
|
sdmmc_ll_set_desc_addr(s_host_ctx.hal.dev, (uint32_t)desc);
|
||||||
|
|
||||||
// Enable everything needed to use DMA
|
// Enable everything needed to use DMA
|
||||||
SDMMC.ctrl.dma_enable = 1;
|
sdmmc_ll_enable_dma(s_host_ctx.hal.dev, true);
|
||||||
SDMMC.ctrl.use_internal_dma = 1;
|
|
||||||
SDMMC.bmod.enable = 1;
|
|
||||||
SDMMC.bmod.fb = 1;
|
|
||||||
sdmmc_host_dma_resume();
|
sdmmc_host_dma_resume();
|
||||||
}
|
}
|
||||||
|
|
||||||
void sdmmc_host_dma_resume(void)
|
void sdmmc_host_dma_resume(void)
|
||||||
{
|
{
|
||||||
SDMMC.pldmnd = 1;
|
sdmmc_ll_poll_demand(s_host_ctx.hal.dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool sdmmc_host_card_busy(void)
|
bool sdmmc_host_card_busy(void)
|
||||||
@ -816,7 +811,7 @@ bool sdmmc_host_card_busy(void)
|
|||||||
|
|
||||||
esp_err_t sdmmc_host_io_int_enable(int slot)
|
esp_err_t sdmmc_host_io_int_enable(int slot)
|
||||||
{
|
{
|
||||||
configure_pin(d1, slot, GPIO_MODE_INPUT_OUTPUT);
|
configure_pin(s_host_ctx.slot_ctx[slot].slot_gpio_num.d1, sdmmc_slot_gpio_sig[slot].d1, GPIO_MODE_INPUT_OUTPUT, "d1", s_host_ctx.slot_ctx[slot].use_gpio_matrix);
|
||||||
return ESP_OK;
|
return ESP_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -829,19 +824,32 @@ esp_err_t sdmmc_host_io_int_wait(int slot, TickType_t timeout_ticks)
|
|||||||
* (in SDIO sense) has occurred and we don't need to use SDMMC peripheral
|
* (in SDIO sense) has occurred and we don't need to use SDMMC peripheral
|
||||||
* interrupt.
|
* interrupt.
|
||||||
*/
|
*/
|
||||||
|
assert(slot == 0 || slot == 1);
|
||||||
|
|
||||||
SDMMC.intmask.sdio &= ~BIT(slot); /* Disable SDIO interrupt */
|
/* Disable SDIO interrupt */
|
||||||
SDMMC.rintsts.sdio = BIT(slot);
|
if (slot == 0) {
|
||||||
if (gpio_get_level(GPIO_NUM(slot, d1)) == 0) {
|
sdmmc_ll_enable_interrupt(s_host_ctx.hal.dev, SDMMC_INTMASK_IO_SLOT0, false);
|
||||||
|
sdmmc_ll_clear_interrupt(s_host_ctx.hal.dev, SDMMC_INTMASK_IO_SLOT0);
|
||||||
|
} else {
|
||||||
|
sdmmc_ll_enable_interrupt(s_host_ctx.hal.dev, SDMMC_INTMASK_IO_SLOT1, false);
|
||||||
|
sdmmc_ll_clear_interrupt(s_host_ctx.hal.dev, SDMMC_INTMASK_IO_SLOT1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gpio_get_level(s_host_ctx.slot_ctx[slot].slot_gpio_num.d1) == 0) {
|
||||||
return ESP_OK;
|
return ESP_OK;
|
||||||
}
|
}
|
||||||
/* Otherwise, need to wait for an interrupt. Since D1 was high,
|
/* Otherwise, need to wait for an interrupt. Since D1 was high,
|
||||||
* SDMMC peripheral interrupt is guaranteed to trigger on negedge.
|
* SDMMC peripheral interrupt is guaranteed to trigger on negedge.
|
||||||
*/
|
*/
|
||||||
xSemaphoreTake(s_io_intr_event, 0);
|
xSemaphoreTake(s_host_ctx.io_intr_event, 0);
|
||||||
SDMMC.intmask.sdio |= BIT(slot); /* Re-enable SDIO interrupt */
|
/* Re-enable SDIO interrupt */
|
||||||
|
if (slot == 0) {
|
||||||
|
sdmmc_ll_enable_interrupt(s_host_ctx.hal.dev, SDMMC_INTMASK_IO_SLOT0, true);
|
||||||
|
} else {
|
||||||
|
sdmmc_ll_enable_interrupt(s_host_ctx.hal.dev, SDMMC_INTMASK_IO_SLOT1, true);
|
||||||
|
}
|
||||||
|
|
||||||
if (xSemaphoreTake(s_io_intr_event, timeout_ticks) == pdTRUE) {
|
if (xSemaphoreTake(s_host_ctx.io_intr_event, timeout_ticks) == pdTRUE) {
|
||||||
return ESP_OK;
|
return ESP_OK;
|
||||||
} else {
|
} else {
|
||||||
return ESP_ERR_TIMEOUT;
|
return ESP_ERR_TIMEOUT;
|
||||||
@ -870,7 +878,7 @@ static void sdmmc_isr(void *arg)
|
|||||||
sdmmc_event_t event;
|
sdmmc_event_t event;
|
||||||
int higher_priority_task_awoken = pdFALSE;
|
int higher_priority_task_awoken = pdFALSE;
|
||||||
|
|
||||||
uint32_t pending = SDMMC.mintsts.val & 0xFFFF;
|
uint32_t pending = sdmmc_ll_get_intr_status(s_host_ctx.hal.dev) & 0xFFFF;
|
||||||
SDMMC.rintsts.val = pending;
|
SDMMC.rintsts.val = pending;
|
||||||
event.sdmmc_status = pending;
|
event.sdmmc_status = pending;
|
||||||
|
|
||||||
@ -882,11 +890,11 @@ static void sdmmc_isr(void *arg)
|
|||||||
xQueueSendFromISR(queue, &event, &higher_priority_task_awoken);
|
xQueueSendFromISR(queue, &event, &higher_priority_task_awoken);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t sdio_pending = SDMMC.mintsts.sdio;
|
uint32_t sdio_pending = (sdmmc_ll_get_intr_status(s_host_ctx.hal.dev) & (SDMMC_INTMASK_IO_SLOT1 | SDMMC_INTMASK_IO_SLOT0));
|
||||||
if (sdio_pending) {
|
if (sdio_pending) {
|
||||||
// disable the interrupt (no need to clear here, this is done in sdmmc_host_io_int_wait)
|
// disable the interrupt (no need to clear here, this is done in sdmmc_host_io_int_wait)
|
||||||
SDMMC.intmask.sdio &= ~sdio_pending;
|
sdmmc_ll_enable_interrupt(s_host_ctx.hal.dev, sdio_pending, false);
|
||||||
xSemaphoreGiveFromISR(s_io_intr_event, &higher_priority_task_awoken);
|
xSemaphoreGiveFromISR(s_host_ctx.io_intr_event, &higher_priority_task_awoken);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (higher_priority_task_awoken == pdTRUE) {
|
if (higher_priority_task_awoken == pdTRUE) {
|
||||||
@ -901,18 +909,18 @@ static esp_err_t sdmmc_host_pullup_en_internal(int slot, int width)
|
|||||||
return ESP_ERR_INVALID_ARG;
|
return ESP_ERR_INVALID_ARG;
|
||||||
}
|
}
|
||||||
// according to the spec, the host controls the clk, we don't to pull it up here
|
// according to the spec, the host controls the clk, we don't to pull it up here
|
||||||
gpio_pullup_en(GPIO_NUM(slot, cmd));
|
gpio_pullup_en(s_host_ctx.slot_ctx[slot].slot_gpio_num.cmd);
|
||||||
gpio_pullup_en(GPIO_NUM(slot, d0));
|
gpio_pullup_en(s_host_ctx.slot_ctx[slot].slot_gpio_num.d0);
|
||||||
if (width >= 4) {
|
if (width >= 4) {
|
||||||
gpio_pullup_en(GPIO_NUM(slot, d1));
|
gpio_pullup_en(s_host_ctx.slot_ctx[slot].slot_gpio_num.d1);
|
||||||
gpio_pullup_en(GPIO_NUM(slot, d2));
|
gpio_pullup_en(s_host_ctx.slot_ctx[slot].slot_gpio_num.d2);
|
||||||
gpio_pullup_en(GPIO_NUM(slot, d3));
|
gpio_pullup_en(s_host_ctx.slot_ctx[slot].slot_gpio_num.d3);
|
||||||
}
|
}
|
||||||
if (width == 8) {
|
if (width == 8) {
|
||||||
gpio_pullup_en(GPIO_NUM(slot, d4));
|
gpio_pullup_en(s_host_ctx.slot_ctx[slot].slot_gpio_num.d4);
|
||||||
gpio_pullup_en(GPIO_NUM(slot, d5));
|
gpio_pullup_en(s_host_ctx.slot_ctx[slot].slot_gpio_num.d5);
|
||||||
gpio_pullup_en(GPIO_NUM(slot, d6));
|
gpio_pullup_en(s_host_ctx.slot_ctx[slot].slot_gpio_num.d6);
|
||||||
gpio_pullup_en(GPIO_NUM(slot, d7));
|
gpio_pullup_en(s_host_ctx.slot_ctx[slot].slot_gpio_num.d7);
|
||||||
}
|
}
|
||||||
return ESP_OK;
|
return ESP_OK;
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
|
* SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*/
|
*/
|
||||||
@ -7,6 +7,7 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include "esp_err.h"
|
#include "esp_err.h"
|
||||||
#include "esp_log.h"
|
#include "esp_log.h"
|
||||||
|
#include "esp_check.h"
|
||||||
#include "esp_pm.h"
|
#include "esp_pm.h"
|
||||||
#include "freertos/FreeRTOS.h"
|
#include "freertos/FreeRTOS.h"
|
||||||
#include "freertos/queue.h"
|
#include "freertos/queue.h"
|
||||||
@ -18,7 +19,10 @@
|
|||||||
#include "driver/sdmmc_defs.h"
|
#include "driver/sdmmc_defs.h"
|
||||||
#include "driver/sdmmc_host.h"
|
#include "driver/sdmmc_host.h"
|
||||||
#include "esp_timer.h"
|
#include "esp_timer.h"
|
||||||
|
#include "esp_cache.h"
|
||||||
|
#include "esp_private/esp_cache_private.h"
|
||||||
#include "sdmmc_private.h"
|
#include "sdmmc_private.h"
|
||||||
|
#include "soc/soc_caps.h"
|
||||||
|
|
||||||
|
|
||||||
/* Number of DMA descriptors used for transfer.
|
/* Number of DMA descriptors used for transfer.
|
||||||
@ -27,6 +31,14 @@
|
|||||||
*/
|
*/
|
||||||
#define SDMMC_DMA_DESC_CNT 4
|
#define SDMMC_DMA_DESC_CNT 4
|
||||||
|
|
||||||
|
#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE
|
||||||
|
#define SDMMC_ALIGN_ATTR __attribute__((aligned(CONFIG_CACHE_L1_CACHE_LINE_SIZE)))
|
||||||
|
#else
|
||||||
|
#define SDMMC_ALIGN_ATTR
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define ALIGN_UP_BY(num, align) (((num) + ((align) - 1)) & ~((align) - 1))
|
||||||
|
|
||||||
static const char* TAG = "sdmmc_req";
|
static const char* TAG = "sdmmc_req";
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
@ -57,7 +69,7 @@ const uint32_t SDMMC_CMD_ERR_MASK =
|
|||||||
SDMMC_INTMASK_RCRC |
|
SDMMC_INTMASK_RCRC |
|
||||||
SDMMC_INTMASK_RESP_ERR;
|
SDMMC_INTMASK_RESP_ERR;
|
||||||
|
|
||||||
static sdmmc_desc_t s_dma_desc[SDMMC_DMA_DESC_CNT];
|
SDMMC_ALIGN_ATTR static sdmmc_desc_t s_dma_desc[SDMMC_DMA_DESC_CNT];
|
||||||
static sdmmc_transfer_state_t s_cur_transfer = { 0 };
|
static sdmmc_transfer_state_t s_cur_transfer = { 0 };
|
||||||
static QueueHandle_t s_request_mutex;
|
static QueueHandle_t s_request_mutex;
|
||||||
static bool s_is_app_cmd; // This flag is set if the next command is an APP command
|
static bool s_is_app_cmd; // This flag is set if the next command is an APP command
|
||||||
@ -113,6 +125,12 @@ esp_err_t sdmmc_host_do_transaction(int slot, sdmmc_command_t* cmdinfo)
|
|||||||
#ifdef CONFIG_PM_ENABLE
|
#ifdef CONFIG_PM_ENABLE
|
||||||
esp_pm_lock_acquire(s_pm_lock);
|
esp_pm_lock_acquire(s_pm_lock);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE
|
||||||
|
// cache sync related
|
||||||
|
size_t cache_sync_len = 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
// dispose of any events which happened asynchronously
|
// dispose of any events which happened asynchronously
|
||||||
handle_idle_state_events();
|
handle_idle_state_events();
|
||||||
// convert cmdinfo to hardware register value
|
// convert cmdinfo to hardware register value
|
||||||
@ -131,6 +149,14 @@ esp_err_t sdmmc_host_do_transaction(int slot, sdmmc_command_t* cmdinfo)
|
|||||||
ret = ESP_ERR_INVALID_ARG;
|
ret = ESP_ERR_INVALID_ARG;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE
|
||||||
|
cache_sync_len = cmdinfo->buflen;
|
||||||
|
ret = esp_cache_msync((void *)cmdinfo->data, cache_sync_len, ESP_CACHE_MSYNC_FLAG_DIR_C2M);
|
||||||
|
if (ret != ESP_OK) {
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
// this clears "owned by IDMAC" bits
|
// this clears "owned by IDMAC" bits
|
||||||
memset(s_dma_desc, 0, sizeof(s_dma_desc));
|
memset(s_dma_desc, 0, sizeof(s_dma_desc));
|
||||||
// initialize first descriptor
|
// initialize first descriptor
|
||||||
@ -167,6 +193,15 @@ esp_err_t sdmmc_host_do_transaction(int slot, sdmmc_command_t* cmdinfo)
|
|||||||
}
|
}
|
||||||
s_is_app_cmd = (ret == ESP_OK && cmdinfo->opcode == MMC_APP_CMD);
|
s_is_app_cmd = (ret == ESP_OK && cmdinfo->opcode == MMC_APP_CMD);
|
||||||
|
|
||||||
|
#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE
|
||||||
|
if (cmdinfo->data) {
|
||||||
|
ret = esp_cache_msync((void *)cmdinfo->data, cache_sync_len, ESP_CACHE_MSYNC_FLAG_DIR_M2C);
|
||||||
|
if (ret != ESP_OK) {
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
out:
|
out:
|
||||||
#ifdef CONFIG_PM_ENABLE
|
#ifdef CONFIG_PM_ENABLE
|
||||||
esp_pm_lock_release(s_pm_lock);
|
esp_pm_lock_release(s_pm_lock);
|
||||||
@ -185,6 +220,10 @@ static size_t get_free_descriptors_count(void)
|
|||||||
*/
|
*/
|
||||||
for (size_t i = 0; i < SDMMC_DMA_DESC_CNT; ++i) {
|
for (size_t i = 0; i < SDMMC_DMA_DESC_CNT; ++i) {
|
||||||
sdmmc_desc_t* desc = &s_dma_desc[(next + i) % SDMMC_DMA_DESC_CNT];
|
sdmmc_desc_t* desc = &s_dma_desc[(next + i) % SDMMC_DMA_DESC_CNT];
|
||||||
|
#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE
|
||||||
|
esp_err_t ret = esp_cache_msync((void *)desc, sizeof(sdmmc_desc_t), ESP_CACHE_MSYNC_FLAG_DIR_M2C);
|
||||||
|
assert(ret == ESP_OK);
|
||||||
|
#endif
|
||||||
if (desc->owned_by_idmac) {
|
if (desc->owned_by_idmac) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -224,6 +263,10 @@ static void fill_dma_descriptors(size_t num_desc)
|
|||||||
ESP_LOGV(TAG, "fill %d desc=%d rem=%d next=%d last=%d sz=%d",
|
ESP_LOGV(TAG, "fill %d desc=%d rem=%d next=%d last=%d sz=%d",
|
||||||
num_desc, next, s_cur_transfer.size_remaining,
|
num_desc, next, s_cur_transfer.size_remaining,
|
||||||
s_cur_transfer.next_desc, desc->last_descriptor, desc->buffer1_size);
|
s_cur_transfer.next_desc, desc->last_descriptor, desc->buffer1_size);
|
||||||
|
#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE
|
||||||
|
esp_err_t ret = esp_cache_msync((void *)desc, sizeof(sdmmc_desc_t), ESP_CACHE_MSYNC_FLAG_DIR_C2M);
|
||||||
|
assert(ret == ESP_OK);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
#include "esp_err.h"
|
#include "esp_err.h"
|
||||||
#include "esp_check.h"
|
#include "esp_check.h"
|
||||||
#include "soc/rtc.h"
|
#include "soc/rtc.h"
|
||||||
|
#include "hal/clk_tree_ll.h"
|
||||||
|
|
||||||
static const char *TAG = "esp_clk_tree";
|
static const char *TAG = "esp_clk_tree";
|
||||||
|
|
||||||
@ -31,6 +32,9 @@ uint32_t *freq_value)
|
|||||||
case SOC_MOD_CLK_LP_PLL:
|
case SOC_MOD_CLK_LP_PLL:
|
||||||
clk_src_freq = 8 * MHZ;
|
clk_src_freq = 8 * MHZ;
|
||||||
break;
|
break;
|
||||||
|
case SOC_MOD_CLK_PLL_F160M:
|
||||||
|
clk_src_freq = CLK_LL_PLL_160M_FREQ_MHZ * MHZ;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -131,6 +131,10 @@ if(NOT BOOTLOADER_BUILD)
|
|||||||
list(APPEND srcs "sdm_hal.c")
|
list(APPEND srcs "sdm_hal.c")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
if(CONFIG_SOC_SDMMC_HOST_SUPPORTED)
|
||||||
|
list(APPEND srcs "sdmmc_hal.c")
|
||||||
|
endif()
|
||||||
|
|
||||||
if(CONFIG_ETH_USE_ESP32_EMAC)
|
if(CONFIG_ETH_USE_ESP32_EMAC)
|
||||||
list(APPEND srcs "emac_hal.c")
|
list(APPEND srcs "emac_hal.c")
|
||||||
endif()
|
endif()
|
||||||
|
360
components/hal/esp32/include/hal/sdmmc_ll.h
Normal file
360
components/hal/esp32/include/hal/sdmmc_ll.h
Normal file
@ -0,0 +1,360 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
* NOTICE
|
||||||
|
* The ll is not public api, don't use in application code.
|
||||||
|
* See readme.md in hal/include/hal/readme.md
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include "esp_bit_defs.h"
|
||||||
|
#include "hal/assert.h"
|
||||||
|
#include "soc/clk_tree_defs.h"
|
||||||
|
#include "soc/sdmmc_struct.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define SDMMC_LL_GET_HW(id) (((id) == 0) ? (&SDMMC) : NULL)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SDMMC capabilities
|
||||||
|
*/
|
||||||
|
#define SDMMC_LL_SLOT_SUPPORT_GPIO_MATRIX(SLOT_ID) 0
|
||||||
|
|
||||||
|
|
||||||
|
#define SDMMC_LL_IOMUX_FUNC 3
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
SDMMC_LL_DELAY_PHASE_0,
|
||||||
|
SDMMC_LL_DELAY_PHASE_1,
|
||||||
|
SDMMC_LL_DELAY_PHASE_2,
|
||||||
|
SDMMC_LL_DELAY_PHASE_3,
|
||||||
|
} sdmmc_ll_delay_phase_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Select SDMMC clock source
|
||||||
|
*
|
||||||
|
* @param hw hardware instance address
|
||||||
|
* @param clk_src clock source, see valid sources in type `soc_periph_psram_clk_src_t`
|
||||||
|
*/
|
||||||
|
static inline void sdmmc_ll_select_clk_source(sdmmc_dev_t *hw, soc_periph_sdmmc_clk_src_t clk_src)
|
||||||
|
{
|
||||||
|
//leave for compatibility
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set SDMMC clock div
|
||||||
|
*
|
||||||
|
* @param hw hardware instance address
|
||||||
|
* @param div divider value
|
||||||
|
*/
|
||||||
|
static inline void sdmmc_ll_set_clock_div(sdmmc_dev_t *hw, uint32_t div)
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Set frequency to 160MHz / div
|
||||||
|
*
|
||||||
|
* n: counter resets at div_factor_n.
|
||||||
|
* l: negedge when counter equals div_factor_l.
|
||||||
|
* h: posedge when counter equals div_factor_h.
|
||||||
|
*
|
||||||
|
* We set the duty cycle to 1/2
|
||||||
|
*/
|
||||||
|
HAL_ASSERT(div > 1 && div <= 16);
|
||||||
|
int h = div - 1;
|
||||||
|
int l = div / 2 - 1;
|
||||||
|
|
||||||
|
hw->clock.div_factor_h = h;
|
||||||
|
hw->clock.div_factor_l = l;
|
||||||
|
hw->clock.div_factor_n = h;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Deinit clock
|
||||||
|
*
|
||||||
|
* @param hw hardware instance address
|
||||||
|
*/
|
||||||
|
static inline void sdmmc_ll_deinit_clk(sdmmc_dev_t *hw)
|
||||||
|
{
|
||||||
|
hw->clock.val = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get SDMMC clock div
|
||||||
|
*
|
||||||
|
* @param hw hardware instance address
|
||||||
|
*
|
||||||
|
* @return Divider value
|
||||||
|
*/
|
||||||
|
static inline uint32_t sdmmc_ll_get_clock_div(sdmmc_dev_t *hw)
|
||||||
|
{
|
||||||
|
return hw->clock.div_factor_h + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Initialise the din, dout, self delay phase
|
||||||
|
*
|
||||||
|
* @param hw hardware instance address
|
||||||
|
*/
|
||||||
|
static inline void sdmmc_ll_init_phase_delay(sdmmc_dev_t *hw)
|
||||||
|
{
|
||||||
|
// 180 degree phase on input and output clocks
|
||||||
|
hw->clock.phase_dout = 4;
|
||||||
|
hw->clock.phase_din = 4;
|
||||||
|
hw->clock.phase_core = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Enable card clock
|
||||||
|
*
|
||||||
|
* @param hw hardware instance address
|
||||||
|
* @param slot slot
|
||||||
|
* @param en enable / disable
|
||||||
|
*/
|
||||||
|
static inline void sdmmc_ll_enable_card_clock(sdmmc_dev_t *hw, uint32_t slot, bool en)
|
||||||
|
{
|
||||||
|
if (en) {
|
||||||
|
hw->clkena.cclk_enable |= BIT(slot);
|
||||||
|
} else {
|
||||||
|
hw->clkena.cclk_enable &= ~BIT(slot);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set card clock div
|
||||||
|
*
|
||||||
|
* @param hw hardware instance address
|
||||||
|
* @param slot slot
|
||||||
|
* @param card_div divider value
|
||||||
|
*/
|
||||||
|
static inline void sdmmc_ll_set_card_clock_div(sdmmc_dev_t *hw, uint32_t slot, uint32_t card_div)
|
||||||
|
{
|
||||||
|
if (slot == 0) {
|
||||||
|
hw->clksrc.card0 = 0;
|
||||||
|
hw->clkdiv.div0 = card_div;
|
||||||
|
} else if (slot == 1) {
|
||||||
|
hw->clksrc.card1 = 1;
|
||||||
|
hw->clkdiv.div1 = card_div;
|
||||||
|
} else {
|
||||||
|
HAL_ASSERT(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get card clock div
|
||||||
|
*
|
||||||
|
* @param hw hardware instance address
|
||||||
|
* @param slot slot
|
||||||
|
*
|
||||||
|
* @return Divider value
|
||||||
|
*/
|
||||||
|
static inline uint32_t sdmmc_ll_get_card_clock_div(sdmmc_dev_t *hw, uint32_t slot)
|
||||||
|
{
|
||||||
|
uint32_t card_div = 0;
|
||||||
|
|
||||||
|
if (slot == 0) {
|
||||||
|
HAL_ASSERT(hw->clksrc.card0 = 0);
|
||||||
|
card_div = hw->clkdiv.div0;
|
||||||
|
} else if (slot == 1) {
|
||||||
|
HAL_ASSERT(hw->clksrc.card1 = 1);
|
||||||
|
card_div = hw->clkdiv.div1;
|
||||||
|
} else {
|
||||||
|
HAL_ASSERT(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
return card_div;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Disable clock when the card is in IDLE state
|
||||||
|
*
|
||||||
|
* @param hw hardware instance address
|
||||||
|
* @param slot slot
|
||||||
|
* @param en enable / disable
|
||||||
|
*/
|
||||||
|
static inline void sdmmc_ll_enable_card_clock_low_power(sdmmc_dev_t *hw, uint32_t slot, bool en)
|
||||||
|
{
|
||||||
|
if (en) {
|
||||||
|
hw->clkena.cclk_low_power |= BIT(slot);
|
||||||
|
} else {
|
||||||
|
hw->clkena.cclk_low_power &= ~BIT(slot);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set card data read timeout cycles
|
||||||
|
*
|
||||||
|
* @param hw hardware instance address
|
||||||
|
* @param timeout_cycles timeout cycles
|
||||||
|
*/
|
||||||
|
static inline void sdmmc_ll_set_data_timeout(sdmmc_dev_t *hw, uint32_t timeout_cycles)
|
||||||
|
{
|
||||||
|
if (timeout_cycles > 0xffffff) {
|
||||||
|
timeout_cycles = 0xffffff;
|
||||||
|
}
|
||||||
|
|
||||||
|
hw->tmout.data = timeout_cycles;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set response timeout cycles (in card output clocks)
|
||||||
|
*
|
||||||
|
* @param hw hardware instance address
|
||||||
|
* @param timeout_cycles timeout cycles
|
||||||
|
*/
|
||||||
|
static inline void sdmmc_ll_set_response_timeout(sdmmc_dev_t *hw, uint32_t timeout_cycles)
|
||||||
|
{
|
||||||
|
hw->tmout.response = timeout_cycles;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Check if card is detected
|
||||||
|
*
|
||||||
|
* @param hw hardware instance address
|
||||||
|
* @param slot slot
|
||||||
|
*
|
||||||
|
* @return True for detected
|
||||||
|
*/
|
||||||
|
static inline bool sdmmc_ll_is_card_detected(sdmmc_dev_t *hw, uint32_t slot)
|
||||||
|
{
|
||||||
|
return ((hw->cdetect.cards & BIT(slot)) == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Check if card is write protected
|
||||||
|
*
|
||||||
|
* @param hw hardware instance address
|
||||||
|
* @param slot slot
|
||||||
|
*
|
||||||
|
* @return True for write protected
|
||||||
|
*/
|
||||||
|
static inline bool sdmmc_ll_is_card_write_protected(sdmmc_dev_t *hw, uint32_t slot)
|
||||||
|
{
|
||||||
|
bool is_protected = hw->wrtprt.cards & BIT(slot);
|
||||||
|
return is_protected;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Enable DDR mode
|
||||||
|
*
|
||||||
|
* @param hw hardware instance address
|
||||||
|
* @param slot slot
|
||||||
|
* @param en enable / disable
|
||||||
|
*/
|
||||||
|
static inline void sdmmc_ll_enable_ddr_mode(sdmmc_dev_t *hw, uint32_t slot, bool en)
|
||||||
|
{
|
||||||
|
if (en) {
|
||||||
|
hw->uhs.ddr |= BIT(slot);
|
||||||
|
hw->emmc_ddr_reg |= BIT(slot);
|
||||||
|
} else {
|
||||||
|
hw->uhs.ddr &= ~BIT(slot);
|
||||||
|
hw->emmc_ddr_reg &= ~BIT(slot);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set data transfer length
|
||||||
|
*
|
||||||
|
* @param hw hardware instance address
|
||||||
|
* @param len length
|
||||||
|
*/
|
||||||
|
static inline void sdmmc_ll_set_data_transfer_len(sdmmc_dev_t *hw, uint32_t len)
|
||||||
|
{
|
||||||
|
hw->bytcnt = len;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set block size
|
||||||
|
*
|
||||||
|
* @param hw hardware instance address
|
||||||
|
* @param block_size block size
|
||||||
|
*/
|
||||||
|
static inline void sdmmc_ll_set_block_size(sdmmc_dev_t *hw, uint32_t block_size)
|
||||||
|
{
|
||||||
|
hw->blksiz = block_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set descriptor addr
|
||||||
|
*
|
||||||
|
* @param hw hardware instance address
|
||||||
|
* @param block_size block size
|
||||||
|
*/
|
||||||
|
static inline void sdmmc_ll_set_desc_addr(sdmmc_dev_t *hw, uint32_t desc_addr)
|
||||||
|
{
|
||||||
|
hw->dbaddr = (sdmmc_desc_t *)desc_addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Enable DMA
|
||||||
|
*
|
||||||
|
* @param hw hardware instance address
|
||||||
|
* @param slot slot
|
||||||
|
* @param en enable / disable
|
||||||
|
*/
|
||||||
|
static inline void sdmmc_ll_enable_dma(sdmmc_dev_t *hw, bool en)
|
||||||
|
{
|
||||||
|
hw->ctrl.dma_enable = en;
|
||||||
|
hw->ctrl.use_internal_dma = en;
|
||||||
|
hw->bmod.enable = en;
|
||||||
|
hw->bmod.fb = en;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Poll demand
|
||||||
|
*
|
||||||
|
* @param hw hardware instance address
|
||||||
|
*/
|
||||||
|
static inline void sdmmc_ll_poll_demand(sdmmc_dev_t *hw)
|
||||||
|
{
|
||||||
|
hw->pldmnd = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get interrupt status
|
||||||
|
*
|
||||||
|
* @param hw hardware instance address
|
||||||
|
*/
|
||||||
|
static inline uint32_t sdmmc_ll_get_intr_status(sdmmc_dev_t *hw)
|
||||||
|
{
|
||||||
|
return hw->mintsts.val;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Enable interrupt
|
||||||
|
*
|
||||||
|
* @param hw hardware instance address
|
||||||
|
* @param mask interrupt mask
|
||||||
|
* @param en enable / disable
|
||||||
|
*/
|
||||||
|
static inline void sdmmc_ll_enable_interrupt(sdmmc_dev_t *hw, uint32_t mask, bool en)
|
||||||
|
{
|
||||||
|
if (en) {
|
||||||
|
hw->intmask.val |= mask;
|
||||||
|
} else {
|
||||||
|
hw->intmask.val &= ~mask;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Clear interrupt
|
||||||
|
*
|
||||||
|
* @param hw hardware instance address
|
||||||
|
* @param mask interrupt mask
|
||||||
|
*/
|
||||||
|
static inline void sdmmc_ll_clear_interrupt(sdmmc_dev_t *hw, uint32_t mask)
|
||||||
|
{
|
||||||
|
hw->rintsts.val = mask;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
@ -154,8 +154,6 @@ static inline uint32_t periph_ll_get_rst_en_mask(periph_module_t periph, bool en
|
|||||||
return ret;
|
return ret;
|
||||||
case PERIPH_ECDSA_MODULE:
|
case PERIPH_ECDSA_MODULE:
|
||||||
return HP_SYS_CLKRST_REG_RST_EN_CRYPTO | HP_SYS_CLKRST_REG_RST_EN_ECDSA;
|
return HP_SYS_CLKRST_REG_RST_EN_CRYPTO | HP_SYS_CLKRST_REG_RST_EN_ECDSA;
|
||||||
case PERIPH_SDMMC_MODULE:
|
|
||||||
return LP_CLKRST_RST_EN_SDMMC;
|
|
||||||
case PERIPH_EMAC_MODULE:
|
case PERIPH_EMAC_MODULE:
|
||||||
return LP_CLKRST_RST_EN_EMAC;
|
return LP_CLKRST_RST_EN_EMAC;
|
||||||
default:
|
default:
|
||||||
@ -237,7 +235,6 @@ static inline uint32_t periph_ll_get_rst_en_reg(periph_module_t periph)
|
|||||||
case PERIPH_SHA_MODULE:
|
case PERIPH_SHA_MODULE:
|
||||||
case PERIPH_ECDSA_MODULE:
|
case PERIPH_ECDSA_MODULE:
|
||||||
return HP_SYS_CLKRST_HP_RST_EN2_REG;
|
return HP_SYS_CLKRST_HP_RST_EN2_REG;
|
||||||
case PERIPH_SDMMC_MODULE:
|
|
||||||
case PERIPH_EMAC_MODULE:
|
case PERIPH_EMAC_MODULE:
|
||||||
return LP_CLKRST_HP_SDMMC_EMAC_RST_CTRL_REG;
|
return LP_CLKRST_HP_SDMMC_EMAC_RST_CTRL_REG;
|
||||||
default:
|
default:
|
||||||
|
444
components/hal/esp32p4/include/hal/sdmmc_ll.h
Normal file
444
components/hal/esp32p4/include/hal/sdmmc_ll.h
Normal file
@ -0,0 +1,444 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
* NOTICE
|
||||||
|
* The ll is not public api, don't use in application code.
|
||||||
|
* See readme.md in hal/include/hal/readme.md
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include "esp_bit_defs.h"
|
||||||
|
#include "hal/assert.h"
|
||||||
|
#include "soc/clk_tree_defs.h"
|
||||||
|
#include "soc/sdmmc_struct.h"
|
||||||
|
#include "soc/hp_sys_clkrst_struct.h"
|
||||||
|
#include "soc/lp_clkrst_struct.h"
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define SDMMC_LL_GET_HW(id) (((id) == 0) ? (&SDMMC) : NULL)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
SDMMC_LL_DELAY_PHASE_0,
|
||||||
|
SDMMC_LL_DELAY_PHASE_1,
|
||||||
|
SDMMC_LL_DELAY_PHASE_2,
|
||||||
|
SDMMC_LL_DELAY_PHASE_3,
|
||||||
|
} sdmmc_ll_delay_phase_t;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Enable the bus clock for SDMMC module
|
||||||
|
*
|
||||||
|
* @param hw hardware instance address
|
||||||
|
* @param en enable / disable
|
||||||
|
*/
|
||||||
|
static inline void sdmmc_ll_enable_bus_clock(sdmmc_dev_t *hw, bool en)
|
||||||
|
{
|
||||||
|
HP_SYS_CLKRST.soc_clk_ctrl1.reg_sdmmc_sys_clk_en = en;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 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 sdmmc_ll_enable_bus_clock(...) (void)__DECLARE_RCC_ATOMIC_ENV; sdmmc_ll_enable_bus_clock(__VA_ARGS__)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Reset the SDMMC module
|
||||||
|
*
|
||||||
|
* @param hw hardware instance address
|
||||||
|
*/
|
||||||
|
static inline void sdmmc_ll_reset_register(sdmmc_dev_t *hw)
|
||||||
|
{
|
||||||
|
LP_AON_CLKRST.hp_sdmmc_emac_rst_ctrl.rst_en_sdmmc = 1;
|
||||||
|
LP_AON_CLKRST.hp_sdmmc_emac_rst_ctrl.rst_en_sdmmc = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 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 sdmmc_ll_reset_register(...) (void)__DECLARE_RCC_ATOMIC_ENV; sdmmc_ll_reset_register(__VA_ARGS__)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Select SDMMC clock source
|
||||||
|
*
|
||||||
|
* @param hw hardware instance address
|
||||||
|
* @param clk_src clock source, see valid sources in type `soc_periph_psram_clk_src_t`
|
||||||
|
*/
|
||||||
|
static inline void sdmmc_ll_select_clk_source(sdmmc_dev_t *hw, soc_periph_sdmmc_clk_src_t clk_src)
|
||||||
|
{
|
||||||
|
uint32_t clk_val = 0;
|
||||||
|
switch (clk_src) {
|
||||||
|
case SDMMC_CLK_SRC_PLL160M:
|
||||||
|
clk_val = 0;
|
||||||
|
break;
|
||||||
|
case SDMMC_CLK_SRC_PLL200M:
|
||||||
|
clk_val = 1;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
HAL_ASSERT(false);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
HP_SYS_CLKRST.peri_clk_ctrl01.reg_sdio_ls_clk_src_sel = clk_val;
|
||||||
|
HP_SYS_CLKRST.peri_clk_ctrl01.reg_sdio_ls_clk_en = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 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 sdmmc_ll_select_clk_source(...) (void)__DECLARE_RCC_ATOMIC_ENV; sdmmc_ll_select_clk_source(__VA_ARGS__)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set SDMMC clock div
|
||||||
|
*
|
||||||
|
* @param hw hardware instance address
|
||||||
|
* @param div divider value
|
||||||
|
*/
|
||||||
|
static inline void sdmmc_ll_set_clock_div(sdmmc_dev_t *hw, uint32_t div)
|
||||||
|
{
|
||||||
|
HP_SYS_CLKRST.peri_clk_ctrl02.reg_sdio_ls_clk_edge_h = div / 2 - 1;
|
||||||
|
HP_SYS_CLKRST.peri_clk_ctrl02.reg_sdio_ls_clk_edge_n = div - 1;
|
||||||
|
HP_SYS_CLKRST.peri_clk_ctrl02.reg_sdio_ls_clk_edge_l = div - 1;
|
||||||
|
|
||||||
|
HP_SYS_CLKRST.peri_clk_ctrl02.reg_sdio_ls_clk_edge_cfg_update = 1;
|
||||||
|
HP_SYS_CLKRST.peri_clk_ctrl02.reg_sdio_ls_clk_edge_cfg_update = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 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 sdmmc_ll_set_clock_div(...) (void)__DECLARE_RCC_ATOMIC_ENV; sdmmc_ll_set_clock_div(__VA_ARGS__)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Deinit clock
|
||||||
|
*
|
||||||
|
* @param hw hardware instance address
|
||||||
|
*/
|
||||||
|
static inline void sdmmc_ll_deinit_clk(sdmmc_dev_t *hw)
|
||||||
|
{
|
||||||
|
hw->clk_edge_sel.val = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get SDMMC clock div
|
||||||
|
*
|
||||||
|
* @param hw hardware instance address
|
||||||
|
*
|
||||||
|
* @return Divider value
|
||||||
|
*/
|
||||||
|
static inline uint32_t sdmmc_ll_get_clock_div(sdmmc_dev_t *hw)
|
||||||
|
{
|
||||||
|
return HP_SYS_CLKRST.peri_clk_ctrl02.reg_sdio_ls_clk_edge_l + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Initialise the din, dout, self delay phase
|
||||||
|
*
|
||||||
|
* @param hw hardware instance address
|
||||||
|
*/
|
||||||
|
static inline void sdmmc_ll_init_phase_delay(sdmmc_dev_t *hw)
|
||||||
|
{
|
||||||
|
HP_SYS_CLKRST.peri_clk_ctrl02.reg_sdio_ls_drv_clk_en = 1;
|
||||||
|
HP_SYS_CLKRST.peri_clk_ctrl02.reg_sdio_ls_sam_clk_en = 1;
|
||||||
|
HP_SYS_CLKRST.peri_clk_ctrl02.reg_sdio_ls_slf_clk_en = 1;
|
||||||
|
|
||||||
|
HP_SYS_CLKRST.peri_clk_ctrl02.reg_sdio_ls_drv_clk_edge_sel = 1;
|
||||||
|
HP_SYS_CLKRST.peri_clk_ctrl02.reg_sdio_ls_sam_clk_edge_sel = 0;
|
||||||
|
HP_SYS_CLKRST.peri_clk_ctrl02.reg_sdio_ls_slf_clk_edge_sel = 0;
|
||||||
|
|
||||||
|
HP_SYS_CLKRST.peri_clk_ctrl02.reg_sdio_ls_clk_edge_cfg_update = 1;
|
||||||
|
HP_SYS_CLKRST.peri_clk_ctrl02.reg_sdio_ls_clk_edge_cfg_update = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 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 sdmmc_ll_init_phase_delay(...) (void)__DECLARE_RCC_ATOMIC_ENV; sdmmc_ll_init_phase_delay(__VA_ARGS__)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set SDMMC din delay
|
||||||
|
*
|
||||||
|
* @param hw hardware instance address
|
||||||
|
* @param phase delay phase
|
||||||
|
*/
|
||||||
|
static inline void sdmmc_ll_set_din_delay(sdmmc_dev_t *hw, sdmmc_ll_delay_phase_t phase)
|
||||||
|
{
|
||||||
|
switch (phase) {
|
||||||
|
case SDMMC_LL_DELAY_PHASE_1:
|
||||||
|
HP_SYS_CLKRST.peri_clk_ctrl02.reg_sdio_ls_sam_clk_edge_sel = 0x1;
|
||||||
|
break;
|
||||||
|
case SDMMC_LL_DELAY_PHASE_2:
|
||||||
|
HP_SYS_CLKRST.peri_clk_ctrl02.reg_sdio_ls_sam_clk_edge_sel = 0x2;
|
||||||
|
break;
|
||||||
|
case SDMMC_LL_DELAY_PHASE_3:
|
||||||
|
HP_SYS_CLKRST.peri_clk_ctrl02.reg_sdio_ls_sam_clk_edge_sel = 0x3;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
HP_SYS_CLKRST.peri_clk_ctrl02.reg_sdio_ls_sam_clk_edge_sel = 0x0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 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 sdmmc_ll_set_din_delay(...) (void)__DECLARE_RCC_ATOMIC_ENV; sdmmc_ll_set_din_delay(__VA_ARGS__)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Enable card clock
|
||||||
|
*
|
||||||
|
* @param hw hardware instance address
|
||||||
|
* @param slot slot
|
||||||
|
* @param en enable / disable
|
||||||
|
*/
|
||||||
|
static inline void sdmmc_ll_enable_card_clock(sdmmc_dev_t *hw, uint32_t slot, bool en)
|
||||||
|
{
|
||||||
|
if (en) {
|
||||||
|
hw->clkena.cclk_enable |= BIT(slot);
|
||||||
|
} else {
|
||||||
|
hw->clkena.cclk_enable &= ~BIT(slot);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set card clock div
|
||||||
|
*
|
||||||
|
* @param hw hardware instance address
|
||||||
|
* @param slot slot
|
||||||
|
* @param card_div divider value
|
||||||
|
*/
|
||||||
|
static inline void sdmmc_ll_set_card_clock_div(sdmmc_dev_t *hw, uint32_t slot, uint32_t card_div)
|
||||||
|
{
|
||||||
|
if (slot == 0) {
|
||||||
|
hw->clksrc.card0 = 0;
|
||||||
|
hw->clkdiv.clk_divider0 = card_div;
|
||||||
|
} else if (slot == 1) {
|
||||||
|
hw->clksrc.card1 = 1;
|
||||||
|
hw->clkdiv.clk_divider1 = card_div;
|
||||||
|
} else {
|
||||||
|
HAL_ASSERT(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get card clock div
|
||||||
|
*
|
||||||
|
* @param hw hardware instance address
|
||||||
|
* @param slot slot
|
||||||
|
*
|
||||||
|
* @return Divider value
|
||||||
|
*/
|
||||||
|
static inline uint32_t sdmmc_ll_get_card_clock_div(sdmmc_dev_t *hw, uint32_t slot)
|
||||||
|
{
|
||||||
|
uint32_t card_div = 0;
|
||||||
|
|
||||||
|
if (slot == 0) {
|
||||||
|
HAL_ASSERT(hw->clksrc.card0 = 0);
|
||||||
|
card_div = hw->clkdiv.clk_divider0;
|
||||||
|
} else if (slot == 1) {
|
||||||
|
HAL_ASSERT(hw->clksrc.card1 = 1);
|
||||||
|
card_div = hw->clkdiv.clk_divider1;
|
||||||
|
} else {
|
||||||
|
HAL_ASSERT(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
return card_div;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Disable clock when the card is in IDLE state
|
||||||
|
*
|
||||||
|
* @param hw hardware instance address
|
||||||
|
* @param slot slot
|
||||||
|
* @param en enable / disable
|
||||||
|
*/
|
||||||
|
static inline void sdmmc_ll_enable_card_clock_low_power(sdmmc_dev_t *hw, uint32_t slot, bool en)
|
||||||
|
{
|
||||||
|
if (en) {
|
||||||
|
hw->clkena.lp_enable |= BIT(slot);
|
||||||
|
} else {
|
||||||
|
hw->clkena.lp_enable &= ~BIT(slot);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set card data read timeout cycles
|
||||||
|
*
|
||||||
|
* @param hw hardware instance address
|
||||||
|
* @param timeout_cycles timeout cycles
|
||||||
|
*/
|
||||||
|
static inline void sdmmc_ll_set_data_timeout(sdmmc_dev_t *hw, uint32_t timeout_cycles)
|
||||||
|
{
|
||||||
|
if (timeout_cycles > 0xffffff) {
|
||||||
|
timeout_cycles = 0xffffff;
|
||||||
|
}
|
||||||
|
|
||||||
|
hw->tmout.data_timeout = timeout_cycles;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set response timeout cycles (in card output clocks)
|
||||||
|
*
|
||||||
|
* @param hw hardware instance address
|
||||||
|
* @param timeout_cycles timeout cycles
|
||||||
|
*/
|
||||||
|
static inline void sdmmc_ll_set_response_timeout(sdmmc_dev_t *hw, uint32_t timeout_cycles)
|
||||||
|
{
|
||||||
|
hw->tmout.response_timeout = timeout_cycles;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Check if card is detected
|
||||||
|
*
|
||||||
|
* @param hw hardware instance address
|
||||||
|
* @param slot slot
|
||||||
|
*
|
||||||
|
* @return True for detected
|
||||||
|
*/
|
||||||
|
static inline bool sdmmc_ll_is_card_detected(sdmmc_dev_t *hw, uint32_t slot)
|
||||||
|
{
|
||||||
|
return ((hw->cdetect.card_detect_n & BIT(slot)) == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Check if card is write protected
|
||||||
|
*
|
||||||
|
* @param hw hardware instance address
|
||||||
|
* @param slot slot
|
||||||
|
*
|
||||||
|
* @return True for write protected
|
||||||
|
*/
|
||||||
|
static inline bool sdmmc_ll_is_card_write_protected(sdmmc_dev_t *hw, uint32_t slot)
|
||||||
|
{
|
||||||
|
bool is_protected = hw->wrtprt.write_protect & BIT(slot);
|
||||||
|
return is_protected;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Enable DDR mode
|
||||||
|
*
|
||||||
|
* @param hw hardware instance address
|
||||||
|
* @param slot slot
|
||||||
|
* @param en enable / disable
|
||||||
|
*/
|
||||||
|
static inline void sdmmc_ll_enable_ddr_mode(sdmmc_dev_t *hw, uint32_t slot, bool en)
|
||||||
|
{
|
||||||
|
if (en) {
|
||||||
|
hw->uhs.ddr |= BIT(slot);
|
||||||
|
hw->emmcddr.halfstartbit_reg |= BIT(slot);
|
||||||
|
} else {
|
||||||
|
hw->uhs.ddr &= ~BIT(slot);
|
||||||
|
hw->emmcddr.halfstartbit_reg &= ~BIT(slot);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set data transfer length
|
||||||
|
*
|
||||||
|
* @param hw hardware instance address
|
||||||
|
* @param len length
|
||||||
|
*/
|
||||||
|
static inline void sdmmc_ll_set_data_transfer_len(sdmmc_dev_t *hw, uint32_t len)
|
||||||
|
{
|
||||||
|
hw->bytcnt.byte_count = len;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set block size
|
||||||
|
*
|
||||||
|
* @param hw hardware instance address
|
||||||
|
* @param block_size block size
|
||||||
|
*/
|
||||||
|
static inline void sdmmc_ll_set_block_size(sdmmc_dev_t *hw, uint32_t block_size)
|
||||||
|
{
|
||||||
|
hw->blksiz.block_size = block_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set descriptor addr
|
||||||
|
*
|
||||||
|
* @param hw hardware instance address
|
||||||
|
* @param block_size block size
|
||||||
|
*/
|
||||||
|
static inline void sdmmc_ll_set_desc_addr(sdmmc_dev_t *hw, uint32_t desc_addr)
|
||||||
|
{
|
||||||
|
hw->dbaddr.dbaddr_reg = desc_addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Enable DMA
|
||||||
|
*
|
||||||
|
* @param hw hardware instance address
|
||||||
|
* @param slot slot
|
||||||
|
* @param en enable / disable
|
||||||
|
*/
|
||||||
|
static inline void sdmmc_ll_enable_dma(sdmmc_dev_t *hw, bool en)
|
||||||
|
{
|
||||||
|
hw->ctrl.dma_enable = en;
|
||||||
|
hw->ctrl.use_internal_dma = en;
|
||||||
|
hw->bmod.enable = en;
|
||||||
|
hw->bmod.fb = en;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Poll demand
|
||||||
|
*
|
||||||
|
* @param hw hardware instance address
|
||||||
|
*/
|
||||||
|
static inline void sdmmc_ll_poll_demand(sdmmc_dev_t *hw)
|
||||||
|
{
|
||||||
|
hw->pldmnd.pldmnd_pd = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get interrupt status
|
||||||
|
*
|
||||||
|
* @param hw hardware instance address
|
||||||
|
*/
|
||||||
|
static inline uint32_t sdmmc_ll_get_intr_status(sdmmc_dev_t *hw)
|
||||||
|
{
|
||||||
|
return hw->mintsts.val;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Enable interrupt
|
||||||
|
*
|
||||||
|
* @param hw hardware instance address
|
||||||
|
* @param mask interrupt mask
|
||||||
|
* @param en enable / disable
|
||||||
|
*/
|
||||||
|
static inline void sdmmc_ll_enable_interrupt(sdmmc_dev_t *hw, uint32_t mask, bool en)
|
||||||
|
{
|
||||||
|
if (en) {
|
||||||
|
hw->intmask.val |= mask;
|
||||||
|
} else {
|
||||||
|
hw->intmask.val &= ~mask;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Clear interrupt
|
||||||
|
*
|
||||||
|
* @param hw hardware instance address
|
||||||
|
* @param mask interrupt mask
|
||||||
|
*/
|
||||||
|
static inline void sdmmc_ll_clear_interrupt(sdmmc_dev_t *hw, uint32_t mask)
|
||||||
|
{
|
||||||
|
hw->rintsts.val = mask;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
400
components/hal/esp32s3/include/hal/sdmmc_ll.h
Normal file
400
components/hal/esp32s3/include/hal/sdmmc_ll.h
Normal file
@ -0,0 +1,400 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
* NOTICE
|
||||||
|
* The ll is not public api, don't use in application code.
|
||||||
|
* See readme.md in hal/include/hal/readme.md
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include "esp_bit_defs.h"
|
||||||
|
#include "hal/assert.h"
|
||||||
|
#include "soc/clk_tree_defs.h"
|
||||||
|
#include "soc/sdmmc_struct.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define SDMMC_LL_GET_HW(id) (((id) == 0) ? (&SDMMC) : NULL)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SDMMC capabilities
|
||||||
|
*/
|
||||||
|
#define SDMMC_LL_SLOT_SUPPORT_GPIO_MATRIX(SLOT_ID) 1
|
||||||
|
|
||||||
|
#define SDMMC_LL_IOMUX_FUNC -1
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
SDMMC_LL_DELAY_PHASE_0,
|
||||||
|
SDMMC_LL_DELAY_PHASE_1,
|
||||||
|
SDMMC_LL_DELAY_PHASE_2,
|
||||||
|
SDMMC_LL_DELAY_PHASE_3,
|
||||||
|
} sdmmc_ll_delay_phase_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Select SDMMC clock source
|
||||||
|
*
|
||||||
|
* @param hw hardware instance address
|
||||||
|
* @param clk_src clock source, see valid sources in type `soc_periph_psram_clk_src_t`
|
||||||
|
*/
|
||||||
|
static inline void sdmmc_ll_select_clk_source(sdmmc_dev_t *hw, soc_periph_sdmmc_clk_src_t clk_src)
|
||||||
|
{
|
||||||
|
uint32_t clk_val = 0;
|
||||||
|
switch (clk_src) {
|
||||||
|
case SDMMC_CLK_SRC_PLL160M:
|
||||||
|
clk_val = 1;
|
||||||
|
break;
|
||||||
|
case SDMMC_CLK_SRC_XTAL:
|
||||||
|
clk_val = 0;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
HAL_ASSERT(false);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
hw->clock.clk_sel = clk_val;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set SDMMC clock div
|
||||||
|
*
|
||||||
|
* @param hw hardware instance address
|
||||||
|
* @param div divider value
|
||||||
|
*/
|
||||||
|
static inline void sdmmc_ll_set_clock_div(sdmmc_dev_t *hw, uint32_t div)
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Set frequency to 160MHz / div
|
||||||
|
*
|
||||||
|
* n: counter resets at div_factor_n.
|
||||||
|
* l: negedge when counter equals div_factor_l.
|
||||||
|
* h: posedge when counter equals div_factor_h.
|
||||||
|
*
|
||||||
|
* We set the duty cycle to 1/2
|
||||||
|
*/
|
||||||
|
|
||||||
|
HAL_ASSERT(div > 1 && div <= 16);
|
||||||
|
int l = div - 1;
|
||||||
|
int h = div / 2 - 1;
|
||||||
|
|
||||||
|
hw->clock.div_factor_h = h;
|
||||||
|
hw->clock.div_factor_l = l;
|
||||||
|
hw->clock.div_factor_n = l;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Deinit clock
|
||||||
|
*
|
||||||
|
* @param hw hardware instance address
|
||||||
|
*/
|
||||||
|
static inline void sdmmc_ll_deinit_clk(sdmmc_dev_t *hw)
|
||||||
|
{
|
||||||
|
hw->clock.val = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get SDMMC clock div
|
||||||
|
*
|
||||||
|
* @param hw hardware instance address
|
||||||
|
*
|
||||||
|
* @return Divider value
|
||||||
|
*/
|
||||||
|
static inline uint32_t sdmmc_ll_get_clock_div(sdmmc_dev_t *hw)
|
||||||
|
{
|
||||||
|
return hw->clock.div_factor_l + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Initialise the din, dout, self delay phase
|
||||||
|
*
|
||||||
|
* @param hw hardware instance address
|
||||||
|
*/
|
||||||
|
static inline void sdmmc_ll_init_phase_delay(sdmmc_dev_t *hw)
|
||||||
|
{
|
||||||
|
hw->clock.phase_core = 0;
|
||||||
|
/* 90 deg. delay for cclk_out to satisfy large hold time for SDR12 (up to 25MHz) and SDR25 (up to 50MHz) modes.
|
||||||
|
* Whether this delayed clock will be used depends on use_hold_reg bit in CMD structure,
|
||||||
|
* determined when sending out the command.
|
||||||
|
*/
|
||||||
|
hw->clock.phase_dout = 1;
|
||||||
|
hw->clock.phase_din = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set SDMMC din delay
|
||||||
|
*
|
||||||
|
* @param hw hardware instance address
|
||||||
|
* @param phase delay phase
|
||||||
|
*/
|
||||||
|
static inline void sdmmc_ll_set_din_delay(sdmmc_dev_t *hw, sdmmc_ll_delay_phase_t phase)
|
||||||
|
{
|
||||||
|
switch (phase) {
|
||||||
|
case SDMMC_LL_DELAY_PHASE_1:
|
||||||
|
hw->clock.phase_din = 0x1;
|
||||||
|
break;
|
||||||
|
case SDMMC_LL_DELAY_PHASE_2:
|
||||||
|
hw->clock.phase_din = 0x4;
|
||||||
|
break;
|
||||||
|
case SDMMC_LL_DELAY_PHASE_3:
|
||||||
|
hw->clock.phase_din = 0x6;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
hw->clock.phase_din = 0x0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Enable card clock
|
||||||
|
*
|
||||||
|
* @param hw hardware instance address
|
||||||
|
* @param slot slot
|
||||||
|
* @param en enable / disable
|
||||||
|
*/
|
||||||
|
static inline void sdmmc_ll_enable_card_clock(sdmmc_dev_t *hw, uint32_t slot, bool en)
|
||||||
|
{
|
||||||
|
if (en) {
|
||||||
|
hw->clkena.cclk_enable |= BIT(slot);
|
||||||
|
} else {
|
||||||
|
hw->clkena.cclk_enable &= ~BIT(slot);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set card clock div
|
||||||
|
*
|
||||||
|
* @param hw hardware instance address
|
||||||
|
* @param slot slot
|
||||||
|
* @param card_div divider value
|
||||||
|
*/
|
||||||
|
static inline void sdmmc_ll_set_card_clock_div(sdmmc_dev_t *hw, uint32_t slot, uint32_t card_div)
|
||||||
|
{
|
||||||
|
if (slot == 0) {
|
||||||
|
hw->clksrc.card0 = 0;
|
||||||
|
hw->clkdiv.div0 = card_div;
|
||||||
|
} else if (slot == 1) {
|
||||||
|
hw->clksrc.card1 = 1;
|
||||||
|
hw->clkdiv.div1 = card_div;
|
||||||
|
} else {
|
||||||
|
HAL_ASSERT(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get card clock div
|
||||||
|
*
|
||||||
|
* @param hw hardware instance address
|
||||||
|
* @param slot slot
|
||||||
|
*
|
||||||
|
* @return Divider value
|
||||||
|
*/
|
||||||
|
static inline uint32_t sdmmc_ll_get_card_clock_div(sdmmc_dev_t *hw, uint32_t slot)
|
||||||
|
{
|
||||||
|
uint32_t card_div = 0;
|
||||||
|
|
||||||
|
if (slot == 0) {
|
||||||
|
HAL_ASSERT(hw->clksrc.card0 = 0);
|
||||||
|
card_div = hw->clkdiv.div0;
|
||||||
|
} else if (slot == 1) {
|
||||||
|
HAL_ASSERT(hw->clksrc.card1 = 1);
|
||||||
|
card_div = hw->clkdiv.div1;
|
||||||
|
} else {
|
||||||
|
HAL_ASSERT(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
return card_div;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Disable clock when the card is in IDLE state
|
||||||
|
*
|
||||||
|
* @param hw hardware instance address
|
||||||
|
* @param slot slot
|
||||||
|
* @param en enable / disable
|
||||||
|
*/
|
||||||
|
static inline void sdmmc_ll_enable_card_clock_low_power(sdmmc_dev_t *hw, uint32_t slot, bool en)
|
||||||
|
{
|
||||||
|
if (en) {
|
||||||
|
hw->clkena.cclk_low_power |= BIT(slot);
|
||||||
|
} else {
|
||||||
|
hw->clkena.cclk_low_power &= ~BIT(slot);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set card data read timeout cycles
|
||||||
|
*
|
||||||
|
* @param hw hardware instance address
|
||||||
|
* @param timeout_cycles timeout cycles
|
||||||
|
*/
|
||||||
|
static inline void sdmmc_ll_set_data_timeout(sdmmc_dev_t *hw, uint32_t timeout_cycles)
|
||||||
|
{
|
||||||
|
if (timeout_cycles > 0xffffff) {
|
||||||
|
timeout_cycles = 0xffffff;
|
||||||
|
}
|
||||||
|
|
||||||
|
hw->tmout.data = timeout_cycles;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set response timeout cycles (in card output clocks)
|
||||||
|
*
|
||||||
|
* @param hw hardware instance address
|
||||||
|
* @param timeout_cycles timeout cycles
|
||||||
|
*/
|
||||||
|
static inline void sdmmc_ll_set_response_timeout(sdmmc_dev_t *hw, uint32_t timeout_cycles)
|
||||||
|
{
|
||||||
|
hw->tmout.response = timeout_cycles;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Check if card is detected
|
||||||
|
*
|
||||||
|
* @param hw hardware instance address
|
||||||
|
* @param slot slot
|
||||||
|
*
|
||||||
|
* @return True for detected
|
||||||
|
*/
|
||||||
|
static inline bool sdmmc_ll_is_card_detected(sdmmc_dev_t *hw, uint32_t slot)
|
||||||
|
{
|
||||||
|
return ((hw->cdetect.cards & BIT(slot)) == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Check if card is write protected
|
||||||
|
*
|
||||||
|
* @param hw hardware instance address
|
||||||
|
* @param slot slot
|
||||||
|
*
|
||||||
|
* @return True for write protected
|
||||||
|
*/
|
||||||
|
static inline bool sdmmc_ll_is_card_write_protected(sdmmc_dev_t *hw, uint32_t slot)
|
||||||
|
{
|
||||||
|
bool is_protected = hw->wrtprt.cards & BIT(slot);
|
||||||
|
return is_protected;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Enable DDR mode
|
||||||
|
*
|
||||||
|
* @param hw hardware instance address
|
||||||
|
* @param slot slot
|
||||||
|
* @param en enable / disable
|
||||||
|
*/
|
||||||
|
static inline void sdmmc_ll_enable_ddr_mode(sdmmc_dev_t *hw, uint32_t slot, bool en)
|
||||||
|
{
|
||||||
|
if (en) {
|
||||||
|
hw->uhs.ddr |= BIT(slot);
|
||||||
|
hw->emmc_ddr_reg |= BIT(slot);
|
||||||
|
} else {
|
||||||
|
hw->uhs.ddr &= ~BIT(slot);
|
||||||
|
hw->emmc_ddr_reg &= ~BIT(slot);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set data transfer length
|
||||||
|
*
|
||||||
|
* @param hw hardware instance address
|
||||||
|
* @param len length
|
||||||
|
*/
|
||||||
|
static inline void sdmmc_ll_set_data_transfer_len(sdmmc_dev_t *hw, uint32_t len)
|
||||||
|
{
|
||||||
|
hw->bytcnt = len;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set block size
|
||||||
|
*
|
||||||
|
* @param hw hardware instance address
|
||||||
|
* @param block_size block size
|
||||||
|
*/
|
||||||
|
static inline void sdmmc_ll_set_block_size(sdmmc_dev_t *hw, uint32_t block_size)
|
||||||
|
{
|
||||||
|
hw->blksiz = block_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set descriptor addr
|
||||||
|
*
|
||||||
|
* @param hw hardware instance address
|
||||||
|
* @param block_size block size
|
||||||
|
*/
|
||||||
|
static inline void sdmmc_ll_set_desc_addr(sdmmc_dev_t *hw, uint32_t desc_addr)
|
||||||
|
{
|
||||||
|
hw->dbaddr = (sdmmc_desc_t *)desc_addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Enable DMA
|
||||||
|
*
|
||||||
|
* @param hw hardware instance address
|
||||||
|
* @param slot slot
|
||||||
|
* @param en enable / disable
|
||||||
|
*/
|
||||||
|
static inline void sdmmc_ll_enable_dma(sdmmc_dev_t *hw, bool en)
|
||||||
|
{
|
||||||
|
hw->ctrl.dma_enable = en;
|
||||||
|
hw->ctrl.use_internal_dma = en;
|
||||||
|
hw->bmod.enable = en;
|
||||||
|
hw->bmod.fb = en;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Poll demand
|
||||||
|
*
|
||||||
|
* @param hw hardware instance address
|
||||||
|
*/
|
||||||
|
static inline void sdmmc_ll_poll_demand(sdmmc_dev_t *hw)
|
||||||
|
{
|
||||||
|
hw->pldmnd = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get interrupt status
|
||||||
|
*
|
||||||
|
* @param hw hardware instance address
|
||||||
|
*/
|
||||||
|
static inline uint32_t sdmmc_ll_get_intr_status(sdmmc_dev_t *hw)
|
||||||
|
{
|
||||||
|
return hw->mintsts.val;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Enable interrupt
|
||||||
|
*
|
||||||
|
* @param hw hardware instance address
|
||||||
|
* @param mask interrupt mask
|
||||||
|
* @param en enable / disable
|
||||||
|
*/
|
||||||
|
static inline void sdmmc_ll_enable_interrupt(sdmmc_dev_t *hw, uint32_t mask, bool en)
|
||||||
|
{
|
||||||
|
if (en) {
|
||||||
|
hw->intmask.val |= mask;
|
||||||
|
} else {
|
||||||
|
hw->intmask.val &= ~mask;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Clear interrupt
|
||||||
|
*
|
||||||
|
* @param hw hardware instance address
|
||||||
|
* @param mask interrupt mask
|
||||||
|
*/
|
||||||
|
static inline void sdmmc_ll_clear_interrupt(sdmmc_dev_t *hw, uint32_t mask)
|
||||||
|
{
|
||||||
|
hw->rintsts.val = mask;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
40
components/hal/include/hal/sdmmc_hal.h
Normal file
40
components/hal/include/hal/sdmmc_hal.h
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
* NOTICE
|
||||||
|
* The hal is not public api, don't use in application code.
|
||||||
|
* See readme.md in hal/include/hal/readme.md
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef struct sdmmc_dev_t *sdmmc_soc_handle_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Context of the HAL
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
sdmmc_soc_handle_t dev; // SDMMC SOC layer handle (i.e. register base address)
|
||||||
|
} sdmmc_hal_context_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Init the sdmmc hal context.
|
||||||
|
*
|
||||||
|
* @param hal Context of the HAL
|
||||||
|
*/
|
||||||
|
void sdmmc_hal_init(sdmmc_hal_context_t *hal);
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
16
components/hal/sdmmc_hal.c
Normal file
16
components/hal/sdmmc_hal.c
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include "hal/sdmmc_hal.h"
|
||||||
|
#include "hal/sdmmc_ll.h"
|
||||||
|
#include "soc/soc_caps.h"
|
||||||
|
|
||||||
|
|
||||||
|
void sdmmc_hal_init(sdmmc_hal_context_t *hal)
|
||||||
|
{
|
||||||
|
hal->dev = SDMMC_LL_GET_HW(0);
|
||||||
|
}
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
|
* SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*/
|
*/
|
||||||
@ -324,18 +324,23 @@ esp_err_t sdmmc_send_cmd_select_card(sdmmc_card_t* card, uint32_t rca)
|
|||||||
esp_err_t sdmmc_send_cmd_send_scr(sdmmc_card_t* card, sdmmc_scr_t *out_scr)
|
esp_err_t sdmmc_send_cmd_send_scr(sdmmc_card_t* card, sdmmc_scr_t *out_scr)
|
||||||
{
|
{
|
||||||
size_t datalen = 8;
|
size_t datalen = 8;
|
||||||
uint32_t* buf = (uint32_t*) heap_caps_malloc(datalen, MALLOC_CAP_DMA);
|
esp_err_t err = ESP_FAIL;
|
||||||
if (buf == NULL) {
|
uint32_t *buf = NULL;
|
||||||
return ESP_ERR_NO_MEM;
|
size_t actual_size = 0;
|
||||||
|
err = esp_dma_malloc(datalen, 0, (void *)&buf, &actual_size);
|
||||||
|
if (err != ESP_OK) {
|
||||||
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
sdmmc_command_t cmd = {
|
sdmmc_command_t cmd = {
|
||||||
.data = buf,
|
.data = buf,
|
||||||
.datalen = datalen,
|
.datalen = datalen,
|
||||||
|
.buflen = actual_size,
|
||||||
.blklen = datalen,
|
.blklen = datalen,
|
||||||
.flags = SCF_CMD_ADTC | SCF_CMD_READ | SCF_RSP_R1,
|
.flags = SCF_CMD_ADTC | SCF_CMD_READ | SCF_RSP_R1,
|
||||||
.opcode = SD_APP_SEND_SCR
|
.opcode = SD_APP_SEND_SCR
|
||||||
};
|
};
|
||||||
esp_err_t err = sdmmc_send_app_cmd(card, &cmd);
|
err = sdmmc_send_app_cmd(card, &cmd);
|
||||||
if (err == ESP_OK) {
|
if (err == ESP_OK) {
|
||||||
err = sdmmc_decode_scr(buf, out_scr);
|
err = sdmmc_decode_scr(buf, out_scr);
|
||||||
}
|
}
|
||||||
@ -395,21 +400,24 @@ esp_err_t sdmmc_write_sectors(sdmmc_card_t* card, const void* src,
|
|||||||
|
|
||||||
esp_err_t err = ESP_OK;
|
esp_err_t err = ESP_OK;
|
||||||
size_t block_size = card->csd.sector_size;
|
size_t block_size = card->csd.sector_size;
|
||||||
if (esp_ptr_dma_capable(src) && (intptr_t)src % 4 == 0) {
|
if (esp_dma_is_buffer_aligned(src, block_size * block_count, ESP_DMA_BUF_LOCATION_INTERNAL)) {
|
||||||
err = sdmmc_write_sectors_dma(card, src, start_block, block_count);
|
err = sdmmc_write_sectors_dma(card, src, start_block, block_count, block_size * block_count);
|
||||||
} else {
|
} else {
|
||||||
// SDMMC peripheral needs DMA-capable buffers. Split the write into
|
// SDMMC peripheral needs DMA-capable buffers. Split the write into
|
||||||
// separate single block writes, if needed, and allocate a temporary
|
// separate single block writes, if needed, and allocate a temporary
|
||||||
// DMA-capable buffer.
|
// DMA-capable buffer.
|
||||||
void* tmp_buf = heap_caps_malloc(block_size, MALLOC_CAP_DMA);
|
void *tmp_buf = NULL;
|
||||||
if (tmp_buf == NULL) {
|
size_t actual_size = 0;
|
||||||
return ESP_ERR_NO_MEM;
|
err = esp_dma_malloc(block_size, 0, &tmp_buf, &actual_size);
|
||||||
|
if (err != ESP_OK) {
|
||||||
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
const uint8_t* cur_src = (const uint8_t*) src;
|
const uint8_t* cur_src = (const uint8_t*) src;
|
||||||
for (size_t i = 0; i < block_count; ++i) {
|
for (size_t i = 0; i < block_count; ++i) {
|
||||||
memcpy(tmp_buf, cur_src, block_size);
|
memcpy(tmp_buf, cur_src, block_size);
|
||||||
cur_src += block_size;
|
cur_src += block_size;
|
||||||
err = sdmmc_write_sectors_dma(card, tmp_buf, start_block + i, 1);
|
err = sdmmc_write_sectors_dma(card, tmp_buf, start_block + i, 1, actual_size);
|
||||||
if (err != ESP_OK) {
|
if (err != ESP_OK) {
|
||||||
ESP_LOGD(TAG, "%s: error 0x%x writing block %d+%d",
|
ESP_LOGD(TAG, "%s: error 0x%x writing block %d+%d",
|
||||||
__func__, err, start_block, i);
|
__func__, err, start_block, i);
|
||||||
@ -422,7 +430,7 @@ esp_err_t sdmmc_write_sectors(sdmmc_card_t* card, const void* src,
|
|||||||
}
|
}
|
||||||
|
|
||||||
esp_err_t sdmmc_write_sectors_dma(sdmmc_card_t* card, const void* src,
|
esp_err_t sdmmc_write_sectors_dma(sdmmc_card_t* card, const void* src,
|
||||||
size_t start_block, size_t block_count)
|
size_t start_block, size_t block_count, size_t buffer_len)
|
||||||
{
|
{
|
||||||
if (start_block + block_count > card->csd.capacity) {
|
if (start_block + block_count > card->csd.capacity) {
|
||||||
return ESP_ERR_INVALID_SIZE;
|
return ESP_ERR_INVALID_SIZE;
|
||||||
@ -433,6 +441,7 @@ esp_err_t sdmmc_write_sectors_dma(sdmmc_card_t* card, const void* src,
|
|||||||
.blklen = block_size,
|
.blklen = block_size,
|
||||||
.data = (void*) src,
|
.data = (void*) src,
|
||||||
.datalen = block_count * block_size,
|
.datalen = block_count * block_size,
|
||||||
|
.buflen = buffer_len,
|
||||||
.timeout_ms = SDMMC_WRITE_CMD_TIMEOUT_MS
|
.timeout_ms = SDMMC_WRITE_CMD_TIMEOUT_MS
|
||||||
};
|
};
|
||||||
if (block_count == 1) {
|
if (block_count == 1) {
|
||||||
@ -509,19 +518,21 @@ esp_err_t sdmmc_read_sectors(sdmmc_card_t* card, void* dst,
|
|||||||
|
|
||||||
esp_err_t err = ESP_OK;
|
esp_err_t err = ESP_OK;
|
||||||
size_t block_size = card->csd.sector_size;
|
size_t block_size = card->csd.sector_size;
|
||||||
if (esp_ptr_dma_capable(dst) && (intptr_t)dst % 4 == 0) {
|
if (esp_dma_is_buffer_aligned(dst, block_size * block_count, ESP_DMA_BUF_LOCATION_INTERNAL)) {
|
||||||
err = sdmmc_read_sectors_dma(card, dst, start_block, block_count);
|
err = sdmmc_read_sectors_dma(card, dst, start_block, block_count, block_size * block_count);
|
||||||
} else {
|
} else {
|
||||||
// SDMMC peripheral needs DMA-capable buffers. Split the read into
|
// SDMMC peripheral needs DMA-capable buffers. Split the read into
|
||||||
// separate single block reads, if needed, and allocate a temporary
|
// separate single block reads, if needed, and allocate a temporary
|
||||||
// DMA-capable buffer.
|
// DMA-capable buffer.
|
||||||
void* tmp_buf = heap_caps_malloc(block_size, MALLOC_CAP_DMA);
|
void *tmp_buf = NULL;
|
||||||
if (tmp_buf == NULL) {
|
size_t actual_size = 0;
|
||||||
return ESP_ERR_NO_MEM;
|
err = esp_dma_malloc(block_size, 0, &tmp_buf, &actual_size);
|
||||||
|
if (err != ESP_OK) {
|
||||||
|
return err;
|
||||||
}
|
}
|
||||||
uint8_t* cur_dst = (uint8_t*) dst;
|
uint8_t* cur_dst = (uint8_t*) dst;
|
||||||
for (size_t i = 0; i < block_count; ++i) {
|
for (size_t i = 0; i < block_count; ++i) {
|
||||||
err = sdmmc_read_sectors_dma(card, tmp_buf, start_block + i, 1);
|
err = sdmmc_read_sectors_dma(card, tmp_buf, start_block + i, 1, actual_size);
|
||||||
if (err != ESP_OK) {
|
if (err != ESP_OK) {
|
||||||
ESP_LOGD(TAG, "%s: error 0x%x writing block %d+%d",
|
ESP_LOGD(TAG, "%s: error 0x%x writing block %d+%d",
|
||||||
__func__, err, start_block, i);
|
__func__, err, start_block, i);
|
||||||
@ -536,7 +547,7 @@ esp_err_t sdmmc_read_sectors(sdmmc_card_t* card, void* dst,
|
|||||||
}
|
}
|
||||||
|
|
||||||
esp_err_t sdmmc_read_sectors_dma(sdmmc_card_t* card, void* dst,
|
esp_err_t sdmmc_read_sectors_dma(sdmmc_card_t* card, void* dst,
|
||||||
size_t start_block, size_t block_count)
|
size_t start_block, size_t block_count, size_t buffer_len)
|
||||||
{
|
{
|
||||||
if (start_block + block_count > card->csd.capacity) {
|
if (start_block + block_count > card->csd.capacity) {
|
||||||
return ESP_ERR_INVALID_SIZE;
|
return ESP_ERR_INVALID_SIZE;
|
||||||
@ -546,7 +557,8 @@ esp_err_t sdmmc_read_sectors_dma(sdmmc_card_t* card, void* dst,
|
|||||||
.flags = SCF_CMD_ADTC | SCF_CMD_READ | SCF_RSP_R1,
|
.flags = SCF_CMD_ADTC | SCF_CMD_READ | SCF_RSP_R1,
|
||||||
.blklen = block_size,
|
.blklen = block_size,
|
||||||
.data = (void*) dst,
|
.data = (void*) dst,
|
||||||
.datalen = block_count * block_size
|
.datalen = block_count * block_size,
|
||||||
|
.buflen = buffer_len,
|
||||||
};
|
};
|
||||||
if (block_count == 1) {
|
if (block_count == 1) {
|
||||||
cmd.opcode = MMC_READ_BLOCK_SINGLE;
|
cmd.opcode = MMC_READ_BLOCK_SINGLE;
|
||||||
|
@ -26,6 +26,7 @@
|
|||||||
#include "sdmmc_cmd.h"
|
#include "sdmmc_cmd.h"
|
||||||
#include "sys/param.h"
|
#include "sys/param.h"
|
||||||
#include "soc/soc_memory_layout.h"
|
#include "soc/soc_memory_layout.h"
|
||||||
|
#include "esp_dma_utils.h"
|
||||||
|
|
||||||
#define SDMMC_GO_IDLE_DELAY_MS 20
|
#define SDMMC_GO_IDLE_DELAY_MS 20
|
||||||
#define SDMMC_IO_SEND_OP_COND_DELAY_MS 10
|
#define SDMMC_IO_SEND_OP_COND_DELAY_MS 10
|
||||||
@ -81,9 +82,9 @@ esp_err_t sdmmc_send_cmd_crc_on_off(sdmmc_card_t* card, bool crc_enable);
|
|||||||
esp_err_t sdmmc_enable_hs_mode(sdmmc_card_t* card);
|
esp_err_t sdmmc_enable_hs_mode(sdmmc_card_t* card);
|
||||||
esp_err_t sdmmc_enable_hs_mode_and_check(sdmmc_card_t* card);
|
esp_err_t sdmmc_enable_hs_mode_and_check(sdmmc_card_t* card);
|
||||||
esp_err_t sdmmc_write_sectors_dma(sdmmc_card_t* card, const void* src,
|
esp_err_t sdmmc_write_sectors_dma(sdmmc_card_t* card, const void* src,
|
||||||
size_t start_block, size_t block_count);
|
size_t start_block, size_t block_count, size_t buffer_len);
|
||||||
esp_err_t sdmmc_read_sectors_dma(sdmmc_card_t* card, void* dst,
|
esp_err_t sdmmc_read_sectors_dma(sdmmc_card_t* card, void* dst,
|
||||||
size_t start_block, size_t block_count);
|
size_t start_block, size_t block_count, size_t buffer_len);
|
||||||
uint32_t sdmmc_get_erase_timeout_ms(const sdmmc_card_t* card, int arg, size_t erase_size_kb);
|
uint32_t sdmmc_get_erase_timeout_ms(const sdmmc_card_t* card, int arg, size_t erase_size_kb);
|
||||||
|
|
||||||
/* SD specific */
|
/* SD specific */
|
||||||
@ -105,7 +106,7 @@ esp_err_t sdmmc_io_rw_extended(sdmmc_card_t* card, int function,
|
|||||||
|
|
||||||
|
|
||||||
/* MMC specific */
|
/* MMC specific */
|
||||||
esp_err_t sdmmc_mmc_send_ext_csd_data(sdmmc_card_t* card, void *out_data, size_t datalen);
|
esp_err_t sdmmc_mmc_send_ext_csd_data(sdmmc_card_t* card, void *out_data, size_t datalen, size_t buffer_len);
|
||||||
esp_err_t sdmmc_mmc_switch(sdmmc_card_t* card, uint8_t set, uint8_t index, uint8_t value);
|
esp_err_t sdmmc_mmc_switch(sdmmc_card_t* card, uint8_t set, uint8_t index, uint8_t value);
|
||||||
esp_err_t sdmmc_mmc_decode_cid(int mmc_ver, sdmmc_response_t resp, sdmmc_cid_t* out_cid);
|
esp_err_t sdmmc_mmc_decode_cid(int mmc_ver, sdmmc_response_t resp, sdmmc_cid_t* out_cid);
|
||||||
esp_err_t sdmmc_mmc_decode_csd(sdmmc_response_t response, sdmmc_csd_t* out_csd);
|
esp_err_t sdmmc_mmc_decode_csd(sdmmc_response_t response, sdmmc_csd_t* out_csd);
|
||||||
|
@ -25,11 +25,12 @@ esp_err_t sdmmc_init_mmc_read_ext_csd(sdmmc_card_t* card)
|
|||||||
{
|
{
|
||||||
int card_type;
|
int card_type;
|
||||||
esp_err_t err = ESP_OK;
|
esp_err_t err = ESP_OK;
|
||||||
|
uint8_t* ext_csd = NULL;
|
||||||
uint8_t* ext_csd = heap_caps_malloc(EXT_CSD_MMC_SIZE, MALLOC_CAP_DMA);
|
size_t actual_size = 0;
|
||||||
if (!ext_csd) {
|
err = esp_dma_malloc(EXT_CSD_MMC_SIZE, 0, (void *)&ext_csd, &actual_size);
|
||||||
|
if (err != ESP_OK) {
|
||||||
ESP_LOGE(TAG, "%s: could not allocate ext_csd", __func__);
|
ESP_LOGE(TAG, "%s: could not allocate ext_csd", __func__);
|
||||||
return ESP_ERR_NO_MEM;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t sectors = 0;
|
uint32_t sectors = 0;
|
||||||
@ -41,7 +42,7 @@ esp_err_t sdmmc_init_mmc_read_ext_csd(sdmmc_card_t* card)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* read EXT_CSD */
|
/* read EXT_CSD */
|
||||||
err = sdmmc_mmc_send_ext_csd_data(card, ext_csd, EXT_CSD_MMC_SIZE);
|
err = sdmmc_mmc_send_ext_csd_data(card, ext_csd, EXT_CSD_MMC_SIZE, actual_size);
|
||||||
if (err != ESP_OK) {
|
if (err != ESP_OK) {
|
||||||
ESP_LOGE(TAG, "%s: send_ext_csd_data error 0x%x", __func__, err);
|
ESP_LOGE(TAG, "%s: send_ext_csd_data error 0x%x", __func__, err);
|
||||||
goto out;
|
goto out;
|
||||||
@ -204,12 +205,13 @@ esp_err_t sdmmc_mmc_decode_csd(sdmmc_response_t response, sdmmc_csd_t* out_csd)
|
|||||||
return ESP_OK;
|
return ESP_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
esp_err_t sdmmc_mmc_send_ext_csd_data(sdmmc_card_t* card, void *out_data, size_t datalen)
|
esp_err_t sdmmc_mmc_send_ext_csd_data(sdmmc_card_t* card, void *out_data, size_t datalen, size_t buffer_len)
|
||||||
{
|
{
|
||||||
assert(esp_ptr_dma_capable(out_data));
|
assert(esp_ptr_dma_capable(out_data));
|
||||||
sdmmc_command_t cmd = {
|
sdmmc_command_t cmd = {
|
||||||
.data = out_data,
|
.data = out_data,
|
||||||
.datalen = datalen,
|
.datalen = datalen,
|
||||||
|
.buflen = buffer_len,
|
||||||
.blklen = datalen,
|
.blklen = datalen,
|
||||||
.opcode = MMC_SEND_EXT_CSD,
|
.opcode = MMC_SEND_EXT_CSD,
|
||||||
.arg = 0,
|
.arg = 0,
|
||||||
@ -250,15 +252,17 @@ esp_err_t sdmmc_init_mmc_check_ext_csd(sdmmc_card_t* card)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* ensure EXT_CSD buffer is available before starting any SD-card operation */
|
/* ensure EXT_CSD buffer is available before starting any SD-card operation */
|
||||||
uint8_t* ext_csd = heap_caps_malloc(EXT_CSD_MMC_SIZE, MALLOC_CAP_DMA);
|
uint8_t* ext_csd = NULL;
|
||||||
if (!ext_csd) {
|
size_t actual_size = 0;
|
||||||
|
esp_err_t err = esp_dma_malloc(EXT_CSD_MMC_SIZE, 0, (void *)&ext_csd, &actual_size);
|
||||||
|
if (err != ESP_OK) {
|
||||||
ESP_LOGE(TAG, "%s: could not allocate ext_csd", __func__);
|
ESP_LOGE(TAG, "%s: could not allocate ext_csd", __func__);
|
||||||
return ESP_ERR_NO_MEM;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ensure card is in transfer state before read ext_csd */
|
/* ensure card is in transfer state before read ext_csd */
|
||||||
uint32_t status;
|
uint32_t status;
|
||||||
esp_err_t err = sdmmc_send_cmd_send_status(card, &status);
|
err = sdmmc_send_cmd_send_status(card, &status);
|
||||||
if (err != ESP_OK) {
|
if (err != ESP_OK) {
|
||||||
ESP_LOGE(TAG, "%s: send_status returned 0x%x", __func__, err);
|
ESP_LOGE(TAG, "%s: send_status returned 0x%x", __func__, err);
|
||||||
goto out;
|
goto out;
|
||||||
@ -271,7 +275,7 @@ esp_err_t sdmmc_init_mmc_check_ext_csd(sdmmc_card_t* card)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* read EXT_CSD to ensure device works fine in HS mode */
|
/* read EXT_CSD to ensure device works fine in HS mode */
|
||||||
err = sdmmc_mmc_send_ext_csd_data(card, ext_csd, EXT_CSD_MMC_SIZE);
|
err = sdmmc_mmc_send_ext_csd_data(card, ext_csd, EXT_CSD_MMC_SIZE, actual_size);
|
||||||
if (err != ESP_OK) {
|
if (err != ESP_OK) {
|
||||||
ESP_LOGE(TAG, "%s: send_ext_csd_data error 0x%x", __func__, err);
|
ESP_LOGE(TAG, "%s: send_ext_csd_data error 0x%x", __func__, err);
|
||||||
goto out;
|
goto out;
|
||||||
|
@ -87,15 +87,18 @@ esp_err_t sdmmc_init_sd_ssr(sdmmc_card_t* card)
|
|||||||
/* Get the contents of SSR register: SD additional information
|
/* Get the contents of SSR register: SD additional information
|
||||||
* ACMD13 to read 512byte SD status information
|
* ACMD13 to read 512byte SD status information
|
||||||
*/
|
*/
|
||||||
uint32_t* sd_ssr = heap_caps_calloc(1, SD_SSR_SIZE, MALLOC_CAP_DMA);
|
uint32_t* sd_ssr = NULL;
|
||||||
if (!sd_ssr) {
|
size_t actual_size = 0;
|
||||||
|
err = esp_dma_calloc(1, SD_SSR_SIZE, 0, (void *)&sd_ssr, &actual_size);
|
||||||
|
if (err != ESP_OK) {
|
||||||
ESP_LOGE(TAG, "%s: could not allocate sd_ssr", __func__);
|
ESP_LOGE(TAG, "%s: could not allocate sd_ssr", __func__);
|
||||||
return ESP_ERR_NO_MEM;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
sdmmc_command_t cmd = {
|
sdmmc_command_t cmd = {
|
||||||
.data = sd_ssr,
|
.data = sd_ssr,
|
||||||
.datalen = SD_SSR_SIZE,
|
.datalen = SD_SSR_SIZE,
|
||||||
|
.buflen = actual_size,
|
||||||
.blklen = SD_SSR_SIZE,
|
.blklen = SD_SSR_SIZE,
|
||||||
.opcode = SD_APP_SD_STATUS,
|
.opcode = SD_APP_SD_STATUS,
|
||||||
.arg = 0,
|
.arg = 0,
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
|
* SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*/
|
*/
|
||||||
@ -286,7 +286,52 @@ typedef volatile struct sdmmc_dev_s {
|
|||||||
|
|
||||||
uint32_t usrid; ///< user ID
|
uint32_t usrid; ///< user ID
|
||||||
uint32_t verid; ///< IP block version
|
uint32_t verid; ///< IP block version
|
||||||
uint32_t hcon; ///< compile-time IP configuration
|
|
||||||
|
union {
|
||||||
|
struct {
|
||||||
|
/** card_type_reg : RO; bitpos: [0]; default: 1;
|
||||||
|
* Hardware support SDIO and MMC.
|
||||||
|
*/
|
||||||
|
uint32_t card_type_reg:1;
|
||||||
|
/** card_num_reg : RO; bitpos: [5:1]; default: 1;
|
||||||
|
* Support card number is 2.
|
||||||
|
*/
|
||||||
|
uint32_t card_num_reg:5;
|
||||||
|
/** bus_type_reg : RO; bitpos: [6]; default: 1;
|
||||||
|
* Register config is APB bus.
|
||||||
|
*/
|
||||||
|
uint32_t bus_type_reg:1;
|
||||||
|
/** data_width_reg : RO; bitpos: [9:7]; default: 1;
|
||||||
|
* Regisger data widht is 32.
|
||||||
|
*/
|
||||||
|
uint32_t data_width_reg:3;
|
||||||
|
/** addr_width_reg : RO; bitpos: [15:10]; default: 19;
|
||||||
|
* Register address width is 32.
|
||||||
|
*/
|
||||||
|
uint32_t addr_width_reg:6;
|
||||||
|
uint32_t reserved_16:2;
|
||||||
|
/** dma_width_reg : RO; bitpos: [20:18]; default: 1;
|
||||||
|
* DMA data witdth is 32.
|
||||||
|
*/
|
||||||
|
uint32_t dma_width_reg:3;
|
||||||
|
/** ram_indise_reg : RO; bitpos: [21]; default: 0;
|
||||||
|
* Inside RAM in SDMMC module.
|
||||||
|
*/
|
||||||
|
uint32_t ram_indise_reg:1;
|
||||||
|
/** hold_reg : RO; bitpos: [22]; default: 1;
|
||||||
|
* Have a hold regiser in data path .
|
||||||
|
*/
|
||||||
|
uint32_t hold_reg:1;
|
||||||
|
uint32_t reserved_23:1;
|
||||||
|
/** num_clk_div_reg : RO; bitpos: [25:24]; default: 3;
|
||||||
|
* Have 4 clk divider in design .
|
||||||
|
*/
|
||||||
|
uint32_t num_clk_div_reg:2;
|
||||||
|
uint32_t reserved_26:6;
|
||||||
|
};
|
||||||
|
uint32_t val;
|
||||||
|
} hcon;
|
||||||
|
|
||||||
union {
|
union {
|
||||||
struct {
|
struct {
|
||||||
uint32_t voltage: 16; ///< voltage control for slots; no-op on ESP32.
|
uint32_t voltage: 16; ///< voltage control for slots; no-op on ESP32.
|
||||||
|
@ -1,16 +1,8 @@
|
|||||||
// Copyright 2015-2018 Espressif Systems (Shanghai) PTE LTD
|
/*
|
||||||
//
|
* SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
*
|
||||||
// you may not use this file except in compliance with the License.
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
// You may obtain a copy of the License at
|
*/
|
||||||
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
#include "soc/sdmmc_periph.h"
|
#include "soc/sdmmc_periph.h"
|
||||||
|
|
||||||
@ -55,3 +47,30 @@ const sdmmc_slot_io_info_t sdmmc_slot_gpio_num[SOC_SDMMC_NUM_SLOTS] = {
|
|||||||
.d7 = -1,
|
.d7 = -1,
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const sdmmc_slot_io_info_t sdmmc_slot_gpio_sig[SOC_SDMMC_NUM_SLOTS] = {
|
||||||
|
{
|
||||||
|
.clk = -1,
|
||||||
|
.cmd = -1,
|
||||||
|
.d0 = -1,
|
||||||
|
.d1 = -1,
|
||||||
|
.d2 = -1,
|
||||||
|
.d3 = -1,
|
||||||
|
.d4 = -1,
|
||||||
|
.d5 = -1,
|
||||||
|
.d6 = -1,
|
||||||
|
.d7 = -1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.clk = -1,
|
||||||
|
.cmd = -1,
|
||||||
|
.d0 = -1,
|
||||||
|
.d1 = -1,
|
||||||
|
.d2 = -1,
|
||||||
|
.d3 = -1,
|
||||||
|
.d4 = -1,
|
||||||
|
.d5 = -1,
|
||||||
|
.d6 = -1,
|
||||||
|
.d7 = -1,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
@ -139,6 +139,10 @@ config SOC_PSRAM_DMA_CAPABLE
|
|||||||
bool
|
bool
|
||||||
default y
|
default y
|
||||||
|
|
||||||
|
config SOC_SDMMC_HOST_SUPPORTED
|
||||||
|
bool
|
||||||
|
default y
|
||||||
|
|
||||||
config SOC_WDT_SUPPORTED
|
config SOC_WDT_SUPPORTED
|
||||||
bool
|
bool
|
||||||
default y
|
default y
|
||||||
@ -763,6 +767,22 @@ config SOC_RSA_MAX_BIT_LEN
|
|||||||
int
|
int
|
||||||
default 4096
|
default 4096
|
||||||
|
|
||||||
|
config SOC_SDMMC_USE_IOMUX
|
||||||
|
bool
|
||||||
|
default y
|
||||||
|
|
||||||
|
config SOC_SDMMC_USE_GPIO_MATRIX
|
||||||
|
bool
|
||||||
|
default y
|
||||||
|
|
||||||
|
config SOC_SDMMC_NUM_SLOTS
|
||||||
|
int
|
||||||
|
default 2
|
||||||
|
|
||||||
|
config SOC_SDMMC_DELAY_PHASE_NUM
|
||||||
|
int
|
||||||
|
default 4
|
||||||
|
|
||||||
config SOC_SHA_DMA_MAX_BUFFER_SIZE
|
config SOC_SHA_DMA_MAX_BUFFER_SIZE
|
||||||
int
|
int
|
||||||
default 3968
|
default 3968
|
||||||
@ -795,26 +815,6 @@ config SOC_ECDSA_SUPPORT_EXPORT_PUBKEY
|
|||||||
bool
|
bool
|
||||||
default y
|
default y
|
||||||
|
|
||||||
config SOC_SDMMC_USE_IOMUX
|
|
||||||
bool
|
|
||||||
default y
|
|
||||||
|
|
||||||
config SOC_SDMMC_USE_GPIO_MATRIX
|
|
||||||
bool
|
|
||||||
default y
|
|
||||||
|
|
||||||
config SOC_SDMMC_NUM_SLOTS
|
|
||||||
int
|
|
||||||
default 2
|
|
||||||
|
|
||||||
config SOC_SDMMC_IOMUX_FUNC
|
|
||||||
bool
|
|
||||||
default n
|
|
||||||
|
|
||||||
config SOC_SDMMC_DMA_NEED_CACHE_WB
|
|
||||||
bool
|
|
||||||
default y
|
|
||||||
|
|
||||||
config SOC_SDM_GROUPS
|
config SOC_SDM_GROUPS
|
||||||
int
|
int
|
||||||
default 1
|
default 1
|
||||||
|
@ -143,6 +143,7 @@ typedef enum {
|
|||||||
// For digital domain: peripherals
|
// For digital domain: peripherals
|
||||||
SOC_MOD_CLK_PLL_F80M, /*!< PLL_F80M_CLK is derived from SPLL (clock gating + fixed divider of 6), it has a fixed frequency of 80MHz */
|
SOC_MOD_CLK_PLL_F80M, /*!< PLL_F80M_CLK is derived from SPLL (clock gating + fixed divider of 6), it has a fixed frequency of 80MHz */
|
||||||
SOC_MOD_CLK_PLL_F160M, /*!< PLL_F160M_CLK is derived from SPLL (clock gating + fixed divider of 3), it has a fixed frequency of 160MHz */
|
SOC_MOD_CLK_PLL_F160M, /*!< PLL_F160M_CLK is derived from SPLL (clock gating + fixed divider of 3), it has a fixed frequency of 160MHz */
|
||||||
|
SOC_MOD_CLK_PLL_F200M, /*!< PLL_F200M_CLK is derived from SPLL (clock gating + fixed divider of 3), it has a fixed frequency of 200MHz */
|
||||||
SOC_MOD_CLK_PLL_F240M, /*!< PLL_F240M_CLK is derived from SPLL (clock gating + fixed divider of 2), it has a fixed frequency of 240MHz */
|
SOC_MOD_CLK_PLL_F240M, /*!< PLL_F240M_CLK is derived from SPLL (clock gating + fixed divider of 2), it has a fixed frequency of 240MHz */
|
||||||
SOC_MOD_CLK_CPLL, /*!< CPLL is from 40MHz XTAL oscillator frequency multipliers, it has a fixed frequency of 400MHz */
|
SOC_MOD_CLK_CPLL, /*!< CPLL is from 40MHz XTAL oscillator frequency multipliers, it has a fixed frequency of 400MHz */
|
||||||
SOC_MOD_CLK_SPLL, /*!< SPLL is from 40MHz XTAL oscillator frequency multipliers, it has a fixed frequency of 480MHz */
|
SOC_MOD_CLK_SPLL, /*!< SPLL is from 40MHz XTAL oscillator frequency multipliers, it has a fixed frequency of 480MHz */
|
||||||
@ -522,6 +523,22 @@ typedef enum {
|
|||||||
#endif
|
#endif
|
||||||
} soc_periph_parlio_clk_src_t;
|
} soc_periph_parlio_clk_src_t;
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////SDMMC///////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Array initializer for all supported clock sources of SDMMC
|
||||||
|
*/
|
||||||
|
#define SOC_SDMMC_CLKS {SOC_MOD_CLK_PLL_F160M, SOC_MOD_CLK_PLL_F200M}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Type of SDMMC clock source
|
||||||
|
*/
|
||||||
|
typedef enum {
|
||||||
|
SDMMC_CLK_SRC_DEFAULT = SOC_MOD_CLK_PLL_F160M, /*!< Select PLL_160M as the default choice */
|
||||||
|
SDMMC_CLK_SRC_PLL160M = SOC_MOD_CLK_PLL_F160M, /*!< Select PLL_160M as the source clock */
|
||||||
|
SDMMC_CLK_SRC_PLL200M = SOC_MOD_CLK_PLL_F200M, /*!< Select PLL_200M as the source clock */
|
||||||
|
} soc_periph_sdmmc_clk_src_t;
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -785,6 +785,8 @@ typedef struct {
|
|||||||
volatile lp_clkrst_date_reg_t date;
|
volatile lp_clkrst_date_reg_t date;
|
||||||
} lp_clkrst_dev_t;
|
} lp_clkrst_dev_t;
|
||||||
|
|
||||||
|
extern lp_clkrst_dev_t LP_AON_CLKRST;
|
||||||
|
|
||||||
|
|
||||||
#ifndef __cplusplus
|
#ifndef __cplusplus
|
||||||
_Static_assert(sizeof(lp_clkrst_dev_t) == 0x400, "Invalid size of lp_clkrst_dev_t structure");
|
_Static_assert(sizeof(lp_clkrst_dev_t) == 0x400, "Invalid size of lp_clkrst_dev_t structure");
|
||||||
|
@ -5,3 +5,17 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#define SDMMC_SLOT0_IOMUX_PIN_NUM_CLK 43
|
||||||
|
#define SDMMC_SLOT0_IOMUX_PIN_NUM_CMD 44
|
||||||
|
#define SDMMC_SLOT0_IOMUX_PIN_NUM_D0 39
|
||||||
|
#define SDMMC_SLOT0_IOMUX_PIN_NUM_D1 40
|
||||||
|
#define SDMMC_SLOT0_IOMUX_PIN_NUM_D2 41
|
||||||
|
#define SDMMC_SLOT0_IOMUX_PIN_NUM_D3 42
|
||||||
|
#define SDMMC_SLOT0_IOMUX_PIN_NUM_D4 45
|
||||||
|
#define SDMMC_SLOT0_IOMUX_PIN_NUM_D5 46
|
||||||
|
#define SDMMC_SLOT0_IOMUX_PIN_NUM_D6 47
|
||||||
|
#define SDMMC_SLOT0_IOMUX_PIN_NUM_D7 48
|
||||||
|
#define SDMMC_SLOT0_FUNC 0
|
||||||
|
|
||||||
|
// SLOT1 doesn't go through IOMUX
|
||||||
|
@ -163,7 +163,7 @@ extern "C" {
|
|||||||
* Clock source selection register
|
* Clock source selection register
|
||||||
*/
|
*/
|
||||||
#define SDHOST_CLKSRC_REG (DR_REG_SDHOST_BASE + 0xc)
|
#define SDHOST_CLKSRC_REG (DR_REG_SDHOST_BASE + 0xc)
|
||||||
/** SDHOST_CLKSRC_REG : R/W; bitpos: [3:0]; default: 0;
|
/** SDHOST_CLKSRC : R/W; bitpos: [3:0]; default: 0;
|
||||||
* Clock divider source for two SD cards is supported. Each card has two bits assigned
|
* Clock divider source for two SD cards is supported. Each card has two bits assigned
|
||||||
* to it. For example, bit[1:0] are assigned for card 0, bit[3:2] are assigned for
|
* to it. For example, bit[1:0] are assigned for card 0, bit[3:2] are assigned for
|
||||||
* card 1. Card 0 maps and internally routes clock divider[0:3] outputs to
|
* card 1. Card 0 maps and internally routes clock divider[0:3] outputs to
|
||||||
@ -173,10 +173,10 @@ extern "C" {
|
|||||||
* 10 : Clock divider 2;
|
* 10 : Clock divider 2;
|
||||||
* 11 : Clock divider 3.
|
* 11 : Clock divider 3.
|
||||||
*/
|
*/
|
||||||
#define SDHOST_CLKSRC_REG 0x0000000FU
|
#define SDHOST_CLKSRC 0x0000000FU
|
||||||
#define SDHOST_CLKSRC_REG_M (SDHOST_CLKSRC_REG_V << SDHOST_CLKSRC_REG_S)
|
#define SDHOST_CLKSRC_M (SDHOST_CLKSRC_V << SDHOST_CLKSRC_S)
|
||||||
#define SDHOST_CLKSRC_REG_V 0x0000000FU
|
#define SDHOST_CLKSRC_V 0x0000000FU
|
||||||
#define SDHOST_CLKSRC_REG_S 0
|
#define SDHOST_CLKSRC_S 0
|
||||||
|
|
||||||
/** SDHOST_CLKENA_REG register
|
/** SDHOST_CLKENA_REG register
|
||||||
* Clock enable register
|
* Clock enable register
|
||||||
@ -321,13 +321,13 @@ extern "C" {
|
|||||||
* Command argument data register
|
* Command argument data register
|
||||||
*/
|
*/
|
||||||
#define SDHOST_CMDARG_REG (DR_REG_SDHOST_BASE + 0x28)
|
#define SDHOST_CMDARG_REG (DR_REG_SDHOST_BASE + 0x28)
|
||||||
/** SDHOST_CMDARG_REG : R/W; bitpos: [31:0]; default: 0;
|
/** SDHOST_CMDARG : R/W; bitpos: [31:0]; default: 0;
|
||||||
* Value indicates command argument to be passed to the card.
|
* Value indicates command argument to be passed to the card.
|
||||||
*/
|
*/
|
||||||
#define SDHOST_CMDARG_REG 0xFFFFFFFFU
|
#define SDHOST_CMDARG 0xFFFFFFFFU
|
||||||
#define SDHOST_CMDARG_REG_M (SDHOST_CMDARG_REG_V << SDHOST_CMDARG_REG_S)
|
#define SDHOST_CMDARG_M (SDHOST_CMDARG_V << SDHOST_CMDARG_S)
|
||||||
#define SDHOST_CMDARG_REG_V 0xFFFFFFFFU
|
#define SDHOST_CMDARG_V 0xFFFFFFFFU
|
||||||
#define SDHOST_CMDARG_REG_S 0
|
#define SDHOST_CMDARG_S 0
|
||||||
|
|
||||||
/** SDHOST_CMD_REG register
|
/** SDHOST_CMD_REG register
|
||||||
* Command and boot configuration register
|
* Command and boot configuration register
|
||||||
@ -808,25 +808,25 @@ extern "C" {
|
|||||||
* Transferred byte count register
|
* Transferred byte count register
|
||||||
*/
|
*/
|
||||||
#define SDHOST_TCBCNT_REG (DR_REG_SDHOST_BASE + 0x5c)
|
#define SDHOST_TCBCNT_REG (DR_REG_SDHOST_BASE + 0x5c)
|
||||||
/** SDHOST_TCBCNT_REG : RO; bitpos: [31:0]; default: 0;
|
/** SDHOST_TCBCNT : RO; bitpos: [31:0]; default: 0;
|
||||||
* Number of bytes transferred by CIU unit to card.
|
* Number of bytes transferred by CIU unit to card.
|
||||||
*/
|
*/
|
||||||
#define SDHOST_TCBCNT_REG 0xFFFFFFFFU
|
#define SDHOST_TCBCNT 0xFFFFFFFFU
|
||||||
#define SDHOST_TCBCNT_REG_M (SDHOST_TCBCNT_REG_V << SDHOST_TCBCNT_REG_S)
|
#define SDHOST_TCBCNT_M (SDHOST_TCBCNT_V << SDHOST_TCBCNT_S)
|
||||||
#define SDHOST_TCBCNT_REG_V 0xFFFFFFFFU
|
#define SDHOST_TCBCNT_V 0xFFFFFFFFU
|
||||||
#define SDHOST_TCBCNT_REG_S 0
|
#define SDHOST_TCBCNT_S 0
|
||||||
|
|
||||||
/** SDHOST_TBBCNT_REG register
|
/** SDHOST_TBBCNT_REG register
|
||||||
* Transferred byte count register
|
* Transferred byte count register
|
||||||
*/
|
*/
|
||||||
#define SDHOST_TBBCNT_REG (DR_REG_SDHOST_BASE + 0x60)
|
#define SDHOST_TBBCNT_REG (DR_REG_SDHOST_BASE + 0x60)
|
||||||
/** SDHOST_TBBCNT_REG : RO; bitpos: [31:0]; default: 0;
|
/** SDHOST_TBBCNT : RO; bitpos: [31:0]; default: 0;
|
||||||
* Number of bytes transferred between Host/DMA memory and BIU FIFO.
|
* Number of bytes transferred between Host/DMA memory and BIU FIFO.
|
||||||
*/
|
*/
|
||||||
#define SDHOST_TBBCNT_REG 0xFFFFFFFFU
|
#define SDHOST_TBBCNT 0xFFFFFFFFU
|
||||||
#define SDHOST_TBBCNT_REG_M (SDHOST_TBBCNT_REG_V << SDHOST_TBBCNT_REG_S)
|
#define SDHOST_TBBCNT_M (SDHOST_TBBCNT_V << SDHOST_TBBCNT_S)
|
||||||
#define SDHOST_TBBCNT_REG_V 0xFFFFFFFFU
|
#define SDHOST_TBBCNT_V 0xFFFFFFFFU
|
||||||
#define SDHOST_TBBCNT_REG_S 0
|
#define SDHOST_TBBCNT_S 0
|
||||||
|
|
||||||
/** SDHOST_DEBNCE_REG register
|
/** SDHOST_DEBNCE_REG register
|
||||||
* Debounce filter time configuration register
|
* Debounce filter time configuration register
|
||||||
@ -846,26 +846,26 @@ extern "C" {
|
|||||||
* User ID (scratchpad) register
|
* User ID (scratchpad) register
|
||||||
*/
|
*/
|
||||||
#define SDHOST_USRID_REG (DR_REG_SDHOST_BASE + 0x68)
|
#define SDHOST_USRID_REG (DR_REG_SDHOST_BASE + 0x68)
|
||||||
/** SDHOST_USRID_REG : R/W; bitpos: [31:0]; default: 0;
|
/** SDHOST_USRID : R/W; bitpos: [31:0]; default: 0;
|
||||||
* User identification register, value set by user. Can also be used as a scratchpad
|
* User identification register, value set by user. Can also be used as a scratchpad
|
||||||
* register by user.
|
* register by user.
|
||||||
*/
|
*/
|
||||||
#define SDHOST_USRID_REG 0xFFFFFFFFU
|
#define SDHOST_USRID 0xFFFFFFFFU
|
||||||
#define SDHOST_USRID_REG_M (SDHOST_USRID_REG_V << SDHOST_USRID_REG_S)
|
#define SDHOST_USRID_M (SDHOST_USRID_V << SDHOST_USRID_S)
|
||||||
#define SDHOST_USRID_REG_V 0xFFFFFFFFU
|
#define SDHOST_USRID_V 0xFFFFFFFFU
|
||||||
#define SDHOST_USRID_REG_S 0
|
#define SDHOST_USRID_S 0
|
||||||
|
|
||||||
/** SDHOST_VERID_REG register
|
/** SDHOST_VERID_REG register
|
||||||
* Version ID (scratchpad) register
|
* Version ID (scratchpad) register
|
||||||
*/
|
*/
|
||||||
#define SDHOST_VERID_REG (DR_REG_SDHOST_BASE + 0x6c)
|
#define SDHOST_VERID_REG (DR_REG_SDHOST_BASE + 0x6c)
|
||||||
/** SDHOST_VERSIONID_REG : RO; bitpos: [31:0]; default: 1412572938;
|
/** SDHOST_VERSIONID : RO; bitpos: [31:0]; default: 1412572938;
|
||||||
* Hardware version register. Can also be read by fireware.
|
* Hardware version register. Can also be read by fireware.
|
||||||
*/
|
*/
|
||||||
#define SDHOST_VERSIONID_REG 0xFFFFFFFFU
|
#define SDHOST_VERSIONID 0xFFFFFFFFU
|
||||||
#define SDHOST_VERSIONID_REG_M (SDHOST_VERSIONID_REG_V << SDHOST_VERSIONID_REG_S)
|
#define SDHOST_VERSIONID_M (SDHOST_VERSIONID_V << SDHOST_VERSIONID_S)
|
||||||
#define SDHOST_VERSIONID_REG_V 0xFFFFFFFFU
|
#define SDHOST_VERSIONID_V 0xFFFFFFFFU
|
||||||
#define SDHOST_VERSIONID_REG_S 0
|
#define SDHOST_VERSIONID_S 0
|
||||||
|
|
||||||
/** SDHOST_HCON_REG register
|
/** SDHOST_HCON_REG register
|
||||||
* Hardware feature register
|
* Hardware feature register
|
||||||
@ -1036,15 +1036,15 @@ extern "C" {
|
|||||||
* Descriptor base address register
|
* Descriptor base address register
|
||||||
*/
|
*/
|
||||||
#define SDHOST_DBADDR_REG (DR_REG_SDHOST_BASE + 0x88)
|
#define SDHOST_DBADDR_REG (DR_REG_SDHOST_BASE + 0x88)
|
||||||
/** SDHOST_DBADDR_REG : R/W; bitpos: [31:0]; default: 0;
|
/** SDHOST_DBADDR : R/W; bitpos: [31:0]; default: 0;
|
||||||
* Start of Descriptor List. Contains the base address of the First Descriptor. The
|
* Start of Descriptor List. Contains the base address of the First Descriptor. The
|
||||||
* LSB bits [1:0] are ignored and taken as all-zero by the IDMAC internally. Hence
|
* LSB bits [1:0] are ignored and taken as all-zero by the IDMAC internally. Hence
|
||||||
* these LSB bits may be treated as read-only.
|
* these LSB bits may be treated as read-only.
|
||||||
*/
|
*/
|
||||||
#define SDHOST_DBADDR_REG 0xFFFFFFFFU
|
#define SDHOST_DBADDR 0xFFFFFFFFU
|
||||||
#define SDHOST_DBADDR_REG_M (SDHOST_DBADDR_REG_V << SDHOST_DBADDR_REG_S)
|
#define SDHOST_DBADDR_M (SDHOST_DBADDR_V << SDHOST_DBADDR_S)
|
||||||
#define SDHOST_DBADDR_REG_V 0xFFFFFFFFU
|
#define SDHOST_DBADDR_V 0xFFFFFFFFU
|
||||||
#define SDHOST_DBADDR_REG_S 0
|
#define SDHOST_DBADDR_S 0
|
||||||
|
|
||||||
/** SDHOST_IDSTS_REG register
|
/** SDHOST_IDSTS_REG register
|
||||||
* IDMAC status register
|
* IDMAC status register
|
||||||
@ -1220,29 +1220,29 @@ extern "C" {
|
|||||||
* Host descriptor address pointer
|
* Host descriptor address pointer
|
||||||
*/
|
*/
|
||||||
#define SDHOST_DSCADDR_REG (DR_REG_SDHOST_BASE + 0x94)
|
#define SDHOST_DSCADDR_REG (DR_REG_SDHOST_BASE + 0x94)
|
||||||
/** SDHOST_DSCADDR_REG : RO; bitpos: [31:0]; default: 0;
|
/** SDHOST_DSCADDR : RO; bitpos: [31:0]; default: 0;
|
||||||
* Host Descriptor Address Pointer, updated by IDMAC during operation and cleared on
|
* Host Descriptor Address Pointer, updated by IDMAC during operation and cleared on
|
||||||
* reset. This register points to the start address of the current descriptor read by
|
* reset. This register points to the start address of the current descriptor read by
|
||||||
* the IDMAC.
|
* the IDMAC.
|
||||||
*/
|
*/
|
||||||
#define SDHOST_DSCADDR_REG 0xFFFFFFFFU
|
#define SDHOST_DSCADDR 0xFFFFFFFFU
|
||||||
#define SDHOST_DSCADDR_REG_M (SDHOST_DSCADDR_REG_V << SDHOST_DSCADDR_REG_S)
|
#define SDHOST_DSCADDR_M (SDHOST_DSCADDR_V << SDHOST_DSCADDR_S)
|
||||||
#define SDHOST_DSCADDR_REG_V 0xFFFFFFFFU
|
#define SDHOST_DSCADDR_V 0xFFFFFFFFU
|
||||||
#define SDHOST_DSCADDR_REG_S 0
|
#define SDHOST_DSCADDR_S 0
|
||||||
|
|
||||||
/** SDHOST_BUFADDR_REG register
|
/** SDHOST_BUFADDR_REG register
|
||||||
* Host buffer address pointer register
|
* Host buffer address pointer register
|
||||||
*/
|
*/
|
||||||
#define SDHOST_BUFADDR_REG (DR_REG_SDHOST_BASE + 0x98)
|
#define SDHOST_BUFADDR_REG (DR_REG_SDHOST_BASE + 0x98)
|
||||||
/** SDHOST_BUFADDR_REG : RO; bitpos: [31:0]; default: 0;
|
/** SDHOST_BUFADDR : RO; bitpos: [31:0]; default: 0;
|
||||||
* Host Buffer Address Pointer, updated by IDMAC during operation and cleared on
|
* Host Buffer Address Pointer, updated by IDMAC during operation and cleared on
|
||||||
* reset. This register points to the current Data Buffer Address being accessed by
|
* reset. This register points to the current Data Buffer Address being accessed by
|
||||||
* the IDMAC.
|
* the IDMAC.
|
||||||
*/
|
*/
|
||||||
#define SDHOST_BUFADDR_REG 0xFFFFFFFFU
|
#define SDHOST_BUFADDR 0xFFFFFFFFU
|
||||||
#define SDHOST_BUFADDR_REG_M (SDHOST_BUFADDR_REG_V << SDHOST_BUFADDR_REG_S)
|
#define SDHOST_BUFADDR_M (SDHOST_BUFADDR_V << SDHOST_BUFADDR_S)
|
||||||
#define SDHOST_BUFADDR_REG_V 0xFFFFFFFFU
|
#define SDHOST_BUFADDR_V 0xFFFFFFFFU
|
||||||
#define SDHOST_BUFADDR_REG_S 0
|
#define SDHOST_BUFADDR_S 0
|
||||||
|
|
||||||
/** SDHOST_CARDTHRCTL_REG register
|
/** SDHOST_CARDTHRCTL_REG register
|
||||||
* Card Threshold Control register
|
* Card Threshold Control register
|
||||||
@ -1328,14 +1328,14 @@ extern "C" {
|
|||||||
* CPU write and read transmit data by FIFO
|
* CPU write and read transmit data by FIFO
|
||||||
*/
|
*/
|
||||||
#define SDHOST_BUFFIFO_REG (DR_REG_SDHOST_BASE + 0x200)
|
#define SDHOST_BUFFIFO_REG (DR_REG_SDHOST_BASE + 0x200)
|
||||||
/** SDHOST_BUFFIFO_REG : R/W; bitpos: [31:0]; default: 0;
|
/** SDHOST_BUFFIFO : R/W; bitpos: [31:0]; default: 0;
|
||||||
* CPU write and read transmit data by FIFO. This register points to the current Data
|
* CPU write and read transmit data by FIFO. This register points to the current Data
|
||||||
* FIFO .
|
* FIFO .
|
||||||
*/
|
*/
|
||||||
#define SDHOST_BUFFIFO_REG 0xFFFFFFFFU
|
#define SDHOST_BUFFIFO 0xFFFFFFFFU
|
||||||
#define SDHOST_BUFFIFO_REG_M (SDHOST_BUFFIFO_REG_V << SDHOST_BUFFIFO_REG_S)
|
#define SDHOST_BUFFIFO_M (SDHOST_BUFFIFO_V << SDHOST_BUFFIFO_S)
|
||||||
#define SDHOST_BUFFIFO_REG_V 0xFFFFFFFFU
|
#define SDHOST_BUFFIFO_V 0xFFFFFFFFU
|
||||||
#define SDHOST_BUFFIFO_REG_S 0
|
#define SDHOST_BUFFIFO_S 0
|
||||||
|
|
||||||
/** SDHOST_CLK_EDGE_SEL_REG register
|
/** SDHOST_CLK_EDGE_SEL_REG register
|
||||||
* SDIO control register.
|
* SDIO control register.
|
||||||
@ -1493,6 +1493,34 @@ extern "C" {
|
|||||||
#define SDHOST_DLL_CAL_END_V 0x00000001U
|
#define SDHOST_DLL_CAL_END_V 0x00000001U
|
||||||
#define SDHOST_DLL_CAL_END_S 1
|
#define SDHOST_DLL_CAL_END_S 1
|
||||||
|
|
||||||
|
|
||||||
|
#define SDMMC_INTMASK_IO_SLOT1 BIT(17)
|
||||||
|
#define SDMMC_INTMASK_IO_SLOT0 BIT(16)
|
||||||
|
#define SDMMC_INTMASK_EBE BIT(15)
|
||||||
|
#define SDMMC_INTMASK_ACD BIT(14)
|
||||||
|
#define SDMMC_INTMASK_SBE BIT(13)
|
||||||
|
#define SDMMC_INTMASK_HLE BIT(12)
|
||||||
|
#define SDMMC_INTMASK_FRUN BIT(11)
|
||||||
|
#define SDMMC_INTMASK_HTO BIT(10)
|
||||||
|
#define SDMMC_INTMASK_DTO BIT(9)
|
||||||
|
#define SDMMC_INTMASK_RTO BIT(8)
|
||||||
|
#define SDMMC_INTMASK_DCRC BIT(7)
|
||||||
|
#define SDMMC_INTMASK_RCRC BIT(6)
|
||||||
|
#define SDMMC_INTMASK_RXDR BIT(5)
|
||||||
|
#define SDMMC_INTMASK_TXDR BIT(4)
|
||||||
|
#define SDMMC_INTMASK_DATA_OVER BIT(3)
|
||||||
|
#define SDMMC_INTMASK_CMD_DONE BIT(2)
|
||||||
|
#define SDMMC_INTMASK_RESP_ERR BIT(1)
|
||||||
|
#define SDMMC_INTMASK_CD BIT(0)
|
||||||
|
|
||||||
|
#define SDMMC_IDMAC_INTMASK_AI BIT(9)
|
||||||
|
#define SDMMC_IDMAC_INTMASK_NI BIT(8)
|
||||||
|
#define SDMMC_IDMAC_INTMASK_CES BIT(5)
|
||||||
|
#define SDMMC_IDMAC_INTMASK_DU BIT(4)
|
||||||
|
#define SDMMC_IDMAC_INTMASK_FBE BIT(2)
|
||||||
|
#define SDMMC_IDMAC_INTMASK_RI BIT(1)
|
||||||
|
#define SDMMC_IDMAC_INTMASK_TI BIT(0)
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -10,6 +10,42 @@
|
|||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
typedef struct sdmmc_desc_s {
|
||||||
|
struct {
|
||||||
|
uint32_t reserved1: 1;
|
||||||
|
uint32_t disable_int_on_completion: 1;
|
||||||
|
uint32_t last_descriptor: 1;
|
||||||
|
uint32_t first_descriptor: 1;
|
||||||
|
uint32_t second_address_chained: 1;
|
||||||
|
uint32_t end_of_ring: 1;
|
||||||
|
uint32_t reserved2: 24;
|
||||||
|
uint32_t card_error_summary: 1;
|
||||||
|
uint32_t owned_by_idmac: 1;
|
||||||
|
};
|
||||||
|
struct {
|
||||||
|
uint32_t buffer1_size: 13;
|
||||||
|
uint32_t buffer2_size: 13;
|
||||||
|
uint32_t reserved3: 6;
|
||||||
|
};
|
||||||
|
void* buffer1_ptr;
|
||||||
|
union {
|
||||||
|
void* buffer2_ptr;
|
||||||
|
void* next_desc_ptr;
|
||||||
|
};
|
||||||
|
/**
|
||||||
|
* These `reserved[12]` are for cache alignment. On P4, L1 Cache alignment is 64B.
|
||||||
|
* For those who want to access the DMA descriptor in a non-cacheable way, you can
|
||||||
|
* consider remove these `reserved[12]` bytes.
|
||||||
|
*/
|
||||||
|
uint32_t reserved[12];
|
||||||
|
} sdmmc_desc_t;
|
||||||
|
|
||||||
|
#define SDMMC_DMA_MAX_BUF_LEN 4096
|
||||||
|
|
||||||
|
#ifndef __cplusplus
|
||||||
|
_Static_assert(sizeof(sdmmc_desc_t) == 64, "invalid size of sdmmc_desc_t structure");
|
||||||
|
#endif
|
||||||
|
|
||||||
/** Group: Control register */
|
/** Group: Control register */
|
||||||
/** Type of ctrl register
|
/** Type of ctrl register
|
||||||
* Control register
|
* Control register
|
||||||
@ -39,7 +75,7 @@ typedef union {
|
|||||||
* Global interrupt enable/disable bit. 0: Disable; 1: Enable.
|
* Global interrupt enable/disable bit. 0: Disable; 1: Enable.
|
||||||
*/
|
*/
|
||||||
uint32_t int_enable:1;
|
uint32_t int_enable:1;
|
||||||
uint32_t reserved_5:1;
|
uint32_t dma_enable:1;
|
||||||
/** read_wait : R/W; bitpos: [6]; default: 0;
|
/** read_wait : R/W; bitpos: [6]; default: 0;
|
||||||
* For sending read-wait to SDIO cards.
|
* For sending read-wait to SDIO cards.
|
||||||
*/
|
*/
|
||||||
@ -90,7 +126,12 @@ typedef union {
|
|||||||
* then software should set this bit.
|
* then software should set this bit.
|
||||||
*/
|
*/
|
||||||
uint32_t ceata_device_interrupt_status:1;
|
uint32_t ceata_device_interrupt_status:1;
|
||||||
uint32_t reserved_12:20;
|
uint32_t reserved2:4;
|
||||||
|
uint32_t card_voltage_a:4;
|
||||||
|
uint32_t card_voltage_b:4;
|
||||||
|
uint32_t enable_od_pullup:1;
|
||||||
|
uint32_t use_internal_dma:1;
|
||||||
|
uint32_t reserved3:6;
|
||||||
};
|
};
|
||||||
uint32_t val;
|
uint32_t val;
|
||||||
} sdhost_ctrl_reg_t;
|
} sdhost_ctrl_reg_t;
|
||||||
@ -147,7 +188,8 @@ typedef union {
|
|||||||
* 10 : Clock divider 2;
|
* 10 : Clock divider 2;
|
||||||
* 11 : Clock divider 3.
|
* 11 : Clock divider 3.
|
||||||
*/
|
*/
|
||||||
uint32_t clksrc_reg:4;
|
uint32_t card0:2;
|
||||||
|
uint32_t card1:2;
|
||||||
uint32_t reserved_4:28;
|
uint32_t reserved_4:28;
|
||||||
};
|
};
|
||||||
uint32_t val;
|
uint32_t val;
|
||||||
@ -211,21 +253,21 @@ typedef union {
|
|||||||
*/
|
*/
|
||||||
typedef union {
|
typedef union {
|
||||||
struct {
|
struct {
|
||||||
/** card_width4 : R/W; bitpos: [1:0]; default: 0;
|
/** card_width : R/W; bitpos: [1:0]; default: 0;
|
||||||
* One bit per card indicates if card is 1-bit or 4-bit mode.
|
* One bit per card indicates if card is 1-bit or 4-bit mode.
|
||||||
* 0: 1-bit mode;
|
* 0: 1-bit mode;
|
||||||
* 1: 4-bit mode.
|
* 1: 4-bit mode.
|
||||||
* Bit[1:0] correspond to card[1:0] respectively.
|
* Bit[1:0] correspond to card[1:0] respectively.
|
||||||
*/
|
*/
|
||||||
uint32_t card_width4:2;
|
uint32_t card_width:2;
|
||||||
uint32_t reserved_2:14;
|
uint32_t reserved_2:14;
|
||||||
/** card_width8 : R/W; bitpos: [17:16]; default: 0;
|
/** card_width_8 : R/W; bitpos: [17:16]; default: 0;
|
||||||
* One bit per card indicates if card is in 8-bit mode.
|
* One bit per card indicates if card is in 8-bit mode.
|
||||||
* 0: Non 8-bit mode;
|
* 0: Non 8-bit mode;
|
||||||
* 1: 8-bit mode.
|
* 1: 8-bit mode.
|
||||||
* Bit[17:16] correspond to card[1:0] respectively.
|
* Bit[17:16] correspond to card[1:0] respectively.
|
||||||
*/
|
*/
|
||||||
uint32_t card_width8:2;
|
uint32_t card_width_8:2;
|
||||||
uint32_t reserved_18:14;
|
uint32_t reserved_18:14;
|
||||||
};
|
};
|
||||||
uint32_t val;
|
uint32_t val;
|
||||||
@ -305,21 +347,6 @@ typedef union {
|
|||||||
} sdhost_intmask_reg_t;
|
} sdhost_intmask_reg_t;
|
||||||
|
|
||||||
|
|
||||||
/** Group: Command argument data register */
|
|
||||||
/** Type of cmdarg register
|
|
||||||
* Command argument data register
|
|
||||||
*/
|
|
||||||
typedef union {
|
|
||||||
struct {
|
|
||||||
/** cmdarg_reg : R/W; bitpos: [31:0]; default: 0;
|
|
||||||
* Value indicates command argument to be passed to the card.
|
|
||||||
*/
|
|
||||||
uint32_t cmdarg_reg:32;
|
|
||||||
};
|
|
||||||
uint32_t val;
|
|
||||||
} sdhost_cmdarg_reg_t;
|
|
||||||
|
|
||||||
|
|
||||||
/** Group: Command and boot configuration register */
|
/** Group: Command and boot configuration register */
|
||||||
/** Type of cmd register
|
/** Type of cmd register
|
||||||
* Command and boot configuration register
|
* Command and boot configuration register
|
||||||
@ -334,10 +361,10 @@ typedef union {
|
|||||||
* 0: No response expected from card; 1: Response expected from card.
|
* 0: No response expected from card; 1: Response expected from card.
|
||||||
*/
|
*/
|
||||||
uint32_t response_expect:1;
|
uint32_t response_expect:1;
|
||||||
/** response_length : R/W; bitpos: [7]; default: 0;
|
/** response_long : R/W; bitpos: [7]; default: 0;
|
||||||
* 0: Short response expected from card; 1: Long response expected from card.
|
* 0: Short response expected from card; 1: Long response expected from card.
|
||||||
*/
|
*/
|
||||||
uint32_t response_length:1;
|
uint32_t response_long:1;
|
||||||
/** check_response_crc : R/W; bitpos: [8]; default: 0;
|
/** check_response_crc : R/W; bitpos: [8]; default: 0;
|
||||||
* 0: Do not check; 1: Check response CRC.
|
* 0: Do not check; 1: Check response CRC.
|
||||||
* Some of command responses do not return valid CRC bits. Software should disable CRC
|
* Some of command responses do not return valid CRC bits. Software should disable CRC
|
||||||
@ -348,11 +375,11 @@ typedef union {
|
|||||||
* 0: No data transfer expected; 1: Data transfer expected.
|
* 0: No data transfer expected; 1: Data transfer expected.
|
||||||
*/
|
*/
|
||||||
uint32_t data_expected:1;
|
uint32_t data_expected:1;
|
||||||
/** read_write : R/W; bitpos: [10]; default: 0;
|
/** rw : R/W; bitpos: [10]; default: 0;
|
||||||
* 0: Read from card; 1: Write to card.
|
* 0: Read from card; 1: Write to card.
|
||||||
* Don't care if no data is expected from card.
|
* Don't care if no data is expected from card.
|
||||||
*/
|
*/
|
||||||
uint32_t read_write:1;
|
uint32_t rw:1;
|
||||||
/** transfer_mode : R/W; bitpos: [11]; default: 0;
|
/** transfer_mode : R/W; bitpos: [11]; default: 0;
|
||||||
* 0: Block data transfer command; 1: Stream data transfer command.
|
* 0: Block data transfer command; 1: Stream data transfer command.
|
||||||
* Don't care if no data expected.
|
* Don't care if no data expected.
|
||||||
@ -363,14 +390,14 @@ typedef union {
|
|||||||
* end of data transfer.
|
* end of data transfer.
|
||||||
*/
|
*/
|
||||||
uint32_t send_auto_stop:1;
|
uint32_t send_auto_stop:1;
|
||||||
/** wait_prvdata_complete : R/W; bitpos: [13]; default: 0;
|
/** wait_complete : R/W; bitpos: [13]; default: 0;
|
||||||
* 0: Send command at once, even if previous data transfer has not completed; 1: Wait
|
* 0: Send command at once, even if previous data transfer has not completed; 1: Wait
|
||||||
* for previous data transfer to complete before sending Command.
|
* for previous data transfer to complete before sending Command.
|
||||||
* The SDHOST_WAIT_PRVDATA_COMPLETE] = 0 option is typically used to query status of
|
* The SDHOST_WAIT_COMPLETE] = 0 option is typically used to query status of
|
||||||
* card during data transfer or to stop current data transfer. SDHOST_CARD_NUMBERr
|
* card during data transfer or to stop current data transfer. SDHOST_CARD_NUMBERr
|
||||||
* should be same as in previous command.
|
* should be same as in previous command.
|
||||||
*/
|
*/
|
||||||
uint32_t wait_prvdata_complete:1;
|
uint32_t wait_complete:1;
|
||||||
/** stop_abort_cmd : R/W; bitpos: [14]; default: 0;
|
/** stop_abort_cmd : R/W; bitpos: [14]; default: 0;
|
||||||
* 0: Neither stop nor abort command can stop current data transfer. If abort is sent
|
* 0: Neither stop nor abort command can stop current data transfer. If abort is sent
|
||||||
* to function-number currently selected or not in data-transfer mode, then bit should
|
* to function-number currently selected or not in data-transfer mode, then bit should
|
||||||
@ -381,20 +408,20 @@ typedef union {
|
|||||||
* state-machines of CIU can return correctly to idle state.
|
* state-machines of CIU can return correctly to idle state.
|
||||||
*/
|
*/
|
||||||
uint32_t stop_abort_cmd:1;
|
uint32_t stop_abort_cmd:1;
|
||||||
/** send_initialization : R/W; bitpos: [15]; default: 0;
|
/** send_init : R/W; bitpos: [15]; default: 0;
|
||||||
* 0: Do not send initialization sequence (80 clocks of 1) before sending this
|
* 0: Do not send initialization sequence (80 clocks of 1) before sending this
|
||||||
* command; 1: Send initialization sequence before sending this command.
|
* command; 1: Send initialization sequence before sending this command.
|
||||||
* After powered on, 80 clocks must be sent to card for initialization before sending
|
* After powered on, 80 clocks must be sent to card for initialization before sending
|
||||||
* any commands to card. Bit should be set while sending first command to card so that
|
* any commands to card. Bit should be set while sending first command to card so that
|
||||||
* controller will initialize clocks before sending command to card.
|
* controller will initialize clocks before sending command to card.
|
||||||
*/
|
*/
|
||||||
uint32_t send_initialization:1;
|
uint32_t send_init:1;
|
||||||
/** card_number : R/W; bitpos: [20:16]; default: 0;
|
/** card_num : R/W; bitpos: [20:16]; default: 0;
|
||||||
* Card number in use. Represents physical slot number of card being accessed. In
|
* Card number in use. Represents physical slot number of card being accessed. In
|
||||||
* SD-only mode, up to two cards are supported.
|
* SD-only mode, up to two cards are supported.
|
||||||
*/
|
*/
|
||||||
uint32_t card_number:5;
|
uint32_t card_num:5;
|
||||||
/** update_clock_registers_only : R/W; bitpos: [21]; default: 0;
|
/** update_clk_reg : R/W; bitpos: [21]; default: 0;
|
||||||
* 0: Normal command sequence; 1: Do not send commands, just update clock register
|
* 0: Normal command sequence; 1: Do not send commands, just update clock register
|
||||||
* value into card clock domain.
|
* value into card clock domain.
|
||||||
* Following register values are transferred into card clock domain: CLKDIV, CLRSRC,
|
* Following register values are transferred into card clock domain: CLKDIV, CLRSRC,
|
||||||
@ -407,7 +434,7 @@ typedef union {
|
|||||||
* register values for new command sequence to card(s). When bit is set, there are no
|
* register values for new command sequence to card(s). When bit is set, there are no
|
||||||
* Command Done interrupts because no command is sent to SD_MMC_CEATA cards.
|
* Command Done interrupts because no command is sent to SD_MMC_CEATA cards.
|
||||||
*/
|
*/
|
||||||
uint32_t update_clock_registers_only:1;
|
uint32_t update_clk_reg:1;
|
||||||
/** read_ceata_device : R/W; bitpos: [22]; default: 0;
|
/** read_ceata_device : R/W; bitpos: [22]; default: 0;
|
||||||
* Read access flag.
|
* Read access flag.
|
||||||
* 0: Host is not performing read access (RW_REG or RW_BLK)towards CE-ATA device;
|
* 0: Host is not performing read access (RW_REG or RW_BLK)towards CE-ATA device;
|
||||||
@ -437,16 +464,16 @@ typedef union {
|
|||||||
* 0: CMD and DATA sent to card bypassing HOLD Register;
|
* 0: CMD and DATA sent to card bypassing HOLD Register;
|
||||||
* 1: CMD and DATA sent to card through the HOLD Register.
|
* 1: CMD and DATA sent to card through the HOLD Register.
|
||||||
*/
|
*/
|
||||||
uint32_t use_hole_reg:1;
|
uint32_t use_hold_reg:1;
|
||||||
uint32_t reserved_30:1;
|
uint32_t reserved_30:1;
|
||||||
/** start_cmd : R/W; bitpos: [31]; default: 0;
|
/** start_command : R/W; bitpos: [31]; default: 0;
|
||||||
* Start command. Once command is served by the CIU, this bit is automatically
|
* Start command. Once command is served by the CIU, this bit is automatically
|
||||||
* cleared. When this bit is set, host should not attempt to write to any command
|
* cleared. When this bit is set, host should not attempt to write to any command
|
||||||
* registers. If a write is attempted, hardware lock error is set in raw interrupt
|
* registers. If a write is attempted, hardware lock error is set in raw interrupt
|
||||||
* register. Once command is sent and a response is received from SD_MMC_CEATA cards,
|
* register. Once command is sent and a response is received from SD_MMC_CEATA cards,
|
||||||
* Command Done bit is set in the raw interrupt Register.
|
* Command Done bit is set in the raw interrupt Register.
|
||||||
*/
|
*/
|
||||||
uint32_t start_cmd:1;
|
uint32_t start_command:1;
|
||||||
};
|
};
|
||||||
uint32_t val;
|
uint32_t val;
|
||||||
} sdhost_cmd_reg_t;
|
} sdhost_cmd_reg_t;
|
||||||
@ -573,7 +600,22 @@ typedef union {
|
|||||||
* Bit 1 (RE): Response error;
|
* Bit 1 (RE): Response error;
|
||||||
* Bit 0 (CD): Card detect.
|
* Bit 0 (CD): Card detect.
|
||||||
*/
|
*/
|
||||||
uint32_t int_status_raw:16;
|
uint32_t cd:1;
|
||||||
|
uint32_t re:1;
|
||||||
|
uint32_t cmd_done:1;
|
||||||
|
uint32_t dto:1;
|
||||||
|
uint32_t txdr:1;
|
||||||
|
uint32_t rxdr:1;
|
||||||
|
uint32_t rcrc:1;
|
||||||
|
uint32_t dcrc:1;
|
||||||
|
uint32_t rto:1;
|
||||||
|
uint32_t drto:1;
|
||||||
|
uint32_t hto:1;
|
||||||
|
uint32_t frun:1;
|
||||||
|
uint32_t hle:1;
|
||||||
|
uint32_t sbi_bci:1;
|
||||||
|
uint32_t acd:1;
|
||||||
|
uint32_t ebe:1;
|
||||||
/** sdio_interrupt_raw : R/W; bitpos: [17:16]; default: 0;
|
/** sdio_interrupt_raw : R/W; bitpos: [17:16]; default: 0;
|
||||||
* Interrupt from SDIO card, one bit for each card. Bit[17:16] correspond to card1 and
|
* Interrupt from SDIO card, one bit for each card. Bit[17:16] correspond to card1 and
|
||||||
* card0, respectively. Setting a bit clears the corresponding interrupt bit and
|
* card0, respectively. Setting a bit clears the corresponding interrupt bit and
|
||||||
@ -809,21 +851,6 @@ typedef union {
|
|||||||
} sdhost_usrid_reg_t;
|
} sdhost_usrid_reg_t;
|
||||||
|
|
||||||
|
|
||||||
/** Group: Version ID (scratchpad) register */
|
|
||||||
/** Type of verid register
|
|
||||||
* Version ID (scratchpad) register
|
|
||||||
*/
|
|
||||||
typedef union {
|
|
||||||
struct {
|
|
||||||
/** versionid_reg : RO; bitpos: [31:0]; default: 1412572938;
|
|
||||||
* Hardware version register. Can also be read by fireware.
|
|
||||||
*/
|
|
||||||
uint32_t versionid_reg:32;
|
|
||||||
};
|
|
||||||
uint32_t val;
|
|
||||||
} sdhost_verid_reg_t;
|
|
||||||
|
|
||||||
|
|
||||||
/** Group: Hardware feature register */
|
/** Group: Hardware feature register */
|
||||||
/** Type of hcon register
|
/** Type of hcon register
|
||||||
* Hardware feature register
|
* Hardware feature register
|
||||||
@ -881,12 +908,12 @@ typedef union {
|
|||||||
typedef union {
|
typedef union {
|
||||||
struct {
|
struct {
|
||||||
uint32_t reserved_0:16;
|
uint32_t reserved_0:16;
|
||||||
/** ddr_reg : R/W; bitpos: [17:16]; default: 0;
|
/** ddr : R/W; bitpos: [17:16]; default: 0;
|
||||||
* DDR mode selecton,1 bit for each card.
|
* DDR mode selecton,1 bit for each card.
|
||||||
* 0-Non-DDR mdoe.
|
* 0-Non-DDR mdoe.
|
||||||
* 1-DDR mdoe.
|
* 1-DDR mdoe.
|
||||||
*/
|
*/
|
||||||
uint32_t ddr_reg:2;
|
uint32_t ddr:2;
|
||||||
uint32_t reserved_18:14;
|
uint32_t reserved_18:14;
|
||||||
};
|
};
|
||||||
uint32_t val;
|
uint32_t val;
|
||||||
@ -920,23 +947,23 @@ typedef union {
|
|||||||
*/
|
*/
|
||||||
typedef union {
|
typedef union {
|
||||||
struct {
|
struct {
|
||||||
/** bmod_swr : R/W; bitpos: [0]; default: 0;
|
/** sw_reset : R/W; bitpos: [0]; default: 0;
|
||||||
* Software Reset. When set, the DMA Controller resets all its internal registers. It
|
* Software Reset. When set, the DMA Controller resets all its internal registers. It
|
||||||
* is automatically cleared after one clock cycle.
|
* is automatically cleared after one clock cycle.
|
||||||
*/
|
*/
|
||||||
uint32_t bmod_swr:1;
|
uint32_t sw_reset:1;
|
||||||
/** bmod_fb : R/W; bitpos: [1]; default: 0;
|
/** fb : R/W; bitpos: [1]; default: 0;
|
||||||
* Fixed Burst. Controls whether the AHB Master interface performs fixed burst
|
* Fixed Burst. Controls whether the AHB Master interface performs fixed burst
|
||||||
* transfers or not. When set, the AHB will use only SINGLE, INCR4, INCR8 or INCR16
|
* transfers or not. When set, the AHB will use only SINGLE, INCR4, INCR8 or INCR16
|
||||||
* during start of normal burst transfers. When reset, the AHB will use SINGLE and
|
* during start of normal burst transfers. When reset, the AHB will use SINGLE and
|
||||||
* INCR burst transfer operations.
|
* INCR burst transfer operations.
|
||||||
*/
|
*/
|
||||||
uint32_t bmod_fb:1;
|
uint32_t fb:1;
|
||||||
uint32_t reserved_2:5;
|
uint32_t reserved_2:5;
|
||||||
/** bmod_de : R/W; bitpos: [7]; default: 0;
|
/** enable : R/W; bitpos: [7]; default: 0;
|
||||||
* IDMAC Enable. When set, the IDMAC is enabled.
|
* IDMAC Enable. When set, the IDMAC is enabled.
|
||||||
*/
|
*/
|
||||||
uint32_t bmod_de:1;
|
uint32_t enable:1;
|
||||||
/** bmod_pbl : R/W; bitpos: [10:8]; default: 0;
|
/** bmod_pbl : R/W; bitpos: [10:8]; default: 0;
|
||||||
* Programmable Burst Length. These bits indicate the maximum number of beats to be
|
* Programmable Burst Length. These bits indicate the maximum number of beats to be
|
||||||
* performed in one IDMAC???Internal DMA Control???transaction. The IDMAC will always
|
* performed in one IDMAC???Internal DMA Control???transaction. The IDMAC will always
|
||||||
@ -1088,16 +1115,16 @@ typedef union {
|
|||||||
*/
|
*/
|
||||||
typedef union {
|
typedef union {
|
||||||
struct {
|
struct {
|
||||||
/** idinten_ti : R/W; bitpos: [0]; default: 0;
|
/** ti : R/W; bitpos: [0]; default: 0;
|
||||||
* Transmit Interrupt Enable. When set with Normal Interrupt Summary Enable, Transmit
|
* Transmit Interrupt Enable. When set with Normal Interrupt Summary Enable, Transmit
|
||||||
* Interrupt is enabled. When reset, Transmit Interrupt is disabled.
|
* Interrupt is enabled. When reset, Transmit Interrupt is disabled.
|
||||||
*/
|
*/
|
||||||
uint32_t idinten_ti:1;
|
uint32_t ti:1;
|
||||||
/** idinten_ri : R/W; bitpos: [1]; default: 0;
|
/** ri : R/W; bitpos: [1]; default: 0;
|
||||||
* Receive Interrupt Enable. When set with Normal Interrupt Summary Enable, Receive
|
* Receive Interrupt Enable. When set with Normal Interrupt Summary Enable, Receive
|
||||||
* Interrupt is enabled. When reset, Receive Interrupt is disabled.
|
* Interrupt is enabled. When reset, Receive Interrupt is disabled.
|
||||||
*/
|
*/
|
||||||
uint32_t idinten_ri:1;
|
uint32_t ri:1;
|
||||||
/** idinten_fbe : R/W; bitpos: [2]; default: 0;
|
/** idinten_fbe : R/W; bitpos: [2]; default: 0;
|
||||||
* Fatal Bus Error Enable. When set with Abnormal Interrupt Summary Enable, the Fatal
|
* Fatal Bus Error Enable. When set with Abnormal Interrupt Summary Enable, the Fatal
|
||||||
* Bus Error Interrupt is enabled. When reset, Fatal Bus Error Enable Interrupt is
|
* Bus Error Interrupt is enabled. When reset, Fatal Bus Error Enable Interrupt is
|
||||||
@ -1116,13 +1143,13 @@ typedef union {
|
|||||||
*/
|
*/
|
||||||
uint32_t idinten_ces:1;
|
uint32_t idinten_ces:1;
|
||||||
uint32_t reserved_6:2;
|
uint32_t reserved_6:2;
|
||||||
/** idinten_ni : R/W; bitpos: [8]; default: 0;
|
/** ni : R/W; bitpos: [8]; default: 0;
|
||||||
* Normal Interrupt Summary Enable. When set, a normal interrupt is enabled. When
|
* Normal Interrupt Summary Enable. When set, a normal interrupt is enabled. When
|
||||||
* reset, a normal interrupt is disabled. This bit enables the following bits:
|
* reset, a normal interrupt is disabled. This bit enables the following bits:
|
||||||
* IDINTEN[0]: Transmit Interrupt;
|
* IDINTEN[0]: Transmit Interrupt;
|
||||||
* IDINTEN[1]: Receive Interrupt.
|
* IDINTEN[1]: Receive Interrupt.
|
||||||
*/
|
*/
|
||||||
uint32_t idinten_ni:1;
|
uint32_t ni:1;
|
||||||
/** idinten_ai : R/W; bitpos: [9]; default: 0;
|
/** idinten_ai : R/W; bitpos: [9]; default: 0;
|
||||||
* Abnormal Interrupt Summary Enable. When set, an abnormal interrupt is enabled. This
|
* Abnormal Interrupt Summary Enable. When set, an abnormal interrupt is enabled. This
|
||||||
* bit enables the following bits:
|
* bit enables the following bits:
|
||||||
@ -1182,12 +1209,12 @@ typedef union {
|
|||||||
* 1'b1-Card read threshold enabled.
|
* 1'b1-Card read threshold enabled.
|
||||||
*/
|
*/
|
||||||
uint32_t cardrdthren_reg:1;
|
uint32_t cardrdthren_reg:1;
|
||||||
/** cardclrinten_reg : R/W; bitpos: [1]; default: 0;
|
/** busy_clr_int_en : R/W; bitpos: [1]; default: 0;
|
||||||
* Busy clear interrupt generation:
|
* Busy clear interrupt generation:
|
||||||
* 1'b0-Busy clear interrypt disabled.
|
* 1'b0-Busy clear interrypt disabled.
|
||||||
* 1'b1-Busy clear interrypt enabled.
|
* 1'b1-Busy clear interrypt enabled.
|
||||||
*/
|
*/
|
||||||
uint32_t cardclrinten_reg:1;
|
uint32_t busy_clr_int_en:1;
|
||||||
/** cardwrthren_reg : R/W; bitpos: [2]; default: 0;
|
/** cardwrthren_reg : R/W; bitpos: [2]; default: 0;
|
||||||
* Applicable when HS400 mode is enabled.
|
* Applicable when HS400 mode is enabled.
|
||||||
* 1'b0-Card write Threshold disabled.
|
* 1'b0-Card write Threshold disabled.
|
||||||
@ -1392,7 +1419,7 @@ typedef union {
|
|||||||
} sdhost_dll_conf_reg_t;
|
} sdhost_dll_conf_reg_t;
|
||||||
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct sdmmc_dev_t {
|
||||||
volatile sdhost_ctrl_reg_t ctrl;
|
volatile sdhost_ctrl_reg_t ctrl;
|
||||||
uint32_t reserved_004;
|
uint32_t reserved_004;
|
||||||
volatile sdhost_clkdiv_reg_t clkdiv;
|
volatile sdhost_clkdiv_reg_t clkdiv;
|
||||||
@ -1403,12 +1430,9 @@ typedef struct {
|
|||||||
volatile sdhost_blksiz_reg_t blksiz;
|
volatile sdhost_blksiz_reg_t blksiz;
|
||||||
volatile sdhost_bytcnt_reg_t bytcnt;
|
volatile sdhost_bytcnt_reg_t bytcnt;
|
||||||
volatile sdhost_intmask_reg_t intmask;
|
volatile sdhost_intmask_reg_t intmask;
|
||||||
volatile sdhost_cmdarg_reg_t cmdarg;
|
volatile uint32_t cmdarg;
|
||||||
volatile sdhost_cmd_reg_t cmd;
|
volatile sdhost_cmd_reg_t cmd;
|
||||||
volatile sdhost_resp0_reg_t resp0;
|
volatile uint32_t resp[4]; ///< Response from card
|
||||||
volatile sdhost_resp1_reg_t resp1;
|
|
||||||
volatile sdhost_resp2_reg_t resp2;
|
|
||||||
volatile sdhost_resp3_reg_t resp3;
|
|
||||||
volatile sdhost_mintsts_reg_t mintsts;
|
volatile sdhost_mintsts_reg_t mintsts;
|
||||||
volatile sdhost_rintsts_reg_t rintsts;
|
volatile sdhost_rintsts_reg_t rintsts;
|
||||||
volatile sdhost_status_reg_t status;
|
volatile sdhost_status_reg_t status;
|
||||||
@ -1420,7 +1444,7 @@ typedef struct {
|
|||||||
volatile sdhost_tbbcnt_reg_t tbbcnt;
|
volatile sdhost_tbbcnt_reg_t tbbcnt;
|
||||||
volatile sdhost_debnce_reg_t debnce;
|
volatile sdhost_debnce_reg_t debnce;
|
||||||
volatile sdhost_usrid_reg_t usrid;
|
volatile sdhost_usrid_reg_t usrid;
|
||||||
volatile sdhost_verid_reg_t verid;
|
volatile uint32_t verid;
|
||||||
volatile sdhost_hcon_reg_t hcon;
|
volatile sdhost_hcon_reg_t hcon;
|
||||||
volatile sdhost_uhs_reg_t uhs;
|
volatile sdhost_uhs_reg_t uhs;
|
||||||
volatile sdhost_rst_n_reg_t rst_n;
|
volatile sdhost_rst_n_reg_t rst_n;
|
||||||
@ -1444,11 +1468,14 @@ typedef struct {
|
|||||||
volatile sdhost_raw_ints_reg_t raw_ints;
|
volatile sdhost_raw_ints_reg_t raw_ints;
|
||||||
volatile sdhost_dll_clk_conf_reg_t dll_clk_conf;
|
volatile sdhost_dll_clk_conf_reg_t dll_clk_conf;
|
||||||
volatile sdhost_dll_conf_reg_t dll_conf;
|
volatile sdhost_dll_conf_reg_t dll_conf;
|
||||||
} sdhost_dev_t;
|
} sdmmc_dev_t;
|
||||||
|
|
||||||
|
extern sdmmc_dev_t SDMMC;
|
||||||
|
|
||||||
|
typedef sdhost_cmd_reg_t sdmmc_hw_cmd_t;
|
||||||
|
|
||||||
#ifndef __cplusplus
|
#ifndef __cplusplus
|
||||||
_Static_assert(sizeof(sdhost_dev_t) == 0x810, "Invalid size of sdhost_dev_t structure");
|
_Static_assert(sizeof(sdmmc_dev_t) == 0x810, "Invalid size of sdmmc_dev_t structure");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
@ -78,7 +78,7 @@
|
|||||||
#define SOC_SPIRAM_SUPPORTED 1
|
#define SOC_SPIRAM_SUPPORTED 1
|
||||||
#define SOC_PSRAM_DMA_CAPABLE 1
|
#define SOC_PSRAM_DMA_CAPABLE 1
|
||||||
// #define SOC_ULP_SUPPORTED 1 //TODO: IDF-7534
|
// #define SOC_ULP_SUPPORTED 1 //TODO: IDF-7534
|
||||||
// #define SOC_SDMMC_HOST_SUPPORTED 1 //TODO: IDF-6502
|
#define SOC_SDMMC_HOST_SUPPORTED 1
|
||||||
// #define SOC_CLK_TREE_SUPPORTED 1 //TODO: IDF-7526
|
// #define SOC_CLK_TREE_SUPPORTED 1 //TODO: IDF-7526
|
||||||
// #define SOC_ASSIST_DEBUG_SUPPORTED 1 //TODO: IDF-7565
|
// #define SOC_ASSIST_DEBUG_SUPPORTED 1 //TODO: IDF-7565
|
||||||
#define SOC_WDT_SUPPORTED 1
|
#define SOC_WDT_SUPPORTED 1
|
||||||
@ -343,6 +343,19 @@
|
|||||||
/*--------------------------- RSA CAPS ---------------------------------------*/
|
/*--------------------------- RSA CAPS ---------------------------------------*/
|
||||||
#define SOC_RSA_MAX_BIT_LEN (4096)
|
#define SOC_RSA_MAX_BIT_LEN (4096)
|
||||||
|
|
||||||
|
/*-------------------------- SDMMC CAPS -----------------------------------------*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Card detect, write protect, interrupt use GPIO Matrix on all chips.
|
||||||
|
* Slot 0 clock/cmd/data pins use IOMUX
|
||||||
|
* Slot 1 clock/cmd/data pins use GPIO Matrix
|
||||||
|
*/
|
||||||
|
#define SOC_SDMMC_USE_IOMUX 1
|
||||||
|
#define SOC_SDMMC_USE_GPIO_MATRIX 1
|
||||||
|
#define SOC_SDMMC_NUM_SLOTS 2
|
||||||
|
/* Supported host clock delay phase number */
|
||||||
|
#define SOC_SDMMC_DELAY_PHASE_NUM 4
|
||||||
|
|
||||||
// TODO: IDF-5353 (Copy from esp32c3, need check)
|
// TODO: IDF-5353 (Copy from esp32c3, need check)
|
||||||
/*--------------------------- SHA CAPS ---------------------------------------*/
|
/*--------------------------- SHA CAPS ---------------------------------------*/
|
||||||
|
|
||||||
@ -367,15 +380,6 @@
|
|||||||
/*--------------------------- ECDSA CAPS ---------------------------------------*/
|
/*--------------------------- ECDSA CAPS ---------------------------------------*/
|
||||||
#define SOC_ECDSA_SUPPORT_EXPORT_PUBKEY (1)
|
#define SOC_ECDSA_SUPPORT_EXPORT_PUBKEY (1)
|
||||||
|
|
||||||
#ifdef SDMMC_DEFAULT_IOMUX
|
|
||||||
#define SOC_SDMMC_USE_IOMUX 1
|
|
||||||
#else
|
|
||||||
#define SOC_SDMMC_USE_GPIO_MATRIX 1
|
|
||||||
#endif
|
|
||||||
#define SOC_SDMMC_NUM_SLOTS 2
|
|
||||||
#define SOC_SDMMC_IOMUX_FUNC 0
|
|
||||||
#define SOC_SDMMC_DMA_NEED_CACHE_WB 1
|
|
||||||
|
|
||||||
/*-------------------------- Sigma Delta Modulator CAPS -----------------*/
|
/*-------------------------- Sigma Delta Modulator CAPS -----------------*/
|
||||||
#define SOC_SDM_GROUPS 1U
|
#define SOC_SDM_GROUPS 1U
|
||||||
#define SOC_SDM_CHANNELS_PER_GROUP 4
|
#define SOC_SDM_CHANNELS_PER_GROUP 4
|
||||||
|
@ -5,15 +5,71 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "soc/sdmmc_periph.h"
|
#include "soc/sdmmc_periph.h"
|
||||||
// ESP32P4-TODO: need new iomux and sig map
|
|
||||||
const sdmmc_slot_info_t sdmmc_slot_info[SOC_SDMMC_NUM_SLOTS] = {
|
const sdmmc_slot_info_t sdmmc_slot_info[SOC_SDMMC_NUM_SLOTS] = {
|
||||||
|
{
|
||||||
|
.width = 8,
|
||||||
|
.card_detect = SD_CARD_DETECT_N_1_PAD_IN_IDX,
|
||||||
|
.write_protect = SD_CARD_WRITE_PRT_1_PAD_IN_IDX,
|
||||||
|
.card_int = SD_CARD_INT_N_1_PAD_IN_IDX,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.width = 8,
|
||||||
|
.card_detect = SD_CARD_DETECT_N_2_PAD_IN_IDX,
|
||||||
|
.write_protect = SD_CARD_WRITE_PRT_2_PAD_IN_IDX,
|
||||||
|
.card_int = SD_CARD_INT_N_2_PAD_IN_IDX,
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const sdmmc_slot_io_info_t sdmmc_slot_gpio_num[SOC_SDMMC_NUM_SLOTS] = {
|
const sdmmc_slot_io_info_t sdmmc_slot_gpio_num[SOC_SDMMC_NUM_SLOTS] = {
|
||||||
|
{
|
||||||
|
.clk = SDMMC_SLOT0_IOMUX_PIN_NUM_CLK,
|
||||||
|
.cmd = SDMMC_SLOT0_IOMUX_PIN_NUM_CMD,
|
||||||
|
.d0 = SDMMC_SLOT0_IOMUX_PIN_NUM_D0,
|
||||||
|
.d1 = SDMMC_SLOT0_IOMUX_PIN_NUM_D1,
|
||||||
|
.d2 = SDMMC_SLOT0_IOMUX_PIN_NUM_D2,
|
||||||
|
.d3 = SDMMC_SLOT0_IOMUX_PIN_NUM_D3,
|
||||||
|
.d4 = SDMMC_SLOT0_IOMUX_PIN_NUM_D4,
|
||||||
|
.d5 = SDMMC_SLOT0_IOMUX_PIN_NUM_D5,
|
||||||
|
.d6 = SDMMC_SLOT0_IOMUX_PIN_NUM_D6,
|
||||||
|
.d7 = SDMMC_SLOT0_IOMUX_PIN_NUM_D7,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.clk = -1,
|
||||||
|
.cmd = -1,
|
||||||
|
.d0 = -1,
|
||||||
|
.d1 = -1,
|
||||||
|
.d2 = -1,
|
||||||
|
.d3 = -1,
|
||||||
|
.d4 = -1,
|
||||||
|
.d5 = -1,
|
||||||
|
.d6 = -1,
|
||||||
|
.d7 = -1,
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const sdmmc_slot_io_info_t sdmmc_slot_gpio_sig[SOC_SDMMC_NUM_SLOTS] = {
|
const sdmmc_slot_io_info_t sdmmc_slot_gpio_sig[SOC_SDMMC_NUM_SLOTS] = {
|
||||||
|
{
|
||||||
|
.clk = -1,
|
||||||
|
.cmd = -1,
|
||||||
|
.d0 = -1,
|
||||||
|
.d1 = -1,
|
||||||
|
.d2 = -1,
|
||||||
|
.d3 = -1,
|
||||||
|
.d4 = -1,
|
||||||
|
.d5 = -1,
|
||||||
|
.d6 = -1,
|
||||||
|
.d7 = -1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.clk = SD_CARD_CCLK_2_PAD_OUT_IDX,
|
||||||
|
.cmd = SD_CARD_CCMD_2_PAD_OUT_IDX,
|
||||||
|
.d0 = SD_CARD_CDATA0_2_PAD_OUT_IDX,
|
||||||
|
.d1 = SD_CARD_CDATA1_2_PAD_OUT_IDX,
|
||||||
|
.d2 = SD_CARD_CDATA2_2_PAD_OUT_IDX,
|
||||||
|
.d3 = SD_CARD_CDATA3_2_PAD_OUT_IDX,
|
||||||
|
.d4 = SD_CARD_CDATA4_2_PAD_OUT_IDX,
|
||||||
|
.d5 = SD_CARD_CDATA5_2_PAD_OUT_IDX,
|
||||||
|
.d6 = SD_CARD_CDATA6_2_PAD_OUT_IDX,
|
||||||
|
.d7 = SD_CARD_CDATA7_2_PAD_OUT_IDX,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
|
* SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*/
|
*/
|
||||||
@ -284,7 +284,52 @@ typedef volatile struct sdmmc_dev_s {
|
|||||||
|
|
||||||
uint32_t usrid; ///< user ID
|
uint32_t usrid; ///< user ID
|
||||||
uint32_t verid; ///< IP block version
|
uint32_t verid; ///< IP block version
|
||||||
uint32_t hcon; ///< compile-time IP configuration
|
|
||||||
|
union {
|
||||||
|
struct {
|
||||||
|
/** card_type_reg : RO; bitpos: [0]; default: 1;
|
||||||
|
* Hardware support SDIO and MMC.
|
||||||
|
*/
|
||||||
|
uint32_t card_type_reg:1;
|
||||||
|
/** card_num_reg : RO; bitpos: [5:1]; default: 1;
|
||||||
|
* Support card number is 2.
|
||||||
|
*/
|
||||||
|
uint32_t card_num_reg:5;
|
||||||
|
/** bus_type_reg : RO; bitpos: [6]; default: 1;
|
||||||
|
* Register config is APB bus.
|
||||||
|
*/
|
||||||
|
uint32_t bus_type_reg:1;
|
||||||
|
/** data_width_reg : RO; bitpos: [9:7]; default: 1;
|
||||||
|
* Regisger data widht is 32.
|
||||||
|
*/
|
||||||
|
uint32_t data_width_reg:3;
|
||||||
|
/** addr_width_reg : RO; bitpos: [15:10]; default: 19;
|
||||||
|
* Register address width is 32.
|
||||||
|
*/
|
||||||
|
uint32_t addr_width_reg:6;
|
||||||
|
uint32_t reserved_16:2;
|
||||||
|
/** dma_width_reg : RO; bitpos: [20:18]; default: 1;
|
||||||
|
* DMA data witdth is 32.
|
||||||
|
*/
|
||||||
|
uint32_t dma_width_reg:3;
|
||||||
|
/** ram_indise_reg : RO; bitpos: [21]; default: 0;
|
||||||
|
* Inside RAM in SDMMC module.
|
||||||
|
*/
|
||||||
|
uint32_t ram_indise_reg:1;
|
||||||
|
/** hold_reg : RO; bitpos: [22]; default: 1;
|
||||||
|
* Have a hold regiser in data path .
|
||||||
|
*/
|
||||||
|
uint32_t hold_reg:1;
|
||||||
|
uint32_t reserved_23:1;
|
||||||
|
/** num_clk_div_reg : RO; bitpos: [25:24]; default: 3;
|
||||||
|
* Have 4 clk divider in design .
|
||||||
|
*/
|
||||||
|
uint32_t num_clk_div_reg:2;
|
||||||
|
uint32_t reserved_26:6;
|
||||||
|
};
|
||||||
|
uint32_t val;
|
||||||
|
} hcon;
|
||||||
|
|
||||||
union {
|
union {
|
||||||
struct {
|
struct {
|
||||||
uint32_t voltage: 16; ///< voltage control for slots; no-op on ESP32.
|
uint32_t voltage: 16; ///< voltage control for slots; no-op on ESP32.
|
||||||
|
@ -1,16 +1,8 @@
|
|||||||
// Copyright 2015-2020 Espressif Systems (Shanghai) PTE LTD
|
/*
|
||||||
//
|
* SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
*
|
||||||
// you may not use this file except in compliance with the License.
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
// You may obtain a copy of the License at
|
*/
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
#include "soc/sdmmc_periph.h"
|
#include "soc/sdmmc_periph.h"
|
||||||
|
|
||||||
@ -29,6 +21,33 @@ const sdmmc_slot_info_t sdmmc_slot_info[SOC_SDMMC_NUM_SLOTS] = {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const sdmmc_slot_io_info_t sdmmc_slot_gpio_num[SOC_SDMMC_NUM_SLOTS] = {
|
||||||
|
{
|
||||||
|
.clk = -1,
|
||||||
|
.cmd = -1,
|
||||||
|
.d0 = -1,
|
||||||
|
.d1 = -1,
|
||||||
|
.d2 = -1,
|
||||||
|
.d3 = -1,
|
||||||
|
.d4 = -1,
|
||||||
|
.d5 = -1,
|
||||||
|
.d6 = -1,
|
||||||
|
.d7 = -1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.clk = -1,
|
||||||
|
.cmd = -1,
|
||||||
|
.d0 = -1,
|
||||||
|
.d1 = -1,
|
||||||
|
.d2 = -1,
|
||||||
|
.d3 = -1,
|
||||||
|
.d4 = -1,
|
||||||
|
.d5 = -1,
|
||||||
|
.d6 = -1,
|
||||||
|
.d7 = -1,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const sdmmc_slot_io_info_t sdmmc_slot_gpio_sig[SOC_SDMMC_NUM_SLOTS] = {
|
const sdmmc_slot_io_info_t sdmmc_slot_gpio_sig[SOC_SDMMC_NUM_SLOTS] = {
|
||||||
{
|
{
|
||||||
.clk = SDHOST_CCLK_OUT_1_IDX,
|
.clk = SDHOST_CCLK_OUT_1_IDX,
|
||||||
|
@ -52,19 +52,12 @@ typedef struct {
|
|||||||
uint8_t d7;
|
uint8_t d7;
|
||||||
} sdmmc_slot_io_info_t;
|
} sdmmc_slot_io_info_t;
|
||||||
|
|
||||||
/* Note: it is in theory possible to have both IOMUX and GPIO Matrix supported
|
|
||||||
* in the same SoC. However this is not used on any SoC at this point, and would
|
|
||||||
* complicate the driver. Hence only one of these options is supported at a time.
|
|
||||||
*/
|
|
||||||
#if SOC_SDMMC_USE_IOMUX
|
|
||||||
/** GPIO pin numbers of SD bus signals, one structure per slot */
|
/** GPIO pin numbers of SD bus signals, one structure per slot */
|
||||||
extern const sdmmc_slot_io_info_t sdmmc_slot_gpio_num[SOC_SDMMC_NUM_SLOTS];
|
extern const sdmmc_slot_io_info_t sdmmc_slot_gpio_num[SOC_SDMMC_NUM_SLOTS];
|
||||||
|
|
||||||
#elif SOC_SDMMC_USE_GPIO_MATRIX
|
|
||||||
/** GPIO matrix signal numbers of SD bus signals, one structure per slot */
|
/** GPIO matrix signal numbers of SD bus signals, one structure per slot */
|
||||||
extern const sdmmc_slot_io_info_t sdmmc_slot_gpio_sig[SOC_SDMMC_NUM_SLOTS];
|
extern const sdmmc_slot_io_info_t sdmmc_slot_gpio_sig[SOC_SDMMC_NUM_SLOTS];
|
||||||
|
|
||||||
#endif // SOC_SDMMC_USE_{IOMUX,GPIO_MATRIX}
|
|
||||||
#endif // SOC_SDMMC_HOST_SUPPORTED
|
#endif // SOC_SDMMC_HOST_SUPPORTED
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
@ -179,7 +179,8 @@ ESP32C6_DOCS = ['api-guides/RF_calibration.rst',
|
|||||||
|
|
||||||
ESP32H2_DOCS = ['api-guides/RF_calibration.rst']
|
ESP32H2_DOCS = ['api-guides/RF_calibration.rst']
|
||||||
|
|
||||||
ESP32P4_DOCS = ['api-reference/system/ipc.rst']
|
ESP32P4_DOCS = ['api-reference/system/ipc.rst',
|
||||||
|
'api-reference/peripherals/sd_pullup_requirements.rst']
|
||||||
|
|
||||||
# format: {tag needed to include: documents to included}, tags are parsed from sdkconfig and peripheral_caps.h headers
|
# format: {tag needed to include: documents to included}, tags are parsed from sdkconfig and peripheral_caps.h headers
|
||||||
conditional_include_dict = {'SOC_BT_SUPPORTED':BT_DOCS,
|
conditional_include_dict = {'SOC_BT_SUPPORTED':BT_DOCS,
|
||||||
|
@ -114,6 +114,7 @@ INPUT = \
|
|||||||
$(PROJECT_PATH)/components/driver/rmt/include/driver/rmt_types.h \
|
$(PROJECT_PATH)/components/driver/rmt/include/driver/rmt_types.h \
|
||||||
$(PROJECT_PATH)/components/driver/sdio_slave/include/driver/sdio_slave.h \
|
$(PROJECT_PATH)/components/driver/sdio_slave/include/driver/sdio_slave.h \
|
||||||
$(PROJECT_PATH)/components/driver/sigma_delta/include/driver/sdm.h \
|
$(PROJECT_PATH)/components/driver/sigma_delta/include/driver/sdm.h \
|
||||||
|
$(PROJECT_PATH)/components/driver/sdmmc/include/driver/sdmmc_default_configs.h \
|
||||||
$(PROJECT_PATH)/components/driver/sdmmc/include/driver/sdmmc_host.h \
|
$(PROJECT_PATH)/components/driver/sdmmc/include/driver/sdmmc_host.h \
|
||||||
$(PROJECT_PATH)/components/driver/sdmmc/include/driver/sdmmc_types.h \
|
$(PROJECT_PATH)/components/driver/sdmmc/include/driver/sdmmc_types.h \
|
||||||
$(PROJECT_PATH)/components/driver/spi/include/driver/sdspi_host.h \
|
$(PROJECT_PATH)/components/driver/spi/include/driver/sdspi_host.h \
|
||||||
|
@ -26,9 +26,7 @@ Peripherals API
|
|||||||
:SOC_PARLIO_SUPPORTED: parlio
|
:SOC_PARLIO_SUPPORTED: parlio
|
||||||
:SOC_PCNT_SUPPORTED: pcnt
|
:SOC_PCNT_SUPPORTED: pcnt
|
||||||
:SOC_RMT_SUPPORTED: rmt
|
:SOC_RMT_SUPPORTED: rmt
|
||||||
:esp32: sd_pullup_requirements
|
:SOC_SDMMC_HOST_SUPPORTED or SOC_SDIO_SLAVE_SUPPORTED: sd_pullup_requirements
|
||||||
:esp32s3: sd_pullup_requirements
|
|
||||||
:esp32c6: sd_pullup_requirements
|
|
||||||
:SOC_SDMMC_HOST_SUPPORTED: sdmmc_host
|
:SOC_SDMMC_HOST_SUPPORTED: sdmmc_host
|
||||||
sdspi_host
|
sdspi_host
|
||||||
:SOC_SDIO_SLAVE_SUPPORTED: sdio_slave
|
:SOC_SDIO_SLAVE_SUPPORTED: sdio_slave
|
||||||
|
@ -28,6 +28,25 @@ For functions used to initialize and configure:
|
|||||||
|
|
||||||
The protocol layer works with the host via the :cpp:class:`sdmmc_host_t` structure. This structure contains pointers to various functions of the host.
|
The protocol layer works with the host via the :cpp:class:`sdmmc_host_t` structure. This structure contains pointers to various functions of the host.
|
||||||
|
|
||||||
|
Pin Configurations
|
||||||
|
------------------
|
||||||
|
|
||||||
|
..only:: SOC_SDMMC_USE_IOMUX and not SOC_SDMMC_USE_GPIO_MATRIX
|
||||||
|
|
||||||
|
SDMMC pins are dedicated, you don't have to configure the pins.
|
||||||
|
|
||||||
|
..only:: SOC_SDMMC_USE_GPIO_MATRIX and not SOC_SDMMC_USE_IOMUX
|
||||||
|
|
||||||
|
SDMMC pin signals are routed via GPIO Matrix, so you will need to configure the pins in :cpp:type:`sdmmc_slot_config_t`.
|
||||||
|
|
||||||
|
..only:: esp32p4
|
||||||
|
|
||||||
|
SDMMC have two slots:
|
||||||
|
|
||||||
|
.. list::
|
||||||
|
|
||||||
|
- slot 0 pins are dedicated for UHS-I mode. This is not yet supported in the driver.
|
||||||
|
- slot 1 pins are routed via GPIO Matrix, and it's for non UHS-I usage. You will need to configure the pins in :cpp:type:`sdmmc_slot_config_t` to use the slot 1.
|
||||||
|
|
||||||
Application Example
|
Application Example
|
||||||
-------------------
|
-------------------
|
||||||
|
@ -26,9 +26,7 @@
|
|||||||
:SOC_PARLIO_SUPPORTED: parlio
|
:SOC_PARLIO_SUPPORTED: parlio
|
||||||
:SOC_PCNT_SUPPORTED: pcnt
|
:SOC_PCNT_SUPPORTED: pcnt
|
||||||
:SOC_RMT_SUPPORTED: rmt
|
:SOC_RMT_SUPPORTED: rmt
|
||||||
:esp32: sd_pullup_requirements
|
:SOC_SDMMC_HOST_SUPPORTED or SOC_SDIO_SLAVE_SUPPORTED: sd_pullup_requirements
|
||||||
:esp32s3: sd_pullup_requirements
|
|
||||||
:esp32c6: sd_pullup_requirements
|
|
||||||
:SOC_SDMMC_HOST_SUPPORTED: sdmmc_host
|
:SOC_SDMMC_HOST_SUPPORTED: sdmmc_host
|
||||||
sdspi_host
|
sdspi_host
|
||||||
:SOC_SDIO_SLAVE_SUPPORTED: sdio_slave
|
:SOC_SDIO_SLAVE_SUPPORTED: sdio_slave
|
||||||
|
@ -215,6 +215,10 @@ examples/peripherals/rmt/stepper_motor:
|
|||||||
- if: SOC_RMT_SUPPORT_TX_LOOP_AUTO_STOP != 1
|
- if: SOC_RMT_SUPPORT_TX_LOOP_AUTO_STOP != 1
|
||||||
|
|
||||||
examples/peripherals/sdio/host:
|
examples/peripherals/sdio/host:
|
||||||
|
disable:
|
||||||
|
- if: IDF_TARGET == "esp32p4"
|
||||||
|
temporary: true
|
||||||
|
reason: request p4 essl spi to be ready for build, TODO IDF-8357
|
||||||
enable:
|
enable:
|
||||||
- if: SOC_SDMMC_HOST_SUPPORTED == 1
|
- if: SOC_SDMMC_HOST_SUPPORTED == 1
|
||||||
- if: IDF_TARGET == "esp32"
|
- if: IDF_TARGET == "esp32"
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
| Supported Targets | ESP32 | ESP32-S3 |
|
| Supported Targets | ESP32 | ESP32-P4 | ESP32-S3 |
|
||||||
| ----------------- | ----- | -------- |
|
| ----------------- | ----- | -------- | -------- |
|
||||||
|
|
||||||
# SD Card example (SDMMC)
|
# SD Card example (SDMMC)
|
||||||
|
|
||||||
@ -48,7 +48,7 @@ GPIO13 (MTCK) | D3 | not used in 1-line SD mode, but card's D3 pin must
|
|||||||
On ESP32-S3, SDMMC peripheral is connected to GPIO pins using GPIO matrix. This allows arbitrary GPIOs to be used to connect an SD card. In this example, GPIOs can be configured in two ways:
|
On ESP32-S3, SDMMC peripheral is connected to GPIO pins using GPIO matrix. This allows arbitrary GPIOs to be used to connect an SD card. In this example, GPIOs can be configured in two ways:
|
||||||
|
|
||||||
1. Using menuconfig: Run `idf.py menuconfig` in the project directory and open "SD/MMC Example Configuration" menu.
|
1. Using menuconfig: Run `idf.py menuconfig` in the project directory and open "SD/MMC Example Configuration" menu.
|
||||||
2. In the source code: See the initialization of ``sdmmc_slot_config_t slot_config`` structure in the example code.
|
2. In the source code: See the initialization of `sdmmc_slot_config_t slot_config` structure in the example code.
|
||||||
|
|
||||||
The table below lists the default pin assignments.
|
The table below lists the default pin assignments.
|
||||||
|
|
||||||
@ -63,6 +63,24 @@ GPIO38 | D1 | not used in 1-line SD mode; 10k pullup in 4-line m
|
|||||||
GPIO33 | D2 | not used in 1-line SD mode; 10k pullup in 4-line mode
|
GPIO33 | D2 | not used in 1-line SD mode; 10k pullup in 4-line mode
|
||||||
GPIO34 | D3 | not used in 1-line SD mode, but card's D3 pin must have a 10k pullup
|
GPIO34 | D3 | not used in 1-line SD mode, but card's D3 pin must have a 10k pullup
|
||||||
|
|
||||||
|
### Pin assignments for ESP32-P4
|
||||||
|
|
||||||
|
On ESP32-P4, Slot 1 of the SDMMC peripheral is connected to GPIO pins using GPIO matrix. This allows arbitrary GPIOs to be used to connect an SD card. In this example, GPIOs can be configured in two ways:
|
||||||
|
|
||||||
|
1. Using menuconfig: Run `idf.py menuconfig` in the project directory and open "SD/MMC Example Configuration" menu.
|
||||||
|
2. In the source code: See the initialization of `sdmmc_slot_config_t slot_config` structure in the example code.
|
||||||
|
|
||||||
|
The table below lists the default pin assignments.
|
||||||
|
|
||||||
|
ESP32-P4 pin | SD card pin | Notes
|
||||||
|
--------------|-------------|------------
|
||||||
|
GPIO43 | CLK | 10k pullup
|
||||||
|
GPIO44 | CMD | 10k pullup
|
||||||
|
GPIO39 | D0 | 10k pullup
|
||||||
|
GPIO40 | D1 | not used in 1-line SD mode; 10k pullup in 4-line mode
|
||||||
|
GPIO41 | D2 | not used in 1-line SD mode; 10k pullup in 4-line mode
|
||||||
|
GPIO42 | D3 | not used in 1-line SD mode, but card's D3 pin must have a 10k pullup
|
||||||
|
|
||||||
### 4-line and 1-line SD modes
|
### 4-line and 1-line SD modes
|
||||||
|
|
||||||
By default, this example uses 4 line SD mode, utilizing 6 pins: CLK, CMD, D0 - D3. It is possible to use 1-line mode (CLK, CMD, D0) by changing "SD/MMC bus width" in the example configuration menu (see `CONFIG_EXAMPLE_SDMMC_BUS_WIDTH_1`).
|
By default, this example uses 4 line SD mode, utilizing 6 pins: CLK, CMD, D0 - D3. It is possible to use 1-line mode (CLK, CMD, D0) by changing "SD/MMC bus width" in the example configuration menu (see `CONFIG_EXAMPLE_SDMMC_BUS_WIDTH_1`).
|
||||||
|
@ -27,28 +27,34 @@ menu "SD/MMC Example Configuration"
|
|||||||
config EXAMPLE_PIN_CMD
|
config EXAMPLE_PIN_CMD
|
||||||
int "CMD GPIO number"
|
int "CMD GPIO number"
|
||||||
default 35 if IDF_TARGET_ESP32S3
|
default 35 if IDF_TARGET_ESP32S3
|
||||||
|
default 44 if IDF_TARGET_ESP32P4
|
||||||
|
|
||||||
config EXAMPLE_PIN_CLK
|
config EXAMPLE_PIN_CLK
|
||||||
int "CLK GPIO number"
|
int "CLK GPIO number"
|
||||||
default 36 if IDF_TARGET_ESP32S3
|
default 36 if IDF_TARGET_ESP32S3
|
||||||
|
default 43 if IDF_TARGET_ESP32P4
|
||||||
|
|
||||||
config EXAMPLE_PIN_D0
|
config EXAMPLE_PIN_D0
|
||||||
int "D0 GPIO number"
|
int "D0 GPIO number"
|
||||||
default 37 if IDF_TARGET_ESP32S3
|
default 37 if IDF_TARGET_ESP32S3
|
||||||
|
default 39 if IDF_TARGET_ESP32P4
|
||||||
|
|
||||||
if EXAMPLE_SDMMC_BUS_WIDTH_4
|
if EXAMPLE_SDMMC_BUS_WIDTH_4
|
||||||
|
|
||||||
config EXAMPLE_PIN_D1
|
config EXAMPLE_PIN_D1
|
||||||
int "D1 GPIO number"
|
int "D1 GPIO number"
|
||||||
default 38 if IDF_TARGET_ESP32S3
|
default 38 if IDF_TARGET_ESP32S3
|
||||||
|
default 40 if IDF_TARGET_ESP32P4
|
||||||
|
|
||||||
config EXAMPLE_PIN_D2
|
config EXAMPLE_PIN_D2
|
||||||
int "D2 GPIO number"
|
int "D2 GPIO number"
|
||||||
default 33 if IDF_TARGET_ESP32S3
|
default 33 if IDF_TARGET_ESP32S3
|
||||||
|
default 41 if IDF_TARGET_ESP32P4
|
||||||
|
|
||||||
config EXAMPLE_PIN_D3
|
config EXAMPLE_PIN_D3
|
||||||
int "D3 GPIO number"
|
int "D3 GPIO number"
|
||||||
default 34 if IDF_TARGET_ESP32S3
|
default 34 if IDF_TARGET_ESP32S3
|
||||||
|
default 42 if IDF_TARGET_ESP32P4
|
||||||
|
|
||||||
endif # EXAMPLE_SDMMC_BUS_WIDTH_4
|
endif # EXAMPLE_SDMMC_BUS_WIDTH_4
|
||||||
|
|
||||||
|
@ -655,7 +655,6 @@ components/soc/esp32/include/soc/uhci_reg.h
|
|||||||
components/soc/esp32/include/soc/uhci_struct.h
|
components/soc/esp32/include/soc/uhci_struct.h
|
||||||
components/soc/esp32/include/soc/wdev_reg.h
|
components/soc/esp32/include/soc/wdev_reg.h
|
||||||
components/soc/esp32/ledc_periph.c
|
components/soc/esp32/ledc_periph.c
|
||||||
components/soc/esp32/sdmmc_periph.c
|
|
||||||
components/soc/esp32/spi_periph.c
|
components/soc/esp32/spi_periph.c
|
||||||
components/soc/esp32/uart_periph.c
|
components/soc/esp32/uart_periph.c
|
||||||
components/soc/esp32c3/i2c_periph.c
|
components/soc/esp32c3/i2c_periph.c
|
||||||
@ -796,7 +795,6 @@ components/soc/esp32s3/include/soc/usb_wrap_reg.h
|
|||||||
components/soc/esp32s3/include/soc/usb_wrap_struct.h
|
components/soc/esp32s3/include/soc/usb_wrap_struct.h
|
||||||
components/soc/esp32s3/include/soc/wdev_reg.h
|
components/soc/esp32s3/include/soc/wdev_reg.h
|
||||||
components/soc/esp32s3/ledc_periph.c
|
components/soc/esp32s3/ledc_periph.c
|
||||||
components/soc/esp32s3/sdmmc_periph.c
|
|
||||||
components/soc/esp32s3/uart_periph.c
|
components/soc/esp32s3/uart_periph.c
|
||||||
components/soc/esp32s3/usb_periph.c
|
components/soc/esp32s3/usb_periph.c
|
||||||
components/soc/include/soc/dedic_gpio_periph.h
|
components/soc/include/soc/dedic_gpio_periph.h
|
||||||
|
Loading…
Reference in New Issue
Block a user