GNU Linux-libre 5.10.217-gnu1
[releases.git] / drivers / mmc / host / sdhci-brcmstb.c
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * sdhci-brcmstb.c Support for SDHCI on Broadcom BRCMSTB SoC's
4  *
5  * Copyright (C) 2015 Broadcom Corporation
6  */
7
8 #include <linux/io.h>
9 #include <linux/mmc/host.h>
10 #include <linux/module.h>
11 #include <linux/of.h>
12 #include <linux/bitops.h>
13 #include <linux/delay.h>
14
15 #include "sdhci-cqhci.h"
16 #include "sdhci-pltfm.h"
17 #include "cqhci.h"
18
19 #define SDHCI_VENDOR 0x78
20 #define  SDHCI_VENDOR_ENHANCED_STRB 0x1
21 #define  SDHCI_VENDOR_GATE_SDCLK_EN 0x2
22
23 #define BRCMSTB_MATCH_FLAGS_NO_64BIT            BIT(0)
24 #define BRCMSTB_MATCH_FLAGS_BROKEN_TIMEOUT      BIT(1)
25 #define BRCMSTB_MATCH_FLAGS_HAS_CLOCK_GATE      BIT(2)
26
27 #define BRCMSTB_PRIV_FLAGS_HAS_CQE              BIT(0)
28 #define BRCMSTB_PRIV_FLAGS_GATE_CLOCK           BIT(1)
29
30 #define SDHCI_ARASAN_CQE_BASE_ADDR              0x200
31
32 struct sdhci_brcmstb_priv {
33         void __iomem *cfg_regs;
34         unsigned int flags;
35 };
36
37 struct brcmstb_match_priv {
38         void (*hs400es)(struct mmc_host *mmc, struct mmc_ios *ios);
39         struct sdhci_ops *ops;
40         const unsigned int flags;
41 };
42
43 static inline void enable_clock_gating(struct sdhci_host *host)
44 {
45         u32 reg;
46
47         reg = sdhci_readl(host, SDHCI_VENDOR);
48         reg |= SDHCI_VENDOR_GATE_SDCLK_EN;
49         sdhci_writel(host, reg, SDHCI_VENDOR);
50 }
51
52 void brcmstb_reset(struct sdhci_host *host, u8 mask)
53 {
54         struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
55         struct sdhci_brcmstb_priv *priv = sdhci_pltfm_priv(pltfm_host);
56
57         sdhci_and_cqhci_reset(host, mask);
58
59         /* Reset will clear this, so re-enable it */
60         if (priv->flags & BRCMSTB_PRIV_FLAGS_GATE_CLOCK)
61                 enable_clock_gating(host);
62 }
63
64 static void sdhci_brcmstb_hs400es(struct mmc_host *mmc, struct mmc_ios *ios)
65 {
66         struct sdhci_host *host = mmc_priv(mmc);
67
68         u32 reg;
69
70         dev_dbg(mmc_dev(mmc), "%s(): Setting HS400-Enhanced-Strobe mode\n",
71                 __func__);
72         reg = readl(host->ioaddr + SDHCI_VENDOR);
73         if (ios->enhanced_strobe)
74                 reg |= SDHCI_VENDOR_ENHANCED_STRB;
75         else
76                 reg &= ~SDHCI_VENDOR_ENHANCED_STRB;
77         writel(reg, host->ioaddr + SDHCI_VENDOR);
78 }
79
80 static void sdhci_brcmstb_set_clock(struct sdhci_host *host, unsigned int clock)
81 {
82         u16 clk;
83
84         host->mmc->actual_clock = 0;
85
86         clk = sdhci_calc_clk(host, clock, &host->mmc->actual_clock);
87         sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
88
89         if (clock == 0)
90                 return;
91
92         sdhci_enable_clk(host, clk);
93 }
94
95 static void sdhci_brcmstb_set_uhs_signaling(struct sdhci_host *host,
96                                             unsigned int timing)
97 {
98         u16 ctrl_2;
99
100         dev_dbg(mmc_dev(host->mmc), "%s: Setting UHS signaling for %d timing\n",
101                 __func__, timing);
102         ctrl_2 = sdhci_readw(host, SDHCI_HOST_CONTROL2);
103         /* Select Bus Speed Mode for host */
104         ctrl_2 &= ~SDHCI_CTRL_UHS_MASK;
105         if ((timing == MMC_TIMING_MMC_HS200) ||
106             (timing == MMC_TIMING_UHS_SDR104))
107                 ctrl_2 |= SDHCI_CTRL_UHS_SDR104;
108         else if (timing == MMC_TIMING_UHS_SDR12)
109                 ctrl_2 |= SDHCI_CTRL_UHS_SDR12;
110         else if (timing == MMC_TIMING_SD_HS ||
111                  timing == MMC_TIMING_MMC_HS ||
112                  timing == MMC_TIMING_UHS_SDR25)
113                 ctrl_2 |= SDHCI_CTRL_UHS_SDR25;
114         else if (timing == MMC_TIMING_UHS_SDR50)
115                 ctrl_2 |= SDHCI_CTRL_UHS_SDR50;
116         else if ((timing == MMC_TIMING_UHS_DDR50) ||
117                  (timing == MMC_TIMING_MMC_DDR52))
118                 ctrl_2 |= SDHCI_CTRL_UHS_DDR50;
119         else if (timing == MMC_TIMING_MMC_HS400)
120                 ctrl_2 |= SDHCI_CTRL_HS400; /* Non-standard */
121         sdhci_writew(host, ctrl_2, SDHCI_HOST_CONTROL2);
122 }
123
124 static void sdhci_brcmstb_dumpregs(struct mmc_host *mmc)
125 {
126         sdhci_dumpregs(mmc_priv(mmc));
127 }
128
129 static void sdhci_brcmstb_cqe_enable(struct mmc_host *mmc)
130 {
131         struct sdhci_host *host = mmc_priv(mmc);
132         u32 reg;
133
134         reg = sdhci_readl(host, SDHCI_PRESENT_STATE);
135         while (reg & SDHCI_DATA_AVAILABLE) {
136                 sdhci_readl(host, SDHCI_BUFFER);
137                 reg = sdhci_readl(host, SDHCI_PRESENT_STATE);
138         }
139
140         sdhci_cqe_enable(mmc);
141 }
142
143 static const struct cqhci_host_ops sdhci_brcmstb_cqhci_ops = {
144         .enable         = sdhci_brcmstb_cqe_enable,
145         .disable        = sdhci_cqe_disable,
146         .dumpregs       = sdhci_brcmstb_dumpregs,
147 };
148
149 static struct sdhci_ops sdhci_brcmstb_ops = {
150         .set_clock = sdhci_set_clock,
151         .set_bus_width = sdhci_set_bus_width,
152         .reset = sdhci_reset,
153         .set_uhs_signaling = sdhci_set_uhs_signaling,
154 };
155
156 static struct sdhci_ops sdhci_brcmstb_ops_7216 = {
157         .set_clock = sdhci_brcmstb_set_clock,
158         .set_bus_width = sdhci_set_bus_width,
159         .reset = brcmstb_reset,
160         .set_uhs_signaling = sdhci_brcmstb_set_uhs_signaling,
161 };
162
163 static struct brcmstb_match_priv match_priv_7425 = {
164         .flags = BRCMSTB_MATCH_FLAGS_NO_64BIT |
165         BRCMSTB_MATCH_FLAGS_BROKEN_TIMEOUT,
166         .ops = &sdhci_brcmstb_ops,
167 };
168
169 static struct brcmstb_match_priv match_priv_7445 = {
170         .flags = BRCMSTB_MATCH_FLAGS_BROKEN_TIMEOUT,
171         .ops = &sdhci_brcmstb_ops,
172 };
173
174 static const struct brcmstb_match_priv match_priv_7216 = {
175         .flags = BRCMSTB_MATCH_FLAGS_HAS_CLOCK_GATE,
176         .hs400es = sdhci_brcmstb_hs400es,
177         .ops = &sdhci_brcmstb_ops_7216,
178 };
179
180 static const struct of_device_id sdhci_brcm_of_match[] = {
181         { .compatible = "brcm,bcm7425-sdhci", .data = &match_priv_7425 },
182         { .compatible = "brcm,bcm7445-sdhci", .data = &match_priv_7445 },
183         { .compatible = "brcm,bcm7216-sdhci", .data = &match_priv_7216 },
184         {},
185 };
186
187 static u32 sdhci_brcmstb_cqhci_irq(struct sdhci_host *host, u32 intmask)
188 {
189         int cmd_error = 0;
190         int data_error = 0;
191
192         if (!sdhci_cqe_irq(host, intmask, &cmd_error, &data_error))
193                 return intmask;
194
195         cqhci_irq(host->mmc, intmask, cmd_error, data_error);
196
197         return 0;
198 }
199
200 static int sdhci_brcmstb_add_host(struct sdhci_host *host,
201                                   struct sdhci_brcmstb_priv *priv)
202 {
203         struct cqhci_host *cq_host;
204         bool dma64;
205         int ret;
206
207         if ((priv->flags & BRCMSTB_PRIV_FLAGS_HAS_CQE) == 0)
208                 return sdhci_add_host(host);
209
210         dev_dbg(mmc_dev(host->mmc), "CQE is enabled\n");
211         host->mmc->caps2 |= MMC_CAP2_CQE | MMC_CAP2_CQE_DCMD;
212         ret = sdhci_setup_host(host);
213         if (ret)
214                 return ret;
215
216         cq_host = devm_kzalloc(mmc_dev(host->mmc),
217                                sizeof(*cq_host), GFP_KERNEL);
218         if (!cq_host) {
219                 ret = -ENOMEM;
220                 goto cleanup;
221         }
222
223         cq_host->mmio = host->ioaddr + SDHCI_ARASAN_CQE_BASE_ADDR;
224         cq_host->ops = &sdhci_brcmstb_cqhci_ops;
225
226         dma64 = host->flags & SDHCI_USE_64_BIT_DMA;
227         if (dma64) {
228                 dev_dbg(mmc_dev(host->mmc), "Using 64 bit DMA\n");
229                 cq_host->caps |= CQHCI_TASK_DESC_SZ_128;
230         }
231
232         ret = cqhci_init(cq_host, host->mmc, dma64);
233         if (ret)
234                 goto cleanup;
235
236         ret = __sdhci_add_host(host);
237         if (ret)
238                 goto cleanup;
239
240         return 0;
241
242 cleanup:
243         sdhci_cleanup_host(host);
244         return ret;
245 }
246
247 static int sdhci_brcmstb_probe(struct platform_device *pdev)
248 {
249         const struct brcmstb_match_priv *match_priv;
250         struct sdhci_pltfm_data brcmstb_pdata;
251         struct sdhci_pltfm_host *pltfm_host;
252         const struct of_device_id *match;
253         struct sdhci_brcmstb_priv *priv;
254         struct sdhci_host *host;
255         struct resource *iomem;
256         struct clk *clk;
257         int res;
258
259         match = of_match_node(sdhci_brcm_of_match, pdev->dev.of_node);
260         match_priv = match->data;
261
262         dev_dbg(&pdev->dev, "Probe found match for %s\n",  match->compatible);
263
264         clk = devm_clk_get_optional(&pdev->dev, NULL);
265         if (IS_ERR(clk))
266                 return dev_err_probe(&pdev->dev, PTR_ERR(clk),
267                                      "Failed to get clock from Device Tree\n");
268
269         res = clk_prepare_enable(clk);
270         if (res)
271                 return res;
272
273         memset(&brcmstb_pdata, 0, sizeof(brcmstb_pdata));
274         brcmstb_pdata.ops = match_priv->ops;
275         host = sdhci_pltfm_init(pdev, &brcmstb_pdata,
276                                 sizeof(struct sdhci_brcmstb_priv));
277         if (IS_ERR(host)) {
278                 res = PTR_ERR(host);
279                 goto err_clk;
280         }
281
282         pltfm_host = sdhci_priv(host);
283         priv = sdhci_pltfm_priv(pltfm_host);
284         if (device_property_read_bool(&pdev->dev, "supports-cqe")) {
285                 priv->flags |= BRCMSTB_PRIV_FLAGS_HAS_CQE;
286                 match_priv->ops->irq = sdhci_brcmstb_cqhci_irq;
287         }
288
289         /* Map in the non-standard CFG registers */
290         iomem = platform_get_resource(pdev, IORESOURCE_MEM, 1);
291         priv->cfg_regs = devm_ioremap_resource(&pdev->dev, iomem);
292         if (IS_ERR(priv->cfg_regs)) {
293                 res = PTR_ERR(priv->cfg_regs);
294                 goto err;
295         }
296
297         sdhci_get_of_property(pdev);
298         res = mmc_of_parse(host->mmc);
299         if (res)
300                 goto err;
301
302         /*
303          * Automatic clock gating does not work for SD cards that may
304          * voltage switch so only enable it for non-removable devices.
305          */
306         if ((match_priv->flags & BRCMSTB_MATCH_FLAGS_HAS_CLOCK_GATE) &&
307             (host->mmc->caps & MMC_CAP_NONREMOVABLE))
308                 priv->flags |= BRCMSTB_PRIV_FLAGS_GATE_CLOCK;
309
310         /*
311          * If the chip has enhanced strobe and it's enabled, add
312          * callback
313          */
314         if (match_priv->hs400es &&
315             (host->mmc->caps2 & MMC_CAP2_HS400_ES))
316                 host->mmc_host_ops.hs400_enhanced_strobe = match_priv->hs400es;
317
318         /*
319          * Supply the existing CAPS, but clear the UHS modes. This
320          * will allow these modes to be specified by device tree
321          * properties through mmc_of_parse().
322          */
323         host->caps = sdhci_readl(host, SDHCI_CAPABILITIES);
324         if (match_priv->flags & BRCMSTB_MATCH_FLAGS_NO_64BIT)
325                 host->caps &= ~SDHCI_CAN_64BIT;
326         host->caps1 = sdhci_readl(host, SDHCI_CAPABILITIES_1);
327         host->caps1 &= ~(SDHCI_SUPPORT_SDR50 | SDHCI_SUPPORT_SDR104 |
328                          SDHCI_SUPPORT_DDR50);
329         host->quirks |= SDHCI_QUIRK_MISSING_CAPS;
330
331         if (match_priv->flags & BRCMSTB_MATCH_FLAGS_BROKEN_TIMEOUT)
332                 host->quirks |= SDHCI_QUIRK_BROKEN_TIMEOUT_VAL;
333
334         res = sdhci_brcmstb_add_host(host, priv);
335         if (res)
336                 goto err;
337
338         pltfm_host->clk = clk;
339         return res;
340
341 err:
342         sdhci_pltfm_free(pdev);
343 err_clk:
344         clk_disable_unprepare(clk);
345         return res;
346 }
347
348 static void sdhci_brcmstb_shutdown(struct platform_device *pdev)
349 {
350         sdhci_pltfm_suspend(&pdev->dev);
351 }
352
353 MODULE_DEVICE_TABLE(of, sdhci_brcm_of_match);
354
355 static struct platform_driver sdhci_brcmstb_driver = {
356         .driver         = {
357                 .name   = "sdhci-brcmstb",
358                 .probe_type = PROBE_PREFER_ASYNCHRONOUS,
359                 .pm     = &sdhci_pltfm_pmops,
360                 .of_match_table = of_match_ptr(sdhci_brcm_of_match),
361         },
362         .probe          = sdhci_brcmstb_probe,
363         .remove         = sdhci_pltfm_unregister,
364         .shutdown       = sdhci_brcmstb_shutdown,
365 };
366
367 module_platform_driver(sdhci_brcmstb_driver);
368
369 MODULE_DESCRIPTION("SDHCI driver for Broadcom BRCMSTB SoCs");
370 MODULE_AUTHOR("Broadcom");
371 MODULE_LICENSE("GPL v2");