
(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@gmail.com Sent: Sunday, March 27, 2016 7:59 AM To: york sun; panto@antoniou-consulting.com; sbabic@denx.de; sjg@chromium.org Cc: u-boot@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.
- Introduce a new structure struct fsl_esdhc_priv
- 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.
- 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@02100000 mmc [ + ] | |-- usdhc@02190000 mmc [ + ] | |-- usdhc@02194000 .... => mmc list FSL_SDHC: 0 (SD) FSL_SDHC: 1 (SD) "
Signed-off-by: Peng Fan van.freenix@gmail.com Cc: York Sun york.sun@nxp.com Cc: Yangbo Lu yangbo.lu@nxp.com Cc: Hector Palacios hector.palacios@digi.com Cc: Eric Nelson eric@nelint.com Cc: Stefano Babic sbabic@denx.de Cc: Fabio Estevam fabio.estevam@nxp.com Cc: Pantelis Antoniou panto@antoniou-consulting.com Cc: Simon Glass sjg@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(®s->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, ®s->irqstaten);
memset(&cfg->cfg, 0, sizeof(cfg->cfg));
memset(&priv->cfg, 0, sizeof(priv->cfg)); voltage_caps = 0; caps = esdhc_read32(®s->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