From 3d296365e4e8823c7c0d4b568fa7accfae4bf895 Mon Sep 17 00:00:00 2001 From: Faiz Abbas Date: Tue, 11 Jun 2019 00:43:34 +0530 Subject: mmc: sdhci: Add support for sdhci-caps-mask Add Support for masking some bits in the capabilities register of a host controller. Also remove the redundant readl() into caps1. Signed-off-by: Faiz Abbas Reviewed-by: Tom Rini --- drivers/mmc/sdhci.c | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) (limited to 'drivers/mmc/sdhci.c') diff --git a/drivers/mmc/sdhci.c b/drivers/mmc/sdhci.c index c4e88790bc..742a54dacd 100644 --- a/drivers/mmc/sdhci.c +++ b/drivers/mmc/sdhci.c @@ -8,6 +8,7 @@ */ #include +#include #include #include #include @@ -681,8 +682,18 @@ int sdhci_setup_cfg(struct mmc_config *cfg, struct sdhci_host *host, u32 f_max, u32 f_min) { u32 caps, caps_1 = 0; +#if CONFIG_IS_ENABLED(DM_MMC) + u32 mask[2] = {0}; + int ret; + ret = dev_read_u32_array(host->mmc->dev, "sdhci-caps-mask", + mask, 2); + if (ret && ret != -1) + return ret; + caps = ~mask[1] & sdhci_readl(host, SDHCI_CAPABILITIES); +#else caps = sdhci_readl(host, SDHCI_CAPABILITIES); +#endif #ifdef CONFIG_MMC_SDHCI_SDMA if (!(caps & SDHCI_CAN_DO_SDMA)) { @@ -722,7 +733,11 @@ int sdhci_setup_cfg(struct mmc_config *cfg, struct sdhci_host *host, /* Check whether the clock multiplier is supported or not */ if (SDHCI_GET_VERSION(host) >= SDHCI_SPEC_300) { +#if CONFIG_IS_ENABLED(DM_MMC) + caps_1 = ~mask[0] & sdhci_readl(host, SDHCI_CAPABILITIES_1); +#else caps_1 = sdhci_readl(host, SDHCI_CAPABILITIES_1); +#endif host->clk_mul = (caps_1 & SDHCI_CLOCK_MUL_MASK) >> SDHCI_CLOCK_MUL_SHIFT; } @@ -779,9 +794,6 @@ int sdhci_setup_cfg(struct mmc_config *cfg, struct sdhci_host *host, cfg->host_caps &= ~MMC_MODE_HS_52MHz; } - if (SDHCI_GET_VERSION(host) >= SDHCI_SPEC_300) - caps_1 = sdhci_readl(host, SDHCI_CAPABILITIES_1); - if (!(cfg->voltages & MMC_VDD_165_195) || (host->quirks & SDHCI_QUIRK_NO_1_8_V)) caps_1 &= ~(SDHCI_SUPPORT_SDR104 | SDHCI_SUPPORT_SDR50 | -- cgit v1.2.3 From 3966c7d0060e7651f1f4e65349bc810426f61602 Mon Sep 17 00:00:00 2001 From: Faiz Abbas Date: Tue, 11 Jun 2019 00:43:35 +0530 Subject: mmc: sdhci: Make sdhci_set_clock() non static The am654_sdhci driver needs to switch the clock off before disabling its phy dll and needs to re-enable the clock before enabling the phy again. Therefore, make the sdhci_set_clock() function accessible in the am654_sdhci driver. Signed-off-by: Faiz Abbas Reviewed-by: Tom Rini --- drivers/mmc/sdhci.c | 2 +- include/sdhci.h | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/mmc/sdhci.c') diff --git a/drivers/mmc/sdhci.c b/drivers/mmc/sdhci.c index 742a54dacd..151e1e3c66 100644 --- a/drivers/mmc/sdhci.c +++ b/drivers/mmc/sdhci.c @@ -410,7 +410,7 @@ static int sdhci_execute_tuning(struct udevice *dev, uint opcode) return 0; } #endif -static int sdhci_set_clock(struct mmc *mmc, unsigned int clock) +int sdhci_set_clock(struct mmc *mmc, unsigned int clock) { struct sdhci_host *host = mmc->priv; unsigned int div, clk = 0, timeout; diff --git a/include/sdhci.h b/include/sdhci.h index eee493ab5f..820cd16e92 100644 --- a/include/sdhci.h +++ b/include/sdhci.h @@ -470,6 +470,7 @@ int add_sdhci(struct sdhci_host *host, u32 f_max, u32 f_min); #ifdef CONFIG_DM_MMC /* Export the operations to drivers */ int sdhci_probe(struct udevice *dev); +int sdhci_set_clock(struct mmc *mmc, unsigned int clock); extern const struct dm_mmc_ops sdhci_ops; #else #endif -- cgit v1.2.3 From a8185c50d384c0a4eb8ff5a542cc96cd8c4bb57e Mon Sep 17 00:00:00 2001 From: Faiz Abbas Date: Tue, 11 Jun 2019 00:43:37 +0530 Subject: mmc: sdhci: Make set_ios_post() return int Make set_ios_post() return int to faciliate error handling in platform drivers. Signed-off-by: Faiz Abbas --- drivers/mmc/sdhci.c | 2 +- drivers/mmc/xenon_sdhci.c | 4 +++- include/sdhci.h | 2 +- 3 files changed, 5 insertions(+), 3 deletions(-) (limited to 'drivers/mmc/sdhci.c') diff --git a/drivers/mmc/sdhci.c b/drivers/mmc/sdhci.c index 151e1e3c66..61cf216e12 100644 --- a/drivers/mmc/sdhci.c +++ b/drivers/mmc/sdhci.c @@ -584,7 +584,7 @@ static int sdhci_set_ios(struct mmc *mmc) /* If available, call the driver specific "post" set_ios() function */ if (host->ops && host->ops->set_ios_post) - host->ops->set_ios_post(host); + return host->ops->set_ios_post(host); return 0; } diff --git a/drivers/mmc/xenon_sdhci.c b/drivers/mmc/xenon_sdhci.c index b576511338..829b75683b 100644 --- a/drivers/mmc/xenon_sdhci.c +++ b/drivers/mmc/xenon_sdhci.c @@ -326,7 +326,7 @@ static void xenon_mask_cmd_conflict_err(struct sdhci_host *host) } /* Platform specific function for post set_ios configuration */ -static void xenon_sdhci_set_ios_post(struct sdhci_host *host) +static int xenon_sdhci_set_ios_post(struct sdhci_host *host) { struct xenon_sdhci_priv *priv = host->mmc->priv; uint speed = host->mmc->tran_speed; @@ -364,6 +364,8 @@ static void xenon_sdhci_set_ios_post(struct sdhci_host *host) /* Re-init the PHY */ xenon_mmc_phy_set(host); + + return 0; } /* Install a driver specific handler for post set_ios configuration */ diff --git a/include/sdhci.h b/include/sdhci.h index 820cd16e92..3dcbc14965 100644 --- a/include/sdhci.h +++ b/include/sdhci.h @@ -247,7 +247,7 @@ struct sdhci_ops { #endif int (*get_cd)(struct sdhci_host *host); void (*set_control_reg)(struct sdhci_host *host); - void (*set_ios_post)(struct sdhci_host *host); + int (*set_ios_post)(struct sdhci_host *host); void (*set_clock)(struct sdhci_host *host, u32 div); int (*platform_execute_tuning)(struct mmc *host, u8 opcode); void (*set_delay)(struct sdhci_host *host); -- cgit v1.2.3 From d1c0a2200afb398f67a0c2c84948a079b44290a1 Mon Sep 17 00:00:00 2001 From: Faiz Abbas Date: Tue, 11 Jun 2019 00:43:40 +0530 Subject: mmc: sdhci: Add support for HOST_CONTROL2 and setting UHS timings The HOST_CONTROL2 register is a part of SDHC v3.00 and not just specific to arasan/zynq controllers. Add the same to sdhci.h. Also create a common API to set UHS timings in HOST_CONTROL2. Signed-off-by: Faiz Abbas Reviewed-by: Tom Rini --- drivers/mmc/sdhci.c | 28 ++++++++++++++++++++++++++++ drivers/mmc/zynq_sdhci.c | 45 +++++++++------------------------------------ include/sdhci.h | 19 ++++++++++++++++++- 3 files changed, 55 insertions(+), 37 deletions(-) (limited to 'drivers/mmc/sdhci.c') diff --git a/drivers/mmc/sdhci.c b/drivers/mmc/sdhci.c index 61cf216e12..0a0770cc20 100644 --- a/drivers/mmc/sdhci.c +++ b/drivers/mmc/sdhci.c @@ -534,6 +534,34 @@ static void sdhci_set_power(struct sdhci_host *host, unsigned short power) sdhci_writeb(host, pwr, SDHCI_POWER_CONTROL); } +void sdhci_set_uhs_timing(struct sdhci_host *host) +{ + struct mmc *mmc = (struct mmc *)host->mmc; + u32 reg; + + reg = sdhci_readw(host, SDHCI_HOST_CONTROL2); + reg &= ~SDHCI_CTRL_UHS_MASK; + + switch (mmc->selected_mode) { + case UHS_SDR50: + case MMC_HS_52: + reg |= SDHCI_CTRL_UHS_SDR50; + break; + case UHS_DDR50: + case MMC_DDR_52: + reg |= SDHCI_CTRL_UHS_DDR50; + break; + case UHS_SDR104: + case MMC_HS_200: + reg |= SDHCI_CTRL_UHS_SDR104; + break; + default: + reg |= SDHCI_CTRL_UHS_SDR12; + } + + sdhci_writew(host, reg, SDHCI_HOST_CONTROL2); +} + #ifdef CONFIG_DM_MMC static int sdhci_set_ios(struct udevice *dev) { diff --git a/drivers/mmc/zynq_sdhci.c b/drivers/mmc/zynq_sdhci.c index 08023783de..c525084250 100644 --- a/drivers/mmc/zynq_sdhci.c +++ b/drivers/mmc/zynq_sdhci.c @@ -48,11 +48,6 @@ static const u8 mode2timing[] = { [MMC_HS_200] = MMC_HS200_BUS_SPEED, }; -#define SDHCI_HOST_CTRL2 0x3E -#define SDHCI_CTRL2_MODE_MASK 0x7 -#define SDHCI_18V_SIGNAL 0x8 -#define SDHCI_CTRL_EXEC_TUNING 0x0040 -#define SDHCI_CTRL_TUNED_CLK 0x80 #define SDHCI_TUNING_LOOP_COUNT 40 static void arasan_zynqmp_dll_reset(struct sdhci_host *host, u8 deviceid) @@ -99,9 +94,9 @@ static int arasan_sdhci_execute_tuning(struct mmc *mmc, u8 opcode) host = priv->host; deviceid = priv->deviceid; - ctrl = sdhci_readw(host, SDHCI_HOST_CTRL2); + ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2); ctrl |= SDHCI_CTRL_EXEC_TUNING; - sdhci_writew(host, ctrl, SDHCI_HOST_CTRL2); + sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2); mdelay(1); @@ -133,7 +128,7 @@ static int arasan_sdhci_execute_tuning(struct mmc *mmc, u8 opcode) sdhci_writew(host, SDHCI_TRNS_READ, SDHCI_TRANSFER_MODE); mmc_send_cmd(mmc, &cmd, NULL); - ctrl = sdhci_readw(host, SDHCI_HOST_CTRL2); + ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2); if (cmd.cmdidx == MMC_CMD_SEND_TUNING_BLOCK) udelay(1); @@ -142,7 +137,7 @@ static int arasan_sdhci_execute_tuning(struct mmc *mmc, u8 opcode) if (tuning_loop_counter < 0) { ctrl &= ~SDHCI_CTRL_TUNED_CLK; - sdhci_writel(host, ctrl, SDHCI_HOST_CTRL2); + sdhci_writel(host, ctrl, SDHCI_HOST_CONTROL2); } if (!(ctrl & SDHCI_CTRL_TUNED_CLK)) { @@ -184,36 +179,14 @@ static void arasan_sdhci_set_control_reg(struct sdhci_host *host) return; if (mmc->signal_voltage == MMC_SIGNAL_VOLTAGE_180) { - reg = sdhci_readw(host, SDHCI_HOST_CTRL2); - reg |= SDHCI_18V_SIGNAL; - sdhci_writew(host, reg, SDHCI_HOST_CTRL2); + reg = sdhci_readw(host, SDHCI_HOST_CONTROL2); + reg |= SDHCI_CTRL_VDD_180; + sdhci_writew(host, reg, SDHCI_HOST_CONTROL2); } if (mmc->selected_mode > SD_HS && - mmc->selected_mode <= UHS_DDR50) { - reg = sdhci_readw(host, SDHCI_HOST_CTRL2); - reg &= ~SDHCI_CTRL2_MODE_MASK; - switch (mmc->selected_mode) { - case UHS_SDR12: - reg |= UHS_SDR12_BUS_SPEED; - break; - case UHS_SDR25: - reg |= UHS_SDR25_BUS_SPEED; - break; - case UHS_SDR50: - reg |= UHS_SDR50_BUS_SPEED; - break; - case UHS_SDR104: - reg |= UHS_SDR104_BUS_SPEED; - break; - case UHS_DDR50: - reg |= UHS_DDR50_BUS_SPEED; - break; - default: - break; - } - sdhci_writew(host, reg, SDHCI_HOST_CTRL2); - } + mmc->selected_mode <= UHS_DDR50) + sdhci_set_uhs_timing(host); } #endif diff --git a/include/sdhci.h b/include/sdhci.h index 3dcbc14965..01addb7a60 100644 --- a/include/sdhci.h +++ b/include/sdhci.h @@ -144,7 +144,23 @@ #define SDHCI_ACMD12_ERR 0x3C -/* 3E-3F reserved */ +#define SDHCI_HOST_CONTROL2 0x3E +#define SDHCI_CTRL_UHS_MASK 0x0007 +#define SDHCI_CTRL_UHS_SDR12 0x0000 +#define SDHCI_CTRL_UHS_SDR25 0x0001 +#define SDHCI_CTRL_UHS_SDR50 0x0002 +#define SDHCI_CTRL_UHS_SDR104 0x0003 +#define SDHCI_CTRL_UHS_DDR50 0x0004 +#define SDHCI_CTRL_HS400 0x0005 /* Non-standard */ +#define SDHCI_CTRL_VDD_180 0x0008 +#define SDHCI_CTRL_DRV_TYPE_MASK 0x0030 +#define SDHCI_CTRL_DRV_TYPE_B 0x0000 +#define SDHCI_CTRL_DRV_TYPE_A 0x0010 +#define SDHCI_CTRL_DRV_TYPE_C 0x0020 +#define SDHCI_CTRL_DRV_TYPE_D 0x0030 +#define SDHCI_CTRL_EXEC_TUNING 0x0040 +#define SDHCI_CTRL_TUNED_CLK 0x0080 +#define SDHCI_CTRL_PRESET_VAL_ENABLE 0x8000 #define SDHCI_CAPABILITIES 0x40 #define SDHCI_TIMEOUT_CLK_MASK 0x0000003F @@ -467,6 +483,7 @@ int sdhci_bind(struct udevice *dev, struct mmc *mmc, struct mmc_config *cfg); int add_sdhci(struct sdhci_host *host, u32 f_max, u32 f_min); #endif /* !CONFIG_BLK */ +void sdhci_set_uhs_timing(struct sdhci_host *host); #ifdef CONFIG_DM_MMC /* Export the operations to drivers */ int sdhci_probe(struct udevice *dev); -- cgit v1.2.3