summaryrefslogtreecommitdiff
path: root/drivers/mmc
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/mmc')
-rw-r--r--drivers/mmc/Kconfig2
-rw-r--r--drivers/mmc/Makefile6
-rw-r--r--drivers/mmc/mmc-uclass.c16
-rw-r--r--drivers/mmc/mmc.c16
-rw-r--r--drivers/mmc/mmc_boot.c173
-rw-r--r--drivers/mmc/mmc_write.c11
-rw-r--r--drivers/mmc/msm_sdhci.c10
-rw-r--r--drivers/mmc/sdhci.c6
-rw-r--r--drivers/mmc/sunxi_mmc.c35
-rw-r--r--drivers/mmc/sunxi_mmc.h18
10 files changed, 230 insertions, 63 deletions
diff --git a/drivers/mmc/Kconfig b/drivers/mmc/Kconfig
index 6740591a653..3ea665d974d 100644
--- a/drivers/mmc/Kconfig
+++ b/drivers/mmc/Kconfig
@@ -528,6 +528,7 @@ config SPL_MMC_SDHCI_ADMA
config MMC_SDHCI_ADMA_FORCE_32BIT
bool "Force 32 bit mode for ADMA on 64 bit platforms"
+ depends on MMC_SDHCI_ADMA || SPL_MMC_SDHCI_ADMA
help
This forces SDHCI ADMA to be built for 32 bit descriptors, even
on a 64 bit platform where they would otherwise be assumed to
@@ -537,6 +538,7 @@ config MMC_SDHCI_ADMA_FORCE_32BIT
config MMC_SDHCI_ADMA_64BIT
bool "Use SHDCI ADMA with 64 bit descriptors"
+ depends on MMC_SDHCI_ADMA || SPL_MMC_SDHCI_ADMA
depends on !MMC_SDHCI_ADMA_FORCE_32BIT
default y if DMA_ADDR_T_64BIT
help
diff --git a/drivers/mmc/Makefile b/drivers/mmc/Makefile
index 94ed28ead71..360706f53d2 100644
--- a/drivers/mmc/Makefile
+++ b/drivers/mmc/Makefile
@@ -4,17 +4,17 @@
# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
obj-y += mmc.o
-obj-$(CONFIG_$(XPL_)DM_MMC) += mmc-uclass.o
+obj-$(CONFIG_$(PHASE_)DM_MMC) += mmc-uclass.o
ifdef CONFIG_$(PHASE_)DM_MMC
obj-$(CONFIG_$(PHASE_)BOOTSTD) += mmc_bootdev.o
endif
obj-$(CONFIG_$(PHASE_)MMC_WRITE) += mmc_write.o
-obj-$(CONFIG_$(XPL_)MMC_PWRSEQ) += mmc-pwrseq.o
+obj-$(CONFIG_$(PHASE_)MMC_PWRSEQ) += mmc-pwrseq.o
obj-$(CONFIG_MMC_SDHCI_ADMA_HELPERS) += sdhci-adma.o
-ifndef CONFIG_$(XPL_)BLK
+ifndef CONFIG_$(PHASE_)BLK
obj-y += mmc_legacy.o
endif
diff --git a/drivers/mmc/mmc-uclass.c b/drivers/mmc/mmc-uclass.c
index c8db4f811c2..9af84da1599 100644
--- a/drivers/mmc/mmc-uclass.c
+++ b/drivers/mmc/mmc-uclass.c
@@ -498,22 +498,12 @@ static int mmc_blk_probe(struct udevice *dev)
return ret;
}
- ret = device_probe(dev);
- if (ret) {
- debug("Probing %s failed (err=%d)\n", dev->name, ret);
-
- mmc_deinit(mmc);
-
- return ret;
- }
-
return 0;
}
-static int mmc_blk_remove(struct udevice *dev)
+static int mmc_remove(struct udevice *dev)
{
- struct udevice *mmc_dev = dev_get_parent(dev);
- struct mmc_uclass_priv *upriv = dev_get_uclass_priv(mmc_dev);
+ struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev);
struct mmc *mmc = upriv->mmc;
return mmc_deinit(mmc);
@@ -533,7 +523,6 @@ U_BOOT_DRIVER(mmc_blk) = {
.id = UCLASS_BLK,
.ops = &mmc_blk_ops,
.probe = mmc_blk_probe,
- .remove = mmc_blk_remove,
.flags = DM_FLAG_OS_PREPARE,
};
#endif /* CONFIG_BLK */
@@ -543,4 +532,5 @@ UCLASS_DRIVER(mmc) = {
.name = "mmc",
.flags = DM_UC_FLAG_SEQ_ALIAS,
.per_device_auto = sizeof(struct mmc_uclass_priv),
+ .pre_remove = mmc_remove,
};
diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c
index 31a72366206..47139e0a911 100644
--- a/drivers/mmc/mmc.c
+++ b/drivers/mmc/mmc.c
@@ -3040,9 +3040,9 @@ static int mmc_complete_init(struct mmc *mmc)
return err;
}
-static void __maybe_unused mmc_cyclic_cd_poll(struct cyclic_info *c)
+static void mmc_cyclic_cd_poll(struct cyclic_info *c)
{
- struct mmc *m = CONFIG_IS_ENABLED(CYCLIC, (container_of(c, struct mmc, cyclic)), (NULL));
+ struct mmc *m = container_of(c, struct mmc, cyclic);
if (!m->has_init)
return;
@@ -3073,15 +3073,15 @@ int mmc_init(struct mmc *mmc)
if (!err)
err = mmc_complete_init(mmc);
- if (err)
+ if (err) {
pr_info("%s: %d, time %lu\n", __func__, err, get_timer(start));
+ return err;
+ }
if (CONFIG_IS_ENABLED(CYCLIC, (!mmc->cyclic.func), (NULL))) {
/* Register cyclic function for card detect polling */
- CONFIG_IS_ENABLED(CYCLIC, (cyclic_register(&mmc->cyclic,
- mmc_cyclic_cd_poll,
- 100 * 1000,
- mmc->cfg->name)));
+ cyclic_register(&mmc->cyclic, mmc_cyclic_cd_poll, 100 * 1000,
+ mmc->cfg->name);
}
return err;
@@ -3092,7 +3092,7 @@ int mmc_deinit(struct mmc *mmc)
u32 caps_filtered;
if (CONFIG_IS_ENABLED(CYCLIC, (mmc->cyclic.func), (NULL)))
- CONFIG_IS_ENABLED(CYCLIC, (cyclic_unregister(&mmc->cyclic)));
+ cyclic_unregister(&mmc->cyclic);
if (!CONFIG_IS_ENABLED(MMC_UHS_SUPPORT) &&
!CONFIG_IS_ENABLED(MMC_HS200_SUPPORT) &&
diff --git a/drivers/mmc/mmc_boot.c b/drivers/mmc/mmc_boot.c
index 367c957b518..986e6c500b1 100644
--- a/drivers/mmc/mmc_boot.c
+++ b/drivers/mmc/mmc_boot.c
@@ -8,20 +8,107 @@
#include <mmc.h>
#include "mmc_private.h"
-/*
- * This function changes the size of boot partition and the size of rpmb
- * partition present on EMMC devices.
- *
- * Input Parameters:
- * struct *mmc: pointer for the mmc device strcuture
- * bootsize: size of boot partition
- * rpmbsize: size of rpmb partition
- *
- * Returns 0 on success.
- */
+static int mmc_resize_boot_micron(struct mmc *mmc, unsigned long bootsize,
+ unsigned long rpmbsize)
+{
+ int err;
-int mmc_boot_partition_size_change(struct mmc *mmc, unsigned long bootsize,
- unsigned long rpmbsize)
+ /* Micron eMMC doesn't support resizing RPMB partition */
+ (void)rpmbsize;
+
+ /* BOOT partition size is multiple of 128KB */
+ bootsize = (bootsize * 1024) / 128;
+
+ if (bootsize > 0xff)
+ bootsize = 0xff;
+
+ /* Set EXT_CSD[175] ERASE_GROUP_DEF to 0x01 */
+ err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
+ EXT_CSD_ERASE_GROUP_DEF, 0x01);
+ if (err)
+ goto error;
+
+ /* Set EXT_CSD[127:125] for BOOT partition size, [125] is low byte */
+ err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
+ EXT_CSD_BOOT_SIZE_MULT_MICRON, bootsize);
+ if (err)
+ goto error;
+
+ err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
+ EXT_CSD_BOOT_SIZE_MULT_MICRON + 1, 0x00);
+ if (err)
+ goto error;
+
+ err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
+ EXT_CSD_BOOT_SIZE_MULT_MICRON + 2, 0x00);
+ if (err)
+ goto error;
+
+ /* Set EXT_CSD[155] PARTITION_SETTING_COMPLETE to 0x01 */
+ err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
+ EXT_CSD_PARTITION_SETTING, 0x01);
+ if (err)
+ goto error;
+
+ return 0;
+
+error:
+ debug("%s: Error = %d\n", __func__, err);
+ return err;
+}
+
+static int mmc_resize_boot_sandisk(struct mmc *mmc, unsigned long bootsize,
+ unsigned long rpmbsize)
+{
+ int err;
+ struct mmc_cmd cmd;
+
+ /* BOOT/RPMB partition size is multiple of 128KB */
+ bootsize = (bootsize * 1024) / 128;
+ rpmbsize = (rpmbsize * 1024) / 128;
+
+ if (bootsize > 0xff)
+ bootsize = 0xff;
+
+ if (rpmbsize > 0xff)
+ rpmbsize = 0xff;
+
+ /* Send BOOT/RPMB resize op code */
+ cmd.cmdidx = MMC_CMD_RES_MAN;
+ cmd.resp_type = MMC_RSP_R1b;
+ cmd.cmdarg = MMC_CMD62_ARG_SANDISK;
+
+ err = mmc_send_cmd(mmc, &cmd, NULL);
+ if (err)
+ goto error;
+
+ /* Arg: BOOT partition size */
+ cmd.cmdidx = MMC_CMD_RES_MAN;
+ cmd.resp_type = MMC_RSP_R1b;
+ cmd.cmdarg = bootsize;
+
+ err = mmc_send_cmd(mmc, &cmd, NULL);
+ if (err)
+ goto error;
+
+ /* Arg: RPMB partition size */
+ cmd.cmdidx = MMC_CMD_RES_MAN;
+ cmd.resp_type = MMC_RSP_R1b;
+ cmd.cmdarg = rpmbsize;
+
+ err = mmc_send_cmd(mmc, &cmd, NULL);
+ if (err)
+ goto error;
+
+ return 0;
+
+error:
+ debug("%s: Error = %d\n", __func__, err);
+ return err;
+}
+
+static int mmc_resize_boot_samsung(struct mmc *mmc, unsigned long bootsize,
+ unsigned long rpmbsize)
{
int err;
struct mmc_cmd cmd;
@@ -32,10 +119,8 @@ int mmc_boot_partition_size_change(struct mmc *mmc, unsigned long bootsize,
cmd.cmdarg = MMC_CMD62_ARG1;
err = mmc_send_cmd(mmc, &cmd, NULL);
- if (err) {
- debug("mmc_boot_partition_size_change: Error1 = %d\n", err);
- return err;
- }
+ if (err)
+ goto error;
/* Boot partition changing mode */
cmd.cmdidx = MMC_CMD_RES_MAN;
@@ -43,10 +128,9 @@ int mmc_boot_partition_size_change(struct mmc *mmc, unsigned long bootsize,
cmd.cmdarg = MMC_CMD62_ARG2;
err = mmc_send_cmd(mmc, &cmd, NULL);
- if (err) {
- debug("mmc_boot_partition_size_change: Error2 = %d\n", err);
- return err;
- }
+ if (err)
+ goto error;
+
/* boot partition size is multiple of 128KB */
bootsize = (bootsize * 1024) / 128;
@@ -56,10 +140,9 @@ int mmc_boot_partition_size_change(struct mmc *mmc, unsigned long bootsize,
cmd.cmdarg = bootsize;
err = mmc_send_cmd(mmc, &cmd, NULL);
- if (err) {
- debug("mmc_boot_partition_size_change: Error3 = %d\n", err);
- return err;
- }
+ if (err)
+ goto error;
+
/* RPMB partition size is multiple of 128KB */
rpmbsize = (rpmbsize * 1024) / 128;
/* Arg: RPMB partition size */
@@ -68,11 +151,43 @@ int mmc_boot_partition_size_change(struct mmc *mmc, unsigned long bootsize,
cmd.cmdarg = rpmbsize;
err = mmc_send_cmd(mmc, &cmd, NULL);
- if (err) {
- debug("mmc_boot_partition_size_change: Error4 = %d\n", err);
- return err;
- }
+ if (err)
+ goto error;
+
return 0;
+
+error:
+ debug("%s: Error = %d\n", __func__, err);
+ return err;
+}
+
+/*
+ * This function changes the size of BOOT partition and the size of RPMB
+ * partition present on eMMC devices.
+ *
+ * Input Parameters:
+ * struct *mmc: pointer for the mmc device strcuture
+ * bootsize: size of BOOT partition
+ * rpmbsize: size of RPMB partition
+ *
+ * Returns 0 on success.
+ */
+
+int mmc_boot_partition_size_change(struct mmc *mmc, unsigned long bootsize,
+ unsigned long rpmbsize)
+{
+ switch (mmc->cid[0] >> 24) {
+ case CID_MANFID_MICRON:
+ return mmc_resize_boot_micron(mmc, bootsize, rpmbsize);
+ case CID_MANFID_SAMSUNG:
+ return mmc_resize_boot_samsung(mmc, bootsize, rpmbsize);
+ case CID_MANFID_SANDISK:
+ return mmc_resize_boot_sandisk(mmc, bootsize, rpmbsize);
+ default:
+ printf("Unsupported manufacturer id 0x%02x\n",
+ mmc->cid[0] >> 24);
+ return -EPERM;
+ }
}
/*
diff --git a/drivers/mmc/mmc_write.c b/drivers/mmc/mmc_write.c
index c023d15e52a..90fcf2679bb 100644
--- a/drivers/mmc/mmc_write.c
+++ b/drivers/mmc/mmc_write.c
@@ -80,6 +80,8 @@ ulong mmc_berase(struct blk_desc *block_dev, lbaint_t start, lbaint_t blkcnt)
struct mmc *mmc = find_mmc_device(dev_num);
lbaint_t blk = 0, blk_r = 0;
int timeout_ms = 1000;
+ u32 grpcnt;
+
if (!mmc)
return -1;
@@ -123,6 +125,15 @@ ulong mmc_berase(struct blk_desc *block_dev, lbaint_t start, lbaint_t blkcnt)
} else {
blk_r = ((blkcnt - blk) > mmc->erase_grp_size) ?
mmc->erase_grp_size : (blkcnt - blk);
+
+ grpcnt = (blkcnt - blk) / mmc->erase_grp_size;
+ /* Max 2GB per spec */
+ if ((blkcnt - blk) > 0x400000)
+ blk_r = 0x400000;
+ else if (grpcnt)
+ blk_r = grpcnt * mmc->erase_grp_size;
+ else
+ blk_r = blkcnt - blk;
}
err = mmc_erase_t(mmc, start + blk, blk_r, erase_args);
if (err)
diff --git a/drivers/mmc/msm_sdhci.c b/drivers/mmc/msm_sdhci.c
index 27bb7052fca..ac77fb06bf7 100644
--- a/drivers/mmc/msm_sdhci.c
+++ b/drivers/mmc/msm_sdhci.c
@@ -10,6 +10,7 @@
#include <clk.h>
#include <dm.h>
#include <malloc.h>
+#include <reset.h>
#include <sdhci.h>
#include <wait_bit.h>
#include <asm/global_data.h>
@@ -153,9 +154,18 @@ static int msm_sdc_probe(struct udevice *dev)
const struct msm_sdhc_variant_info *var_info;
struct sdhci_host *host = &prv->host;
u32 core_version, core_minor, core_major;
+ struct reset_ctl bcr_rst;
u32 caps;
int ret;
+ ret = reset_get_by_index(dev, 0, &bcr_rst);
+ if (!ret) {
+ reset_assert(&bcr_rst);
+ udelay(200);
+ reset_deassert(&bcr_rst);
+ udelay(200);
+ }
+
host->quirks = SDHCI_QUIRK_WAIT_SEND_CMD | SDHCI_QUIRK_BROKEN_R1B;
host->max_clk = 0;
diff --git a/drivers/mmc/sdhci.c b/drivers/mmc/sdhci.c
index 4833b5158c7..dc7f0724a7b 100644
--- a/drivers/mmc/sdhci.c
+++ b/drivers/mmc/sdhci.c
@@ -177,8 +177,10 @@ static int sdhci_transfer_data(struct sdhci_host *host, struct mmc_data *data)
} while (!(stat & SDHCI_INT_DATA_END));
#if (CONFIG_IS_ENABLED(MMC_SDHCI_SDMA) || CONFIG_IS_ENABLED(MMC_SDHCI_ADMA))
- dma_unmap_single(host->start_addr, data->blocks * data->blocksize,
- mmc_get_dma_dir(data));
+ if (host->flags & USE_DMA) {
+ dma_unmap_single(host->start_addr, data->blocks * data->blocksize,
+ mmc_get_dma_dir(data));
+ }
#endif
return 0;
diff --git a/drivers/mmc/sunxi_mmc.c b/drivers/mmc/sunxi_mmc.c
index 0b56d1405be..951e6acd34d 100644
--- a/drivers/mmc/sunxi_mmc.c
+++ b/drivers/mmc/sunxi_mmc.c
@@ -92,6 +92,13 @@ static int mmc_set_mod_clk(struct sunxi_mmc_priv *priv, unsigned int hz)
pll = CCM_MMC_CTRL_PLL6;
pll_hz = clock_get_pll6();
#endif
+ /*
+ * On the D1/R528/T113 mux source 1 refers to PLL_PERIPH0(1x),
+ * like for the older SoCs. However we still have the hidden
+ * divider of 2x, so compensate for that here.
+ */
+ if (IS_ENABLED(CONFIG_MACH_SUN8I_R528))
+ pll_hz /= 2;
}
div = pll_hz / hz;
@@ -442,6 +449,26 @@ out:
return error;
}
+static void sunxi_mmc_reset(void *regs)
+{
+ /* Reset controller */
+ writel(SUNXI_MMC_GCTRL_RESET, regs + SUNXI_MMC_GCTRL);
+ udelay(1000);
+
+ if (IS_ENABLED(CONFIG_SUN50I_GEN_H6) || IS_ENABLED(CONFIG_SUNXI_GEN_NCAT2)) {
+ /* Reset card */
+ writel(SUNXI_MMC_HWRST_ASSERT, regs + SUNXI_MMC_HWRST);
+ udelay(10);
+ writel(SUNXI_MMC_HWRST_DEASSERT, regs + SUNXI_MMC_HWRST);
+ udelay(300);
+
+ /* Setup FIFO R/W threshold. Needed on H616. */
+ writel(SUNXI_MMC_THLDC_READ_THLD(512) |
+ SUNXI_MMC_THLDC_WRITE_EN |
+ SUNXI_MMC_THLDC_READ_EN, regs + SUNXI_MMC_THLDC);
+ }
+}
+
/* non-DM code here is used by the (ARM) SPL only */
#if !CONFIG_IS_ENABLED(DM_MMC)
@@ -489,9 +516,7 @@ static int sunxi_mmc_core_init(struct mmc *mmc)
{
struct sunxi_mmc_priv *priv = mmc->priv;
- /* Reset controller */
- writel(SUNXI_MMC_GCTRL_RESET, &priv->reg->gctrl);
- udelay(1000);
+ sunxi_mmc_reset(priv->reg);
return 0;
}
@@ -684,9 +709,7 @@ static int sunxi_mmc_probe(struct udevice *dev)
upriv->mmc = &plat->mmc;
- /* Reset controller */
- writel(SUNXI_MMC_GCTRL_RESET, &priv->reg->gctrl);
- udelay(1000);
+ sunxi_mmc_reset(priv->reg);
return 0;
}
diff --git a/drivers/mmc/sunxi_mmc.h b/drivers/mmc/sunxi_mmc.h
index f4ae5a790c8..71865160319 100644
--- a/drivers/mmc/sunxi_mmc.h
+++ b/drivers/mmc/sunxi_mmc.h
@@ -37,7 +37,9 @@ struct sunxi_mmc {
u32 res0; /* 0x54 reserved */
u32 a12a; /* 0x58 Auto command 12 argument */
u32 ntsr; /* 0x5c New timing set register */
- u32 res1[8];
+ u32 res1[6];
+ u32 hwrst; /* 0x78 Hardware Reset */
+ u32 res5;
u32 dmac; /* 0x80 internal DMA control */
u32 dlba; /* 0x84 internal DMA descr list base address */
u32 idst; /* 0x88 internal DMA status */
@@ -46,7 +48,8 @@ struct sunxi_mmc {
u32 cbda; /* 0x94 */
u32 res2[26];
#if defined(CONFIG_SUNXI_GEN_SUN6I) || defined(CONFIG_SUN50I_GEN_H6) || defined(CONFIG_SUNXI_GEN_NCAT2)
- u32 res3[17];
+ u32 thldc; /* 0x100 Threshold control */
+ u32 res3[16];
u32 samp_dl;
u32 res4[46];
#endif
@@ -57,6 +60,7 @@ struct sunxi_mmc {
#define SUNXI_MMC_CLK_ENABLE (0x1 << 16)
#define SUNXI_MMC_CLK_DIVIDER_MASK (0xff)
+#define SUNXI_MMC_GCTRL 0x000
#define SUNXI_MMC_GCTRL_SOFT_RESET (0x1 << 0)
#define SUNXI_MMC_GCTRL_FIFO_RESET (0x1 << 1)
#define SUNXI_MMC_GCTRL_DMA_RESET (0x1 << 2)
@@ -123,6 +127,10 @@ struct sunxi_mmc {
#define SUNXI_MMC_NTSR_MODE_SEL_NEW (0x1 << 31)
+#define SUNXI_MMC_HWRST 0x078
+#define SUNXI_MMC_HWRST_ASSERT (0x0 << 0)
+#define SUNXI_MMC_HWRST_DEASSERT (0x1 << 0)
+
#define SUNXI_MMC_IDMAC_RESET (0x1 << 0)
#define SUNXI_MMC_IDMAC_FIXBURST (0x1 << 1)
#define SUNXI_MMC_IDMAC_ENABLE (0x1 << 7)
@@ -133,6 +141,12 @@ struct sunxi_mmc {
#define SUNXI_MMC_COMMON_CLK_GATE (1 << 16)
#define SUNXI_MMC_COMMON_RESET (1 << 18)
+#define SUNXI_MMC_THLDC 0x100
+#define SUNXI_MMC_THLDC_READ_EN (0x1 << 0)
+#define SUNXI_MMC_THLDC_BSY_CLR_INT_EN (0x1 << 1)
+#define SUNXI_MMC_THLDC_WRITE_EN (0x1 << 2)
+#define SUNXI_MMC_THLDC_READ_THLD(x) (((x) & 0xfff) << 16)
+
#define SUNXI_MMC_CAL_DL_SW_EN (0x1 << 7)
#endif /* _SUNXI_MMC_H */