[U-Boot] [PATCH 1/3] nds32: mmc: Support mmc DM.

Andes uboot at andestech.com
Fri Dec 2 07:49:07 CET 2016


From: rick <rick at 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 <rick at andestech.com>
Cc: Andes <uboot at 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, rick at 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



More information about the U-Boot mailing list