CI: https://source.denx.de/u-boot/custodians/u-boot-mmc/-/pipelines/25640

- Support Sandisk and Micron eMMC BOOT/RPMB hardware partition resizing
- Optimize eMMC erasing time
- Simplify poll CD logic
- Fix possible Synchronous Abort for sdhci
- Kconfig dependencies fix
- Minor code update, return fail if mmc_complete_init, avoid uniniting twice
This commit is contained in:
Tom Rini 2025-04-11 08:50:55 -06:00
commit 048266be42
7 changed files with 183 additions and 53 deletions

View File

@ -528,6 +528,7 @@ config SPL_MMC_SDHCI_ADMA
config MMC_SDHCI_ADMA_FORCE_32BIT
bool "Force 32 bit mode for ADMA on 64 bit platforms"
depends on MMC_SDHCI_ADMA || SPL_MMC_SDHCI_ADMA
help
This forces SDHCI ADMA to be built for 32 bit descriptors, even
on a 64 bit platform where they would otherwise be assumed to
@ -537,6 +538,7 @@ config MMC_SDHCI_ADMA_FORCE_32BIT
config MMC_SDHCI_ADMA_64BIT
bool "Use SHDCI ADMA with 64 bit descriptors"
depends on MMC_SDHCI_ADMA || SPL_MMC_SDHCI_ADMA
depends on !MMC_SDHCI_ADMA_FORCE_32BIT
default y if DMA_ADDR_T_64BIT
help

View File

@ -498,22 +498,12 @@ static int mmc_blk_probe(struct udevice *dev)
return ret;
}
ret = device_probe(dev);
if (ret) {
debug("Probing %s failed (err=%d)\n", dev->name, ret);
mmc_deinit(mmc);
return ret;
}
return 0;
}
static int mmc_blk_remove(struct udevice *dev)
static int mmc_remove(struct udevice *dev)
{
struct udevice *mmc_dev = dev_get_parent(dev);
struct mmc_uclass_priv *upriv = dev_get_uclass_priv(mmc_dev);
struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev);
struct mmc *mmc = upriv->mmc;
return mmc_deinit(mmc);
@ -533,7 +523,6 @@ U_BOOT_DRIVER(mmc_blk) = {
.id = UCLASS_BLK,
.ops = &mmc_blk_ops,
.probe = mmc_blk_probe,
.remove = mmc_blk_remove,
.flags = DM_FLAG_OS_PREPARE,
};
#endif /* CONFIG_BLK */
@ -543,4 +532,5 @@ UCLASS_DRIVER(mmc) = {
.name = "mmc",
.flags = DM_UC_FLAG_SEQ_ALIAS,
.per_device_auto = sizeof(struct mmc_uclass_priv),
.pre_remove = mmc_remove,
};

View File

