[U-Boot] [RFC PATCH 05/13] mmc: add MMC (glue) driver for Nexell SoCs

Simon Glass
2017-12-02T03:30:42Z

Hi Andre,

On 29 November 2017 at 18:25, Andre Przywara <andre.przywara@arm.com> wrote:
> From: Amit Singh Tomar <amittomer25@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 <amittomer25@gmail.com>
> Signed-off-by: Andre Przywara <andre.przywara@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 <amittomer25@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;

comments

> +};
> +
> +/* 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);

How about using setbits_le32() ?

> +
> + /* Select PLL1 as clock source */
> + val = readl(SDMMCCLKGEN0L);
> + val = val & ~(PLL_SEL_MASK);
> + val |= (PLL1_SEL << PLLSEL_SHIFT) & PLL_SEL_MASK;
> + writel(val, SDMMCCLKGEN0L);

clrsetbits_le32

> +}
> +
> +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);

debug() ? And below

> + return ret;
> + }
> +
> + fifo_depth = fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev),
> + "fifo-depth", 0);

dev_read_...()

and below

> + 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

Do we need to support non-BLK? It is going away in March anyway.

> + 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
>

Regards,
Simon