From 300df508c806c0b0446f075bc7658f0fefa1b701 Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Mon, 5 Feb 2018 18:20:14 +0530 Subject: [PATCH 01/55] mmc: sdhci-omap: Update 'power_mode' outside sdhci_omap_init_74_clocks Updating 'power_mode' in sdhci_omap_init_74_clocks results in 'power_mode' never updated to MMC_POWER_OFF during card removal. This results in initialization sequence not sent to the card during re-insertion. Fix it here by adding sdhci_omap_set_power_mode to update power_mode. This function can also be used later to perform operations that are specific to a power mode (e.g, disable tuning during power off). Signed-off-by: Kishon Vijay Abraham I Acked-by: Adrian Hunter Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci-omap.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/drivers/mmc/host/sdhci-omap.c b/drivers/mmc/host/sdhci-omap.c index 628bfe9a3d17..96985786cadf 100644 --- a/drivers/mmc/host/sdhci-omap.c +++ b/drivers/mmc/host/sdhci-omap.c @@ -244,6 +244,12 @@ static int sdhci_omap_start_signal_voltage_switch(struct mmc_host *mmc, return 0; } +static void sdhci_omap_set_power_mode(struct sdhci_omap_host *omap_host, + u8 power_mode) +{ + omap_host->power_mode = power_mode; +} + static void sdhci_omap_set_bus_mode(struct sdhci_omap_host *omap_host, unsigned int mode) { @@ -273,6 +279,7 @@ static void sdhci_omap_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) sdhci_omap_set_bus_mode(omap_host, ios->bus_mode); sdhci_set_ios(mmc, ios); + sdhci_omap_set_power_mode(omap_host, ios->power_mode); } static u16 sdhci_omap_calc_divisor(struct sdhci_pltfm_host *host, @@ -401,8 +408,6 @@ static void sdhci_omap_init_74_clocks(struct sdhci_host *host, u8 power_mode) sdhci_omap_writel(omap_host, SDHCI_OMAP_STAT, INT_CC_EN); enable_irq(host->irq); - - omap_host->power_mode = power_mode; } static struct sdhci_ops sdhci_omap_ops = { @@ -504,6 +509,7 @@ static int sdhci_omap_probe(struct platform_device *pdev) omap_host->host = host; omap_host->base = host->ioaddr; omap_host->dev = dev; + omap_host->power_mode = MMC_POWER_UNDEFINED; host->ioaddr += offset; mmc = host->mmc; From 20ea26a1e3a513dadafcd35531c6d289820f60cb Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Mon, 5 Feb 2018 18:20:15 +0530 Subject: [PATCH 02/55] mmc: sdhci-omap: Add card_busy host ops MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add card_busy host ops in sdhci_omap to check card busy status. The voltage switching sequence for AM572x platform is mentioned in Figure 25-48. eMMC/SD/SDIO Power Switching Procedure of AM572x Sitara Processors Silicon Revision 2.0, 1.1 TRM (SPRUHZ6I - October 2014–Revised April 2017 [1]). In the voltage switching sequence, CLKEXTFREE bit in MMCHS_CON should also be set after switching to 1.8v which is also taken care in the card_busy ops. [1] -> http://www.ti.com/lit/ug/spruhz6i/spruhz6i.pdf Signed-off-by: Kishon Vijay Abraham I Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci-omap.c | 52 +++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/drivers/mmc/host/sdhci-omap.c b/drivers/mmc/host/sdhci-omap.c index 96985786cadf..df927f3faaf6 100644 --- a/drivers/mmc/host/sdhci-omap.c +++ b/drivers/mmc/host/sdhci-omap.c @@ -31,11 +31,17 @@ #define SDHCI_OMAP_CON 0x12c #define CON_DW8 BIT(5) #define CON_DMA_MASTER BIT(20) +#define CON_CLKEXTFREE BIT(16) +#define CON_PADEN BIT(15) #define CON_INIT BIT(1) #define CON_OD BIT(0) #define SDHCI_OMAP_CMD 0x20c +#define SDHCI_OMAP_PSTATE 0x0224 +#define PSTATE_DLEV_DAT0 BIT(20) +#define PSTATE_DATI BIT(1) + #define SDHCI_OMAP_HCTL 0x228 #define HCTL_SDBP BIT(8) #define HCTL_SDVS_SHIFT 9 @@ -191,6 +197,51 @@ static void sdhci_omap_conf_bus_power(struct sdhci_omap_host *omap_host, } } +static int sdhci_omap_card_busy(struct mmc_host *mmc) +{ + u32 reg, ac12; + int ret = false; + struct sdhci_host *host = mmc_priv(mmc); + struct sdhci_pltfm_host *pltfm_host; + struct sdhci_omap_host *omap_host; + u32 ier = host->ier; + + pltfm_host = sdhci_priv(host); + omap_host = sdhci_pltfm_priv(pltfm_host); + + reg = sdhci_omap_readl(omap_host, SDHCI_OMAP_CON); + ac12 = sdhci_omap_readl(omap_host, SDHCI_OMAP_AC12); + reg &= ~CON_CLKEXTFREE; + if (ac12 & AC12_V1V8_SIGEN) + reg |= CON_CLKEXTFREE; + reg |= CON_PADEN; + sdhci_omap_writel(omap_host, SDHCI_OMAP_CON, reg); + + disable_irq(host->irq); + ier |= SDHCI_INT_CARD_INT; + sdhci_writel(host, ier, SDHCI_INT_ENABLE); + sdhci_writel(host, ier, SDHCI_SIGNAL_ENABLE); + + /* + * Delay is required for PSTATE to correctly reflect + * DLEV/CLEV values after PADEN is set. + */ + usleep_range(50, 100); + reg = sdhci_omap_readl(omap_host, SDHCI_OMAP_PSTATE); + if ((reg & PSTATE_DATI) || !(reg & PSTATE_DLEV_DAT0)) + ret = true; + + reg = sdhci_omap_readl(omap_host, SDHCI_OMAP_CON); + reg &= ~(CON_CLKEXTFREE | CON_PADEN); + sdhci_omap_writel(omap_host, SDHCI_OMAP_CON, reg); + + sdhci_writel(host, host->ier, SDHCI_INT_ENABLE); + sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE); + enable_irq(host->irq); + + return ret; +} + static int sdhci_omap_start_signal_voltage_switch(struct mmc_host *mmc, struct mmc_ios *ios) { @@ -562,6 +613,7 @@ static int sdhci_omap_probe(struct platform_device *pdev) host->mmc_host_ops.start_signal_voltage_switch = sdhci_omap_start_signal_voltage_switch; host->mmc_host_ops.set_ios = sdhci_omap_set_ios; + host->mmc_host_ops.card_busy = sdhci_omap_card_busy; sdhci_read_caps(host); host->caps |= SDHCI_CAN_DO_ADMA2; From 27ceb7e0b0ae08cada8e790a84cfd912c1002783 Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Mon, 5 Feb 2018 18:20:16 +0530 Subject: [PATCH 03/55] mmc: sdhci-omap: Add custom set_uhs_signaling sdhci_host ops UHS-1 DDR50 and MMC DDR52 mode require DDR bit to be set in the configuration register (MMCHS_CON). Add sdhci-omap specific set_uhs_signaling ops to set this bit. Also while setting the UHSMS bit, clock should be disabled. Signed-off-by: Kishon Vijay Abraham I Acked-by: Adrian Hunter Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci-omap.c | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/drivers/mmc/host/sdhci-omap.c b/drivers/mmc/host/sdhci-omap.c index df927f3faaf6..86b6cc0a5380 100644 --- a/drivers/mmc/host/sdhci-omap.c +++ b/drivers/mmc/host/sdhci-omap.c @@ -31,6 +31,7 @@ #define SDHCI_OMAP_CON 0x12c #define CON_DW8 BIT(5) #define CON_DMA_MASTER BIT(20) +#define CON_DDR BIT(19) #define CON_CLKEXTFREE BIT(16) #define CON_PADEN BIT(15) #define CON_INIT BIT(1) @@ -461,6 +462,26 @@ static void sdhci_omap_init_74_clocks(struct sdhci_host *host, u8 power_mode) enable_irq(host->irq); } +static void sdhci_omap_set_uhs_signaling(struct sdhci_host *host, + unsigned int timing) +{ + u32 reg; + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct sdhci_omap_host *omap_host = sdhci_pltfm_priv(pltfm_host); + + sdhci_omap_stop_clock(omap_host); + + reg = sdhci_omap_readl(omap_host, SDHCI_OMAP_CON); + if (timing == MMC_TIMING_UHS_DDR50 || timing == MMC_TIMING_MMC_DDR52) + reg |= CON_DDR; + else + reg &= ~CON_DDR; + sdhci_omap_writel(omap_host, SDHCI_OMAP_CON, reg); + + sdhci_set_uhs_signaling(host, timing); + sdhci_omap_start_clock(omap_host); +} + static struct sdhci_ops sdhci_omap_ops = { .set_clock = sdhci_omap_set_clock, .set_power = sdhci_omap_set_power, @@ -470,7 +491,7 @@ static struct sdhci_ops sdhci_omap_ops = { .set_bus_width = sdhci_omap_set_bus_width, .platform_send_init_74_clocks = sdhci_omap_init_74_clocks, .reset = sdhci_reset, - .set_uhs_signaling = sdhci_set_uhs_signaling, + .set_uhs_signaling = sdhci_omap_set_uhs_signaling, }; static int sdhci_omap_set_capabilities(struct sdhci_omap_host *omap_host) From 9fc2cd76125cab476ec6fd86fac7f9a780e34dcf Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Mon, 5 Feb 2018 18:20:17 +0530 Subject: [PATCH 04/55] mmc: sdhci-omap: Add tuning support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit MMC tuning procedure is required to support SD card UHS1-SDR104 mode and EMMC HS200 mode. SDR104/HS200 DLL Tuning Procedure for AM572x platform is mentioned in Figure 25-51. SDR104/HS200 DLL Tuning Procedure of AM572x Sitara Processors Silicon Revision 2.0, 1.1 TRM (SPRUHZ6I - October 2014–Revised April 2017 [1]). The tuning function sdhci_omap_execute_tuning() will only be called by the MMC/SD core if the corresponding speed modes are supported by the OMAP silicon which is set in the mmc host "caps" field. [1] -> http://www.ti.com/lit/ug/spruhz6i/spruhz6i.pdf Signed-off-by: Kishon Vijay Abraham I Acked-by: Adrian Hunter Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci-omap.c | 130 ++++++++++++++++++++++++++++++++++ 1 file changed, 130 insertions(+) diff --git a/drivers/mmc/host/sdhci-omap.c b/drivers/mmc/host/sdhci-omap.c index 86b6cc0a5380..36e0626d3de2 100644 --- a/drivers/mmc/host/sdhci-omap.c +++ b/drivers/mmc/host/sdhci-omap.c @@ -37,6 +37,13 @@ #define CON_INIT BIT(1) #define CON_OD BIT(0) +#define SDHCI_OMAP_DLL 0x0134 +#define DLL_SWT BIT(20) +#define DLL_FORCE_SR_C_SHIFT 13 +#define DLL_FORCE_SR_C_MASK (0x7f << DLL_FORCE_SR_C_SHIFT) +#define DLL_FORCE_VALUE BIT(12) +#define DLL_CALIB BIT(1) + #define SDHCI_OMAP_CMD 0x20c #define SDHCI_OMAP_PSTATE 0x0224 @@ -63,12 +70,16 @@ #define SDHCI_OMAP_AC12 0x23c #define AC12_V1V8_SIGEN BIT(19) +#define AC12_SCLK_SEL BIT(23) #define SDHCI_OMAP_CAPA 0x240 #define CAPA_VS33 BIT(24) #define CAPA_VS30 BIT(25) #define CAPA_VS18 BIT(26) +#define SDHCI_OMAP_CAPA2 0x0244 +#define CAPA2_TSDR50 BIT(13) + #define SDHCI_OMAP_TIMEOUT 1 /* 1 msec */ #define SYSCTL_CLKD_MAX 0x3FF @@ -77,6 +88,8 @@ #define IOV_3V0 3000000 /* 300000 uV */ #define IOV_3V3 3300000 /* 330000 uV */ +#define MAX_PHASE_DELAY 0x7C + struct sdhci_omap_data { u32 offset; }; @@ -198,6 +211,120 @@ static void sdhci_omap_conf_bus_power(struct sdhci_omap_host *omap_host, } } +static inline void sdhci_omap_set_dll(struct sdhci_omap_host *omap_host, + int count) +{ + int i; + u32 reg; + + reg = sdhci_omap_readl(omap_host, SDHCI_OMAP_DLL); + reg |= DLL_FORCE_VALUE; + reg &= ~DLL_FORCE_SR_C_MASK; + reg |= (count << DLL_FORCE_SR_C_SHIFT); + sdhci_omap_writel(omap_host, SDHCI_OMAP_DLL, reg); + + reg |= DLL_CALIB; + sdhci_omap_writel(omap_host, SDHCI_OMAP_DLL, reg); + for (i = 0; i < 1000; i++) { + reg = sdhci_omap_readl(omap_host, SDHCI_OMAP_DLL); + if (reg & DLL_CALIB) + break; + } + reg &= ~DLL_CALIB; + sdhci_omap_writel(omap_host, SDHCI_OMAP_DLL, reg); +} + +static void sdhci_omap_disable_tuning(struct sdhci_omap_host *omap_host) +{ + u32 reg; + + reg = sdhci_omap_readl(omap_host, SDHCI_OMAP_AC12); + reg &= ~AC12_SCLK_SEL; + sdhci_omap_writel(omap_host, SDHCI_OMAP_AC12, reg); + + reg = sdhci_omap_readl(omap_host, SDHCI_OMAP_DLL); + reg &= ~(DLL_FORCE_VALUE | DLL_SWT); + sdhci_omap_writel(omap_host, SDHCI_OMAP_DLL, reg); +} + +static int sdhci_omap_execute_tuning(struct mmc_host *mmc, u32 opcode) +{ + struct sdhci_host *host = mmc_priv(mmc); + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct sdhci_omap_host *omap_host = sdhci_pltfm_priv(pltfm_host); + struct device *dev = omap_host->dev; + struct mmc_ios *ios = &mmc->ios; + u32 start_window = 0, max_window = 0; + u8 cur_match, prev_match = 0; + u32 length = 0, max_len = 0; + u32 phase_delay = 0; + int ret = 0; + u32 reg; + + pltfm_host = sdhci_priv(host); + omap_host = sdhci_pltfm_priv(pltfm_host); + dev = omap_host->dev; + + /* clock tuning is not needed for upto 52MHz */ + if (ios->clock <= 52000000) + return 0; + + reg = sdhci_omap_readl(omap_host, SDHCI_OMAP_CAPA2); + if (ios->timing == MMC_TIMING_UHS_SDR50 && !(reg & CAPA2_TSDR50)) + return 0; + + reg = sdhci_omap_readl(omap_host, SDHCI_OMAP_DLL); + reg |= DLL_SWT; + sdhci_omap_writel(omap_host, SDHCI_OMAP_DLL, reg); + + while (phase_delay <= MAX_PHASE_DELAY) { + sdhci_omap_set_dll(omap_host, phase_delay); + + cur_match = !mmc_send_tuning(mmc, opcode, NULL); + if (cur_match) { + if (prev_match) { + length++; + } else { + start_window = phase_delay; + length = 1; + } + } + + if (length > max_len) { + max_window = start_window; + max_len = length; + } + + prev_match = cur_match; + phase_delay += 4; + } + + if (!max_len) { + dev_err(dev, "Unable to find match\n"); + ret = -EIO; + goto tuning_error; + } + + reg = sdhci_omap_readl(omap_host, SDHCI_OMAP_AC12); + if (!(reg & AC12_SCLK_SEL)) { + ret = -EIO; + goto tuning_error; + } + + phase_delay = max_window + 4 * (max_len >> 1); + sdhci_omap_set_dll(omap_host, phase_delay); + + goto ret; + +tuning_error: + dev_err(dev, "Tuning failed\n"); + sdhci_omap_disable_tuning(omap_host); + +ret: + sdhci_reset(host, SDHCI_RESET_CMD | SDHCI_RESET_DATA); + return ret; +} + static int sdhci_omap_card_busy(struct mmc_host *mmc) { u32 reg, ac12; @@ -299,6 +426,8 @@ static int sdhci_omap_start_signal_voltage_switch(struct mmc_host *mmc, static void sdhci_omap_set_power_mode(struct sdhci_omap_host *omap_host, u8 power_mode) { + if (omap_host->bus_mode == MMC_POWER_OFF) + sdhci_omap_disable_tuning(omap_host); omap_host->power_mode = power_mode; } @@ -635,6 +764,7 @@ static int sdhci_omap_probe(struct platform_device *pdev) sdhci_omap_start_signal_voltage_switch; host->mmc_host_ops.set_ios = sdhci_omap_set_ios; host->mmc_host_ops.card_busy = sdhci_omap_card_busy; + host->mmc_host_ops.execute_tuning = sdhci_omap_execute_tuning; sdhci_read_caps(host); host->caps |= SDHCI_CAN_DO_ADMA2; From 7d33c3581536b8193b9788a63a68e7bfc22cdc31 Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Mon, 5 Feb 2018 18:20:18 +0530 Subject: [PATCH 05/55] mmc: sdhci-omap: Workaround for Errata i802 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Errata i802 in AM572x Sitara Processors Silicon Revision 2.0, 1.1 (SPRZ429K July 2014–Revised March 2017 [1]) mentions DCRC error interrupts (MMCHS_STAT[21] DCRC=0x1) can occur during the tuning procedure and it has to be disabled during the tuning procedure Implement workaround for Errata i802 here.. [1] -> http://www.ti.com/lit/er/sprz429k/sprz429k.pdf Signed-off-by: Kishon Vijay Abraham I Acked-by: Adrian Hunter Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci-omap.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/drivers/mmc/host/sdhci-omap.c b/drivers/mmc/host/sdhci-omap.c index 36e0626d3de2..e24ae903f7ba 100644 --- a/drivers/mmc/host/sdhci-omap.c +++ b/drivers/mmc/host/sdhci-omap.c @@ -257,6 +257,7 @@ static int sdhci_omap_execute_tuning(struct mmc_host *mmc, u32 opcode) u32 start_window = 0, max_window = 0; u8 cur_match, prev_match = 0; u32 length = 0, max_len = 0; + u32 ier = host->ier; u32 phase_delay = 0; int ret = 0; u32 reg; @@ -277,6 +278,16 @@ static int sdhci_omap_execute_tuning(struct mmc_host *mmc, u32 opcode) reg |= DLL_SWT; sdhci_omap_writel(omap_host, SDHCI_OMAP_DLL, reg); + /* + * OMAP5/DRA74X/DRA72x Errata i802: + * DCRC error interrupts (MMCHS_STAT[21] DCRC=0x1) can occur + * during the tuning procedure. So disable it during the + * tuning procedure. + */ + ier &= ~SDHCI_INT_DATA_CRC; + sdhci_writel(host, ier, SDHCI_INT_ENABLE); + sdhci_writel(host, ier, SDHCI_SIGNAL_ENABLE); + while (phase_delay <= MAX_PHASE_DELAY) { sdhci_omap_set_dll(omap_host, phase_delay); @@ -322,6 +333,8 @@ tuning_error: ret: sdhci_reset(host, SDHCI_RESET_CMD | SDHCI_RESET_DATA); + sdhci_writel(host, host->ier, SDHCI_INT_ENABLE); + sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE); return ret; } From 8d20b2eae6c47b09552364afa20511aa43f2367c Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Mon, 5 Feb 2018 18:20:19 +0530 Subject: [PATCH 06/55] mmc: sdhci_omap: Add support to set IODELAY values The data manual of J6/J6 Eco recommends to set different IODELAY values depending on the mode in which the MMC/SD is enumerated in order to ensure IO timings are met. Add support to set the IODELAY values depending on the various MMC modes using the pinctrl APIs. Signed-off-by: Kishon Vijay Abraham I Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci-omap.c | 148 ++++++++++++++++++++++++++++++++++ 1 file changed, 148 insertions(+) diff --git a/drivers/mmc/host/sdhci-omap.c b/drivers/mmc/host/sdhci-omap.c index e24ae903f7ba..428849387992 100644 --- a/drivers/mmc/host/sdhci-omap.c +++ b/drivers/mmc/host/sdhci-omap.c @@ -25,6 +25,7 @@ #include #include #include +#include #include "sdhci-pltfm.h" @@ -90,8 +91,12 @@ #define MAX_PHASE_DELAY 0x7C +/* sdhci-omap controller flags */ +#define SDHCI_OMAP_REQUIRE_IODELAY BIT(0) + struct sdhci_omap_data { u32 offset; + u8 flags; }; struct sdhci_omap_host { @@ -102,8 +107,16 @@ struct sdhci_omap_host { struct sdhci_host *host; u8 bus_mode; u8 power_mode; + u8 timing; + u8 flags; + + struct pinctrl *pinctrl; + struct pinctrl_state **pinctrl_state; }; +static void sdhci_omap_start_clock(struct sdhci_omap_host *omap_host); +static void sdhci_omap_stop_clock(struct sdhci_omap_host *omap_host); + static inline u32 sdhci_omap_readl(struct sdhci_omap_host *host, unsigned int offset) { @@ -436,6 +449,31 @@ static int sdhci_omap_start_signal_voltage_switch(struct mmc_host *mmc, return 0; } +static void sdhci_omap_set_timing(struct sdhci_omap_host *omap_host, u8 timing) +{ + int ret; + struct pinctrl_state *pinctrl_state; + struct device *dev = omap_host->dev; + + if (!(omap_host->flags & SDHCI_OMAP_REQUIRE_IODELAY)) + return; + + if (omap_host->timing == timing) + return; + + sdhci_omap_stop_clock(omap_host); + + pinctrl_state = omap_host->pinctrl_state[timing]; + ret = pinctrl_select_state(omap_host->pinctrl, pinctrl_state); + if (ret) { + dev_err(dev, "failed to select pinctrl state\n"); + return; + } + + sdhci_omap_start_clock(omap_host); + omap_host->timing = timing; +} + static void sdhci_omap_set_power_mode(struct sdhci_omap_host *omap_host, u8 power_mode) { @@ -472,6 +510,7 @@ static void sdhci_omap_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) omap_host = sdhci_pltfm_priv(pltfm_host); sdhci_omap_set_bus_mode(omap_host, ios->bus_mode); + sdhci_omap_set_timing(omap_host, ios->timing); sdhci_set_ios(mmc, ios); sdhci_omap_set_power_mode(omap_host, ios->power_mode); } @@ -680,6 +719,7 @@ static const struct sdhci_pltfm_data sdhci_omap_pdata = { static const struct sdhci_omap_data dra7_data = { .offset = 0x200, + .flags = SDHCI_OMAP_REQUIRE_IODELAY, }; static const struct of_device_id omap_sdhci_match[] = { @@ -688,6 +728,108 @@ static const struct of_device_id omap_sdhci_match[] = { }; MODULE_DEVICE_TABLE(of, omap_sdhci_match); +static struct pinctrl_state +*sdhci_omap_iodelay_pinctrl_state(struct sdhci_omap_host *omap_host, char *mode, + u32 *caps, u32 capmask) +{ + struct device *dev = omap_host->dev; + struct pinctrl_state *pinctrl_state = ERR_PTR(-ENODEV); + + if (!(*caps & capmask)) + goto ret; + + pinctrl_state = pinctrl_lookup_state(omap_host->pinctrl, mode); + if (IS_ERR(pinctrl_state)) { + dev_err(dev, "no pinctrl state for %s mode", mode); + *caps &= ~capmask; + } + +ret: + return pinctrl_state; +} + +static int sdhci_omap_config_iodelay_pinctrl_state(struct sdhci_omap_host + *omap_host) +{ + struct device *dev = omap_host->dev; + struct sdhci_host *host = omap_host->host; + struct mmc_host *mmc = host->mmc; + u32 *caps = &mmc->caps; + u32 *caps2 = &mmc->caps2; + struct pinctrl_state *state; + struct pinctrl_state **pinctrl_state; + + if (!(omap_host->flags & SDHCI_OMAP_REQUIRE_IODELAY)) + return 0; + + pinctrl_state = devm_kzalloc(dev, sizeof(*pinctrl_state) * + (MMC_TIMING_MMC_HS200 + 1), GFP_KERNEL); + if (!pinctrl_state) + return -ENOMEM; + + omap_host->pinctrl = devm_pinctrl_get(omap_host->dev); + if (IS_ERR(omap_host->pinctrl)) { + dev_err(dev, "Cannot get pinctrl\n"); + return PTR_ERR(omap_host->pinctrl); + } + + state = pinctrl_lookup_state(omap_host->pinctrl, "default"); + if (IS_ERR(state)) { + dev_err(dev, "no pinctrl state for default mode\n"); + return PTR_ERR(state); + } + pinctrl_state[MMC_TIMING_LEGACY] = state; + + state = sdhci_omap_iodelay_pinctrl_state(omap_host, "sdr104", caps, + MMC_CAP_UHS_SDR104); + if (!IS_ERR(state)) + pinctrl_state[MMC_TIMING_UHS_SDR104] = state; + + state = sdhci_omap_iodelay_pinctrl_state(omap_host, "ddr50", caps, + MMC_CAP_UHS_DDR50); + if (!IS_ERR(state)) + pinctrl_state[MMC_TIMING_UHS_DDR50] = state; + + state = sdhci_omap_iodelay_pinctrl_state(omap_host, "sdr50", caps, + MMC_CAP_UHS_SDR50); + if (!IS_ERR(state)) + pinctrl_state[MMC_TIMING_UHS_SDR50] = state; + + state = sdhci_omap_iodelay_pinctrl_state(omap_host, "sdr25", caps, + MMC_CAP_UHS_SDR25); + if (!IS_ERR(state)) + pinctrl_state[MMC_TIMING_UHS_SDR25] = state; + + state = sdhci_omap_iodelay_pinctrl_state(omap_host, "sdr12", caps, + MMC_CAP_UHS_SDR12); + if (!IS_ERR(state)) + pinctrl_state[MMC_TIMING_UHS_SDR12] = state; + + state = sdhci_omap_iodelay_pinctrl_state(omap_host, "ddr_1_8v", caps, + MMC_CAP_1_8V_DDR); + if (!IS_ERR(state)) + pinctrl_state[MMC_TIMING_MMC_DDR52] = state; + + state = sdhci_omap_iodelay_pinctrl_state(omap_host, "hs", caps, + MMC_CAP_SD_HIGHSPEED); + if (!IS_ERR(state)) + pinctrl_state[MMC_TIMING_SD_HS] = state; + + state = sdhci_omap_iodelay_pinctrl_state(omap_host, "hs", caps, + MMC_CAP_MMC_HIGHSPEED); + if (!IS_ERR(state)) + pinctrl_state[MMC_TIMING_MMC_HS] = state; + + state = sdhci_omap_iodelay_pinctrl_state(omap_host, "hs200_1_8v", caps2, + MMC_CAP2_HS200_1_8V_SDR); + if (!IS_ERR(state)) + pinctrl_state[MMC_TIMING_MMC_HS200] = state; + + omap_host->pinctrl_state = pinctrl_state; + + return 0; +} + static int sdhci_omap_probe(struct platform_device *pdev) { int ret; @@ -724,6 +866,8 @@ static int sdhci_omap_probe(struct platform_device *pdev) omap_host->base = host->ioaddr; omap_host->dev = dev; omap_host->power_mode = MMC_POWER_UNDEFINED; + omap_host->timing = MMC_TIMING_LEGACY; + omap_host->flags = data->flags; host->ioaddr += offset; mmc = host->mmc; @@ -772,6 +916,10 @@ static int sdhci_omap_probe(struct platform_device *pdev) goto err_put_sync; } + ret = sdhci_omap_config_iodelay_pinctrl_state(omap_host); + if (ret) + goto err_put_sync; + host->mmc_host_ops.get_ro = mmc_gpio_get_ro; host->mmc_host_ops.start_signal_voltage_switch = sdhci_omap_start_signal_voltage_switch; From e0b2dbcfaacd1c1662fd3facdd75805a95505054 Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Mon, 5 Feb 2018 18:20:20 +0530 Subject: [PATCH 07/55] mmc: sdhci_omap: Fix sdhci-omap quirks Add SDHCI_QUIRK2_PRESET_VALUE_BROKEN quirk as setting preset values loads incorrect CLKD values (for UHS modes). Remove SDHCI_QUIRK2_NO_1_8_V quirk as sdhci-omap now supports UHS modes. Signed-off-by: Kishon Vijay Abraham I Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci-omap.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/mmc/host/sdhci-omap.c b/drivers/mmc/host/sdhci-omap.c index 428849387992..1456abd5eeb9 100644 --- a/drivers/mmc/host/sdhci-omap.c +++ b/drivers/mmc/host/sdhci-omap.c @@ -711,8 +711,8 @@ static const struct sdhci_pltfm_data sdhci_omap_pdata = { SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN | SDHCI_QUIRK_NO_HISPD_BIT | SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC, - .quirks2 = SDHCI_QUIRK2_NO_1_8_V | - SDHCI_QUIRK2_ACMD23_BROKEN | + .quirks2 = SDHCI_QUIRK2_ACMD23_BROKEN | + SDHCI_QUIRK2_PRESET_VALUE_BROKEN | SDHCI_QUIRK2_RSP_136_HAS_CRC, .ops = &sdhci_omap_ops, }; From 5a871bf081dd7915ed7b9942a5484ff0c742e2cc Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Mon, 5 Feb 2018 14:28:22 +0100 Subject: [PATCH 08/55] mmc: sh_mmcif: remove some cruft The TODO section from 2010 is obsolete. We have DMA and PM meanwhile and we always want to handle errors better, if possible. Also DRIVER_VERSION is not used anymore these days. Signed-off-by: Wolfram Sang Reviewed-by: Simon Horman Signed-off-by: Ulf Hansson --- drivers/mmc/host/sh_mmcif.c | 8 -------- 1 file changed, 8 deletions(-) diff --git a/drivers/mmc/host/sh_mmcif.c b/drivers/mmc/host/sh_mmcif.c index 7bb00c68a756..4c2a1f8ddbf3 100644 --- a/drivers/mmc/host/sh_mmcif.c +++ b/drivers/mmc/host/sh_mmcif.c @@ -7,13 +7,6 @@ * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License. - * - * - * TODO - * 1. DMA - * 2. Power management - * 3. Handle MMC errors better - * */ /* @@ -67,7 +60,6 @@ #include #define DRIVER_NAME "sh_mmcif" -#define DRIVER_VERSION "2010-04-28" /* CE_CMD_SET */ #define CMD_MASK 0x3f000000 From b305882fbc878f10ad089348da147987c330a2ee Mon Sep 17 00:00:00 2001 From: Sergio Valverde Date: Thu, 8 Feb 2018 11:41:43 -0600 Subject: [PATCH 09/55] mmc: core: optimize mmc_calc_max_discard If the max_discard value is zero, the conditional branch that checks the trim capabilities will never update this value with max_trim. Change the condition statement to also check the max_discard value in order to avoid an unnecessary call to mmc_do_calc_max_discard. Signed-off-by: Sergio Valverde Reviewed-by: Shawn Lin Signed-off-by: Ulf Hansson --- drivers/mmc/core/core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index c0ba6d8823b7..e01910dd964b 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -2369,7 +2369,7 @@ unsigned int mmc_calc_max_discard(struct mmc_card *card) return card->pref_erase; max_discard = mmc_do_calc_max_discard(card, MMC_ERASE_ARG); - if (mmc_can_trim(card)) { + if (max_discard && mmc_can_trim(card)) { max_trim = mmc_do_calc_max_discard(card, MMC_TRIM_ARG); if (max_trim < max_discard) max_discard = max_trim; From 7f7a385d0a7c5091a85de5b78d550f27b81dfc37 Mon Sep 17 00:00:00 2001 From: Stefan Wahren Date: Mon, 12 Feb 2018 21:02:44 +0100 Subject: [PATCH 10/55] mmc: sdhci-iproc: Disable preset values for BCM2835 According to the BCM2835 datasheet there are no preset value registers. This wasn't an issue before, because we didn't propagate 1.8V support. Signed-off-by: Stefan Wahren Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci-iproc.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/mmc/host/sdhci-iproc.c b/drivers/mmc/host/sdhci-iproc.c index 61666d269771..0ef741bc515d 100644 --- a/drivers/mmc/host/sdhci-iproc.c +++ b/drivers/mmc/host/sdhci-iproc.c @@ -214,6 +214,7 @@ static const struct sdhci_pltfm_data sdhci_bcm2835_pltfm_data = { SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK | SDHCI_QUIRK_MISSING_CAPS | SDHCI_QUIRK_NO_HISPD_BIT, + .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN, .ops = &sdhci_iproc_32only_ops, }; From 2ad1db059b9a4874b05bac49dba22c8b8e68afd4 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Thu, 18 Jan 2018 01:28:07 +0900 Subject: [PATCH 11/55] mmc: renesas_sdhi: use MMC_CAP2_NO_WRITE_PROTECT instead of TMIO own flag TMIO_MMC_WRPROTECT_DISABLE is equivalent to MMC_CAP2_NO_WRITE_PROTECT. The flag is propagated as follows: renesas_sdhi_of_data::capabilities2 -> tmio_mmc_data::capabilities2 -> mmc_host::caps2 Only the difference is the TMIO_... makes tmio_mmc_get_ro() return 0 (i.e. it does not affect mmc_gpio_get_ro() at all), while MMC_CAP2_... returns 0 before calling ->get_ro() hook (i.e. it affects both IP own logic and GPIO detection). The TMIO MMC drivers do not set-up gpio_ro by themselves. Only the possibility, if any, would be DT specifies "wp-gpios" property, and gpio_ro is set by mmc_gpiod_request_ro() called from mmc_of_parse(). However, it does not make sense to specify "wp-gpios" property and TMIO_MMC_WRPROTECT_DISABLE at the same time. I checked under arch/arm/boot/dts/ and arch/arm64/boot/dts/renesas/, and I did not see any Renesas boards with "wp-gpios". So, this conversion should be safe. Signed-off-by: Masahiro Yamada Reviewed-by: Wolfram Sang Signed-off-by: Ulf Hansson Tested-by: Wolfram Sang --- drivers/mmc/host/renesas_sdhi_internal_dmac.c | 6 +++--- drivers/mmc/host/renesas_sdhi_sys_dmac.c | 16 ++++++++-------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/drivers/mmc/host/renesas_sdhi_internal_dmac.c b/drivers/mmc/host/renesas_sdhi_internal_dmac.c index 7c03cfead6f9..c063b2d0364d 100644 --- a/drivers/mmc/host/renesas_sdhi_internal_dmac.c +++ b/drivers/mmc/host/renesas_sdhi_internal_dmac.c @@ -71,11 +71,11 @@ static struct renesas_sdhi_scc rcar_gen3_scc_taps[] = { }; static const struct renesas_sdhi_of_data of_rcar_gen3_compatible = { - .tmio_flags = TMIO_MMC_HAS_IDLE_WAIT | TMIO_MMC_WRPROTECT_DISABLE | - TMIO_MMC_CLK_ACTUAL | TMIO_MMC_HAVE_CBSY | - TMIO_MMC_MIN_RCAR2, + .tmio_flags = TMIO_MMC_HAS_IDLE_WAIT | TMIO_MMC_CLK_ACTUAL | + TMIO_MMC_HAVE_CBSY | TMIO_MMC_MIN_RCAR2, .capabilities = MMC_CAP_SD_HIGHSPEED | MMC_CAP_SDIO_IRQ | MMC_CAP_CMD23, + .capabilities2 = MMC_CAP2_NO_WRITE_PROTECT, .bus_shift = 2, .scc_offset = 0x1000, .taps = rcar_gen3_scc_taps, diff --git a/drivers/mmc/host/renesas_sdhi_sys_dmac.c b/drivers/mmc/host/renesas_sdhi_sys_dmac.c index 82d757c480b2..434afa9dd9a1 100644 --- a/drivers/mmc/host/renesas_sdhi_sys_dmac.c +++ b/drivers/mmc/host/renesas_sdhi_sys_dmac.c @@ -40,9 +40,9 @@ static const struct renesas_sdhi_of_data of_rz_compatible = { }; static const struct renesas_sdhi_of_data of_rcar_gen1_compatible = { - .tmio_flags = TMIO_MMC_HAS_IDLE_WAIT | TMIO_MMC_WRPROTECT_DISABLE | - TMIO_MMC_CLK_ACTUAL, + .tmio_flags = TMIO_MMC_HAS_IDLE_WAIT | TMIO_MMC_CLK_ACTUAL, .capabilities = MMC_CAP_SD_HIGHSPEED | MMC_CAP_SDIO_IRQ, + .capabilities2 = MMC_CAP2_NO_WRITE_PROTECT, }; /* Definitions for sampling clocks */ @@ -58,11 +58,11 @@ static struct renesas_sdhi_scc rcar_gen2_scc_taps[] = { }; static const struct renesas_sdhi_of_data of_rcar_gen2_compatible = { - .tmio_flags = TMIO_MMC_HAS_IDLE_WAIT | TMIO_MMC_WRPROTECT_DISABLE | - TMIO_MMC_CLK_ACTUAL | TMIO_MMC_HAVE_CBSY | - TMIO_MMC_MIN_RCAR2, + .tmio_flags = TMIO_MMC_HAS_IDLE_WAIT | TMIO_MMC_CLK_ACTUAL | + TMIO_MMC_HAVE_CBSY | TMIO_MMC_MIN_RCAR2, .capabilities = MMC_CAP_SD_HIGHSPEED | MMC_CAP_SDIO_IRQ | MMC_CAP_CMD23, + .capabilities2 = MMC_CAP2_NO_WRITE_PROTECT, .dma_buswidth = DMA_SLAVE_BUSWIDTH_4_BYTES, .dma_rx_offset = 0x2000, .scc_offset = 0x0300, @@ -79,11 +79,11 @@ static struct renesas_sdhi_scc rcar_gen3_scc_taps[] = { }; static const struct renesas_sdhi_of_data of_rcar_gen3_compatible = { - .tmio_flags = TMIO_MMC_HAS_IDLE_WAIT | TMIO_MMC_WRPROTECT_DISABLE | - TMIO_MMC_CLK_ACTUAL | TMIO_MMC_HAVE_CBSY | - TMIO_MMC_MIN_RCAR2, + .tmio_flags = TMIO_MMC_HAS_IDLE_WAIT | TMIO_MMC_CLK_ACTUAL | + TMIO_MMC_HAVE_CBSY | TMIO_MMC_MIN_RCAR2, .capabilities = MMC_CAP_SD_HIGHSPEED | MMC_CAP_SDIO_IRQ | MMC_CAP_CMD23, + .capabilities2 = MMC_CAP2_NO_WRITE_PROTECT, .bus_shift = 2, .scc_offset = 0x1000, .taps = rcar_gen3_scc_taps, From 3ca1507b5b3bba2a7d610659fb93c666282f83e5 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Thu, 18 Jan 2018 01:28:08 +0900 Subject: [PATCH 12/55] sh: kfr2r09: use MMC_CAP2_NO_WRITE_PROTECT instead of TMIO own flag TMIO_MMC_WRPROTECT_DISABLE is equivalent to MMC_CAP2_NO_WRITE_PROTECT. The flag is propagated as follows: tmio_mmc_data::capabilities2 -> mmc_host::caps2 Only the difference is the TMIO_... makes tmio_mmc_get_ro() return 0 (i.e. it does not affect mmc_gpio_get_ro() at all), while MMC_CAP2_... returns 0 before calling ->get_ro() hook (i.e. it affects both IP own logic and GPIO detection). The TMIO MMC drivers do not set-up gpio_ro by themselves, so gpio_ro is obviously unused by legacy boards like this. So, this conversion should be safe. Signed-off-by: Masahiro Yamada Reviewed-by: Wolfram Sang Signed-off-by: Ulf Hansson Tested-by: Wolfram Sang --- arch/sh/boards/mach-kfr2r09/setup.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/sh/boards/mach-kfr2r09/setup.c b/arch/sh/boards/mach-kfr2r09/setup.c index 5deb2d82f19f..6af7777332fc 100644 --- a/arch/sh/boards/mach-kfr2r09/setup.c +++ b/arch/sh/boards/mach-kfr2r09/setup.c @@ -375,8 +375,8 @@ static struct resource kfr2r09_sh_sdhi0_resources[] = { static struct tmio_mmc_data sh7724_sdhi0_data = { .chan_priv_tx = (void *)SHDMA_SLAVE_SDHI0_TX, .chan_priv_rx = (void *)SHDMA_SLAVE_SDHI0_RX, - .flags = TMIO_MMC_WRPROTECT_DISABLE, .capabilities = MMC_CAP_SDIO_IRQ, + .capabilities2 = MMC_CAP2_NO_WRITE_PROTECT, }; static struct platform_device kfr2r09_sh_sdhi0_device = { From 7c53b79766a463a97dd013715a1cc8a2802f6448 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Thu, 18 Jan 2018 01:28:09 +0900 Subject: [PATCH 13/55] mmc: tmio: use MMC_CAP2_NO_WRITE_PROTECT instead of TMIO own flag TMIO_MMC_WRPROTECT_DISABLE is equivalent to MMC_CAP2_NO_WRITE_PROTECT. Only the difference is the TMIO_... makes tmio_mmc_get_ro() return 0 (i.e. it does not affect mmc_gpio_get_ro() at all), while MMC_CAP2_... returns 0 before calling ->get_ro() hook (i.e. it affects both IP own logic and GPIO detection). The TMIO MMC drivers do not set-up gpio_ro by themselves. Only the possibility, if any, would be DT specifies "wp-gpios" property, and gpio_ro is set by mmc_gpiod_request_ro() called from mmc_of_parse(). However, it does not make sense to specify "wp-gpios" property and "toshiba,mmc-wrprotect-disable" at the same time. I checked under arch/arm/boot/dts/ and arch/arm64/boot/dts/renesas/, and I did not see any Renesas boards with "wp-gpios". So, this conversion should be safe. Signed-off-by: Masahiro Yamada Reviewed-by: Wolfram Sang Signed-off-by: Ulf Hansson Tested-by: Wolfram Sang --- drivers/mmc/host/tmio_mmc_core.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/mmc/host/tmio_mmc_core.c b/drivers/mmc/host/tmio_mmc_core.c index 33494241245a..1497da07e33c 100644 --- a/drivers/mmc/host/tmio_mmc_core.c +++ b/drivers/mmc/host/tmio_mmc_core.c @@ -1114,7 +1114,7 @@ static int tmio_mmc_init_ocr(struct tmio_mmc_host *host) } static void tmio_mmc_of_parse(struct platform_device *pdev, - struct tmio_mmc_data *pdata) + struct mmc_host *mmc) { const struct device_node *np = pdev->dev.of_node; @@ -1122,7 +1122,7 @@ static void tmio_mmc_of_parse(struct platform_device *pdev, return; if (of_get_property(np, "toshiba,mmc-wrprotect-disable", NULL)) - pdata->flags |= TMIO_MMC_WRPROTECT_DISABLE; + mmc->caps2 |= MMC_CAP2_NO_WRITE_PROTECT; } struct tmio_mmc_host *tmio_mmc_host_alloc(struct platform_device *pdev, @@ -1157,7 +1157,7 @@ struct tmio_mmc_host *tmio_mmc_host_alloc(struct platform_device *pdev, goto free; } - tmio_mmc_of_parse(pdev, pdata); + tmio_mmc_of_parse(pdev, mmc); platform_set_drvdata(pdev, host); From 218f6024abec04ec78e56b6761f70d404bab8637 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Thu, 18 Jan 2018 01:28:10 +0900 Subject: [PATCH 14/55] mmc: tmio: remove TMIO_MMC_WRPROTECT_DISABLE The use of this flag has been replaced with MMC_CAP2_NO_WRITE_PROTECT. No platform defines this flag any more. Remove. Signed-off-by: Masahiro Yamada Acked-by: Lee Jones Reviewed-by: Wolfram Sang Signed-off-by: Ulf Hansson Tested-by: Wolfram Sang --- drivers/mmc/host/tmio_mmc_core.c | 5 ++--- include/linux/mfd/tmio.h | 1 - 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/mmc/host/tmio_mmc_core.c b/drivers/mmc/host/tmio_mmc_core.c index 1497da07e33c..fb5a29c93ec5 100644 --- a/drivers/mmc/host/tmio_mmc_core.c +++ b/drivers/mmc/host/tmio_mmc_core.c @@ -1061,10 +1061,9 @@ static void tmio_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) static int tmio_mmc_get_ro(struct mmc_host *mmc) { struct tmio_mmc_host *host = mmc_priv(mmc); - struct tmio_mmc_data *pdata = host->pdata; - return !((pdata->flags & TMIO_MMC_WRPROTECT_DISABLE) || - (sd_ctrl_read16_and_16_as_32(host, CTL_STATUS) & TMIO_STAT_WRPROTECT)); + return !(sd_ctrl_read16_and_16_as_32(host, CTL_STATUS) & + TMIO_STAT_WRPROTECT); } static int tmio_multi_io_quirk(struct mmc_card *card, diff --git a/include/linux/mfd/tmio.h b/include/linux/mfd/tmio.h index 396a103c8bc6..91f92215ca74 100644 --- a/include/linux/mfd/tmio.h +++ b/include/linux/mfd/tmio.h @@ -36,7 +36,6 @@ } while (0) /* tmio MMC platform flags */ -#define TMIO_MMC_WRPROTECT_DISABLE BIT(0) /* * Some controllers can support a 2-byte block size when the bus width * is configured in 4-bit mode. From 788778b0d21a6d5cd5bc6c880591119e17932327 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Thu, 18 Jan 2018 01:28:11 +0900 Subject: [PATCH 15/55] mmc: tmio: deprecate "toshiba, mmc-wrprotect-disable" DT property This property is equivalent to "disable-wp" defined in Documentation/devicetree/bindings/mmc/mmc.txt The TMIO MMC core calls mmc_of_parse(), and it sets MMC_CAP2_NO_WRITE_PROTECT if "disable-wp" property is present. We do not need a vendor-specific property to do the same thing. Let's remove the description from the dt-binding to prevent new boards from using it. I am keeping the driver code for existing DT files, but added comments that this is deprecated. Signed-off-by: Masahiro Yamada Acked-by: Rob Herring Reviewed-by: Wolfram Sang Signed-off-by: Ulf Hansson Tested-by: Wolfram Sang --- Documentation/devicetree/bindings/mmc/tmio_mmc.txt | 1 - drivers/mmc/host/tmio_mmc_core.c | 5 +++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/mmc/tmio_mmc.txt b/Documentation/devicetree/bindings/mmc/tmio_mmc.txt index d8685cb83325..2d5287eeed95 100644 --- a/Documentation/devicetree/bindings/mmc/tmio_mmc.txt +++ b/Documentation/devicetree/bindings/mmc/tmio_mmc.txt @@ -50,7 +50,6 @@ Required properties: 2: R7S72100 Optional properties: -- toshiba,mmc-wrprotect-disable: write-protect detection is unavailable - pinctrl-names: should be "default", "state_uhs" - pinctrl-0: should contain default/high speed pin ctrl - pinctrl-1: should contain uhs mode pin ctrl diff --git a/drivers/mmc/host/tmio_mmc_core.c b/drivers/mmc/host/tmio_mmc_core.c index fb5a29c93ec5..f5da8bbf6dd3 100644 --- a/drivers/mmc/host/tmio_mmc_core.c +++ b/drivers/mmc/host/tmio_mmc_core.c @@ -1120,6 +1120,11 @@ static void tmio_mmc_of_parse(struct platform_device *pdev, if (!np) return; + /* + * DEPRECATED: + * For new platforms, please use "disable-wp" instead of + * "toshiba,mmc-wrprotect-disable" + */ if (of_get_property(np, "toshiba,mmc-wrprotect-disable", NULL)) mmc->caps2 |= MMC_CAP2_NO_WRITE_PROTECT; } From 497d1f965c207f1d670066e9c87a2ffad1ce4e5e Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Thu, 18 Jan 2018 01:28:12 +0900 Subject: [PATCH 16/55] mmc: tmio: support IP-builtin card detection logic A card detect GPIO is set up only for platforms with "cd-gpios" DT property or TMIO_MMC_USE_GPIO_CD flag. However, the driver core always uses mmc_gpio_get_cd, which just fails with -ENOSYS if ctx->cd_gpio is unset. The bit 5 of the status register provides the current signal level of the CD line. Allow to use it if the GPIO is unused. Signed-off-by: Masahiro Yamada Reviewed-by: Wolfram Sang Signed-off-by: Ulf Hansson Tested-by: Wolfram Sang --- drivers/mmc/host/tmio_mmc_core.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/drivers/mmc/host/tmio_mmc_core.c b/drivers/mmc/host/tmio_mmc_core.c index f5da8bbf6dd3..2abc425d45fd 100644 --- a/drivers/mmc/host/tmio_mmc_core.c +++ b/drivers/mmc/host/tmio_mmc_core.c @@ -1066,6 +1066,14 @@ static int tmio_mmc_get_ro(struct mmc_host *mmc) TMIO_STAT_WRPROTECT); } +static int tmio_mmc_get_cd(struct mmc_host *mmc) +{ + struct tmio_mmc_host *host = mmc_priv(mmc); + + return !!(sd_ctrl_read16_and_16_as_32(host, CTL_STATUS) & + TMIO_STAT_SIGSTATE); +} + static int tmio_multi_io_quirk(struct mmc_card *card, unsigned int direction, int blk_size) { @@ -1081,7 +1089,7 @@ static const struct mmc_host_ops tmio_mmc_ops = { .request = tmio_mmc_request, .set_ios = tmio_mmc_set_ios, .get_ro = tmio_mmc_get_ro, - .get_cd = mmc_gpio_get_cd, + .get_cd = tmio_mmc_get_cd, .enable_sdio_irq = tmio_mmc_enable_sdio_irq, .multi_io_quirk = tmio_multi_io_quirk, .hw_reset = tmio_mmc_hw_reset, @@ -1234,6 +1242,9 @@ int tmio_mmc_host_probe(struct tmio_mmc_host *_host) if (mmc_can_gpio_ro(mmc)) _host->ops.get_ro = mmc_gpio_get_ro; + if (mmc_can_gpio_cd(mmc)) + _host->ops.get_cd = mmc_gpio_get_cd; + _host->native_hotplug = !(mmc_can_gpio_cd(mmc) || mmc->caps & MMC_CAP_NEEDS_POLL || !mmc_card_is_removable(mmc)); From c7cd630a9751b9ec8bba37edbba06a29e7d9a14b Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Thu, 18 Jan 2018 01:28:13 +0900 Subject: [PATCH 17/55] mmc: tmio: fix never-detected card insertion bug The TMIO mmc cannot detect the card insertion in native_hotplug mode if the driver is probed without a card inserted. The reason is obvious; all IRQs are disabled by tmio_mmc_host_probe(), as follows: tmio_mmc_disable_mmc_irqs(_host, TMIO_MASK_ALL); The card event IRQs are first enabled by tmio_mmc_start_command() as follows: if (!host->native_hotplug) irq_mask &= ~(TMIO_STAT_CARD_REMOVE | TMIO_STAT_CARD_INSERT); tmio_mmc_enable_mmc_irqs(host, irq_mask); If the driver is probed without a card, tmio_mmc_start_command() is never called in the first place. So, the card is never detected. The card event IRQs must be enabled in probe/resume functions. Signed-off-by: Masahiro Yamada Reviewed-by: Wolfram Sang Signed-off-by: Ulf Hansson Tested-by: Wolfram Sang --- drivers/mmc/host/tmio_mmc_core.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/drivers/mmc/host/tmio_mmc_core.c b/drivers/mmc/host/tmio_mmc_core.c index 2abc425d45fd..add095368482 100644 --- a/drivers/mmc/host/tmio_mmc_core.c +++ b/drivers/mmc/host/tmio_mmc_core.c @@ -350,8 +350,6 @@ static int tmio_mmc_start_command(struct tmio_mmc_host *host, c |= TRANSFER_READ; } - if (!host->native_hotplug) - irq_mask &= ~(TMIO_STAT_CARD_REMOVE | TMIO_STAT_CARD_INSERT); tmio_mmc_enable_mmc_irqs(host, irq_mask); /* Fire off the command */ @@ -1280,11 +1278,13 @@ int tmio_mmc_host_probe(struct tmio_mmc_host *_host) irq_mask |= TMIO_MASK_READOP; if (!_host->chan_tx) irq_mask |= TMIO_MASK_WRITEOP; - if (!_host->native_hotplug) - irq_mask &= ~(TMIO_STAT_CARD_REMOVE | TMIO_STAT_CARD_INSERT); _host->sdcard_irq_mask &= ~irq_mask; + if (_host->native_hotplug) + tmio_mmc_enable_mmc_irqs(_host, + TMIO_STAT_CARD_REMOVE | TMIO_STAT_CARD_INSERT); + spin_lock_init(&_host->lock); mutex_init(&_host->ios_lock); @@ -1382,6 +1382,10 @@ int tmio_mmc_host_runtime_resume(struct device *dev) if (host->clk_cache) tmio_mmc_set_clock(host, host->clk_cache); + if (host->native_hotplug) + tmio_mmc_enable_mmc_irqs(host, + TMIO_STAT_CARD_REMOVE | TMIO_STAT_CARD_INSERT); + tmio_mmc_enable_dma(host, true); if (tmio_mmc_can_retune(host) && host->select_tuning(host)) From b12a7a28f860c3ab078ae306e13a659ec70b3c33 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Thu, 18 Jan 2018 01:28:14 +0900 Subject: [PATCH 18/55] mmc: tmio: move TMIO_MASK_{READOP, WRITEOP} handling to correct place As far as I tested the IP on UniPhier SoCs, TMIO_STAT_{RXRDY,TXRQ} are asserted for DMA mode as well as for PIO. I need to disable the those IRQs in dma_ops->start hook, otherwise the DMA transfer fails with the following error message: PIO IRQ in DMA mode! Renesas chips are the same cases since I see their dma_ops->start hooks explicitly clear TMIO_STAT_{RXRDY,TXRQ} (with nice comment!). If we do this sanity check in TMIO MMC core, RXRDY/TXRQ handling should be entirely moved to the core. tmio_mmc_cmd_irq() will be a suitable place to disable them. The probe function sets TMIO_MASK_{READOP,WRITEOP} but this is odd. /* Unmask the IRQs we want to know about */ if (!_host->chan_rx) irq_mask |= TMIO_MASK_READOP; if (!_host->chan_tx) irq_mask |= TMIO_MASK_WRITEOP; At this point, _host->{chan_rx,chan_tx} are _always_ NULL because tmio_mmc_request_dma() is called after this code. Consequently, TMIO_MASK_{READOP,WRITEOP} are set here whether DMA is used or not. Remove this pointless code. Signed-off-by: Masahiro Yamada Signed-off-by: Ulf Hansson Reviewed-by: Wolfram Sang Tested-by: Wolfram Sang --- drivers/mmc/host/renesas_sdhi_internal_dmac.c | 6 ------ drivers/mmc/host/renesas_sdhi_sys_dmac.c | 4 ---- drivers/mmc/host/tmio_mmc_core.c | 20 +++++++++---------- 3 files changed, 10 insertions(+), 20 deletions(-) diff --git a/drivers/mmc/host/renesas_sdhi_internal_dmac.c b/drivers/mmc/host/renesas_sdhi_internal_dmac.c index c063b2d0364d..a04f31fea72f 100644 --- a/drivers/mmc/host/renesas_sdhi_internal_dmac.c +++ b/drivers/mmc/host/renesas_sdhi_internal_dmac.c @@ -145,7 +145,6 @@ renesas_sdhi_internal_dmac_start_dma(struct tmio_mmc_host *host, u32 dtran_mode = DTRAN_MODE_BUS_WID_TH | DTRAN_MODE_ADDR_MODE; enum dma_data_direction dir; int ret; - u32 irq_mask; /* This DMAC cannot handle if sg_len is not 1 */ WARN_ON(host->sg_len > 1); @@ -157,11 +156,9 @@ renesas_sdhi_internal_dmac_start_dma(struct tmio_mmc_host *host, if (data->flags & MMC_DATA_READ) { dtran_mode |= DTRAN_MODE_CH_NUM_CH1; dir = DMA_FROM_DEVICE; - irq_mask = TMIO_STAT_RXRDY; } else { dtran_mode |= DTRAN_MODE_CH_NUM_CH0; dir = DMA_TO_DEVICE; - irq_mask = TMIO_STAT_TXRQ; } ret = dma_map_sg(&host->pdev->dev, sg, host->sg_len, dir); @@ -170,9 +167,6 @@ renesas_sdhi_internal_dmac_start_dma(struct tmio_mmc_host *host, renesas_sdhi_internal_dmac_enable_dma(host, true); - /* disable PIO irqs to avoid "PIO IRQ in DMA mode!" */ - tmio_mmc_disable_mmc_irqs(host, irq_mask); - /* set dma parameters */ renesas_sdhi_internal_dmac_dm_write(host, DM_CM_DTRAN_MODE, dtran_mode); diff --git a/drivers/mmc/host/renesas_sdhi_sys_dmac.c b/drivers/mmc/host/renesas_sdhi_sys_dmac.c index 434afa9dd9a1..4bb46c489d71 100644 --- a/drivers/mmc/host/renesas_sdhi_sys_dmac.c +++ b/drivers/mmc/host/renesas_sdhi_sys_dmac.c @@ -205,8 +205,6 @@ static void renesas_sdhi_sys_dmac_start_dma_rx(struct tmio_mmc_host *host) return; } - tmio_mmc_disable_mmc_irqs(host, TMIO_STAT_RXRDY); - /* The only sg element can be unaligned, use our bounce buffer then */ if (!aligned) { sg_init_one(&host->bounce_sg, host->bounce_buf, sg->length); @@ -280,8 +278,6 @@ static void renesas_sdhi_sys_dmac_start_dma_tx(struct tmio_mmc_host *host) return; } - tmio_mmc_disable_mmc_irqs(host, TMIO_STAT_TXRQ); - /* The only sg element can be unaligned, use our bounce buffer then */ if (!aligned) { unsigned long flags; diff --git a/drivers/mmc/host/tmio_mmc_core.c b/drivers/mmc/host/tmio_mmc_core.c index add095368482..75f0d6e273b5 100644 --- a/drivers/mmc/host/tmio_mmc_core.c +++ b/drivers/mmc/host/tmio_mmc_core.c @@ -621,15 +621,21 @@ static void tmio_mmc_cmd_irq(struct tmio_mmc_host *host, unsigned int stat) */ if (host->data && (!cmd->error || cmd->error == -EILSEQ)) { if (host->data->flags & MMC_DATA_READ) { - if (host->force_pio || !host->chan_rx) + if (host->force_pio || !host->chan_rx) { tmio_mmc_enable_mmc_irqs(host, TMIO_MASK_READOP); - else + } else { + tmio_mmc_disable_mmc_irqs(host, + TMIO_MASK_READOP); tasklet_schedule(&host->dma_issue); + } } else { - if (host->force_pio || !host->chan_tx) + if (host->force_pio || !host->chan_tx) { tmio_mmc_enable_mmc_irqs(host, TMIO_MASK_WRITEOP); - else + } else { + tmio_mmc_disable_mmc_irqs(host, + TMIO_MASK_WRITEOP); tasklet_schedule(&host->dma_issue); + } } } else { schedule_work(&host->done); @@ -1273,12 +1279,6 @@ int tmio_mmc_host_probe(struct tmio_mmc_host *_host) _host->sdcard_irq_mask = sd_ctrl_read16_and_16_as_32(_host, CTL_IRQ_MASK); tmio_mmc_disable_mmc_irqs(_host, TMIO_MASK_ALL); - /* Unmask the IRQs we want to know about */ - if (!_host->chan_rx) - irq_mask |= TMIO_MASK_READOP; - if (!_host->chan_tx) - irq_mask |= TMIO_MASK_WRITEOP; - _host->sdcard_irq_mask &= ~irq_mask; if (_host->native_hotplug) From 9b3ab55dbabd8bc8ac226a603f02ad39e6202521 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Thu, 18 Jan 2018 01:28:15 +0900 Subject: [PATCH 19/55] mmc: tmio: clear force_pio flag before starting data transfer Currently, force_pio is cleared when the driver exits. Then, it resulted in clearing it in multiple places since MMC drivers in general have multiple exit points. tmio_mmc_reset_work - bails out on timeout tmio_process_mrq - error out when it cannot send a command tmio_mmc_finish_request - successful exit This is error-prone since we may miss to cover all bail-out points. To simplify the code, the data structure should be initialized just before used since we have a single entrance. force_pio is only used for data transfer, so tmio_mmc_start_data() will be a suitable place to clear this flag. Signed-off-by: Masahiro Yamada Reviewed-by: Wolfram Sang Tested-by: Wolfram Sang Signed-off-by: Ulf Hansson --- drivers/mmc/host/tmio_mmc_core.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/mmc/host/tmio_mmc_core.c b/drivers/mmc/host/tmio_mmc_core.c index 75f0d6e273b5..bcc9fcd5f559 100644 --- a/drivers/mmc/host/tmio_mmc_core.c +++ b/drivers/mmc/host/tmio_mmc_core.c @@ -278,7 +278,6 @@ static void tmio_mmc_reset_work(struct work_struct *work) host->cmd = NULL; host->data = NULL; - host->force_pio = false; spin_unlock_irqrestore(&host->lock, flags); @@ -759,6 +758,7 @@ static int tmio_mmc_start_data(struct tmio_mmc_host *host, tmio_mmc_init_sg(host, data); host->data = data; + host->force_pio = false; /* Set transfer length / blocksize */ sd_ctrl_write16(host, CTL_SD_XFER_LEN, data->blksz); @@ -850,7 +850,6 @@ static void tmio_process_mrq(struct tmio_mmc_host *host, return; fail: - host->force_pio = false; host->mrq = NULL; mrq->cmd->error = ret; mmc_request_done(host->mmc, mrq); @@ -900,7 +899,6 @@ static void tmio_mmc_finish_request(struct tmio_mmc_host *host) if (host->cmd != mrq->sbc) { host->cmd = NULL; host->data = NULL; - host->force_pio = false; host->mrq = NULL; } From c9b929edf4e1f96c550584fe8445755b6d600e71 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Thu, 18 Jan 2018 01:28:16 +0900 Subject: [PATCH 20/55] mmc: tmio: remove useless TMIO_MASK_CMD handling in tmio_mmc_host_probe() TMIO_MASK_CMD is properly enabled in tmio_mmc_start_command(). We have no reason to set it up in tmio_mmc_host_probe(). (If we really wanted to set it in the probe, we would have to do likewise when resuming.) Even worse, the following code is extremely confusing: _host->sdcard_irq_mask &= ~irq_mask; The logic is opposite between "->sdcard_irq_mask" and "irq_mask". The intention is not clear at a glance. Signed-off-by: Masahiro Yamada Reviewed-by: Wolfram Sang Tested-by: Wolfram Sang Signed-off-by: Ulf Hansson --- drivers/mmc/host/tmio_mmc_core.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/mmc/host/tmio_mmc_core.c b/drivers/mmc/host/tmio_mmc_core.c index bcc9fcd5f559..e30df9ad8197 100644 --- a/drivers/mmc/host/tmio_mmc_core.c +++ b/drivers/mmc/host/tmio_mmc_core.c @@ -1195,7 +1195,6 @@ int tmio_mmc_host_probe(struct tmio_mmc_host *_host) struct tmio_mmc_data *pdata = _host->pdata; struct mmc_host *mmc = _host->mmc; int ret; - u32 irq_mask = TMIO_MASK_CMD; /* * Check the sanity of mmc->f_min to prevent tmio_mmc_set_clock() from @@ -1277,8 +1276,6 @@ int tmio_mmc_host_probe(struct tmio_mmc_host *_host) _host->sdcard_irq_mask = sd_ctrl_read16_and_16_as_32(_host, CTL_IRQ_MASK); tmio_mmc_disable_mmc_irqs(_host, TMIO_MASK_ALL); - _host->sdcard_irq_mask &= ~irq_mask; - if (_host->native_hotplug) tmio_mmc_enable_mmc_irqs(_host, TMIO_STAT_CARD_REMOVE | TMIO_STAT_CARD_INSERT); From 871cfe05f40b52ebb692c56eecd1d27b673d8a21 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 14 Feb 2018 17:45:12 +0200 Subject: [PATCH 21/55] mmc: core: Re-use DEFINE_SHOW_ATTRIBUTE() macro ...instead of open coding file operations followed by custom ->open() callbacks per each attribute. Signed-off-by: Andy Shevchenko Reviewed-by: Avri Altman Reviewed-by: Linus Walleij Reviewed-by: Shawn Lin Signed-off-by: Ulf Hansson --- drivers/mmc/core/debugfs.c | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/drivers/mmc/core/debugfs.c b/drivers/mmc/core/debugfs.c index 0f4a7d7b2626..c51e0c044a3e 100644 --- a/drivers/mmc/core/debugfs.c +++ b/drivers/mmc/core/debugfs.c @@ -196,18 +196,7 @@ static int mmc_ios_show(struct seq_file *s, void *data) return 0; } - -static int mmc_ios_open(struct inode *inode, struct file *file) -{ - return single_open(file, mmc_ios_show, inode->i_private); -} - -static const struct file_operations mmc_ios_fops = { - .open = mmc_ios_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; +DEFINE_SHOW_ATTRIBUTE(mmc_ios); static int mmc_clock_opt_get(void *data, u64 *val) { From 64c1412b77d08df1bc4ddea1187eb8a76df1186c Mon Sep 17 00:00:00 2001 From: Shawn Lin Date: Fri, 23 Feb 2018 16:47:26 +0800 Subject: [PATCH 22/55] mmc: dw_mmc: Convert to use DEFINE_SHOW_ATTRIBUTE Use the newly added macro to simply to the code. Signed-off-by: Shawn Lin Reviewed-by: Jaehoon Chung Signed-off-by: Ulf Hansson --- drivers/mmc/host/dw_mmc.c | 28 ++-------------------------- 1 file changed, 2 insertions(+), 26 deletions(-) diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c index d9b4acefed31..5332120030e4 100644 --- a/drivers/mmc/host/dw_mmc.c +++ b/drivers/mmc/host/dw_mmc.c @@ -147,19 +147,7 @@ static int dw_mci_req_show(struct seq_file *s, void *v) return 0; } - -static int dw_mci_req_open(struct inode *inode, struct file *file) -{ - return single_open(file, dw_mci_req_show, inode->i_private); -} - -static const struct file_operations dw_mci_req_fops = { - .owner = THIS_MODULE, - .open = dw_mci_req_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; +DEFINE_SHOW_ATTRIBUTE(dw_mci_req); static int dw_mci_regs_show(struct seq_file *s, void *v) { @@ -178,19 +166,7 @@ static int dw_mci_regs_show(struct seq_file *s, void *v) return 0; } - -static int dw_mci_regs_open(struct inode *inode, struct file *file) -{ - return single_open(file, dw_mci_regs_show, inode->i_private); -} - -static const struct file_operations dw_mci_regs_fops = { - .owner = THIS_MODULE, - .open = dw_mci_regs_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; +DEFINE_SHOW_ATTRIBUTE(dw_mci_regs); static void dw_mci_init_debugfs(struct dw_mci_slot *slot) { From ec10ab572e4060f6ef586952196ef80f3b3b7f3b Mon Sep 17 00:00:00 2001 From: Shawn Lin Date: Fri, 23 Feb 2018 10:23:16 +0800 Subject: [PATCH 23/55] mmc: dw_mmc: Remove prev_state and state assignment for STATE_SENDING_CMD Clang reports a compile warning: drivers/mmc/host/dw_mmc.c:2124:5: warning: Value stored to 'prev_state' is never read By checking the code, prev_state and state assignment for STATE_SENDING_CMD is indeed never used after jumping to unlock tag. So remove it. Signed-off-by: Shawn Lin Acked-by: Jaehoon Chung Signed-off-by: Ulf Hansson --- drivers/mmc/host/dw_mmc.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c index 5332120030e4..aecc3e255507 100644 --- a/drivers/mmc/host/dw_mmc.c +++ b/drivers/mmc/host/dw_mmc.c @@ -2001,7 +2001,6 @@ static void dw_mci_tasklet_func(unsigned long priv) set_bit(EVENT_CMD_COMPLETE, &host->completed_events); err = dw_mci_command_complete(host, cmd); if (cmd == mrq->sbc && !err) { - prev_state = state = STATE_SENDING_CMD; __dw_mci_start_request(host, host->slot, mrq->cmd); goto unlock; From 4b514fa28760cc8f2b415fb0da72be79ccb5a5fd Mon Sep 17 00:00:00 2001 From: Alexey Roslyakov Date: Fri, 23 Feb 2018 02:45:25 +0700 Subject: [PATCH 24/55] mmc: dw_mmc: update kernel-doc comments for dw_mci cur_slot and num_slots has been removed from struct dw_mci in 42f989c002f2. Unfortunately, inline documentation was not updated so far. Fix @lock field documentation in Locking section. Move @mrq field of struct dw_mci_slot mention closer to it description, so no one could miss this slightest detail. Couple of code style fixes as a bonus. Signed-off-by: Alexey Roslyakov Reviewed-by: Shawn Lin Acked-by: Jaehoon Chung Signed-off-by: Ulf Hansson --- drivers/mmc/host/dw_mmc.h | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/drivers/mmc/host/dw_mmc.h b/drivers/mmc/host/dw_mmc.h index 1424bd490dd1..9c7085ab63df 100644 --- a/drivers/mmc/host/dw_mmc.h +++ b/drivers/mmc/host/dw_mmc.h @@ -65,8 +65,7 @@ struct dw_mci_dma_slave { * @fifo_reg: Pointer to MMIO registers for data FIFO * @sg: Scatterlist entry currently being processed by PIO code, if any. * @sg_miter: PIO mapping scatterlist iterator. - * @cur_slot: The slot which is currently using the controller. - * @mrq: The request currently being processed on @cur_slot, + * @mrq: The request currently being processed on @slot, * or NULL if the controller is idle. * @cmd: The command currently being sent to the card, or NULL. * @data: The data currently being transferred, or NULL if no data @@ -102,7 +101,6 @@ struct dw_mci_dma_slave { * @bus_hz: The rate of @mck in Hz. This forms the basis for MMC bus * rate and timeout calculations. * @current_speed: Configured rate of the controller. - * @num_slots: Number of slots available. * @fifoth_val: The value of FIFOTH register. * @verid: Denote Version ID. * @dev: Device associated with the MMC controller. @@ -134,17 +132,17 @@ struct dw_mci_dma_slave { * ======= * * @lock is a softirq-safe spinlock protecting @queue as well as + * @slot, @mrq and @state. These must always be updated * at the same time while holding @lock. + * The @mrq field of struct dw_mci_slot is also protected by @lock, + * and must always be written at the same time as the slot is added to + * @queue. * * @irq_lock is an irq-safe spinlock protecting the INTMASK register * to allow the interrupt handler to modify it directly. Held for only long * enough to read-modify-write INTMASK and no other locks are grabbed when * holding this one. * - * The @mrq field of struct dw_mci_slot is also protected by @lock, - * and must always be written at the same time as the slot is added to - * @queue. - * * @pending_events and @completed_events are accessed using atomic bit * operations, so they don't need any locking. * @@ -321,8 +319,8 @@ struct dw_mci_board { #define SDMMC_ENABLE_SHIFT 0x110 #define SDMMC_DATA(x) (x) /* -* Registers to support idmac 64-bit address mode -*/ + * Registers to support idmac 64-bit address mode + */ #define SDMMC_DBADDRL 0x088 #define SDMMC_DBADDRU 0x08c #define SDMMC_IDSTS64 0x090 @@ -449,7 +447,8 @@ struct dw_mci_board { (SDMMC_CTRL_RESET | SDMMC_CTRL_FIFO_RESET | SDMMC_CTRL_DMA_RESET) /* FIFO register access macros. These should not change the data endian-ness - * as they are written to memory to be dealt with by the upper layers */ + * as they are written to memory to be dealt with by the upper layers + */ #define mci_fifo_readw(__reg) __raw_readw(__reg) #define mci_fifo_readl(__reg) __raw_readl(__reg) #define mci_fifo_readq(__reg) __raw_readq(__reg) From 129d21ce15af027696864b2798b41f4514f1c8c2 Mon Sep 17 00:00:00 2001 From: Shawn Lin Date: Sun, 25 Feb 2018 09:37:36 +0800 Subject: [PATCH 25/55] mmc: ushc: Remove bogus check of usb_submit_urb Not sure why it was there in the first place, but it's obviously useless check, so let's remove it. Signed-off-by: Shawn Lin Signed-off-by: Ulf Hansson --- drivers/mmc/host/ushc.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/mmc/host/ushc.c b/drivers/mmc/host/ushc.c index 1d843357422e..81dac17064d7 100644 --- a/drivers/mmc/host/ushc.c +++ b/drivers/mmc/host/ushc.c @@ -309,8 +309,6 @@ static void ushc_request(struct mmc_host *mmc, struct mmc_request *req) /* Submit CSW. */ ret = usb_submit_urb(ushc->csw_urb, GFP_ATOMIC); - if (ret < 0) - goto out; out: spin_unlock_irqrestore(&ushc->lock, flags); From 7b7d57fd1b773d25d8358c6017592b4928bf76ce Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Wed, 14 Feb 2018 15:57:44 +0200 Subject: [PATCH 26/55] mmc: sdhci-pci: Get rid of glk_cqe_enable() Now that tuning no longer leaves the Buffer Read Enable bit set (refer intel_execute_tuning()), glk_cqe_enable() is no longer needed. Get rid of it. Signed-off-by: Adrian Hunter Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci-pci-core.c | 20 +------------------- 1 file changed, 1 insertion(+), 19 deletions(-) diff --git a/drivers/mmc/host/sdhci-pci-core.c b/drivers/mmc/host/sdhci-pci-core.c index 82c4f05f91d8..ce21d86a8141 100644 --- a/drivers/mmc/host/sdhci-pci-core.c +++ b/drivers/mmc/host/sdhci-pci-core.c @@ -712,26 +712,8 @@ static int glk_emmc_probe_slot(struct sdhci_pci_slot *slot) return ret; } -static void glk_cqe_enable(struct mmc_host *mmc) -{ - struct sdhci_host *host = mmc_priv(mmc); - u32 reg; - - /* - * CQE gets stuck if it sees Buffer Read Enable bit set, which can be - * the case after tuning, so ensure the buffer is drained. - */ - reg = sdhci_readl(host, SDHCI_PRESENT_STATE); - while (reg & SDHCI_DATA_AVAILABLE) { - sdhci_readl(host, SDHCI_BUFFER); - reg = sdhci_readl(host, SDHCI_PRESENT_STATE); - } - - sdhci_cqe_enable(mmc); -} - static const struct cqhci_host_ops glk_cqhci_ops = { - .enable = glk_cqe_enable, + .enable = sdhci_cqe_enable, .disable = sdhci_cqe_disable, .dumpregs = sdhci_pci_dumpregs, }; From 9c316b38b7801e5dabfc41ab700a0caf743e38b4 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Tue, 27 Feb 2018 14:51:23 +0200 Subject: [PATCH 27/55] mmc: sdhci: Do not unnecessarily enable wakeup for card detect interrupt Do not unnecessarily enable card detect wakeup in the cases that the card is not removable or a GPIO is used for card detect. Signed-off-by: Adrian Hunter Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 2020e57ffa7e..996845cb5af3 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -2899,6 +2899,14 @@ static irqreturn_t sdhci_thread_irq(int irq, void *dev_id) \*****************************************************************************/ #ifdef CONFIG_PM + +static bool sdhci_cd_irq_can_wakeup(struct sdhci_host *host) +{ + return mmc_card_is_removable(host->mmc) && + !(host->quirks & SDHCI_QUIRK_BROKEN_CARD_DETECTION) && + !mmc_can_gpio_cd(host->mmc); +} + /* * To enable wakeup events, the corresponding events have to be enabled in * the Interrupt Status Enable register too. See 'Table 1-6: Wakeup Signal @@ -2915,7 +2923,7 @@ static bool sdhci_enable_irq_wakeups(struct sdhci_host *host) u8 wake_val = 0; u8 val; - if (!(host->quirks & SDHCI_QUIRK_BROKEN_CARD_DETECTION)) { + if (sdhci_cd_irq_can_wakeup(host)) { wake_val |= SDHCI_WAKE_ON_INSERT | SDHCI_WAKE_ON_REMOVE; irq_val |= SDHCI_INT_CARD_INSERT | SDHCI_INT_CARD_REMOVE; } From d5d568fad9a52ac4eba5d9a080a5cddb8498fa5e Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Tue, 27 Feb 2018 14:51:24 +0200 Subject: [PATCH 28/55] mmc: sdhci: Do not unnecessarily enable wakeup for SDIO card interrupt Do not enable wakeup for SDIO card interrupt unless the SDIO function driver has requested it which is indicated by mmc_card_wake_sdio_irq(). Signed-off-by: Adrian Hunter Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 996845cb5af3..2ededa7f43df 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -2928,8 +2928,13 @@ static bool sdhci_enable_irq_wakeups(struct sdhci_host *host) irq_val |= SDHCI_INT_CARD_INSERT | SDHCI_INT_CARD_REMOVE; } - wake_val |= SDHCI_WAKE_ON_INT; - irq_val |= SDHCI_INT_CARD_INT; + if (mmc_card_wake_sdio_irq(host->mmc)) { + wake_val |= SDHCI_WAKE_ON_INT; + irq_val |= SDHCI_INT_CARD_INT; + } + + if (!irq_val) + return false; val = sdhci_readb(host, SDHCI_WAKE_UP_CONTROL); val &= ~mask; From 36f1d7e817a5540f6624ce1007339688bd443308 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Tue, 27 Feb 2018 14:51:25 +0200 Subject: [PATCH 29/55] mmc: slot-gpio: Add a function to enable/disable card detect IRQ wakeup Commit 03dbaa04a2e5 ("mmc: slot-gpio: Add support to enable irq wake on cd_irq") enabled wakeup at initialization. However drivers may wish to enable and disable based on different criteria. Add a helper function mmc_gpio_set_cd_wake() to make it easy for drivers to do that. Signed-off-by: Adrian Hunter Signed-off-by: Ulf Hansson --- drivers/mmc/core/core.c | 3 +-- drivers/mmc/core/slot-gpio.c | 21 +++++++++++++++++++++ include/linux/mmc/slot-gpio.h | 1 + 3 files changed, 23 insertions(+), 2 deletions(-) diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index e01910dd964b..121ce50b6d5e 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -2655,8 +2655,7 @@ void mmc_start_host(struct mmc_host *host) void mmc_stop_host(struct mmc_host *host) { if (host->slot.cd_irq >= 0) { - if (host->slot.cd_wake_enabled) - disable_irq_wake(host->slot.cd_irq); + mmc_gpio_set_cd_wake(host, false); disable_irq(host->slot.cd_irq); } diff --git a/drivers/mmc/core/slot-gpio.c b/drivers/mmc/core/slot-gpio.c index 3698b0576009..dccbc52af5c4 100644 --- a/drivers/mmc/core/slot-gpio.c +++ b/drivers/mmc/core/slot-gpio.c @@ -154,6 +154,27 @@ void mmc_gpiod_request_cd_irq(struct mmc_host *host) } EXPORT_SYMBOL(mmc_gpiod_request_cd_irq); +int mmc_gpio_set_cd_wake(struct mmc_host *host, bool on) +{ + int ret = 0; + + if (!(host->caps & MMC_CAP_CD_WAKE) || + host->slot.cd_irq < 0 || + on == host->slot.cd_wake_enabled) + return 0; + + if (on) { + ret = enable_irq_wake(host->slot.cd_irq); + host->slot.cd_wake_enabled = !ret; + } else { + disable_irq_wake(host->slot.cd_irq); + host->slot.cd_wake_enabled = false; + } + + return ret; +} +EXPORT_SYMBOL(mmc_gpio_set_cd_wake); + /* Register an alternate interrupt service routine for * the card-detect GPIO. */ diff --git a/include/linux/mmc/slot-gpio.h b/include/linux/mmc/slot-gpio.h index 91f1ba0663c8..06607c59c4d0 100644 --- a/include/linux/mmc/slot-gpio.h +++ b/include/linux/mmc/slot-gpio.h @@ -31,6 +31,7 @@ int mmc_gpiod_request_ro(struct mmc_host *host, const char *con_id, unsigned int debounce, bool *gpio_invert); void mmc_gpio_set_cd_isr(struct mmc_host *host, irqreturn_t (*isr)(int irq, void *dev_id)); +int mmc_gpio_set_cd_wake(struct mmc_host *host, bool on); void mmc_gpiod_request_cd_irq(struct mmc_host *host); bool mmc_can_gpio_cd(struct mmc_host *host); bool mmc_can_gpio_ro(struct mmc_host *host); From d56ee1ff30860b12d6a072676114abb9d63f03b9 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Tue, 27 Feb 2018 14:51:26 +0200 Subject: [PATCH 30/55] mmc: sdhci-pci: Respect PM flags when enabling card detect GPIO IRQ wakeup Commit 03dbaa04a2e5 ("mmc: slot-gpio: Add support to enable irq wake on cd_irq") enabled wakeup at initialization. However, users also want to control it from sysfs power/wakeup attribute. That means the driver needs to check the PM flags before enabling it in the suspend callback. Add support for that in sdhci-pci, which is the only driver presently using the MMC_CAP_CD_WAKE flag, and remove the enabling in mmc_gpiod_request_cd_irq() Signed-off-by: Adrian Hunter Signed-off-by: Ulf Hansson --- drivers/mmc/core/slot-gpio.c | 2 -- drivers/mmc/host/sdhci-pci-core.c | 23 +++++++++++++++++++---- 2 files changed, 19 insertions(+), 6 deletions(-) diff --git a/drivers/mmc/core/slot-gpio.c b/drivers/mmc/core/slot-gpio.c index dccbc52af5c4..31f7dbb15668 100644 --- a/drivers/mmc/core/slot-gpio.c +++ b/drivers/mmc/core/slot-gpio.c @@ -149,8 +149,6 @@ void mmc_gpiod_request_cd_irq(struct mmc_host *host) if (irq < 0) host->caps |= MMC_CAP_NEEDS_POLL; - else if ((host->caps & MMC_CAP_CD_WAKE) && !enable_irq_wake(irq)) - host->slot.cd_wake_enabled = true; } EXPORT_SYMBOL(mmc_gpiod_request_cd_irq); diff --git a/drivers/mmc/host/sdhci-pci-core.c b/drivers/mmc/host/sdhci-pci-core.c index ce21d86a8141..787434e5589d 100644 --- a/drivers/mmc/host/sdhci-pci-core.c +++ b/drivers/mmc/host/sdhci-pci-core.c @@ -41,18 +41,25 @@ static void sdhci_pci_hw_reset(struct sdhci_host *host); static int sdhci_pci_init_wakeup(struct sdhci_pci_chip *chip) { mmc_pm_flag_t pm_flags = 0; + bool cap_cd_wake = false; int i; for (i = 0; i < chip->num_slots; i++) { struct sdhci_pci_slot *slot = chip->slots[i]; - if (slot) + if (slot) { pm_flags |= slot->host->mmc->pm_flags; + if (slot->host->mmc->caps & MMC_CAP_CD_WAKE) + cap_cd_wake = true; + } } - return device_set_wakeup_enable(&chip->pdev->dev, - (pm_flags & MMC_PM_KEEP_POWER) && - (pm_flags & MMC_PM_WAKE_SDIO_IRQ)); + if ((pm_flags & MMC_PM_KEEP_POWER) && (pm_flags & MMC_PM_WAKE_SDIO_IRQ)) + return device_wakeup_enable(&chip->pdev->dev); + else if (!cap_cd_wake) + return device_wakeup_disable(&chip->pdev->dev); + + return 0; } static int sdhci_pci_suspend_host(struct sdhci_pci_chip *chip) @@ -76,6 +83,9 @@ static int sdhci_pci_suspend_host(struct sdhci_pci_chip *chip) ret = sdhci_suspend_host(host); if (ret) goto err_pci_suspend; + + if (device_may_wakeup(&chip->pdev->dev)) + mmc_gpio_set_cd_wake(host->mmc, true); } return 0; @@ -99,6 +109,8 @@ int sdhci_pci_resume_host(struct sdhci_pci_chip *chip) ret = sdhci_resume_host(slot->host); if (ret) return ret; + + mmc_gpio_set_cd_wake(slot->host->mmc, false); } return 0; @@ -1698,6 +1710,9 @@ static struct sdhci_pci_slot *sdhci_pci_probe_slot( if (device_can_wakeup(&pdev->dev)) host->mmc->pm_caps |= MMC_PM_WAKE_SDIO_IRQ; + if (host->mmc->caps & MMC_CAP_CD_WAKE) + device_init_wakeup(&pdev->dev, true); + if (slot->cd_idx >= 0) { ret = mmc_gpiod_request_cd(host->mmc, NULL, slot->cd_idx, slot->cd_override_level, 0, NULL); From df1d7c8d45a50aa0441b413bbd8f4d51438038a8 Mon Sep 17 00:00:00 2001 From: Sean Wang Date: Mon, 5 Mar 2018 15:03:19 +0800 Subject: [PATCH 31/55] mmc: dt-bindings: add support for MT7622 SoC Add the devicetree binding for MT7622 SoC Signed-off-by: Sean Wang Signed-off-by: Ulf Hansson --- Documentation/devicetree/bindings/mmc/mtk-sd.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/mmc/mtk-sd.txt b/Documentation/devicetree/bindings/mmc/mtk-sd.txt index 9b8017670870..f33467a54a05 100644 --- a/Documentation/devicetree/bindings/mmc/mtk-sd.txt +++ b/Documentation/devicetree/bindings/mmc/mtk-sd.txt @@ -12,6 +12,7 @@ Required properties: "mediatek,mt8173-mmc": for mmc host ip compatible with mt8173 "mediatek,mt2701-mmc": for mmc host ip compatible with mt2701 "mediatek,mt2712-mmc": for mmc host ip compatible with mt2712 + "mediatek,mt7622-mmc": for MT7622 SoC "mediatek,mt7623-mmc", "mediatek,mt2701-mmc": for MT7623 SoC - reg: physical base address of the controller and length From 966580ad236e825483abd956c99edbdc0b06476c Mon Sep 17 00:00:00 2001 From: Sean Wang Date: Mon, 5 Mar 2018 15:03:20 +0800 Subject: [PATCH 32/55] mmc: mediatek: add support for MT7622 SoC Just applying the existing logic and adding its own characteristics into the space pointed by an extra entry of struct of_device_id to have support of MT7622 SoC. Signed-off-by: Chaotian Jing Signed-off-by: Sean Wang Tested-by: Jumin Li Signed-off-by: Ulf Hansson --- drivers/mmc/host/mtk-sd.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/drivers/mmc/host/mtk-sd.c b/drivers/mmc/host/mtk-sd.c index 6457a7d8880f..cb274e822293 100644 --- a/drivers/mmc/host/mtk-sd.c +++ b/drivers/mmc/host/mtk-sd.c @@ -438,11 +438,23 @@ static const struct mtk_mmc_compatible mt2712_compat = { .enhance_rx = true, }; +static const struct mtk_mmc_compatible mt7622_compat = { + .clk_div_bits = 12, + .hs400_tune = false, + .pad_tune_reg = MSDC_PAD_TUNE0, + .async_fifo = true, + .data_tune = true, + .busy_check = true, + .stop_clk_fix = true, + .enhance_rx = true, +}; + static const struct of_device_id msdc_of_ids[] = { { .compatible = "mediatek,mt8135-mmc", .data = &mt8135_compat}, { .compatible = "mediatek,mt8173-mmc", .data = &mt8173_compat}, { .compatible = "mediatek,mt2701-mmc", .data = &mt2701_compat}, { .compatible = "mediatek,mt2712-mmc", .data = &mt2712_compat}, + { .compatible = "mediatek,mt7622-mmc", .data = &mt7622_compat}, {} }; MODULE_DEVICE_TABLE(of, msdc_of_ids); From 86b93a4825d8fa22f05e712a0e70b7406e1df1b5 Mon Sep 17 00:00:00 2001 From: Jaehoon Chung Date: Fri, 23 Feb 2018 15:41:33 +0900 Subject: [PATCH 33/55] mmc: dw_mmc: remove the deprecated "clock-freq-min-max" property 'clock-freq-min-max' property had already deprecated. Remove the 'clock-freq-min-max' property that is kept to maintain the compatibility. Signed-off-by: Jaehoon Chung Reviewed-by: Rob Herring Signed-off-by: Ulf Hansson --- .../devicetree/bindings/mmc/synopsys-dw-mshc.txt | 4 ---- drivers/mmc/host/dw_mmc.c | 15 ++++----------- 2 files changed, 4 insertions(+), 15 deletions(-) diff --git a/Documentation/devicetree/bindings/mmc/synopsys-dw-mshc.txt b/Documentation/devicetree/bindings/mmc/synopsys-dw-mshc.txt index ef3e5f14067a..75c9fdca4aaf 100644 --- a/Documentation/devicetree/bindings/mmc/synopsys-dw-mshc.txt +++ b/Documentation/devicetree/bindings/mmc/synopsys-dw-mshc.txt @@ -59,10 +59,6 @@ Optional properties: is specified and the ciu clock is specified then we'll try to set the ciu clock to this at probe time. -* clock-freq-min-max (DEPRECATED): Minimum and Maximum clock frequency for card output - clock(cclk_out). If it's not specified, max is 200MHZ and min is 400KHz by default. - (Use the "max-frequency" instead of "clock-freq-min-max".) - * num-slots (DEPRECATED): specifies the number of slots supported by the controller. The number of physical slots actually used could be equal or less than the value specified by num-slots. If this property is not specified, the value diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c index 09ed242de464..b07135e6f74f 100644 --- a/drivers/mmc/host/dw_mmc.c +++ b/drivers/mmc/host/dw_mmc.c @@ -2799,6 +2799,10 @@ static int dw_mci_init_slot_caps(struct dw_mci_slot *slot) if (host->pdata->caps2) mmc->caps2 = host->pdata->caps2; + mmc->f_min = DW_MCI_FREQ_MIN; + if (!mmc->f_max) + mmc->f_max = DW_MCI_FREQ_MAX; + /* Process SDIO IRQs through the sdio_irq_work. */ if (mmc->caps & MMC_CAP_SDIO_IRQ) mmc->caps2 |= MMC_CAP2_SDIO_IRQ_NOTHREAD; @@ -2811,7 +2815,6 @@ static int dw_mci_init_slot(struct dw_mci *host) struct mmc_host *mmc; struct dw_mci_slot *slot; int ret; - u32 freq[2]; mmc = mmc_alloc_host(sizeof(struct dw_mci_slot), host->dev); if (!mmc) @@ -2825,16 +2828,6 @@ static int dw_mci_init_slot(struct dw_mci *host) host->slot = slot; mmc->ops = &dw_mci_ops; - if (device_property_read_u32_array(host->dev, "clock-freq-min-max", - freq, 2)) { - mmc->f_min = DW_MCI_FREQ_MIN; - mmc->f_max = DW_MCI_FREQ_MAX; - } else { - dev_info(host->dev, - "'clock-freq-min-max' property was deprecated.\n"); - mmc->f_min = freq[0]; - mmc->f_max = freq[1]; - } /*if there are external regulators, get them*/ ret = mmc_regulator_get_supply(mmc); From 01b653c2199b55ea798f9b4e224d055317524d8f Mon Sep 17 00:00:00 2001 From: Jaehoon Chung Date: Fri, 23 Feb 2018 15:41:34 +0900 Subject: [PATCH 34/55] mmc: dw_mmc: remove the deprecated "num-slots" 'num-slots' property had already deprecated. Remove the 'nom-slots' property that is kept to maintain the compatibility. Signed-off-by: Jaehoon Chung Reviewed-by: Rob Herring Signed-off-by: Ulf Hansson --- Documentation/devicetree/bindings/mmc/synopsys-dw-mshc.txt | 5 ----- drivers/mmc/host/dw_mmc-pci.c | 1 - drivers/mmc/host/dw_mmc.c | 4 ---- drivers/mmc/host/dw_mmc.h | 2 -- 4 files changed, 12 deletions(-) diff --git a/Documentation/devicetree/bindings/mmc/synopsys-dw-mshc.txt b/Documentation/devicetree/bindings/mmc/synopsys-dw-mshc.txt index 75c9fdca4aaf..7e5e427a22ce 100644 --- a/Documentation/devicetree/bindings/mmc/synopsys-dw-mshc.txt +++ b/Documentation/devicetree/bindings/mmc/synopsys-dw-mshc.txt @@ -59,11 +59,6 @@ Optional properties: is specified and the ciu clock is specified then we'll try to set the ciu clock to this at probe time. -* num-slots (DEPRECATED): specifies the number of slots supported by the controller. - The number of physical slots actually used could be equal or less than the - value specified by num-slots. If this property is not specified, the value - of num-slot property is assumed to be 1. - * fifo-depth: The maximum size of the tx/rx fifo's. If this property is not specified, the default value of the fifo size is determined from the controller registers. diff --git a/drivers/mmc/host/dw_mmc-pci.c b/drivers/mmc/host/dw_mmc-pci.c index ab8713297edb..3ad07d7b2c97 100644 --- a/drivers/mmc/host/dw_mmc-pci.c +++ b/drivers/mmc/host/dw_mmc-pci.c @@ -29,7 +29,6 @@ MMC_CAP_SDIO_IRQ) static struct dw_mci_board pci_board_data = { - .num_slots = 1, .caps = DW_MCI_CAPABILITIES, .bus_hz = 33 * 1000 * 1000, .detect_delay_ms = 200, diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c index b07135e6f74f..e7de83805e60 100644 --- a/drivers/mmc/host/dw_mmc.c +++ b/drivers/mmc/host/dw_mmc.c @@ -3126,10 +3126,6 @@ static struct dw_mci_board *dw_mci_parse_dt(struct dw_mci *host) return ERR_PTR(-EPROBE_DEFER); } - /* find out number of slots supported */ - if (!device_property_read_u32(dev, "num-slots", &pdata->num_slots)) - dev_info(dev, "'num-slots' was deprecated.\n"); - if (device_property_read_u32(dev, "fifo-depth", &pdata->fifo_depth)) dev_info(dev, "fifo-depth property not found, using value of FIFOTH register as default\n"); diff --git a/drivers/mmc/host/dw_mmc.h b/drivers/mmc/host/dw_mmc.h index 9c7085ab63df..950f194e1573 100644 --- a/drivers/mmc/host/dw_mmc.h +++ b/drivers/mmc/host/dw_mmc.h @@ -251,8 +251,6 @@ struct dma_pdata; /* Board platform data */ struct dw_mci_board { - u32 num_slots; - unsigned int bus_hz; /* Clock speed at the cclk_in pad */ u32 caps; /* Capabilities */ From 984f624e94b42440998cc6e4a1a6fed4d9c74888 Mon Sep 17 00:00:00 2001 From: Jaehoon Chung Date: Fri, 23 Feb 2018 15:41:35 +0900 Subject: [PATCH 35/55] ARM: dts: socfpga: remove 'num-slots' property for dwmmc Since 'num-slots' had already deprecated, remove the property in device-tree file. Signed-off-by: Jaehoon Chung Signed-off-by: Ulf Hansson --- arch/arm/boot/dts/socfpga_arria10_socdk_sdmmc.dts | 1 - arch/arm/boot/dts/socfpga_arria5.dtsi | 1 - arch/arm/boot/dts/socfpga_cyclone5.dtsi | 1 - arch/arm/boot/dts/socfpga_vt.dts | 1 - 4 files changed, 4 deletions(-) diff --git a/arch/arm/boot/dts/socfpga_arria10_socdk_sdmmc.dts b/arch/arm/boot/dts/socfpga_arria10_socdk_sdmmc.dts index 040a164ba148..5822fd2085db 100644 --- a/arch/arm/boot/dts/socfpga_arria10_socdk_sdmmc.dts +++ b/arch/arm/boot/dts/socfpga_arria10_socdk_sdmmc.dts @@ -20,7 +20,6 @@ &mmc { status = "okay"; - num-slots = <1>; cap-sd-highspeed; broken-cd; bus-width = <4>; diff --git a/arch/arm/boot/dts/socfpga_arria5.dtsi b/arch/arm/boot/dts/socfpga_arria5.dtsi index 8c037297296c..e59461f5416e 100644 --- a/arch/arm/boot/dts/socfpga_arria5.dtsi +++ b/arch/arm/boot/dts/socfpga_arria5.dtsi @@ -30,7 +30,6 @@ }; mmc0: dwmmc0@ff704000 { - num-slots = <1>; broken-cd; bus-width = <4>; cap-mmc-highspeed; diff --git a/arch/arm/boot/dts/socfpga_cyclone5.dtsi b/arch/arm/boot/dts/socfpga_cyclone5.dtsi index a05e3df23103..68ced67f8bfb 100644 --- a/arch/arm/boot/dts/socfpga_cyclone5.dtsi +++ b/arch/arm/boot/dts/socfpga_cyclone5.dtsi @@ -31,7 +31,6 @@ }; mmc0: dwmmc0@ff704000 { - num-slots = <1>; broken-cd; bus-width = <4>; cap-mmc-highspeed; diff --git a/arch/arm/boot/dts/socfpga_vt.dts b/arch/arm/boot/dts/socfpga_vt.dts index dfe2193cd4d5..547c38632c68 100644 --- a/arch/arm/boot/dts/socfpga_vt.dts +++ b/arch/arm/boot/dts/socfpga_vt.dts @@ -42,7 +42,6 @@ }; dwmmc0@ff704000 { - num-slots = <1>; broken-cd; bus-width = <4>; cap-mmc-highspeed; From a6306eb6a5f7038a8ba2eefb254efe4ead5ce05e Mon Sep 17 00:00:00 2001 From: Jaehoon Chung Date: Fri, 23 Feb 2018 15:41:36 +0900 Subject: [PATCH 36/55] arm64: dts: stratix10: remove 'num-slots' property for dwmmc Since 'num-slots' had already deprecated, remove the property in device-tree file. Signed-off-by: Jaehoon Chung Acked-by: Dinh Nguyen Signed-off-by: Ulf Hansson --- arch/arm64/boot/dts/altera/socfpga_stratix10_socdk.dts | 1 - 1 file changed, 1 deletion(-) diff --git a/arch/arm64/boot/dts/altera/socfpga_stratix10_socdk.dts b/arch/arm64/boot/dts/altera/socfpga_stratix10_socdk.dts index 000756429b77..51ce5832ee1d 100644 --- a/arch/arm64/boot/dts/altera/socfpga_stratix10_socdk.dts +++ b/arch/arm64/boot/dts/altera/socfpga_stratix10_socdk.dts @@ -88,7 +88,6 @@ &mmc { status = "okay"; - num-slots = <1>; cap-sd-highspeed; broken-cd; bus-width = <4>; From 09cdb2894a804913f7c2258a05fb3f43f26bd06d Mon Sep 17 00:00:00 2001 From: Jaehoon Chung Date: Fri, 23 Feb 2018 15:41:37 +0900 Subject: [PATCH 37/55] ARM: dts: lpc18xx: remove 'num-slots' property for dwmmc Since 'num-slots' had already deprecated, remove the property in device-tree file. Signed-off-by: Jaehoon Chung Signed-off-by: Ulf Hansson --- arch/arm/boot/dts/lpc18xx.dtsi | 1 - 1 file changed, 1 deletion(-) diff --git a/arch/arm/boot/dts/lpc18xx.dtsi b/arch/arm/boot/dts/lpc18xx.dtsi index 7cae9c5e27db..10b8249b8ab6 100644 --- a/arch/arm/boot/dts/lpc18xx.dtsi +++ b/arch/arm/boot/dts/lpc18xx.dtsi @@ -115,7 +115,6 @@ compatible = "snps,dw-mshc"; reg = <0x40004000 0x1000>; interrupts = <6>; - num-slots = <1>; clocks = <&ccu2 CLK_SDIO>, <&ccu1 CLK_CPU_SDIO>; clock-names = "ciu", "biu"; resets = <&rgu 20>; From 812dd0202379a242f764f75aa30abfbef4398ba4 Mon Sep 17 00:00:00 2001 From: Jaehoon Chung Date: Fri, 23 Feb 2018 15:41:38 +0900 Subject: [PATCH 38/55] arm64: dts: hi3660: remove 'num-slots' property for dwmmc Since 'num-slots' had already deprecated, remove the property in device-tree file. Signed-off-by: Jaehoon Chung Signed-off-by: Ulf Hansson --- arch/arm64/boot/dts/hisilicon/hi3660.dtsi | 2 -- 1 file changed, 2 deletions(-) diff --git a/arch/arm64/boot/dts/hisilicon/hi3660.dtsi b/arch/arm64/boot/dts/hisilicon/hi3660.dtsi index 63d4f9dca77f..a7ecd9074ea2 100644 --- a/arch/arm64/boot/dts/hisilicon/hi3660.dtsi +++ b/arch/arm64/boot/dts/hisilicon/hi3660.dtsi @@ -922,7 +922,6 @@ #size-cells = <0>; cd-inverted; compatible = "hisilicon,hi3660-dw-mshc"; - num-slots = <1>; bus-width = <0x4>; disable-wp; cap-sd-highspeed; @@ -960,7 +959,6 @@ compatible = "hisilicon,hi3660-dw-mshc"; reg = <0x0 0xff3ff000 0x0 0x1000>; interrupts = ; - num-slots = <1>; clocks = <&crg_ctrl HI3660_CLK_GATE_SDIO0>, <&crg_ctrl HI3660_HCLK_GATE_SDIO0>; clock-names = "ciu", "biu"; From d6743a8a1ae38269a41094ad14d7ef86199f661d Mon Sep 17 00:00:00 2001 From: Shawn Lin Date: Tue, 27 Feb 2018 08:49:25 +0800 Subject: [PATCH 39/55] mmc: core: Don't try UHS-I mode if 4-bit mode isn't supported Per SD specification physical layer v4.0, section 3.9.4, it says "UHS-I supports only 4-bit mode. Host shall select 4-bit mode by ACMD6. However mmc_sd_init_uhs_card() still go ahead to initialize the cards anyway, whether card or host won't support 4-bit mode. This breaks the platforms which could support UHS-I mode but on some certain boards only support 1-bit mode with a UHS-I card inserted, as all the tuning process is broken due to this. Alternatively, we should check the return value from mmc_set_bus_width() to see if host could finish the request to switch the bus width on its side. But that needs more thing to do than this patch that just bails out early to try high speed mode if 4-bit mode isn't available for whatever reason. And this patch could also fix the same problem for sdio since R4_18V_PRESENT won't be set for ocr when mmc_sdio_init_card() finds mmc_host_uhs() is false. Note that this patch doesn't keep the checking of card->scr.sda_spec3 and comparing card->scr.bus_widths with SD_SCR_BUS_WIDTH_4 within mmc_sd_init_uhs_card() since if the sd cards response with SD_ROCR_S18A, it definitely supports UHS-I mode, which implicitly means these checkings are always true. Signed-off-by: Shawn Lin Signed-off-by: Ulf Hansson --- drivers/mmc/core/host.h | 3 ++- drivers/mmc/core/sd.c | 16 +++++----------- 2 files changed, 7 insertions(+), 12 deletions(-) diff --git a/drivers/mmc/core/host.h b/drivers/mmc/core/host.h index 06ec19b5bf9f..4805438c02ff 100644 --- a/drivers/mmc/core/host.h +++ b/drivers/mmc/core/host.h @@ -56,7 +56,8 @@ static inline int mmc_host_uhs(struct mmc_host *host) return host->caps & (MMC_CAP_UHS_SDR12 | MMC_CAP_UHS_SDR25 | MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_SDR104 | - MMC_CAP_UHS_DDR50); + MMC_CAP_UHS_DDR50) && + host->caps & MMC_CAP_4_BIT_DATA; } static inline bool mmc_card_hs200(struct mmc_card *card) diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c index 62b84dd8f9fe..d094497480ca 100644 --- a/drivers/mmc/core/sd.c +++ b/drivers/mmc/core/sd.c @@ -582,9 +582,6 @@ static int mmc_sd_init_uhs_card(struct mmc_card *card) int err; u8 *status; - if (!card->scr.sda_spec3) - return 0; - if (!(card->csd.cmdclass & CCC_SWITCH)) return 0; @@ -593,14 +590,11 @@ static int mmc_sd_init_uhs_card(struct mmc_card *card) return -ENOMEM; /* Set 4-bit bus width */ - if ((card->host->caps & MMC_CAP_4_BIT_DATA) && - (card->scr.bus_widths & SD_SCR_BUS_WIDTH_4)) { - err = mmc_app_set_bus_width(card, MMC_BUS_WIDTH_4); - if (err) - goto out; + err = mmc_app_set_bus_width(card, MMC_BUS_WIDTH_4); + if (err) + goto out; - mmc_set_bus_width(card->host, MMC_BUS_WIDTH_4); - } + mmc_set_bus_width(card->host, MMC_BUS_WIDTH_4); /* * Select the bus speed mode depending on host @@ -1033,7 +1027,7 @@ retry: } /* Initialization sequence for UHS-I cards */ - if (rocr & SD_ROCR_S18A) { + if (rocr & SD_ROCR_S18A && mmc_host_uhs(host)) { err = mmc_sd_init_uhs_card(card); if (err) goto free_card; From 1e178270dfcf2b576b0060b382836219dcda83b5 Mon Sep 17 00:00:00 2001 From: Shawn Lin Date: Tue, 27 Feb 2018 09:26:34 +0800 Subject: [PATCH 40/55] mmc: sdio: Check the return value of sdio_enable_4bit_bus Since we could move card->host->caps & MMC_CAP_4_BIT_DATA ahead of mmc_sdio_init_uhs_card, in mmc_host_uhs(). So there we could save this bit to check that. Also, if the process of sdio_enable_4bit_bus goes wrong, we should bails out early. Signed-off-by: Shawn Lin Signed-off-by: Ulf Hansson --- drivers/mmc/core/sdio.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c index cc43687ca241..c599a628a387 100644 --- a/drivers/mmc/core/sdio.c +++ b/drivers/mmc/core/sdio.c @@ -518,11 +518,10 @@ static int mmc_sdio_init_uhs_card(struct mmc_card *card) if (!card->scr.sda_spec3) return 0; - /* - * Switch to wider bus (if supported). - */ - if (card->host->caps & MMC_CAP_4_BIT_DATA) - err = sdio_enable_4bit_bus(card); + /* Switch to wider bus */ + err = sdio_enable_4bit_bus(card); + if (err) + goto out; /* Set the driver strength for the card */ sdio_select_driver_type(card); From 3715ce57f4d26d09fc1813d157286abc5aa319a5 Mon Sep 17 00:00:00 2001 From: Shawn Lin Date: Tue, 27 Feb 2018 09:26:35 +0800 Subject: [PATCH 41/55] mmc: sd: Remove redundant err assignment from mmc_read_switch Variable err would be firstly initialized by the return value of mmc_sd_switch(). Signed-off-by: Shawn Lin Signed-off-by: Ulf Hansson --- drivers/mmc/core/sd.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c index d094497480ca..329e6005d9ad 100644 --- a/drivers/mmc/core/sd.c +++ b/drivers/mmc/core/sd.c @@ -291,8 +291,6 @@ static int mmc_read_switch(struct mmc_card *card) return 0; } - err = -EIO; - status = kmalloc(64, GFP_KERNEL); if (!status) return -ENOMEM; From e988867fd774d00aeaf5d3c332032bf5b97a4147 Mon Sep 17 00:00:00 2001 From: John Keeping Date: Thu, 1 Mar 2018 10:36:25 +0000 Subject: [PATCH 42/55] mmc: dw_mmc-rockchip: correct property names in debug Following up the device tree fixed in commits e78c637127ee ("ARM: dts: rockchip: Fix DWMMC clocks") and ca9eee95a2de ("arm64: dts: rockchip: Fix DWMMC clocks", 2018-02-15), avoid confusion by using the correct property name in the debug output if clocks are not found. Signed-off-by: John Keeping Reviewed-by: Robin Murphy Reviewed-by: Shawn Lin Signed-off-by: Ulf Hansson --- drivers/mmc/host/dw_mmc-rockchip.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/mmc/host/dw_mmc-rockchip.c b/drivers/mmc/host/dw_mmc-rockchip.c index 339295212935..40d7de2eea12 100644 --- a/drivers/mmc/host/dw_mmc-rockchip.c +++ b/drivers/mmc/host/dw_mmc-rockchip.c @@ -282,11 +282,11 @@ static int dw_mci_rk3288_parse_dt(struct dw_mci *host) priv->drv_clk = devm_clk_get(host->dev, "ciu-drive"); if (IS_ERR(priv->drv_clk)) - dev_dbg(host->dev, "ciu_drv not available\n"); + dev_dbg(host->dev, "ciu-drive not available\n"); priv->sample_clk = devm_clk_get(host->dev, "ciu-sample"); if (IS_ERR(priv->sample_clk)) - dev_dbg(host->dev, "ciu_sample not available\n"); + dev_dbg(host->dev, "ciu-sample not available\n"); host->priv = priv; From 97a0c3134f0594389fac704759f83c38ac7d1c17 Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Mon, 5 Mar 2018 11:33:21 +0100 Subject: [PATCH 43/55] mmc: core: Use memdup_user() rather than duplicating its implementation Reuse existing functionality from memdup_user() instead of keeping duplicate source code. This issue was detected by using the Coccinelle software. Signed-off-by: Markus Elfring Signed-off-by: Ulf Hansson --- drivers/mmc/core/block.c | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/drivers/mmc/core/block.c b/drivers/mmc/core/block.c index 20135a5de748..4b09c7380e70 100644 --- a/drivers/mmc/core/block.c +++ b/drivers/mmc/core/block.c @@ -375,22 +375,15 @@ static struct mmc_blk_ioc_data *mmc_blk_ioctl_copy_from_user( return idata; } - idata->buf = kmalloc(idata->buf_bytes, GFP_KERNEL); - if (!idata->buf) { - err = -ENOMEM; + idata->buf = memdup_user((void __user *)(unsigned long) + idata->ic.data_ptr, idata->buf_bytes); + if (IS_ERR(idata->buf)) { + err = PTR_ERR(idata->buf); goto idata_err; } - if (copy_from_user(idata->buf, (void __user *)(unsigned long) - idata->ic.data_ptr, idata->buf_bytes)) { - err = -EFAULT; - goto copy_err; - } - return idata; -copy_err: - kfree(idata->buf); idata_err: kfree(idata); out: From e060d376cc6185dde7e852c028de36614e2201fa Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Mon, 5 Mar 2018 21:48:42 +0100 Subject: [PATCH 44/55] mmc: renesas_sdhi: fix WP detection Commit "mmc: renesas_sdhi: use MMC_CAP2_NO_WRITE_PROTECT instead of TMIO own flag" activated MMC_CAP2_NO_WRITE_PROTECT for Renesas SDHI which incorrectly disabled WP altogether instead of only disabling the internal mechanism. Since the whole WP handling has been reworked, we can simply disable this capability to re-enable WP GPIOs. Signed-off-by: Wolfram Sang Reviewed-by: Masahiro Yamada Signed-off-by: Ulf Hansson --- drivers/mmc/host/renesas_sdhi_internal_dmac.c | 1 - drivers/mmc/host/renesas_sdhi_sys_dmac.c | 3 --- 2 files changed, 4 deletions(-) diff --git a/drivers/mmc/host/renesas_sdhi_internal_dmac.c b/drivers/mmc/host/renesas_sdhi_internal_dmac.c index a04f31fea72f..8e0acd197c43 100644 --- a/drivers/mmc/host/renesas_sdhi_internal_dmac.c +++ b/drivers/mmc/host/renesas_sdhi_internal_dmac.c @@ -75,7 +75,6 @@ static const struct renesas_sdhi_of_data of_rcar_gen3_compatible = { TMIO_MMC_HAVE_CBSY | TMIO_MMC_MIN_RCAR2, .capabilities = MMC_CAP_SD_HIGHSPEED | MMC_CAP_SDIO_IRQ | MMC_CAP_CMD23, - .capabilities2 = MMC_CAP2_NO_WRITE_PROTECT, .bus_shift = 2, .scc_offset = 0x1000, .taps = rcar_gen3_scc_taps, diff --git a/drivers/mmc/host/renesas_sdhi_sys_dmac.c b/drivers/mmc/host/renesas_sdhi_sys_dmac.c index 4bb46c489d71..848e50c1638a 100644 --- a/drivers/mmc/host/renesas_sdhi_sys_dmac.c +++ b/drivers/mmc/host/renesas_sdhi_sys_dmac.c @@ -42,7 +42,6 @@ static const struct renesas_sdhi_of_data of_rz_compatible = { static const struct renesas_sdhi_of_data of_rcar_gen1_compatible = { .tmio_flags = TMIO_MMC_HAS_IDLE_WAIT | TMIO_MMC_CLK_ACTUAL, .capabilities = MMC_CAP_SD_HIGHSPEED | MMC_CAP_SDIO_IRQ, - .capabilities2 = MMC_CAP2_NO_WRITE_PROTECT, }; /* Definitions for sampling clocks */ @@ -62,7 +61,6 @@ static const struct renesas_sdhi_of_data of_rcar_gen2_compatible = { TMIO_MMC_HAVE_CBSY | TMIO_MMC_MIN_RCAR2, .capabilities = MMC_CAP_SD_HIGHSPEED | MMC_CAP_SDIO_IRQ | MMC_CAP_CMD23, - .capabilities2 = MMC_CAP2_NO_WRITE_PROTECT, .dma_buswidth = DMA_SLAVE_BUSWIDTH_4_BYTES, .dma_rx_offset = 0x2000, .scc_offset = 0x0300, @@ -83,7 +81,6 @@ static const struct renesas_sdhi_of_data of_rcar_gen3_compatible = { TMIO_MMC_HAVE_CBSY | TMIO_MMC_MIN_RCAR2, .capabilities = MMC_CAP_SD_HIGHSPEED | MMC_CAP_SDIO_IRQ | MMC_CAP_CMD23, - .capabilities2 = MMC_CAP2_NO_WRITE_PROTECT, .bus_shift = 2, .scc_offset = 0x1000, .taps = rcar_gen3_scc_taps, From 974e85e90c84a32f49b70c6615f1e8f156f38a3c Mon Sep 17 00:00:00 2001 From: Harish Jenny K N Date: Wed, 7 Mar 2018 10:31:42 +0530 Subject: [PATCH 45/55] mmc: core: Export card RCA register via sysfs This patch exports RCA register to sysfs which will help in reading the disk identification information. Reviewed-by: Shawn Lin Signed-off-by: Harish Jenny K N Signed-off-by: Ulf Hansson --- drivers/mmc/core/mmc.c | 2 ++ drivers/mmc/core/sd.c | 2 ++ 2 files changed, 4 insertions(+) diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index 208a762b87ef..6f8ebd6caa4c 100644 --- a/drivers/mmc/core/mmc.c +++ b/drivers/mmc/core/mmc.c @@ -792,6 +792,7 @@ MMC_DEV_ATTR(enhanced_area_size, "%u\n", card->ext_csd.enhanced_area_size); MMC_DEV_ATTR(raw_rpmb_size_mult, "%#x\n", card->ext_csd.raw_rpmb_size_mult); MMC_DEV_ATTR(rel_sectors, "%#x\n", card->ext_csd.rel_sectors); MMC_DEV_ATTR(ocr, "0x%08x\n", card->ocr); +MMC_DEV_ATTR(rca, "0x%04x\n", card->rca); MMC_DEV_ATTR(cmdq_en, "%d\n", card->ext_csd.cmdq_en); static ssize_t mmc_fwrev_show(struct device *dev, @@ -848,6 +849,7 @@ static struct attribute *mmc_std_attrs[] = { &dev_attr_raw_rpmb_size_mult.attr, &dev_attr_rel_sectors.attr, &dev_attr_ocr.attr, + &dev_attr_rca.attr, &dev_attr_dsr.attr, &dev_attr_cmdq_en.attr, NULL, diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c index 329e6005d9ad..baf3d5da4ccb 100644 --- a/drivers/mmc/core/sd.c +++ b/drivers/mmc/core/sd.c @@ -668,6 +668,7 @@ MMC_DEV_ATTR(name, "%s\n", card->cid.prod_name); MMC_DEV_ATTR(oemid, "0x%04x\n", card->cid.oemid); MMC_DEV_ATTR(serial, "0x%08x\n", card->cid.serial); MMC_DEV_ATTR(ocr, "0x%08x\n", card->ocr); +MMC_DEV_ATTR(rca, "0x%04x\n", card->rca); static ssize_t mmc_dsr_show(struct device *dev, @@ -701,6 +702,7 @@ static struct attribute *sd_std_attrs[] = { &dev_attr_oemid.attr, &dev_attr_serial.attr, &dev_attr_ocr.attr, + &dev_attr_rca.attr, &dev_attr_dsr.attr, NULL, }; From 8a9cdf985258d3409e5647fbcb8a573da35ee4f8 Mon Sep 17 00:00:00 2001 From: tianshuliang Date: Thu, 8 Mar 2018 09:01:33 +0800 Subject: [PATCH 46/55] dt-bindings: mmc: add bindings for hi3798cv200-dw-mshc Hisilicon hi3798cv200 SoC extends the dw-mshc controller for additional clock control. Add device tree bindings for hi3798cv200-dw-mshc. Signed-off-by: tianshuliang Signed-off-by: Jiancheng Xue Signed-off-by: Shawn Guo Reviewed-by: Rob Herring Signed-off-by: Ulf Hansson --- .../bindings/mmc/hi3798cv200-dw-mshc.txt | 40 +++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 Documentation/devicetree/bindings/mmc/hi3798cv200-dw-mshc.txt diff --git a/Documentation/devicetree/bindings/mmc/hi3798cv200-dw-mshc.txt b/Documentation/devicetree/bindings/mmc/hi3798cv200-dw-mshc.txt new file mode 100644 index 000000000000..a0693b7145f2 --- /dev/null +++ b/Documentation/devicetree/bindings/mmc/hi3798cv200-dw-mshc.txt @@ -0,0 +1,40 @@ +* Hisilicon Hi3798CV200 specific extensions to the Synopsys Designware Mobile + Storage Host Controller + +Read synopsys-dw-mshc.txt for more details + +The Synopsys designware mobile storage host controller is used to interface +a SoC with storage medium such as eMMC or SD/MMC cards. This file documents +differences between the core Synopsys dw mshc controller properties described +by synopsys-dw-mshc.txt and the properties used by the Hisilicon Hi3798CV200 +specific extensions to the Synopsys Designware Mobile Storage Host Controller. + +Required Properties: +- compatible: Should contain "hisilicon,hi3798cv200-dw-mshc". +- clocks: A list of phandle + clock-specifier pairs for the clocks listed + in clock-names. +- clock-names: Should contain the following: + "ciu" - The ciu clock described in synopsys-dw-mshc.txt. + "biu" - The biu clock described in synopsys-dw-mshc.txt. + "ciu-sample" - Hi3798CV200 extended phase clock for ciu sampling. + "ciu-drive" - Hi3798CV200 extended phase clock for ciu driving. + +Example: + + emmc: mmc@9830000 { + compatible = "hisilicon,hi3798cv200-dw-mshc"; + reg = <0x9830000 0x10000>; + interrupts = ; + clocks = <&crg HISTB_MMC_CIU_CLK>, + <&crg HISTB_MMC_BIU_CLK>, + <&crg HISTB_MMC_SAMPLE_CLK>, + <&crg HISTB_MMC_DRV_CLK>; + clock-names = "ciu", "biu", "ciu-sample", "ciu-drive"; + fifo-depth = <256>; + clock-frequency = <200000000>; + cap-mmc-highspeed; + mmc-ddr-1_8v; + mmc-hs200-1_8v; + non-removable; + bus-width = <8>; + }; From e382ab741252471383e9990583258e3054f66963 Mon Sep 17 00:00:00 2001 From: tianshuliang Date: Thu, 8 Mar 2018 09:01:34 +0800 Subject: [PATCH 47/55] mmc: dw_mmc: add support for hi3798cv200 specific extensions of dw-mshc Hi3798CV200 SoC extends the dw-mshc controller for additional clock and bus control. Add support for these extensions. Signed-off-by: tianshuliang Signed-off-by: Jiancheng Xue Signed-off-by: Shawn Guo Reviewed-by: Shawn Lin Signed-off-by: Ulf Hansson --- drivers/mmc/host/Kconfig | 9 ++ drivers/mmc/host/Makefile | 1 + drivers/mmc/host/dw_mmc-hi3798cv200.c | 202 ++++++++++++++++++++++++++ drivers/mmc/host/dw_mmc.h | 6 + 4 files changed, 218 insertions(+) create mode 100644 drivers/mmc/host/dw_mmc-hi3798cv200.c diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig index 620c2d90a646..de36fffe8225 100644 --- a/drivers/mmc/host/Kconfig +++ b/drivers/mmc/host/Kconfig @@ -718,6 +718,15 @@ config MMC_DW_EXYNOS Synopsys DesignWare Memory Card Interface driver. Select this option for platforms based on Exynos4 and Exynos5 SoC's. +config MMC_DW_HI3798CV200 + tristate "Hi3798CV200 specific extensions for Synopsys DW Memory Card Interface" + depends on MMC_DW + select MMC_DW_PLTFM + help + This selects support for HiSilicon Hi3798CV200 SoC specific extensions to the + Synopsys DesignWare Memory Card Interface driver. Select this option + for platforms based on HiSilicon Hi3798CV200 SoC. + config MMC_DW_K3 tristate "K3 specific extensions for Synopsys DW Memory Card Interface" depends on MMC_DW diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile index 84cd1388abc3..00ec9a2f59be 100644 --- a/drivers/mmc/host/Makefile +++ b/drivers/mmc/host/Makefile @@ -51,6 +51,7 @@ obj-$(CONFIG_MMC_CAVIUM_THUNDERX) += thunderx-mmc.o obj-$(CONFIG_MMC_DW) += dw_mmc.o obj-$(CONFIG_MMC_DW_PLTFM) += dw_mmc-pltfm.o obj-$(CONFIG_MMC_DW_EXYNOS) += dw_mmc-exynos.o +obj-$(CONFIG_MMC_DW_HI3798CV200) += dw_mmc-hi3798cv200.o obj-$(CONFIG_MMC_DW_K3) += dw_mmc-k3.o obj-$(CONFIG_MMC_DW_PCI) += dw_mmc-pci.o obj-$(CONFIG_MMC_DW_ROCKCHIP) += dw_mmc-rockchip.o diff --git a/drivers/mmc/host/dw_mmc-hi3798cv200.c b/drivers/mmc/host/dw_mmc-hi3798cv200.c new file mode 100644 index 000000000000..f9b333ff259e --- /dev/null +++ b/drivers/mmc/host/dw_mmc-hi3798cv200.c @@ -0,0 +1,202 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2018 HiSilicon Technologies Co., Ltd. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "dw_mmc.h" +#include "dw_mmc-pltfm.h" + +#define ALL_INT_CLR 0x1ffff + +struct hi3798cv200_priv { + struct clk *sample_clk; + struct clk *drive_clk; +}; + +static void dw_mci_hi3798cv200_set_ios(struct dw_mci *host, struct mmc_ios *ios) +{ + struct hi3798cv200_priv *priv = host->priv; + u32 val; + + val = mci_readl(host, UHS_REG); + if (ios->timing == MMC_TIMING_MMC_DDR52 || + ios->timing == MMC_TIMING_UHS_DDR50) + val |= SDMMC_UHS_DDR; + else + val &= ~SDMMC_UHS_DDR; + mci_writel(host, UHS_REG, val); + + val = mci_readl(host, ENABLE_SHIFT); + if (ios->timing == MMC_TIMING_MMC_DDR52) + val |= SDMMC_ENABLE_PHASE; + else + val &= ~SDMMC_ENABLE_PHASE; + mci_writel(host, ENABLE_SHIFT, val); + + val = mci_readl(host, DDR_REG); + if (ios->timing == MMC_TIMING_MMC_HS400) + val |= SDMMC_DDR_HS400; + else + val &= ~SDMMC_DDR_HS400; + mci_writel(host, DDR_REG, val); + + if (ios->timing == MMC_TIMING_MMC_HS || + ios->timing == MMC_TIMING_LEGACY) + clk_set_phase(priv->drive_clk, 180); + else if (ios->timing == MMC_TIMING_MMC_HS200) + clk_set_phase(priv->drive_clk, 135); +} + +static int dw_mci_hi3798cv200_execute_tuning(struct dw_mci_slot *slot, + u32 opcode) +{ + int degrees[] = { 0, 45, 90, 135, 180, 225, 270, 315 }; + struct dw_mci *host = slot->host; + struct hi3798cv200_priv *priv = host->priv; + int raise_point = -1, fall_point = -1; + int err, prev_err = -1; + int found = 0; + int i; + + for (i = 0; i < ARRAY_SIZE(degrees); i++) { + clk_set_phase(priv->sample_clk, degrees[i]); + mci_writel(host, RINTSTS, ALL_INT_CLR); + + err = mmc_send_tuning(slot->mmc, opcode, NULL); + if (!err) + found = 1; + + if (i > 0) { + if (err && !prev_err) + fall_point = i - 1; + if (!err && prev_err) + raise_point = i; + } + + if (raise_point != -1 && fall_point != -1) + goto tuning_out; + + prev_err = err; + err = 0; + } + +tuning_out: + if (found) { + if (raise_point == -1) + raise_point = 0; + if (fall_point == -1) + fall_point = ARRAY_SIZE(degrees) - 1; + if (fall_point < raise_point) { + if ((raise_point + fall_point) > + (ARRAY_SIZE(degrees) - 1)) + i = fall_point / 2; + else + i = (raise_point + ARRAY_SIZE(degrees) - 1) / 2; + } else { + i = (raise_point + fall_point) / 2; + } + + clk_set_phase(priv->sample_clk, degrees[i]); + dev_dbg(host->dev, "Tuning clk_sample[%d, %d], set[%d]\n", + raise_point, fall_point, degrees[i]); + } else { + dev_err(host->dev, "No valid clk_sample shift! use default\n"); + err = -EINVAL; + } + + mci_writel(host, RINTSTS, ALL_INT_CLR); + return err; +} + +static int dw_mci_hi3798cv200_init(struct dw_mci *host) +{ + struct hi3798cv200_priv *priv; + int ret; + + priv = devm_kzalloc(host->dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->sample_clk = devm_clk_get(host->dev, "ciu-sample"); + if (IS_ERR(priv->sample_clk)) { + dev_err(host->dev, "failed to get ciu-sample clock\n"); + return PTR_ERR(priv->sample_clk); + } + + priv->drive_clk = devm_clk_get(host->dev, "ciu-drive"); + if (IS_ERR(priv->drive_clk)) { + dev_err(host->dev, "failed to get ciu-drive clock\n"); + return PTR_ERR(priv->drive_clk); + } + + ret = clk_prepare_enable(priv->sample_clk); + if (ret) { + dev_err(host->dev, "failed to enable ciu-sample clock\n"); + return ret; + } + + ret = clk_prepare_enable(priv->drive_clk); + if (ret) { + dev_err(host->dev, "failed to enable ciu-drive clock\n"); + goto disable_sample_clk; + } + + host->priv = priv; + return 0; + +disable_sample_clk: + clk_disable_unprepare(priv->sample_clk); + return ret; +} + +static const struct dw_mci_drv_data hi3798cv200_data = { + .init = dw_mci_hi3798cv200_init, + .set_ios = dw_mci_hi3798cv200_set_ios, + .execute_tuning = dw_mci_hi3798cv200_execute_tuning, +}; + +static int dw_mci_hi3798cv200_probe(struct platform_device *pdev) +{ + return dw_mci_pltfm_register(pdev, &hi3798cv200_data); +} + +static int dw_mci_hi3798cv200_remove(struct platform_device *pdev) +{ + struct dw_mci *host = platform_get_drvdata(pdev); + struct hi3798cv200_priv *priv = host->priv; + + clk_disable_unprepare(priv->drive_clk); + clk_disable_unprepare(priv->sample_clk); + + return dw_mci_pltfm_remove(pdev); +} + +static const struct of_device_id dw_mci_hi3798cv200_match[] = { + { .compatible = "hisilicon,hi3798cv200-dw-mshc", }, + {}, +}; + +MODULE_DEVICE_TABLE(of, dw_mci_hi3798cv200_match); +static struct platform_driver dw_mci_hi3798cv200_driver = { + .probe = dw_mci_hi3798cv200_probe, + .remove = dw_mci_hi3798cv200_remove, + .driver = { + .name = "dwmmc_hi3798cv200", + .of_match_table = dw_mci_hi3798cv200_match, + }, +}; +module_platform_driver(dw_mci_hi3798cv200_driver); + +MODULE_DESCRIPTION("HiSilicon Hi3798CV200 Specific DW-MSHC Driver Extension"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:dwmmc_hi3798cv200"); diff --git a/drivers/mmc/host/dw_mmc.h b/drivers/mmc/host/dw_mmc.h index 950f194e1573..46e9f8ec5398 100644 --- a/drivers/mmc/host/dw_mmc.h +++ b/drivers/mmc/host/dw_mmc.h @@ -314,6 +314,7 @@ struct dw_mci_board { #define SDMMC_BUFADDR 0x098 #define SDMMC_CDTHRCTL 0x100 #define SDMMC_UHS_REG_EXT 0x108 +#define SDMMC_DDR_REG 0x10c #define SDMMC_ENABLE_SHIFT 0x110 #define SDMMC_DATA(x) (x) /* @@ -439,7 +440,12 @@ struct dw_mci_board { #define SDMMC_CARD_WR_THR_EN BIT(2) #define SDMMC_CARD_RD_THR_EN BIT(0) /* UHS-1 register defines */ +#define SDMMC_UHS_DDR BIT(16) #define SDMMC_UHS_18V BIT(0) +/* DDR register defines */ +#define SDMMC_DDR_HS400 BIT(31) +/* Enable shift register defines */ +#define SDMMC_ENABLE_PHASE BIT(0) /* All ctrl reset bits */ #define SDMMC_CTRL_ALL_RESET_FLAGS \ (SDMMC_CTRL_RESET | SDMMC_CTRL_FIFO_RESET | SDMMC_CTRL_DMA_RESET) From 774c010350a16f44705971e8aff457580628c76e Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Thu, 8 Mar 2018 15:52:51 +0100 Subject: [PATCH 48/55] mmc: sunxi: Move resources management to separate functions We've had all our resources management, and especially the clocks and reset sequence, done directly as part of the probe. As we want to implement runtime_pm, we'll obviously want to have that moved outside of the probe so that we can call do it in our runtime suspend and resume hooks without too much duplication. Signed-off-by: Maxime Ripard Signed-off-by: Ulf Hansson --- drivers/mmc/host/sunxi-mmc.c | 142 ++++++++++++++++++++--------------- 1 file changed, 82 insertions(+), 60 deletions(-) diff --git a/drivers/mmc/host/sunxi-mmc.c b/drivers/mmc/host/sunxi-mmc.c index bad612d6f879..3601746d37a9 100644 --- a/drivers/mmc/host/sunxi-mmc.c +++ b/drivers/mmc/host/sunxi-mmc.c @@ -268,6 +268,7 @@ struct sunxi_mmc_cfg { }; struct sunxi_mmc_host { + struct device *dev; struct mmc_host *mmc; struct reset_control *reset; const struct sunxi_mmc_cfg *cfg; @@ -1165,6 +1166,80 @@ static const struct of_device_id sunxi_mmc_of_match[] = { }; MODULE_DEVICE_TABLE(of, sunxi_mmc_of_match); +static int sunxi_mmc_enable(struct sunxi_mmc_host *host) +{ + int ret; + + ret = clk_prepare_enable(host->clk_ahb); + if (ret) { + dev_err(dev, "Couldn't enable the bus clocks (%d)\n", ret); + return ret; + } + + ret = clk_prepare_enable(host->clk_mmc); + if (ret) { + dev_err(host->dev, "Enable mmc clk err %d\n", ret); + goto error_disable_clk_ahb; + } + + ret = clk_prepare_enable(host->clk_output); + if (ret) { + dev_err(host->dev, "Enable output clk err %d\n", ret); + goto error_disable_clk_mmc; + } + + ret = clk_prepare_enable(host->clk_sample); + if (ret) { + dev_err(host->dev, "Enable sample clk err %d\n", ret); + goto error_disable_clk_output; + } + + if (!IS_ERR(host->reset)) { + ret = reset_control_reset(host->reset); + if (ret) { + dev_err(dev, "Couldn't reset the MMC controller (%d)\n", + ret); + goto error_disable_clk_sample; + } + } + + /* + * Sometimes the controller asserts the irq on boot for some reason, + * make sure the controller is in a sane state before enabling irqs. + */ + ret = sunxi_mmc_reset_host(host); + if (ret) + goto error_assert_reset; + + return 0; + +error_assert_reset: + if (!IS_ERR(host->reset)) + reset_control_assert(host->reset); +error_disable_clk_sample: + clk_disable_unprepare(host->clk_sample); +error_disable_clk_output: + clk_disable_unprepare(host->clk_output); +error_disable_clk_mmc: + clk_disable_unprepare(host->clk_mmc); +error_disable_clk_ahb: + clk_disable_unprepare(host->clk_ahb); + return ret; +} + +static void sunxi_mmc_disable(struct sunxi_mmc_host *host) +{ + sunxi_mmc_reset_host(host); + + if (!IS_ERR(host->reset)) + reset_control_assert(host->reset); + + clk_disable_unprepare(host->clk_sample); + clk_disable_unprepare(host->clk_output); + clk_disable_unprepare(host->clk_mmc); + clk_disable_unprepare(host->clk_ahb); +} + static int sunxi_mmc_resource_request(struct sunxi_mmc_host *host, struct platform_device *pdev) { @@ -1214,66 +1289,21 @@ static int sunxi_mmc_resource_request(struct sunxi_mmc_host *host, if (PTR_ERR(host->reset) == -EPROBE_DEFER) return PTR_ERR(host->reset); - ret = clk_prepare_enable(host->clk_ahb); - if (ret) { - dev_err(&pdev->dev, "Enable ahb clk err %d\n", ret); - return ret; - } - - ret = clk_prepare_enable(host->clk_mmc); - if (ret) { - dev_err(&pdev->dev, "Enable mmc clk err %d\n", ret); - goto error_disable_clk_ahb; - } - - ret = clk_prepare_enable(host->clk_output); - if (ret) { - dev_err(&pdev->dev, "Enable output clk err %d\n", ret); - goto error_disable_clk_mmc; - } - - ret = clk_prepare_enable(host->clk_sample); - if (ret) { - dev_err(&pdev->dev, "Enable sample clk err %d\n", ret); - goto error_disable_clk_output; - } - - if (!IS_ERR(host->reset)) { - ret = reset_control_reset(host->reset); - if (ret) { - dev_err(&pdev->dev, "reset err %d\n", ret); - goto error_disable_clk_sample; - } - } - - /* - * Sometimes the controller asserts the irq on boot for some reason, - * make sure the controller is in a sane state before enabling irqs. - */ - ret = sunxi_mmc_reset_host(host); + ret = sunxi_mmc_enable(host); if (ret) - goto error_assert_reset; + return ret; host->irq = platform_get_irq(pdev, 0); if (host->irq <= 0) { ret = -EINVAL; - goto error_assert_reset; + goto error_disable_mmc; } return devm_request_threaded_irq(&pdev->dev, host->irq, sunxi_mmc_irq, sunxi_mmc_handle_manual_stop, 0, "sunxi-mmc", host); -error_assert_reset: - if (!IS_ERR(host->reset)) - reset_control_assert(host->reset); -error_disable_clk_sample: - clk_disable_unprepare(host->clk_sample); -error_disable_clk_output: - clk_disable_unprepare(host->clk_output); -error_disable_clk_mmc: - clk_disable_unprepare(host->clk_mmc); -error_disable_clk_ahb: - clk_disable_unprepare(host->clk_ahb); +error_disable_mmc: + sunxi_mmc_disable(host); return ret; } @@ -1290,6 +1320,7 @@ static int sunxi_mmc_probe(struct platform_device *pdev) } host = mmc_priv(mmc); + host->dev = &pdev->dev; host->mmc = mmc; spin_lock_init(&host->lock); @@ -1370,16 +1401,7 @@ static int sunxi_mmc_remove(struct platform_device *pdev) mmc_remove_host(mmc); disable_irq(host->irq); - sunxi_mmc_reset_host(host); - - if (!IS_ERR(host->reset)) - reset_control_assert(host->reset); - - clk_disable_unprepare(host->clk_sample); - clk_disable_unprepare(host->clk_output); - clk_disable_unprepare(host->clk_mmc); - clk_disable_unprepare(host->clk_ahb); - + sunxi_mmc_disable(host); dma_free_coherent(&pdev->dev, PAGE_SIZE, host->sg_cpu, host->sg_dma); mmc_free_host(mmc); From d81819419b2be4eee6643681ce0366856a772ba9 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Thu, 8 Mar 2018 15:52:52 +0100 Subject: [PATCH 49/55] mmc: sunxi: Move the reset deassertion before enabling the clocks As per Allwinner guidelines, the reset line should be deasserted before turning the clocks on. Implement it in our driver as well. Signed-off-by: Maxime Ripard Signed-off-by: Ulf Hansson --- drivers/mmc/host/sunxi-mmc.c | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/drivers/mmc/host/sunxi-mmc.c b/drivers/mmc/host/sunxi-mmc.c index 3601746d37a9..b747d65a7d15 100644 --- a/drivers/mmc/host/sunxi-mmc.c +++ b/drivers/mmc/host/sunxi-mmc.c @@ -1170,10 +1170,19 @@ static int sunxi_mmc_enable(struct sunxi_mmc_host *host) { int ret; + if (!IS_ERR(host->reset)) { + ret = reset_control_reset(host->reset); + if (ret) { + dev_err(host->dev, "Couldn't reset the MMC controller (%d)\n", + ret); + return ret; + } + } + ret = clk_prepare_enable(host->clk_ahb); if (ret) { - dev_err(dev, "Couldn't enable the bus clocks (%d)\n", ret); - return ret; + dev_err(host->dev, "Couldn't enable the bus clocks (%d)\n", ret); + goto error_assert_reset; } ret = clk_prepare_enable(host->clk_mmc); @@ -1194,28 +1203,16 @@ static int sunxi_mmc_enable(struct sunxi_mmc_host *host) goto error_disable_clk_output; } - if (!IS_ERR(host->reset)) { - ret = reset_control_reset(host->reset); - if (ret) { - dev_err(dev, "Couldn't reset the MMC controller (%d)\n", - ret); - goto error_disable_clk_sample; - } - } - /* * Sometimes the controller asserts the irq on boot for some reason, * make sure the controller is in a sane state before enabling irqs. */ ret = sunxi_mmc_reset_host(host); if (ret) - goto error_assert_reset; + goto error_disable_clk_sample; return 0; -error_assert_reset: - if (!IS_ERR(host->reset)) - reset_control_assert(host->reset); error_disable_clk_sample: clk_disable_unprepare(host->clk_sample); error_disable_clk_output: @@ -1224,6 +1221,9 @@ error_disable_clk_mmc: clk_disable_unprepare(host->clk_mmc); error_disable_clk_ahb: clk_disable_unprepare(host->clk_ahb); +error_assert_reset: + if (!IS_ERR(host->reset)) + reset_control_assert(host->reset); return ret; } @@ -1231,13 +1231,13 @@ static void sunxi_mmc_disable(struct sunxi_mmc_host *host) { sunxi_mmc_reset_host(host); - if (!IS_ERR(host->reset)) - reset_control_assert(host->reset); - clk_disable_unprepare(host->clk_sample); clk_disable_unprepare(host->clk_output); clk_disable_unprepare(host->clk_mmc); clk_disable_unprepare(host->clk_ahb); + + if (!IS_ERR(host->reset)) + reset_control_assert(host->reset); } static int sunxi_mmc_resource_request(struct sunxi_mmc_host *host, From cb1214d27a3ef8817a7a208d546aa9f947bf5f7d Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Thu, 8 Mar 2018 15:52:53 +0100 Subject: [PATCH 50/55] mmc: sunxi: Set our device drvdata earlier As soon as the pm_runtime_enable hook is called, our runtime_suspend and runtime_resume hooks can be called as well. However, we only set the device drvdata that we will use after we have registered into the MMC core. Move that earlier so that we don't have a race that could lead to a crash. Signed-off-by: Maxime Ripard Signed-off-by: Ulf Hansson --- drivers/mmc/host/sunxi-mmc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mmc/host/sunxi-mmc.c b/drivers/mmc/host/sunxi-mmc.c index b747d65a7d15..20cfb20418f3 100644 --- a/drivers/mmc/host/sunxi-mmc.c +++ b/drivers/mmc/host/sunxi-mmc.c @@ -1318,6 +1318,7 @@ static int sunxi_mmc_probe(struct platform_device *pdev) dev_err(&pdev->dev, "mmc alloc host failed\n"); return -ENOMEM; } + platform_set_drvdata(pdev, mmc); host = mmc_priv(mmc); host->dev = &pdev->dev; @@ -1384,7 +1385,6 @@ static int sunxi_mmc_probe(struct platform_device *pdev) goto error_free_dma; dev_info(&pdev->dev, "base:0x%p irq:%u\n", host->reg_base, host->irq); - platform_set_drvdata(pdev, mmc); return 0; error_free_dma: From a0e9576634f0bcfa5c4d8efdcf8c9b28298d7570 Mon Sep 17 00:00:00 2001 From: Bastian Stender Date: Thu, 8 Mar 2018 15:08:11 +0100 Subject: [PATCH 51/55] mmc: block: fix updating ext_csd caches on ioctl call PARTITION_CONFIG is cached in mmc_card->ext_csd.part_config and the currently active partition in mmc_blk_data->part_curr. These caches do not always reflect changes if the ioctl call modifies the PARTITION_CONFIG registers, e.g. by changing BOOT_PARTITION_ENABLE. Write the PARTITION_CONFIG value extracted from the ioctl call to the cache and update the currently active partition accordingly. This ensures that the user space cannot change the values behind the kernel's back. The next call to mmc_blk_part_switch() will operate on the data set by the ioctl and reflect the changes appropriately. Signed-off-by: Bastian Stender Signed-off-by: Jan Luebbe Cc: stable@vger.kernel.org Signed-off-by: Ulf Hansson --- drivers/mmc/core/block.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/drivers/mmc/core/block.c b/drivers/mmc/core/block.c index 4b09c7380e70..a2b9c2500c4c 100644 --- a/drivers/mmc/core/block.c +++ b/drivers/mmc/core/block.c @@ -72,6 +72,7 @@ MODULE_ALIAS("mmc:block"); #define MMC_BLK_TIMEOUT_MS (10 * 1000) #define MMC_SANITIZE_REQ_TIMEOUT 240000 #define MMC_EXTRACT_INDEX_FROM_ARG(x) ((x & 0x00FF0000) >> 16) +#define MMC_EXTRACT_VALUE_FROM_ARG(x) ((x & 0x0000FF00) >> 8) #define mmc_req_rel_wr(req) ((req->cmd_flags & REQ_FUA) && \ (rq_data_dir(req) == WRITE)) @@ -579,6 +580,24 @@ static int __mmc_blk_ioctl_cmd(struct mmc_card *card, struct mmc_blk_data *md, return data.error; } + /* + * Make sure the cache of the PARTITION_CONFIG register and + * PARTITION_ACCESS bits is updated in case the ioctl ext_csd write + * changed it successfully. + */ + if ((MMC_EXTRACT_INDEX_FROM_ARG(cmd.arg) == EXT_CSD_PART_CONFIG) && + (cmd.opcode == MMC_SWITCH)) { + struct mmc_blk_data *main_md = dev_get_drvdata(&card->dev); + u8 value = MMC_EXTRACT_VALUE_FROM_ARG(cmd.arg); + + /* + * Update cache so the next mmc_blk_part_switch call operates + * on up-to-date data. + */ + card->ext_csd.part_config = value; + main_md->part_curr = value & EXT_CSD_PART_CONFIG_ACC_MASK; + } + /* * According to the SD specs, some commands require a delay after * issuing the command. From 8ef0797a898b166016d486d6f30ce6044f800ddb Mon Sep 17 00:00:00 2001 From: Dirk Behme Date: Wed, 14 Mar 2018 14:50:09 +0000 Subject: [PATCH 52/55] mmc: core: Disable HPI for certain Micron (Numonyx) eMMC cards Certain Micron eMMC v4.5 cards might get broken when HPI feature is used and hence this patch disables the HPI feature for such buggy cards. In U-Boot, these cards are reported as Manufacturer: Micron (ID: 0xFE) OEM: 0x4E Name: MMC32G Revision: 19 (0x13) Serial: 959241022 Manufact. date: 8/2015 (0x82) CRC: 0x00 Tran Speed: 52000000 Rd Block Len: 512 MMC version 4.5 High Capacity: Yes Capacity: 29.1 GiB Boot Partition Size: 16 MiB Bus Width: 8-bit According to JEDEC JEP106 manufacturer 0xFE is Numonyx, which was bought by Micron. Signed-off-by: Dirk Behme Signed-off-by: Mark Craske Cc: # 4.8+ Signed-off-by: Ulf Hansson --- drivers/mmc/core/card.h | 1 + drivers/mmc/core/quirks.h | 6 ++++++ 2 files changed, 7 insertions(+) diff --git a/drivers/mmc/core/card.h b/drivers/mmc/core/card.h index 79a5b985ccf5..9c821eedd156 100644 --- a/drivers/mmc/core/card.h +++ b/drivers/mmc/core/card.h @@ -82,6 +82,7 @@ struct mmc_fixup { #define CID_MANFID_APACER 0x27 #define CID_MANFID_KINGSTON 0x70 #define CID_MANFID_HYNIX 0x90 +#define CID_MANFID_NUMONYX 0xFE #define END_FIXUP { NULL } diff --git a/drivers/mmc/core/quirks.h b/drivers/mmc/core/quirks.h index 75d317623852..5153577754f0 100644 --- a/drivers/mmc/core/quirks.h +++ b/drivers/mmc/core/quirks.h @@ -109,6 +109,12 @@ static const struct mmc_fixup mmc_ext_csd_fixups[] = { */ MMC_FIXUP_EXT_CSD_REV(CID_NAME_ANY, CID_MANFID_HYNIX, 0x014a, add_quirk, MMC_QUIRK_BROKEN_HPI, 5), + /* + * Certain Micron (Numonyx) eMMC 4.5 cards might get broken when HPI + * feature is used so disable the HPI feature for such buggy cards. + */ + MMC_FIXUP_EXT_CSD_REV(CID_NAME_ANY, CID_MANFID_NUMONYX, + 0x014e, add_quirk, MMC_QUIRK_BROKEN_HPI, 6), END_FIXUP }; From 9c5c685e58bab9a7f985c71b18302953d1c90b27 Mon Sep 17 00:00:00 2001 From: Abbas Raza Date: Mon, 5 Mar 2018 19:09:19 +0530 Subject: [PATCH 53/55] mmc: Export host capabilities to debugfs. This patch exports the host capabilities to debugfs Signed-off-by: Abbas Raza Signed-off-by: Andrew Gabbasov [Harish: Added caps2, moved creation to mmc_add_host_debugfs] Signed-off-by: Harish Jenny K N Reviewed-by: Shawn Lin Signed-off-by: Ulf Hansson --- drivers/mmc/core/debugfs.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/mmc/core/debugfs.c b/drivers/mmc/core/debugfs.c index c51e0c044a3e..d2275c5a2311 100644 --- a/drivers/mmc/core/debugfs.c +++ b/drivers/mmc/core/debugfs.c @@ -243,6 +243,12 @@ void mmc_add_host_debugfs(struct mmc_host *host) if (!debugfs_create_file("ios", S_IRUSR, root, host, &mmc_ios_fops)) goto err_node; + if (!debugfs_create_x32("caps", S_IRUSR, root, &host->caps)) + goto err_node; + + if (!debugfs_create_x32("caps2", S_IRUSR, root, &host->caps2)) + goto err_node; + if (!debugfs_create_file("clock", S_IRUSR | S_IWUSR, root, host, &mmc_clock_fops)) goto err_node; From 8647d26eb3f19ab0fa29f68a8bf648054c21e4bc Mon Sep 17 00:00:00 2001 From: Joel Cunningham Date: Mon, 19 Mar 2018 14:15:38 +0000 Subject: [PATCH 54/55] mmc: update sdio_claim_irq documentation Update documentation for sdio_claim_irq to downgrade the wording about doing recursive claims in an IRQ handler from 'must not' to 'should not'. This clarifies that recursive claims are supported, but not the recommended (best) practice Signed-off-by: Joel Cunningham Signed-off-by: Ulf Hansson --- drivers/mmc/core/sdio_irq.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/mmc/core/sdio_irq.c b/drivers/mmc/core/sdio_irq.c index 7a2eaf8410a3..7ca7b99413f0 100644 --- a/drivers/mmc/core/sdio_irq.c +++ b/drivers/mmc/core/sdio_irq.c @@ -277,8 +277,8 @@ static void sdio_single_irq_set(struct mmc_card *card) * * Claim and activate the IRQ for the given SDIO function. The provided * handler will be called when that IRQ is asserted. The host is always - * claimed already when the handler is called so the handler must not - * call sdio_claim_host() nor sdio_release_host(). + * claimed already when the handler is called so the handler should not + * call sdio_claim_host() or sdio_release_host(). */ int sdio_claim_irq(struct sdio_func *func, sdio_irq_handler_t *handler) { From 4472f0fc248e3f0573301f725eff9dc9cde5cb62 Mon Sep 17 00:00:00 2001 From: Masaharu Hayakawa Date: Tue, 20 Mar 2018 22:42:58 +0100 Subject: [PATCH 55/55] mmc: renesas_sdhi: replace EXT_ACC with HOST_MODE All our documentation says HOST_MODE, we don't really know where EXT_ACC came from. Rename it to reduce the confusion. Signed-off-by: Masaharu Hayakawa Signed-off-by: Wolfram Sang Signed-off-by: Ulf Hansson --- drivers/mmc/host/renesas_sdhi_core.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/mmc/host/renesas_sdhi_core.c b/drivers/mmc/host/renesas_sdhi_core.c index 80943fa07db6..51e01f03fb99 100644 --- a/drivers/mmc/host/renesas_sdhi_core.c +++ b/drivers/mmc/host/renesas_sdhi_core.c @@ -38,7 +38,7 @@ #include "renesas_sdhi.h" #include "tmio_mmc.h" -#define EXT_ACC 0xe4 +#define HOST_MODE 0xe4 #define SDHI_VER_GEN2_SDR50 0x490c #define SDHI_VER_RZ_A1 0x820b @@ -76,7 +76,7 @@ static void renesas_sdhi_sdbuf_width(struct tmio_mmc_host *host, int width) return; } - sd_ctrl_write16(host, EXT_ACC, val); + sd_ctrl_write16(host, HOST_MODE, val); } static int renesas_sdhi_clk_enable(struct tmio_mmc_host *host) @@ -417,7 +417,7 @@ static int renesas_sdhi_write16_hook(struct tmio_mmc_host *host, int addr) case CTL_SD_MEM_CARD_OPT: case CTL_TRANSACTION_CTL: case CTL_DMA_ENABLE: - case EXT_ACC: + case HOST_MODE: if (host->pdata->flags & TMIO_MMC_HAVE_CBSY) bit = TMIO_STAT_CMD_BUSY; /* fallthrough */