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>
14 #include <linux/mmc/host.h>
70 * - host->chan_{rx,tx} will be used as a flag of enabling/disabling the dma
71 * - Since this SDHI DMAC register set has 16 but 32-bit width, we
77 * Workaround for avoiding to use RX DMAC by multiple channels. On R-Car M3-W
80 * DMAC interrupt happened. So, this driver then uses one RX DMAC channel only.
100 .scc_offset = 0 - 0x1000,
103 /* DMAC can handle 32bit blk count but only 1 segment */
118 /* DMAC can handle 32bit blk count but only 1 segment */
134 /* DMAC can handle 32bit blk count but only 1 segment */
221 * So, we want to treat them equally and only have a match for ES1.2 to enforce
279 { .compatible = "renesas,sdhi-r7s9210", .data = &of_rza2_compatible, },
280 { .compatible = "renesas,sdhi-mmc-r8a77470", .data = &of_rcar_gen3_compatible, },
281 { .compatible = "renesas,sdhi-r8a7795", .data = &of_r8a7795_compatible, },
282 { .compatible = "renesas,sdhi-r8a77961", .data = &of_r8a77961_compatible, },
283 { .compatible = "renesas,sdhi-r8a77965", .data = &of_r8a77965_compatible, },
284 { .compatible = "renesas,sdhi-r8a77970", .data = &of_r8a77970_compatible, },
285 { .compatible = "renesas,sdhi-r8a77990", .data = &of_r8a77990_compatible, },
286 { .compatible = "renesas,sdhi-r8a77995", .data = &of_rcar_gen3_nohs400_compatible, },
287 { .compatible = "renesas,sdhi-r9a09g011", .data = &of_rzg2l_compatible, },
288 { .compatible = "renesas,sdhi-r9a09g057", .data = &of_rzg2l_compatible, },
289 { .compatible = "renesas,rzg2l-sdhi", .data = &of_rzg2l_compatible, },
290 { .compatible = "renesas,rcar-gen3-sdhi", .data = &of_rcar_gen3_compatible, },
291 { .compatible = "renesas,rcar-gen4-sdhi", .data = &of_rcar_gen3_compatible, },
297 renesas_sdhi_internal_dmac_enable_dma(struct tmio_mmc_host *host, bool enable) in renesas_sdhi_internal_dmac_enable_dma() argument
299 struct renesas_sdhi *priv = host_to_priv(host); in renesas_sdhi_internal_dmac_enable_dma()
304 if (!host->chan_tx || !host->chan_rx) in renesas_sdhi_internal_dmac_enable_dma()
307 writel(enable ? ~dma_irqs : INFO1_MASK_CLEAR, host->ctl + DM_CM_INFO1_MASK); in renesas_sdhi_internal_dmac_enable_dma()
309 if (priv->dma_priv.enable) in renesas_sdhi_internal_dmac_enable_dma()
310 priv->dma_priv.enable(host, enable); in renesas_sdhi_internal_dmac_enable_dma()
314 renesas_sdhi_internal_dmac_abort_dma(struct tmio_mmc_host *host) in renesas_sdhi_internal_dmac_abort_dma() argument
318 renesas_sdhi_internal_dmac_enable_dma(host, false); in renesas_sdhi_internal_dmac_abort_dma()
320 writel(RST_RESERVED_BITS & ~val, host->ctl + DM_CM_RST); in renesas_sdhi_internal_dmac_abort_dma()
321 writel(RST_RESERVED_BITS | val, host->ctl + DM_CM_RST); in renesas_sdhi_internal_dmac_abort_dma()
325 renesas_sdhi_internal_dmac_enable_dma(host, true); in renesas_sdhi_internal_dmac_abort_dma()
328 static bool renesas_sdhi_internal_dmac_dma_irq(struct tmio_mmc_host *host) in renesas_sdhi_internal_dmac_dma_irq() argument
330 struct renesas_sdhi *priv = host_to_priv(host); in renesas_sdhi_internal_dmac_dma_irq()
331 struct renesas_sdhi_dma *dma_priv = &priv->dma_priv; in renesas_sdhi_internal_dmac_dma_irq()
336 u32 status = readl(host->ctl + DM_CM_INFO1); in renesas_sdhi_internal_dmac_dma_irq()
339 writel(status ^ dma_irqs, host->ctl + DM_CM_INFO1); in renesas_sdhi_internal_dmac_dma_irq()
340 set_bit(SDHI_DMA_END_FLAG_DMA, &dma_priv->end_flags); in renesas_sdhi_internal_dmac_dma_irq()
341 if (test_bit(SDHI_DMA_END_FLAG_ACCESS, &dma_priv->end_flags)) in renesas_sdhi_internal_dmac_dma_irq()
342 queue_work(system_bh_wq, &dma_priv->dma_complete); in renesas_sdhi_internal_dmac_dma_irq()
349 renesas_sdhi_internal_dmac_dataend_dma(struct tmio_mmc_host *host) in renesas_sdhi_internal_dmac_dataend_dma() argument
351 struct renesas_sdhi *priv = host_to_priv(host); in renesas_sdhi_internal_dmac_dataend_dma()
352 struct renesas_sdhi_dma *dma_priv = &priv->dma_priv; in renesas_sdhi_internal_dmac_dataend_dma()
354 set_bit(SDHI_DMA_END_FLAG_ACCESS, &dma_priv->end_flags); in renesas_sdhi_internal_dmac_dataend_dma()
355 if (test_bit(SDHI_DMA_END_FLAG_DMA, &dma_priv->end_flags) || in renesas_sdhi_internal_dmac_dataend_dma()
356 host->data->error) in renesas_sdhi_internal_dmac_dataend_dma()
357 queue_work(system_bh_wq, &dma_priv->dma_complete); in renesas_sdhi_internal_dmac_dataend_dma()
362 * sg pointers in two mmc_data by .pre_req(), but tmio host can have a single
363 * sg_ptr only. So, renesas_sdhi_internal_dmac_{un}map() should use a sg
364 * pointer in a mmc_data instead of host->sg_ptr.
367 renesas_sdhi_internal_dmac_unmap(struct tmio_mmc_host *host, in renesas_sdhi_internal_dmac_unmap() argument
371 bool unmap = cookie == COOKIE_UNMAPPED ? (data->host_cookie != cookie) : in renesas_sdhi_internal_dmac_unmap()
372 (data->host_cookie == cookie); in renesas_sdhi_internal_dmac_unmap()
375 dma_unmap_sg(&host->pdev->dev, data->sg, data->sg_len, in renesas_sdhi_internal_dmac_unmap()
377 data->host_cookie = COOKIE_UNMAPPED; in renesas_sdhi_internal_dmac_unmap()
382 renesas_sdhi_internal_dmac_map(struct tmio_mmc_host *host, in renesas_sdhi_internal_dmac_map() argument
386 if (data->host_cookie == COOKIE_PRE_MAPPED) in renesas_sdhi_internal_dmac_map()
389 if (!dma_map_sg(&host->pdev->dev, data->sg, data->sg_len, in renesas_sdhi_internal_dmac_map()
393 data->host_cookie = cookie; in renesas_sdhi_internal_dmac_map()
395 /* This DMAC needs buffers to be 128-byte aligned */ in renesas_sdhi_internal_dmac_map()
396 if (!IS_ALIGNED(sg_dma_address(data->sg), 128)) { in renesas_sdhi_internal_dmac_map()
397 renesas_sdhi_internal_dmac_unmap(host, data, cookie); in renesas_sdhi_internal_dmac_map()
405 renesas_sdhi_internal_dmac_start_dma(struct tmio_mmc_host *host, in renesas_sdhi_internal_dmac_start_dma() argument
408 struct renesas_sdhi *priv = host_to_priv(host); in renesas_sdhi_internal_dmac_start_dma()
409 struct scatterlist *sg = host->sg_ptr; in renesas_sdhi_internal_dmac_start_dma()
415 if (!renesas_sdhi_internal_dmac_map(host, data, COOKIE_MAPPED)) in renesas_sdhi_internal_dmac_start_dma()
418 if (data->flags & MMC_DATA_READ) { in renesas_sdhi_internal_dmac_start_dma()
427 priv->dma_priv.end_flags = 0; in renesas_sdhi_internal_dmac_start_dma()
428 renesas_sdhi_internal_dmac_enable_dma(host, true); in renesas_sdhi_internal_dmac_start_dma()
431 writel(dtran_mode, host->ctl + DM_CM_DTRAN_MODE); in renesas_sdhi_internal_dmac_start_dma()
432 writel(sg_dma_address(sg), host->ctl + DM_DTRAN_ADDR); in renesas_sdhi_internal_dmac_start_dma()
434 host->dma_on = true; in renesas_sdhi_internal_dmac_start_dma()
439 renesas_sdhi_internal_dmac_unmap(host, data, COOKIE_UNMAPPED); in renesas_sdhi_internal_dmac_start_dma()
442 renesas_sdhi_internal_dmac_enable_dma(host, false); in renesas_sdhi_internal_dmac_start_dma()
447 struct tmio_mmc_host *host = from_work(host, work, dma_issue); in renesas_sdhi_internal_dmac_issue_work_fn() local
448 struct renesas_sdhi *priv = host_to_priv(host); in renesas_sdhi_internal_dmac_issue_work_fn()
450 tmio_mmc_enable_mmc_irqs(host, TMIO_STAT_DATAEND); in renesas_sdhi_internal_dmac_issue_work_fn()
452 if (!host->cmd->error) { in renesas_sdhi_internal_dmac_issue_work_fn()
454 writel(DTRAN_CTRL_DM_START, host->ctl + DM_CM_DTRAN_CTRL); in renesas_sdhi_internal_dmac_issue_work_fn()
457 set_bit(SDHI_DMA_END_FLAG_DMA, &priv->dma_priv.end_flags); in renesas_sdhi_internal_dmac_issue_work_fn()
458 if (test_bit(SDHI_DMA_END_FLAG_ACCESS, &priv->dma_priv.end_flags)) in renesas_sdhi_internal_dmac_issue_work_fn()
459 queue_work(system_bh_wq, &priv->dma_priv.dma_complete); in renesas_sdhi_internal_dmac_issue_work_fn()
463 static bool renesas_sdhi_internal_dmac_complete(struct tmio_mmc_host *host) in renesas_sdhi_internal_dmac_complete() argument
467 if (!host->dma_on) in renesas_sdhi_internal_dmac_complete()
470 if (!host->data) in renesas_sdhi_internal_dmac_complete()
473 if (host->data->flags & MMC_DATA_READ) in renesas_sdhi_internal_dmac_complete()
478 renesas_sdhi_internal_dmac_enable_dma(host, false); in renesas_sdhi_internal_dmac_complete()
479 renesas_sdhi_internal_dmac_unmap(host, host->data, COOKIE_MAPPED); in renesas_sdhi_internal_dmac_complete()
484 host->dma_on = false; in renesas_sdhi_internal_dmac_complete()
493 struct tmio_mmc_host *host = priv->host; in renesas_sdhi_internal_dmac_complete_work_fn() local
495 spin_lock_irq(&host->lock); in renesas_sdhi_internal_dmac_complete_work_fn()
496 if (!renesas_sdhi_internal_dmac_complete(host)) in renesas_sdhi_internal_dmac_complete_work_fn()
499 tmio_mmc_do_data_irq(host); in renesas_sdhi_internal_dmac_complete_work_fn()
501 spin_unlock_irq(&host->lock); in renesas_sdhi_internal_dmac_complete_work_fn()
504 static void renesas_sdhi_internal_dmac_end_dma(struct tmio_mmc_host *host) in renesas_sdhi_internal_dmac_end_dma() argument
506 if (host->data) in renesas_sdhi_internal_dmac_end_dma()
507 renesas_sdhi_internal_dmac_complete(host); in renesas_sdhi_internal_dmac_end_dma()
514 struct tmio_mmc_host *host = mmc_priv(mmc); in renesas_sdhi_internal_dmac_post_req() local
515 struct mmc_data *data = mrq->data; in renesas_sdhi_internal_dmac_post_req()
520 renesas_sdhi_internal_dmac_unmap(host, data, COOKIE_UNMAPPED); in renesas_sdhi_internal_dmac_post_req()
526 struct tmio_mmc_host *host = mmc_priv(mmc); in renesas_sdhi_internal_dmac_pre_req() local
527 struct mmc_data *data = mrq->data; in renesas_sdhi_internal_dmac_pre_req()
532 data->host_cookie = COOKIE_UNMAPPED; in renesas_sdhi_internal_dmac_pre_req()
533 renesas_sdhi_internal_dmac_map(host, data, COOKIE_PRE_MAPPED); in renesas_sdhi_internal_dmac_pre_req()
537 renesas_sdhi_internal_dmac_request_dma(struct tmio_mmc_host *host, in renesas_sdhi_internal_dmac_request_dma() argument
540 struct renesas_sdhi *priv = host_to_priv(host); in renesas_sdhi_internal_dmac_request_dma()
543 writel(INFO1_MASK_CLEAR, host->ctl + DM_CM_INFO1_MASK); in renesas_sdhi_internal_dmac_request_dma()
544 writel(INFO2_MASK_CLEAR, host->ctl + DM_CM_INFO2_MASK); in renesas_sdhi_internal_dmac_request_dma()
545 writel(0, host->ctl + DM_CM_INFO1); in renesas_sdhi_internal_dmac_request_dma()
546 writel(0, host->ctl + DM_CM_INFO2); in renesas_sdhi_internal_dmac_request_dma()
548 /* Each value is set to non-zero to assume "enabling" each DMA */ in renesas_sdhi_internal_dmac_request_dma()
549 host->chan_rx = host->chan_tx = (void *)0xdeadbeaf; in renesas_sdhi_internal_dmac_request_dma()
551 INIT_WORK(&priv->dma_priv.dma_complete, in renesas_sdhi_internal_dmac_request_dma()
553 INIT_WORK(&host->dma_issue, in renesas_sdhi_internal_dmac_request_dma()
557 host->ops.pre_req = renesas_sdhi_internal_dmac_pre_req; in renesas_sdhi_internal_dmac_request_dma()
558 host->ops.post_req = renesas_sdhi_internal_dmac_post_req; in renesas_sdhi_internal_dmac_request_dma()
562 renesas_sdhi_internal_dmac_release_dma(struct tmio_mmc_host *host) in renesas_sdhi_internal_dmac_release_dma() argument
565 host->chan_rx = host->chan_tx = NULL; in renesas_sdhi_internal_dmac_release_dma()
584 struct device *dev = &pdev->dev; in renesas_sdhi_internal_dmac_probe()
586 of_data_quirks = of_device_get_match_data(&pdev->dev); in renesas_sdhi_internal_dmac_probe()
587 quirks = of_data_quirks->quirks; in renesas_sdhi_internal_dmac_probe()
591 quirks = attr->data; in renesas_sdhi_internal_dmac_probe()
597 of_data_quirks->of_data, quirks); in renesas_sdhi_internal_dmac_probe()