From: Amit Singh Tomar <amittome...@gmail.com>

The Nexell SoCs contain multiple MMC devices, which can be driven by
U-Boot's DesignWare MMC driver, if supported by the required glue driver
file.
Provide that file along with the Makefile/Kconfig changes.

Signed-off-by: Amit Singh Tomar <amittome...@gmail.com>
Signed-off-by: Andre Przywara <andre.przyw...@arm.com>
---
 drivers/mmc/Kconfig         |   8 +++
 drivers/mmc/Makefile        |   1 +
 drivers/mmc/nexell_dw_mmc.c | 159 ++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 168 insertions(+)
 create mode 100644 drivers/mmc/nexell_dw_mmc.c

diff --git a/drivers/mmc/Kconfig b/drivers/mmc/Kconfig
index 62ce0af7d3..243878aa65 100644
--- a/drivers/mmc/Kconfig
+++ b/drivers/mmc/Kconfig
@@ -91,6 +91,14 @@ config MMC_DW_K3
          Synopsys DesignWare Memory Card Interface driver. Select this option
          for platforms based on Hisilicon K3 SoC's.
 
+config MMC_DW_NEXELL
+        bool "NEXELL SD/MMC controller support"
+        depends on ARCH_NEXELL && DM_MMC && OF_CONTROL
+        depends on MMC_DW
+        help
+          This enables support for the Nexell SD/MMM controller, which is
+          based on Designware IP.
+
 config MMC_DW_ROCKCHIP
        bool "Rockchip SD/MMC controller support"
        depends on DM_MMC && OF_CONTROL
diff --git a/drivers/mmc/Makefile b/drivers/mmc/Makefile
index d505f37f01..0fb6eb7803 100644
--- a/drivers/mmc/Makefile
+++ b/drivers/mmc/Makefile
@@ -26,6 +26,7 @@ obj-$(CONFIG_MMC_DAVINCI)             += davinci_mmc.o
 obj-$(CONFIG_MMC_DW)                   += dw_mmc.o
 obj-$(CONFIG_MMC_DW_EXYNOS)            += exynos_dw_mmc.o
 obj-$(CONFIG_MMC_DW_K3)                        += hi6220_dw_mmc.o
+obj-$(CONFIG_MMC_DW_NEXELL)            += nexell_dw_mmc.o
 obj-$(CONFIG_MMC_DW_ROCKCHIP)          += rockchip_dw_mmc.o
 obj-$(CONFIG_MMC_DW_SOCFPGA)           += socfpga_dw_mmc.o
 obj-$(CONFIG_FSL_ESDHC) += fsl_esdhc.o
