Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * Copyright (C) 2016 Socionext Inc.
0004  *   Author: Masahiro Yamada <yamada.masahiro@socionext.com>
0005  */
0006 
0007 #include <linux/bitfield.h>
0008 #include <linux/bits.h>
0009 #include <linux/iopoll.h>
0010 #include <linux/module.h>
0011 #include <linux/mmc/host.h>
0012 #include <linux/mmc/mmc.h>
0013 #include <linux/of.h>
0014 #include <linux/of_device.h>
0015 
0016 #include "sdhci-pltfm.h"
0017 
0018 /* HRS - Host Register Set (specific to Cadence) */
0019 #define SDHCI_CDNS_HRS04        0x10        /* PHY access port */
0020 #define   SDHCI_CDNS_HRS04_ACK          BIT(26)
0021 #define   SDHCI_CDNS_HRS04_RD           BIT(25)
0022 #define   SDHCI_CDNS_HRS04_WR           BIT(24)
0023 #define   SDHCI_CDNS_HRS04_RDATA        GENMASK(23, 16)
0024 #define   SDHCI_CDNS_HRS04_WDATA        GENMASK(15, 8)
0025 #define   SDHCI_CDNS_HRS04_ADDR         GENMASK(5, 0)
0026 
0027 #define SDHCI_CDNS_HRS06        0x18        /* eMMC control */
0028 #define   SDHCI_CDNS_HRS06_TUNE_UP      BIT(15)
0029 #define   SDHCI_CDNS_HRS06_TUNE         GENMASK(13, 8)
0030 #define   SDHCI_CDNS_HRS06_MODE         GENMASK(2, 0)
0031 #define   SDHCI_CDNS_HRS06_MODE_SD      0x0
0032 #define   SDHCI_CDNS_HRS06_MODE_MMC_SDR     0x2
0033 #define   SDHCI_CDNS_HRS06_MODE_MMC_DDR     0x3
0034 #define   SDHCI_CDNS_HRS06_MODE_MMC_HS200   0x4
0035 #define   SDHCI_CDNS_HRS06_MODE_MMC_HS400   0x5
0036 #define   SDHCI_CDNS_HRS06_MODE_MMC_HS400ES 0x6
0037 
0038 /* SRS - Slot Register Set (SDHCI-compatible) */
0039 #define SDHCI_CDNS_SRS_BASE     0x200
0040 
0041 /* PHY */
0042 #define SDHCI_CDNS_PHY_DLY_SD_HS    0x00
0043 #define SDHCI_CDNS_PHY_DLY_SD_DEFAULT   0x01
0044 #define SDHCI_CDNS_PHY_DLY_UHS_SDR12    0x02
0045 #define SDHCI_CDNS_PHY_DLY_UHS_SDR25    0x03
0046 #define SDHCI_CDNS_PHY_DLY_UHS_SDR50    0x04
0047 #define SDHCI_CDNS_PHY_DLY_UHS_DDR50    0x05
0048 #define SDHCI_CDNS_PHY_DLY_EMMC_LEGACY  0x06
0049 #define SDHCI_CDNS_PHY_DLY_EMMC_SDR 0x07
0050 #define SDHCI_CDNS_PHY_DLY_EMMC_DDR 0x08
0051 #define SDHCI_CDNS_PHY_DLY_SDCLK    0x0b
0052 #define SDHCI_CDNS_PHY_DLY_HSMMC    0x0c
0053 #define SDHCI_CDNS_PHY_DLY_STROBE   0x0d
0054 
0055 /*
0056  * The tuned val register is 6 bit-wide, but not the whole of the range is
0057  * available.  The range 0-42 seems to be available (then 43 wraps around to 0)
0058  * but I am not quite sure if it is official.  Use only 0 to 39 for safety.
0059  */
0060 #define SDHCI_CDNS_MAX_TUNING_LOOP  40
0061 
0062 struct sdhci_cdns_phy_param {
0063     u8 addr;
0064     u8 data;
0065 };
0066 
0067 struct sdhci_cdns_priv {
0068     void __iomem *hrs_addr;
0069     bool enhanced_strobe;
0070     unsigned int nr_phy_params;
0071     struct sdhci_cdns_phy_param phy_params[];
0072 };
0073 
0074 struct sdhci_cdns_phy_cfg {
0075     const char *property;
0076     u8 addr;
0077 };
0078 
0079 static const struct sdhci_cdns_phy_cfg sdhci_cdns_phy_cfgs[] = {
0080     { "cdns,phy-input-delay-sd-highspeed", SDHCI_CDNS_PHY_DLY_SD_HS, },
0081     { "cdns,phy-input-delay-legacy", SDHCI_CDNS_PHY_DLY_SD_DEFAULT, },
0082     { "cdns,phy-input-delay-sd-uhs-sdr12", SDHCI_CDNS_PHY_DLY_UHS_SDR12, },
0083     { "cdns,phy-input-delay-sd-uhs-sdr25", SDHCI_CDNS_PHY_DLY_UHS_SDR25, },
0084     { "cdns,phy-input-delay-sd-uhs-sdr50", SDHCI_CDNS_PHY_DLY_UHS_SDR50, },
0085     { "cdns,phy-input-delay-sd-uhs-ddr50", SDHCI_CDNS_PHY_DLY_UHS_DDR50, },
0086     { "cdns,phy-input-delay-mmc-highspeed", SDHCI_CDNS_PHY_DLY_EMMC_SDR, },
0087     { "cdns,phy-input-delay-mmc-ddr", SDHCI_CDNS_PHY_DLY_EMMC_DDR, },
0088     { "cdns,phy-dll-delay-sdclk", SDHCI_CDNS_PHY_DLY_SDCLK, },
0089     { "cdns,phy-dll-delay-sdclk-hsmmc", SDHCI_CDNS_PHY_DLY_HSMMC, },
0090     { "cdns,phy-dll-delay-strobe", SDHCI_CDNS_PHY_DLY_STROBE, },
0091 };
0092 
0093 static int sdhci_cdns_write_phy_reg(struct sdhci_cdns_priv *priv,
0094                     u8 addr, u8 data)
0095 {
0096     void __iomem *reg = priv->hrs_addr + SDHCI_CDNS_HRS04;
0097     u32 tmp;
0098     int ret;
0099 
0100     ret = readl_poll_timeout(reg, tmp, !(tmp & SDHCI_CDNS_HRS04_ACK),
0101                  0, 10);
0102     if (ret)
0103         return ret;
0104 
0105     tmp = FIELD_PREP(SDHCI_CDNS_HRS04_WDATA, data) |
0106           FIELD_PREP(SDHCI_CDNS_HRS04_ADDR, addr);
0107     writel(tmp, reg);
0108 
0109     tmp |= SDHCI_CDNS_HRS04_WR;
0110     writel(tmp, reg);
0111 
0112     ret = readl_poll_timeout(reg, tmp, tmp & SDHCI_CDNS_HRS04_ACK, 0, 10);
0113     if (ret)
0114         return ret;
0115 
0116     tmp &= ~SDHCI_CDNS_HRS04_WR;
0117     writel(tmp, reg);
0118 
0119     ret = readl_poll_timeout(reg, tmp, !(tmp & SDHCI_CDNS_HRS04_ACK),
0120                  0, 10);
0121 
0122     return ret;
0123 }
0124 
0125 static unsigned int sdhci_cdns_phy_param_count(struct device_node *np)
0126 {
0127     unsigned int count = 0;
0128     int i;
0129 
0130     for (i = 0; i < ARRAY_SIZE(sdhci_cdns_phy_cfgs); i++)
0131         if (of_property_read_bool(np, sdhci_cdns_phy_cfgs[i].property))
0132             count++;
0133 
0134     return count;
0135 }
0136 
0137 static void sdhci_cdns_phy_param_parse(struct device_node *np,
0138                        struct sdhci_cdns_priv *priv)
0139 {
0140     struct sdhci_cdns_phy_param *p = priv->phy_params;
0141     u32 val;
0142     int ret, i;
0143 
0144     for (i = 0; i < ARRAY_SIZE(sdhci_cdns_phy_cfgs); i++) {
0145         ret = of_property_read_u32(np, sdhci_cdns_phy_cfgs[i].property,
0146                        &val);
0147         if (ret)
0148             continue;
0149 
0150         p->addr = sdhci_cdns_phy_cfgs[i].addr;
0151         p->data = val;
0152         p++;
0153     }
0154 }
0155 
0156 static int sdhci_cdns_phy_init(struct sdhci_cdns_priv *priv)
0157 {
0158     int ret, i;
0159 
0160     for (i = 0; i < priv->nr_phy_params; i++) {
0161         ret = sdhci_cdns_write_phy_reg(priv, priv->phy_params[i].addr,
0162                            priv->phy_params[i].data);
0163         if (ret)
0164             return ret;
0165     }
0166 
0167     return 0;
0168 }
0169 
0170 static void *sdhci_cdns_priv(struct sdhci_host *host)
0171 {
0172     struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
0173 
0174     return sdhci_pltfm_priv(pltfm_host);
0175 }
0176 
0177 static unsigned int sdhci_cdns_get_timeout_clock(struct sdhci_host *host)
0178 {
0179     /*
0180      * Cadence's spec says the Timeout Clock Frequency is the same as the
0181      * Base Clock Frequency.
0182      */
0183     return host->max_clk;
0184 }
0185 
0186 static void sdhci_cdns_set_emmc_mode(struct sdhci_cdns_priv *priv, u32 mode)
0187 {
0188     u32 tmp;
0189 
0190     /* The speed mode for eMMC is selected by HRS06 register */
0191     tmp = readl(priv->hrs_addr + SDHCI_CDNS_HRS06);
0192     tmp &= ~SDHCI_CDNS_HRS06_MODE;
0193     tmp |= FIELD_PREP(SDHCI_CDNS_HRS06_MODE, mode);
0194     writel(tmp, priv->hrs_addr + SDHCI_CDNS_HRS06);
0195 }
0196 
0197 static u32 sdhci_cdns_get_emmc_mode(struct sdhci_cdns_priv *priv)
0198 {
0199     u32 tmp;
0200 
0201     tmp = readl(priv->hrs_addr + SDHCI_CDNS_HRS06);
0202     return FIELD_GET(SDHCI_CDNS_HRS06_MODE, tmp);
0203 }
0204 
0205 static int sdhci_cdns_set_tune_val(struct sdhci_host *host, unsigned int val)
0206 {
0207     struct sdhci_cdns_priv *priv = sdhci_cdns_priv(host);
0208     void __iomem *reg = priv->hrs_addr + SDHCI_CDNS_HRS06;
0209     u32 tmp;
0210     int i, ret;
0211 
0212     if (WARN_ON(!FIELD_FIT(SDHCI_CDNS_HRS06_TUNE, val)))
0213         return -EINVAL;
0214 
0215     tmp = readl(reg);
0216     tmp &= ~SDHCI_CDNS_HRS06_TUNE;
0217     tmp |= FIELD_PREP(SDHCI_CDNS_HRS06_TUNE, val);
0218 
0219     /*
0220      * Workaround for IP errata:
0221      * The IP6116 SD/eMMC PHY design has a timing issue on receive data
0222      * path. Send tune request twice.
0223      */
0224     for (i = 0; i < 2; i++) {
0225         tmp |= SDHCI_CDNS_HRS06_TUNE_UP;
0226         writel(tmp, reg);
0227 
0228         ret = readl_poll_timeout(reg, tmp,
0229                      !(tmp & SDHCI_CDNS_HRS06_TUNE_UP),
0230                      0, 1);
0231         if (ret)
0232             return ret;
0233     }
0234 
0235     return 0;
0236 }
0237 
0238 /*
0239  * In SD mode, software must not use the hardware tuning and instead perform
0240  * an almost identical procedure to eMMC.
0241  */
0242 static int sdhci_cdns_execute_tuning(struct sdhci_host *host, u32 opcode)
0243 {
0244     int cur_streak = 0;
0245     int max_streak = 0;
0246     int end_of_streak = 0;
0247     int i;
0248 
0249     /*
0250      * Do not execute tuning for UHS_SDR50 or UHS_DDR50.
0251      * The delay is set by probe, based on the DT properties.
0252      */
0253     if (host->timing != MMC_TIMING_MMC_HS200 &&
0254         host->timing != MMC_TIMING_UHS_SDR104)
0255         return 0;
0256 
0257     for (i = 0; i < SDHCI_CDNS_MAX_TUNING_LOOP; i++) {
0258         if (sdhci_cdns_set_tune_val(host, i) ||
0259             mmc_send_tuning(host->mmc, opcode, NULL)) { /* bad */
0260             cur_streak = 0;
0261         } else { /* good */
0262             cur_streak++;
0263             if (cur_streak > max_streak) {
0264                 max_streak = cur_streak;
0265                 end_of_streak = i;
0266             }
0267         }
0268     }
0269 
0270     if (!max_streak) {
0271         dev_err(mmc_dev(host->mmc), "no tuning point found\n");
0272         return -EIO;
0273     }
0274 
0275     return sdhci_cdns_set_tune_val(host, end_of_streak - max_streak / 2);
0276 }
0277 
0278 static void sdhci_cdns_set_uhs_signaling(struct sdhci_host *host,
0279                      unsigned int timing)
0280 {
0281     struct sdhci_cdns_priv *priv = sdhci_cdns_priv(host);
0282     u32 mode;
0283 
0284     switch (timing) {
0285     case MMC_TIMING_MMC_HS:
0286         mode = SDHCI_CDNS_HRS06_MODE_MMC_SDR;
0287         break;
0288     case MMC_TIMING_MMC_DDR52:
0289         mode = SDHCI_CDNS_HRS06_MODE_MMC_DDR;
0290         break;
0291     case MMC_TIMING_MMC_HS200:
0292         mode = SDHCI_CDNS_HRS06_MODE_MMC_HS200;
0293         break;
0294     case MMC_TIMING_MMC_HS400:
0295         if (priv->enhanced_strobe)
0296             mode = SDHCI_CDNS_HRS06_MODE_MMC_HS400ES;
0297         else
0298             mode = SDHCI_CDNS_HRS06_MODE_MMC_HS400;
0299         break;
0300     default:
0301         mode = SDHCI_CDNS_HRS06_MODE_SD;
0302         break;
0303     }
0304 
0305     sdhci_cdns_set_emmc_mode(priv, mode);
0306 
0307     /* For SD, fall back to the default handler */
0308     if (mode == SDHCI_CDNS_HRS06_MODE_SD)
0309         sdhci_set_uhs_signaling(host, timing);
0310 }
0311 
0312 static const struct sdhci_ops sdhci_cdns_ops = {
0313     .set_clock = sdhci_set_clock,
0314     .get_timeout_clock = sdhci_cdns_get_timeout_clock,
0315     .set_bus_width = sdhci_set_bus_width,
0316     .reset = sdhci_reset,
0317     .platform_execute_tuning = sdhci_cdns_execute_tuning,
0318     .set_uhs_signaling = sdhci_cdns_set_uhs_signaling,
0319 };
0320 
0321 static const struct sdhci_pltfm_data sdhci_cdns_uniphier_pltfm_data = {
0322     .ops = &sdhci_cdns_ops,
0323     .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN,
0324 };
0325 
0326 static const struct sdhci_pltfm_data sdhci_cdns_pltfm_data = {
0327     .ops = &sdhci_cdns_ops,
0328 };
0329 
0330 static void sdhci_cdns_hs400_enhanced_strobe(struct mmc_host *mmc,
0331                          struct mmc_ios *ios)
0332 {
0333     struct sdhci_host *host = mmc_priv(mmc);
0334     struct sdhci_cdns_priv *priv = sdhci_cdns_priv(host);
0335     u32 mode;
0336 
0337     priv->enhanced_strobe = ios->enhanced_strobe;
0338 
0339     mode = sdhci_cdns_get_emmc_mode(priv);
0340 
0341     if (mode == SDHCI_CDNS_HRS06_MODE_MMC_HS400 && ios->enhanced_strobe)
0342         sdhci_cdns_set_emmc_mode(priv,
0343                      SDHCI_CDNS_HRS06_MODE_MMC_HS400ES);
0344 
0345     if (mode == SDHCI_CDNS_HRS06_MODE_MMC_HS400ES && !ios->enhanced_strobe)
0346         sdhci_cdns_set_emmc_mode(priv,
0347                      SDHCI_CDNS_HRS06_MODE_MMC_HS400);
0348 }
0349 
0350 static int sdhci_cdns_probe(struct platform_device *pdev)
0351 {
0352     struct sdhci_host *host;
0353     const struct sdhci_pltfm_data *data;
0354     struct sdhci_pltfm_host *pltfm_host;
0355     struct sdhci_cdns_priv *priv;
0356     struct clk *clk;
0357     unsigned int nr_phy_params;
0358     int ret;
0359     struct device *dev = &pdev->dev;
0360     static const u16 version = SDHCI_SPEC_400 << SDHCI_SPEC_VER_SHIFT;
0361 
0362     clk = devm_clk_get(dev, NULL);
0363     if (IS_ERR(clk))
0364         return PTR_ERR(clk);
0365 
0366     ret = clk_prepare_enable(clk);
0367     if (ret)
0368         return ret;
0369 
0370     data = of_device_get_match_data(dev);
0371     if (!data)
0372         data = &sdhci_cdns_pltfm_data;
0373 
0374     nr_phy_params = sdhci_cdns_phy_param_count(dev->of_node);
0375     host = sdhci_pltfm_init(pdev, data,
0376                 struct_size(priv, phy_params, nr_phy_params));
0377     if (IS_ERR(host)) {
0378         ret = PTR_ERR(host);
0379         goto disable_clk;
0380     }
0381 
0382     pltfm_host = sdhci_priv(host);
0383     pltfm_host->clk = clk;
0384 
0385     priv = sdhci_pltfm_priv(pltfm_host);
0386     priv->nr_phy_params = nr_phy_params;
0387     priv->hrs_addr = host->ioaddr;
0388     priv->enhanced_strobe = false;
0389     host->ioaddr += SDHCI_CDNS_SRS_BASE;
0390     host->mmc_host_ops.hs400_enhanced_strobe =
0391                 sdhci_cdns_hs400_enhanced_strobe;
0392     sdhci_enable_v4_mode(host);
0393     __sdhci_read_caps(host, &version, NULL, NULL);
0394 
0395     sdhci_get_of_property(pdev);
0396 
0397     ret = mmc_of_parse(host->mmc);
0398     if (ret)
0399         goto free;
0400 
0401     sdhci_cdns_phy_param_parse(dev->of_node, priv);
0402 
0403     ret = sdhci_cdns_phy_init(priv);
0404     if (ret)
0405         goto free;
0406 
0407     ret = sdhci_add_host(host);
0408     if (ret)
0409         goto free;
0410 
0411     return 0;
0412 free:
0413     sdhci_pltfm_free(pdev);
0414 disable_clk:
0415     clk_disable_unprepare(clk);
0416 
0417     return ret;
0418 }
0419 
0420 #ifdef CONFIG_PM_SLEEP
0421 static int sdhci_cdns_resume(struct device *dev)
0422 {
0423     struct sdhci_host *host = dev_get_drvdata(dev);
0424     struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
0425     struct sdhci_cdns_priv *priv = sdhci_pltfm_priv(pltfm_host);
0426     int ret;
0427 
0428     ret = clk_prepare_enable(pltfm_host->clk);
0429     if (ret)
0430         return ret;
0431 
0432     ret = sdhci_cdns_phy_init(priv);
0433     if (ret)
0434         goto disable_clk;
0435 
0436     ret = sdhci_resume_host(host);
0437     if (ret)
0438         goto disable_clk;
0439 
0440     return 0;
0441 
0442 disable_clk:
0443     clk_disable_unprepare(pltfm_host->clk);
0444 
0445     return ret;
0446 }
0447 #endif
0448 
0449 static const struct dev_pm_ops sdhci_cdns_pm_ops = {
0450     SET_SYSTEM_SLEEP_PM_OPS(sdhci_pltfm_suspend, sdhci_cdns_resume)
0451 };
0452 
0453 static const struct of_device_id sdhci_cdns_match[] = {
0454     {
0455         .compatible = "socionext,uniphier-sd4hc",
0456         .data = &sdhci_cdns_uniphier_pltfm_data,
0457     },
0458     { .compatible = "cdns,sd4hc" },
0459     { /* sentinel */ }
0460 };
0461 MODULE_DEVICE_TABLE(of, sdhci_cdns_match);
0462 
0463 static struct platform_driver sdhci_cdns_driver = {
0464     .driver = {
0465         .name = "sdhci-cdns",
0466         .probe_type = PROBE_PREFER_ASYNCHRONOUS,
0467         .pm = &sdhci_cdns_pm_ops,
0468         .of_match_table = sdhci_cdns_match,
0469     },
0470     .probe = sdhci_cdns_probe,
0471     .remove = sdhci_pltfm_unregister,
0472 };
0473 module_platform_driver(sdhci_cdns_driver);
0474 
0475 MODULE_AUTHOR("Masahiro Yamada <yamada.masahiro@socionext.com>");
0476 MODULE_DESCRIPTION("Cadence SD/SDIO/eMMC Host Controller Driver");
0477 MODULE_LICENSE("GPL");