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>
14 #include <linux/mmc/host.h>
76 { .compatible = "renesas,sdhi-sh73a0", .data = &of_default_cfg, },
77 { .compatible = "renesas,sdhi-r8a73a4", .data = &of_default_cfg, },
78 { .compatible = "renesas,sdhi-r8a7740", .data = &of_default_cfg, },
79 { .compatible = "renesas,sdhi-r7s72100", .data = &of_rz_compatible, },
80 { .compatible = "renesas,sdhi-r8a7778", .data = &of_rcar_gen1_compatible, },
81 { .compatible = "renesas,sdhi-r8a7779", .data = &of_rcar_gen1_compatible, },
82 { .compatible = "renesas,sdhi-r8a7743", .data = &of_rcar_gen2_compatible, },
83 { .compatible = "renesas,sdhi-r8a7745", .data = &of_rcar_gen2_compatible, },
84 { .compatible = "renesas,sdhi-r8a7790", .data = &of_rcar_gen2_compatible, },
85 { .compatible = "renesas,sdhi-r8a7791", .data = &of_rcar_gen2_compatible, },
86 { .compatible = "renesas,sdhi-r8a7792", .data = &of_rcar_gen2_compatible, },
87 { .compatible = "renesas,sdhi-r8a7793", .data = &of_rcar_gen2_compatible, },
88 { .compatible = "renesas,sdhi-r8a7794", .data = &of_rcar_gen2_compatible, },
89 { .compatible = "renesas,rcar-gen1-sdhi", .data = &of_rcar_gen1_compatible, },
90 { .compatible = "renesas,rcar-gen2-sdhi", .data = &of_rcar_gen2_compatible, },
91 { .compatible = "renesas,sdhi-shmobile" },
96 static void renesas_sdhi_sys_dmac_enable_dma(struct tmio_mmc_host *host, in renesas_sdhi_sys_dmac_enable_dma() argument
99 struct renesas_sdhi *priv = host_to_priv(host); in renesas_sdhi_sys_dmac_enable_dma()
101 if (!host->chan_tx || !host->chan_rx) in renesas_sdhi_sys_dmac_enable_dma()
104 if (priv->dma_priv.enable) in renesas_sdhi_sys_dmac_enable_dma()
105 priv->dma_priv.enable(host, enable); in renesas_sdhi_sys_dmac_enable_dma()
108 static void renesas_sdhi_sys_dmac_abort_dma(struct tmio_mmc_host *host) in renesas_sdhi_sys_dmac_abort_dma() argument
110 renesas_sdhi_sys_dmac_enable_dma(host, false); in renesas_sdhi_sys_dmac_abort_dma()
112 if (host->chan_rx) in renesas_sdhi_sys_dmac_abort_dma()
113 dmaengine_terminate_sync(host->chan_rx); in renesas_sdhi_sys_dmac_abort_dma()
114 if (host->chan_tx) in renesas_sdhi_sys_dmac_abort_dma()
115 dmaengine_terminate_sync(host->chan_tx); in renesas_sdhi_sys_dmac_abort_dma()
117 renesas_sdhi_sys_dmac_enable_dma(host, true); in renesas_sdhi_sys_dmac_abort_dma()
120 static void renesas_sdhi_sys_dmac_dataend_dma(struct tmio_mmc_host *host) in renesas_sdhi_sys_dmac_dataend_dma() argument
122 struct renesas_sdhi *priv = host_to_priv(host); in renesas_sdhi_sys_dmac_dataend_dma()
124 complete(&priv->dma_priv.dma_dataend); in renesas_sdhi_sys_dmac_dataend_dma()
129 struct tmio_mmc_host *host = arg; in renesas_sdhi_sys_dmac_dma_callback() local
130 struct renesas_sdhi *priv = host_to_priv(host); in renesas_sdhi_sys_dmac_dma_callback()
132 spin_lock_irq(&host->lock); in renesas_sdhi_sys_dmac_dma_callback()
134 if (!host->data) in renesas_sdhi_sys_dmac_dma_callback()
137 if (host->data->flags & MMC_DATA_READ) in renesas_sdhi_sys_dmac_dma_callback()
138 dma_unmap_sg(host->chan_rx->device->dev, in renesas_sdhi_sys_dmac_dma_callback()
139 host->sg_ptr, host->sg_len, in renesas_sdhi_sys_dmac_dma_callback()
142 dma_unmap_sg(host->chan_tx->device->dev, in renesas_sdhi_sys_dmac_dma_callback()
143 host->sg_ptr, host->sg_len, in renesas_sdhi_sys_dmac_dma_callback()
146 spin_unlock_irq(&host->lock); in renesas_sdhi_sys_dmac_dma_callback()
148 wait_for_completion(&priv->dma_priv.dma_dataend); in renesas_sdhi_sys_dmac_dma_callback()
150 spin_lock_irq(&host->lock); in renesas_sdhi_sys_dmac_dma_callback()
151 tmio_mmc_do_data_irq(host); in renesas_sdhi_sys_dmac_dma_callback()
153 spin_unlock_irq(&host->lock); in renesas_sdhi_sys_dmac_dma_callback()
156 static void renesas_sdhi_sys_dmac_start_dma_rx(struct tmio_mmc_host *host) in renesas_sdhi_sys_dmac_start_dma_rx() argument
158 struct renesas_sdhi *priv = host_to_priv(host); in renesas_sdhi_sys_dmac_start_dma_rx()
159 struct scatterlist *sg = host->sg_ptr, *sg_tmp; in renesas_sdhi_sys_dmac_start_dma_rx()
161 struct dma_chan *chan = host->chan_rx; in renesas_sdhi_sys_dmac_start_dma_rx()
165 unsigned int align = 1; /* 2-byte alignment */ in renesas_sdhi_sys_dmac_start_dma_rx()
167 for_each_sg(sg, sg_tmp, host->sg_len, i) { in renesas_sdhi_sys_dmac_start_dma_rx()
168 if (sg_tmp->offset & align) in renesas_sdhi_sys_dmac_start_dma_rx()
170 if (sg_tmp->length & align) { in renesas_sdhi_sys_dmac_start_dma_rx()
176 if ((!aligned && (host->sg_len > 1 || sg->length > PAGE_SIZE || in renesas_sdhi_sys_dmac_start_dma_rx()
178 ret = -EINVAL; in renesas_sdhi_sys_dmac_start_dma_rx()
182 if (sg->length < TMIO_MMC_MIN_DMA_LEN) in renesas_sdhi_sys_dmac_start_dma_rx()
185 /* The only sg element can be unaligned, use our bounce buffer then */ in renesas_sdhi_sys_dmac_start_dma_rx()
187 sg_init_one(&host->bounce_sg, host->bounce_buf, sg->length); in renesas_sdhi_sys_dmac_start_dma_rx()
188 host->sg_ptr = &host->bounce_sg; in renesas_sdhi_sys_dmac_start_dma_rx()
189 sg = host->sg_ptr; in renesas_sdhi_sys_dmac_start_dma_rx()
192 ret = dma_map_sg(chan->device->dev, sg, host->sg_len, DMA_FROM_DEVICE); in renesas_sdhi_sys_dmac_start_dma_rx()
198 reinit_completion(&priv->dma_priv.dma_dataend); in renesas_sdhi_sys_dmac_start_dma_rx()
199 desc->callback = renesas_sdhi_sys_dmac_dma_callback; in renesas_sdhi_sys_dmac_start_dma_rx()
200 desc->callback_param = host; in renesas_sdhi_sys_dmac_start_dma_rx()
207 host->dma_on = true; in renesas_sdhi_sys_dmac_start_dma_rx()
212 renesas_sdhi_sys_dmac_enable_dma(host, false); in renesas_sdhi_sys_dmac_start_dma_rx()
214 ret = -EIO; in renesas_sdhi_sys_dmac_start_dma_rx()
215 host->chan_rx = NULL; in renesas_sdhi_sys_dmac_start_dma_rx()
218 chan = host->chan_tx; in renesas_sdhi_sys_dmac_start_dma_rx()
220 host->chan_tx = NULL; in renesas_sdhi_sys_dmac_start_dma_rx()
223 dev_warn(&host->pdev->dev, in renesas_sdhi_sys_dmac_start_dma_rx()
228 static void renesas_sdhi_sys_dmac_start_dma_tx(struct tmio_mmc_host *host) in renesas_sdhi_sys_dmac_start_dma_tx() argument
230 struct renesas_sdhi *priv = host_to_priv(host); in renesas_sdhi_sys_dmac_start_dma_tx()
231 struct scatterlist *sg = host->sg_ptr, *sg_tmp; in renesas_sdhi_sys_dmac_start_dma_tx()
233 struct dma_chan *chan = host->chan_tx; in renesas_sdhi_sys_dmac_start_dma_tx()
237 unsigned int align = 1; /* 2-byte alignment */ in renesas_sdhi_sys_dmac_start_dma_tx()
239 for_each_sg(sg, sg_tmp, host->sg_len, i) { in renesas_sdhi_sys_dmac_start_dma_tx()
240 if (sg_tmp->offset & align) in renesas_sdhi_sys_dmac_start_dma_tx()
242 if (sg_tmp->length & align) { in renesas_sdhi_sys_dmac_start_dma_tx()
248 if ((!aligned && (host->sg_len > 1 || sg->length > PAGE_SIZE || in renesas_sdhi_sys_dmac_start_dma_tx()
250 ret = -EINVAL; in renesas_sdhi_sys_dmac_start_dma_tx()
254 if (sg->length < TMIO_MMC_MIN_DMA_LEN) in renesas_sdhi_sys_dmac_start_dma_tx()
257 /* The only sg element can be unaligned, use our bounce buffer then */ in renesas_sdhi_sys_dmac_start_dma_tx()
261 sg_init_one(&host->bounce_sg, host->bounce_buf, sg->length); in renesas_sdhi_sys_dmac_start_dma_tx()
262 memcpy(host->bounce_buf, sg_vaddr + sg->offset, host->bounce_sg.length); in renesas_sdhi_sys_dmac_start_dma_tx()
264 host->sg_ptr = &host->bounce_sg; in renesas_sdhi_sys_dmac_start_dma_tx()
265 sg = host->sg_ptr; in renesas_sdhi_sys_dmac_start_dma_tx()
268 ret = dma_map_sg(chan->device->dev, sg, host->sg_len, DMA_TO_DEVICE); in renesas_sdhi_sys_dmac_start_dma_tx()
274 reinit_completion(&priv->dma_priv.dma_dataend); in renesas_sdhi_sys_dmac_start_dma_tx()
275 desc->callback = renesas_sdhi_sys_dmac_dma_callback; in renesas_sdhi_sys_dmac_start_dma_tx()
276 desc->callback_param = host; in renesas_sdhi_sys_dmac_start_dma_tx()
283 host->dma_on = true; in renesas_sdhi_sys_dmac_start_dma_tx()
288 renesas_sdhi_sys_dmac_enable_dma(host, false); in renesas_sdhi_sys_dmac_start_dma_tx()
290 ret = -EIO; in renesas_sdhi_sys_dmac_start_dma_tx()
291 host->chan_tx = NULL; in renesas_sdhi_sys_dmac_start_dma_tx()
294 chan = host->chan_rx; in renesas_sdhi_sys_dmac_start_dma_tx()
296 host->chan_rx = NULL; in renesas_sdhi_sys_dmac_start_dma_tx()
299 dev_warn(&host->pdev->dev, in renesas_sdhi_sys_dmac_start_dma_tx()
304 static void renesas_sdhi_sys_dmac_start_dma(struct tmio_mmc_host *host, in renesas_sdhi_sys_dmac_start_dma() argument
307 if (data->flags & MMC_DATA_READ) { in renesas_sdhi_sys_dmac_start_dma()
308 if (host->chan_rx) in renesas_sdhi_sys_dmac_start_dma()
309 renesas_sdhi_sys_dmac_start_dma_rx(host); in renesas_sdhi_sys_dmac_start_dma()
311 if (host->chan_tx) in renesas_sdhi_sys_dmac_start_dma()
312 renesas_sdhi_sys_dmac_start_dma_tx(host); in renesas_sdhi_sys_dmac_start_dma()
318 struct tmio_mmc_host *host = from_work(host, work, dma_issue); in renesas_sdhi_sys_dmac_issue_work_fn() local
321 spin_lock_irq(&host->lock); in renesas_sdhi_sys_dmac_issue_work_fn()
323 if (host->data) { in renesas_sdhi_sys_dmac_issue_work_fn()
324 if (host->data->flags & MMC_DATA_READ) in renesas_sdhi_sys_dmac_issue_work_fn()
325 chan = host->chan_rx; in renesas_sdhi_sys_dmac_issue_work_fn()
327 chan = host->chan_tx; in renesas_sdhi_sys_dmac_issue_work_fn()
330 spin_unlock_irq(&host->lock); in renesas_sdhi_sys_dmac_issue_work_fn()
332 tmio_mmc_enable_mmc_irqs(host, TMIO_STAT_DATAEND); in renesas_sdhi_sys_dmac_issue_work_fn()
338 static void renesas_sdhi_sys_dmac_request_dma(struct tmio_mmc_host *host, in renesas_sdhi_sys_dmac_request_dma() argument
341 struct renesas_sdhi *priv = host_to_priv(host); in renesas_sdhi_sys_dmac_request_dma()
343 /* We can only either use DMA for both Tx and Rx or not use it at all */ in renesas_sdhi_sys_dmac_request_dma()
344 if (!host->pdev->dev.of_node && in renesas_sdhi_sys_dmac_request_dma()
345 (!pdata->chan_priv_tx || !pdata->chan_priv_rx)) in renesas_sdhi_sys_dmac_request_dma()
348 if (!host->chan_tx && !host->chan_rx) { in renesas_sdhi_sys_dmac_request_dma()
349 struct resource *res = platform_get_resource(host->pdev, in renesas_sdhi_sys_dmac_request_dma()
361 host->chan_tx = dma_request_slave_channel_compat(mask, in renesas_sdhi_sys_dmac_request_dma()
362 priv->dma_priv.filter, pdata->chan_priv_tx, in renesas_sdhi_sys_dmac_request_dma()
363 &host->pdev->dev, "tx"); in renesas_sdhi_sys_dmac_request_dma()
364 dev_dbg(&host->pdev->dev, "%s: TX: got channel %p\n", __func__, in renesas_sdhi_sys_dmac_request_dma()
365 host->chan_tx); in renesas_sdhi_sys_dmac_request_dma()
367 if (!host->chan_tx) in renesas_sdhi_sys_dmac_request_dma()
371 cfg.dst_addr = res->start + in renesas_sdhi_sys_dmac_request_dma()
372 (CTL_SD_DATA_PORT << host->bus_shift); in renesas_sdhi_sys_dmac_request_dma()
373 cfg.dst_addr_width = priv->dma_priv.dma_buswidth; in renesas_sdhi_sys_dmac_request_dma()
377 ret = dmaengine_slave_config(host->chan_tx, &cfg); in renesas_sdhi_sys_dmac_request_dma()
381 host->chan_rx = dma_request_slave_channel_compat(mask, in renesas_sdhi_sys_dmac_request_dma()
382 priv->dma_priv.filter, pdata->chan_priv_rx, in renesas_sdhi_sys_dmac_request_dma()
383 &host->pdev->dev, "rx"); in renesas_sdhi_sys_dmac_request_dma()
384 dev_dbg(&host->pdev->dev, "%s: RX: got channel %p\n", __func__, in renesas_sdhi_sys_dmac_request_dma()
385 host->chan_rx); in renesas_sdhi_sys_dmac_request_dma()
387 if (!host->chan_rx) in renesas_sdhi_sys_dmac_request_dma()
391 cfg.src_addr = cfg.dst_addr + host->pdata->dma_rx_offset; in renesas_sdhi_sys_dmac_request_dma()
392 cfg.src_addr_width = priv->dma_priv.dma_buswidth; in renesas_sdhi_sys_dmac_request_dma()
396 ret = dmaengine_slave_config(host->chan_rx, &cfg); in renesas_sdhi_sys_dmac_request_dma()
400 host->bounce_buf = (u8 *)__get_free_page(GFP_KERNEL | GFP_DMA); in renesas_sdhi_sys_dmac_request_dma()
401 if (!host->bounce_buf) in renesas_sdhi_sys_dmac_request_dma()
404 init_completion(&priv->dma_priv.dma_dataend); in renesas_sdhi_sys_dmac_request_dma()
405 INIT_WORK(&host->dma_issue, in renesas_sdhi_sys_dmac_request_dma()
409 renesas_sdhi_sys_dmac_enable_dma(host, true); 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()
423 static void renesas_sdhi_sys_dmac_release_dma(struct tmio_mmc_host *host) in renesas_sdhi_sys_dmac_release_dma() argument
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()