@ -3040,9 +3040,9 @@ static int mmc_complete_init(struct mmc *mmc)
return err;
}
static void __maybe_unused mmc_cyclic_cd_poll(struct cyclic_info *c)
static void mmc_cyclic_cd_poll(struct cyclic_info *c)
{
struct mmc *m = CONFIG_IS_ENABLED(CYCLIC, (container_of(c, struct mmc, cyclic)), (NULL));
struct mmc *m = container_of(c, struct mmc, cyclic);
if (!m->has_init)
return;
@ -3073,15 +3073,15 @@ int mmc_init(struct mmc *mmc)
if (!err)
err = mmc_complete_init(mmc);
if (err)
if (err) {
pr_info("%s: %d, time %lu\n", __func__, err, get_timer(start));
return err;
}
if (CONFIG_IS_ENABLED(CYCLIC, (!mmc->cyclic.func), (NULL))) {
/* Register cyclic function for card detect polling */
CONFIG_IS_ENABLED(CYCLIC, (cyclic_register(&mmc->cyclic,
mmc_cyclic_cd_poll,
100 * 1000,
mmc->cfg->name)));
cyclic_register(&mmc->cyclic, mmc_cyclic_cd_poll, 100 * 1000,
mmc->cfg->name);
}
return err;
@ -3092,7 +3092,7 @@ int mmc_deinit(struct mmc *mmc)
u32 caps_filtered;
if (CONFIG_IS_ENABLED(CYCLIC, (mmc->cyclic.func), (NULL)))
CONFIG_IS_ENABLED(CYCLIC, (cyclic_unregister(&mmc->cyclic)));
cyclic_unregister(&mmc->cyclic);
if (!CONFIG_IS_ENABLED(MMC_UHS_SUPPORT) &&
!CONFIG_IS_ENABLED(MMC_HS200_SUPPORT) &&

View File

@ -8,20 +8,107 @@
#include <mmc.h>
#include "mmc_private.h"
/*
* This function changes the size of boot partition and the size of rpmb
* partition present on EMMC devices.
*
* Input Parameters:
* struct *mmc: pointer for the mmc device strcuture
* bootsize: size of boot partition
* rpmbsize: size of rpmb partition
*
* Returns 0 on success.
*/
static int mmc_resize_boot_micron(struct mmc *mmc, unsigned long bootsize,
unsigned long rpmbsize)
{
int err;
int mmc_boot_partition_size_change(struct mmc *mmc, unsigned long bootsize,
unsigned long rpmbsize)
/* Micron eMMC doesn't support resizing RPMB partition */
(void)rpmbsize;
/* BOOT partition size is multiple of 128KB */
bootsize = (bootsize * 1024) / 128;
if (bootsize > 0xff)
bootsize = 0xff;
/* Set EXT_CSD[175] ERASE_GROUP_DEF to 0x01 */
err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
EXT_CSD_ERASE_GROUP_DEF, 0x01);
if (err)
goto error;
/* Set EXT_CSD[127:125] for BOOT partition size, [125] is low byte */
err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
EXT_CSD_BOOT_SIZE_MULT_MICRON, bootsize);
if (err)
goto error;
err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
EXT_CSD_BOOT_SIZE_MULT_MICRON + 1, 0x00);
if (err)
goto error;
err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
EXT_CSD_BOOT_SIZE_MULT_MICRON + 2, 0x00);
if (err)
goto error;
/* Set EXT_CSD[155] PARTITION_SETTING_COMPLETE to 0x01 */
err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
EXT_CSD_PARTITION_SETTING, 0x01);
if (err)
goto error;
return 0;
error:
debug("%s: Error = %d\n", __func__, err);
return err;
}
static int mmc_resize_boot_sandisk(struct mmc *mmc, unsigned long bootsize,
unsigned long rpmbsize)
{
int err;
struct mmc_cmd cmd;
/* BOOT/RPMB partition size is multiple of 128KB */
bootsize = (bootsize * 1024) / 128;
rpmbsize = (rpmbsize * 1024) / 128;
if (bootsize > 0xff)
bootsize = 0xff;
if (rpmbsize > 0xff)
rpmbsize = 0xff;
/* Send BOOT/RPMB resize op code */
cmd.cmdidx = MMC_CMD_RES_MAN;
cmd.resp_type = MMC_RSP_R1b;
cmd.cmdarg = MMC_CMD62_ARG_SANDISK;
err = mmc_send_cmd(mmc, &cmd, NULL);
if (err)
goto error;
/* Arg: BOOT partition size */
cmd.cmdidx = MMC_CMD_RES_MAN;
cmd.resp_type = MMC_RSP_R1b;
cmd.cmdarg = bootsize;
err = mmc_send_cmd(mmc, &cmd, NULL);
if (err)
goto error;
/* Arg: RPMB partition size */
cmd.cmdidx = MMC_CMD_RES_MAN;
cmd.resp_type = MMC_RSP_R1b;
cmd.cmdarg = rpmbsize;
err = mmc_send_cmd(mmc, &cmd, NULL);
if (err)
goto error;
return 0;
error:
debug("%s: Error = %d\n", __func__, err);
return err;
}
static int mmc_resize_boot_samsung(struct mmc *mmc, unsigned long bootsize,
unsigned long rpmbsize)
{
int err;
struct mmc_cmd cmd;
@ -32,10 +119,8 @@ int mmc_boot_partition_size_change(struct mmc *mmc, unsigned long bootsize,
cmd.cmdarg = MMC_CMD62_ARG1;
err = mmc_send_cmd(mmc, &cmd, NULL);
if (err) {
debug("mmc_boot_partition_size_change: Error1 = %d\n", err);
return err;
}
if (err)
goto error;
/* Boot partition changing mode */
cmd.cmdidx = MMC_CMD_RES_MAN;
@ -43,10 +128,9 @@ int mmc_boot_partition_size_change(struct mmc *mmc, unsigned long bootsize,
cmd.cmdarg = MMC_CMD62_ARG2;
err = mmc_send_cmd(mmc, &cmd, NULL);
if (err) {
debug("mmc_boot_partition_size_change: Error2 = %d\n", err);
return err;
}
if (err)
goto error;
/* boot partition size is multiple of 128KB */
bootsize = (bootsize * 1024) / 128;
@ -56,10 +140,9 @@ int mmc_boot_partition_size_change(struct mmc *mmc, unsigned long bootsize,
cmd.cmdarg = bootsize;
err = mmc_send_cmd(mmc, &cmd, NULL);
if (err) {
debug("mmc_boot_partition_size_change: Error3 = %d\n", err);
return err;
}
if (err)
goto error;
/* RPMB partition size is multiple of 128KB */
rpmbsize = (rpmbsize * 1024) / 128;
/* Arg: RPMB partition size */
@ -68,11 +151,43 @@ int mmc_boot_partition_size_change(struct mmc *mmc, unsigned long bootsize,
cmd.cmdarg = rpmbsize;
err = mmc_send_cmd(mmc, &cmd, NULL);
if (err) {
debug("mmc_boot_partition_size_change: Error4 = %d\n", err);
return err;
}
if (err)
goto error;
return 0;
error:
debug("%s: Error = %d\n", __func__, err);
return err;
}
/*
* This function changes the size of BOOT partition and the size of RPMB
* partition present on eMMC devices.
*
* Input Parameters:
* struct *mmc: pointer for the mmc device strcuture
* bootsize: size of BOOT partition
* rpmbsize: size of RPMB partition
*
* Returns 0 on success.
*/
int mmc_boot_partition_size_change(struct mmc *mmc, unsigned long bootsize,
unsigned long rpmbsize)
{
switch (mmc->cid[0] >> 24) {
case CID_MANFID_MICRON:
return mmc_resize_boot_micron(mmc, bootsize, rpmbsize);
case CID_MANFID_SAMSUNG:
return mmc_resize_boot_samsung(mmc, bootsize, rpmbsize);
case CID_MANFID_SANDISK:
return mmc_resize_boot_sandisk(mmc, bootsize, rpmbsize);
default:
printf("Unsupported manufacturer id 0x%02x\n",
mmc->cid[0] >> 24);
return -EPERM;
}
}
/*

View File

@ -80,6 +80,8 @@ ulong mmc_berase(struct blk_desc *block_dev, lbaint_t start, lbaint_t blkcnt)
struct mmc *mmc = find_mmc_device(dev_num);
lbaint_t blk = 0, blk_r = 0;
int timeout_ms = 1000;
u32 grpcnt;
if (!mmc)
return -1;
@ -123,6 +125,15 @@ ulong mmc_berase(struct blk_desc *block_dev, lbaint_t start, lbaint_t blkcnt)
} else {
blk_r = ((blkcnt - blk) > mmc->erase_grp_size) ?
mmc->erase_grp_size : (blkcnt - blk);
grpcnt = (blkcnt - blk) / mmc->erase_grp_size;
/* Max 2GB per spec */
if ((blkcnt - blk) > 0x400000)
blk_r = 0x400000;
else if (grpcnt)
blk_r = grpcnt * mmc->erase_grp_size;
else
blk_r = blkcnt - blk;
}
err = mmc_erase_t(mmc, start + blk, blk_r, erase_args);
if (err)

View File

@ -177,8 +177,10 @@ static int sdhci_transfer_data(struct sdhci_host *host, struct mmc_data *data)
} while (!(stat & SDHCI_INT_DATA_END));
#if (CONFIG_IS_ENABLED(MMC_SDHCI_SDMA) || CONFIG_IS_ENABLED(MMC_SDHCI_ADMA))
dma_unmap_single(host->start_addr, data->blocks * data->blocksize,
mmc_get_dma_dir(data));
if (host->flags & USE_DMA) {
dma_unmap_single(host->start_addr, data->blocks * data->blocksize,
mmc_get_dma_dir(data));
}
#endif
return 0;

View File

@ -79,6 +79,10 @@ struct bd_info;
#define IS_SD(x) ((x)->version & SD_VERSION_SD)
#define IS_MMC(x) ((x)->version & MMC_VERSION_MMC)
#define CID_MANFID_MICRON 0x13
#define CID_MANFID_SAMSUNG 0x15
#define CID_MANFID_SANDISK 0x45
#define MMC_DATA_READ 1
#define MMC_DATA_WRITE 2
@ -112,6 +116,7 @@ struct bd_info;
#define MMC_CMD62_ARG1 0xefac62ec
#define MMC_CMD62_ARG2 0xcbaea7
#define MMC_CMD62_ARG_SANDISK 0x254ddec4
#define SD_CMD_SEND_RELATIVE_ADDR 3
#define SD_CMD_SWITCH_FUNC 6
@ -205,6 +210,7 @@ static inline bool mmc_is_tuning_cmd(uint cmdidx)
/*
* EXT_CSD fields
*/
#define EXT_CSD_BOOT_SIZE_MULT_MICRON 125 /* R/W, vendor specific field */
#define EXT_CSD_ENH_START_ADDR 136 /* R/W */
#define EXT_CSD_ENH_SIZE_MULT 140 /* R/W */
#define EXT_CSD_GP_SIZE_MULT 143 /* R/W */
@ -759,7 +765,11 @@ struct mmc {
enum bus_mode user_speed_mode; /* input speed mode from user */
CONFIG_IS_ENABLED(CYCLIC, (struct cyclic_info cyclic));
/*
* If CONFIG_CYCLIC is not set, struct cyclic_info is
* zero-size structure and does not add any space here.
*/
struct cyclic_info cyclic;
};
#if CONFIG_IS_ENABLED(DM_MMC)