diff options
-rw-r--r-- | arch/arm/mach-imx/spl.c | 2 | ||||
-rw-r--r-- | arch/arm/mach-k3/am6_init.c | 2 | ||||
-rw-r--r-- | arch/arm/mach-k3/j721e_init.c | 2 | ||||
-rw-r--r-- | arch/arm/mach-omap2/boot-common.c | 2 | ||||
-rw-r--r-- | arch/arm/mach-rockchip/spl.c | 2 | ||||
-rw-r--r-- | arch/arm/mach-socfpga/spl_a10.c | 2 | ||||
-rw-r--r-- | arch/arm/mach-socfpga/spl_agilex.c | 2 | ||||
-rw-r--r-- | arch/arm/mach-socfpga/spl_gen5.c | 2 | ||||
-rw-r--r-- | arch/arm/mach-socfpga/spl_s10.c | 2 | ||||
-rw-r--r-- | arch/arm/mach-stm32mp/spl.c | 4 | ||||
-rw-r--r-- | arch/arm/mach-uniphier/mmc-boot-mode.c | 2 | ||||
-rw-r--r-- | cmd/Kconfig | 26 | ||||
-rw-r--r-- | cmd/mmc.c | 46 | ||||
-rw-r--r-- | common/bouncebuf.c | 20 | ||||
-rw-r--r-- | common/spl/spl_mmc.c | 9 | ||||
-rw-r--r-- | drivers/mmc/Kconfig | 1 | ||||
-rw-r--r-- | drivers/mmc/Makefile | 2 | ||||
-rw-r--r-- | drivers/mmc/iproc_sdhci.c | 22 | ||||
-rw-r--r-- | drivers/mmc/mmc-uclass.c | 16 | ||||
-rw-r--r-- | drivers/mmc/mmc.c | 23 | ||||
-rw-r--r-- | drivers/mmc/renesas-sdhi.c | 103 | ||||
-rw-r--r-- | drivers/mmc/tmio-common.c | 8 | ||||
-rw-r--r-- | drivers/mmc/tmio-common.h | 1 | ||||
-rw-r--r-- | include/bouncebuf.h | 15 | ||||
-rw-r--r-- | include/configs/rcar-gen3-common.h | 2 | ||||
-rw-r--r-- | include/mmc.h | 39 | ||||
-rw-r--r-- | include/spl.h | 32 |
27 files changed, 337 insertions, 52 deletions
diff --git a/arch/arm/mach-imx/spl.c b/arch/arm/mach-imx/spl.c index 87dbdf3011..49bb3b928d 100644 --- a/arch/arm/mach-imx/spl.c +++ b/arch/arm/mach-imx/spl.c @@ -189,7 +189,7 @@ int g_dnl_bind_fixup(struct usb_device_descriptor *dev, const char *name) #if defined(CONFIG_SPL_MMC_SUPPORT) /* called from spl_mmc to see type of boot mode for storage (RAW or FAT) */ -u32 spl_boot_mode(const u32 boot_device) +u32 spl_mmc_boot_mode(const u32 boot_device) { #if defined(CONFIG_MX7) || defined(CONFIG_IMX8M) || defined(CONFIG_IMX8) switch (get_boot_device()) { diff --git a/arch/arm/mach-k3/am6_init.c b/arch/arm/mach-k3/am6_init.c index 3768bccafa..b692806352 100644 --- a/arch/arm/mach-k3/am6_init.c +++ b/arch/arm/mach-k3/am6_init.c @@ -199,7 +199,7 @@ void board_init_f(ulong dummy) #endif } -u32 spl_boot_mode(const u32 boot_device) +u32 spl_mmc_boot_mode(const u32 boot_device) { #if defined(CONFIG_SUPPORT_EMMC_BOOT) u32 devstat = readl(CTRLMMR_MAIN_DEVSTAT); diff --git a/arch/arm/mach-k3/j721e_init.c b/arch/arm/mach-k3/j721e_init.c index f34090f9cc..71fc20c30b 100644 --- a/arch/arm/mach-k3/j721e_init.c +++ b/arch/arm/mach-k3/j721e_init.c @@ -223,7 +223,7 @@ void board_init_f(ulong dummy) #endif } -u32 spl_boot_mode(const u32 boot_device) +u32 spl_mmc_boot_mode(const u32 boot_device) { switch (boot_device) { case BOOT_DEVICE_MMC1: diff --git a/arch/arm/mach-omap2/boot-common.c b/arch/arm/mach-omap2/boot-common.c index 734fa9d9e6..7538523724 100644 --- a/arch/arm/mach-omap2/boot-common.c +++ b/arch/arm/mach-omap2/boot-common.c @@ -187,7 +187,7 @@ u32 spl_boot_device(void) return gd->arch.omap_boot_device; } -u32 spl_boot_mode(const u32 boot_device) +u32 spl_mmc_boot_mode(const u32 boot_device) { return gd->arch.omap_boot_mode; } diff --git a/arch/arm/mach-rockchip/spl.c b/arch/arm/mach-rockchip/spl.c index 48ab0e60c6..0b76af6080 100644 --- a/arch/arm/mach-rockchip/spl.c +++ b/arch/arm/mach-rockchip/spl.c @@ -58,7 +58,7 @@ u32 spl_boot_device(void) return boot_device; } -u32 spl_boot_mode(const u32 boot_device) +u32 spl_mmc_boot_mode(const u32 boot_device) { return MMCSD_MODE_RAW; } diff --git a/arch/arm/mach-socfpga/spl_a10.c b/arch/arm/mach-socfpga/spl_a10.c index b10be33268..d2f52f2f2c 100644 --- a/arch/arm/mach-socfpga/spl_a10.c +++ b/arch/arm/mach-socfpga/spl_a10.c @@ -92,7 +92,7 @@ u32 spl_boot_device(void) } #ifdef CONFIG_SPL_MMC_SUPPORT -u32 spl_boot_mode(const u32 boot_device) +u32 spl_mmc_boot_mode(const u32 boot_device) { #if defined(CONFIG_SPL_FS_FAT) || defined(CONFIG_SPL_FS_EXT4) return MMCSD_MODE_FS; diff --git a/arch/arm/mach-socfpga/spl_agilex.c b/arch/arm/mach-socfpga/spl_agilex.c index ecc1a35c49..aa9f3e646c 100644 --- a/arch/arm/mach-socfpga/spl_agilex.c +++ b/arch/arm/mach-socfpga/spl_agilex.c @@ -28,7 +28,7 @@ u32 spl_boot_device(void) } #ifdef CONFIG_SPL_MMC_SUPPORT -u32 spl_boot_mode(const u32 boot_device) +u32 spl_mmc_boot_mode(const u32 boot_device) { #if defined(CONFIG_SPL_FS_FAT) || defined(CONFIG_SPL_FS_EXT4) return MMCSD_MODE_FS; diff --git a/arch/arm/mach-socfpga/spl_gen5.c b/arch/arm/mach-socfpga/spl_gen5.c index a01e2a5cb9..e9967ac450 100644 --- a/arch/arm/mach-socfpga/spl_gen5.c +++ b/arch/arm/mach-socfpga/spl_gen5.c @@ -49,7 +49,7 @@ u32 spl_boot_device(void) } #ifdef CONFIG_SPL_MMC_SUPPORT -u32 spl_boot_mode(const u32 boot_device) +u32 spl_mmc_boot_mode(const u32 boot_device) { #if defined(CONFIG_SPL_FS_FAT) || defined(CONFIG_SPL_FS_EXT4) return MMCSD_MODE_FS; diff --git a/arch/arm/mach-socfpga/spl_s10.c b/arch/arm/mach-socfpga/spl_s10.c index d89151d902..08427dd83e 100644 --- a/arch/arm/mach-socfpga/spl_s10.c +++ b/arch/arm/mach-socfpga/spl_s10.c @@ -30,7 +30,7 @@ u32 spl_boot_device(void) } #ifdef CONFIG_SPL_MMC_SUPPORT -u32 spl_boot_mode(const u32 boot_device) +u32 spl_mmc_boot_mode(const u32 boot_device) { #if defined(CONFIG_SPL_FS_FAT) || defined(CONFIG_SPL_FS_EXT4) return MMCSD_MODE_FS; diff --git a/arch/arm/mach-stm32mp/spl.c b/arch/arm/mach-stm32mp/spl.c index ca4231cd0d..f85391c6af 100644 --- a/arch/arm/mach-stm32mp/spl.c +++ b/arch/arm/mach-stm32mp/spl.c @@ -44,12 +44,12 @@ u32 spl_boot_device(void) return BOOT_DEVICE_MMC1; } -u32 spl_boot_mode(const u32 boot_device) +u32 spl_mmc_boot_mode(const u32 boot_device) { return MMCSD_MODE_RAW; } -int spl_boot_partition(const u32 boot_device) +int spl_mmc_boot_partition(const u32 boot_device) { switch (boot_device) { case BOOT_DEVICE_MMC1: diff --git a/arch/arm/mach-uniphier/mmc-boot-mode.c b/arch/arm/mach-uniphier/mmc-boot-mode.c index 19b4560494..b48495365c 100644 --- a/arch/arm/mach-uniphier/mmc-boot-mode.c +++ b/arch/arm/mach-uniphier/mmc-boot-mode.c @@ -8,7 +8,7 @@ #include <mmc.h> #include <spl.h> -u32 spl_boot_mode(const u32 boot_device) +u32 spl_mmc_boot_mode(const u32 boot_device) { struct mmc *mmc; diff --git a/cmd/Kconfig b/cmd/Kconfig index 95a67e9d02..6ce9e5521c 100644 --- a/cmd/Kconfig +++ b/cmd/Kconfig @@ -1060,21 +1060,34 @@ config CMD_MMC help MMC memory mapped support. +if CMD_MMC + +config CMD_BKOPS_ENABLE + bool "mmc bkops enable" + depends on CMD_MMC + default n + help + Enable command for setting manual background operations handshake + on a eMMC device. The feature is optionally available on eMMC devices + conforming to standard >= 4.41. + config CMD_MMC_RPMB bool "Enable support for RPMB in the mmc command" - depends on CMD_MMC + depends on SUPPORT_EMMC_RPMB help Enable the commands for reading, writing and programming the key for the Replay Protection Memory Block partition in eMMC. config CMD_MMC_SWRITE bool "mmc swrite" - depends on CMD_MMC && MMC_WRITE + depends on MMC_WRITE select IMAGE_SPARSE help Enable support for the "mmc swrite" command to write Android sparse images to eMMC. +endif + config CMD_MTD bool "mtd" depends on MTD @@ -1607,15 +1620,6 @@ config CMD_BSP option provides a way to control this. The commands that are enabled vary depending on the board. -config CMD_BKOPS_ENABLE - bool "mmc bkops enable" - depends on CMD_MMC - default n - help - Enable command for setting manual background operations handshake - on a eMMC device. The feature is optionally available on eMMC devices - conforming to standard >= 4.41. - config CMD_BLOCK_CACHE bool "blkcache - control and stats for block cache" depends on BLOCK_CACHE @@ -54,6 +54,8 @@ static void print_mmcinfo(struct mmc *mmc) if (!IS_SD(mmc) && mmc->version >= MMC_VERSION_4_41) { bool has_enh = (mmc->part_support & ENHNCD_SUPPORT) != 0; bool usr_enh = has_enh && (mmc->part_attr & EXT_CSD_ENH_USR); + u8 wp, ext_csd[MMC_MAX_BLOCK_LEN]; + int ret; #if CONFIG_IS_ENABLED(MMC_HW_PARTITIONING) puts("HC WP Group Size: "); @@ -90,6 +92,28 @@ static void print_mmcinfo(struct mmc *mmc) putc('\n'); } } + ret = mmc_send_ext_csd(mmc, ext_csd); + if (ret) + return; + wp = ext_csd[EXT_CSD_BOOT_WP_STATUS]; + for (i = 0; i < 2; ++i) { + printf("Boot area %d is ", i); + switch (wp & 3) { + case 0: + printf("not write protected\n"); + break; + case 1: + printf("power on protected\n"); + break; + case 2: + printf("permanently protected\n"); + break; + default: + printf("in reserved protection state\n"); + break; + } + wp >>= 2; + } } } static struct mmc *init_mmc_device(int dev, bool force_init) @@ -872,9 +896,30 @@ static int do_mmc_bkops_enable(cmd_tbl_t *cmdtp, int flag, } #endif +static int do_mmc_boot_wp(cmd_tbl_t *cmdtp, int flag, + int argc, char * const argv[]) +{ + int err; + struct mmc *mmc; + + mmc = init_mmc_device(curr_device, false); + if (!mmc) + return CMD_RET_FAILURE; + if (IS_SD(mmc)) { + printf("It is not an eMMC device\n"); + return CMD_RET_FAILURE; + } + err = mmc_boot_wp(mmc); + if (err) + return CMD_RET_FAILURE; + printf("boot areas protected\n"); + return CMD_RET_SUCCESS; +} + static cmd_tbl_t cmd_mmc[] = { U_BOOT_CMD_MKENT(info, 1, 0, do_mmcinfo, "", ""), U_BOOT_CMD_MKENT(read, 4, 1, do_mmc_read, "", ""), + U_BOOT_CMD_MKENT(wp, 1, 0, do_mmc_boot_wp, "", ""), #if CONFIG_IS_ENABLED(MMC_WRITE) U_BOOT_CMD_MKENT(write, 4, 0, do_mmc_write, "", ""), U_BOOT_CMD_MKENT(erase, 3, 0, do_mmc_erase, "", ""), @@ -944,6 +989,7 @@ U_BOOT_CMD( "mmc part - lists available partition on current mmc device\n" "mmc dev [dev] [part] - show or set current mmc device [partition]\n" "mmc list - lists available devices\n" + "mmc wp - power on write protect booot partitions\n" #if CONFIG_IS_ENABLED(MMC_HW_PARTITIONING) "mmc hwpartition [args...] - does hardware partitioning\n" " arguments (sizes in 512-byte blocks):\n" diff --git a/common/bouncebuf.c b/common/bouncebuf.c index 614eb36c78..0ace152b98 100644 --- a/common/bouncebuf.c +++ b/common/bouncebuf.c @@ -31,17 +31,19 @@ static int addr_aligned(struct bounce_buffer *state) return 1; } -int bounce_buffer_start(struct bounce_buffer *state, void *data, - size_t len, unsigned int flags) +int bounce_buffer_start_extalign(struct bounce_buffer *state, void *data, + size_t len, unsigned int flags, + size_t alignment, + int (*addr_is_aligned)(struct bounce_buffer *state)) { state->user_buffer = data; state->bounce_buffer = data; state->len = len; - state->len_aligned = roundup(len, ARCH_DMA_MINALIGN); + state->len_aligned = roundup(len, alignment); state->flags = flags; - if (!addr_aligned(state)) { - state->bounce_buffer = memalign(ARCH_DMA_MINALIGN, + if (!addr_is_aligned(state)) { + state->bounce_buffer = memalign(alignment, state->len_aligned); if (!state->bounce_buffer) return -ENOMEM; @@ -62,6 +64,14 @@ int bounce_buffer_start(struct bounce_buffer *state, void *data, return 0; } +int bounce_buffer_start(struct bounce_buffer *state, void *data, + size_t len, unsigned int flags) +{ + return bounce_buffer_start_extalign(state, data, len, flags, + ARCH_DMA_MINALIGN, + addr_aligned); +} + int bounce_buffer_stop(struct bounce_buffer *state) { if (state->flags & GEN_BB_WRITE) { diff --git a/common/spl/spl_mmc.c b/common/spl/spl_mmc.c index a2ea363e96..a68cdec8dc 100644 --- a/common/spl/spl_mmc.c +++ b/common/spl/spl_mmc.c @@ -298,7 +298,7 @@ static int spl_mmc_do_fs_boot(struct spl_image_info *spl_image, struct mmc *mmc, } #endif -u32 __weak spl_boot_mode(const u32 boot_device) +u32 __weak spl_mmc_boot_mode(const u32 boot_device) { #if defined(CONFIG_SPL_FS_FAT) || defined(CONFIG_SPL_FS_EXT4) return MMCSD_MODE_FS; @@ -310,8 +310,7 @@ u32 __weak spl_boot_mode(const u32 boot_device) } #ifdef CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_USE_PARTITION -__weak -int spl_boot_partition(const u32 boot_device) +int __weak spl_mmc_boot_partition(const u32 boot_device) { return CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_PARTITION; } @@ -350,7 +349,7 @@ int spl_mmc_load(struct spl_image_info *spl_image, } } - boot_mode = spl_boot_mode(bootdev->boot_device); + boot_mode = spl_mmc_boot_mode(bootdev->boot_device); err = -EINVAL; switch (boot_mode) { case MMCSD_MODE_EMMCBOOT: @@ -431,7 +430,7 @@ int spl_mmc_load_image(struct spl_image_info *spl_image, NULL, #endif #ifdef CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_PARTITION - spl_boot_partition(bootdev->boot_device), + spl_mmc_boot_partition(bootdev->boot_device), #else 0, #endif diff --git a/drivers/mmc/Kconfig b/drivers/mmc/Kconfig index bb38787eca..8f0df568b9 100644 --- a/drivers/mmc/Kconfig +++ b/drivers/mmc/Kconfig @@ -358,6 +358,7 @@ config RENESAS_SDHI depends on ARCH_RMOBILE depends on BLK && DM_MMC depends on OF_CONTROL + select BOUNCE_BUFFER help This selects support for the Matsushita SD/MMC Host Controller on Renesas R-Car SoCs. diff --git a/drivers/mmc/Makefile b/drivers/mmc/Makefile index 615b724bf0..e84c792999 100644 --- a/drivers/mmc/Makefile +++ b/drivers/mmc/Makefile @@ -38,7 +38,7 @@ obj-$(CONFIG_MMC_MXC) += mxcmmc.o obj-$(CONFIG_MMC_MXS) += mxsmmc.o obj-$(CONFIG_MMC_PCI) += pci_mmc.o obj-$(CONFIG_PXA_MMC_GENERIC) += pxa_mmc_gen.o -obj-$(CONFIG_SUPPORT_EMMC_RPMB) += rpmb.o +obj-$(CONFIG_$(SPL_TPL_)SUPPORT_EMMC_RPMB) += rpmb.o obj-$(CONFIG_MMC_SANDBOX) += sandbox_mmc.o obj-$(CONFIG_SH_MMCIF) += sh_mmcif.o obj-$(CONFIG_SH_SDHI) += sh_sdhi.o diff --git a/drivers/mmc/iproc_sdhci.c b/drivers/mmc/iproc_sdhci.c index 831dd32eb7..c2319b4134 100644 --- a/drivers/mmc/iproc_sdhci.c +++ b/drivers/mmc/iproc_sdhci.c @@ -136,7 +136,7 @@ static void sdhci_iproc_writeb(struct sdhci_host *host, u8 val, int reg) } #endif -static void sdhci_iproc_set_ios_post(struct sdhci_host *host) +static int sdhci_iproc_set_ios_post(struct sdhci_host *host) { u32 ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2); @@ -147,6 +147,8 @@ static void sdhci_iproc_set_ios_post(struct sdhci_host *host) ctrl |= UHS_DDR50_BUS_SPEED; sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2); + + return 0; } static struct sdhci_ops sdhci_platform_ops = { @@ -176,8 +178,7 @@ static int iproc_sdhci_probe(struct udevice *dev) u32 f_min_max[2]; int ret; - iproc_host = (struct sdhci_iproc_host *) - malloc(sizeof(struct sdhci_iproc_host)); + iproc_host = malloc(sizeof(struct sdhci_iproc_host)); if (!iproc_host) { printf("%s: sdhci host malloc fail!\n", __func__); return -ENOMEM; @@ -189,7 +190,7 @@ static int iproc_sdhci_probe(struct udevice *dev) host->ioaddr = (void *)devfdt_get_addr(dev); host->voltages = MMC_VDD_165_195 | MMC_VDD_32_33 | MMC_VDD_33_34; - host->quirks = SDHCI_QUIRK_BROKEN_VOLTAGE; + host->quirks = SDHCI_QUIRK_BROKEN_VOLTAGE | SDHCI_QUIRK_BROKEN_R1B; host->host_caps = MMC_MODE_DDR_52MHz; host->index = fdtdec_get_uint(gd->fdt_blob, node, "index", 0); host->ops = &sdhci_platform_ops; @@ -198,6 +199,7 @@ static int iproc_sdhci_probe(struct udevice *dev) "clock-freq-min-max", f_min_max, 2); if (ret) { printf("sdhci: clock-freq-min-max not found\n"); + free(iproc_host); return ret; } host->max_clk = f_min_max[1]; @@ -210,16 +212,18 @@ static int iproc_sdhci_probe(struct udevice *dev) memcpy(&iproc_host->host, host, sizeof(struct sdhci_host)); - ret = sdhci_setup_cfg(&plat->cfg, &iproc_host->host, - f_min_max[1], f_min_max[0]); - if (ret) - return ret; - iproc_host->host.mmc = &plat->mmc; iproc_host->host.mmc->dev = dev; iproc_host->host.mmc->priv = &iproc_host->host; upriv->mmc = iproc_host->host.mmc; + ret = sdhci_setup_cfg(&plat->cfg, &iproc_host->host, + f_min_max[1], f_min_max[0]); + if (ret) { + free(iproc_host); + return ret; + } + return sdhci_probe(dev); } diff --git a/drivers/mmc/mmc-uclass.c b/drivers/mmc/mmc-uclass.c index c75892a72c..cb26d841be 100644 --- a/drivers/mmc/mmc-uclass.c +++ b/drivers/mmc/mmc-uclass.c @@ -13,6 +13,22 @@ #include <linux/compat.h> #include "mmc_private.h" +int dm_mmc_get_b_max(struct udevice *dev, void *dst, lbaint_t blkcnt) +{ + struct dm_mmc_ops *ops = mmc_get_ops(dev); + struct mmc *mmc = mmc_get_mmc_dev(dev); + + if (ops->get_b_max) + return ops->get_b_max(dev, dst, blkcnt); + else + return mmc->cfg->b_max; +} + +int mmc_get_b_max(struct mmc *mmc, void *dst, lbaint_t blkcnt) +{ + return dm_mmc_get_b_max(mmc->dev, dst, blkcnt); +} + int dm_mmc_send_cmd(struct udevice *dev, struct mmc_cmd *cmd, struct mmc_data *data) { diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c index 3e36566693..523c055967 100644 --- a/drivers/mmc/mmc.c +++ b/drivers/mmc/mmc.c @@ -409,6 +409,16 @@ static int mmc_read_blocks(struct mmc *mmc, void *dst, lbaint_t start, return blkcnt; } +#if !CONFIG_IS_ENABLED(DM_MMC) +static int mmc_get_b_max(struct mmc *mmc, void *dst, lbaint_t blkcnt) +{ + if (mmc->cfg->ops->get_b_max) + return mmc->cfg->ops->get_b_max(mmc, dst, blkcnt); + else + return mmc->cfg->b_max; +} +#endif + #if CONFIG_IS_ENABLED(BLK) ulong mmc_bread(struct udevice *dev, lbaint_t start, lbaint_t blkcnt, void *dst) #else @@ -422,6 +432,7 @@ ulong mmc_bread(struct blk_desc *block_dev, lbaint_t start, lbaint_t blkcnt, int dev_num = block_dev->devnum; int err; lbaint_t cur, blocks_todo = blkcnt; + uint b_max; if (blkcnt == 0) return 0; @@ -451,9 +462,10 @@ ulong mmc_bread(struct blk_desc *block_dev, lbaint_t start, lbaint_t blkcnt, return 0; } + b_max = mmc_get_b_max(mmc, dst, blkcnt); + do { - cur = (blocks_todo > mmc->cfg->b_max) ? - mmc->cfg->b_max : blocks_todo; + cur = (blocks_todo > b_max) ? b_max : blocks_todo; if (mmc_read_blocks(mmc, dst, start, cur) != cur) { pr_debug("%s: Failed to read blocks\n", __func__); return 0; @@ -718,7 +730,7 @@ static int mmc_complete_op_cond(struct mmc *mmc) } -static int mmc_send_ext_csd(struct mmc *mmc, u8 *ext_csd) +int mmc_send_ext_csd(struct mmc *mmc, u8 *ext_csd) { struct mmc_cmd cmd; struct mmc_data data; @@ -810,6 +822,11 @@ int mmc_switch(struct mmc *mmc, u8 set, u8 index, u8 value) return __mmc_switch(mmc, set, index, value, true); } +int mmc_boot_wp(struct mmc *mmc) +{ + return mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BOOT_WP, 1); +} + #if !CONFIG_IS_ENABLED(MMC_TINY) static int mmc_set_card_speed(struct mmc *mmc, enum bus_mode mode, bool hsdowngrade) diff --git a/drivers/mmc/renesas-sdhi.c b/drivers/mmc/renesas-sdhi.c index c3b13136f8..88a7160b0a 100644 --- a/drivers/mmc/renesas-sdhi.c +++ b/drivers/mmc/renesas-sdhi.c @@ -4,6 +4,7 @@ */ #include <common.h> +#include <bouncebuf.h> #include <clk.h> #include <fdtdec.h> #include <malloc.h> @@ -689,12 +690,94 @@ static int renesas_sdhi_wait_dat0(struct udevice *dev, int state, } #endif +#define RENESAS_SDHI_DMA_ALIGNMENT 128 + +static int renesas_sdhi_addr_aligned_gen(uintptr_t ubuf, + size_t len, size_t len_aligned) +{ + /* Check if start is aligned */ + if (!IS_ALIGNED(ubuf, RENESAS_SDHI_DMA_ALIGNMENT)) { + debug("Unaligned buffer address %lx\n", ubuf); + return 0; + } + + /* Check if length is aligned */ + if (len != len_aligned) { + debug("Unaligned buffer length %zu\n", len); + return 0; + } + +#ifdef CONFIG_PHYS_64BIT + /* Check if below 32bit boundary */ + if ((ubuf >> 32) || (ubuf + len_aligned) >> 32) { + debug("Buffer above 32bit boundary %lx-%lx\n", + ubuf, ubuf + len_aligned); + return 0; + } +#endif + + /* Aligned */ + return 1; +} + +static int renesas_sdhi_addr_aligned(struct bounce_buffer *state) +{ + uintptr_t ubuf = (uintptr_t)state->user_buffer; + + return renesas_sdhi_addr_aligned_gen(ubuf, state->len, + state->len_aligned); +} + static int renesas_sdhi_send_cmd(struct udevice *dev, struct mmc_cmd *cmd, struct mmc_data *data) { + struct bounce_buffer bbstate; + unsigned int bbflags; + bool bbok = false; + size_t len; + void *buf; int ret; + if (data) { + if (data->flags & MMC_DATA_READ) { + buf = data->dest; + bbflags = GEN_BB_WRITE; + } else { + buf = (void *)data->src; + bbflags = GEN_BB_READ; + } + len = data->blocks * data->blocksize; + + ret = bounce_buffer_start_extalign(&bbstate, buf, len, bbflags, + RENESAS_SDHI_DMA_ALIGNMENT, + renesas_sdhi_addr_aligned); + /* + * If the amount of data to transfer is too large, we can get + * -ENOMEM when starting the bounce buffer. If that happens, + * fall back to PIO as it was before, otherwise use the BB. + */ + if (!ret) { + bbok = true; + if (data->flags & MMC_DATA_READ) + data->dest = bbstate.bounce_buffer; + else + data->src = bbstate.bounce_buffer; + } + } + ret = tmio_sd_send_cmd(dev, cmd, data); + + if (data && bbok) { + buf = bbstate.user_buffer; + + bounce_buffer_stop(&bbstate); + + if (data->flags & MMC_DATA_READ) + data->dest = buf; + else + data->src = buf; + } + if (ret) return ret; @@ -712,6 +795,24 @@ static int renesas_sdhi_send_cmd(struct udevice *dev, struct mmc_cmd *cmd, return 0; } +int renesas_sdhi_get_b_max(struct udevice *dev, void *dst, lbaint_t blkcnt) +{ + struct tmio_sd_priv *priv = dev_get_priv(dev); + struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev); + struct mmc *mmc = upriv->mmc; + size_t len = blkcnt * mmc->read_bl_len; + size_t len_align = roundup(len, RENESAS_SDHI_DMA_ALIGNMENT); + + if (renesas_sdhi_addr_aligned_gen((uintptr_t)dst, len, len_align)) { + if (priv->quirks & TMIO_SD_CAP_16BIT) + return U16_MAX; + else + return U32_MAX; + } else { + return (CONFIG_SYS_MALLOC_LEN / 4) / mmc->read_bl_len; + } +} + static const struct dm_mmc_ops renesas_sdhi_ops = { .send_cmd = renesas_sdhi_send_cmd, .set_ios = renesas_sdhi_set_ios, @@ -724,6 +825,7 @@ static const struct dm_mmc_ops renesas_sdhi_ops = { #if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT) .wait_dat0 = renesas_sdhi_wait_dat0, #endif + .get_b_max = renesas_sdhi_get_b_max, }; #define RENESAS_GEN2_QUIRKS TMIO_SD_CAP_RCAR_GEN2 @@ -889,6 +991,7 @@ static int renesas_sdhi_probe(struct udevice *dev) return ret; } + priv->quirks = quirks; ret = tmio_sd_probe(dev, quirks); renesas_sdhi_filter_caps(dev); diff --git a/drivers/mmc/tmio-common.c b/drivers/mmc/tmio-common.c index faf18191b3..1dc13db9ea 100644 --- a/drivers/mmc/tmio-common.c +++ b/drivers/mmc/tmio-common.c @@ -358,14 +358,16 @@ static int tmio_sd_dma_xfer(struct udevice *dev, struct mmc_data *data) } /* check if the address is DMA'able */ -static bool tmio_sd_addr_is_dmaable(const char *src) +static bool tmio_sd_addr_is_dmaable(struct mmc_data *data) { - uintptr_t addr = (uintptr_t)src; + uintptr_t addr = (uintptr_t)data->src; if (!IS_ALIGNED(addr, TMIO_SD_DMA_MINALIGN)) return false; #if defined(CONFIG_RCAR_GEN3) + if (!(data->flags & MMC_DATA_READ) && !IS_ALIGNED(addr, 128)) + return false; /* Gen3 DMA has 32bit limit */ if (addr >> 32) return false; @@ -480,7 +482,7 @@ int tmio_sd_send_cmd(struct udevice *dev, struct mmc_cmd *cmd, if (data) { /* use DMA if the HW supports it and the buffer is aligned */ if (priv->caps & TMIO_SD_CAP_DMA_INTERNAL && - tmio_sd_addr_is_dmaable(data->src)) + tmio_sd_addr_is_dmaable(data)) ret = tmio_sd_dma_xfer(dev, data); else ret = tmio_sd_pio_xfer(dev, cmd, data); diff --git a/drivers/mmc/tmio-common.h b/drivers/mmc/tmio-common.h index 047458849b..2f671df4bc 100644 --- a/drivers/mmc/tmio-common.h +++ b/drivers/mmc/tmio-common.h @@ -147,6 +147,7 @@ struct tmio_sd_priv { u8 adjust_hs400_calibrate; u8 hs400_bad_tap; const u8 *adjust_hs400_calib_table; + u32 quirks; #endif ulong (*clk_get_rate)(struct tmio_sd_priv *); }; diff --git a/include/bouncebuf.h b/include/bouncebuf.h index fd9b0f3b28..7427bd12e2 100644 --- a/include/bouncebuf.h +++ b/include/bouncebuf.h @@ -62,6 +62,21 @@ struct bounce_buffer { */ int bounce_buffer_start(struct bounce_buffer *state, void *data, size_t len, unsigned int flags); + +/** + * bounce_buffer_start() -- Start the bounce buffer session with external align check function + * state: stores state passed between bounce_buffer_{start,stop} + * data: pointer to buffer to be aligned + * len: length of the buffer + * flags: flags describing the transaction, see above. + * alignment: alignment of the newly allocated bounce buffer + * addr_is_aligned: function for checking the alignment instead of the default one + */ +int bounce_buffer_start_extalign(struct bounce_buffer *state, void *data, + size_t len, unsigned int flags, + size_t alignment, + int (*addr_is_aligned)(struct bounce_buffer *state)); + /** * bounce_buffer_stop() -- Finish the bounce buffer session * state: stores state passed between bounce_buffer_{start,stop} diff --git a/include/configs/rcar-gen3-common.h b/include/configs/rcar-gen3-common.h index 6528f1fa62..8f400ba05a 100644 --- a/include/configs/rcar-gen3-common.h +++ b/include/configs/rcar-gen3-common.h @@ -47,7 +47,7 @@ #define CONFIG_SYS_MONITOR_BASE 0x00000000 #define CONFIG_SYS_MONITOR_LEN (1 * 1024 * 1024) -#define CONFIG_SYS_MALLOC_LEN (1 * 1024 * 1024) +#define CONFIG_SYS_MALLOC_LEN (64 * 1024 * 1024) #define CONFIG_SYS_BOOTM_LEN (64 << 20) /* The HF/QSPI layout permits up to 1 MiB large bootloader blob */ diff --git a/include/mmc.h b/include/mmc.h index e83c22423b..5e9d15cb41 100644 --- a/include/mmc.h +++ b/include/mmc.h @@ -223,6 +223,9 @@ static inline bool mmc_is_tuning_cmd(uint cmdidx) #define EXT_CSD_WR_REL_PARAM 166 /* R */ #define EXT_CSD_WR_REL_SET 167 /* R/W */ #define EXT_CSD_RPMB_MULT 168 /* RO */ +#define EXT_CSD_USER_WP 171 /* R/W & R/W/C_P & R/W/E_P */ +#define EXT_CSD_BOOT_WP 173 /* R/W & R/W/C_P */ +#define EXT_CSD_BOOT_WP_STATUS 174 /* R */ #define EXT_CSD_ERASE_GROUP_DEF 175 /* R/W */ #define EXT_CSD_BOOT_BUS_WIDTH 177 #define EXT_CSD_PART_CONF 179 /* R/W */ @@ -488,6 +491,19 @@ struct dm_mmc_ops { * @return 0 if not present, 1 if present, -ve on error */ int (*host_power_cycle)(struct udevice *dev); + + /** + * get_b_max - get maximum length of single transfer + * Called before reading blocks from the card, + * useful for system which have e.g. DMA limits + * on various memory ranges. + * + * @dev: Device to check + * @dst: Destination buffer in memory + * @blkcnt: Total number of blocks in this transfer + * @return maximum number of blocks for this transfer + */ + int (*get_b_max)(struct udevice *dev, void *dst, lbaint_t blkcnt); }; #define mmc_get_ops(dev) ((struct dm_mmc_ops *)(dev)->driver->ops) @@ -501,6 +517,7 @@ int dm_mmc_execute_tuning(struct udevice *dev, uint opcode); int dm_mmc_wait_dat0(struct udevice *dev, int state, int timeout_us); int dm_mmc_host_power_cycle(struct udevice *dev); int dm_mmc_deferred_probe(struct udevice *dev); +int dm_mmc_get_b_max(struct udevice *dev, void *dst, lbaint_t blkcnt); /* Transition functions for compatibility */ int mmc_set_ios(struct mmc *mmc); @@ -511,6 +528,7 @@ int mmc_wait_dat0(struct mmc *mmc, int state, int timeout_us); int mmc_set_enhanced_strobe(struct mmc *mmc); int mmc_host_power_cycle(struct mmc *mmc); int mmc_deferred_probe(struct mmc *mmc); +int mmc_get_b_max(struct mmc *mmc, void *dst, lbaint_t blkcnt); #else struct mmc_ops { @@ -521,6 +539,7 @@ struct mmc_ops { int (*getcd)(struct mmc *mmc); int (*getwp)(struct mmc *mmc); int (*host_power_cycle)(struct mmc *mmc); + int (*get_b_max)(struct mmc *mmc, void *dst, lbaint_t blkcnt); }; #endif @@ -893,6 +912,26 @@ int mmc_get_env_dev(void); */ struct blk_desc *mmc_get_blk_desc(struct mmc *mmc); +/** + * mmc_send_ext_csd() - read the extended CSD register + * + * @mmc: MMC device + * @ext_csd a cache aligned buffer of length MMC_MAX_BLOCK_LEN allocated by + * the caller, e.g. using + * ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN) + * Return: 0 for success + */ +int mmc_send_ext_csd(struct mmc *mmc, u8 *ext_csd); + +/** + * mmc_boot_wp() - power on write protect boot partitions + * + * The boot partitions are write protected until the next power cycle. + * + * Return: 0 for success + */ +int mmc_boot_wp(struct mmc *mmc); + static inline enum dma_data_direction mmc_get_dma_dir(struct mmc_data *data) { return data->flags & MMC_DATA_WRITE ? DMA_TO_DEVICE : DMA_FROM_DEVICE; diff --git a/include/spl.h b/include/spl.h index 5d8d14dbf5..8b15cd4914 100644 --- a/include/spl.h +++ b/include/spl.h @@ -238,8 +238,36 @@ int spl_load_imx_container(struct spl_image_info *spl_image, /* SPL common functions */ void preloader_console_init(void); u32 spl_boot_device(void); -u32 spl_boot_mode(const u32 boot_device); -int spl_boot_partition(const u32 boot_device); + +/** + * spl_mmc_boot_mode() - Lookup function for the mode of an MMC boot source. + * @boot_device: ID of the device which the MMC driver wants to read + * from. Common values are e.g. BOOT_DEVICE_MMC1, + * BOOT_DEVICE_MMC2, BOOT_DEVICE_MMC2_2. + * + * This function should return one of MMCSD_MODE_FS, MMCSD_MODE_EMMCBOOT, or + * MMCSD_MODE_RAW for each MMC boot source which is defined for the target. The + * boot_device parameter tells which device the MMC driver is interested in. + * + * If not overridden, it is weakly defined in common/spl/spl_mmc.c. + * + * Note: It is important to use the boot_device parameter instead of e.g. + * spl_boot_device() as U-Boot is not always loaded from the same device as SPL. + */ +u32 spl_mmc_boot_mode(const u32 boot_device); + +/** + * spl_mmc_boot_partition() - MMC partition to load U-Boot from. + * @boot_device: ID of the device which the MMC driver wants to load + * U-Boot from. + * + * This function should return the partition number which the SPL + * should load U-Boot from (on the given boot_device) when + * CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_USE_PARTITION is set. + * + * If not overridden, it is weakly defined in common/spl/spl_mmc.c. + */ +int spl_mmc_boot_partition(const u32 boot_device); void spl_set_bd(void); /** |