From 9b8ebd3aec40b35c57973682e5c2df62279417c2 Mon Sep 17 00:00:00 2001 From: Oleksandr Suvorov Date: Wed, 23 Aug 2023 18:45:45 +0300 Subject: mmc: spl: select SPL_BLK for SPL_DM_MMC mmc_bind() in mmc-uclass.c calls blk_create_devicef() which is defined in blk-uclass.c, so SPL_BLK is required by SPL_DM_MMC. Implicitly select SPL_BLK for SPL_DM_MMC. Signed-off-by: Oleksandr Suvorov Reviewed-by: Tom Rini Reviewed-by: Jaehoon Chung --- drivers/mmc/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/mmc/Kconfig b/drivers/mmc/Kconfig index 726c8d8f705..17618c3bdcc 100644 --- a/drivers/mmc/Kconfig +++ b/drivers/mmc/Kconfig @@ -46,6 +46,7 @@ config SPL_DM_MMC depends on SPL_DM && DM_MMC default n if ARCH_MVEBU && !MVEBU_SPL_BOOT_DEVICE_MMC default y + select SPL_BLK help This enables the MultiMediaCard (MMC) uclass which supports MMC and Secure Digital I/O (SDIO) cards. Both removable (SD, micro-SD, etc.) -- cgit v1.3.1 From c27c8102e128827c684d8d3da7f0ce03d550b65a Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Wed, 11 Oct 2023 19:00:52 +0800 Subject: mmc: pci: Drop the superfluous cast dm_pci_map_bar() return a value of (void *) already, hence no need to cast it again before assigning to host->ioaddr. Signed-off-by: Bin Meng Reviewed-by: Simon Glass Reviewed-by: Jaehoon Chung --- drivers/mmc/pci_mmc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/mmc/pci_mmc.c b/drivers/mmc/pci_mmc.c index 9fb70440293..4d163ccba04 100644 --- a/drivers/mmc/pci_mmc.c +++ b/drivers/mmc/pci_mmc.c @@ -50,8 +50,8 @@ static int pci_mmc_probe(struct udevice *dev) desc = mmc_get_blk_desc(&plat->mmc); desc->removable = !(plat->cfg.host_caps & MMC_CAP_NONREMOVABLE); - host->ioaddr = (void *)dm_pci_map_bar(dev, PCI_BASE_ADDRESS_0, 0, 0, PCI_REGION_TYPE, - PCI_REGION_MEM); + host->ioaddr = dm_pci_map_bar(dev, PCI_BASE_ADDRESS_0, 0, 0, + PCI_REGION_TYPE, PCI_REGION_MEM); host->name = dev->name; host->cd_gpio = priv->cd_gpio; host->mmc = &plat->mmc; -- cgit v1.3.1 From 21c84bb1112695f9bd49379f7e32c251b55a3cad Mon Sep 17 00:00:00 2001 From: Sean Anderson Date: Fri, 27 Oct 2023 16:57:03 -0400 Subject: mmc: sdhci: Rework SDHCI_QUIRK_BROKEN_R1B As noted in commit 3a6383207be ("mmc: sdhci: add the quirk for broken r1b response"), some MMC controllers don't always set the transfer complete bit with R1b responses. According to the SD Host Controller Simplified Specification v4.20, > In the case of a command pairing with response-with-busy[, Transfer > Complete] is set when busy is de-asserted. Refer to DAT Line Active > and Command Inhibit (DAT) in the Present State register. By polling the DAT Line Active bit in the present state register, we can detect when we are no longer busy, without waiting for a long timeout. This results in much faster reads/writes on buggy controllers. Signed-off-by: Sean Anderson Tested-by: Henrik Grimler --- drivers/mmc/sdhci.c | 19 ++++++++++++------- include/sdhci.h | 1 + 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/drivers/mmc/sdhci.c b/drivers/mmc/sdhci.c index fc9c6c37996..0178ed8a11e 100644 --- a/drivers/mmc/sdhci.c +++ b/drivers/mmc/sdhci.c @@ -306,14 +306,19 @@ static int sdhci_send_command(struct mmc *mmc, struct mmc_cmd *cmd, if (stat & SDHCI_INT_ERROR) break; - if (get_timer(start) >= SDHCI_READ_STATUS_TIMEOUT) { - if (host->quirks & SDHCI_QUIRK_BROKEN_R1B) { + if (host->quirks & SDHCI_QUIRK_BROKEN_R1B && + cmd->resp_type & MMC_RSP_BUSY && !data) { + unsigned int state = + sdhci_readl(host, SDHCI_PRESENT_STATE); + + if (!(state & SDHCI_DAT_ACTIVE)) return 0; - } else { - printf("%s: Timeout for status update!\n", - __func__); - return -ETIMEDOUT; - } + } + + if (get_timer(start) >= SDHCI_READ_STATUS_TIMEOUT) { + printf("%s: Timeout for status update: %08x %08x\n", + __func__, stat, mask); + return -ETIMEDOUT; } } while ((stat & mask) != mask); diff --git a/include/sdhci.h b/include/sdhci.h index 70fefca2a97..a1b74e3bd79 100644 --- a/include/sdhci.h +++ b/include/sdhci.h @@ -57,6 +57,7 @@ #define SDHCI_PRESENT_STATE 0x24 #define SDHCI_CMD_INHIBIT BIT(0) #define SDHCI_DATA_INHIBIT BIT(1) +#define SDHCI_DAT_ACTIVE BIT(2) #define SDHCI_DOING_WRITE BIT(8) #define SDHCI_DOING_READ BIT(9) #define SDHCI_SPACE_AVAILABLE BIT(10) -- cgit v1.3.1 From b5f403936d037e0bc08e78b8af64adf53da13b90 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Tue, 31 Oct 2023 13:20:17 +0100 Subject: cmd: mmc: Add mmc reg read command for reading card registers Add extension to the 'mmc' command to read out the card registers. Currently, only the eMMC OCR/CID/CSD/EXTCSD/RCA/DSR register are supported. A register value can either be displayed or read into an environment variable. Tested-by: Jaehoon Chung Reviewed-by: Jaehoon Chung Signed-off-by: Marek Vasut Reviewed-by: Fabio Estevam --- cmd/Kconfig | 7 ++++ cmd/mmc.c | 96 +++++++++++++++++++++++++++++++++++++++++++++++++++ doc/usage/cmd/mmc.rst | 26 ++++++++++++++ 3 files changed, 129 insertions(+) diff --git a/cmd/Kconfig b/cmd/Kconfig index 60aed2c307c..fd16c3a48e5 100644 --- a/cmd/Kconfig +++ b/cmd/Kconfig @@ -1313,6 +1313,13 @@ config CMD_BKOPS_ENABLE on a eMMC device. The feature is optionally available on eMMC devices conforming to standard >= 4.41. +config CMD_MMC_REG + bool "Enable support for reading card registers in the mmc command" + depends on CMD_MMC + help + Enable the commands for reading card registers. This is useful + mostly for debugging or extracting details from the card. + config CMD_MMC_RPMB bool "Enable support for RPMB in the mmc command" depends on SUPPORT_EMMC_RPMB diff --git a/cmd/mmc.c b/cmd/mmc.c index c6bd81cebbc..96befb27eec 100644 --- a/cmd/mmc.c +++ b/cmd/mmc.c @@ -1110,6 +1110,93 @@ static int do_mmc_boot_wp(struct cmd_tbl *cmdtp, int flag, return CMD_RET_SUCCESS; } +#if CONFIG_IS_ENABLED(CMD_MMC_REG) +static int do_mmc_reg(struct cmd_tbl *cmdtp, int flag, + int argc, char *const argv[]) +{ + ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN); + struct mmc *mmc; + int i, ret; + u32 off; + + if (argc < 3 || argc > 5) + return CMD_RET_USAGE; + + mmc = find_mmc_device(curr_device); + if (!mmc) { + printf("no mmc device at slot %x\n", curr_device); + return CMD_RET_FAILURE; + } + + if (IS_SD(mmc)) { + printf("SD registers are not supported\n"); + return CMD_RET_FAILURE; + } + + off = simple_strtoul(argv[3], NULL, 10); + if (!strcmp(argv[2], "cid")) { + if (off > 3) + return CMD_RET_USAGE; + printf("CID[%i]: 0x%08x\n", off, mmc->cid[off]); + if (argv[4]) + env_set_hex(argv[4], mmc->cid[off]); + return CMD_RET_SUCCESS; + } + if (!strcmp(argv[2], "csd")) { + if (off > 3) + return CMD_RET_USAGE; + printf("CSD[%i]: 0x%08x\n", off, mmc->csd[off]); + if (argv[4]) + env_set_hex(argv[4], mmc->csd[off]); + return CMD_RET_SUCCESS; + } + if (!strcmp(argv[2], "dsr")) { + printf("DSR: 0x%08x\n", mmc->dsr); + if (argv[4]) + env_set_hex(argv[4], mmc->dsr); + return CMD_RET_SUCCESS; + } + if (!strcmp(argv[2], "ocr")) { + printf("OCR: 0x%08x\n", mmc->ocr); + if (argv[4]) + env_set_hex(argv[4], mmc->ocr); + return CMD_RET_SUCCESS; + } + if (!strcmp(argv[2], "rca")) { + printf("RCA: 0x%08x\n", mmc->rca); + if (argv[4]) + env_set_hex(argv[4], mmc->rca); + return CMD_RET_SUCCESS; + } + if (!strcmp(argv[2], "extcsd") && + mmc->version >= MMC_VERSION_4_41) { + ret = mmc_send_ext_csd(mmc, ext_csd); + if (ret) + return CMD_RET_FAILURE; + if (!strcmp(argv[3], "all")) { + /* Dump the entire register */ + printf("EXT_CSD:"); + for (i = 0; i < MMC_MAX_BLOCK_LEN; i++) { + if (!(i % 10)) + printf("\n%03i: ", i); + printf(" %02x", ext_csd[i]); + } + printf("\n"); + return CMD_RET_SUCCESS; + } + off = simple_strtoul(argv[3], NULL, 10); + if (off > 512) + return CMD_RET_USAGE; + printf("EXT_CSD[%i]: 0x%02x\n", off, ext_csd[off]); + if (argv[4]) + env_set_hex(argv[4], ext_csd[off]); + return CMD_RET_SUCCESS; + } + + return CMD_RET_FAILURE; +} +#endif + static struct cmd_tbl cmd_mmc[] = { U_BOOT_CMD_MKENT(info, 1, 0, do_mmcinfo, "", ""), U_BOOT_CMD_MKENT(read, 4, 1, do_mmc_read, "", ""), @@ -1142,6 +1229,9 @@ static struct cmd_tbl cmd_mmc[] = { U_BOOT_CMD_MKENT(bkops-enable, 2, 0, do_mmc_bkops_enable, "", ""), U_BOOT_CMD_MKENT(bkops, 4, 0, do_mmc_bkops, "", ""), #endif +#if CONFIG_IS_ENABLED(CMD_MMC_REG) + U_BOOT_CMD_MKENT(reg, 5, 0, do_mmc_reg, "", ""), +#endif }; static int do_mmcops(struct cmd_tbl *cmdtp, int flag, int argc, @@ -1229,6 +1319,12 @@ U_BOOT_CMD( " WARNING: This is a write-once setting.\n" "mmc bkops [auto|manual] [enable|disable]\n" " - configure background operations handshake on device\n" +#endif +#if CONFIG_IS_ENABLED(CMD_MMC_REG) + "mmc reg read [env] - read card register offset \n" + " (optionally into [env] variable)\n" + " - reg: cid/csd/dsr/ocr/rca/extcsd\n" + " - offset: for cid/csd [0..3], for extcsd [0..511,all]\n" #endif ); diff --git a/doc/usage/cmd/mmc.rst b/doc/usage/cmd/mmc.rst index 71a0303109c..c0924ba5769 100644 --- a/doc/usage/cmd/mmc.rst +++ b/doc/usage/cmd/mmc.rst @@ -21,6 +21,7 @@ Synopsis mmc bootpart-resize mmc partconf [[varname] | [ ]] mmc rst-function + mmc reg read [env] Description ----------- @@ -183,6 +184,31 @@ The 'mmc rst-function' command changes the RST_n_FUNCTION field. 0x3 Reserved +The 'mmc reg read [env]' reads eMMC card register and +either print it to standard output, or store the value in environment +variable. + + with +optional offset into the register array, and print it to +standard output or store it into environment variable [env]. + + reg + cid + The Device IDentification (CID) register. Uses offset. + csd + The Device-Specific Data (CSD) register. Uses offset. + dsr + The driver stage register (DSR). + ocr + The operation conditions register (OCR). + rca + The relative Device address (RCA) register. + extcsd + The Extended CSD register. Uses offset. + offset + For 'cid'/'csd' 128 bit registers '[0..3]' in 32-bit increments. For 'extcsd' 512 bit register '[0..512,all]' in 8-bit increments, or 'all' to read the entire register. + env + Optional environment variable into which 32-bit value read from register should be stored. Examples -------- -- cgit v1.3.1