| .. | .. |
|---|
| 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 | }, |
|---|