- 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
This commit is contained in:
Tom Rini 2020-04-22 08:58:41 -04:00
commit 2b63959e30
27 changed files with 337 additions and 52 deletions

View File

@ -189,7 +189,7 @@ int g_dnl_bind_fixup(struct usb_device_descriptor *dev, const char *name)
#if defined(CONFIG_SPL_MMC_SUPPORT) #if defined(CONFIG_SPL_MMC_SUPPORT)
/* called from spl_mmc to see type of boot mode for storage (RAW or FAT) */ /* 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) #if defined(CONFIG_MX7) || defined(CONFIG_IMX8M) || defined(CONFIG_IMX8)
switch (get_boot_device()) { switch (get_boot_device()) {

View File

@ -199,7 +199,7 @@ void board_init_f(ulong dummy)
#endif #endif
} }
u32 spl_boot_mode(const u32 boot_device) u32 spl_mmc_boot_mode(const u32 boot_device)
{ {
#if defined(CONFIG_SUPPORT_EMMC_BOOT) #if defined(CONFIG_SUPPORT_EMMC_BOOT)
u32 devstat = readl(CTRLMMR_MAIN_DEVSTAT); u32 devstat = readl(CTRLMMR_MAIN_DEVSTAT);

View File

@ -223,7 +223,7 @@ void board_init_f(ulong dummy)
#endif #endif
} }
u32 spl_boot_mode(const u32 boot_device) u32 spl_mmc_boot_mode(const u32 boot_device)
{ {
switch (boot_device) { switch (boot_device) {
case BOOT_DEVICE_MMC1: case BOOT_DEVICE_MMC1:

View File

@ -187,7 +187,7 @@ u32 spl_boot_device(void)
return gd->arch.omap_boot_device; 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; return gd->arch.omap_boot_mode;
} }

View File

@ -58,7 +58,7 @@ u32 spl_boot_device(void)
return boot_device; return boot_device;
} }
u32 spl_boot_mode(const u32 boot_device) u32 spl_mmc_boot_mode(const u32 boot_device)
{ {
return MMCSD_MODE_RAW; return MMCSD_MODE_RAW;
} }

View File

@ -92,7 +92,7 @@ u32 spl_boot_device(void)
} }
#ifdef CONFIG_SPL_MMC_SUPPORT #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) #if defined(CONFIG_SPL_FS_FAT) || defined(CONFIG_SPL_FS_EXT4)
return MMCSD_MODE_FS; return MMCSD_MODE_FS;

View File

@ -28,7 +28,7 @@ u32 spl_boot_device(void)
} }
#ifdef CONFIG_SPL_MMC_SUPPORT #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) #if defined(CONFIG_SPL_FS_FAT) || defined(CONFIG_SPL_FS_EXT4)
return MMCSD_MODE_FS; return MMCSD_MODE_FS;

View File

@ -49,7 +49,7 @@ u32 spl_boot_device(void)
} }
#ifdef CONFIG_SPL_MMC_SUPPORT #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) #if defined(CONFIG_SPL_FS_FAT) || defined(CONFIG_SPL_FS_EXT4)
return MMCSD_MODE_FS; return MMCSD_MODE_FS;

View File

@ -30,7 +30,7 @@ u32 spl_boot_device(void)
} }
#ifdef CONFIG_SPL_MMC_SUPPORT #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) #if defined(CONFIG_SPL_FS_FAT) || defined(CONFIG_SPL_FS_EXT4)
return MMCSD_MODE_FS; return MMCSD_MODE_FS;

View File

@ -44,12 +44,12 @@ u32 spl_boot_device(void)
return BOOT_DEVICE_MMC1; 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; return MMCSD_MODE_RAW;
} }
int spl_boot_partition(const u32 boot_device) int spl_mmc_boot_partition(const u32 boot_device)
{ {
switch (boot_device) { switch (boot_device) {
case BOOT_DEVICE_MMC1: case BOOT_DEVICE_MMC1:

View File

@ -8,7 +8,7 @@
#include <mmc.h> #include <mmc.h>
#include <spl.h> #include <spl.h>
u32 spl_boot_mode(const u32 boot_device) u32 spl_mmc_boot_mode(const u32 boot_device)
{ {
struct mmc *mmc; struct mmc *mmc;

View File

@ -1060,21 +1060,34 @@ config CMD_MMC
help help
MMC memory mapped support. 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 config CMD_MMC_RPMB
bool "Enable support for RPMB in the mmc command" bool "Enable support for RPMB in the mmc command"
depends on CMD_MMC depends on SUPPORT_EMMC_RPMB
help help
Enable the commands for reading, writing and programming the Enable the commands for reading, writing and programming the
key for the Replay Protection Memory Block partition in eMMC. key for the Replay Protection Memory Block partition in eMMC.
config CMD_MMC_SWRITE config CMD_MMC_SWRITE
bool "mmc swrite" bool "mmc swrite"
depends on CMD_MMC && MMC_WRITE depends on MMC_WRITE
select IMAGE_SPARSE select IMAGE_SPARSE
help help
Enable support for the "mmc swrite" command to write Android sparse Enable support for the "mmc swrite" command to write Android sparse
images to eMMC. images to eMMC.
endif
config CMD_MTD config CMD_MTD
bool "mtd" bool "mtd"
depends on MTD depends on MTD
@ -1607,15 +1620,6 @@ config CMD_BSP
option provides a way to control this. The commands that are enabled option provides a way to control this. The commands that are enabled
vary depending on the board. 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 config CMD_BLOCK_CACHE
bool "blkcache - control and stats for block cache" bool "blkcache - control and stats for block cache"
depends on BLOCK_CACHE depends on BLOCK_CACHE

View File

@ -54,6 +54,8 @@ static void print_mmcinfo(struct mmc *mmc)
if (!IS_SD(mmc) && mmc->version >= MMC_VERSION_4_41) { if (!IS_SD(mmc) && mmc->version >= MMC_VERSION_4_41) {
bool has_enh = (mmc->part_support & ENHNCD_SUPPORT) != 0; bool has_enh = (mmc->part_support & ENHNCD_SUPPORT) != 0;
bool usr_enh = has_enh && (mmc->part_attr & EXT_CSD_ENH_USR); 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) #if CONFIG_IS_ENABLED(MMC_HW_PARTITIONING)
puts("HC WP Group Size: "); puts("HC WP Group Size: ");
@ -90,6 +92,28 @@ static void print_mmcinfo(struct mmc *mmc)
putc('\n'); 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) 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 #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[] = { static cmd_tbl_t cmd_mmc[] = {
U_BOOT_CMD_MKENT(info, 1, 0, do_mmcinfo, "", ""), U_BOOT_CMD_MKENT(info, 1, 0, do_mmcinfo, "", ""),
U_BOOT_CMD_MKENT(read, 4, 1, do_mmc_read, "", ""), 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) #if CONFIG_IS_ENABLED(MMC_WRITE)
U_BOOT_CMD_MKENT(write, 4, 0, do_mmc_write, "", ""), U_BOOT_CMD_MKENT(write, 4, 0, do_mmc_write, "", ""),
U_BOOT_CMD_MKENT(erase, 3, 0, do_mmc_erase, "", ""), 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 part - lists available partition on current mmc device\n"
"mmc dev [dev] [part] - show or set current mmc device [partition]\n" "mmc dev [dev] [part] - show or set current mmc device [partition]\n"
"mmc list - lists available devices\n" "mmc list - lists available devices\n"
"mmc wp - power on write protect booot partitions\n"
#if CONFIG_IS_ENABLED(MMC_HW_PARTITIONING) #if CONFIG_IS_ENABLED(MMC_HW_PARTITIONING)
"mmc hwpartition [args...] - does hardware partitioning\n" "mmc hwpartition [args...] - does hardware partitioning\n"
" arguments (sizes in 512-byte blocks):\n" " arguments (sizes in 512-byte blocks):\n"

View File

@ -31,17 +31,19 @@ static int addr_aligned(struct bounce_buffer *state)
return 1; return 1;
} }
int bounce_buffer_start(struct bounce_buffer *state, void *data, int bounce_buffer_start_extalign(struct bounce_buffer *state, void *data,
size_t len, unsigned int flags) size_t len, unsigned int flags,
size_t alignment,
int (*addr_is_aligned)(struct bounce_buffer *state))
{ {
state->user_buffer = data; state->user_buffer = data;
state->bounce_buffer = data; state->bounce_buffer = data;
state->len = len; state->len = len;
state->len_aligned = roundup(len, ARCH_DMA_MINALIGN); state->len_aligned = roundup(len, alignment);
state->flags = flags; state->flags = flags;
if (!addr_aligned(state)) { if (!addr_is_aligned(state)) {
state->bounce_buffer = memalign(ARCH_DMA_MINALIGN, state->bounce_buffer = memalign(alignment,
state->len_aligned); state->len_aligned);
if (!state->bounce_buffer) if (!state->bounce_buffer)
return -ENOMEM; return -ENOMEM;
@ -62,6 +64,14 @@ int bounce_buffer_start(struct bounce_buffer *state, void *data,
return 0; 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) int bounce_buffer_stop(struct bounce_buffer *state)
{ {
if (state->flags & GEN_BB_WRITE) { if (state->flags & GEN_BB_WRITE) {

View File

@ -298,7 +298,7 @@ static int spl_mmc_do_fs_boot(struct spl_image_info *spl_image, struct mmc *mmc,
} }
#endif #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) #if defined(CONFIG_SPL_FS_FAT) || defined(CONFIG_SPL_FS_EXT4)
return MMCSD_MODE_FS; 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 #ifdef CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_USE_PARTITION
__weak int __weak spl_mmc_boot_partition(const u32 boot_device)
int spl_boot_partition(const u32 boot_device)
{ {
return CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_PARTITION; 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; err = -EINVAL;
switch (boot_mode) { switch (boot_mode) {
case MMCSD_MODE_EMMCBOOT: case MMCSD_MODE_EMMCBOOT:
@ -431,7 +430,7 @@ int spl_mmc_load_image(struct spl_image_info *spl_image,
NULL, NULL,
#endif #endif
#ifdef CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_PARTITION #ifdef CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_PARTITION
spl_boot_partition(bootdev->boot_device), spl_mmc_boot_partition(bootdev->boot_device),
#else #else
0, 0,
#endif #endif

View File

@ -358,6 +358,7 @@ config RENESAS_SDHI
depends on ARCH_RMOBILE depends on ARCH_RMOBILE
depends on BLK && DM_MMC depends on BLK && DM_MMC
depends on OF_CONTROL depends on OF_CONTROL
select BOUNCE_BUFFER
help help
This selects support for the Matsushita SD/MMC Host Controller on This selects support for the Matsushita SD/MMC Host Controller on
Renesas R-Car SoCs. Renesas R-Car SoCs.

View File

@ -38,7 +38,7 @@ obj-$(CONFIG_MMC_MXC) += mxcmmc.o
obj-$(CONFIG_MMC_MXS) += mxsmmc.o obj-$(CONFIG_MMC_MXS) += mxsmmc.o
obj-$(CONFIG_MMC_PCI) += pci_mmc.o obj-$(CONFIG_MMC_PCI) += pci_mmc.o
obj-$(CONFIG_PXA_MMC_GENERIC) += pxa_mmc_gen.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_MMC_SANDBOX) += sandbox_mmc.o
obj-$(CONFIG_SH_MMCIF) += sh_mmcif.o obj-$(CONFIG_SH_MMCIF) += sh_mmcif.o
obj-$(CONFIG_SH_SDHI) += sh_sdhi.o obj-$(CONFIG_SH_SDHI) += sh_sdhi.o

View File

@ -136,7 +136,7 @@ static void sdhci_iproc_writeb(struct sdhci_host *host, u8 val, int reg)
} }
#endif #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); 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; ctrl |= UHS_DDR50_BUS_SPEED;
sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2); sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2);
return 0;
} }
static struct sdhci_ops sdhci_platform_ops = { static struct sdhci_ops sdhci_platform_ops = {
@ -176,8 +178,7 @@ static int iproc_sdhci_probe(struct udevice *dev)
u32 f_min_max[2]; u32 f_min_max[2];
int ret; int ret;
iproc_host = (struct sdhci_iproc_host *) iproc_host = malloc(sizeof(struct sdhci_iproc_host));
malloc(sizeof(struct sdhci_iproc_host));
if (!iproc_host) { if (!iproc_host) {
printf("%s: sdhci host malloc fail!\n", __func__); printf("%s: sdhci host malloc fail!\n", __func__);
return -ENOMEM; return -ENOMEM;
@ -189,7 +190,7 @@ static int iproc_sdhci_probe(struct udevice *dev)
host->ioaddr = (void *)devfdt_get_addr(dev); host->ioaddr = (void *)devfdt_get_addr(dev);
host->voltages = MMC_VDD_165_195 | host->voltages = MMC_VDD_165_195 |
MMC_VDD_32_33 | MMC_VDD_33_34; 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->host_caps = MMC_MODE_DDR_52MHz;
host->index = fdtdec_get_uint(gd->fdt_blob, node, "index", 0); host->index = fdtdec_get_uint(gd->fdt_blob, node, "index", 0);
host->ops = &sdhci_platform_ops; 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); "clock-freq-min-max", f_min_max, 2);
if (ret) { if (ret) {
printf("sdhci: clock-freq-min-max not found\n"); printf("sdhci: clock-freq-min-max not found\n");
free(iproc_host);
return ret; return ret;
} }
host->max_clk = f_min_max[1]; 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)); 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 = &plat->mmc;
iproc_host->host.mmc->dev = dev; iproc_host->host.mmc->dev = dev;
iproc_host->host.mmc->priv = &iproc_host->host; iproc_host->host.mmc->priv = &iproc_host->host;
upriv->mmc = iproc_host->host.mmc; 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); return sdhci_probe(dev);
} }

View File

@ -13,6 +13,22 @@
#include <linux/compat.h> #include <linux/compat.h>
#include "mmc_private.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, int dm_mmc_send_cmd(struct udevice *dev, struct mmc_cmd *cmd,
struct mmc_data *data) struct mmc_data *data)
{ {

View File

@ -409,6 +409,16 @@ static int mmc_read_blocks(struct mmc *mmc, void *dst, lbaint_t start,
return blkcnt; 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) #if CONFIG_IS_ENABLED(BLK)
ulong mmc_bread(struct udevice *dev, lbaint_t start, lbaint_t blkcnt, void *dst) ulong mmc_bread(struct udevice *dev, lbaint_t start, lbaint_t blkcnt, void *dst)
#else #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 dev_num = block_dev->devnum;
int err; int err;
lbaint_t cur, blocks_todo = blkcnt; lbaint_t cur, blocks_todo = blkcnt;
uint b_max;
if (blkcnt == 0) if (blkcnt == 0)
return 0; return 0;
@ -451,9 +462,10 @@ ulong mmc_bread(struct blk_desc *block_dev, lbaint_t start, lbaint_t blkcnt,
return 0; return 0;
} }
b_max = mmc_get_b_max(mmc, dst, blkcnt);
do { do {
cur = (blocks_todo > mmc->cfg->b_max) ? cur = (blocks_todo > b_max) ? b_max : blocks_todo;
mmc->cfg->b_max : blocks_todo;
if (mmc_read_blocks(mmc, dst, start, cur) != cur) { if (mmc_read_blocks(mmc, dst, start, cur) != cur) {
pr_debug("%s: Failed to read blocks\n", __func__); pr_debug("%s: Failed to read blocks\n", __func__);
return 0; 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_cmd cmd;
struct mmc_data data; 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); 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) #if !CONFIG_IS_ENABLED(MMC_TINY)
static int mmc_set_card_speed(struct mmc *mmc, enum bus_mode mode, static int mmc_set_card_speed(struct mmc *mmc, enum bus_mode mode,
bool hsdowngrade) bool hsdowngrade)

View File

@ -4,6 +4,7 @@
*/ */
#include <common.h> #include <common.h>
#include <bouncebuf.h>
#include <clk.h> #include <clk.h>
#include <fdtdec.h> #include <fdtdec.h>
#include <malloc.h> #include <malloc.h>
@ -689,12 +690,94 @@ static int renesas_sdhi_wait_dat0(struct udevice *dev, int state,
} }
#endif #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, static int renesas_sdhi_send_cmd(struct udevice *dev, struct mmc_cmd *cmd,
struct mmc_data *data) struct mmc_data *data)
{ {
struct bounce_buffer bbstate;
unsigned int bbflags;
bool bbok = false;
size_t len;
void *buf;
int ret; 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); 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) if (ret)
return ret; return ret;
@ -712,6 +795,24 @@ static int renesas_sdhi_send_cmd(struct udevice *dev, struct mmc_cmd *cmd,
return 0; 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 = { static const struct dm_mmc_ops renesas_sdhi_ops = {
.send_cmd = renesas_sdhi_send_cmd, .send_cmd = renesas_sdhi_send_cmd,
.set_ios = renesas_sdhi_set_ios, .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) #if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT)
.wait_dat0 = renesas_sdhi_wait_dat0, .wait_dat0 = renesas_sdhi_wait_dat0,
#endif #endif
.get_b_max = renesas_sdhi_get_b_max,
}; };
#define RENESAS_GEN2_QUIRKS TMIO_SD_CAP_RCAR_GEN2 #define RENESAS_GEN2_QUIRKS TMIO_SD_CAP_RCAR_GEN2
@ -889,6 +991,7 @@ static int renesas_sdhi_probe(struct udevice *dev)
return ret; return ret;
} }
priv->quirks = quirks;
ret = tmio_sd_probe(dev, quirks); ret = tmio_sd_probe(dev, quirks);
renesas_sdhi_filter_caps(dev); renesas_sdhi_filter_caps(dev);

