]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
mmc: sdhci-of-dwcmshc: Fix reset, clk, and SDIO support for Eswin EIC7700
authorHuan He <hehuan1@eswincomputing.com>
Sat, 9 May 2026 08:49:07 +0000 (16:49 +0800)
committerUlf Hansson <ulfh@kernel.org>
Fri, 29 May 2026 12:13:58 +0000 (14:13 +0200)
The EIC7700 code in sdhci-of-dwcmshc uses host->mmc->caps2 to select
different configuration paths for different card types. The current logic
distinguishes eMMC and SD, but does not handle SDIO separately.

Update the EIC7700 card-type checks so that eMMC, SD and SDIO are
distinguished explicitly.

Switch the reset path to dwcmshc_reset() so that pending interrupt state
is cleared consistently, and use sdhci_enable_clk() so the clock enable
sequence follows the standard SDHCI flow.

Fixes: 32b2633219d3 ("mmc: sdhci-of-dwcmshc: Add support for Eswin EIC7700")
Signed-off-by: Huan He <hehuan1@eswincomputing.com>
Acked-by: Adrian Hunter <adrian.hunter@intel.com>
Cc: stable@vger.kernel.org
Signed-off-by: Ulf Hansson <ulfh@kernel.org>
drivers/mmc/host/sdhci-of-dwcmshc.c

index 0b2158a7e40909aa95e8a2b03b65e9c5ef007a7b..b9ecd91f44ad4a6ef4c7868f9385468028ccd1d8 100644 (file)
 #define PHY_DELAY_CODE_MAX             0x7f
 #define PHY_DELAY_CODE_EMMC            0x17
 #define PHY_DELAY_CODE_SD              0x55
+#define PHY_DELAY_CODE_SDIO            0x29
 
 struct rk35xx_priv {
        struct reset_control *reset;
@@ -1433,10 +1434,7 @@ static void sdhci_eic7700_set_clock(struct sdhci_host *host, unsigned int clock)
        clk_set_rate(pltfm_host->clk, clock);
 
        clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL);
-       clk |= SDHCI_CLOCK_INT_EN;
-       sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
-
-       dwcmshc_enable_card_clk(host);
+       sdhci_enable_clk(host, clk);
 }
 
 static void sdhci_eic7700_config_phy_delay(struct sdhci_host *host, int delay)
