[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(®s->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(®s->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(®s->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(®s->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(®s->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