.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0 |
---|
1 | 2 | /* |
---|
2 | 3 | * DMA support for Internal DMAC with SDHI SD/SDIO controller |
---|
3 | 4 | * |
---|
4 | | - * Copyright (C) 2016-17 Renesas Electronics Corporation |
---|
| 5 | + * Copyright (C) 2016-19 Renesas Electronics Corporation |
---|
5 | 6 | * Copyright (C) 2016-17 Horms Solutions, Simon Horman |
---|
6 | | - * |
---|
7 | | - * This program is free software; you can redistribute it and/or modify |
---|
8 | | - * it under the terms of the GNU General Public License version 2 as |
---|
9 | | - * published by the Free Software Foundation. |
---|
| 7 | + * Copyright (C) 2018-19 Sang Engineering, Wolfram Sang |
---|
10 | 8 | */ |
---|
11 | 9 | |
---|
12 | 10 | #include <linux/bitops.h> |
---|
.. | .. |
---|
35 | 33 | |
---|
36 | 34 | /* DM_CM_DTRAN_MODE */ |
---|
37 | 35 | #define DTRAN_MODE_CH_NUM_CH0 0 /* "downstream" = for write commands */ |
---|
38 | | -#define DTRAN_MODE_CH_NUM_CH1 BIT(16) /* "uptream" = for read commands */ |
---|
39 | | -#define DTRAN_MODE_BUS_WID_TH (BIT(5) | BIT(4)) |
---|
40 | | -#define DTRAN_MODE_ADDR_MODE BIT(0) /* 1 = Increment address */ |
---|
| 36 | +#define DTRAN_MODE_CH_NUM_CH1 BIT(16) /* "upstream" = for read commands */ |
---|
| 37 | +#define DTRAN_MODE_BUS_WIDTH (BIT(5) | BIT(4)) |
---|
| 38 | +#define DTRAN_MODE_ADDR_MODE BIT(0) /* 1 = Increment address, 0 = Fixed */ |
---|
41 | 39 | |
---|
42 | 40 | /* DM_CM_DTRAN_CTRL */ |
---|
43 | 41 | #define DTRAN_CTRL_DM_START BIT(0) |
---|
.. | .. |
---|
76 | 74 | #define SDHI_INTERNAL_DMAC_ONE_RX_ONLY 0 |
---|
77 | 75 | #define SDHI_INTERNAL_DMAC_RX_IN_USE 1 |
---|
78 | 76 | |
---|
| 77 | +/* RZ/A2 does not have the ADRR_MODE bit */ |
---|
| 78 | +#define SDHI_INTERNAL_DMAC_ADDR_MODE_FIXED_ONLY 2 |
---|
| 79 | + |
---|
79 | 80 | /* Definitions for sampling clocks */ |
---|
80 | 81 | static struct renesas_sdhi_scc rcar_gen3_scc_taps[] = { |
---|
81 | 82 | { |
---|
82 | 83 | .clk_rate = 0, |
---|
83 | 84 | .tap = 0x00000300, |
---|
| 85 | + .tap_hs400_4tap = 0x00000100, |
---|
84 | 86 | }, |
---|
85 | 87 | }; |
---|
86 | 88 | |
---|
87 | | -static const struct renesas_sdhi_of_data of_rcar_r8a7795_compatible = { |
---|
| 89 | +static const struct renesas_sdhi_of_data of_rza2_compatible = { |
---|
88 | 90 | .tmio_flags = TMIO_MMC_HAS_IDLE_WAIT | TMIO_MMC_CLK_ACTUAL | |
---|
89 | | - TMIO_MMC_HAVE_CBSY | TMIO_MMC_MIN_RCAR2 | |
---|
90 | | - TMIO_MMC_HAVE_4TAP_HS400, |
---|
| 91 | + TMIO_MMC_HAVE_CBSY, |
---|
| 92 | + .tmio_ocr_mask = MMC_VDD_32_33, |
---|
91 | 93 | .capabilities = MMC_CAP_SD_HIGHSPEED | MMC_CAP_SDIO_IRQ | |
---|
92 | 94 | MMC_CAP_CMD23, |
---|
93 | | - .capabilities2 = MMC_CAP2_NO_WRITE_PROTECT, |
---|
94 | 95 | .bus_shift = 2, |
---|
95 | | - .scc_offset = 0x1000, |
---|
| 96 | + .scc_offset = 0 - 0x1000, |
---|
96 | 97 | .taps = rcar_gen3_scc_taps, |
---|
97 | 98 | .taps_num = ARRAY_SIZE(rcar_gen3_scc_taps), |
---|
98 | | - /* DMAC can handle 0xffffffff blk count but only 1 segment */ |
---|
99 | | - .max_blk_count = 0xffffffff, |
---|
| 99 | + /* DMAC can handle 32bit blk count but only 1 segment */ |
---|
| 100 | + .max_blk_count = UINT_MAX / TMIO_MAX_BLK_SIZE, |
---|
100 | 101 | .max_segs = 1, |
---|
101 | 102 | }; |
---|
102 | 103 | |
---|
.. | .. |
---|
105 | 106 | TMIO_MMC_HAVE_CBSY | TMIO_MMC_MIN_RCAR2, |
---|
106 | 107 | .capabilities = MMC_CAP_SD_HIGHSPEED | MMC_CAP_SDIO_IRQ | |
---|
107 | 108 | MMC_CAP_CMD23, |
---|
108 | | - .capabilities2 = MMC_CAP2_NO_WRITE_PROTECT, |
---|
| 109 | + .capabilities2 = MMC_CAP2_NO_WRITE_PROTECT | MMC_CAP2_MERGE_CAPABLE, |
---|
109 | 110 | .bus_shift = 2, |
---|
110 | 111 | .scc_offset = 0x1000, |
---|
111 | 112 | .taps = rcar_gen3_scc_taps, |
---|
112 | 113 | .taps_num = ARRAY_SIZE(rcar_gen3_scc_taps), |
---|
113 | | - /* DMAC can handle 0xffffffff blk count but only 1 segment */ |
---|
114 | | - .max_blk_count = 0xffffffff, |
---|
| 114 | + /* DMAC can handle 32bit blk count but only 1 segment */ |
---|
| 115 | + .max_blk_count = UINT_MAX / TMIO_MAX_BLK_SIZE, |
---|
115 | 116 | .max_segs = 1, |
---|
116 | 117 | }; |
---|
117 | 118 | |
---|
118 | 119 | static const struct of_device_id renesas_sdhi_internal_dmac_of_match[] = { |
---|
119 | | - { .compatible = "renesas,sdhi-r8a7795", .data = &of_rcar_r8a7795_compatible, }, |
---|
120 | | - { .compatible = "renesas,sdhi-r8a7796", .data = &of_rcar_r8a7795_compatible, }, |
---|
| 120 | + { .compatible = "renesas,sdhi-r7s9210", .data = &of_rza2_compatible, }, |
---|
| 121 | + { .compatible = "renesas,sdhi-mmc-r8a77470", .data = &of_rcar_gen3_compatible, }, |
---|
| 122 | + { .compatible = "renesas,sdhi-r8a7795", .data = &of_rcar_gen3_compatible, }, |
---|
| 123 | + { .compatible = "renesas,sdhi-r8a7796", .data = &of_rcar_gen3_compatible, }, |
---|
121 | 124 | { .compatible = "renesas,rcar-gen3-sdhi", .data = &of_rcar_gen3_compatible, }, |
---|
122 | 125 | {}, |
---|
123 | 126 | }; |
---|
.. | .. |
---|
174 | 177 | struct mmc_data *data) |
---|
175 | 178 | { |
---|
176 | 179 | struct scatterlist *sg = host->sg_ptr; |
---|
177 | | - u32 dtran_mode = DTRAN_MODE_BUS_WID_TH | DTRAN_MODE_ADDR_MODE; |
---|
| 180 | + u32 dtran_mode = DTRAN_MODE_BUS_WIDTH; |
---|
| 181 | + |
---|
| 182 | + if (!test_bit(SDHI_INTERNAL_DMAC_ADDR_MODE_FIXED_ONLY, &global_flags)) |
---|
| 183 | + dtran_mode |= DTRAN_MODE_ADDR_MODE; |
---|
178 | 184 | |
---|
179 | 185 | if (!dma_map_sg(&host->pdev->dev, sg, host->sg_len, |
---|
180 | 186 | mmc_get_dma_dir(data))) |
---|
.. | .. |
---|
201 | 207 | renesas_sdhi_internal_dmac_dm_write(host, DM_DTRAN_ADDR, |
---|
202 | 208 | sg_dma_address(sg)); |
---|
203 | 209 | |
---|
| 210 | + host->dma_on = true; |
---|
| 211 | + |
---|
204 | 212 | return; |
---|
205 | 213 | |
---|
206 | 214 | force_pio_with_unmap: |
---|
207 | 215 | dma_unmap_sg(&host->pdev->dev, sg, host->sg_len, mmc_get_dma_dir(data)); |
---|
208 | 216 | |
---|
209 | 217 | force_pio: |
---|
210 | | - host->force_pio = true; |
---|
211 | 218 | renesas_sdhi_internal_dmac_enable_dma(host, false); |
---|
212 | 219 | } |
---|
213 | 220 | |
---|
.. | .. |
---|
226 | 233 | { |
---|
227 | 234 | enum dma_data_direction dir; |
---|
228 | 235 | |
---|
| 236 | + if (!host->dma_on) |
---|
| 237 | + return false; |
---|
| 238 | + |
---|
229 | 239 | if (!host->data) |
---|
230 | 240 | return false; |
---|
231 | 241 | |
---|
.. | .. |
---|
239 | 249 | |
---|
240 | 250 | if (dir == DMA_FROM_DEVICE) |
---|
241 | 251 | clear_bit(SDHI_INTERNAL_DMAC_RX_IN_USE, &global_flags); |
---|
| 252 | + |
---|
| 253 | + host->dma_on = false; |
---|
242 | 254 | |
---|
243 | 255 | return true; |
---|
244 | 256 | } |
---|
.. | .. |
---|
254 | 266 | tmio_mmc_do_data_irq(host); |
---|
255 | 267 | out: |
---|
256 | 268 | spin_unlock_irq(&host->lock); |
---|
| 269 | +} |
---|
| 270 | + |
---|
| 271 | +static void renesas_sdhi_internal_dmac_end_dma(struct tmio_mmc_host *host) |
---|
| 272 | +{ |
---|
| 273 | + if (host->data) |
---|
| 274 | + renesas_sdhi_internal_dmac_complete(host); |
---|
257 | 275 | } |
---|
258 | 276 | |
---|
259 | 277 | static void |
---|
.. | .. |
---|
293 | 311 | .release = renesas_sdhi_internal_dmac_release_dma, |
---|
294 | 312 | .abort = renesas_sdhi_internal_dmac_abort_dma, |
---|
295 | 313 | .dataend = renesas_sdhi_internal_dmac_dataend_dma, |
---|
| 314 | + .end = renesas_sdhi_internal_dmac_end_dma, |
---|
296 | 315 | }; |
---|
297 | 316 | |
---|
298 | 317 | /* |
---|
299 | 318 | * Whitelist of specific R-Car Gen3 SoC ES versions to use this DMAC |
---|
300 | 319 | * implementation as others may use a different implementation. |
---|
301 | 320 | */ |
---|
302 | | -static const struct soc_device_attribute gen3_soc_whitelist[] = { |
---|
303 | | - /* specific ones */ |
---|
| 321 | +static const struct soc_device_attribute soc_dma_quirks[] = { |
---|
| 322 | + { .soc_id = "r7s9210", |
---|
| 323 | + .data = (void *)BIT(SDHI_INTERNAL_DMAC_ADDR_MODE_FIXED_ONLY) }, |
---|
304 | 324 | { .soc_id = "r8a7795", .revision = "ES1.*", |
---|
305 | 325 | .data = (void *)BIT(SDHI_INTERNAL_DMAC_ONE_RX_ONLY) }, |
---|
306 | 326 | { .soc_id = "r8a7796", .revision = "ES1.0", |
---|
307 | 327 | .data = (void *)BIT(SDHI_INTERNAL_DMAC_ONE_RX_ONLY) }, |
---|
308 | | - /* generic ones */ |
---|
309 | | - { .soc_id = "r8a774a1" }, |
---|
310 | | - { .soc_id = "r8a7795" }, |
---|
311 | | - { .soc_id = "r8a7796" }, |
---|
312 | | - { .soc_id = "r8a77965" }, |
---|
313 | | - { .soc_id = "r8a77980" }, |
---|
314 | | - { .soc_id = "r8a77995" }, |
---|
315 | 328 | { /* sentinel */ } |
---|
316 | 329 | }; |
---|
317 | 330 | |
---|
318 | 331 | static int renesas_sdhi_internal_dmac_probe(struct platform_device *pdev) |
---|
319 | 332 | { |
---|
320 | | - const struct soc_device_attribute *soc = soc_device_match(gen3_soc_whitelist); |
---|
| 333 | + const struct soc_device_attribute *soc = soc_device_match(soc_dma_quirks); |
---|
321 | 334 | struct device *dev = &pdev->dev; |
---|
322 | 335 | |
---|
323 | | - if (!soc) |
---|
324 | | - return -ENODEV; |
---|
325 | | - |
---|
326 | | - global_flags |= (unsigned long)soc->data; |
---|
327 | | - |
---|
328 | | - dev->dma_parms = devm_kzalloc(dev, sizeof(*dev->dma_parms), GFP_KERNEL); |
---|
329 | | - if (!dev->dma_parms) |
---|
330 | | - return -ENOMEM; |
---|
| 336 | + if (soc) |
---|
| 337 | + global_flags |= (unsigned long)soc->data; |
---|
331 | 338 | |
---|
332 | 339 | /* value is max of SD_SECCNT. Confirmed by HW engineers */ |
---|
333 | 340 | dma_set_max_seg_size(dev, 0xffffffff); |
---|
.. | .. |
---|
346 | 353 | static struct platform_driver renesas_internal_dmac_sdhi_driver = { |
---|
347 | 354 | .driver = { |
---|
348 | 355 | .name = "renesas_sdhi_internal_dmac", |
---|
| 356 | + .probe_type = PROBE_PREFER_ASYNCHRONOUS, |
---|
349 | 357 | .pm = &renesas_sdhi_internal_dmac_dev_pm_ops, |
---|
350 | 358 | .of_match_table = renesas_sdhi_internal_dmac_of_match, |
---|
351 | 359 | }, |
---|