mirror of
https://xff.cz/git/u-boot/
synced 2025-09-01 08:42:12 +02:00
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
This commit is contained in:
@@ -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.
|
||||
|
@@ -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
|
||||
|
@@ -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);
|
||||
}
|
||||
|
||||
|
@@ -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)
|
||||
{
|
||||
|
@@ -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)
|
||||
|
@@ -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);
|
||||
|
@@ -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);
|
||||
|
@@ -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 *);
|
||||
};
|
||||
|
Reference in New Issue
Block a user