Lines Matching +full:can +full:- +full:r8a7791

1 // SPDX-License-Identifier: GPL-2.0
5 * Copyright (C) 2016-19 Renesas Electronics Corporation
6 * Copyright (C) 2016-19 Sang Engineering, Wolfram Sang
8 * Copyright (C) 2010-2011 Guennadi Liakhovetski
12 #include <linux/dma-mapping.h>
74 { .compatible = "renesas,sdhi-sh73a0", .data = &of_default_cfg, },
75 { .compatible = "renesas,sdhi-r8a73a4", .data = &of_default_cfg, },
76 { .compatible = "renesas,sdhi-r8a7740", .data = &of_default_cfg, },
77 { .compatible = "renesas,sdhi-r7s72100", .data = &of_rz_compatible, },
78 { .compatible = "renesas,sdhi-r8a7778", .data = &of_rcar_gen1_compatible, },
79 { .compatible = "renesas,sdhi-r8a7779", .data = &of_rcar_gen1_compatible, },
80 { .compatible = "renesas,sdhi-r8a7743", .data = &of_rcar_gen2_compatible, },
81 { .compatible = "renesas,sdhi-r8a7745", .data = &of_rcar_gen2_compatible, },
82 { .compatible = "renesas,sdhi-r8a7790", .data = &of_rcar_gen2_compatible, },
83 { .compatible = "renesas,sdhi-r8a7791", .data = &of_rcar_gen2_compatible, },
84 { .compatible = "renesas,sdhi-r8a7792", .data = &of_rcar_gen2_compatible, },
85 { .compatible = "renesas,sdhi-r8a7793", .data = &of_rcar_gen2_compatible, },
86 { .compatible = "renesas,sdhi-r8a7794", .data = &of_rcar_gen2_compatible, },
87 { .compatible = "renesas,rcar-gen1-sdhi", .data = &of_rcar_gen1_compatible, },
88 { .compatible = "renesas,rcar-gen2-sdhi", .data = &of_rcar_gen2_compatible, },
89 { .compatible = "renesas,sdhi-shmobile" },
99 if (!host->chan_tx || !host->chan_rx) in renesas_sdhi_sys_dmac_enable_dma()
102 if (priv->dma_priv.enable) in renesas_sdhi_sys_dmac_enable_dma()
103 priv->dma_priv.enable(host, enable); in renesas_sdhi_sys_dmac_enable_dma()
110 if (host->chan_rx) in renesas_sdhi_sys_dmac_abort_dma()
111 dmaengine_terminate_sync(host->chan_rx); in renesas_sdhi_sys_dmac_abort_dma()
112 if (host->chan_tx) in renesas_sdhi_sys_dmac_abort_dma()
113 dmaengine_terminate_sync(host->chan_tx); in renesas_sdhi_sys_dmac_abort_dma()
122 complete(&priv->dma_priv.dma_dataend); in renesas_sdhi_sys_dmac_dataend_dma()
130 spin_lock_irq(&host->lock); in renesas_sdhi_sys_dmac_dma_callback()
132 if (!host->data) in renesas_sdhi_sys_dmac_dma_callback()
135 if (host->data->flags & MMC_DATA_READ) in renesas_sdhi_sys_dmac_dma_callback()
136 dma_unmap_sg(host->chan_rx->device->dev, in renesas_sdhi_sys_dmac_dma_callback()
137 host->sg_ptr, host->sg_len, in renesas_sdhi_sys_dmac_dma_callback()
140 dma_unmap_sg(host->chan_tx->device->dev, in renesas_sdhi_sys_dmac_dma_callback()
141 host->sg_ptr, host->sg_len, in renesas_sdhi_sys_dmac_dma_callback()
144 spin_unlock_irq(&host->lock); in renesas_sdhi_sys_dmac_dma_callback()
146 wait_for_completion(&priv->dma_priv.dma_dataend); in renesas_sdhi_sys_dmac_dma_callback()
148 spin_lock_irq(&host->lock); in renesas_sdhi_sys_dmac_dma_callback()
151 spin_unlock_irq(&host->lock); in renesas_sdhi_sys_dmac_dma_callback()
157 struct scatterlist *sg = host->sg_ptr, *sg_tmp; in renesas_sdhi_sys_dmac_start_dma_rx()
159 struct dma_chan *chan = host->chan_rx; in renesas_sdhi_sys_dmac_start_dma_rx()
163 unsigned int align = (1 << host->pdata->alignment_shift) - 1; in renesas_sdhi_sys_dmac_start_dma_rx()
165 for_each_sg(sg, sg_tmp, host->sg_len, i) { in renesas_sdhi_sys_dmac_start_dma_rx()
166 if (sg_tmp->offset & align) in renesas_sdhi_sys_dmac_start_dma_rx()
168 if (sg_tmp->length & align) { in renesas_sdhi_sys_dmac_start_dma_rx()
174 if ((!aligned && (host->sg_len > 1 || sg->length > PAGE_SIZE || in renesas_sdhi_sys_dmac_start_dma_rx()
176 ret = -EINVAL; in renesas_sdhi_sys_dmac_start_dma_rx()
180 if (sg->length < TMIO_MMC_MIN_DMA_LEN) in renesas_sdhi_sys_dmac_start_dma_rx()
183 /* The only sg element can be unaligned, use our bounce buffer then */ in renesas_sdhi_sys_dmac_start_dma_rx()
185 sg_init_one(&host->bounce_sg, host->bounce_buf, sg->length); in renesas_sdhi_sys_dmac_start_dma_rx()
186 host->sg_ptr = &host->bounce_sg; in renesas_sdhi_sys_dmac_start_dma_rx()
187 sg = host->sg_ptr; in renesas_sdhi_sys_dmac_start_dma_rx()
190 ret = dma_map_sg(chan->device->dev, sg, host->sg_len, DMA_FROM_DEVICE); in renesas_sdhi_sys_dmac_start_dma_rx()
196 reinit_completion(&priv->dma_priv.dma_dataend); in renesas_sdhi_sys_dmac_start_dma_rx()
197 desc->callback = renesas_sdhi_sys_dmac_dma_callback; in renesas_sdhi_sys_dmac_start_dma_rx()
198 desc->callback_param = host; in renesas_sdhi_sys_dmac_start_dma_rx()
205 host->dma_on = true; in renesas_sdhi_sys_dmac_start_dma_rx()
212 ret = -EIO; in renesas_sdhi_sys_dmac_start_dma_rx()
213 host->chan_rx = NULL; in renesas_sdhi_sys_dmac_start_dma_rx()
216 chan = host->chan_tx; in renesas_sdhi_sys_dmac_start_dma_rx()
218 host->chan_tx = NULL; in renesas_sdhi_sys_dmac_start_dma_rx()
221 dev_warn(&host->pdev->dev, in renesas_sdhi_sys_dmac_start_dma_rx()
229 struct scatterlist *sg = host->sg_ptr, *sg_tmp; in renesas_sdhi_sys_dmac_start_dma_tx()
231 struct dma_chan *chan = host->chan_tx; in renesas_sdhi_sys_dmac_start_dma_tx()
235 unsigned int align = (1 << host->pdata->alignment_shift) - 1; in renesas_sdhi_sys_dmac_start_dma_tx()
237 for_each_sg(sg, sg_tmp, host->sg_len, i) { in renesas_sdhi_sys_dmac_start_dma_tx()
238 if (sg_tmp->offset & align) in renesas_sdhi_sys_dmac_start_dma_tx()
240 if (sg_tmp->length & align) { in renesas_sdhi_sys_dmac_start_dma_tx()
246 if ((!aligned && (host->sg_len > 1 || sg->length > PAGE_SIZE || in renesas_sdhi_sys_dmac_start_dma_tx()
248 ret = -EINVAL; in renesas_sdhi_sys_dmac_start_dma_tx()
252 if (sg->length < TMIO_MMC_MIN_DMA_LEN) in renesas_sdhi_sys_dmac_start_dma_tx()
255 /* The only sg element can be unaligned, use our bounce buffer then */ in renesas_sdhi_sys_dmac_start_dma_tx()
260 sg_init_one(&host->bounce_sg, host->bounce_buf, sg->length); in renesas_sdhi_sys_dmac_start_dma_tx()
261 memcpy(host->bounce_buf, sg_vaddr, host->bounce_sg.length); in renesas_sdhi_sys_dmac_start_dma_tx()
263 host->sg_ptr = &host->bounce_sg; in renesas_sdhi_sys_dmac_start_dma_tx()
264 sg = host->sg_ptr; in renesas_sdhi_sys_dmac_start_dma_tx()
267 ret = dma_map_sg(chan->device->dev, sg, host->sg_len, DMA_TO_DEVICE); in renesas_sdhi_sys_dmac_start_dma_tx()
273 reinit_completion(&priv->dma_priv.dma_dataend); in renesas_sdhi_sys_dmac_start_dma_tx()
274 desc->callback = renesas_sdhi_sys_dmac_dma_callback; in renesas_sdhi_sys_dmac_start_dma_tx()
275 desc->callback_param = host; in renesas_sdhi_sys_dmac_start_dma_tx()
282 host->dma_on = true; in renesas_sdhi_sys_dmac_start_dma_tx()
289 ret = -EIO; in renesas_sdhi_sys_dmac_start_dma_tx()
290 host->chan_tx = NULL; in renesas_sdhi_sys_dmac_start_dma_tx()
293 chan = host->chan_rx; in renesas_sdhi_sys_dmac_start_dma_tx()
295 host->chan_rx = NULL; in renesas_sdhi_sys_dmac_start_dma_tx()
298 dev_warn(&host->pdev->dev, in renesas_sdhi_sys_dmac_start_dma_tx()
306 if (data->flags & MMC_DATA_READ) { in renesas_sdhi_sys_dmac_start_dma()
307 if (host->chan_rx) in renesas_sdhi_sys_dmac_start_dma()
310 if (host->chan_tx) in renesas_sdhi_sys_dmac_start_dma()
320 spin_lock_irq(&host->lock); in renesas_sdhi_sys_dmac_issue_tasklet_fn()
322 if (host->data) { in renesas_sdhi_sys_dmac_issue_tasklet_fn()
323 if (host->data->flags & MMC_DATA_READ) in renesas_sdhi_sys_dmac_issue_tasklet_fn()
324 chan = host->chan_rx; in renesas_sdhi_sys_dmac_issue_tasklet_fn()
326 chan = host->chan_tx; in renesas_sdhi_sys_dmac_issue_tasklet_fn()
329 spin_unlock_irq(&host->lock); in renesas_sdhi_sys_dmac_issue_tasklet_fn()
342 /* We can only either use DMA for both Tx and Rx or not use it at all */ in renesas_sdhi_sys_dmac_request_dma()
343 if (!host->pdev->dev.of_node && in renesas_sdhi_sys_dmac_request_dma()
344 (!pdata->chan_priv_tx || !pdata->chan_priv_rx)) in renesas_sdhi_sys_dmac_request_dma()
347 if (!host->chan_tx && !host->chan_rx) { in renesas_sdhi_sys_dmac_request_dma()
348 struct resource *res = platform_get_resource(host->pdev, in renesas_sdhi_sys_dmac_request_dma()
360 host->chan_tx = dma_request_slave_channel_compat(mask, in renesas_sdhi_sys_dmac_request_dma()
361 priv->dma_priv.filter, pdata->chan_priv_tx, in renesas_sdhi_sys_dmac_request_dma()
362 &host->pdev->dev, "tx"); in renesas_sdhi_sys_dmac_request_dma()
363 dev_dbg(&host->pdev->dev, "%s: TX: got channel %p\n", __func__, in renesas_sdhi_sys_dmac_request_dma()
364 host->chan_tx); in renesas_sdhi_sys_dmac_request_dma()
366 if (!host->chan_tx) in renesas_sdhi_sys_dmac_request_dma()
370 cfg.dst_addr = res->start + in renesas_sdhi_sys_dmac_request_dma()
371 (CTL_SD_DATA_PORT << host->bus_shift); in renesas_sdhi_sys_dmac_request_dma()
372 cfg.dst_addr_width = priv->dma_priv.dma_buswidth; in renesas_sdhi_sys_dmac_request_dma()
376 ret = dmaengine_slave_config(host->chan_tx, &cfg); in renesas_sdhi_sys_dmac_request_dma()
380 host->chan_rx = dma_request_slave_channel_compat(mask, in renesas_sdhi_sys_dmac_request_dma()
381 priv->dma_priv.filter, pdata->chan_priv_rx, in renesas_sdhi_sys_dmac_request_dma()
382 &host->pdev->dev, "rx"); in renesas_sdhi_sys_dmac_request_dma()
383 dev_dbg(&host->pdev->dev, "%s: RX: got channel %p\n", __func__, in renesas_sdhi_sys_dmac_request_dma()
384 host->chan_rx); in renesas_sdhi_sys_dmac_request_dma()
386 if (!host->chan_rx) in renesas_sdhi_sys_dmac_request_dma()
390 cfg.src_addr = cfg.dst_addr + host->pdata->dma_rx_offset; in renesas_sdhi_sys_dmac_request_dma()
391 cfg.src_addr_width = priv->dma_priv.dma_buswidth; in renesas_sdhi_sys_dmac_request_dma()
395 ret = dmaengine_slave_config(host->chan_rx, &cfg); in renesas_sdhi_sys_dmac_request_dma()
399 host->bounce_buf = (u8 *)__get_free_page(GFP_KERNEL | GFP_DMA); in renesas_sdhi_sys_dmac_request_dma()
400 if (!host->bounce_buf) in renesas_sdhi_sys_dmac_request_dma()
403 init_completion(&priv->dma_priv.dma_dataend); in renesas_sdhi_sys_dmac_request_dma()
404 tasklet_init(&host->dma_issue, in renesas_sdhi_sys_dmac_request_dma()
415 dma_release_channel(host->chan_rx); in renesas_sdhi_sys_dmac_request_dma()
416 host->chan_rx = NULL; in renesas_sdhi_sys_dmac_request_dma()
419 dma_release_channel(host->chan_tx); in renesas_sdhi_sys_dmac_request_dma()
420 host->chan_tx = NULL; in renesas_sdhi_sys_dmac_request_dma()
425 if (host->chan_tx) { in renesas_sdhi_sys_dmac_release_dma()
426 struct dma_chan *chan = host->chan_tx; in renesas_sdhi_sys_dmac_release_dma()
428 host->chan_tx = NULL; in renesas_sdhi_sys_dmac_release_dma()
431 if (host->chan_rx) { in renesas_sdhi_sys_dmac_release_dma()
432 struct dma_chan *chan = host->chan_rx; in renesas_sdhi_sys_dmac_release_dma()
434 host->chan_rx = NULL; in renesas_sdhi_sys_dmac_release_dma()
437 if (host->bounce_buf) { in renesas_sdhi_sys_dmac_release_dma()
438 free_pages((unsigned long)host->bounce_buf, 0); in renesas_sdhi_sys_dmac_release_dma()
439 host->bounce_buf = NULL; in renesas_sdhi_sys_dmac_release_dma()
455 of_device_get_match_data(&pdev->dev), NULL); in renesas_sdhi_sys_dmac_probe()