renesas_sdhi_internal_dmac.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360
  1. /*
  2. * DMA support for Internal DMAC with SDHI SD/SDIO controller
  3. *
  4. * Copyright (C) 2016-17 Renesas Electronics Corporation
  5. * 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.
  10. */
  11. #include <linux/bitops.h>
  12. #include <linux/device.h>
  13. #include <linux/dma-mapping.h>
  14. #include <linux/io-64-nonatomic-hi-lo.h>
  15. #include <linux/mfd/tmio.h>
  16. #include <linux/mmc/host.h>
  17. #include <linux/mod_devicetable.h>
  18. #include <linux/module.h>
  19. #include <linux/pagemap.h>
  20. #include <linux/scatterlist.h>
  21. #include <linux/sys_soc.h>
  22. #include "renesas_sdhi.h"
  23. #include "tmio_mmc.h"
  24. #define DM_CM_DTRAN_MODE 0x820
  25. #define DM_CM_DTRAN_CTRL 0x828
  26. #define DM_CM_RST 0x830
  27. #define DM_CM_INFO1 0x840
  28. #define DM_CM_INFO1_MASK 0x848
  29. #define DM_CM_INFO2 0x850
  30. #define DM_CM_INFO2_MASK 0x858
  31. #define DM_DTRAN_ADDR 0x880
  32. /* DM_CM_DTRAN_MODE */
  33. #define DTRAN_MODE_CH_NUM_CH0 0 /* "downstream" = for write commands */
  34. #define DTRAN_MODE_CH_NUM_CH1 BIT(16) /* "uptream" = for read commands */
  35. #define DTRAN_MODE_BUS_WID_TH (BIT(5) | BIT(4))
  36. #define DTRAN_MODE_ADDR_MODE BIT(0) /* 1 = Increment address */
  37. /* DM_CM_DTRAN_CTRL */
  38. #define DTRAN_CTRL_DM_START BIT(0)
  39. /* DM_CM_RST */
  40. #define RST_DTRANRST1 BIT(9)
  41. #define RST_DTRANRST0 BIT(8)
  42. #define RST_RESERVED_BITS GENMASK_ULL(31, 0)
  43. /* DM_CM_INFO1 and DM_CM_INFO1_MASK */
  44. #define INFO1_CLEAR 0
  45. #define INFO1_MASK_CLEAR GENMASK_ULL(31, 0)
  46. #define INFO1_DTRANEND1 BIT(17)
  47. #define INFO1_DTRANEND0 BIT(16)
  48. /* DM_CM_INFO2 and DM_CM_INFO2_MASK */
  49. #define INFO2_MASK_CLEAR GENMASK_ULL(31, 0)
  50. #define INFO2_DTRANERR1 BIT(17)
  51. #define INFO2_DTRANERR0 BIT(16)
  52. /*
  53. * Specification of this driver:
  54. * - host->chan_{rx,tx} will be used as a flag of enabling/disabling the dma
  55. * - Since this SDHI DMAC register set has 16 but 32-bit width, we
  56. * need a custom accessor.
  57. */
  58. static unsigned long global_flags;
  59. /*
  60. * Workaround for avoiding to use RX DMAC by multiple channels.
  61. * On R-Car H3 ES1.* and M3-W ES1.0, when multiple SDHI channels use
  62. * RX DMAC simultaneously, sometimes hundreds of bytes data are not
  63. * stored into the system memory even if the DMAC interrupt happened.
  64. * So, this driver then uses one RX DMAC channel only.
  65. */
  66. #define SDHI_INTERNAL_DMAC_ONE_RX_ONLY 0
  67. #define SDHI_INTERNAL_DMAC_RX_IN_USE 1
  68. /* Definitions for sampling clocks */
  69. static struct renesas_sdhi_scc rcar_gen3_scc_taps[] = {
  70. {
  71. .clk_rate = 0,
  72. .tap = 0x00000300,
  73. },
  74. };
  75. static const struct renesas_sdhi_of_data of_rcar_r8a7795_compatible = {
  76. .tmio_flags = TMIO_MMC_HAS_IDLE_WAIT | TMIO_MMC_CLK_ACTUAL |
  77. TMIO_MMC_HAVE_CBSY | TMIO_MMC_MIN_RCAR2 |
  78. TMIO_MMC_HAVE_4TAP_HS400,
  79. .capabilities = MMC_CAP_SD_HIGHSPEED | MMC_CAP_SDIO_IRQ |
  80. MMC_CAP_CMD23,
  81. .capabilities2 = MMC_CAP2_NO_WRITE_PROTECT,
  82. .bus_shift = 2,
  83. .scc_offset = 0x1000,
  84. .taps = rcar_gen3_scc_taps,
  85. .taps_num = ARRAY_SIZE(rcar_gen3_scc_taps),
  86. /* DMAC can handle 0xffffffff blk count but only 1 segment */
  87. .max_blk_count = 0xffffffff,
  88. .max_segs = 1,
  89. };
  90. static const struct renesas_sdhi_of_data of_rcar_gen3_compatible = {
  91. .tmio_flags = TMIO_MMC_HAS_IDLE_WAIT | TMIO_MMC_CLK_ACTUAL |
  92. TMIO_MMC_HAVE_CBSY | TMIO_MMC_MIN_RCAR2,
  93. .capabilities = MMC_CAP_SD_HIGHSPEED | MMC_CAP_SDIO_IRQ |
  94. MMC_CAP_CMD23,
  95. .capabilities2 = MMC_CAP2_NO_WRITE_PROTECT,
  96. .bus_shift = 2,
  97. .scc_offset = 0x1000,
  98. .taps = rcar_gen3_scc_taps,
  99. .taps_num = ARRAY_SIZE(rcar_gen3_scc_taps),
  100. /* DMAC can handle 0xffffffff blk count but only 1 segment */
  101. .max_blk_count = 0xffffffff,
  102. .max_segs = 1,
  103. };
  104. static const struct of_device_id renesas_sdhi_internal_dmac_of_match[] = {
  105. { .compatible = "renesas,sdhi-r8a7795", .data = &of_rcar_r8a7795_compatible, },
  106. { .compatible = "renesas,sdhi-r8a7796", .data = &of_rcar_r8a7795_compatible, },
  107. { .compatible = "renesas,rcar-gen3-sdhi", .data = &of_rcar_gen3_compatible, },
  108. {},
  109. };
  110. MODULE_DEVICE_TABLE(of, renesas_sdhi_internal_dmac_of_match);
  111. static void
  112. renesas_sdhi_internal_dmac_dm_write(struct tmio_mmc_host *host,
  113. int addr, u64 val)
  114. {
  115. writeq(val, host->ctl + addr);
  116. }
  117. static void
  118. renesas_sdhi_internal_dmac_enable_dma(struct tmio_mmc_host *host, bool enable)
  119. {
  120. struct renesas_sdhi *priv = host_to_priv(host);
  121. if (!host->chan_tx || !host->chan_rx)
  122. return;
  123. if (!enable)
  124. renesas_sdhi_internal_dmac_dm_write(host, DM_CM_INFO1,
  125. INFO1_CLEAR);
  126. if (priv->dma_priv.enable)
  127. priv->dma_priv.enable(host, enable);
  128. }
  129. static void
  130. renesas_sdhi_internal_dmac_abort_dma(struct tmio_mmc_host *host) {
  131. u64 val = RST_DTRANRST1 | RST_DTRANRST0;
  132. renesas_sdhi_internal_dmac_enable_dma(host, false);
  133. renesas_sdhi_internal_dmac_dm_write(host, DM_CM_RST,
  134. RST_RESERVED_BITS & ~val);
  135. renesas_sdhi_internal_dmac_dm_write(host, DM_CM_RST,
  136. RST_RESERVED_BITS | val);
  137. clear_bit(SDHI_INTERNAL_DMAC_RX_IN_USE, &global_flags);
  138. renesas_sdhi_internal_dmac_enable_dma(host, true);
  139. }
  140. static void
  141. renesas_sdhi_internal_dmac_dataend_dma(struct tmio_mmc_host *host) {
  142. struct renesas_sdhi *priv = host_to_priv(host);
  143. tasklet_schedule(&priv->dma_priv.dma_complete);
  144. }
  145. static void
  146. renesas_sdhi_internal_dmac_start_dma(struct tmio_mmc_host *host,
  147. struct mmc_data *data)
  148. {
  149. struct scatterlist *sg = host->sg_ptr;
  150. u32 dtran_mode = DTRAN_MODE_BUS_WID_TH | DTRAN_MODE_ADDR_MODE;
  151. if (!dma_map_sg(&host->pdev->dev, sg, host->sg_len,
  152. mmc_get_dma_dir(data)))
  153. goto force_pio;
  154. /* This DMAC cannot handle if buffer is not 128-bytes alignment */
  155. if (!IS_ALIGNED(sg_dma_address(sg), 128))
  156. goto force_pio_with_unmap;
  157. if (data->flags & MMC_DATA_READ) {
  158. dtran_mode |= DTRAN_MODE_CH_NUM_CH1;
  159. if (test_bit(SDHI_INTERNAL_DMAC_ONE_RX_ONLY, &global_flags) &&
  160. test_and_set_bit(SDHI_INTERNAL_DMAC_RX_IN_USE, &global_flags))
  161. goto force_pio_with_unmap;
  162. } else {
  163. dtran_mode |= DTRAN_MODE_CH_NUM_CH0;
  164. }
  165. renesas_sdhi_internal_dmac_enable_dma(host, true);
  166. /* set dma parameters */
  167. renesas_sdhi_internal_dmac_dm_write(host, DM_CM_DTRAN_MODE,
  168. dtran_mode);
  169. renesas_sdhi_internal_dmac_dm_write(host, DM_DTRAN_ADDR,
  170. sg_dma_address(sg));
  171. return;
  172. force_pio_with_unmap:
  173. dma_unmap_sg(&host->pdev->dev, sg, host->sg_len, mmc_get_dma_dir(data));
  174. force_pio:
  175. host->force_pio = true;
  176. renesas_sdhi_internal_dmac_enable_dma(host, false);
  177. }
  178. static void renesas_sdhi_internal_dmac_issue_tasklet_fn(unsigned long arg)
  179. {
  180. struct tmio_mmc_host *host = (struct tmio_mmc_host *)arg;
  181. tmio_mmc_enable_mmc_irqs(host, TMIO_STAT_DATAEND);
  182. /* start the DMAC */
  183. renesas_sdhi_internal_dmac_dm_write(host, DM_CM_DTRAN_CTRL,
  184. DTRAN_CTRL_DM_START);
  185. }
  186. static bool renesas_sdhi_internal_dmac_complete(struct tmio_mmc_host *host)
  187. {
  188. enum dma_data_direction dir;
  189. if (!host->data)
  190. return false;
  191. if (host->data->flags & MMC_DATA_READ)
  192. dir = DMA_FROM_DEVICE;
  193. else
  194. dir = DMA_TO_DEVICE;
  195. renesas_sdhi_internal_dmac_enable_dma(host, false);
  196. dma_unmap_sg(&host->pdev->dev, host->sg_ptr, host->sg_len, dir);
  197. if (dir == DMA_FROM_DEVICE)
  198. clear_bit(SDHI_INTERNAL_DMAC_RX_IN_USE, &global_flags);
  199. return true;
  200. }
  201. static void renesas_sdhi_internal_dmac_complete_tasklet_fn(unsigned long arg)
  202. {
  203. struct tmio_mmc_host *host = (struct tmio_mmc_host *)arg;
  204. spin_lock_irq(&host->lock);
  205. if (!renesas_sdhi_internal_dmac_complete(host))
  206. goto out;
  207. tmio_mmc_do_data_irq(host);
  208. out:
  209. spin_unlock_irq(&host->lock);
  210. }
  211. static void
  212. renesas_sdhi_internal_dmac_request_dma(struct tmio_mmc_host *host,
  213. struct tmio_mmc_data *pdata)
  214. {
  215. struct renesas_sdhi *priv = host_to_priv(host);
  216. /* Disable DMAC interrupts, we don't use them */
  217. renesas_sdhi_internal_dmac_dm_write(host, DM_CM_INFO1_MASK,
  218. INFO1_MASK_CLEAR);
  219. renesas_sdhi_internal_dmac_dm_write(host, DM_CM_INFO2_MASK,
  220. INFO2_MASK_CLEAR);
  221. /* Each value is set to non-zero to assume "enabling" each DMA */
  222. host->chan_rx = host->chan_tx = (void *)0xdeadbeaf;
  223. tasklet_init(&priv->dma_priv.dma_complete,
  224. renesas_sdhi_internal_dmac_complete_tasklet_fn,
  225. (unsigned long)host);
  226. tasklet_init(&host->dma_issue,
  227. renesas_sdhi_internal_dmac_issue_tasklet_fn,
  228. (unsigned long)host);
  229. }
  230. static void
  231. renesas_sdhi_internal_dmac_release_dma(struct tmio_mmc_host *host)
  232. {
  233. /* Each value is set to zero to assume "disabling" each DMA */
  234. host->chan_rx = host->chan_tx = NULL;
  235. }
  236. static const struct tmio_mmc_dma_ops renesas_sdhi_internal_dmac_dma_ops = {
  237. .start = renesas_sdhi_internal_dmac_start_dma,
  238. .enable = renesas_sdhi_internal_dmac_enable_dma,
  239. .request = renesas_sdhi_internal_dmac_request_dma,
  240. .release = renesas_sdhi_internal_dmac_release_dma,
  241. .abort = renesas_sdhi_internal_dmac_abort_dma,
  242. .dataend = renesas_sdhi_internal_dmac_dataend_dma,
  243. };
  244. /*
  245. * Whitelist of specific R-Car Gen3 SoC ES versions to use this DMAC
  246. * implementation as others may use a different implementation.
  247. */
  248. static const struct soc_device_attribute gen3_soc_whitelist[] = {
  249. /* specific ones */
  250. { .soc_id = "r8a7795", .revision = "ES1.*",
  251. .data = (void *)BIT(SDHI_INTERNAL_DMAC_ONE_RX_ONLY) },
  252. { .soc_id = "r8a7796", .revision = "ES1.0",
  253. .data = (void *)BIT(SDHI_INTERNAL_DMAC_ONE_RX_ONLY) },
  254. /* generic ones */
  255. { .soc_id = "r8a774a1" },
  256. { .soc_id = "r8a7795" },
  257. { .soc_id = "r8a7796" },
  258. { .soc_id = "r8a77965" },
  259. { .soc_id = "r8a77980" },
  260. { .soc_id = "r8a77995" },
  261. { /* sentinel */ }
  262. };
  263. static int renesas_sdhi_internal_dmac_probe(struct platform_device *pdev)
  264. {
  265. const struct soc_device_attribute *soc = soc_device_match(gen3_soc_whitelist);
  266. struct device *dev = &pdev->dev;
  267. if (!soc)
  268. return -ENODEV;
  269. global_flags |= (unsigned long)soc->data;
  270. dev->dma_parms = devm_kzalloc(dev, sizeof(*dev->dma_parms), GFP_KERNEL);
  271. if (!dev->dma_parms)
  272. return -ENOMEM;
  273. /* value is max of SD_SECCNT. Confirmed by HW engineers */
  274. dma_set_max_seg_size(dev, 0xffffffff);
  275. return renesas_sdhi_probe(pdev, &renesas_sdhi_internal_dmac_dma_ops);
  276. }
  277. static const struct dev_pm_ops renesas_sdhi_internal_dmac_dev_pm_ops = {
  278. SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
  279. pm_runtime_force_resume)
  280. SET_RUNTIME_PM_OPS(tmio_mmc_host_runtime_suspend,
  281. tmio_mmc_host_runtime_resume,
  282. NULL)
  283. };
  284. static struct platform_driver renesas_internal_dmac_sdhi_driver = {
  285. .driver = {
  286. .name = "renesas_sdhi_internal_dmac",
  287. .pm = &renesas_sdhi_internal_dmac_dev_pm_ops,
  288. .of_match_table = renesas_sdhi_internal_dmac_of_match,
  289. },
  290. .probe = renesas_sdhi_internal_dmac_probe,
  291. .remove = renesas_sdhi_remove,
  292. };
  293. module_platform_driver(renesas_internal_dmac_sdhi_driver);
  294. MODULE_DESCRIPTION("Renesas SDHI driver for internal DMAC");
  295. MODULE_AUTHOR("Yoshihiro Shimoda");
  296. MODULE_LICENSE("GPL v2");