summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTom Rini <trini@konsulko.com>2020-04-22 08:58:41 -0400
committerTom Rini <trini@konsulko.com>2020-04-22 08:58:41 -0400
commit2b63959e30f23ef3088dbed6626341c6d8371a66 (patch)
tree1ea89ae7672fbb34886d05c0f6eabfea4d0e00d3
parent2f2031e647564be8121c05507fbec8e6c5bc0e63 (diff)
parent2448c34f9fc26d3c459e6e7b28c6357656bfa287 (diff)
Merge tag 'mmc-2020-4-22' of https://gitlab.denx.de/u-boot/custodians/u-boot-mmc
- iproc_sdhci memory leak fix and enable R1B resp quirk - more mmc cmds and several mmc updates from Heinirich - Use bounce buffer for tmio sdhci - Alignment check for tmio sdhci
-rw-r--r--arch/arm/mach-imx/spl.c2
-rw-r--r--arch/arm/mach-k3/am6_init.c2
-rw-r--r--arch/arm/mach-k3/j721e_init.c2
-rw-r--r--arch/arm/mach-omap2/boot-common.c2
-rw-r--r--arch/arm/mach-rockchip/spl.c2
-rw-r--r--arch/arm/mach-socfpga/spl_a10.c2
-rw-r--r--arch/arm/mach-socfpga/spl_agilex.c2
-rw-r--r--arch/arm/mach-socfpga/spl_gen5.c2
-rw-r--r--arch/arm/mach-socfpga/spl_s10.c2
-rw-r--r--arch/arm/mach-stm32mp/spl.c4
-rw-r--r--arch/arm/mach-uniphier/mmc-boot-mode.c2
-rw-r--r--cmd/Kconfig26
-rw-r--r--cmd/mmc.c46
-rw-r--r--common/bouncebuf.c20
-rw-r--r--common/spl/spl_mmc.c9
-rw-r--r--drivers/mmc/Kconfig1
-rw-r--r--drivers/mmc/Makefile2
-rw-r--r--drivers/mmc/iproc_sdhci.c22
-rw-r--r--drivers/mmc/mmc-uclass.c16
-rw-r--r--drivers/mmc/mmc.c23
-rw-r--r--drivers/mmc/renesas-sdhi.c103
-rw-r--r--drivers/mmc/tmio-common.c8
-rw-r--r--drivers/mmc/tmio-common.h1
-rw-r--r--include/bouncebuf.h15
-rw-r--r--include/configs/rcar-gen3-common.h2
-rw-r--r--include/mmc.h39
-rw-r--r--include/spl.h32
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
diff --git a/cmd/mmc.c b/cmd/mmc.c
index 1860a3f2e5..6142ec8e20 100644
--- a/cmd/mmc.c
+++ b/cmd/mmc.c
@@ -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);
/**