diff options
Diffstat (limited to 'drivers/mmc')
-rw-r--r-- | drivers/mmc/Kconfig | 18 | ||||
-rw-r--r-- | drivers/mmc/fsl_esdhc.c | 31 | ||||
-rw-r--r-- | drivers/mmc/fsl_esdhc_imx.c | 53 | ||||
-rw-r--r-- | drivers/mmc/mmc-uclass.c | 12 | ||||
-rw-r--r-- | drivers/mmc/mmc.c | 8 | ||||
-rw-r--r-- | drivers/mmc/mvebu_mmc.c | 307 | ||||
-rw-r--r-- | drivers/mmc/pci_mmc.c | 6 |
7 files changed, 276 insertions, 159 deletions
diff --git a/drivers/mmc/Kconfig b/drivers/mmc/Kconfig index f8ca52efb6b..d862d1e2024 100644 --- a/drivers/mmc/Kconfig +++ b/drivers/mmc/Kconfig @@ -311,6 +311,7 @@ config MMC_MXS config MMC_PCI bool "Support for MMC controllers on PCI" + depends on MMC_SDHCI help This selects PCI-based MMC controllers. If you have an MMC controller on a PCI bus, say Y here. @@ -326,6 +327,15 @@ config MMC_OCTEONTX If unsure, say N. +config MVEBU_MMC + bool "Kirkwood MMC controller support" + depends on DM_MMC && BLK && ARCH_KIRKWOOD + help + Support for MMC host controller on Kirkwood SoCs. + If you are on a Kirkwood architecture, say Y here. + + If unsure, say N. + config PXA_MMC_GENERIC bool "Support for MMC controllers on PXA" help @@ -794,7 +804,7 @@ config FSL_ESDHC_IMX config FSL_USDHC bool "Freescale/NXP i.MX uSDHC controller support" - depends on MX6 || MX7 ||ARCH_MX7ULP || IMX8 || IMX8M || IMXRT || TARGET_S32V234EVB + depends on MX6 || MX7 ||ARCH_MX7ULP || IMX8 || IMX8M || IMXRT select FSL_ESDHC_IMX help This enables the Ultra Secured Digital Host Controller enhancements @@ -812,3 +822,9 @@ config SYS_FSL_ERRATUM_ESDHC135 config SYS_FSL_ERRATUM_ESDHC_A001 bool + +config SYS_FSL_ERRATUM_A011334 + bool + +config SYS_FSL_ESDHC_UNRELIABLE_PULSE_DETECTION_WORKAROUND + bool diff --git a/drivers/mmc/fsl_esdhc.c b/drivers/mmc/fsl_esdhc.c index 6014e1c5cac..7501fdb71e1 100644 --- a/drivers/mmc/fsl_esdhc.c +++ b/drivers/mmc/fsl_esdhc.c @@ -71,7 +71,8 @@ struct fsl_esdhc { uint sdtimingctl; /* SD timing control register */ char reserved8[20]; /* reserved */ uint dllcfg0; /* DLL config 0 register */ - char reserved9[12]; /* reserved */ + uint dllcfg1; /* DLL config 1 register */ + char reserved9[8]; /* reserved */ uint dllstat0; /* DLL status 0 register */ char reserved10[664];/* reserved */ uint esdhcctl; /* eSDHC control register */ @@ -518,6 +519,24 @@ static void set_sysctl(struct fsl_esdhc_priv *priv, struct mmc *mmc, uint clock) while (sdhc_clk / (div * pre_div) > clock && div < 16) div++; + if (IS_ENABLED(CONFIG_SYS_FSL_ERRATUM_A011334) && + clock == 200000000 && mmc->selected_mode == MMC_HS_400) { + u32 div_ratio = pre_div * div; + + if (div_ratio <= 4) { + pre_div = 4; + div = 1; + } else if (div_ratio <= 8) { + pre_div = 4; + div = 2; + } else if (div_ratio <= 12) { + pre_div = 4; + div = 3; + } else { + printf("unsupported clock division.\n"); + } + } + mmc->clock = sdhc_clk / pre_div / div; priv->clock = mmc->clock; @@ -749,6 +768,9 @@ static int esdhc_init_common(struct fsl_esdhc_priv *priv, struct mmc *mmc) /* Set timout to the maximum value */ esdhc_clrsetbits32(®s->sysctl, SYSCTL_TIMEOUT_MASK, 14 << 16); + if (IS_ENABLED(CONFIG_SYS_FSL_ESDHC_UNRELIABLE_PULSE_DETECTION_WORKAROUND)) + esdhc_clrbits32(®s->dllcfg1, DLL_PD_PULSE_STRETCH_SEL); + return 0; } @@ -1063,9 +1085,14 @@ static int fsl_esdhc_execute_tuning(struct udevice *dev, uint32_t opcode) struct fsl_esdhc_plat *plat = dev_get_plat(dev); struct fsl_esdhc_priv *priv = dev_get_priv(dev); struct fsl_esdhc *regs = priv->esdhc_regs; + struct mmc *mmc = &plat->mmc; u32 val, irqstaten; int i; + if (IS_ENABLED(CONFIG_SYS_FSL_ERRATUM_A011334) && + plat->mmc.hs400_tuning) + set_sysctl(priv, mmc, mmc->clock); + esdhc_tuning_block_enable(priv, true); esdhc_setbits32(®s->autoc12err, EXECUTE_TUNING); @@ -1073,7 +1100,7 @@ static int fsl_esdhc_execute_tuning(struct udevice *dev, uint32_t opcode) esdhc_write32(®s->irqstaten, IRQSTATEN_BRR); for (i = 0; i < MAX_TUNING_LOOP; i++) { - mmc_send_tuning(&plat->mmc, opcode, NULL); + mmc_send_tuning(mmc, opcode, NULL); mdelay(1); val = esdhc_read32(®s->autoc12err); diff --git a/drivers/mmc/fsl_esdhc_imx.c b/drivers/mmc/fsl_esdhc_imx.c index 6a9403dc004..a4675838e58 100644 --- a/drivers/mmc/fsl_esdhc_imx.c +++ b/drivers/mmc/fsl_esdhc_imx.c @@ -146,6 +146,7 @@ struct esdhc_soc_data { * @start_tuning_tap: the start point for tuning in tuning_ctrl register * @strobe_dll_delay_target: settings in strobe_dllctrl * @signal_voltage: indicating the current voltage + * @signal_voltage_switch_extra_delay_ms: extra delay for IO voltage switch * @cd_gpio: gpio for card detection * @wp_gpio: gpio for write protection */ @@ -170,6 +171,7 @@ struct fsl_esdhc_priv { u32 tuning_start_tap; u32 strobe_dll_delay_target; u32 signal_voltage; + u32 signal_voltage_switch_extra_delay_ms; #if CONFIG_IS_ENABLED(DM_REGULATOR) struct udevice *vqmmc_dev; struct udevice *vmmc_dev; @@ -521,15 +523,6 @@ static int esdhc_send_cmd_common(struct fsl_esdhc_priv *priv, struct mmc *mmc, goto out; } - /* Switch voltage to 1.8V if CMD11 succeeded */ - if (cmd->cmdidx == SD_CMD_SWITCH_UHS18V) { - esdhc_setbits32(®s->vendorspec, ESDHC_VENDORSPEC_VSELECT); - - printf("Run CMD11 1.8V switch\n"); - /* Sleep for 5 ms - max time for card to switch to 1.8V */ - udelay(5000); - } - /* Workaround for ESDHC errata ENGcm03648 */ if (!data && (cmd->resp_type & MMC_RSP_BUSY)) { int timeout = 50000; @@ -660,7 +653,10 @@ static void set_sysctl(struct fsl_esdhc_priv *priv, struct mmc *mmc, uint clock) clk = (pre_div << 8) | (div << 4); #ifdef CONFIG_FSL_USDHC - esdhc_clrbits32(®s->vendorspec, VENDORSPEC_CKEN); + esdhc_clrbits32(®s->vendorspec, VENDORSPEC_FRC_SDCLK_ON); + ret = readx_poll_timeout(esdhc_read32, ®s->prsstat, tmp, tmp & PRSSTAT_SDOFF, 100); + if (ret) + pr_warn("fsl_esdhc_imx: Internal clock never gate off.\n"); #else esdhc_clrbits32(®s->sysctl, SYSCTL_CKEN); #endif @@ -672,7 +668,7 @@ static void set_sysctl(struct fsl_esdhc_priv *priv, struct mmc *mmc, uint clock) pr_warn("fsl_esdhc_imx: Internal clock never stabilised.\n"); #ifdef CONFIG_FSL_USDHC - esdhc_setbits32(®s->vendorspec, VENDORSPEC_PEREN | VENDORSPEC_CKEN); + esdhc_setbits32(®s->vendorspec, VENDORSPEC_FRC_SDCLK_ON); #else esdhc_setbits32(®s->sysctl, SYSCTL_PEREN | SYSCTL_CKEN); #endif @@ -727,8 +723,14 @@ static void esdhc_set_strobe_dll(struct mmc *mmc) struct fsl_esdhc_priv *priv = dev_get_priv(mmc->dev); struct fsl_esdhc *regs = priv->esdhc_regs; u32 val; + u32 tmp; + int ret; if (priv->clock > ESDHC_STROBE_DLL_CLK_FREQ) { + esdhc_clrbits32(®s->vendorspec, VENDORSPEC_FRC_SDCLK_ON); + ret = readx_poll_timeout(esdhc_read32, ®s->prsstat, tmp, tmp & PRSSTAT_SDOFF, 100); + if (ret) + pr_warn("fsl_esdhc_imx: Internal clock never gate off.\n"); esdhc_write32(®s->strobe_dllctrl, ESDHC_STROBE_DLL_CTRL_RESET); /* @@ -746,6 +748,7 @@ static void esdhc_set_strobe_dll(struct mmc *mmc) pr_warn("HS400 strobe DLL status REF not lock!\n"); if (!(val & ESDHC_STROBE_DLL_STS_SLV_LOCK)) pr_warn("HS400 strobe DLL status SLV not lock!\n"); + esdhc_setbits32(®s->vendorspec, VENDORSPEC_FRC_SDCLK_ON); } } @@ -835,6 +838,14 @@ static int esdhc_set_voltage(struct mmc *mmc) } #endif esdhc_setbits32(®s->vendorspec, ESDHC_VENDORSPEC_VSELECT); + /* + * some board like imx8mm-evk need about 18ms to switch + * the IO voltage from 3.3v to 1.8v, common code only + * delay 10ms, so need to delay extra time to make sure + * the IO voltage change to 1.8v. + */ + if (priv->signal_voltage_switch_extra_delay_ms) + mdelay(priv->signal_voltage_switch_extra_delay_ms); if (esdhc_read32(®s->vendorspec) & ESDHC_VENDORSPEC_VSELECT) return 0; @@ -969,14 +980,18 @@ static int esdhc_set_ios_common(struct fsl_esdhc_priv *priv, struct mmc *mmc) #ifdef MMC_SUPPORTS_TUNING if (mmc->clk_disable) { #ifdef CONFIG_FSL_USDHC - esdhc_clrbits32(®s->vendorspec, VENDORSPEC_CKEN); + u32 tmp; + + esdhc_clrbits32(®s->vendorspec, VENDORSPEC_FRC_SDCLK_ON); + ret = readx_poll_timeout(esdhc_read32, ®s->prsstat, tmp, tmp & PRSSTAT_SDOFF, 100); + if (ret) + pr_warn("fsl_esdhc_imx: Internal clock never gate off.\n"); #else esdhc_clrbits32(®s->sysctl, SYSCTL_CKEN); #endif } else { #ifdef CONFIG_FSL_USDHC - esdhc_setbits32(®s->vendorspec, VENDORSPEC_PEREN | - VENDORSPEC_CKEN); + esdhc_setbits32(®s->vendorspec, VENDORSPEC_FRC_SDCLK_ON); #else esdhc_setbits32(®s->sysctl, SYSCTL_PEREN | SYSCTL_CKEN); #endif @@ -1052,7 +1067,7 @@ static int esdhc_init_common(struct fsl_esdhc_priv *priv, struct mmc *mmc) #ifndef CONFIG_FSL_USDHC esdhc_setbits32(®s->sysctl, SYSCTL_HCKEN | SYSCTL_IPGEN); #else - esdhc_setbits32(®s->vendorspec, VENDORSPEC_HCKEN | VENDORSPEC_IPGEN); + esdhc_setbits32(®s->vendorspec, VENDORSPEC_FRC_SDCLK_ON); #endif /* Set the initial clock speed */ @@ -1190,8 +1205,7 @@ static int fsl_esdhc_init(struct fsl_esdhc_priv *priv, esdhc_write32(®s->autoc12err, 0); esdhc_write32(®s->clktunectrlstatus, 0); #else - esdhc_setbits32(®s->vendorspec, VENDORSPEC_PEREN | - VENDORSPEC_HCKEN | VENDORSPEC_IPGEN | VENDORSPEC_CKEN); + esdhc_setbits32(®s->vendorspec, VENDORSPEC_FRC_SDCLK_ON); #endif if (priv->vs18_enable) @@ -1446,6 +1460,8 @@ static int fsl_esdhc_of_to_plat(struct udevice *dev) val = fdtdec_get_int(fdt, node, "fsl,strobe-dll-delay-target", ESDHC_STROBE_DLL_CTRL_SLV_DLY_TARGET_DEFAULT); priv->strobe_dll_delay_target = val; + val = fdtdec_get_int(fdt, node, "fsl,signal-voltage-switch-extra-delay-ms", 0); + priv->signal_voltage_switch_extra_delay_ms = val; if (dev_read_bool(dev, "broken-cd")) priv->broken_cd = 1; @@ -1530,8 +1546,7 @@ static int fsl_esdhc_probe(struct udevice *dev) if (CONFIG_IS_ENABLED(DM_GPIO) && !priv->non_removable) { struct udevice *gpiodev; - ret = device_get_by_driver_info_idx(dtplat->cd_gpios->idx, - &gpiodev); + ret = device_get_by_ofplat_idx(dtplat->cd_gpios->idx, &gpiodev); if (ret) return ret; diff --git a/drivers/mmc/mmc-uclass.c b/drivers/mmc/mmc-uclass.c index 53eabc9e612..d36aae367e7 100644 --- a/drivers/mmc/mmc-uclass.c +++ b/drivers/mmc/mmc-uclass.c @@ -383,18 +383,16 @@ int mmc_bind(struct udevice *dev, struct mmc *mmc, const struct mmc_config *cfg) { struct blk_desc *bdesc; struct udevice *bdev; - int ret, devnum = -1; + int ret; if (!mmc_get_ops(dev)) return -ENOSYS; -#ifndef CONFIG_SPL_BUILD - /* Use the fixed index with aliase node's index */ - ret = dev_read_alias_seq(dev, &devnum); - debug("%s: alias ret=%d, devnum=%d\n", __func__, ret, devnum); -#endif + + /* Use the fixed index with aliases node's index */ + debug("%s: alias devnum=%d\n", __func__, dev_seq(dev)); ret = blk_create_devicef(dev, "mmc_blk", "blk", IF_TYPE_MMC, - devnum, 512, 0, &bdev); + dev_seq(dev), 512, 0, &bdev); if (ret) { debug("Cannot create block device\n"); return ret; diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c index b4c8e7f293b..1e83007286b 100644 --- a/drivers/mmc/mmc.c +++ b/drivers/mmc/mmc.c @@ -3052,9 +3052,11 @@ int mmc_init_device(int num) struct mmc *m; int ret; - ret = uclass_get_device(UCLASS_MMC, num, &dev); - if (ret) - return ret; + if (uclass_get_device_by_seq(UCLASS_MMC, num, &dev)) { + ret = uclass_get_device(UCLASS_MMC, num, &dev); + if (ret) + return ret; + } m = mmc_get_mmc_dev(dev); if (!m) diff --git a/drivers/mmc/mvebu_mmc.c b/drivers/mmc/mvebu_mmc.c index 8ec1f57a1b7..fea55c61ed7 100644 --- a/drivers/mmc/mvebu_mmc.c +++ b/drivers/mmc/mvebu_mmc.c @@ -11,60 +11,67 @@ #include <errno.h> #include <log.h> #include <malloc.h> +#include <dm.h> +#include <fdtdec.h> #include <part.h> #include <mmc.h> -#include <asm/global_data.h> #include <asm/io.h> #include <asm/arch/cpu.h> #include <asm/arch/soc.h> #include <mvebu_mmc.h> - -DECLARE_GLOBAL_DATA_PTR; - -#define DRIVER_NAME "MVEBU_MMC" +#include <dm/device_compat.h> #define MVEBU_TARGET_DRAM 0 #define TIMEOUT_DELAY 5*CONFIG_SYS_HZ /* wait 5 seconds */ -static void mvebu_mmc_write(u32 offs, u32 val) +static inline void *get_regbase(const struct mmc *mmc) { - writel(val, CONFIG_SYS_MMC_BASE + (offs)); + struct mvebu_mmc_plat *pdata = mmc->priv; + + return pdata->iobase; } -static u32 mvebu_mmc_read(u32 offs) +static void mvebu_mmc_write(const struct mmc *mmc, u32 offs, u32 val) { - return readl(CONFIG_SYS_MMC_BASE + (offs)); + writel(val, get_regbase(mmc) + (offs)); } -static int mvebu_mmc_setup_data(struct mmc_data *data) +static u32 mvebu_mmc_read(const struct mmc *mmc, u32 offs) { + return readl(get_regbase(mmc) + (offs)); +} + +static int mvebu_mmc_setup_data(struct udevice *dev, struct mmc_data *data) +{ + struct mvebu_mmc_plat *pdata = dev_get_plat(dev); + struct mmc *mmc = &pdata->mmc; u32 ctrl_reg; - debug("%s, data %s : blocks=%d blksz=%d\n", DRIVER_NAME, - (data->flags & MMC_DATA_READ) ? "read" : "write", - data->blocks, data->blocksize); + dev_dbg(dev, "data %s : blocks=%d blksz=%d\n", + (data->flags & MMC_DATA_READ) ? "read" : "write", + data->blocks, data->blocksize); /* default to maximum timeout */ - ctrl_reg = mvebu_mmc_read(SDIO_HOST_CTRL); + ctrl_reg = mvebu_mmc_read(mmc, SDIO_HOST_CTRL); ctrl_reg |= SDIO_HOST_CTRL_TMOUT(SDIO_HOST_CTRL_TMOUT_MAX); - mvebu_mmc_write(SDIO_HOST_CTRL, ctrl_reg); + mvebu_mmc_write(mmc, SDIO_HOST_CTRL, ctrl_reg); if (data->flags & MMC_DATA_READ) { - mvebu_mmc_write(SDIO_SYS_ADDR_LOW, (u32)data->dest & 0xffff); - mvebu_mmc_write(SDIO_SYS_ADDR_HI, (u32)data->dest >> 16); + mvebu_mmc_write(mmc, SDIO_SYS_ADDR_LOW, (u32)data->dest & 0xffff); + mvebu_mmc_write(mmc, SDIO_SYS_ADDR_HI, (u32)data->dest >> 16); } else { - mvebu_mmc_write(SDIO_SYS_ADDR_LOW, (u32)data->src & 0xffff); - mvebu_mmc_write(SDIO_SYS_ADDR_HI, (u32)data->src >> 16); + mvebu_mmc_write(mmc, SDIO_SYS_ADDR_LOW, (u32)data->src & 0xffff); + mvebu_mmc_write(mmc, SDIO_SYS_ADDR_HI, (u32)data->src >> 16); } - mvebu_mmc_write(SDIO_BLK_COUNT, data->blocks); - mvebu_mmc_write(SDIO_BLK_SIZE, data->blocksize); + mvebu_mmc_write(mmc, SDIO_BLK_COUNT, data->blocks); + mvebu_mmc_write(mmc, SDIO_BLK_SIZE, data->blocksize); return 0; } -static int mvebu_mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, +static int mvebu_mmc_send_cmd(struct udevice *dev, struct mmc_cmd *cmd, struct mmc_data *data) { ulong start; @@ -72,12 +79,14 @@ static int mvebu_mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, ushort resptype = 0; ushort xfertype = 0; ushort resp_indx = 0; + struct mvebu_mmc_plat *pdata = dev_get_plat(dev); + struct mmc *mmc = &pdata->mmc; - debug("%s: cmdidx [0x%x] resp_type[0x%x] cmdarg[0x%x]\n", - DRIVER_NAME, cmd->cmdidx, cmd->resp_type, cmd->cmdarg); + dev_dbg(dev, "cmdidx [0x%x] resp_type[0x%x] cmdarg[0x%x]\n", + cmd->cmdidx, cmd->resp_type, cmd->cmdarg); - debug("%s: cmd %d (hw state 0x%04x)\n", DRIVER_NAME, - cmd->cmdidx, mvebu_mmc_read(SDIO_HW_STATE)); + dev_dbg(dev, "cmd %d (hw state 0x%04x)\n", + cmd->cmdidx, mvebu_mmc_read(mmc, SDIO_HW_STATE)); /* * Hardware weirdness. The FIFO_EMPTY bit of the HW_STATE @@ -88,26 +97,26 @@ static int mvebu_mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, * this bit comes to good sense (which eventually happens by * itself) then the new transfer simply fails with a timeout. */ - if (!(mvebu_mmc_read(SDIO_HW_STATE) & CMD_FIFO_EMPTY)) { + if (!(mvebu_mmc_read(mmc, SDIO_HW_STATE) & CMD_FIFO_EMPTY)) { ushort hw_state, count = 0; start = get_timer(0); do { - hw_state = mvebu_mmc_read(SDIO_HW_STATE); + hw_state = mvebu_mmc_read(mmc, SDIO_HW_STATE); if ((get_timer(0) - start) > TIMEOUT_DELAY) { printf("%s : FIFO_EMPTY bit missing\n", - DRIVER_NAME); + dev->name); break; } count++; } while (!(hw_state & CMD_FIFO_EMPTY)); - debug("%s *** wait for FIFO_EMPTY bit (hw=0x%04x, count=%d, jiffies=%ld)\n", - DRIVER_NAME, hw_state, count, (get_timer(0) - (start))); + dev_dbg(dev, "*** wait for FIFO_EMPTY bit (hw=0x%04x, count=%d, jiffies=%ld)\n", + hw_state, count, (get_timer(0) - (start))); } /* Clear status */ - mvebu_mmc_write(SDIO_NOR_INTR_STATUS, SDIO_POLL_MASK); - mvebu_mmc_write(SDIO_ERR_INTR_STATUS, SDIO_POLL_MASK); + mvebu_mmc_write(mmc, SDIO_NOR_INTR_STATUS, SDIO_POLL_MASK); + mvebu_mmc_write(mmc, SDIO_ERR_INTR_STATUS, SDIO_POLL_MASK); resptype = SDIO_CMD_INDEX(cmd->cmdidx); @@ -133,11 +142,10 @@ static int mvebu_mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, } if (data) { - int err = mvebu_mmc_setup_data(data); + int err = mvebu_mmc_setup_data(dev, data); if (err) { - debug("%s: command DATA error :%x\n", - DRIVER_NAME, err); + dev_dbg(dev, "command DATA error :%x\n", err); return err; } @@ -154,34 +162,33 @@ static int mvebu_mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, } /* Setting cmd arguments */ - mvebu_mmc_write(SDIO_ARG_LOW, cmd->cmdarg & 0xffff); - mvebu_mmc_write(SDIO_ARG_HI, cmd->cmdarg >> 16); + mvebu_mmc_write(mmc, SDIO_ARG_LOW, cmd->cmdarg & 0xffff); + mvebu_mmc_write(mmc, SDIO_ARG_HI, cmd->cmdarg >> 16); /* Setting Xfer mode */ - mvebu_mmc_write(SDIO_XFER_MODE, xfertype); + mvebu_mmc_write(mmc, SDIO_XFER_MODE, xfertype); /* Sending command */ - mvebu_mmc_write(SDIO_CMD, resptype); + mvebu_mmc_write(mmc, SDIO_CMD, resptype); start = get_timer(0); - while (!((mvebu_mmc_read(SDIO_NOR_INTR_STATUS)) & waittype)) { - if (mvebu_mmc_read(SDIO_NOR_INTR_STATUS) & SDIO_NOR_ERROR) { - debug("%s: error! cmdidx : %d, err reg: %04x\n", - DRIVER_NAME, cmd->cmdidx, - mvebu_mmc_read(SDIO_ERR_INTR_STATUS)); - if (mvebu_mmc_read(SDIO_ERR_INTR_STATUS) & + while (!((mvebu_mmc_read(mmc, SDIO_NOR_INTR_STATUS)) & waittype)) { + if (mvebu_mmc_read(mmc, SDIO_NOR_INTR_STATUS) & SDIO_NOR_ERROR) { + dev_dbg(dev, "error! cmdidx : %d, err reg: %04x\n", + cmd->cmdidx, + mvebu_mmc_read(mmc, SDIO_ERR_INTR_STATUS)); + if (mvebu_mmc_read(mmc, SDIO_ERR_INTR_STATUS) & (SDIO_ERR_CMD_TIMEOUT | SDIO_ERR_DATA_TIMEOUT)) { - debug("%s: command READ timed out\n", - DRIVER_NAME); + dev_dbg(dev, "command READ timed out\n"); return -ETIMEDOUT; } - debug("%s: command READ error\n", DRIVER_NAME); + dev_dbg(dev, "command READ error\n"); return -ECOMM; } if ((get_timer(0) - start) > TIMEOUT_DELAY) { - debug("%s: command timed out\n", DRIVER_NAME); + dev_dbg(dev, "command timed out\n"); return -ETIMEDOUT; } } @@ -191,8 +198,7 @@ static int mvebu_mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, uint response[8]; for (resp_indx = 0; resp_indx < 8; resp_indx++) - response[resp_indx] - = mvebu_mmc_read(SDIO_RSP(resp_indx)); + response[resp_indx] = mvebu_mmc_read(mmc, SDIO_RSP(resp_indx)); cmd->response[0] = ((response[0] & 0x03ff) << 22) | ((response[1] & 0xffff) << 6) | @@ -209,8 +215,7 @@ static int mvebu_mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, uint response[3]; for (resp_indx = 0; resp_indx < 3; resp_indx++) - response[resp_indx] - = mvebu_mmc_read(SDIO_RSP(resp_indx)); + response[resp_indx] = mvebu_mmc_read(mmc, SDIO_RSP(resp_indx)); cmd->response[0] = ((response[2] & 0x003f) << (8 - 8)) | ((response[1] & 0xffff) << (14 - 8)) | @@ -225,64 +230,71 @@ static int mvebu_mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, cmd->response[3] = 0; } - debug("%s: resp[0x%x] ", DRIVER_NAME, cmd->resp_type); + dev_dbg(dev, "resp[0x%x] ", cmd->resp_type); debug("[0x%x] ", cmd->response[0]); debug("[0x%x] ", cmd->response[1]); debug("[0x%x] ", cmd->response[2]); debug("[0x%x] ", cmd->response[3]); debug("\n"); - if (mvebu_mmc_read(SDIO_ERR_INTR_STATUS) & + if (mvebu_mmc_read(mmc, SDIO_ERR_INTR_STATUS) & (SDIO_ERR_CMD_TIMEOUT | SDIO_ERR_DATA_TIMEOUT)) return -ETIMEDOUT; return 0; } -static void mvebu_mmc_power_up(void) +static void mvebu_mmc_power_up(struct udevice *dev) { - debug("%s: power up\n", DRIVER_NAME); + struct mvebu_mmc_plat *pdata = dev_get_plat(dev); + struct mmc *mmc = &pdata->mmc; + + dev_dbg(dev, "power up\n"); /* disable interrupts */ - mvebu_mmc_write(SDIO_NOR_INTR_EN, 0); - mvebu_mmc_write(SDIO_ERR_INTR_EN, 0); + mvebu_mmc_write(mmc, SDIO_NOR_INTR_EN, 0); + mvebu_mmc_write(mmc, SDIO_ERR_INTR_EN, 0); /* SW reset */ - mvebu_mmc_write(SDIO_SW_RESET, SDIO_SW_RESET_NOW); + mvebu_mmc_write(mmc, SDIO_SW_RESET, SDIO_SW_RESET_NOW); - mvebu_mmc_write(SDIO_XFER_MODE, 0); + mvebu_mmc_write(mmc, SDIO_XFER_MODE, 0); /* enable status */ - mvebu_mmc_write(SDIO_NOR_STATUS_EN, SDIO_POLL_MASK); - mvebu_mmc_write(SDIO_ERR_STATUS_EN, SDIO_POLL_MASK); + mvebu_mmc_write(mmc, SDIO_NOR_STATUS_EN, SDIO_POLL_MASK); + mvebu_mmc_write(mmc, SDIO_ERR_STATUS_EN, SDIO_POLL_MASK); /* enable interrupts status */ - mvebu_mmc_write(SDIO_NOR_INTR_STATUS, SDIO_POLL_MASK); - mvebu_mmc_write(SDIO_ERR_INTR_STATUS, SDIO_POLL_MASK); + mvebu_mmc_write(mmc, SDIO_NOR_INTR_STATUS, SDIO_POLL_MASK); + mvebu_mmc_write(mmc, SDIO_ERR_INTR_STATUS, SDIO_POLL_MASK); } -static void mvebu_mmc_set_clk(unsigned int clock) +static void mvebu_mmc_set_clk(struct udevice *dev, unsigned int clock) { unsigned int m; + struct mvebu_mmc_plat *pdata = dev_get_plat(dev); + struct mmc *mmc = &pdata->mmc; if (clock == 0) { - debug("%s: clock off\n", DRIVER_NAME); - mvebu_mmc_write(SDIO_XFER_MODE, SDIO_XFER_MODE_STOP_CLK); - mvebu_mmc_write(SDIO_CLK_DIV, MVEBU_MMC_BASE_DIV_MAX); + dev_dbg(dev, "clock off\n"); + mvebu_mmc_write(mmc, SDIO_XFER_MODE, SDIO_XFER_MODE_STOP_CLK); + mvebu_mmc_write(mmc, SDIO_CLK_DIV, MVEBU_MMC_BASE_DIV_MAX); } else { m = MVEBU_MMC_BASE_FAST_CLOCK/(2*clock) - 1; if (m > MVEBU_MMC_BASE_DIV_MAX) m = MVEBU_MMC_BASE_DIV_MAX; - mvebu_mmc_write(SDIO_CLK_DIV, m & MVEBU_MMC_BASE_DIV_MAX); - debug("%s: clock (%d) div : %d\n", DRIVER_NAME, clock, m); + mvebu_mmc_write(mmc, SDIO_CLK_DIV, m & MVEBU_MMC_BASE_DIV_MAX); + dev_dbg(dev, "clock (%d) div : %d\n", clock, m); } } -static void mvebu_mmc_set_bus(unsigned int bus) +static void mvebu_mmc_set_bus(struct udevice *dev, unsigned int bus) { + struct mvebu_mmc_plat *pdata = dev_get_plat(dev); + struct mmc *mmc = &pdata->mmc; u32 ctrl_reg = 0; - ctrl_reg = mvebu_mmc_read(SDIO_HOST_CTRL); + ctrl_reg = mvebu_mmc_read(mmc, SDIO_HOST_CTRL); ctrl_reg &= ~SDIO_HOST_CTRL_DATA_WIDTH_4_BITS; switch (bus) { @@ -306,23 +318,26 @@ static void mvebu_mmc_set_bus(unsigned int bus) ctrl_reg |= SDIO_HOST_CTRL_CARD_TYPE_MEM_ONLY; - debug("%s: ctrl 0x%04x: %s %s %s\n", DRIVER_NAME, ctrl_reg, - (ctrl_reg & SDIO_HOST_CTRL_PUSH_PULL_EN) ? - "push-pull" : "open-drain", - (ctrl_reg & SDIO_HOST_CTRL_DATA_WIDTH_4_BITS) ? - "4bit-width" : "1bit-width", - (ctrl_reg & SDIO_HOST_CTRL_HI_SPEED_EN) ? - "high-speed" : ""); + dev_dbg(dev, "ctrl 0x%04x: %s %s %s\n", ctrl_reg, + (ctrl_reg & SDIO_HOST_CTRL_PUSH_PULL_EN) ? + "push-pull" : "open-drain", + (ctrl_reg & SDIO_HOST_CTRL_DATA_WIDTH_4_BITS) ? + "4bit-width" : "1bit-width", + (ctrl_reg & SDIO_HOST_CTRL_HI_SPEED_EN) ? + "high-speed" : ""); - mvebu_mmc_write(SDIO_HOST_CTRL, ctrl_reg); + mvebu_mmc_write(mmc, SDIO_HOST_CTRL, ctrl_reg); } -static int mvebu_mmc_set_ios(struct mmc *mmc) +static int mvebu_mmc_set_ios(struct udevice *dev) { - debug("%s: bus[%d] clock[%d]\n", DRIVER_NAME, - mmc->bus_width, mmc->clock); - mvebu_mmc_set_bus(mmc->bus_width); - mvebu_mmc_set_clk(mmc->clock); + struct mvebu_mmc_plat *pdata = dev_get_plat(dev); + struct mmc *mmc = &pdata->mmc; + + dev_dbg(dev, "bus[%d] clock[%d]\n", + mmc->bus_width, mmc->clock); + mvebu_mmc_set_bus(dev, mmc->bus_width); + mvebu_mmc_set_clk(dev, mmc->clock); return 0; } @@ -330,13 +345,13 @@ static int mvebu_mmc_set_ios(struct mmc *mmc) /* * Set window register. */ -static void mvebu_window_setup(void) +static void mvebu_window_setup(const struct mmc *mmc) { int i; for (i = 0; i < 4; i++) { - mvebu_mmc_write(WINDOW_CTRL(i), 0); - mvebu_mmc_write(WINDOW_BASE(i), 0); + mvebu_mmc_write(mmc, WINDOW_CTRL(i), 0); + mvebu_mmc_write(mmc, WINDOW_BASE(i), 0); } for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++) { u32 size, base, attrib; @@ -364,79 +379,119 @@ static void mvebu_window_setup(void) size = gd->bd->bi_dram[i].size; base = gd->bd->bi_dram[i].start; if (size && attrib) { - mvebu_mmc_write(WINDOW_CTRL(i), + mvebu_mmc_write(mmc, WINDOW_CTRL(i), MVCPU_WIN_CTRL_DATA(size, MVEBU_TARGET_DRAM, attrib, MVCPU_WIN_ENABLE)); } else { - mvebu_mmc_write(WINDOW_CTRL(i), MVCPU_WIN_DISABLE); + mvebu_mmc_write(mmc, WINDOW_CTRL(i), MVCPU_WIN_DISABLE); } - mvebu_mmc_write(WINDOW_BASE(i), base); + mvebu_mmc_write(mmc, WINDOW_BASE(i), base); } } -static int mvebu_mmc_initialize(struct mmc *mmc) +static int mvebu_mmc_initialize(struct udevice *dev) { - debug("%s: mvebu_mmc_initialize\n", DRIVER_NAME); + struct mvebu_mmc_plat *pdata = dev_get_plat(dev); + struct mmc *mmc = &pdata->mmc; + + dev_dbg(dev, "%s\n", __func__); /* * Setting host parameters * Initial Host Ctrl : Timeout : max , Normal Speed mode, * 4-bit data mode, Big Endian, SD memory Card, Push_pull CMD Line */ - mvebu_mmc_write(SDIO_HOST_CTRL, + mvebu_mmc_write(mmc, SDIO_HOST_CTRL, SDIO_HOST_CTRL_TMOUT(SDIO_HOST_CTRL_TMOUT_MAX) | SDIO_HOST_CTRL_DATA_WIDTH_4_BITS | SDIO_HOST_CTRL_BIG_ENDIAN | SDIO_HOST_CTRL_PUSH_PULL_EN | SDIO_HOST_CTRL_CARD_TYPE_MEM_ONLY); - mvebu_mmc_write(SDIO_CLK_CTRL, 0); + mvebu_mmc_write(mmc, SDIO_CLK_CTRL, 0); /* enable status */ - mvebu_mmc_write(SDIO_NOR_STATUS_EN, SDIO_POLL_MASK); - mvebu_mmc_write(SDIO_ERR_STATUS_EN, SDIO_POLL_MASK); + mvebu_mmc_write(mmc, SDIO_NOR_STATUS_EN, SDIO_POLL_MASK); + mvebu_mmc_write(mmc, SDIO_ERR_STATUS_EN, SDIO_POLL_MASK); /* disable interrupts */ - mvebu_mmc_write(SDIO_NOR_INTR_EN, 0); - mvebu_mmc_write(SDIO_ERR_INTR_EN, 0); + mvebu_mmc_write(mmc, SDIO_NOR_INTR_EN, 0); + mvebu_mmc_write(mmc, SDIO_ERR_INTR_EN, 0); - mvebu_window_setup(); + mvebu_window_setup(mmc); /* SW reset */ - mvebu_mmc_write(SDIO_SW_RESET, SDIO_SW_RESET_NOW); + mvebu_mmc_write(mmc, SDIO_SW_RESET, SDIO_SW_RESET_NOW); return 0; } -static const struct mmc_ops mvebu_mmc_ops = { - .send_cmd = mvebu_mmc_send_cmd, - .set_ios = mvebu_mmc_set_ios, - .init = mvebu_mmc_initialize, -}; +static int mvebu_mmc_of_to_plat(struct udevice *dev) +{ + struct mvebu_mmc_plat *pdata = dev_get_plat(dev); + fdt_addr_t addr; -static struct mmc_config mvebu_mmc_cfg = { - .name = DRIVER_NAME, - .ops = &mvebu_mmc_ops, - .f_min = MVEBU_MMC_BASE_FAST_CLOCK / MVEBU_MMC_BASE_DIV_MAX, - .f_max = MVEBU_MMC_CLOCKRATE_MAX, - .voltages = MMC_VDD_32_33 | MMC_VDD_33_34, - .host_caps = MMC_MODE_4BIT | MMC_MODE_HS | - MMC_MODE_HS_52MHz, - .part_type = PART_TYPE_DOS, - .b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT, -}; + addr = dev_read_addr(dev); + if (addr == FDT_ADDR_T_NONE) + return -EINVAL; -int mvebu_mmc_init(struct bd_info *bis) -{ - struct mmc *mmc; + pdata->iobase = (void *)addr; - mvebu_mmc_power_up(); + return 0; +} - mmc = mmc_create(&mvebu_mmc_cfg, bis); - if (mmc == NULL) - return -1; +static int mvebu_mmc_probe(struct udevice *dev) +{ + struct mvebu_mmc_plat *pdata = dev_get_plat(dev); + struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev); + struct mmc *mmc = &pdata->mmc; + struct mmc_config *cfg = &pdata->cfg; + + cfg->name = dev->name; + cfg->f_min = MVEBU_MMC_BASE_FAST_CLOCK / MVEBU_MMC_BASE_DIV_MAX; + cfg->f_max = MVEBU_MMC_CLOCKRATE_MAX; + cfg->voltages = MMC_VDD_32_33 | MMC_VDD_33_34; + cfg->host_caps = MMC_MODE_4BIT | MMC_MODE_HS | MMC_MODE_HS_52MHz; + cfg->part_type = PART_TYPE_DOS; + cfg->b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT; + + mmc->cfg = cfg; + mmc->priv = pdata; + mmc->dev = dev; + upriv->mmc = mmc; + + mvebu_mmc_power_up(dev); + mvebu_mmc_initialize(dev); return 0; } + +static const struct dm_mmc_ops mvebu_dm_mmc_ops = { + .send_cmd = mvebu_mmc_send_cmd, + .set_ios = mvebu_mmc_set_ios, +}; + +static int mvebu_mmc_bind(struct udevice *dev) +{ + struct mvebu_mmc_plat *pdata = dev_get_plat(dev); + + return mmc_bind(dev, &pdata->mmc, &pdata->cfg); +} + +static const struct udevice_id mvebu_mmc_match[] = { + { .compatible = "marvell,orion-sdio" }, + { /* sentinel */ } +}; + +U_BOOT_DRIVER(mvebu_mmc) = { + .name = "mvebu_mmc", + .id = UCLASS_MMC, + .of_match = mvebu_mmc_match, + .ops = &mvebu_dm_mmc_ops, + .probe = mvebu_mmc_probe, + .bind = mvebu_mmc_bind, + .of_to_plat = mvebu_mmc_of_to_plat, + .plat_auto = sizeof(struct mvebu_mmc_plat), +}; diff --git a/drivers/mmc/pci_mmc.c b/drivers/mmc/pci_mmc.c index fd5dd229b58..b9ab064b60e 100644 --- a/drivers/mmc/pci_mmc.c +++ b/drivers/mmc/pci_mmc.c @@ -53,6 +53,7 @@ static int pci_mmc_probe(struct udevice *dev) host->ioaddr = (void *)dm_pci_map_bar(dev, PCI_BASE_ADDRESS_0, PCI_REGION_MEM); host->name = dev->name; + host->cd_gpio = priv->cd_gpio; host->mmc = &plat->mmc; host->mmc->dev = dev; ret = sdhci_setup_cfg(&plat->cfg, host, 0, 0); @@ -68,8 +69,11 @@ static int pci_mmc_of_to_plat(struct udevice *dev) { if (CONFIG_IS_ENABLED(DM_GPIO)) { struct pci_mmc_priv *priv = dev_get_priv(dev); + int ret; - gpio_request_by_name(dev, "cd-gpios", 0, &priv->cd_gpio, GPIOD_IS_IN); + ret = gpio_request_by_name(dev, "cd-gpios", 0, &priv->cd_gpio, + GPIOD_IS_IN); + log_debug("cd-gpio %s done, ret=%d\n", dev->name, ret); } return 0; |