#include <config.h>
#include <common.h>
#include <command.h>
+#include <errno.h>
#include <hwconfig.h>
#include <mmc.h>
#include <part.h>
#include <malloc.h>
-#include <mmc.h>
#include <fsl_esdhc.h>
#include <fdt_support.h>
#include <asm/io.h>
struct udevice *dev;
int non_removable;
int wp_enable;
+#ifdef CONFIG_DM_GPIO
struct gpio_desc cd_gpio;
struct gpio_desc wp_gpio;
+#endif
};
/* Return the XFERTYP flags for a given command and data packet */
if ((esdhc_read32(®s->prsstat) &
PRSSTAT_WPSPL) == 0) {
printf("\nThe SD card is locked. Can not write to a locked card.\n\n");
- return TIMEOUT;
+ return -ETIMEDOUT;
}
}
irqstat = esdhc_read32(®s->irqstat);
if (irqstat & CMD_ERR) {
- err = COMM_ERR;
+ err = -ECOMM;
goto out;
}
if (irqstat & IRQSTAT_CTOE) {
- err = TIMEOUT;
+ err = -ETIMEDOUT;
goto out;
}
if (timeout <= 0) {
printf("Timeout waiting for DAT0 to go high!\n");
- err = TIMEOUT;
+ err = -ETIMEDOUT;
goto out;
}
}
irqstat = esdhc_read32(®s->irqstat);
if (irqstat & IRQSTAT_DTOE) {
- err = TIMEOUT;
+ err = -ETIMEDOUT;
goto out;
}
if (irqstat & DATA_ERR) {
- err = COMM_ERR;
+ err = -ECOMM;
goto out;
}
} while ((irqstat & DATA_COMPLETE) != DATA_COMPLETE);
static void set_sysctl(struct mmc *mmc, uint clock)
{
- int div, pre_div;
+ int div = 1;
+#ifdef ARCH_MXC
+ int pre_div = 1;
+#else
+ int pre_div = 2;
+#endif
+ int ddr_pre_div = mmc->ddr_mode ? 2 : 1;
struct fsl_esdhc_priv *priv = mmc->priv;
struct fsl_esdhc *regs = priv->esdhc_regs;
int sdhc_clk = priv->sdhc_clk;
if (clock < mmc->cfg->f_min)
clock = mmc->cfg->f_min;
- if (sdhc_clk / 16 > clock) {
- for (pre_div = 2; pre_div < 256; pre_div *= 2)
- if ((sdhc_clk / pre_div) <= (clock * 16))
- break;
- } else
- pre_div = 2;
+ while (sdhc_clk / (16 * pre_div * ddr_pre_div) > clock && pre_div < 256)
+ pre_div *= 2;
- for (div = 1; div <= 16; div++)
- if ((sdhc_clk / (div * pre_div)) <= clock)
- break;
+ while (sdhc_clk / (div * pre_div * ddr_pre_div) > clock && div < 16)
+ div++;
- pre_div >>= mmc->ddr_mode ? 2 : 1;
+ pre_div >>= 1;
div -= 1;
clk = (pre_div << 8) | (div << 4);
}
#endif
-static void esdhc_set_ios(struct mmc *mmc)
+static int esdhc_set_ios(struct mmc *mmc)
{
struct fsl_esdhc_priv *priv = mmc->priv;
struct fsl_esdhc *regs = priv->esdhc_regs;
else if (mmc->bus_width == 8)
esdhc_setbits32(®s->proctl, PROCTL_DTW_8);
+ return 0;
}
static int esdhc_init(struct mmc *mmc)
#ifdef CONFIG_DM_MMC
if (priv->non_removable)
return 1;
-
+#ifdef CONFIG_DM_GPIO
if (dm_gpio_is_valid(&priv->cd_gpio))
return dm_gpio_get_value(&priv->cd_gpio);
#endif
+#endif
while (!(esdhc_read32(®s->prsstat) & PRSSTAT_CINS) && --timeout)
udelay(1000);
.getcd = esdhc_getcd,
};
-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;
- priv->wp_enable = cfg->wp_enable;
-
- return 0;
-};
-
static int fsl_esdhc_init(struct fsl_esdhc_priv *priv)
{
struct fsl_esdhc *regs;
return 0;
}
+#ifndef CONFIG_DM_MMC
+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;
+ priv->wp_enable = cfg->wp_enable;
+
+ return 0;
+};
+
int fsl_esdhc_initialize(bd_t *bis, struct fsl_esdhc_cfg *cfg)
{
struct fsl_esdhc_priv *priv;
cfg->sdhc_clk = gd->arch.sdhc_clk;
return fsl_esdhc_initialize(bis, cfg);
}
+#endif
#ifdef CONFIG_FSL_ESDHC_ADAPTER_IDENT
void mmc_adapter_card_type_ident(void)
#endif
#ifdef CONFIG_OF_LIBFDT
-void fdt_fixup_esdhc(void *blob, bd_t *bd)
+__weak int esdhc_status_fixup(void *blob, const char *compat)
{
- const char *compat = "fsl,esdhc";
-
#ifdef CONFIG_FSL_ESDHC_PIN_MUX
if (!hwconfig("esdhc")) {
do_fixup_by_compat(blob, compat, "status", "disabled",
- 8 + 1, 1);
- return;
+ sizeof("disabled"), 1);
+ return 1;
}
#endif
+ do_fixup_by_compat(blob, compat, "status", "okay",
+ sizeof("okay"), 1);
+ return 0;
+}
+
+void fdt_fixup_esdhc(void *blob, bd_t *bd)
+{
+ const char *compat = "fsl,esdhc";
+
+ if (esdhc_status_fixup(blob, compat))
+ return;
#ifdef CONFIG_FSL_ESDHC_USE_PERIPHERAL_CLK
do_fixup_by_compat_u32(blob, compat, "peripheral-frequency",
do_fixup_by_compat_u32(blob, compat, "adapter-type",
(u32)(gd->arch.sdhc_adapter), 1);
#endif
- do_fixup_by_compat(blob, compat, "status", "okay",
- 4 + 1, 1);
}
#endif
#ifdef CONFIG_DM_MMC
#include <asm/arch/clock.h>
+__weak void init_clk_usdhc(u32 index)
+{
+}
+
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;
+ int node = dev_of_offset(dev);
fdt_addr_t addr;
unsigned int val;
int ret;
- addr = dev_get_addr(dev);
+ addr = devfdt_get_addr(dev);
if (addr == FDT_ADDR_T_NONE)
return -EINVAL;
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);
+#ifdef CONFIG_DM_GPIO
+ gpio_request_by_name_nodev(offset_to_ofnode(node), "cd-gpios",
+ 0, &priv->cd_gpio, GPIOD_IS_IN);
+#endif
}
priv->wp_enable = 1;
- ret = gpio_request_by_name_nodev(fdt, node, "wp-gpios", 0,
+#ifdef CONFIG_DM_GPIO
+ ret = gpio_request_by_name_nodev(offset_to_ofnode(node), "wp-gpios", 0,
&priv->wp_gpio, GPIOD_IS_IN);
if (ret)
priv->wp_enable = 0;
-
+#endif
/*
* TODO:
* Because lack of clk driver, if SDHC clk is not enabled,
* correctly get the seq as 2 and 3, then let mxc_get_clock
* work as expected.
*/
+
+ init_clk_usdhc(dev->seq);
+
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);
}
upriv->mmc = priv->mmc;
+ priv->mmc->dev = dev;
return 0;
}
{ .compatible = "fsl,imx6sl-usdhc", },
{ .compatible = "fsl,imx6q-usdhc", },
{ .compatible = "fsl,imx7d-usdhc", },
+ { .compatible = "fsl,imx7ulp-usdhc", },
+ { .compatible = "fsl,esdhc", },
{ /* sentinel */ }
};