@@ -1497,7 +1495,7 @@ static void sdhci_eic7700_config_phy(struct sdhci_host *host)
 
 static void sdhci_eic7700_reset(struct sdhci_host *host, u8 mask)
 {
-       sdhci_reset(host, mask);
+       dwcmshc_reset(host, mask);
 
        /* after reset all, the phy's config will be clear */
        if (mask == SDHCI_RESET_ALL)
@@ -1594,18 +1592,17 @@ static int sdhci_eic7700_phase_code_tuning(struct sdhci_host *host, u32 opcode)
 {
        struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
        struct dwcmshc_priv *priv = sdhci_pltfm_priv(pltfm_host);
-       u32 sd_caps = MMC_CAP2_NO_MMC | MMC_CAP2_NO_SDIO;
+       u32 emmc_caps = MMC_CAP2_NO_SD | MMC_CAP2_NO_SDIO;
        int phase_code = -1;
        int code_range = -1;
-       bool is_sd = false;
        int code_min = -1;
        int code_max = -1;
        int cmd_error = 0;
+       bool is_emmc;
        int ret = 0;
        int i = 0;
 
-       if ((host->mmc->caps2 & sd_caps) == sd_caps)
-               is_sd = true;
+       is_emmc = (host->mmc->caps2 & emmc_caps) == emmc_caps;
 
        for (i = 0; i <= MAX_PHASE_CODE; i++) {
                /* Centered Phase code */
@@ -1614,8 +1611,8 @@ static int sdhci_eic7700_phase_code_tuning(struct sdhci_host *host, u32 opcode)
                host->ops->reset(host, SDHCI_RESET_CMD | SDHCI_RESET_DATA);
 
                if (ret) {
-                       /* SD specific range tracking */
-                       if (is_sd && code_min != -1 && code_max != -1) {
+                       /* SD/SDIO specific range tracking */
+                       if (!is_emmc && code_min != -1 && code_max != -1) {
                                if (code_max - code_min > code_range) {
                                        code_range = code_max - code_min;
                                        phase_code = (code_min + code_max) / 2;
@@ -1626,17 +1623,17 @@ static int sdhci_eic7700_phase_code_tuning(struct sdhci_host *host, u32 opcode)
                                code_max = -1;
                        }
                        /* EMMC breaks after first valid range */
-                       if (!is_sd && code_min != -1 && code_max != -1)
+                       if (is_emmc && code_min != -1 && code_max != -1)
                                break;
                } else {
                        /* Track valid phase code range */
                        if (code_min == -1) {
                                code_min = i;
-                               if (!is_sd)
+                               if (is_emmc)
                                        continue;
                        }
                        code_max = i;
-                       if (is_sd && i == MAX_PHASE_CODE) {
+                       if (!is_emmc && i == MAX_PHASE_CODE) {
                                if (code_max - code_min > code_range) {
                                        code_range = code_max - code_min;
                                        phase_code = (code_min + code_max) / 2;
@@ -1646,19 +1643,19 @@ static int sdhci_eic7700_phase_code_tuning(struct sdhci_host *host, u32 opcode)
        }
 
        /* Handle tuning failure case */
-       if ((is_sd && phase_code == -1) ||
-           (!is_sd && code_min == -1 && code_max == -1)) {
+       if ((!is_emmc && phase_code == -1) ||
+           (is_emmc && code_min == -1 && code_max == -1)) {
                pr_err("%s: phase code tuning failed!\n", mmc_hostname(host->mmc));
                sdhci_writew(host, 0, priv->vendor_specific_area1 + DWCMSHC_AT_STAT);
                return -EIO;
        }
-       if (!is_sd)
+       if (is_emmc)
                phase_code = (code_min + code_max) / 2;
 
        sdhci_writew(host, phase_code, priv->vendor_specific_area1 + DWCMSHC_AT_STAT);
 
-       /* SD specific final verification */
-       if (is_sd) {
+       /* SD/SDIO specific final verification */
+       if (!is_emmc) {
                ret = mmc_send_tuning(host->mmc, opcode, &cmd_error);
                host->ops->reset(host, SDHCI_RESET_CMD | SDHCI_RESET_DATA);
                if (ret) {
@@ -1756,9 +1753,9 @@ static void sdhci_eic7700_set_uhs_signaling(struct sdhci_host *host, unsigned in
 
 static void sdhci_eic7700_set_uhs_wrapper(struct sdhci_host *host, unsigned int timing)
 {
-       u32 sd_caps = MMC_CAP2_NO_MMC | MMC_CAP2_NO_SDIO;
+       u32 emmc_caps = MMC_CAP2_NO_SD | MMC_CAP2_NO_SDIO;
 
-       if ((host->mmc->caps2 & sd_caps) == sd_caps)
+       if ((host->mmc->caps2 & emmc_caps) != emmc_caps)
                sdhci_set_uhs_signaling(host, timing);
        else
                sdhci_eic7700_set_uhs_signaling(host, timing);
@@ -1767,6 +1764,7 @@ static void sdhci_eic7700_set_uhs_wrapper(struct sdhci_host *host, unsigned int
 static int eic7700_init(struct device *dev, struct sdhci_host *host, struct dwcmshc_priv *dwc_priv)
 {
        u32 emmc_caps = MMC_CAP2_NO_SD | MMC_CAP2_NO_SDIO;
+       u32 sd_caps = MMC_CAP2_NO_MMC | MMC_CAP2_NO_SDIO;
        unsigned int val, hsp_int_status, hsp_pwr_ctrl;
        static const char * const clk_ids[] = {"axi"};
        struct of_phandle_args args;
@@ -1821,8 +1819,10 @@ static int eic7700_init(struct device *dev, struct sdhci_host *host, struct dwcm
 
        if ((host->mmc->caps2 & emmc_caps) == emmc_caps)
                dwc_priv->delay_line = PHY_DELAY_CODE_EMMC;
-       else
+       else if ((host->mmc->caps2 & sd_caps) == sd_caps)
                dwc_priv->delay_line = PHY_DELAY_CODE_SD;
+       else
+               dwc_priv->delay_line = PHY_DELAY_CODE_SDIO;
 
        if (!of_property_read_u32(dev->of_node, "eswin,drive-impedance-ohms", &val))
                priv->drive_impedance = eic7700_convert_drive_impedance_ohm(dev, val);