drivers/sdmmc_stm32: add eMMC support

The only difference is calling HAL_MMC_*() instead of HAL_SD_*() functions,
and removing the card detect logic.

Signed-off-by: Armin Brauns <armin.brauns@embedded-solutions.at>
This commit is contained in:
Armin Brauns 2024-03-05 14:58:28 +00:00 committed by Henrik Brix Andersen
parent 0d53af4aa1
commit 444018f133
2 changed files with 134 additions and 52 deletions

View file

@ -38,8 +38,10 @@ config SDMMC_STM32
bool "STM32 SDMMC driver"
default y
depends on DT_HAS_ST_STM32_SDMMC_ENABLED
select USE_STM32_HAL_SD
select USE_STM32_HAL_SD_EX if SOC_SERIES_STM32L4X
select USE_STM32_HAL_SD if !SDMMC_STM32_EMMC
select USE_STM32_HAL_SD_EX if !SDMMC_STM32_EMMC && SOC_SERIES_STM32L4X
select USE_STM32_HAL_MMC if SDMMC_STM32_EMMC
select USE_STM32_HAL_MMC_EX if SDMMC_STM32_EMMC && SOC_SERIES_STM32L4X
select USE_STM32_LL_SDMMC
select USE_STM32_HAL_DMA if (SOC_SERIES_STM32L4X || SOC_SERIES_STM32F7X || SOC_SERIES_STM32F4X)
select DMA if ($(DT_STM32_SDMMC_HAS_DMA) && SOC_SERIES_STM32F4X)
@ -58,6 +60,12 @@ config SDMMC_STM32_HWFC
Enable SDMMC Hardware Flow Control to avoid FIFO underrun (TX mode) and
overrun (RX mode) errors.
config SDMMC_STM32_EMMC
bool "STM32 SDMMC eMMC mode"
depends on SDMMC_STM32
help
Use eMMC instead of SDIO (SD card) protocol. These are similar, but not entirely the same.
config SDMMC_STM32_CLOCK_CHECK
bool "Runtime SDMMC 48MHz clock check"
depends on SDMMC_STM32

View file