diff --git a/drivers/mmc/nexell_dw_mmc.c b/drivers/mmc/nexell_dw_mmc.c
new file mode 100644
index 0000000000..e96395cdaf
--- /dev/null
+++ b/drivers/mmc/nexell_dw_mmc.c
@@ -0,0 +1,159 @@
+/*
+ * Copyright (C) 2017 Amit Singh Tomar <amittome...@gmail.com>
+ *
+ * SPDX-License-Identifier:     GPL-2.0+
+ */
+
+#include <common.h>
+#include <clk.h>
+#include <dm.h>
+#include <dt-structs.h>
+#include <dwmmc.h>
+#include <errno.h>
+#include <mapmem.h>
+#include <linux/err.h>
+#include <reset.h>
+#include <asm/arch/clk.h>
+
+#define SDMMCCLKENB 0xC00C5000
+#define SDMMCCLKGEN0L 0xC00C5004
+#define PLL_SEL_MASK GENMASK(4, 2)
+#define CLK_DIV_MASK GENMASK(12, 5)
+#define PLLSEL_SHIFT 0x2
+#define PLL0_SEL 0
+#define PLL1_SEL 1
+#define PLL2_SEL 2
+#define SDMMC_CLK_ENB 0xc /* Magic bit to enable/generate SDMMC clock */
+
+DECLARE_GLOBAL_DATA_PTR;
+
+struct nexell_mmc_plat {
+       struct mmc_config cfg;
+       struct mmc mmc;
+};
+
+struct nexell_dwmmc_priv {
+       struct clk clk;
+       struct dwmci_host host;
+       struct reset_ctl reset_ctl;
+       int fifo_depth;
+       bool fifo_mode;
+};
+
+/* Should this be done from CCF ? */
+static void nexell_dwmci_clksel(struct dwmci_host *host)
+{
+       u32 val;
+
+       /* Enable SDMMC clock */
+       val = readl(SDMMCCLKENB);
+       val |= SDMMC_CLK_ENB;
+       writel(val, SDMMCCLKENB);
+
+       /* Select PLL1 as clock source */
+       val = readl(SDMMCCLKGEN0L);
+       val = val & ~(PLL_SEL_MASK);
+       val |= (PLL1_SEL << PLLSEL_SHIFT) & PLL_SEL_MASK;
+       writel(val, SDMMCCLKGEN0L);
+}
+
+static int nexell_dwmmc_ofdata_to_platdata(struct udevice *dev)
+{
+       struct nexell_dwmmc_priv *priv = dev_get_priv(dev);
+       struct dwmci_host *host = &priv->host;
+       int fifo_depth, ret;
+
+       ret = reset_get_by_name(dev, "mmc", &priv->reset_ctl);
+       if (ret) {
+               printf("reset_get_by_name(rst) failed: %d", ret);
+               return ret;
+       }
+
+       fifo_depth = fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev),
+                                   "fifo-depth", 0);
+       if (fifo_depth < 0) {
+               printf("DWMMC: Can't get FIFO depth\n");
+               return -EINVAL;
+       }
+
+       host->name = dev->name;
+       host->ioaddr = (void *)devfdt_get_addr(dev);
+       host->buswidth = fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev),
+                                       "bus-width", 4);
+
+       ret = reset_assert(&priv->reset_ctl);
+       if (ret)
+               return ret;
+
+       host->clksel = nexell_dwmci_clksel;
+
+       ret = reset_deassert(&priv->reset_ctl);
+       if (ret)
+               return ret;
+
+       host->dev_index = 0;
+       host->bus_hz = get_mmc_clk(host->dev_index);
+       host->fifoth_val = MSIZE(0x2) | RX_WMARK(fifo_depth / 2 - 1) |
+                          TX_WMARK(fifo_depth / 2);
+       host->priv = priv;
+
+       return 0;
+}
+
+static int nexell_dwmmc_probe(struct udevice *dev)
+{
+#ifdef CONFIG_BLK
+       struct nexell_mmc_plat *plat = dev_get_platdata(dev);
+#endif
+       struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev);
+       struct nexell_dwmmc_priv *priv = dev_get_priv(dev);
+       struct dwmci_host *host = &priv->host;
+
+#ifdef CONFIG_BLK
+       dwmci_setup_cfg(&plat->cfg, host, host->bus_hz, 400000);
+       host->mmc = &plat->mmc;
+#else
+       int ret;
+
+       ret = add_dwmci(host, host->bus_hz, 400000);
+       if (ret)
+               return ret;
+#endif
+
+       host->mmc->priv = &priv->host;
+       upriv->mmc = host->mmc;
+       host->mmc->dev = dev;
+
+       return 0;
+}
+
+static int nexell_dwmmc_bind(struct udevice *dev)
+{
+#ifdef CONFIG_BLK
+       struct nexell_mmc_plat *plat = dev_get_platdata(dev);
+       int ret;
+
+       ret = dwmci_bind(dev, &plat->mmc, &plat->cfg);
+       if (ret)
+               return ret;
+#endif
+
+       return 0;
+}
+
+static const struct udevice_id nexell_dwmmc_ids[] = {
+       { .compatible = "nexell,s5p6818-dw-mshc" },
+       { }
+};
+
+U_BOOT_DRIVER(nexell_dwmmc_drv) = {
+       .name           = "nexell_s5p6818_dw_mshc",
+       .id             = UCLASS_MMC,
+       .of_match       = nexell_dwmmc_ids,
+       .ops            = &dm_dwmci_ops,
+       .ofdata_to_platdata = nexell_dwmmc_ofdata_to_platdata,
+       .bind           = nexell_dwmmc_bind,
+       .probe          = nexell_dwmmc_probe,
+       .priv_auto_alloc_size = sizeof(struct nexell_dwmmc_priv),
+       .platdata_auto_alloc_size = sizeof(struct nexell_mmc_plat),
+};
-- 
2.14.1

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

Reply via email to