From: rick <r...@andestech.com>

Add Andestech mmc DM driver for ag101p board.
Do not use get_timer() to check mmc state can
improve throughput performance.

Signed-off-by: rick <r...@andestech.com>
Cc: Andes <ub...@andestech.com>
---
 drivers/mmc/Kconfig        |    7 +++
 drivers/mmc/Makefile       |    1 +
 drivers/mmc/ftsdc010_mci.c |  106 ++++++++++++++++++++++++---------
 drivers/mmc/nds32_mmc.c    |  140 ++++++++++++++++++++++++++++++++++++++++++++
 include/faraday/ftsdc010.h |   41 +++++++++++++
 5 files changed, 267 insertions(+), 28 deletions(-)
 create mode 100644 drivers/mmc/nds32_mmc.c

diff --git a/drivers/mmc/Kconfig b/drivers/mmc/Kconfig
index 24f4b28..59c5e24 100644
--- a/drivers/mmc/Kconfig
+++ b/drivers/mmc/Kconfig
@@ -54,6 +54,13 @@ config ROCKCHIP_DWMMC
          SD 3.0, SDIO 3.0 and MMC 4.5 and supports common eMMC chips as well
          as removeable SD and micro-SD cards.
 
+config NDS32_MMC
+       bool "Andestech SD/MMC controller support"
+       depends on DM_MMC && OF_CONTROL
+       help
+         This enables support for the Andestech SD/MMM controller, which is
+         based on Faraday IP.
+
 config SH_SDHI
        bool "SuperH/Renesas ARM SoCs on-chip SDHI host controller support"
        depends on RMOBILE
diff --git a/drivers/mmc/Makefile b/drivers/mmc/Makefile
index d850758..905c3e0 100644
--- a/drivers/mmc/Makefile
+++ b/drivers/mmc/Makefile
@@ -40,6 +40,7 @@ obj-$(CONFIG_OMAP_HSMMC) += omap_hsmmc.o
 obj-$(CONFIG_X86) += pci_mmc.o
 obj-$(CONFIG_PXA_MMC_GENERIC) += pxa_mmc_gen.o
 obj-$(CONFIG_ROCKCHIP_DWMMC) += rockchip_dw_mmc.o
+obj-$(CONFIG_NDS32_MMC) += nds32_mmc.o
 obj-$(CONFIG_SUPPORT_EMMC_RPMB) += rpmb.o
 obj-$(CONFIG_S3C_SDI) += s3c_sdi.o
 obj-$(CONFIG_S5P_SDHCI) += s5p_sdhci.o
diff --git a/drivers/mmc/ftsdc010_mci.c b/drivers/mmc/ftsdc010_mci.c
index e88c632..9807eba 100644
--- a/drivers/mmc/ftsdc010_mci.c
+++ b/drivers/mmc/ftsdc010_mci.c
@@ -11,7 +11,6 @@
 #include <malloc.h>
 #include <part.h>
 #include <mmc.h>
-
 #include <asm/io.h>
 #include <linux/errno.h>
 #include <asm/byteorder.h>
@@ -20,16 +19,6 @@
 #define CFG_CMD_TIMEOUT (CONFIG_SYS_HZ >> 4) /* 250 ms */
 #define CFG_RST_TIMEOUT CONFIG_SYS_HZ /* 1 sec reset timeout */
 