@ -64,11 +64,19 @@ struct sdmmc_dma_stream {
};
#endif
#ifdef CONFIG_SDMMC_STM32_EMMC
typedef MMC_HandleTypeDef HandleTypeDef;
typedef HAL_MMC_CardInfoTypeDef CardInfoTypeDef;
#else
typedef SD_HandleTypeDef HandleTypeDef;
typedef HAL_SD_CardInfoTypeDef CardInfoTypeDef;
#endif
struct stm32_sdmmc_priv {
irq_config_func_t irq_config;
struct k_sem thread_lock;
struct k_sem sync;
SD_HandleTypeDef hsd;
HandleTypeDef hsd;
int status;
struct k_work work;
struct gpio_callback cd_cb;
@ -97,38 +105,32 @@ static void stm32_sdmmc_isr(const struct device *dev)
{
struct stm32_sdmmc_priv *priv = dev->data;
#ifdef CONFIG_SDMMC_STM32_EMMC
HAL_MMC_IRQHandler(&priv->hsd);
#else
HAL_SD_IRQHandler(&priv->hsd);
#endif
}
void HAL_SD_TxCpltCallback(SD_HandleTypeDef *hsd)
{
struct stm32_sdmmc_priv *priv =
CONTAINER_OF(hsd, struct stm32_sdmmc_priv, hsd);
#define DEFINE_HAL_CALLBACK(name) \
void name(HandleTypeDef *hsd) \
{ \
struct stm32_sdmmc_priv *priv = CONTAINER_OF(hsd, struct stm32_sdmmc_priv, hsd); \
\
priv->status = hsd->ErrorCode; \
\
k_sem_give(&priv->sync); \
}
priv->status = hsd->ErrorCode;
k_sem_give(&priv->sync);
}
void HAL_SD_RxCpltCallback(SD_HandleTypeDef *hsd)
{
struct stm32_sdmmc_priv *priv =
CONTAINER_OF(hsd, struct stm32_sdmmc_priv, hsd);
priv->status = hsd->ErrorCode;
k_sem_give(&priv->sync);
}
void HAL_SD_ErrorCallback(SD_HandleTypeDef *hsd)
{
struct stm32_sdmmc_priv *priv =
CONTAINER_OF(hsd, struct stm32_sdmmc_priv, hsd);
priv->status = hsd->ErrorCode;
k_sem_give(&priv->sync);
}
#ifdef CONFIG_SDMMC_STM32_EMMC
DEFINE_HAL_CALLBACK(HAL_MMC_TxCpltCallback);
DEFINE_HAL_CALLBACK(HAL_MMC_RxCpltCallback);
DEFINE_HAL_CALLBACK(HAL_MMC_ErrorCallback);
#else
DEFINE_HAL_CALLBACK(HAL_SD_TxCpltCallback);
DEFINE_HAL_CALLBACK(HAL_SD_RxCpltCallback);
DEFINE_HAL_CALLBACK(HAL_SD_ErrorCallback);
#endif
static int stm32_sdmmc_clock_enable(struct stm32_sdmmc_priv *priv)
{
@ -166,6 +168,7 @@ static int stm32_sdmmc_clock_enable(struct stm32_sdmmc_priv *priv)
return clock_control_on(clock, (clock_control_subsys_t)&priv->pclken[0]);
}
#if !defined(CONFIG_SDMMC_STM32_EMMC)
static int stm32_sdmmc_clock_disable(struct stm32_sdmmc_priv *priv)
{
const struct device *clock;
@ -175,6 +178,7 @@ static int stm32_sdmmc_clock_disable(struct stm32_sdmmc_priv *priv)
return clock_control_off(clock,
(clock_control_subsys_t)&priv->pclken);
}
#endif
#if STM32_SDMMC_USE_DMA
@ -289,7 +293,11 @@ static int stm32_sdmmc_access_init(struct disk_info *disk)
return err;
}
#ifdef CONFIG_SDMMC_STM32_EMMC
err = HAL_MMC_Init(&priv->hsd);
#else
err = HAL_SD_Init(&priv->hsd);
#endif
if (err != HAL_OK) {
LOG_ERR("failed to init stm32_sdmmc (ErrorCode 0x%X)", priv->hsd.ErrorCode);
return -EIO;
@ -303,11 +311,14 @@ static int stm32_sdmmc_access_init(struct disk_info *disk)
return 0;
}
#if !defined(CONFIG_SDMMC_STM32_EMMC)
static void stm32_sdmmc_access_deinit(struct stm32_sdmmc_priv *priv)
{
HAL_SD_DeInit(&priv->hsd);
stm32_sdmmc_clock_disable(priv);
}
#endif
static int stm32_sdmmc_access_status(struct disk_info *disk)
{
@ -317,6 +328,37 @@ static int stm32_sdmmc_access_status(struct disk_info *disk)
return priv->status;
}
static int stm32_sdmmc_is_card_in_transfer(HandleTypeDef *hsd)
{
#ifdef CONFIG_SDMMC_STM32_EMMC
return HAL_MMC_GetCardState(hsd) == HAL_MMC_CARD_TRANSFER;
#else
return HAL_SD_GetCardState(hsd) == HAL_SD_CARD_TRANSFER;
#endif
}
static int stm32_sdmmc_read_blocks(HandleTypeDef *hsd, uint8_t *data_buf,
uint32_t start_sector, uint32_t num_sector)
{
#if STM32_SDMMC_USE_DMA || IS_ENABLED(DT_PROP(DT_DRV_INST(0), idma))
#ifdef CONFIG_SDMMC_STM32_EMMC
return HAL_MMC_ReadBlocks_DMA(hsd, data_buf, start_sector, num_sector);
#else
return HAL_SD_ReadBlocks_DMA(hsd, data_buf, start_sector, num_sector);
#endif
#else
#ifdef CONFIG_SDMMC_STM32_EMMC
return HAL_MMC_ReadBlocks_IT(hsd, data_buf, start_sector, num_sector);
#else
return HAL_SD_ReadBlocks_IT(hsd, data_buf, start_sector, num_sector);
#endif
#endif
}
static int stm32_sdmmc_access_read(struct disk_info *disk, uint8_t *data_buf,
uint32_t start_sector, uint32_t num_sector)
{
@ -326,13 +368,7 @@ static int stm32_sdmmc_access_read(struct disk_info *disk, uint8_t *data_buf,
k_sem_take(&priv->thread_lock, K_FOREVER);
#if STM32_SDMMC_USE_DMA || IS_ENABLED(DT_PROP(DT_DRV_INST(0), idma))
err = HAL_SD_ReadBlocks_DMA(&priv->hsd, data_buf, start_sector,
num_sector);
#else
err = HAL_SD_ReadBlocks_IT(&priv->hsd, data_buf, start_sector,
num_sector);
#endif
err = stm32_sdmmc_read_blocks(&priv->hsd, data_buf, start_sector, num_sector);
if (err != HAL_OK) {
LOG_ERR("sd read block failed %d", err);
err = -EIO;
@ -347,7 +383,7 @@ static int stm32_sdmmc_access_read(struct disk_info *disk, uint8_t *data_buf,
goto end;
}
while (HAL_SD_GetCardState(&priv->hsd) != HAL_SD_CARD_TRANSFER) {
while (!stm32_sdmmc_is_card_in_transfer(&priv->hsd)) {
}
end:
@ -355,6 +391,29 @@ end:
return err;
}
static int stm32_sdmmc_write_blocks(HandleTypeDef *hsd,
uint8_t *data_buf,
uint32_t start_sector, uint32_t num_sector)
{
#if STM32_SDMMC_USE_DMA || IS_ENABLED(DT_PROP(DT_DRV_INST(0), idma))
#ifdef CONFIG_SDMMC_STM32_EMMC
return HAL_MMC_WriteBlocks_DMA(hsd, data_buf, start_sector, num_sector);
#else
return HAL_SD_WriteBlocks_DMA(hsd, data_buf, start_sector, num_sector);
#endif
#else
#ifdef CONFIG_SDMMC_STM32_EMMC
return HAL_MMC_WriteBlocks_IT(hsd, data_buf, start_sector, num_sector);
#else
return HAL_SD_WriteBlocks_IT(hsd, data_buf, start_sector, num_sector);
#endif
#endif
}
static int stm32_sdmmc_access_write(struct disk_info *disk,
const uint8_t *data_buf,
uint32_t start_sector, uint32_t num_sector)
@ -365,13 +424,7 @@ static int stm32_sdmmc_access_write(struct disk_info *disk,
k_sem_take(&priv->thread_lock, K_FOREVER);
#if STM32_SDMMC_USE_DMA || IS_ENABLED(DT_PROP(DT_DRV_INST(0), idma))
err = HAL_SD_WriteBlocks_DMA(&priv->hsd, (uint8_t *)data_buf, start_sector,
num_sector);
#else
err = HAL_SD_WriteBlocks_IT(&priv->hsd, (uint8_t *)data_buf, start_sector,
num_sector);
#endif
err = stm32_sdmmc_write_blocks(&priv->hsd, (uint8_t *)data_buf, start_sector, num_sector);
if (err != HAL_OK) {
LOG_ERR("sd write block failed %d", err);
err = -EIO;
@ -386,7 +439,7 @@ static int stm32_sdmmc_access_write(struct disk_info *disk,
goto end;
}
while (HAL_SD_GetCardState(&priv->hsd) != HAL_SD_CARD_TRANSFER) {
while (!stm32_sdmmc_is_card_in_transfer(&priv->hsd)) {
}
end:
@ -394,24 +447,33 @@ end:
return err;
}
static int stm32_sdmmc_get_card_info(HandleTypeDef *hsd, CardInfoTypeDef *info)
{
#ifdef CONFIG_SDMMC_STM32_EMMC
return HAL_MMC_GetCardInfo(hsd, info);
#else
return HAL_SD_GetCardInfo(hsd, info);
#endif
}
static int stm32_sdmmc_access_ioctl(struct disk_info *disk, uint8_t cmd,
void *buff)
{
const struct device *dev = disk->dev;
struct stm32_sdmmc_priv *priv = dev->data;
HAL_SD_CardInfoTypeDef info;
CardInfoTypeDef info;
int err;
switch (cmd) {
case DISK_IOCTL_GET_SECTOR_COUNT:
err = HAL_SD_GetCardInfo(&priv->hsd, &info);
err = stm32_sdmmc_get_card_info(&priv->hsd, &info);
if (err != HAL_OK) {
return -EIO;
}
*(uint32_t *)buff = info.LogBlockNbr;
break;
case DISK_IOCTL_GET_SECTOR_SIZE:
err = HAL_SD_GetCardInfo(&priv->hsd, &info);
err = stm32_sdmmc_get_card_info(&priv->hsd, &info);
if (err != HAL_OK) {
return -EIO;
}
@ -442,6 +504,13 @@ static struct disk_info stm32_sdmmc_info = {
.ops = &stm32_sdmmc_ops,
};
#ifdef CONFIG_SDMMC_STM32_EMMC
static bool stm32_sdmmc_card_present(struct stm32_sdmmc_priv *priv)
{
return true;
}
#else /* CONFIG_SDMMC_STM32_EMMC */
/*
* Check if the card is present or not. If no card detect gpio is set, assume
* the card is present. If reading the gpio fails for some reason, assume the
@ -539,6 +608,7 @@ static int stm32_sdmmc_card_detect_uninit(struct stm32_sdmmc_priv *priv)
gpio_remove_callback(priv->cd.port, &priv->cd_cb);
return 0;
}
#endif /* !CONFIG_SDMMC_STM32_EMMC */
static int stm32_sdmmc_pwr_init(struct stm32_sdmmc_priv *priv)
{
@ -588,8 +658,6 @@ static int disk_stm32_sdmmc_init(const struct device *dev)
return -ENODEV;
}
k_work_init(&priv->work, stm32_sdmmc_cd_handler);
/* Configure dt provided device signals when available */
err = pinctrl_apply_state(priv->pcfg, PINCTRL_STATE_DEFAULT);
if (err < 0) {
@ -602,10 +670,14 @@ static int disk_stm32_sdmmc_init(const struct device *dev)
k_sem_init(&priv->thread_lock, 1, 1);
k_sem_init(&priv->sync, 0, 1);
#if !defined(CONFIG_SDMMC_STM32_EMMC)
k_work_init(&priv->work, stm32_sdmmc_cd_handler);
err = stm32_sdmmc_card_detect_init(priv);
if (err) {
return err;
}
#endif
err = stm32_sdmmc_pwr_init(priv);
if (err) {
@ -628,7 +700,9 @@ static int disk_stm32_sdmmc_init(const struct device *dev)
err_pwr:
stm32_sdmmc_pwr_uninit(priv);
err_card_detect:
#if !defined(CONFIG_SDMMC_STM32_EMMC)
stm32_sdmmc_card_detect_uninit(priv);
#endif
return err;
}