[U-Boot] [PATCH V3] fsl: esdhc: support driver model

york sun york.sun at nxp.com
Sun Mar 27 18:58:05 CEST 2016


(Sorry for top posting. Using OWA)

Yes, I can compile it for PPC and spot check on selected boards.

York


________________________________________
From: Peng Fan <van.freenix at gmail.com>
Sent: Sunday, March 27, 2016 7:59 AM
To: york sun; panto at antoniou-consulting.com; sbabic at denx.de; sjg at chromium.org
Cc: u-boot at lists.denx.de; Yangbo Lu; Hector Palacios; Eric Nelson; Fabio Estevam
Subject: Re: [PATCH V3] fsl: esdhc: support driver model

Hi York,

Could you test this patch for PPC and layerscape platform? Since I
only test this on i.MX6 platform, I do not want to break PPC or else.

Thanks,
Peng.

On Fri, Mar 25, 2016 at 02:16:56PM +0800, Peng Fan wrote:
>Support Driver Model for fsl esdhc driver.
>
>1. Introduce a new structure struct fsl_esdhc_priv
>2. Refactor fsl_esdhc_initialize which is originally used by board code.
>   - Introduce fsl_esdhc_init to be common usage for DM and non-DM
>   - Introduce fsl_esdhc_cfg_to_priv to build the bridge for non-DM part.
>   - The original API for board code is still there, but we use
>     'fsl_esdhc_cfg_to_priv' and 'fsl_esdhc_init' to serve it.
>3. All the functions are changed to use 'struct fsl_esdhc_priv', except
>   fsl_esdhc_initialize.
>4. Since clk driver is not implemented, use mxc_get_clock to geth
>   the clk and fill 'priv->sdhc_clk'.
>
>Has been tested on i.MX6UL 14X14 EVK board:
>"
>=>dm tree
>....
> simple_bus  [ + ]    |   `-- aips-bus at 02100000
>  mmc        [ + ]    |       |-- usdhc at 02190000
>  mmc        [ + ]    |       |-- usdhc at 02194000
>....
>=> mmc list
>FSL_SDHC: 0 (SD)
>FSL_SDHC: 1 (SD)
>"
>
>Signed-off-by: Peng Fan <van.freenix at gmail.com>
>Cc: York Sun <york.sun at nxp.com>
>Cc: Yangbo Lu <yangbo.lu at nxp.com>
>Cc: Hector Palacios <hector.palacios at digi.com>
>Cc: Eric Nelson <eric at nelint.com>
>Cc: Stefano Babic <sbabic at denx.de>
>Cc: Fabio Estevam <fabio.estevam at nxp.com>
>Cc: Pantelis Antoniou <panto at antoniou-consulting.com>
>Cc: Simon Glass <sjg at chromium.org>
>---
>
>V3:
> Fix build error reported by York for PPC.
>
>V2:
> restructure the V1 patch.
> Introduce fsl_esdhc_priv structure.
> Introduce code to handle cd-gpios and non-removable.
>
> drivers/mmc/fsl_esdhc.c | 253 ++++++++++++++++++++++++++++++++++++++++--------
> 1 file changed, 213 insertions(+), 40 deletions(-)
>
>diff --git a/drivers/mmc/fsl_esdhc.c b/drivers/mmc/fsl_esdhc.c
>index ea5f4bf..3acf9e8 100644
>--- a/drivers/mmc/fsl_esdhc.c
>+++ b/drivers/mmc/fsl_esdhc.c
>@@ -20,6 +20,8 @@
> #include <fsl_esdhc.h>
> #include <fdt_support.h>
> #include <asm/io.h>
>+#include <dm.h>
>+#include <asm-generic/gpio.h>
>
> DECLARE_GLOBAL_DATA_PTR;
>
>@@ -72,6 +74,30 @@ struct fsl_esdhc {
>       uint    scr;            /* eSDHC control register */
> };
>
>+/**
>+ * struct fsl_esdhc_priv
>+ *
>+ * @esdhc_regs: registers of the sdhc controller
>+ * @sdhc_clk: Current clk of the sdhc controller
>+ * @bus_width: bus width, 1bit, 4bit or 8bit
>+ * @cfg: mmc config
>+ * @mmc: mmc
>+ * Following is used when Driver Model is enabled for MMC
>+ * @dev: pointer for the device
>+ * @non_removable: 0: removable; 1: non-removable
>+ * @cd_gpio: gpio for card detection
>+ */
>+struct fsl_esdhc_priv {
>+      struct fsl_esdhc *esdhc_regs;
>+      unsigned int sdhc_clk;
>+      unsigned int bus_width;
>+      struct mmc_config cfg;
>+      struct mmc *mmc;
>+      struct udevice *dev;
>+      int non_removable;
>+      struct gpio_desc cd_gpio;
>+};
>+
> /* Return the XFERTYP flags for a given command and data packet */
> static uint esdhc_xfertyp(struct mmc_cmd *cmd, struct mmc_data *data)
> {
>@@ -118,8 +144,8 @@ static uint esdhc_xfertyp(struct mmc_cmd *cmd, struct mmc_data *data)
> static void
> esdhc_pio_read_write(struct mmc *mmc, struct mmc_data *data)
> {
>-      struct fsl_esdhc_cfg *cfg = mmc->priv;
>-      struct fsl_esdhc *regs = (struct fsl_esdhc *)cfg->esdhc_base;
>+      struct fsl_esdhc_priv *priv = mmc->priv;
>+      struct fsl_esdhc *regs = priv->esdhc_regs;
>       uint blocks;
>       char *buffer;
>       uint databuf;
>@@ -180,8 +206,8 @@ esdhc_pio_read_write(struct mmc *mmc, struct mmc_data *data)
> static int esdhc_setup_data(struct mmc *mmc, struct mmc_data *data)
> {
>       int timeout;
>-      struct fsl_esdhc_cfg *cfg = mmc->priv;
>-      struct fsl_esdhc *regs = (struct fsl_esdhc *)cfg->esdhc_base;
>+      struct fsl_esdhc_priv *priv = mmc->priv;
>+      struct fsl_esdhc *regs = priv->esdhc_regs;
> #ifdef CONFIG_FSL_LAYERSCAPE
>       dma_addr_t addr;
> #endif
>@@ -312,8 +338,8 @@ esdhc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data)
>       int     err = 0;
>       uint    xfertyp;
>       uint    irqstat;
>-      struct fsl_esdhc_cfg *cfg = mmc->priv;
>-      volatile struct fsl_esdhc *regs = (struct fsl_esdhc *)cfg->esdhc_base;
>+      struct fsl_esdhc_priv *priv = mmc->priv;
>+      struct fsl_esdhc *regs = priv->esdhc_regs;
>
> #ifdef CONFIG_SYS_FSL_ERRATUM_ESDHC111
>       if (cmd->cmdidx == MMC_CMD_STOP_TRANSMISSION)
>@@ -482,9 +508,9 @@ out:
> static void set_sysctl(struct mmc *mmc, uint clock)
> {
>       int div, pre_div;
>-      struct fsl_esdhc_cfg *cfg = mmc->priv;
>-      volatile struct fsl_esdhc *regs = (struct fsl_esdhc *)cfg->esdhc_base;
>-      int sdhc_clk = cfg->sdhc_clk;
>+      struct fsl_esdhc_priv *priv = mmc->priv;
>+      struct fsl_esdhc *regs = priv->esdhc_regs;
>+      int sdhc_clk = priv->sdhc_clk;
>       uint clk;
>
>       if (clock < mmc->cfg->f_min)
>@@ -527,8 +553,8 @@ static void set_sysctl(struct mmc *mmc, uint clock)
> #ifdef CONFIG_FSL_ESDHC_USE_PERIPHERAL_CLK
> static void esdhc_clock_control(struct mmc *mmc, bool enable)
> {
>-      struct fsl_esdhc_cfg *cfg = mmc->priv;
>-      struct fsl_esdhc *regs = (struct fsl_esdhc *)cfg->esdhc_base;
>+      struct fsl_esdhc_priv *priv = mmc->priv;
>+      struct fsl_esdhc *regs = priv->esdhc_regs;
>       u32 value;
>       u32 time_out;
>
>@@ -556,8 +582,8 @@ static void esdhc_clock_control(struct mmc *mmc, bool enable)
>
> static void esdhc_set_ios(struct mmc *mmc)
> {
>-      struct fsl_esdhc_cfg *cfg = mmc->priv;
>-      struct fsl_esdhc *regs = (struct fsl_esdhc *)cfg->esdhc_base;
>+      struct fsl_esdhc_priv *priv = mmc->priv;
>+      struct fsl_esdhc *regs = priv->esdhc_regs;
>
> #ifdef CONFIG_FSL_ESDHC_USE_PERIPHERAL_CLK
>       /* Select to use peripheral clock */
>@@ -580,8 +606,8 @@ static void esdhc_set_ios(struct mmc *mmc)
>
> static int esdhc_init(struct mmc *mmc)
> {
>-      struct fsl_esdhc_cfg *cfg = mmc->priv;
>-      struct fsl_esdhc *regs = (struct fsl_esdhc *)cfg->esdhc_base;
>+      struct fsl_esdhc_priv *priv = mmc->priv;
>+      struct fsl_esdhc *regs = priv->esdhc_regs;
>       int timeout = 1000;
>
>       /* Reset the entire host controller */
>@@ -621,14 +647,23 @@ static int esdhc_init(struct mmc *mmc)
>
> static int esdhc_getcd(struct mmc *mmc)
> {
>-      struct fsl_esdhc_cfg *cfg = mmc->priv;
>-      struct fsl_esdhc *regs = (struct fsl_esdhc *)cfg->esdhc_base;
>+      struct fsl_esdhc_priv *priv = mmc->priv;
>+      struct fsl_esdhc *regs = priv->esdhc_regs;
>       int timeout = 1000;
>
> #ifdef CONFIG_ESDHC_DETECT_QUIRK
>       if (CONFIG_ESDHC_DETECT_QUIRK)
>               return 1;
> #endif
>+
>+#ifdef CONFIG_DM_MMC
>+      if (priv->non_removable)
>+              return 1;
>+
>+      if (dm_gpio_is_valid(&priv->cd_gpio))
>+              return dm_gpio_get_value(&priv->cd_gpio);
>+#endif
>+
>       while (!(esdhc_read32(&regs->prsstat) & PRSSTAT_CINS) && --timeout)
>               udelay(1000);
>
>@@ -656,16 +691,29 @@ static const struct mmc_ops esdhc_ops = {
>       .getcd          = esdhc_getcd,
> };
>
>-int fsl_esdhc_initialize(bd_t *bis, struct fsl_esdhc_cfg *cfg)
>+static int fsl_esdhc_cfg_to_priv(struct fsl_esdhc_cfg *cfg,
>+                               struct fsl_esdhc_priv *priv)
>+{
>+      if (!cfg || !priv)
>+              return -EINVAL;
>+
>+      priv->esdhc_regs = (struct fsl_esdhc *)(unsigned long)(cfg->esdhc_base);
>+      priv->bus_width = cfg->max_bus_width;
>+      priv->sdhc_clk = cfg->sdhc_clk;
>+
>+      return 0;
>+};
>+
>+static int fsl_esdhc_init(struct fsl_esdhc_priv *priv)
> {
>       struct fsl_esdhc *regs;
>       struct mmc *mmc;
>       u32 caps, voltage_caps;
>
>-      if (!cfg)
>-              return -1;
>+      if (!priv)
>+              return -EINVAL;
>
>-      regs = (struct fsl_esdhc *)cfg->esdhc_base;
>+      regs = priv->esdhc_regs;
>
>       /* First reset the eSDHC controller */
>       esdhc_reset(regs);
>@@ -676,7 +724,7 @@ int fsl_esdhc_initialize(bd_t *bis, struct fsl_esdhc_cfg *cfg)
> #endif
>
>       writel(SDHCI_IRQ_EN_BITS, &regs->irqstaten);
>-      memset(&cfg->cfg, 0, sizeof(cfg->cfg));
>+      memset(&priv->cfg, 0, sizeof(priv->cfg));
>
>       voltage_caps = 0;
>       caps = esdhc_read32(&regs->hostcapblt);
>@@ -698,47 +746,83 @@ int fsl_esdhc_initialize(bd_t *bis, struct fsl_esdhc_cfg *cfg)
>       if (caps & ESDHC_HOSTCAPBLT_VS33)
>               voltage_caps |= MMC_VDD_32_33 | MMC_VDD_33_34;
>
>-      cfg->cfg.name = "FSL_SDHC";
>-      cfg->cfg.ops = &esdhc_ops;
>+      priv->cfg.name = "FSL_SDHC";
>+      priv->cfg.ops = &esdhc_ops;
> #ifdef CONFIG_SYS_SD_VOLTAGE
>-      cfg->cfg.voltages = CONFIG_SYS_SD_VOLTAGE;
>+      priv->cfg.voltages = CONFIG_SYS_SD_VOLTAGE;
> #else
>-      cfg->cfg.voltages = MMC_VDD_32_33 | MMC_VDD_33_34;
>+      priv->cfg.voltages = MMC_VDD_32_33 | MMC_VDD_33_34;
> #endif
>-      if ((cfg->cfg.voltages & voltage_caps) == 0) {
>+      if ((priv->cfg.voltages & voltage_caps) == 0) {
>               printf("voltage not supported by controller\n");
>               return -1;
>       }
>
>-      cfg->cfg.host_caps = MMC_MODE_4BIT | MMC_MODE_8BIT;
>+      if (priv->bus_width == 8)
>+              priv->cfg.host_caps = MMC_MODE_4BIT | MMC_MODE_8BIT;
>+      else if (priv->bus_width == 4)
>+              priv->cfg.host_caps = MMC_MODE_4BIT;
>+
>+      priv->cfg.host_caps = MMC_MODE_4BIT | MMC_MODE_8BIT;
> #ifdef CONFIG_SYS_FSL_ESDHC_HAS_DDR_MODE
>-      cfg->cfg.host_caps |= MMC_MODE_DDR_52MHz;
>+      priv->cfg.host_caps |= MMC_MODE_DDR_52MHz;
> #endif
>
>-      if (cfg->max_bus_width > 0) {
>-              if (cfg->max_bus_width < 8)
>-                      cfg->cfg.host_caps &= ~MMC_MODE_8BIT;
>-              if (cfg->max_bus_width < 4)
>-                      cfg->cfg.host_caps &= ~MMC_MODE_4BIT;
>+      if (priv->bus_width > 0) {
>+              if (priv->bus_width < 8)
>+                      priv->cfg.host_caps &= ~MMC_MODE_8BIT;
>+              if (priv->bus_width < 4)
>+                      priv->cfg.host_caps &= ~MMC_MODE_4BIT;
>       }
>
>       if (caps & ESDHC_HOSTCAPBLT_HSS)
>-              cfg->cfg.host_caps |= MMC_MODE_HS_52MHz | MMC_MODE_HS;
>+              priv->cfg.host_caps |= MMC_MODE_HS_52MHz | MMC_MODE_HS;
>
> #ifdef CONFIG_ESDHC_DETECT_8_BIT_QUIRK
>       if (CONFIG_ESDHC_DETECT_8_BIT_QUIRK)
>-              cfg->cfg.host_caps &= ~MMC_MODE_8BIT;
>+              priv->cfg.host_caps &= ~MMC_MODE_8BIT;
> #endif
>
>-      cfg->cfg.f_min = 400000;
>-      cfg->cfg.f_max = min(cfg->sdhc_clk, (u32)52000000);
>+      priv->cfg.f_min = 400000;
>+      priv->cfg.f_max = min(priv->sdhc_clk, (u32)52000000);
>
>-      cfg->cfg.b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT;
>+      priv->cfg.b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT;
>
>-      mmc = mmc_create(&cfg->cfg, cfg);
>+      mmc = mmc_create(&priv->cfg, priv);
>       if (mmc == NULL)
>               return -1;
>
>+      priv->mmc = mmc;
>+
>+      return 0;
>+}
>+
>+int fsl_esdhc_initialize(bd_t *bis, struct fsl_esdhc_cfg *cfg)
>+{
>+      struct fsl_esdhc_priv *priv;
>+      int ret;
>+
>+      if (!cfg)
>+              return -EINVAL;
>+
>+      priv = calloc(sizeof(struct fsl_esdhc_priv), 1);
>+      if (!priv)
>+              return -ENOMEM;
>+
>+      ret = fsl_esdhc_cfg_to_priv(cfg, priv);
>+      if (ret) {
>+              debug("%s xlate failure\n", __func__);
>+              free(priv);
>+              return ret;
>+      }
>+
>+      ret = fsl_esdhc_init(priv);
>+      if (ret) {
>+              debug("%s init failure\n", __func__);
>+              free(priv);
>+              return ret;
>+      }
>+
>       return 0;
> }
>
>@@ -819,3 +903,92 @@ void fdt_fixup_esdhc(void *blob, bd_t *bd)
>                          4 + 1, 1);
> }
> #endif
>+
>+#ifdef CONFIG_DM_MMC
>+#include <asm/arch/clock.h>
>+static int fsl_esdhc_probe(struct udevice *dev)
>+{
>+      struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev);
>+      struct fsl_esdhc_priv *priv = dev_get_priv(dev);
>+      const void *fdt = gd->fdt_blob;
>+      int node = dev->of_offset;
>+      fdt_addr_t addr;
>+      unsigned int val;
>+      int ret;
>+
>+      addr = dev_get_addr(dev);
>+      if (addr == FDT_ADDR_T_NONE)
>+              return -EINVAL;
>+
>+      priv->esdhc_regs = (struct fsl_esdhc *)addr;
>+      priv->dev = dev;
>+
>+      val = fdtdec_get_int(fdt, node, "bus-width", -1);
>+      if (val == 8)
>+              priv->bus_width = 8;
>+      else if (val == 4)
>+              priv->bus_width = 4;
>+      else
>+              priv->bus_width = 1;
>+
>+      if (fdt_get_property(fdt, node, "non-removable", NULL)) {
>+              priv->non_removable = 1;
>+       } else {
>+              priv->non_removable = 0;
>+              gpio_request_by_name_nodev(fdt, node, "cd-gpios", 0,
>+                                         &priv->cd_gpio, GPIOD_IS_IN);
>+      }
>+
>+      /*
>+       * TODO:
>+       * Because lack of clk driver, if SDHC clk is not enabled,
>+       * need to enable it first before this driver is invoked.
>+       *
>+       * we use MXC_ESDHC_CLK to get clk freq.
>+       * If one would like to make this function work,
>+       * the aliases should be provided in dts as this:
>+       *
>+       *  aliases {
>+       *      mmc0 = &usdhc1;
>+       *      mmc1 = &usdhc2;
>+       *      mmc2 = &usdhc3;
>+       *      mmc3 = &usdhc4;
>+       *      };
>+       * Then if your board only supports mmc2 and mmc3, but we can
>+       * correctly get the seq as 2 and 3, then let mxc_get_clock
>+       * work as expected.
>+       */
>+      priv->sdhc_clk = mxc_get_clock(MXC_ESDHC_CLK + dev->seq);
>+      if (priv->sdhc_clk <= 0) {
>+              dev_err(dev, "Unable to get clk for %s\n", dev->name);
>+              return -EINVAL;
>+      }
>+
>+      ret = fsl_esdhc_init(priv);
>+      if (ret) {
>+              dev_err(dev, "fsl_esdhc_init failure\n");
>+              return ret;
>+      }
>+
>+      upriv->mmc = priv->mmc;
>+
>+      return 0;
>+}
>+
>+static const struct udevice_id fsl_esdhc_ids[] = {
>+      { .compatible = "fsl,imx6ul-usdhc", },
>+      { .compatible = "fsl,imx6sx-usdhc", },
>+      { .compatible = "fsl,imx6sl-usdhc", },
>+      { .compatible = "fsl,imx6q-usdhc", },
>+      { .compatible = "fsl,imx7d-usdhc", },
>+      { /* sentinel */ }
>+};
>+
>+U_BOOT_DRIVER(fsl_esdhc) = {
>+      .name   = "fsl-esdhc-mmc",
>+      .id     = UCLASS_MMC,
>+      .of_match = fsl_esdhc_ids,
>+      .probe  = fsl_esdhc_probe,
>+      .priv_auto_alloc_size = sizeof(struct fsl_esdhc_priv),
>+};
>+#endif
>--
>2.6.2
>


More information about the U-Boot mailing list