Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * sdhci-brcmstb.c Support for SDHCI on Broadcom BRCMSTB SoC's
0004  *
0005  * Copyright (C) 2015 Broadcom Corporation
0006  */
0007 
0008 #include <linux/io.h>
0009 #include <linux/mmc/host.h>
0010 #include <linux/module.h>
0011 #include <linux/of.h>
0012 #include <linux/bitops.h>
0013 #include <linux/delay.h>
0014 
0015 #include "sdhci-pltfm.h"
0016 #include "cqhci.h"
0017 
0018 #define SDHCI_VENDOR 0x78
0019 #define  SDHCI_VENDOR_ENHANCED_STRB 0x1
0020 #define  SDHCI_VENDOR_GATE_SDCLK_EN 0x2
0021 
0022 #define BRCMSTB_MATCH_FLAGS_NO_64BIT        BIT(0)
0023 #define BRCMSTB_MATCH_FLAGS_BROKEN_TIMEOUT  BIT(1)
0024 #define BRCMSTB_MATCH_FLAGS_HAS_CLOCK_GATE  BIT(2)
0025 
0026 #define BRCMSTB_PRIV_FLAGS_HAS_CQE      BIT(0)
0027 #define BRCMSTB_PRIV_FLAGS_GATE_CLOCK       BIT(1)
0028 
0029 #define SDHCI_ARASAN_CQE_BASE_ADDR      0x200
0030 
0031 struct sdhci_brcmstb_priv {
0032     void __iomem *cfg_regs;
0033     unsigned int flags;
0034     struct clk *base_clk;
0035     u32 base_freq_hz;
0036 };
0037 
0038 struct brcmstb_match_priv {
0039     void (*hs400es)(struct mmc_host *mmc, struct mmc_ios *ios);
0040     struct sdhci_ops *ops;
0041     const unsigned int flags;
0042 };
0043 
0044 static inline void enable_clock_gating(struct sdhci_host *host)
0045 {
0046     u32 reg;
0047 
0048     reg = sdhci_readl(host, SDHCI_VENDOR);
0049     reg |= SDHCI_VENDOR_GATE_SDCLK_EN;
0050     sdhci_writel(host, reg, SDHCI_VENDOR);
0051 }
0052 
0053 static void brcmstb_reset(struct sdhci_host *host, u8 mask)
0054 {
0055     struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
0056     struct sdhci_brcmstb_priv *priv = sdhci_pltfm_priv(pltfm_host);
0057 
0058     sdhci_reset(host, mask);
0059 
0060     /* Reset will clear this, so re-enable it */
0061     if (priv->flags & BRCMSTB_PRIV_FLAGS_GATE_CLOCK)
0062         enable_clock_gating(host);
0063 }
0064 
0065 static void sdhci_brcmstb_hs400es(struct mmc_host *mmc, struct mmc_ios *ios)
0066 {
0067     struct sdhci_host *host = mmc_priv(mmc);
0068 
0069     u32 reg;
0070 
0071     dev_dbg(mmc_dev(mmc), "%s(): Setting HS400-Enhanced-Strobe mode\n",
0072         __func__);
0073     reg = readl(host->ioaddr + SDHCI_VENDOR);
0074     if (ios->enhanced_strobe)
0075         reg |= SDHCI_VENDOR_ENHANCED_STRB;
0076     else
0077         reg &= ~SDHCI_VENDOR_ENHANCED_STRB;
0078     writel(reg, host->ioaddr + SDHCI_VENDOR);
0079 }
0080 
0081 static void sdhci_brcmstb_set_clock(struct sdhci_host *host, unsigned int clock)
0082 {
0083     u16 clk;
0084 
0085     host->mmc->actual_clock = 0;
0086 
0087     clk = sdhci_calc_clk(host, clock, &host->mmc->actual_clock);
0088     sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
0089 
0090     if (clock == 0)
0091         return;
0092 
0093     sdhci_enable_clk(host, clk);
0094 }
0095 
0096 static void sdhci_brcmstb_set_uhs_signaling(struct sdhci_host *host,
0097                         unsigned int timing)
0098 {
0099     u16 ctrl_2;
0100 
0101     dev_dbg(mmc_dev(host->mmc), "%s: Setting UHS signaling for %d timing\n",
0102         __func__, timing);
0103     ctrl_2 = sdhci_readw(host, SDHCI_HOST_CONTROL2);
0104     /* Select Bus Speed Mode for host */
0105     ctrl_2 &= ~SDHCI_CTRL_UHS_MASK;
0106     if ((timing == MMC_TIMING_MMC_HS200) ||
0107         (timing == MMC_TIMING_UHS_SDR104))
0108         ctrl_2 |= SDHCI_CTRL_UHS_SDR104;
0109     else if (timing == MMC_TIMING_UHS_SDR12)
0110         ctrl_2 |= SDHCI_CTRL_UHS_SDR12;
0111     else if (timing == MMC_TIMING_SD_HS ||
0112          timing == MMC_TIMING_MMC_HS ||
0113          timing == MMC_TIMING_UHS_SDR25)
0114         ctrl_2 |= SDHCI_CTRL_UHS_SDR25;
0115     else if (timing == MMC_TIMING_UHS_SDR50)
0116         ctrl_2 |= SDHCI_CTRL_UHS_SDR50;
0117     else if ((timing == MMC_TIMING_UHS_DDR50) ||
0118          (timing == MMC_TIMING_MMC_DDR52))
0119         ctrl_2 |= SDHCI_CTRL_UHS_DDR50;
0120     else if (timing == MMC_TIMING_MMC_HS400)
0121         ctrl_2 |= SDHCI_CTRL_HS400; /* Non-standard */
0122     sdhci_writew(host, ctrl_2, SDHCI_HOST_CONTROL2);
0123 }
0124 
0125 static void sdhci_brcmstb_dumpregs(struct mmc_host *mmc)
0126 {
0127     sdhci_dumpregs(mmc_priv(mmc));
0128 }
0129 
0130 static void sdhci_brcmstb_cqe_enable(struct mmc_host *mmc)
0131 {
0132     struct sdhci_host *host = mmc_priv(mmc);
0133     u32 reg;
0134 
0135     reg = sdhci_readl(host, SDHCI_PRESENT_STATE);
0136     while (reg & SDHCI_DATA_AVAILABLE) {
0137         sdhci_readl(host, SDHCI_BUFFER);
0138         reg = sdhci_readl(host, SDHCI_PRESENT_STATE);
0139     }
0140 
0141     sdhci_cqe_enable(mmc);
0142 }
0143 
0144 static const struct cqhci_host_ops sdhci_brcmstb_cqhci_ops = {
0145     .enable         = sdhci_brcmstb_cqe_enable,
0146     .disable        = sdhci_cqe_disable,
0147     .dumpregs       = sdhci_brcmstb_dumpregs,
0148 };
0149 
0150 static struct sdhci_ops sdhci_brcmstb_ops = {
0151     .set_clock = sdhci_set_clock,
0152     .set_bus_width = sdhci_set_bus_width,
0153     .reset = sdhci_reset,
0154     .set_uhs_signaling = sdhci_set_uhs_signaling,
0155 };
0156 
0157 static struct sdhci_ops sdhci_brcmstb_ops_7216 = {
0158     .set_clock = sdhci_brcmstb_set_clock,
0159     .set_bus_width = sdhci_set_bus_width,
0160     .reset = brcmstb_reset,
0161     .set_uhs_signaling = sdhci_brcmstb_set_uhs_signaling,
0162 };
0163 
0164 static struct brcmstb_match_priv match_priv_7425 = {
0165     .flags = BRCMSTB_MATCH_FLAGS_NO_64BIT |
0166     BRCMSTB_MATCH_FLAGS_BROKEN_TIMEOUT,
0167     .ops = &sdhci_brcmstb_ops,
0168 };
0169 
0170 static struct brcmstb_match_priv match_priv_7445 = {
0171     .flags = BRCMSTB_MATCH_FLAGS_BROKEN_TIMEOUT,
0172     .ops = &sdhci_brcmstb_ops,
0173 };
0174 
0175 static const struct brcmstb_match_priv match_priv_7216 = {
0176     .flags = BRCMSTB_MATCH_FLAGS_HAS_CLOCK_GATE,
0177     .hs400es = sdhci_brcmstb_hs400es,
0178     .ops = &sdhci_brcmstb_ops_7216,
0179 };
0180 
0181 static const struct of_device_id sdhci_brcm_of_match[] = {
0182     { .compatible = "brcm,bcm7425-sdhci", .data = &match_priv_7425 },
0183     { .compatible = "brcm,bcm7445-sdhci", .data = &match_priv_7445 },
0184     { .compatible = "brcm,bcm7216-sdhci", .data = &match_priv_7216 },
0185     {},
0186 };
0187 
0188 static u32 sdhci_brcmstb_cqhci_irq(struct sdhci_host *host, u32 intmask)
0189 {
0190     int cmd_error = 0;
0191     int data_error = 0;
0192 
0193     if (!sdhci_cqe_irq(host, intmask, &cmd_error, &data_error))
0194         return intmask;
0195 
0196     cqhci_irq(host->mmc, intmask, cmd_error, data_error);
0197 
0198     return 0;
0199 }
0200 
0201 static int sdhci_brcmstb_add_host(struct sdhci_host *host,
0202                   struct sdhci_brcmstb_priv *priv)
0203 {
0204     struct cqhci_host *cq_host;
0205     bool dma64;
0206     int ret;
0207 
0208     if ((priv->flags & BRCMSTB_PRIV_FLAGS_HAS_CQE) == 0)
0209         return sdhci_add_host(host);
0210 
0211     dev_dbg(mmc_dev(host->mmc), "CQE is enabled\n");
0212     host->mmc->caps2 |= MMC_CAP2_CQE | MMC_CAP2_CQE_DCMD;
0213     ret = sdhci_setup_host(host);
0214     if (ret)
0215         return ret;
0216 
0217     cq_host = devm_kzalloc(mmc_dev(host->mmc),
0218                    sizeof(*cq_host), GFP_KERNEL);
0219     if (!cq_host) {
0220         ret = -ENOMEM;
0221         goto cleanup;
0222     }
0223 
0224     cq_host->mmio = host->ioaddr + SDHCI_ARASAN_CQE_BASE_ADDR;
0225     cq_host->ops = &sdhci_brcmstb_cqhci_ops;
0226 
0227     dma64 = host->flags & SDHCI_USE_64_BIT_DMA;
0228     if (dma64) {
0229         dev_dbg(mmc_dev(host->mmc), "Using 64 bit DMA\n");
0230         cq_host->caps |= CQHCI_TASK_DESC_SZ_128;
0231     }
0232 
0233     ret = cqhci_init(cq_host, host->mmc, dma64);
0234     if (ret)
0235         goto cleanup;
0236 
0237     ret = __sdhci_add_host(host);
0238     if (ret)
0239         goto cleanup;
0240 
0241     return 0;
0242 
0243 cleanup:
0244     sdhci_cleanup_host(host);
0245     return ret;
0246 }
0247 
0248 static int sdhci_brcmstb_probe(struct platform_device *pdev)
0249 {
0250     const struct brcmstb_match_priv *match_priv;
0251     struct sdhci_pltfm_data brcmstb_pdata;
0252     struct sdhci_pltfm_host *pltfm_host;
0253     const struct of_device_id *match;
0254     struct sdhci_brcmstb_priv *priv;
0255     u32 actual_clock_mhz;
0256     struct sdhci_host *host;
0257     struct resource *iomem;
0258     struct clk *clk;
0259     struct clk *base_clk = NULL;
0260     int res;
0261 
0262     match = of_match_node(sdhci_brcm_of_match, pdev->dev.of_node);
0263     match_priv = match->data;
0264 
0265     dev_dbg(&pdev->dev, "Probe found match for %s\n",  match->compatible);
0266 
0267     clk = devm_clk_get_optional(&pdev->dev, NULL);
0268     if (IS_ERR(clk))
0269         return dev_err_probe(&pdev->dev, PTR_ERR(clk),
0270                      "Failed to get clock from Device Tree\n");
0271 
0272     res = clk_prepare_enable(clk);
0273     if (res)
0274         return res;
0275 
0276     memset(&brcmstb_pdata, 0, sizeof(brcmstb_pdata));
0277     brcmstb_pdata.ops = match_priv->ops;
0278     host = sdhci_pltfm_init(pdev, &brcmstb_pdata,
0279                 sizeof(struct sdhci_brcmstb_priv));
0280     if (IS_ERR(host)) {
0281         res = PTR_ERR(host);
0282         goto err_clk;
0283     }
0284 
0285     pltfm_host = sdhci_priv(host);
0286     priv = sdhci_pltfm_priv(pltfm_host);
0287     if (device_property_read_bool(&pdev->dev, "supports-cqe")) {
0288         priv->flags |= BRCMSTB_PRIV_FLAGS_HAS_CQE;
0289         match_priv->ops->irq = sdhci_brcmstb_cqhci_irq;
0290     }
0291 
0292     /* Map in the non-standard CFG registers */
0293     iomem = platform_get_resource(pdev, IORESOURCE_MEM, 1);
0294     priv->cfg_regs = devm_ioremap_resource(&pdev->dev, iomem);
0295     if (IS_ERR(priv->cfg_regs)) {
0296         res = PTR_ERR(priv->cfg_regs);
0297         goto err;
0298     }
0299 
0300     sdhci_get_of_property(pdev);
0301     res = mmc_of_parse(host->mmc);
0302     if (res)
0303         goto err;
0304 
0305     /*
0306      * Automatic clock gating does not work for SD cards that may
0307      * voltage switch so only enable it for non-removable devices.
0308      */
0309     if ((match_priv->flags & BRCMSTB_MATCH_FLAGS_HAS_CLOCK_GATE) &&
0310         (host->mmc->caps & MMC_CAP_NONREMOVABLE))
0311         priv->flags |= BRCMSTB_PRIV_FLAGS_GATE_CLOCK;
0312 
0313     /*
0314      * If the chip has enhanced strobe and it's enabled, add
0315      * callback
0316      */
0317     if (match_priv->hs400es &&
0318         (host->mmc->caps2 & MMC_CAP2_HS400_ES))
0319         host->mmc_host_ops.hs400_enhanced_strobe = match_priv->hs400es;
0320 
0321     /*
0322      * Supply the existing CAPS, but clear the UHS modes. This
0323      * will allow these modes to be specified by device tree
0324      * properties through mmc_of_parse().
0325      */
0326     host->caps = sdhci_readl(host, SDHCI_CAPABILITIES);
0327     if (match_priv->flags & BRCMSTB_MATCH_FLAGS_NO_64BIT)
0328         host->caps &= ~SDHCI_CAN_64BIT;
0329     host->caps1 = sdhci_readl(host, SDHCI_CAPABILITIES_1);
0330     host->caps1 &= ~(SDHCI_SUPPORT_SDR50 | SDHCI_SUPPORT_SDR104 |
0331              SDHCI_SUPPORT_DDR50);
0332     host->quirks |= SDHCI_QUIRK_MISSING_CAPS;
0333 
0334     if (match_priv->flags & BRCMSTB_MATCH_FLAGS_BROKEN_TIMEOUT)
0335         host->quirks |= SDHCI_QUIRK_BROKEN_TIMEOUT_VAL;
0336 
0337     /* Change the base clock frequency if the DT property exists */
0338     if (device_property_read_u32(&pdev->dev, "clock-frequency",
0339                      &priv->base_freq_hz) != 0)
0340         goto add_host;
0341 
0342     base_clk = devm_clk_get_optional(&pdev->dev, "sdio_freq");
0343     if (IS_ERR(base_clk)) {
0344         dev_warn(&pdev->dev, "Clock for \"sdio_freq\" not found\n");
0345         goto add_host;
0346     }
0347 
0348     res = clk_prepare_enable(base_clk);
0349     if (res)
0350         goto err;
0351 
0352     /* set improved clock rate */
0353     clk_set_rate(base_clk, priv->base_freq_hz);
0354     actual_clock_mhz = clk_get_rate(base_clk) / 1000000;
0355 
0356     host->caps &= ~SDHCI_CLOCK_V3_BASE_MASK;
0357     host->caps |= (actual_clock_mhz << SDHCI_CLOCK_BASE_SHIFT);
0358     /* Disable presets because they are now incorrect */
0359     host->quirks2 |= SDHCI_QUIRK2_PRESET_VALUE_BROKEN;
0360 
0361     dev_dbg(&pdev->dev, "Base Clock Frequency changed to %dMHz\n",
0362         actual_clock_mhz);
0363     priv->base_clk = base_clk;
0364 
0365 add_host:
0366     res = sdhci_brcmstb_add_host(host, priv);
0367     if (res)
0368         goto err;
0369 
0370     pltfm_host->clk = clk;
0371     return res;
0372 
0373 err:
0374     sdhci_pltfm_free(pdev);
0375 err_clk:
0376     clk_disable_unprepare(base_clk);
0377     clk_disable_unprepare(clk);
0378     return res;
0379 }
0380 
0381 static void sdhci_brcmstb_shutdown(struct platform_device *pdev)
0382 {
0383     sdhci_pltfm_suspend(&pdev->dev);
0384 }
0385 
0386 MODULE_DEVICE_TABLE(of, sdhci_brcm_of_match);
0387 
0388 #ifdef CONFIG_PM_SLEEP
0389 static int sdhci_brcmstb_suspend(struct device *dev)
0390 {
0391     struct sdhci_host *host = dev_get_drvdata(dev);
0392     struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
0393     struct sdhci_brcmstb_priv *priv = sdhci_pltfm_priv(pltfm_host);
0394 
0395     clk_disable_unprepare(priv->base_clk);
0396     return sdhci_pltfm_suspend(dev);
0397 }
0398 
0399 static int sdhci_brcmstb_resume(struct device *dev)
0400 {
0401     struct sdhci_host *host = dev_get_drvdata(dev);
0402     struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
0403     struct sdhci_brcmstb_priv *priv = sdhci_pltfm_priv(pltfm_host);
0404     int ret;
0405 
0406     ret = sdhci_pltfm_resume(dev);
0407     if (!ret && priv->base_freq_hz) {
0408         ret = clk_prepare_enable(priv->base_clk);
0409         /*
0410          * Note: using clk_get_rate() below as clk_get_rate()
0411          * honors CLK_GET_RATE_NOCACHE attribute, but clk_set_rate()
0412          * may do implicit get_rate() calls that do not honor
0413          * CLK_GET_RATE_NOCACHE.
0414          */
0415         if (!ret &&
0416             (clk_get_rate(priv->base_clk) != priv->base_freq_hz))
0417             ret = clk_set_rate(priv->base_clk, priv->base_freq_hz);
0418     }
0419 
0420     return ret;
0421 }
0422 #endif
0423 
0424 static const struct dev_pm_ops sdhci_brcmstb_pmops = {
0425     SET_SYSTEM_SLEEP_PM_OPS(sdhci_brcmstb_suspend, sdhci_brcmstb_resume)
0426 };
0427 
0428 static struct platform_driver sdhci_brcmstb_driver = {
0429     .driver     = {
0430         .name   = "sdhci-brcmstb",
0431         .probe_type = PROBE_PREFER_ASYNCHRONOUS,
0432         .pm = &sdhci_brcmstb_pmops,
0433         .of_match_table = of_match_ptr(sdhci_brcm_of_match),
0434     },
0435     .probe      = sdhci_brcmstb_probe,
0436     .remove     = sdhci_pltfm_unregister,
0437     .shutdown   = sdhci_brcmstb_shutdown,
0438 };
0439 
0440 module_platform_driver(sdhci_brcmstb_driver);
0441 
0442 MODULE_DESCRIPTION("SDHCI driver for Broadcom BRCMSTB SoCs");
0443 MODULE_AUTHOR("Broadcom");
0444 MODULE_LICENSE("GPL v2");