Lines Matching +full:host +full:- +full:only
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>
15 #include <linux/mmc/host.h>
72 { .compatible = "renesas,sdhi-sh73a0", .data = &of_default_cfg, },
73 { .compatible = "renesas,sdhi-r8a73a4", .data = &of_default_cfg, },
74 { .compatible = "renesas,sdhi-r8a7740", .data = &of_default_cfg, },
75 { .compatible = "renesas,sdhi-r7s72100", .data = &of_rz_compatible, },
76 { .compatible = "renesas,sdhi-r8a7778", .data = &of_rcar_gen1_compatible, },
77 { .compatible = "renesas,sdhi-r8a7779", .data = &of_rcar_gen1_compatible, },
78 { .compatible = "renesas,sdhi-r8a7743", .data = &of_rcar_gen2_compatible, },
79 { .compatible = "renesas,sdhi-r8a7745", .data = &of_rcar_gen2_compatible, },
80 { .compatible = "renesas,sdhi-r8a7790", .data = &of_rcar_gen2_compatible, },
81 { .compatible = "renesas,sdhi-r8a7791", .data = &of_rcar_gen2_compatible, },
82 { .compatible = "renesas,sdhi-r8a7792", .data = &of_rcar_gen2_compatible, },
83 { .compatible = "renesas,sdhi-r8a7793", .data = &of_rcar_gen2_compatible, },
84 { .compatible = "renesas,sdhi-r8a7794", .data = &of_rcar_gen2_compatible, },
85 { .compatible = "renesas,rcar-gen1-sdhi", .data = &of_rcar_gen1_compatible, },
86 { .compatible = "renesas,rcar-gen2-sdhi", .data = &of_rcar_gen2_compatible, },
87 { .compatible = "renesas,sdhi-shmobile" },
92 static void renesas_sdhi_sys_dmac_enable_dma(struct tmio_mmc_host *host, in renesas_sdhi_sys_dmac_enable_dma() argument
95 struct renesas_sdhi *priv = host_to_priv(host); in renesas_sdhi_sys_dmac_enable_dma()
97 if (!host->chan_tx || !host->chan_rx) in renesas_sdhi_sys_dmac_enable_dma()
100 if (priv->dma_priv.enable) in renesas_sdhi_sys_dmac_enable_dma()
101 priv->dma_priv.enable(host, enable); in renesas_sdhi_sys_dmac_enable_dma()
104 static void renesas_sdhi_sys_dmac_abort_dma(struct tmio_mmc_host *host) in renesas_sdhi_sys_dmac_abort_dma() argument
106 renesas_sdhi_sys_dmac_enable_dma(host, false); in renesas_sdhi_sys_dmac_abort_dma()
108 if (host->chan_rx) in renesas_sdhi_sys_dmac_abort_dma()
109 dmaengine_terminate_all(host->chan_rx); in renesas_sdhi_sys_dmac_abort_dma()
110 if (host->chan_tx) in renesas_sdhi_sys_dmac_abort_dma()
111 dmaengine_terminate_all(host->chan_tx); in renesas_sdhi_sys_dmac_abort_dma()
113 renesas_sdhi_sys_dmac_enable_dma(host, true); in renesas_sdhi_sys_dmac_abort_dma()
116 static void renesas_sdhi_sys_dmac_dataend_dma(struct tmio_mmc_host *host) in renesas_sdhi_sys_dmac_dataend_dma() argument
118 struct renesas_sdhi *priv = host_to_priv(host); in renesas_sdhi_sys_dmac_dataend_dma()
120 complete(&priv->dma_priv.dma_dataend); in renesas_sdhi_sys_dmac_dataend_dma()
125 struct tmio_mmc_host *host = arg; in renesas_sdhi_sys_dmac_dma_callback() local
126 struct renesas_sdhi *priv = host_to_priv(host); in renesas_sdhi_sys_dmac_dma_callback()
128 spin_lock_irq(&host->lock); in renesas_sdhi_sys_dmac_dma_callback()
130 if (!host->data) in renesas_sdhi_sys_dmac_dma_callback()
133 if (host->data->flags & MMC_DATA_READ) in renesas_sdhi_sys_dmac_dma_callback()
134 dma_unmap_sg(host->chan_rx->device->dev, in renesas_sdhi_sys_dmac_dma_callback()
135 host->sg_ptr, host->sg_len, in renesas_sdhi_sys_dmac_dma_callback()
138 dma_unmap_sg(host->chan_tx->device->dev, in renesas_sdhi_sys_dmac_dma_callback()
139 host->sg_ptr, host->sg_len, in renesas_sdhi_sys_dmac_dma_callback()
142 spin_unlock_irq(&host->lock); in renesas_sdhi_sys_dmac_dma_callback()
144 wait_for_completion(&priv->dma_priv.dma_dataend); in renesas_sdhi_sys_dmac_dma_callback()
146 spin_lock_irq(&host->lock); in renesas_sdhi_sys_dmac_dma_callback()
147 tmio_mmc_do_data_irq(host); in renesas_sdhi_sys_dmac_dma_callback()
149 spin_unlock_irq(&host->lock); in renesas_sdhi_sys_dmac_dma_callback()
152 static void renesas_sdhi_sys_dmac_start_dma_rx(struct tmio_mmc_host *host) in renesas_sdhi_sys_dmac_start_dma_rx() argument
154 struct renesas_sdhi *priv = host_to_priv(host); in renesas_sdhi_sys_dmac_start_dma_rx()
155 struct scatterlist *sg = host->sg_ptr, *sg_tmp; in renesas_sdhi_sys_dmac_start_dma_rx()
157 struct dma_chan *chan = host->chan_rx; in renesas_sdhi_sys_dmac_start_dma_rx()
161 unsigned int align = (1 << host->pdata->alignment_shift) - 1; in renesas_sdhi_sys_dmac_start_dma_rx()
163 for_each_sg(sg, sg_tmp, host->sg_len, i) { in renesas_sdhi_sys_dmac_start_dma_rx()
164 if (sg_tmp->offset & align) in renesas_sdhi_sys_dmac_start_dma_rx()
166 if (sg_tmp->length & align) { in renesas_sdhi_sys_dmac_start_dma_rx()
172 if ((!aligned && (host->sg_len > 1 || sg->length > PAGE_SIZE || in renesas_sdhi_sys_dmac_start_dma_rx()
174 ret = -EINVAL; in renesas_sdhi_sys_dmac_start_dma_rx()
178 if (sg->length < TMIO_MMC_MIN_DMA_LEN) in renesas_sdhi_sys_dmac_start_dma_rx()
181 /* The only sg element can be unaligned, use our bounce buffer then */ in renesas_sdhi_sys_dmac_start_dma_rx()
183 sg_init_one(&host->bounce_sg, host->bounce_buf, sg->length); in renesas_sdhi_sys_dmac_start_dma_rx()
184 host->sg_ptr = &host->bounce_sg; in renesas_sdhi_sys_dmac_start_dma_rx()
185 sg = host->sg_ptr; in renesas_sdhi_sys_dmac_start_dma_rx()
188 ret = dma_map_sg(chan->device->dev, sg, host->sg_len, DMA_FROM_DEVICE); in renesas_sdhi_sys_dmac_start_dma_rx()
194 reinit_completion(&priv->dma_priv.dma_dataend); in renesas_sdhi_sys_dmac_start_dma_rx()
195 desc->callback = renesas_sdhi_sys_dmac_dma_callback; in renesas_sdhi_sys_dmac_start_dma_rx()
196 desc->callback_param = host; in renesas_sdhi_sys_dmac_start_dma_rx()
203 host->dma_on = true; in renesas_sdhi_sys_dmac_start_dma_rx()
208 renesas_sdhi_sys_dmac_enable_dma(host, false); in renesas_sdhi_sys_dmac_start_dma_rx()
210 ret = -EIO; in renesas_sdhi_sys_dmac_start_dma_rx()
211 host->chan_rx = NULL; in renesas_sdhi_sys_dmac_start_dma_rx()
214 chan = host->chan_tx; in renesas_sdhi_sys_dmac_start_dma_rx()
216 host->chan_tx = NULL; in renesas_sdhi_sys_dmac_start_dma_rx()
219 dev_warn(&host->pdev->dev, in renesas_sdhi_sys_dmac_start_dma_rx()
224 static void renesas_sdhi_sys_dmac_start_dma_tx(struct tmio_mmc_host *host) in renesas_sdhi_sys_dmac_start_dma_tx() argument
226 struct renesas_sdhi *priv = host_to_priv(host); in renesas_sdhi_sys_dmac_start_dma_tx()
227 struct scatterlist *sg = host->sg_ptr, *sg_tmp; in renesas_sdhi_sys_dmac_start_dma_tx()
229 struct dma_chan *chan = host->chan_tx; in renesas_sdhi_sys_dmac_start_dma_tx()
233 unsigned int align = (1 << host->pdata->alignment_shift) - 1; in renesas_sdhi_sys_dmac_start_dma_tx()
235 for_each_sg(sg, sg_tmp, host->sg_len, i) { in renesas_sdhi_sys_dmac_start_dma_tx()
236 if (sg_tmp->offset & align) in renesas_sdhi_sys_dmac_start_dma_tx()
238 if (sg_tmp->length & align) { in renesas_sdhi_sys_dmac_start_dma_tx()
244 if ((!aligned && (host->sg_len > 1 || sg->length > PAGE_SIZE || in renesas_sdhi_sys_dmac_start_dma_tx()
246 ret = -EINVAL; in renesas_sdhi_sys_dmac_start_dma_tx()
250 if (sg->length < TMIO_MMC_MIN_DMA_LEN) in renesas_sdhi_sys_dmac_start_dma_tx()
253 /* The only sg element can be unaligned, use our bounce buffer then */ in renesas_sdhi_sys_dmac_start_dma_tx()
258 sg_init_one(&host->bounce_sg, host->bounce_buf, sg->length); in renesas_sdhi_sys_dmac_start_dma_tx()
259 memcpy(host->bounce_buf, sg_vaddr, host->bounce_sg.length); in renesas_sdhi_sys_dmac_start_dma_tx()
261 host->sg_ptr = &host->bounce_sg; in renesas_sdhi_sys_dmac_start_dma_tx()
262 sg = host->sg_ptr; in renesas_sdhi_sys_dmac_start_dma_tx()
265 ret = dma_map_sg(chan->device->dev, sg, host->sg_len, DMA_TO_DEVICE); in renesas_sdhi_sys_dmac_start_dma_tx()
271 reinit_completion(&priv->dma_priv.dma_dataend); in renesas_sdhi_sys_dmac_start_dma_tx()
272 desc->callback = renesas_sdhi_sys_dmac_dma_callback; in renesas_sdhi_sys_dmac_start_dma_tx()
273 desc->callback_param = host; in renesas_sdhi_sys_dmac_start_dma_tx()
280 host->dma_on = true; in renesas_sdhi_sys_dmac_start_dma_tx()
285 renesas_sdhi_sys_dmac_enable_dma(host, false); in renesas_sdhi_sys_dmac_start_dma_tx()
287 ret = -EIO; in renesas_sdhi_sys_dmac_start_dma_tx()
288 host->chan_tx = NULL; in renesas_sdhi_sys_dmac_start_dma_tx()
291 chan = host->chan_rx; in renesas_sdhi_sys_dmac_start_dma_tx()
293 host->chan_rx = NULL; in renesas_sdhi_sys_dmac_start_dma_tx()
296 dev_warn(&host->pdev->dev, in renesas_sdhi_sys_dmac_start_dma_tx()
301 static void renesas_sdhi_sys_dmac_start_dma(struct tmio_mmc_host *host, in renesas_sdhi_sys_dmac_start_dma() argument
304 if (data->flags & MMC_DATA_READ) { in renesas_sdhi_sys_dmac_start_dma()
305 if (host->chan_rx) in renesas_sdhi_sys_dmac_start_dma()
306 renesas_sdhi_sys_dmac_start_dma_rx(host); in renesas_sdhi_sys_dmac_start_dma()
308 if (host->chan_tx) in renesas_sdhi_sys_dmac_start_dma()
309 renesas_sdhi_sys_dmac_start_dma_tx(host); in renesas_sdhi_sys_dmac_start_dma()
315 struct tmio_mmc_host *host = (struct tmio_mmc_host *)priv; in renesas_sdhi_sys_dmac_issue_tasklet_fn() local
318 spin_lock_irq(&host->lock); in renesas_sdhi_sys_dmac_issue_tasklet_fn()
320 if (host->data) { in renesas_sdhi_sys_dmac_issue_tasklet_fn()
321 if (host->data->flags & MMC_DATA_READ) in renesas_sdhi_sys_dmac_issue_tasklet_fn()
322 chan = host->chan_rx; in renesas_sdhi_sys_dmac_issue_tasklet_fn()
324 chan = host->chan_tx; in renesas_sdhi_sys_dmac_issue_tasklet_fn()
327 spin_unlock_irq(&host->lock); in renesas_sdhi_sys_dmac_issue_tasklet_fn()
329 tmio_mmc_enable_mmc_irqs(host, TMIO_STAT_DATAEND); in renesas_sdhi_sys_dmac_issue_tasklet_fn()
335 static void renesas_sdhi_sys_dmac_request_dma(struct tmio_mmc_host *host, in renesas_sdhi_sys_dmac_request_dma() argument
338 struct renesas_sdhi *priv = host_to_priv(host); in renesas_sdhi_sys_dmac_request_dma()
340 /* We can only either use DMA for both Tx and Rx or not use it at all */ in renesas_sdhi_sys_dmac_request_dma()
341 if (!host->pdev->dev.of_node && in renesas_sdhi_sys_dmac_request_dma()
342 (!pdata->chan_priv_tx || !pdata->chan_priv_rx)) in renesas_sdhi_sys_dmac_request_dma()
345 if (!host->chan_tx && !host->chan_rx) { in renesas_sdhi_sys_dmac_request_dma()
346 struct resource *res = platform_get_resource(host->pdev, in renesas_sdhi_sys_dmac_request_dma()
358 host->chan_tx = dma_request_slave_channel_compat(mask, in renesas_sdhi_sys_dmac_request_dma()
359 priv->dma_priv.filter, pdata->chan_priv_tx, in renesas_sdhi_sys_dmac_request_dma()
360 &host->pdev->dev, "tx"); in renesas_sdhi_sys_dmac_request_dma()
361 dev_dbg(&host->pdev->dev, "%s: TX: got channel %p\n", __func__, in renesas_sdhi_sys_dmac_request_dma()
362 host->chan_tx); in renesas_sdhi_sys_dmac_request_dma()
364 if (!host->chan_tx) in renesas_sdhi_sys_dmac_request_dma()
368 cfg.dst_addr = res->start + in renesas_sdhi_sys_dmac_request_dma()
369 (CTL_SD_DATA_PORT << host->bus_shift); in renesas_sdhi_sys_dmac_request_dma()
370 cfg.dst_addr_width = priv->dma_priv.dma_buswidth; in renesas_sdhi_sys_dmac_request_dma()
374 ret = dmaengine_slave_config(host->chan_tx, &cfg); in renesas_sdhi_sys_dmac_request_dma()
378 host->chan_rx = dma_request_slave_channel_compat(mask, in renesas_sdhi_sys_dmac_request_dma()
379 priv->dma_priv.filter, pdata->chan_priv_rx, in renesas_sdhi_sys_dmac_request_dma()
380 &host->pdev->dev, "rx"); in renesas_sdhi_sys_dmac_request_dma()
381 dev_dbg(&host->pdev->dev, "%s: RX: got channel %p\n", __func__, in renesas_sdhi_sys_dmac_request_dma()
382 host->chan_rx); in renesas_sdhi_sys_dmac_request_dma()
384 if (!host->chan_rx) in renesas_sdhi_sys_dmac_request_dma()
388 cfg.src_addr = cfg.dst_addr + host->pdata->dma_rx_offset; in renesas_sdhi_sys_dmac_request_dma()
389 cfg.src_addr_width = priv->dma_priv.dma_buswidth; in renesas_sdhi_sys_dmac_request_dma()
393 ret = dmaengine_slave_config(host->chan_rx, &cfg); in renesas_sdhi_sys_dmac_request_dma()
397 host->bounce_buf = (u8 *)__get_free_page(GFP_KERNEL | GFP_DMA); in renesas_sdhi_sys_dmac_request_dma()
398 if (!host->bounce_buf) in renesas_sdhi_sys_dmac_request_dma()
401 init_completion(&priv->dma_priv.dma_dataend); in renesas_sdhi_sys_dmac_request_dma()
402 tasklet_init(&host->dma_issue, in renesas_sdhi_sys_dmac_request_dma()
404 (unsigned long)host); in renesas_sdhi_sys_dmac_request_dma()
407 renesas_sdhi_sys_dmac_enable_dma(host, true); in renesas_sdhi_sys_dmac_request_dma()
413 dma_release_channel(host->chan_rx); in renesas_sdhi_sys_dmac_request_dma()
414 host->chan_rx = NULL; in renesas_sdhi_sys_dmac_request_dma()
417 dma_release_channel(host->chan_tx); in renesas_sdhi_sys_dmac_request_dma()
418 host->chan_tx = NULL; in renesas_sdhi_sys_dmac_request_dma()
421 static void renesas_sdhi_sys_dmac_release_dma(struct tmio_mmc_host *host) in renesas_sdhi_sys_dmac_release_dma() argument
423 if (host->chan_tx) { in renesas_sdhi_sys_dmac_release_dma()
424 struct dma_chan *chan = host->chan_tx; in renesas_sdhi_sys_dmac_release_dma()
426 host->chan_tx = NULL; in renesas_sdhi_sys_dmac_release_dma()
429 if (host->chan_rx) { in renesas_sdhi_sys_dmac_release_dma()
430 struct dma_chan *chan = host->chan_rx; in renesas_sdhi_sys_dmac_release_dma()
432 host->chan_rx = NULL; in renesas_sdhi_sys_dmac_release_dma()
435 if (host->bounce_buf) { in renesas_sdhi_sys_dmac_release_dma()
436 free_pages((unsigned long)host->bounce_buf, 0); in renesas_sdhi_sys_dmac_release_dma()
437 host->bounce_buf = NULL; in renesas_sdhi_sys_dmac_release_dma()