summaryrefslogtreecommitdiff
path: root/drivers/mmc
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/mmc')
-rw-r--r--drivers/mmc/Makefile1
-rw-r--r--drivers/mmc/atmel_sdhci.c40
-rw-r--r--drivers/mmc/fsl_esdhc.c9
-rw-r--r--drivers/mmc/gen_atmel_mci.c60
-rw-r--r--drivers/mmc/sdhci.c20
5 files changed, 103 insertions, 27 deletions
diff --git a/drivers/mmc/Makefile b/drivers/mmc/Makefile
index 99d0295..5d35705 100644
--- a/drivers/mmc/Makefile
+++ b/drivers/mmc/Makefile
@@ -8,6 +8,7 @@
obj-$(CONFIG_DM_MMC) += mmc-uclass.o
obj-$(CONFIG_ARM_PL180_MMCI) += arm_pl180_mmci.o
+obj-$(CONFIG_ATMEL_SDHCI) += atmel_sdhci.o
obj-$(CONFIG_BCM2835_SDHCI) += bcm2835_sdhci.o
obj-$(CONFIG_BFIN_SDH) += bfin_sdh.o
obj-$(CONFIG_DAVINCI_MMC) += davinci_mmc.o
diff --git a/drivers/mmc/atmel_sdhci.c b/drivers/mmc/atmel_sdhci.c
new file mode 100644
index 0000000..24b68b6
--- /dev/null
+++ b/drivers/mmc/atmel_sdhci.c
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2015 Atmel Corporation
+ * Wenyou.Yang <wenyou.yang@atmel.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <malloc.h>
+#include <sdhci.h>
+#include <asm/arch/clk.h>
+
+#define ATMEL_SDHC_MIN_FREQ 400000
+
+int atmel_sdhci_init(void *regbase, u32 id)
+{
+ struct sdhci_host *host;
+ u32 max_clk, min_clk = ATMEL_SDHC_MIN_FREQ;
+
+ host = (struct sdhci_host *)calloc(1, sizeof(struct sdhci_host));
+ if (!host) {
+ printf("%s: sdhci_host calloc failed\n", __func__);
+ return -ENOMEM;
+ }
+
+ host->name = "atmel_sdhci";
+ host->ioaddr = regbase;
+ host->quirks = 0;
+ host->version = sdhci_readw(host, SDHCI_HOST_VERSION);
+ max_clk = at91_get_periph_generated_clk(id);
+ if (!max_clk) {
+ printf("%s: Failed to get the proper clock\n", __func__);
+ free(host);
+ return -ENODEV;
+ }
+
+ add_sdhci(host, max_clk, min_clk);
+
+ return 0;
+}
diff --git a/drivers/mmc/fsl_esdhc.c b/drivers/mmc/fsl_esdhc.c
index 471d6ee..c5054d6 100644
--- a/drivers/mmc/fsl_esdhc.c
+++ b/drivers/mmc/fsl_esdhc.c
@@ -106,7 +106,8 @@ static uint esdhc_xfertyp(struct mmc_cmd *cmd, struct mmc_data *data)
xfertyp |= XFERTYP_RSPTYP_48;
#if defined(CONFIG_MX53) || defined(CONFIG_PPC_T4240) || \
- defined(CONFIG_LS102XA) || defined(CONFIG_FSL_LAYERSCAPE)
+ defined(CONFIG_LS102XA) || defined(CONFIG_FSL_LAYERSCAPE) || \
+ defined(CONFIG_PPC_T4160)
if (cmd->cmdidx == MMC_CMD_STOP_TRANSMISSION)
xfertyp |= XFERTYP_CMDTYP_ABORT;
#endif
@@ -747,8 +748,14 @@ void mmc_adapter_card_type_ident(void)
switch (card_id) {
case QIXIS_ESDHC_ADAPTER_TYPE_EMMC45:
+ value = QIXIS_READ(brdcfg[5]);
+ value |= (QIXIS_DAT4 | QIXIS_DAT5_6_7);
+ QIXIS_WRITE(brdcfg[5], value);
break;
case QIXIS_ESDHC_ADAPTER_TYPE_SDMMC_LEGACY:
+ value = QIXIS_READ(pwr_ctl[1]);
+ value |= QIXIS_EVDD_BY_SDHC_VS;
+ QIXIS_WRITE(pwr_ctl[1], value);
break;
case QIXIS_ESDHC_ADAPTER_TYPE_EMMC44:
value = QIXIS_READ(brdcfg[5]);
diff --git a/drivers/mmc/gen_atmel_mci.c b/drivers/mmc/gen_atmel_mci.c
index 45bcffb..da870c6 100644
--- a/drivers/mmc/gen_atmel_mci.c
+++ b/drivers/mmc/gen_atmel_mci.c
@@ -32,7 +32,11 @@
# define MCI_BUS 0
#endif
-static int initialized = 0;
+struct atmel_mci_priv {
+ struct mmc_config cfg;
+ struct atmel_mci *mci;
+ unsigned int initialized:1;
+};
/* Read Atmel MCI IP version */
static unsigned int atmel_mci_get_version(struct atmel_mci *mci)
@@ -48,14 +52,15 @@ static unsigned int atmel_mci_get_version(struct atmel_mci *mci)
*/
static void dump_cmd(u32 cmdr, u32 arg, u32 status, const char* msg)
{
- printf("gen_atmel_mci: CMDR %08x (%2u) ARGR %08x (SR: %08x) %s\n",
- cmdr, cmdr&0x3F, arg, status, msg);
+ debug("gen_atmel_mci: CMDR %08x (%2u) ARGR %08x (SR: %08x) %s\n",
+ cmdr, cmdr & 0x3F, arg, status, msg);
}
/* Setup for MCI Clock and Block Size */
static void mci_set_mode(struct mmc *mmc, u32 hz, u32 blklen)
{
- atmel_mci_t *mci = mmc->priv;
+ struct atmel_mci_priv *priv = mmc->priv;
+ atmel_mci_t *mci = priv->mci;
u32 bus_hz = get_mci_clk_rate();
u32 clkdiv = 255;
unsigned int version = atmel_mci_get_version(mci);
@@ -73,16 +78,16 @@ static void mci_set_mode(struct mmc *mmc, u32 hz, u32 blklen)
clkodd = clkdiv & 1;
clkdiv >>= 1;
- printf("mci: setting clock %u Hz, block size %u\n",
- bus_hz / (clkdiv * 2 + clkodd + 2), blklen);
+ debug("mci: setting clock %u Hz, block size %u\n",
+ bus_hz / (clkdiv * 2 + clkodd + 2), blklen);
} else {
/* find clkdiv yielding a rate <= than requested */
for (clkdiv = 0; clkdiv < 255; clkdiv++) {
if ((bus_hz / (clkdiv + 1) / 2) <= hz)
break;
}
- printf("mci: setting clock %u Hz, block size %u\n",
- (bus_hz / (clkdiv + 1)) / 2, blklen);
+ debug("mci: setting clock %u Hz, block size %u\n",
+ (bus_hz / (clkdiv + 1)) / 2, blklen);
}
}
@@ -113,7 +118,9 @@ static void mci_set_mode(struct mmc *mmc, u32 hz, u32 blklen)
if (mmc->card_caps & mmc->cfg->host_caps & MMC_MODE_HS)
writel(MMCI_BIT(HSMODE), &mci->cfg);
- initialized = 1;
+ udelay(50);
+
+ priv->initialized = 1;
}
/* Return the CMDR with flags for a given command and data packet */
@@ -196,12 +203,13 @@ io_fail:
static int
mci_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data)
{
- atmel_mci_t *mci = mmc->priv;
+ struct atmel_mci_priv *priv = mmc->priv;
+ atmel_mci_t *mci = priv->mci;
u32 cmdr;
u32 error_flags = 0;
u32 status;
- if (!initialized) {
+ if (!priv->initialized) {
puts ("MCI not initialized!\n");
return COMM_ERR;
}
@@ -321,7 +329,8 @@ mci_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data)
/* Entered into mmc structure during driver init */
static void mci_set_ios(struct mmc *mmc)
{
- atmel_mci_t *mci = mmc->priv;
+ struct atmel_mci_priv *priv = mmc->priv;
+ atmel_mci_t *mci = priv->mci;
int bus_width = mmc->bus_width;
unsigned int version = atmel_mci_get_version(mci);
int busw;
@@ -357,7 +366,8 @@ static void mci_set_ios(struct mmc *mmc)
/* Entered into mmc structure during driver init */
static int mci_init(struct mmc *mmc)
{
- atmel_mci_t *mci = mmc->priv;
+ struct atmel_mci_priv *priv = mmc->priv;
+ atmel_mci_t *mci = priv->mci;
/* Initialize controller */
writel(MMCI_BIT(SWRST), &mci->cr); /* soft reset */
@@ -391,22 +401,24 @@ int atmel_mci_init(void *regs)
{
struct mmc *mmc;
struct mmc_config *cfg;
- struct atmel_mci *mci;
+ struct atmel_mci_priv *priv;
unsigned int version;
- cfg = malloc(sizeof(*cfg));
- if (cfg == NULL)
- return -1;
- memset(cfg, 0, sizeof(*cfg));
+ priv = calloc(1, sizeof(*priv));
+ if (!priv)
+ return -ENOMEM;
- mci = (struct atmel_mci *)regs;
+ cfg = &priv->cfg;
cfg->name = "mci";
cfg->ops = &atmel_mci_ops;
+ priv->mci = (struct atmel_mci *)regs;
+ priv->initialized = 0;
+
/* need to be able to pass these in on a board by board basis */
cfg->voltages = MMC_VDD_32_33 | MMC_VDD_33_34;
- version = atmel_mci_get_version(mci);
+ version = atmel_mci_get_version(priv->mci);
if ((version & 0xf00) >= 0x300) {
cfg->host_caps = MMC_MODE_8BIT;
cfg->host_caps |= MMC_MODE_HS | MMC_MODE_HS_52MHz;
@@ -423,13 +435,13 @@ int atmel_mci_init(void *regs)
cfg->b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT;
- mmc = mmc_create(cfg, regs);
+ mmc = mmc_create(cfg, priv);
if (mmc == NULL) {
- free(cfg);
- return -1;
+ free(priv);
+ return -ENODEV;
}
- /* NOTE: possibly leaking the cfg structure */
+ /* NOTE: possibly leaking the priv structure */
return 0;
}
diff --git a/drivers/mmc/sdhci.c b/drivers/mmc/sdhci.c
index d89e302..02d71b9 100644
--- a/drivers/mmc/sdhci.c
+++ b/drivers/mmc/sdhci.c
@@ -286,9 +286,25 @@ static int sdhci_send_command(struct mmc *mmc, struct mmc_cmd *cmd,
static int sdhci_set_clock(struct mmc *mmc, unsigned int clock)
{
struct sdhci_host *host = mmc->priv;
- unsigned int div, clk, timeout;
+ unsigned int div, clk, timeout, reg;
- sdhci_writew(host, 0, SDHCI_CLOCK_CONTROL);
+ /* Wait max 20 ms */
+ timeout = 200;
+ while (sdhci_readl(host, SDHCI_PRESENT_STATE) &
+ (SDHCI_CMD_INHIBIT | SDHCI_DATA_INHIBIT)) {
+ if (timeout == 0) {
+ printf("%s: Timeout to wait cmd & data inhibit\n",
+ __func__);
+ return -1;
+ }
+
+ timeout--;
+ udelay(100);
+ }
+
+ reg = sdhci_readw(host, SDHCI_CLOCK_CONTROL);
+ reg &= ~SDHCI_CLOCK_CARD_EN;
+ sdhci_writew(host, reg, SDHCI_CLOCK_CONTROL);
if (clock == 0)
return 0;