-struct ftsdc010_chip {
-       void __iomem *regs;
-       uint32_t wprot;   /* write protected (locked) */
-       uint32_t rate;    /* actual SD clock in Hz */
-       uint32_t sclk;    /* FTSDC010 source clock in Hz */
-       uint32_t fifo;    /* fifo depth in bytes */
-       uint32_t acmd;
-       struct mmc_config cfg;  /* mmc configuration */
-};
-
 static inline int ftsdc010_send_cmd(struct mmc *mmc, struct mmc_cmd *mmc_cmd)
 {
        struct ftsdc010_chip *chip = mmc->priv;
@@ -127,9 +116,8 @@ static void ftsdc010_clkset(struct mmc *mmc, uint32_t rate)
 static int ftsdc010_wait(struct ftsdc010_mmc __iomem *regs, uint32_t mask)
 {
        int ret = -ETIMEDOUT;
-       uint32_t st, ts;
-
-       for (ts = get_timer(0); get_timer(ts) < CFG_CMD_TIMEOUT; ) {
+       uint32_t st, timeout = 10000000;
+       while (timeout--) {
                st = readl(&regs->status);
                if (!(st & mask))
                        continue;
@@ -137,7 +125,6 @@ static int ftsdc010_wait(struct ftsdc010_mmc __iomem *regs, 
uint32_t mask)
                ret = 0;
                break;
        }
-
        if (ret)
                debug("ftsdc010: wait st(0x%x) timeout\n", mask);
 
@@ -147,10 +134,16 @@ static int ftsdc010_wait(struct ftsdc010_mmc __iomem 
*regs, uint32_t mask)
 /*
  * u-boot mmc api
  */
-
+#ifdef CONFIG_DM_MMC_OPS
+static int ftsdc010_request(struct udevice *dev, struct mmc_cmd *cmd,
+       struct mmc_data *data)
+{
+       struct mmc *mmc = mmc_get_mmc_dev(dev);
+#else
 static int ftsdc010_request(struct mmc *mmc, struct mmc_cmd *cmd,
        struct mmc_data *data)
 {
+#endif
        int ret = -EOPNOTSUPP;
        uint32_t len = 0;
        struct ftsdc010_chip *chip = mmc->priv;
@@ -251,8 +244,14 @@ static int ftsdc010_request(struct mmc *mmc, struct 
mmc_cmd *cmd,
        return ret;
 }
 
+#ifdef CONFIG_DM_MMC_OPS
+static int ftsdc010_set_ios(struct udevice *dev)
+{
+       struct mmc *mmc = mmc_get_mmc_dev(dev);
+#else
 static void ftsdc010_set_ios(struct mmc *mmc)
 {
+#endif
        struct ftsdc010_chip *chip = mmc->priv;
        struct ftsdc010_mmc __iomem *regs = chip->regs;
 
@@ -270,6 +269,9 @@ static void ftsdc010_set_ios(struct mmc *mmc)
                setbits_le32(&regs->bwr, FTSDC010_BWR_MODE_1BIT);
                break;
        }
+#ifdef CONFIG_DM_MMC_OPS
+       return 0;
+#endif
 }
 
 static int ftsdc010_init(struct mmc *mmc)
@@ -277,7 +279,6 @@ static int ftsdc010_init(struct mmc *mmc)
        struct ftsdc010_chip *chip = mmc->priv;
        struct ftsdc010_mmc __iomem *regs = chip->regs;
        uint32_t ts;
-
        if (readl(&regs->status) & FTSDC010_STATUS_CARD_DETECT)
                return -ENOMEDIUM;
 
@@ -309,11 +310,67 @@ static int ftsdc010_init(struct mmc *mmc)
        return 0;
 }
 
+#ifdef CONFIG_DM_MMC_OPS
+int ftsdc010_probe(struct udevice *dev)
+{
+       struct mmc *mmc = mmc_get_mmc_dev(dev);
+       return ftsdc010_init(mmc);
+}
+
+const struct dm_mmc_ops dm_ftsdc010_ops = {
+       .send_cmd       = ftsdc010_request,
+       .set_ios        = ftsdc010_set_ios,
+};
+
+#else
 static const struct mmc_ops ftsdc010_ops = {
        .send_cmd       = ftsdc010_request,
        .set_ios        = ftsdc010_set_ios,
        .init           = ftsdc010_init,
 };
+#endif
+
+void ftsdc_setup_cfg(struct mmc_config *cfg, const char *name, int buswidth,
+                    uint caps, u32 max_clk, u32 min_clk)
+{
+       cfg->name = name;
+       cfg->f_min = min_clk;
+       cfg->f_max = max_clk;
+       cfg->voltages = MMC_VDD_32_33 | MMC_VDD_33_34 | MMC_VDD_165_195;
+       cfg->host_caps = caps;
+       if (buswidth == 8) {
+               cfg->host_caps |= MMC_MODE_8BIT;
+               cfg->host_caps &= ~MMC_MODE_4BIT;
+       } else {
+               cfg->host_caps |= MMC_MODE_4BIT;
+               cfg->host_caps &= ~MMC_MODE_8BIT;
+       }
+       cfg->host_caps |= MMC_MODE_HS | MMC_MODE_HS_52MHz;
+       cfg->part_type = PART_TYPE_DOS;
+       cfg->b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT;
+}
+
+void set_bus_width(struct ftsdc010_mmc __iomem *regs, struct mmc_config *cfg)
+{
+       switch (readl(&regs->bwr) & FTSDC010_BWR_CAPS_MASK) {
+       case FTSDC010_BWR_CAPS_4BIT:
+               cfg->host_caps |= MMC_MODE_4BIT;
+               cfg->host_caps &= ~MMC_MODE_8BIT;
+               break;
+       case FTSDC010_BWR_CAPS_8BIT:
+               cfg->host_caps |= MMC_MODE_4BIT | MMC_MODE_8BIT;
+               break;
+       default:
+               break;
+       }
+}
+
+#ifdef CONFIG_BLK
+int ftsdc010_bind(struct udevice *dev, struct mmc *mmc, struct mmc_config *cfg)
+{
+       return mmc_bind(dev, mmc, cfg);
+}
+#else
 
 int ftsdc010_mmc_init(int devid)
 {
@@ -343,19 +400,11 @@ int ftsdc010_mmc_init(int devid)
 #endif
 
        chip->cfg.name = "ftsdc010";
+#ifndef CONFIG_DM_MMC_OPS
        chip->cfg.ops = &ftsdc010_ops;
+#endif
        chip->cfg.host_caps = MMC_MODE_HS | MMC_MODE_HS_52MHz;
-       switch (readl(&regs->bwr) & FTSDC010_BWR_CAPS_MASK) {
-       case FTSDC010_BWR_CAPS_4BIT:
-               chip->cfg.host_caps |= MMC_MODE_4BIT;
-               break;
-       case FTSDC010_BWR_CAPS_8BIT:
-               chip->cfg.host_caps |= MMC_MODE_4BIT | MMC_MODE_8BIT;
-               break;
-       default:
-               break;
-       }
-
+       set_bus_width(regs , &chip->cfg);
        chip->cfg.voltages  = MMC_VDD_32_33 | MMC_VDD_33_34;
        chip->cfg.f_max     = chip->sclk / 2;
        chip->cfg.f_min     = chip->sclk / 0x100;
@@ -371,3 +420,4 @@ int ftsdc010_mmc_init(int devid)
 
        return 0;
 }
+#endif
diff --git a/drivers/mmc/nds32_mmc.c b/drivers/mmc/nds32_mmc.c
new file mode 100644
index 0000000..f63661c
--- /dev/null
+++ b/drivers/mmc/nds32_mmc.c
@@ -0,0 +1,140 @@
+/*
+ * Andestech ATFSDC010 SD/MMC driver
+ *
+ * (C) Copyright 2016
+ * Rick Chen, NDS32 Software Engineering, r...@andestech.com
+
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+#include <common.h>
+#include <clk.h>
+#include <dm.h>
+#include <dt-structs.h>
+#include <faraday/ftsdc010.h>
+#include <errno.h>
+#include <mapmem.h>
+#include <pwrseq.h>
+#include <syscon.h>
+#include <mmc.h>
+#include <linux/err.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#if CONFIG_IS_ENABLED(OF_PLATDATA)
+struct nds_mmc {
+       fdt32_t         bus_width;
+       bool            cap_mmc_highspeed;
+       bool            cap_sd_highspeed;
+       fdt32_t         card_detect_delay;
+       fdt32_t         clock_freq_min_max[2];
+       struct phandle_2_cell   clocks[4];
+       bool            disable_wp;
+       fdt32_t         fifo_depth;
+       fdt32_t         interrupts[3];
+       fdt32_t         num_slots;
+       fdt32_t         reg[2];
+       fdt32_t         vmmc_supply;
+};
+#endif
+
+struct nds_mmc_plat {
+#if CONFIG_IS_ENABLED(OF_PLATDATA)
+       struct nds_mmc dtplat;
+#endif
+       struct mmc_config cfg;
+       struct mmc mmc;
+};
+
+struct ftsdc_priv {
+       struct clk clk;
+       struct ftsdc010_chip chip;
+       int fifo_depth;
+       bool fifo_mode;
+       u32 minmax[2];
+};
+
+static int nds32_mmc_ofdata_to_platdata(struct udevice *dev)
+{
+#if !CONFIG_IS_ENABLED(OF_PLATDATA)
+       struct ftsdc_priv *priv = dev_get_priv(dev);
+       struct ftsdc010_chip *chip = &priv->chip;
+       chip->name = dev->name;
+       chip->ioaddr = (void *)dev_get_addr(dev);
+       chip->buswidth = fdtdec_get_int(gd->fdt_blob, dev->of_offset,
+                                       "bus-width", 4);
+       chip->priv = dev;
+       /* use non-removeable as sdcard and emmc as judgement */
+       if (fdtdec_get_bool(gd->fdt_blob, dev->of_offset, "non-removable"))
+               chip->dev_index = 0;
+       else
+               chip->dev_index = 1;
+
+       priv->fifo_depth = fdtdec_get_int(gd->fdt_blob, dev->of_offset,
+                                   "fifo-depth", 0);
+       priv->fifo_mode = fdtdec_get_bool(gd->fdt_blob, dev->of_offset,
+                                         "fifo-mode");
+       if (fdtdec_get_int_array(gd->fdt_blob, dev->of_offset,
+                                "clock-freq-min-max", priv->minmax, 2))
+               return -EINVAL;
+#endif
+       chip->sclk = priv->minmax[1];
+       chip->regs = chip->ioaddr;
+       return 0;
+}
+
+static int nds32_mmc_probe(struct udevice *dev)
+{
+       struct nds_mmc_plat *plat = dev_get_platdata(dev);
+       struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev);
+       struct ftsdc_priv *priv = dev_get_priv(dev);
+       struct ftsdc010_chip *chip = &priv->chip;
+       struct udevice *pwr_dev __maybe_unused;
+#if CONFIG_IS_ENABLED(OF_PLATDATA)
+       int ret;
+       struct nds_mmc *dtplat = &plat->dtplat;
+       chip->name = dev->name;
+       chip->ioaddr = map_sysmem(dtplat->reg[0], dtplat->reg[1]);
+       chip->buswidth = dtplat->bus_width;
+       chip->priv = dev;
+       chip->dev_index = 0;
+       priv->fifo_depth = dtplat->fifo_depth;
+       priv->fifo_mode = 0;
+       memcpy(priv->minmax, dtplat->clock_freq_min_max, sizeof(priv->minmax));
+       ret = clk_get_by_index_platdata(dev, 0, dtplat->clocks, &priv->clk);
+       if (ret < 0)
+               return ret;
+#endif
+       ftsdc_setup_cfg(&plat->cfg, dev->name, chip->buswidth, chip->caps,
+                       priv->minmax[1] , priv->minmax[0]);
+       set_bus_width(chip->regs , &chip->cfg);
+
+       chip->mmc = &plat->mmc;
+       chip->mmc->priv = &priv->chip;
+       chip->mmc->dev = dev;
+       upriv->mmc = chip->mmc;
+       return ftsdc010_probe(dev);
+}
+
+static int nds32_mmc_bind(struct udevice *dev)
+{
+       struct nds_mmc_plat *plat = dev_get_platdata(dev);
+       return ftsdc010_bind(dev, &plat->mmc, &plat->cfg);
+}
+
+static const struct udevice_id nds32_mmc_ids[] = {
+       { .compatible = "andestech,atsdc010" },
+       { }
+};
+
+U_BOOT_DRIVER(rockchip_dwmmc_drv) = {
+       .name           = "nds32_mmc",
+       .id             = UCLASS_MMC,
+       .of_match       = nds32_mmc_ids,
+       .ofdata_to_platdata = nds32_mmc_ofdata_to_platdata,
+       .ops            = &dm_ftsdc010_ops,
+       .bind           = nds32_mmc_bind,
+       .probe          = nds32_mmc_probe,
+       .priv_auto_alloc_size = sizeof(struct ftsdc_priv),
+       .platdata_auto_alloc_size = sizeof(struct nds_mmc_plat),
+};
diff --git a/include/faraday/ftsdc010.h b/include/faraday/ftsdc010.h
index 9bfdef9..8b30034 100644
--- a/include/faraday/ftsdc010.h
+++ b/include/faraday/ftsdc010.h
@@ -6,6 +6,7 @@
  *
  * SPDX-License-Identifier:    GPL-2.0+
  */
+#include <mmc.h>
 
 #ifndef __FTSDC010_H
 #define __FTSDC010_H
@@ -243,4 +244,44 @@ int ftsdc010_mmc_init(int dev_index);
 
 #endif /* CONFIG_FTSDC010_SDIO */
 
+struct ftsdc010_chip {
+       void __iomem *regs;
+       uint32_t wprot;   /* write protected (locked) */
+       uint32_t rate;    /* actual SD clock in Hz */
+       uint32_t sclk;    /* FTSDC010 source clock in Hz */
+       uint32_t fifo;    /* fifo depth in bytes */
+       uint32_t acmd;
+       struct mmc_config cfg;  /* mmc configuration */
+       const char *name;
+       void *ioaddr;
+       unsigned int quirks;
+       unsigned int caps;
+       unsigned int version;
+       unsigned int clock;
+       unsigned int bus_hz;
+       unsigned int div;
+       int dev_index;
+       int dev_id;
+       int buswidth;
+       u32 fifoth_val;
+       struct mmc *mmc;
+       void *priv;
+       bool fifo_mode;
+};
+
+
+#ifdef CONFIG_DM_MMC_OPS
+/* Export the operations to drivers */
+int ftsdc010_probe(struct udevice *dev);
+extern const struct dm_mmc_ops dm_ftsdc010_ops;
+#endif
+void ftsdc_setup_cfg(struct mmc_config *cfg, const char *name, int buswidth,
+                    uint caps, u32 max_clk, u32 min_clk);
+void set_bus_width(struct ftsdc010_mmc __iomem *regs, struct mmc_config *cfg);
+
+#ifdef CONFIG_BLK
+int ftsdc010_bind(struct udevice *dev, struct mmc *mmc, struct mmc_config 
*cfg);
+#endif
+
+
 #endif /* __FTSDC010_H */
-- 
1.7.9.5

_______________________________________________
U-Boot mailing list
U-Boot@lists.denx.de
http://lists.denx.de/mailman/listinfo/u-boot

Reply via email to