1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | // Copyright (C) 2014 Broadcom Corporation |
3 | |
4 | /* |
5 | * iProc SDHCI platform driver |
6 | */ |
7 | |
8 | #include <linux/acpi.h> |
9 | #include <linux/delay.h> |
10 | #include <linux/module.h> |
11 | #include <linux/mmc/host.h> |
12 | #include <linux/of.h> |
13 | #include <linux/platform_device.h> |
14 | #include "sdhci-pltfm.h" |
15 | |
16 | struct sdhci_iproc_data { |
17 | const struct sdhci_pltfm_data *pdata; |
18 | u32 caps; |
19 | u32 caps1; |
20 | u32 mmc_caps; |
21 | bool missing_caps; |
22 | }; |
23 | |
24 | struct sdhci_iproc_host { |
25 | const struct sdhci_iproc_data *data; |
26 | u32 shadow_cmd; |
27 | u32 shadow_blk; |
28 | bool is_cmd_shadowed; |
29 | bool is_blk_shadowed; |
30 | }; |
31 | |
32 | #define REG_OFFSET_IN_BITS(reg) ((reg) << 3 & 0x18) |
33 | |
34 | static inline u32 sdhci_iproc_readl(struct sdhci_host *host, int reg) |
35 | { |
36 | u32 val = readl(addr: host->ioaddr + reg); |
37 | |
38 | pr_debug("%s: readl [0x%02x] 0x%08x\n" , |
39 | mmc_hostname(host->mmc), reg, val); |
40 | return val; |
41 | } |
42 | |
43 | static u16 sdhci_iproc_readw(struct sdhci_host *host, int reg) |
44 | { |
45 | struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); |
46 | struct sdhci_iproc_host *iproc_host = sdhci_pltfm_priv(host: pltfm_host); |
47 | u32 val; |
48 | u16 word; |
49 | |
50 | if ((reg == SDHCI_TRANSFER_MODE) && iproc_host->is_cmd_shadowed) { |
51 | /* Get the saved transfer mode */ |
52 | val = iproc_host->shadow_cmd; |
53 | } else if ((reg == SDHCI_BLOCK_SIZE || reg == SDHCI_BLOCK_COUNT) && |
54 | iproc_host->is_blk_shadowed) { |
55 | /* Get the saved block info */ |
56 | val = iproc_host->shadow_blk; |
57 | } else { |
58 | val = sdhci_iproc_readl(host, reg: (reg & ~3)); |
59 | } |
60 | word = val >> REG_OFFSET_IN_BITS(reg) & 0xffff; |
61 | return word; |
62 | } |
63 | |
64 | static u8 sdhci_iproc_readb(struct sdhci_host *host, int reg) |
65 | { |
66 | u32 val = sdhci_iproc_readl(host, reg: (reg & ~3)); |
67 | u8 byte = val >> REG_OFFSET_IN_BITS(reg) & 0xff; |
68 | return byte; |
69 | } |
70 | |
71 | static inline void sdhci_iproc_writel(struct sdhci_host *host, u32 val, int reg) |
72 | { |
73 | pr_debug("%s: writel [0x%02x] 0x%08x\n" , |
74 | mmc_hostname(host->mmc), reg, val); |
75 | |
76 | writel(val, addr: host->ioaddr + reg); |
77 | |
78 | if (host->clock <= 400000) { |
79 | /* Round up to micro-second four SD clock delay */ |
80 | if (host->clock) |
81 | udelay((4 * 1000000 + host->clock - 1) / host->clock); |
82 | else |
83 | udelay(10); |
84 | } |
85 | } |
86 | |
87 | /* |
88 | * The Arasan has a bugette whereby it may lose the content of successive |
89 | * writes to the same register that are within two SD-card clock cycles of |
90 | * each other (a clock domain crossing problem). The data |
91 | * register does not have this problem, which is just as well - otherwise we'd |
92 | * have to nobble the DMA engine too. |
93 | * |
94 | * This wouldn't be a problem with the code except that we can only write the |
95 | * controller with 32-bit writes. So two different 16-bit registers are |
96 | * written back to back creates the problem. |
97 | * |
98 | * In reality, this only happens when SDHCI_BLOCK_SIZE and SDHCI_BLOCK_COUNT |
99 | * are written followed by SDHCI_TRANSFER_MODE and SDHCI_COMMAND. |
100 | * The BLOCK_SIZE and BLOCK_COUNT are meaningless until a command issued so |
101 | * the work around can be further optimized. We can keep shadow values of |
102 | * BLOCK_SIZE, BLOCK_COUNT, and TRANSFER_MODE until a COMMAND is issued. |
103 | * Then, write the BLOCK_SIZE+BLOCK_COUNT in a single 32-bit write followed |
104 | * by the TRANSFER+COMMAND in another 32-bit write. |
105 | */ |
106 | static void sdhci_iproc_writew(struct sdhci_host *host, u16 val, int reg) |
107 | { |
108 | struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); |
109 | struct sdhci_iproc_host *iproc_host = sdhci_pltfm_priv(host: pltfm_host); |
110 | u32 word_shift = REG_OFFSET_IN_BITS(reg); |
111 | u32 mask = 0xffff << word_shift; |
112 | u32 oldval, newval; |
113 | |
114 | if (reg == SDHCI_COMMAND) { |
115 | /* Write the block now as we are issuing a command */ |
116 | if (iproc_host->is_blk_shadowed) { |
117 | sdhci_iproc_writel(host, val: iproc_host->shadow_blk, |
118 | SDHCI_BLOCK_SIZE); |
119 | iproc_host->is_blk_shadowed = false; |
120 | } |
121 | oldval = iproc_host->shadow_cmd; |
122 | iproc_host->is_cmd_shadowed = false; |
123 | } else if ((reg == SDHCI_BLOCK_SIZE || reg == SDHCI_BLOCK_COUNT) && |
124 | iproc_host->is_blk_shadowed) { |
125 | /* Block size and count are stored in shadow reg */ |
126 | oldval = iproc_host->shadow_blk; |
127 | } else { |
128 | /* Read reg, all other registers are not shadowed */ |
129 | oldval = sdhci_iproc_readl(host, reg: (reg & ~3)); |
130 | } |
131 | newval = (oldval & ~mask) | (val << word_shift); |
132 | |
133 | if (reg == SDHCI_TRANSFER_MODE) { |
134 | /* Save the transfer mode until the command is issued */ |
135 | iproc_host->shadow_cmd = newval; |
136 | iproc_host->is_cmd_shadowed = true; |
137 | } else if (reg == SDHCI_BLOCK_SIZE || reg == SDHCI_BLOCK_COUNT) { |
138 | /* Save the block info until the command is issued */ |
139 | iproc_host->shadow_blk = newval; |
140 | iproc_host->is_blk_shadowed = true; |
141 | } else { |
142 | /* Command or other regular 32-bit write */ |
143 | sdhci_iproc_writel(host, val: newval, reg: reg & ~3); |
144 | } |
145 | } |
146 | |
147 | static void sdhci_iproc_writeb(struct sdhci_host *host, u8 val, int reg) |
148 | { |
149 | u32 oldval = sdhci_iproc_readl(host, reg: (reg & ~3)); |
150 | u32 byte_shift = REG_OFFSET_IN_BITS(reg); |
151 | u32 mask = 0xff << byte_shift; |
152 | u32 newval = (oldval & ~mask) | (val << byte_shift); |
153 | |
154 | sdhci_iproc_writel(host, val: newval, reg: reg & ~3); |
155 | } |
156 | |
157 | static unsigned int sdhci_iproc_get_max_clock(struct sdhci_host *host) |
158 | { |
159 | struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); |
160 | |
161 | if (pltfm_host->clk) |
162 | return sdhci_pltfm_clk_get_max_clock(host); |
163 | else |
164 | return pltfm_host->clock; |
165 | } |
166 | |
167 | /* |
168 | * There is a known bug on BCM2711's SDHCI core integration where the |
169 | * controller will hang when the difference between the core clock and the bus |
170 | * clock is too great. Specifically this can be reproduced under the following |
171 | * conditions: |
172 | * |
173 | * - No SD card plugged in, polling thread is running, probing cards at |
174 | * 100 kHz. |
175 | * - BCM2711's core clock configured at 500MHz or more |
176 | * |
177 | * So we set 200kHz as the minimum clock frequency available for that SoC. |
178 | */ |
179 | static unsigned int sdhci_iproc_bcm2711_get_min_clock(struct sdhci_host *host) |
180 | { |
181 | return 200000; |
182 | } |
183 | |
184 | static const struct sdhci_ops sdhci_iproc_ops = { |
185 | .set_clock = sdhci_set_clock, |
186 | .get_max_clock = sdhci_iproc_get_max_clock, |
187 | .set_bus_width = sdhci_set_bus_width, |
188 | .reset = sdhci_reset, |
189 | .set_uhs_signaling = sdhci_set_uhs_signaling, |
190 | }; |
191 | |
192 | static const struct sdhci_ops sdhci_iproc_32only_ops = { |
193 | .read_l = sdhci_iproc_readl, |
194 | .read_w = sdhci_iproc_readw, |
195 | .read_b = sdhci_iproc_readb, |
196 | .write_l = sdhci_iproc_writel, |
197 | .write_w = sdhci_iproc_writew, |
198 | .write_b = sdhci_iproc_writeb, |
199 | .set_clock = sdhci_set_clock, |
200 | .get_max_clock = sdhci_iproc_get_max_clock, |
201 | .set_bus_width = sdhci_set_bus_width, |
202 | .reset = sdhci_reset, |
203 | .set_uhs_signaling = sdhci_set_uhs_signaling, |
204 | }; |
205 | |
206 | static const struct sdhci_pltfm_data sdhci_iproc_cygnus_pltfm_data = { |
207 | .quirks = SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK | |
208 | SDHCI_QUIRK_NO_HISPD_BIT, |
209 | .quirks2 = SDHCI_QUIRK2_ACMD23_BROKEN | SDHCI_QUIRK2_HOST_OFF_CARD_ON, |
210 | .ops = &sdhci_iproc_32only_ops, |
211 | }; |
212 | |
213 | static const struct sdhci_iproc_data iproc_cygnus_data = { |
214 | .pdata = &sdhci_iproc_cygnus_pltfm_data, |
215 | .caps = ((0x1 << SDHCI_MAX_BLOCK_SHIFT) |
216 | & SDHCI_MAX_BLOCK_MASK) | |
217 | SDHCI_CAN_VDD_330 | |
218 | SDHCI_CAN_VDD_180 | |
219 | SDHCI_CAN_DO_SUSPEND | |
220 | SDHCI_CAN_DO_HISPD | |
221 | SDHCI_CAN_DO_ADMA2 | |
222 | SDHCI_CAN_DO_SDMA, |
223 | .caps1 = SDHCI_DRIVER_TYPE_C | |
224 | SDHCI_DRIVER_TYPE_D | |
225 | SDHCI_SUPPORT_DDR50, |
226 | .mmc_caps = MMC_CAP_1_8V_DDR, |
227 | }; |
228 | |
229 | static const struct sdhci_pltfm_data sdhci_iproc_pltfm_data = { |
230 | .quirks = SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK | |
231 | SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12 | |
232 | SDHCI_QUIRK_NO_HISPD_BIT, |
233 | .quirks2 = SDHCI_QUIRK2_ACMD23_BROKEN, |
234 | .ops = &sdhci_iproc_ops, |
235 | }; |
236 | |
237 | static const struct sdhci_iproc_data iproc_data = { |
238 | .pdata = &sdhci_iproc_pltfm_data, |
239 | .caps = ((0x1 << SDHCI_MAX_BLOCK_SHIFT) |
240 | & SDHCI_MAX_BLOCK_MASK) | |
241 | SDHCI_CAN_VDD_330 | |
242 | SDHCI_CAN_VDD_180 | |
243 | SDHCI_CAN_DO_SUSPEND | |
244 | SDHCI_CAN_DO_HISPD | |
245 | SDHCI_CAN_DO_ADMA2 | |
246 | SDHCI_CAN_DO_SDMA, |
247 | .caps1 = SDHCI_DRIVER_TYPE_C | |
248 | SDHCI_DRIVER_TYPE_D | |
249 | SDHCI_SUPPORT_DDR50, |
250 | }; |
251 | |
252 | static const struct sdhci_pltfm_data sdhci_bcm2835_pltfm_data = { |
253 | .quirks = SDHCI_QUIRK_BROKEN_CARD_DETECTION | |
254 | SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK | |
255 | SDHCI_QUIRK_NO_HISPD_BIT, |
256 | .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN, |
257 | .ops = &sdhci_iproc_32only_ops, |
258 | }; |
259 | |
260 | static const struct sdhci_iproc_data bcm2835_data = { |
261 | .pdata = &sdhci_bcm2835_pltfm_data, |
262 | .caps = ((0x1 << SDHCI_MAX_BLOCK_SHIFT) |
263 | & SDHCI_MAX_BLOCK_MASK) | |
264 | SDHCI_CAN_VDD_330 | |
265 | SDHCI_CAN_DO_HISPD, |
266 | .caps1 = SDHCI_DRIVER_TYPE_A | |
267 | SDHCI_DRIVER_TYPE_C, |
268 | .mmc_caps = 0x00000000, |
269 | .missing_caps = true, |
270 | }; |
271 | |
272 | static const struct sdhci_ops sdhci_iproc_bcm2711_ops = { |
273 | .read_l = sdhci_iproc_readl, |
274 | .read_w = sdhci_iproc_readw, |
275 | .read_b = sdhci_iproc_readb, |
276 | .write_l = sdhci_iproc_writel, |
277 | .write_w = sdhci_iproc_writew, |
278 | .write_b = sdhci_iproc_writeb, |
279 | .set_clock = sdhci_set_clock, |
280 | .set_power = sdhci_set_power_and_bus_voltage, |
281 | .get_max_clock = sdhci_iproc_get_max_clock, |
282 | .get_min_clock = sdhci_iproc_bcm2711_get_min_clock, |
283 | .set_bus_width = sdhci_set_bus_width, |
284 | .reset = sdhci_reset, |
285 | .set_uhs_signaling = sdhci_set_uhs_signaling, |
286 | }; |
287 | |
288 | static const struct sdhci_pltfm_data sdhci_bcm2711_pltfm_data = { |
289 | .quirks = SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12, |
290 | .ops = &sdhci_iproc_bcm2711_ops, |
291 | }; |
292 | |
293 | static const struct sdhci_iproc_data bcm2711_data = { |
294 | .pdata = &sdhci_bcm2711_pltfm_data, |
295 | .mmc_caps = MMC_CAP_3_3V_DDR, |
296 | }; |
297 | |
298 | static const struct sdhci_pltfm_data sdhci_bcm7211a0_pltfm_data = { |
299 | .quirks = SDHCI_QUIRK_BROKEN_TIMEOUT_VAL | |
300 | SDHCI_QUIRK_BROKEN_DMA | |
301 | SDHCI_QUIRK_BROKEN_ADMA, |
302 | .ops = &sdhci_iproc_ops, |
303 | }; |
304 | |
305 | #define BCM7211A0_BASE_CLK_MHZ 100 |
306 | static const struct sdhci_iproc_data bcm7211a0_data = { |
307 | .pdata = &sdhci_bcm7211a0_pltfm_data, |
308 | .caps = ((BCM7211A0_BASE_CLK_MHZ / 2) << SDHCI_TIMEOUT_CLK_SHIFT) | |
309 | (BCM7211A0_BASE_CLK_MHZ << SDHCI_CLOCK_BASE_SHIFT) | |
310 | ((0x2 << SDHCI_MAX_BLOCK_SHIFT) |
311 | & SDHCI_MAX_BLOCK_MASK) | |
312 | SDHCI_CAN_VDD_330 | |
313 | SDHCI_CAN_VDD_180 | |
314 | SDHCI_CAN_DO_SUSPEND | |
315 | SDHCI_CAN_DO_HISPD, |
316 | .caps1 = SDHCI_DRIVER_TYPE_C | |
317 | SDHCI_DRIVER_TYPE_D, |
318 | .missing_caps = true, |
319 | }; |
320 | |
321 | static const struct of_device_id sdhci_iproc_of_match[] = { |
322 | { .compatible = "brcm,bcm2835-sdhci" , .data = &bcm2835_data }, |
323 | { .compatible = "brcm,bcm2711-emmc2" , .data = &bcm2711_data }, |
324 | { .compatible = "brcm,sdhci-iproc-cygnus" , .data = &iproc_cygnus_data}, |
325 | { .compatible = "brcm,sdhci-iproc" , .data = &iproc_data }, |
326 | { .compatible = "brcm,bcm7211a0-sdhci" , .data = &bcm7211a0_data }, |
327 | { } |
328 | }; |
329 | MODULE_DEVICE_TABLE(of, sdhci_iproc_of_match); |
330 | |
331 | #ifdef CONFIG_ACPI |
332 | /* |
333 | * This is a duplicate of bcm2835_(pltfrm_)data without caps quirks |
334 | * which are provided by the ACPI table. |
335 | */ |
336 | static const struct sdhci_pltfm_data sdhci_bcm_arasan_data = { |
337 | .quirks = SDHCI_QUIRK_BROKEN_CARD_DETECTION | |
338 | SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK | |
339 | SDHCI_QUIRK_NO_HISPD_BIT, |
340 | .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN, |
341 | .ops = &sdhci_iproc_32only_ops, |
342 | }; |
343 | |
344 | static const struct sdhci_iproc_data bcm_arasan_data = { |
345 | .pdata = &sdhci_bcm_arasan_data, |
346 | }; |
347 | |
348 | static const struct acpi_device_id sdhci_iproc_acpi_ids[] = { |
349 | { .id = "BRCM5871" , .driver_data = (kernel_ulong_t)&iproc_cygnus_data }, |
350 | { .id = "BRCM5872" , .driver_data = (kernel_ulong_t)&iproc_data }, |
351 | { .id = "BCM2847" , .driver_data = (kernel_ulong_t)&bcm_arasan_data }, |
352 | { .id = "BRCME88C" , .driver_data = (kernel_ulong_t)&bcm2711_data }, |
353 | { /* sentinel */ } |
354 | }; |
355 | MODULE_DEVICE_TABLE(acpi, sdhci_iproc_acpi_ids); |
356 | #endif |
357 | |
358 | static int sdhci_iproc_probe(struct platform_device *pdev) |
359 | { |
360 | struct device *dev = &pdev->dev; |
361 | const struct sdhci_iproc_data *iproc_data = NULL; |
362 | struct sdhci_host *host; |
363 | struct sdhci_iproc_host *iproc_host; |
364 | struct sdhci_pltfm_host *pltfm_host; |
365 | int ret; |
366 | |
367 | iproc_data = device_get_match_data(dev); |
368 | if (!iproc_data) |
369 | return -ENODEV; |
370 | |
371 | host = sdhci_pltfm_init(pdev, pdata: iproc_data->pdata, priv_size: sizeof(*iproc_host)); |
372 | if (IS_ERR(ptr: host)) |
373 | return PTR_ERR(ptr: host); |
374 | |
375 | pltfm_host = sdhci_priv(host); |
376 | iproc_host = sdhci_pltfm_priv(host: pltfm_host); |
377 | |
378 | iproc_host->data = iproc_data; |
379 | |
380 | ret = mmc_of_parse(host: host->mmc); |
381 | if (ret) |
382 | goto err; |
383 | |
384 | sdhci_get_property(pdev); |
385 | |
386 | host->mmc->caps |= iproc_host->data->mmc_caps; |
387 | |
388 | if (dev->of_node) { |
389 | pltfm_host->clk = devm_clk_get_enabled(dev, NULL); |
390 | if (IS_ERR(ptr: pltfm_host->clk)) { |
391 | ret = PTR_ERR(ptr: pltfm_host->clk); |
392 | goto err; |
393 | } |
394 | } |
395 | |
396 | if (iproc_host->data->missing_caps) { |
397 | __sdhci_read_caps(host, NULL, |
398 | caps: &iproc_host->data->caps, |
399 | caps1: &iproc_host->data->caps1); |
400 | } |
401 | |
402 | ret = sdhci_add_host(host); |
403 | if (ret) |
404 | goto err; |
405 | |
406 | return 0; |
407 | |
408 | err: |
409 | sdhci_pltfm_free(pdev); |
410 | return ret; |
411 | } |
412 | |
413 | static void sdhci_iproc_shutdown(struct platform_device *pdev) |
414 | { |
415 | sdhci_pltfm_suspend(dev: &pdev->dev); |
416 | } |
417 | |
418 | static struct platform_driver sdhci_iproc_driver = { |
419 | .driver = { |
420 | .name = "sdhci-iproc" , |
421 | .probe_type = PROBE_PREFER_ASYNCHRONOUS, |
422 | .of_match_table = sdhci_iproc_of_match, |
423 | .acpi_match_table = ACPI_PTR(sdhci_iproc_acpi_ids), |
424 | .pm = &sdhci_pltfm_pmops, |
425 | }, |
426 | .probe = sdhci_iproc_probe, |
427 | .remove_new = sdhci_pltfm_remove, |
428 | .shutdown = sdhci_iproc_shutdown, |
429 | }; |
430 | module_platform_driver(sdhci_iproc_driver); |
431 | |
432 | MODULE_AUTHOR("Broadcom" ); |
433 | MODULE_DESCRIPTION("IPROC SDHCI driver" ); |
434 | MODULE_LICENSE("GPL v2" ); |
435 | |