View File

@ -358,14 +358,16 @@ static int tmio_sd_dma_xfer(struct udevice *dev, struct mmc_data *data)
} }
/* check if the address is DMA'able */ /* 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)) if (!IS_ALIGNED(addr, TMIO_SD_DMA_MINALIGN))
return false; return false;
#if defined(CONFIG_RCAR_GEN3) #if defined(CONFIG_RCAR_GEN3)
if (!(data->flags & MMC_DATA_READ) && !IS_ALIGNED(addr, 128))
return false;
/* Gen3 DMA has 32bit limit */ /* Gen3 DMA has 32bit limit */
if (addr >> 32) if (addr >> 32)
return false; return false;
@ -480,7 +482,7 @@ int tmio_sd_send_cmd(struct udevice *dev, struct mmc_cmd *cmd,
if (data) { if (data) {
/* use DMA if the HW supports it and the buffer is aligned */ /* use DMA if the HW supports it and the buffer is aligned */
if (priv->caps & TMIO_SD_CAP_DMA_INTERNAL && 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); ret = tmio_sd_dma_xfer(dev, data);
else else
ret = tmio_sd_pio_xfer(dev, cmd, data); ret = tmio_sd_pio_xfer(dev, cmd, data);

View File

@ -147,6 +147,7 @@ struct tmio_sd_priv {
u8 adjust_hs400_calibrate; u8 adjust_hs400_calibrate;
u8 hs400_bad_tap; u8 hs400_bad_tap;
const u8 *adjust_hs400_calib_table; const u8 *adjust_hs400_calib_table;
u32 quirks;
#endif #endif
ulong (*clk_get_rate)(struct tmio_sd_priv *); ulong (*clk_get_rate)(struct tmio_sd_priv *);
}; };

View File

@ -62,6 +62,21 @@ struct bounce_buffer {
*/ */
int bounce_buffer_start(struct bounce_buffer *state, void *data, int bounce_buffer_start(struct bounce_buffer *state, void *data,
size_t len, unsigned int flags); 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 * bounce_buffer_stop() -- Finish the bounce buffer session
* state: stores state passed between bounce_buffer_{start,stop} * state: stores state passed between bounce_buffer_{start,stop}

View File

@ -47,7 +47,7 @@
#define CONFIG_SYS_MONITOR_BASE 0x00000000 #define CONFIG_SYS_MONITOR_BASE 0x00000000
#define CONFIG_SYS_MONITOR_LEN (1 * 1024 * 1024) #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) #define CONFIG_SYS_BOOTM_LEN (64 << 20)
/* The HF/QSPI layout permits up to 1 MiB large bootloader blob */ /* The HF/QSPI layout permits up to 1 MiB large bootloader blob */

View File

@ -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_PARAM 166 /* R */
#define EXT_CSD_WR_REL_SET 167 /* R/W */ #define EXT_CSD_WR_REL_SET 167 /* R/W */
#define EXT_CSD_RPMB_MULT 168 /* RO */ #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_ERASE_GROUP_DEF 175 /* R/W */
#define EXT_CSD_BOOT_BUS_WIDTH 177 #define EXT_CSD_BOOT_BUS_WIDTH 177
#define EXT_CSD_PART_CONF 179 /* R/W */ #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 * @return 0 if not present, 1 if present, -ve on error
*/ */
int (*host_power_cycle)(struct udevice *dev); 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) #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_wait_dat0(struct udevice *dev, int state, int timeout_us);
int dm_mmc_host_power_cycle(struct udevice *dev); int dm_mmc_host_power_cycle(struct udevice *dev);
int dm_mmc_deferred_probe(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 */ /* Transition functions for compatibility */
int mmc_set_ios(struct mmc *mmc); 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_set_enhanced_strobe(struct mmc *mmc);
int mmc_host_power_cycle(struct mmc *mmc); int mmc_host_power_cycle(struct mmc *mmc);
int mmc_deferred_probe(struct mmc *mmc); int mmc_deferred_probe(struct mmc *mmc);
int mmc_get_b_max(struct mmc *mmc, void *dst, lbaint_t blkcnt);
#else #else
struct mmc_ops { struct mmc_ops {
@ -521,6 +539,7 @@ struct mmc_ops {
int (*getcd)(struct mmc *mmc); int (*getcd)(struct mmc *mmc);
int (*getwp)(struct mmc *mmc); int (*getwp)(struct mmc *mmc);
int (*host_power_cycle)(struct mmc *mmc); int (*host_power_cycle)(struct mmc *mmc);
int (*get_b_max)(struct mmc *mmc, void *dst, lbaint_t blkcnt);
}; };
#endif #endif
@ -893,6 +912,26 @@ int mmc_get_env_dev(void);
*/ */
struct blk_desc *mmc_get_blk_desc(struct mmc *mmc); 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) 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; return data->flags & MMC_DATA_WRITE ? DMA_TO_DEVICE : DMA_FROM_DEVICE;

View File

@ -238,8 +238,36 @@ int spl_load_imx_container(struct spl_image_info *spl_image,
/* SPL common functions */ /* SPL common functions */
void preloader_console_init(void); void preloader_console_init(void);
u32 spl_boot_device(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); void spl_set_bd(void);
/** /**