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-17 Horms Solutions, Simon Horman
7 * Copyright (C) 2018-19 Sang Engineering, Wolfram Sang
12 #include <linux/dma-mapping.h>
13 #include <linux/io-64-nonatomic-hi-lo.h>
15 #include <linux/mmc/host.h>
69 * - host->chan_{rx,tx} will be used as a flag of enabling/disabling the dma
70 * - Since this SDHI DMAC register set has 16 but 32-bit width, we
76 * Workaround for avoiding to use RX DMAC by multiple channels. On R-Car M3-W
79 * DMAC interrupt happened. So, this driver then uses one RX DMAC channel only.
99 .scc_offset = 0 - 0x1000,
102 /* DMAC can handle 32bit blk count but only 1 segment */
117 /* DMAC can handle 32bit blk count but only 1 segment */
133 /* DMAC can handle 32bit blk count but only 1 segment */
220 * So, we want to treat them equally and only have a match for ES1.2 to enforce
278 { .compatible = "renesas,sdhi-r7s9210", .data = &of_rza2_compatible, },
279 { .compatible = "renesas,sdhi-mmc-r8a77470", .data = &of_rcar_gen3_compatible, },
280 { .compatible = "renesas,sdhi-r8a7795", .data = &of_r8a7795_compatible, },
281 { .compatible = "renesas,sdhi-r8a77961", .data = &of_r8a77961_compatible, },
282 { .compatible = "renesas,sdhi-r8a77965", .data = &of_r8a77965_compatible, },
283 { .compatible = "renesas,sdhi-r8a77970", .data = &of_r8a77970_compatible, },
284 { .compatible = "renesas,sdhi-r8a77990", .data = &of_r8a77990_compatible, },
285 { .compatible = "renesas,sdhi-r8a77995", .data = &of_rcar_gen3_nohs400_compatible, },
286 { .compatible = "renesas,sdhi-r9a09g011", .data = &of_r9a09g011_compatible, },
287 { .compatible = "renesas,rcar-gen3-sdhi", .data = &of_rcar_gen3_compatible, },
288 { .compatible = "renesas,rcar-gen4-sdhi", .data = &of_rcar_gen3_compatible, },
294 renesas_sdhi_internal_dmac_enable_dma(struct tmio_mmc_host *host, bool enable) in renesas_sdhi_internal_dmac_enable_dma() argument
296 struct renesas_sdhi *priv = host_to_priv(host); in renesas_sdhi_internal_dmac_enable_dma()
301 if (!host->chan_tx || !host->chan_rx) in renesas_sdhi_internal_dmac_enable_dma()
304 writel(enable ? ~dma_irqs : INFO1_MASK_CLEAR, host->ctl + DM_CM_INFO1_MASK); in renesas_sdhi_internal_dmac_enable_dma()
306 if (priv->dma_priv.enable) in renesas_sdhi_internal_dmac_enable_dma()
307 priv->dma_priv.enable(host, enable); in renesas_sdhi_internal_dmac_enable_dma()
311 renesas_sdhi_internal_dmac_abort_dma(struct tmio_mmc_host *host) in renesas_sdhi_internal_dmac_abort_dma() argument
315 renesas_sdhi_internal_dmac_enable_dma(host, false); in renesas_sdhi_internal_dmac_abort_dma()
317 writel(RST_RESERVED_BITS & ~val, host->ctl + DM_CM_RST); in renesas_sdhi_internal_dmac_abort_dma()
318 writel(RST_RESERVED_BITS | val, host->ctl + DM_CM_RST); in renesas_sdhi_internal_dmac_abort_dma()
322 renesas_sdhi_internal_dmac_enable_dma(host, true); in renesas_sdhi_internal_dmac_abort_dma()
325 static bool renesas_sdhi_internal_dmac_dma_irq(struct tmio_mmc_host *host) in renesas_sdhi_internal_dmac_dma_irq() argument
327 struct renesas_sdhi *priv = host_to_priv(host); in renesas_sdhi_internal_dmac_dma_irq()
328 struct renesas_sdhi_dma *dma_priv = &priv->dma_priv; in renesas_sdhi_internal_dmac_dma_irq()
333 u32 status = readl(host->ctl + DM_CM_INFO1); in renesas_sdhi_internal_dmac_dma_irq()
336 writel(status ^ dma_irqs, host->ctl + DM_CM_INFO1); in renesas_sdhi_internal_dmac_dma_irq()
337 set_bit(SDHI_DMA_END_FLAG_DMA, &dma_priv->end_flags); in renesas_sdhi_internal_dmac_dma_irq()
338 if (test_bit(SDHI_DMA_END_FLAG_ACCESS, &dma_priv->end_flags)) in renesas_sdhi_internal_dmac_dma_irq()
339 tasklet_schedule(&dma_priv->dma_complete); in renesas_sdhi_internal_dmac_dma_irq()
346 renesas_sdhi_internal_dmac_dataend_dma(struct tmio_mmc_host *host) in renesas_sdhi_internal_dmac_dataend_dma() argument
348 struct renesas_sdhi *priv = host_to_priv(host); in renesas_sdhi_internal_dmac_dataend_dma()
349 struct renesas_sdhi_dma *dma_priv = &priv->dma_priv; in renesas_sdhi_internal_dmac_dataend_dma()
351 set_bit(SDHI_DMA_END_FLAG_ACCESS, &dma_priv->end_flags); in renesas_sdhi_internal_dmac_dataend_dma()
352 if (test_bit(SDHI_DMA_END_FLAG_DMA, &dma_priv->end_flags) || in renesas_sdhi_internal_dmac_dataend_dma()
353 host->data->error) in renesas_sdhi_internal_dmac_dataend_dma()
354 tasklet_schedule(&dma_priv->dma_complete); in renesas_sdhi_internal_dmac_dataend_dma()
359 * sg pointers in two mmc_data by .pre_req(), but tmio host can have a single
360 * sg_ptr only. So, renesas_sdhi_internal_dmac_{un}map() should use a sg
361 * pointer in a mmc_data instead of host->sg_ptr.
364 renesas_sdhi_internal_dmac_unmap(struct tmio_mmc_host *host, in renesas_sdhi_internal_dmac_unmap() argument
368 bool unmap = cookie == COOKIE_UNMAPPED ? (data->host_cookie != cookie) : in renesas_sdhi_internal_dmac_unmap()
369 (data->host_cookie == cookie); in renesas_sdhi_internal_dmac_unmap()
372 dma_unmap_sg(&host->pdev->dev, data->sg, data->sg_len, in renesas_sdhi_internal_dmac_unmap()
374 data->host_cookie = COOKIE_UNMAPPED; in renesas_sdhi_internal_dmac_unmap()
379 renesas_sdhi_internal_dmac_map(struct tmio_mmc_host *host, in renesas_sdhi_internal_dmac_map() argument
383 if (data->host_cookie == COOKIE_PRE_MAPPED) in renesas_sdhi_internal_dmac_map()
386 if (!dma_map_sg(&host->pdev->dev, data->sg, data->sg_len, in renesas_sdhi_internal_dmac_map()
390 data->host_cookie = cookie; in renesas_sdhi_internal_dmac_map()
392 /* This DMAC needs buffers to be 128-byte aligned */ in renesas_sdhi_internal_dmac_map()
393 if (!IS_ALIGNED(sg_dma_address(data->sg), 128)) { in renesas_sdhi_internal_dmac_map()
394 renesas_sdhi_internal_dmac_unmap(host, data, cookie); in renesas_sdhi_internal_dmac_map()
402 renesas_sdhi_internal_dmac_start_dma(struct tmio_mmc_host *host, in renesas_sdhi_internal_dmac_start_dma() argument
405 struct renesas_sdhi *priv = host_to_priv(host); in renesas_sdhi_internal_dmac_start_dma()
406 struct scatterlist *sg = host->sg_ptr; in renesas_sdhi_internal_dmac_start_dma()
412 if (!renesas_sdhi_internal_dmac_map(host, data, COOKIE_MAPPED)) in renesas_sdhi_internal_dmac_start_dma()
415 if (data->flags & MMC_DATA_READ) { in renesas_sdhi_internal_dmac_start_dma()
424 priv->dma_priv.end_flags = 0; in renesas_sdhi_internal_dmac_start_dma()
425 renesas_sdhi_internal_dmac_enable_dma(host, true); in renesas_sdhi_internal_dmac_start_dma()
428 writel(dtran_mode, host->ctl + DM_CM_DTRAN_MODE); in renesas_sdhi_internal_dmac_start_dma()
429 writel(sg_dma_address(sg), host->ctl + DM_DTRAN_ADDR); in renesas_sdhi_internal_dmac_start_dma()
431 host->dma_on = true; in renesas_sdhi_internal_dmac_start_dma()
436 renesas_sdhi_internal_dmac_unmap(host, data, COOKIE_UNMAPPED); in renesas_sdhi_internal_dmac_start_dma()
439 renesas_sdhi_internal_dmac_enable_dma(host, false); in renesas_sdhi_internal_dmac_start_dma()
444 struct tmio_mmc_host *host = (struct tmio_mmc_host *)arg; in renesas_sdhi_internal_dmac_issue_tasklet_fn() local
445 struct renesas_sdhi *priv = host_to_priv(host); in renesas_sdhi_internal_dmac_issue_tasklet_fn()
447 tmio_mmc_enable_mmc_irqs(host, TMIO_STAT_DATAEND); in renesas_sdhi_internal_dmac_issue_tasklet_fn()
449 if (!host->cmd->error) { in renesas_sdhi_internal_dmac_issue_tasklet_fn()
451 writel(DTRAN_CTRL_DM_START, host->ctl + DM_CM_DTRAN_CTRL); in renesas_sdhi_internal_dmac_issue_tasklet_fn()
454 set_bit(SDHI_DMA_END_FLAG_DMA, &priv->dma_priv.end_flags); in renesas_sdhi_internal_dmac_issue_tasklet_fn()
455 if (test_bit(SDHI_DMA_END_FLAG_ACCESS, &priv->dma_priv.end_flags)) in renesas_sdhi_internal_dmac_issue_tasklet_fn()
456 tasklet_schedule(&priv->dma_priv.dma_complete); in renesas_sdhi_internal_dmac_issue_tasklet_fn()
460 static bool renesas_sdhi_internal_dmac_complete(struct tmio_mmc_host *host) in renesas_sdhi_internal_dmac_complete() argument
464 if (!host->dma_on) in renesas_sdhi_internal_dmac_complete()
467 if (!host->data) in renesas_sdhi_internal_dmac_complete()
470 if (host->data->flags & MMC_DATA_READ) in renesas_sdhi_internal_dmac_complete()
475 renesas_sdhi_internal_dmac_enable_dma(host, false); in renesas_sdhi_internal_dmac_complete()
476 renesas_sdhi_internal_dmac_unmap(host, host->data, COOKIE_MAPPED); in renesas_sdhi_internal_dmac_complete()
481 host->dma_on = false; in renesas_sdhi_internal_dmac_complete()
488 struct tmio_mmc_host *host = (struct tmio_mmc_host *)arg; in renesas_sdhi_internal_dmac_complete_tasklet_fn() local
490 spin_lock_irq(&host->lock); in renesas_sdhi_internal_dmac_complete_tasklet_fn()
491 if (!renesas_sdhi_internal_dmac_complete(host)) in renesas_sdhi_internal_dmac_complete_tasklet_fn()
494 tmio_mmc_do_data_irq(host); in renesas_sdhi_internal_dmac_complete_tasklet_fn()
496 spin_unlock_irq(&host->lock); in renesas_sdhi_internal_dmac_complete_tasklet_fn()
499 static void renesas_sdhi_internal_dmac_end_dma(struct tmio_mmc_host *host) in renesas_sdhi_internal_dmac_end_dma() argument
501 if (host->data) in renesas_sdhi_internal_dmac_end_dma()
502 renesas_sdhi_internal_dmac_complete(host); in renesas_sdhi_internal_dmac_end_dma()
509 struct tmio_mmc_host *host = mmc_priv(mmc); in renesas_sdhi_internal_dmac_post_req() local
510 struct mmc_data *data = mrq->data; in renesas_sdhi_internal_dmac_post_req()
515 renesas_sdhi_internal_dmac_unmap(host, data, COOKIE_UNMAPPED); in renesas_sdhi_internal_dmac_post_req()
521 struct tmio_mmc_host *host = mmc_priv(mmc); in renesas_sdhi_internal_dmac_pre_req() local
522 struct mmc_data *data = mrq->data; in renesas_sdhi_internal_dmac_pre_req()
527 data->host_cookie = COOKIE_UNMAPPED; in renesas_sdhi_internal_dmac_pre_req()
528 renesas_sdhi_internal_dmac_map(host, data, COOKIE_PRE_MAPPED); in renesas_sdhi_internal_dmac_pre_req()
532 renesas_sdhi_internal_dmac_request_dma(struct tmio_mmc_host *host, in renesas_sdhi_internal_dmac_request_dma() argument
535 struct renesas_sdhi *priv = host_to_priv(host); in renesas_sdhi_internal_dmac_request_dma()
538 writel(INFO1_MASK_CLEAR, host->ctl + DM_CM_INFO1_MASK); in renesas_sdhi_internal_dmac_request_dma()
539 writel(INFO2_MASK_CLEAR, host->ctl + DM_CM_INFO2_MASK); in renesas_sdhi_internal_dmac_request_dma()
540 writel(0, host->ctl + DM_CM_INFO1); in renesas_sdhi_internal_dmac_request_dma()
541 writel(0, host->ctl + DM_CM_INFO2); in renesas_sdhi_internal_dmac_request_dma()
543 /* Each value is set to non-zero to assume "enabling" each DMA */ in renesas_sdhi_internal_dmac_request_dma()
544 host->chan_rx = host->chan_tx = (void *)0xdeadbeaf; in renesas_sdhi_internal_dmac_request_dma()
546 tasklet_init(&priv->dma_priv.dma_complete, in renesas_sdhi_internal_dmac_request_dma()
548 (unsigned long)host); in renesas_sdhi_internal_dmac_request_dma()
549 tasklet_init(&host->dma_issue, in renesas_sdhi_internal_dmac_request_dma()
551 (unsigned long)host); in renesas_sdhi_internal_dmac_request_dma()
554 host->ops.pre_req = renesas_sdhi_internal_dmac_pre_req; in renesas_sdhi_internal_dmac_request_dma()
555 host->ops.post_req = renesas_sdhi_internal_dmac_post_req; in renesas_sdhi_internal_dmac_request_dma()
559 renesas_sdhi_internal_dmac_release_dma(struct tmio_mmc_host *host) in renesas_sdhi_internal_dmac_release_dma() argument
562 host->chan_rx = host->chan_tx = NULL; in renesas_sdhi_internal_dmac_release_dma()
581 struct device *dev = &pdev->dev; in renesas_sdhi_internal_dmac_probe()
583 of_data_quirks = of_device_get_match_data(&pdev->dev); in renesas_sdhi_internal_dmac_probe()
584 quirks = of_data_quirks->quirks; in renesas_sdhi_internal_dmac_probe()
588 quirks = attr->data; in renesas_sdhi_internal_dmac_probe()
594 of_data_quirks->of_data, quirks); in renesas_sdhi_internal_dmac_probe()