162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * DMA support for Internal DMAC with SDHI SD/SDIO controller 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2016-19 Renesas Electronics Corporation 662306a36Sopenharmony_ci * Copyright (C) 2016-17 Horms Solutions, Simon Horman 762306a36Sopenharmony_ci * Copyright (C) 2018-19 Sang Engineering, Wolfram Sang 862306a36Sopenharmony_ci */ 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#include <linux/bitops.h> 1162306a36Sopenharmony_ci#include <linux/device.h> 1262306a36Sopenharmony_ci#include <linux/dma-mapping.h> 1362306a36Sopenharmony_ci#include <linux/io-64-nonatomic-hi-lo.h> 1462306a36Sopenharmony_ci#include <linux/mfd/tmio.h> 1562306a36Sopenharmony_ci#include <linux/mmc/host.h> 1662306a36Sopenharmony_ci#include <linux/mod_devicetable.h> 1762306a36Sopenharmony_ci#include <linux/module.h> 1862306a36Sopenharmony_ci#include <linux/of.h> 1962306a36Sopenharmony_ci#include <linux/platform_device.h> 2062306a36Sopenharmony_ci#include <linux/pagemap.h> 2162306a36Sopenharmony_ci#include <linux/scatterlist.h> 2262306a36Sopenharmony_ci#include <linux/sys_soc.h> 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ci#include "renesas_sdhi.h" 2562306a36Sopenharmony_ci#include "tmio_mmc.h" 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci#define DM_CM_DTRAN_MODE 0x820 2862306a36Sopenharmony_ci#define DM_CM_DTRAN_CTRL 0x828 2962306a36Sopenharmony_ci#define DM_CM_RST 0x830 3062306a36Sopenharmony_ci#define DM_CM_INFO1 0x840 3162306a36Sopenharmony_ci#define DM_CM_INFO1_MASK 0x848 3262306a36Sopenharmony_ci#define DM_CM_INFO2 0x850 3362306a36Sopenharmony_ci#define DM_CM_INFO2_MASK 0x858 3462306a36Sopenharmony_ci#define DM_DTRAN_ADDR 0x880 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_ci/* DM_CM_DTRAN_MODE */ 3762306a36Sopenharmony_ci#define DTRAN_MODE_CH_NUM_CH0 0 /* "downstream" = for write commands */ 3862306a36Sopenharmony_ci#define DTRAN_MODE_CH_NUM_CH1 BIT(16) /* "upstream" = for read commands */ 3962306a36Sopenharmony_ci#define DTRAN_MODE_BUS_WIDTH (BIT(5) | BIT(4)) 4062306a36Sopenharmony_ci#define DTRAN_MODE_ADDR_MODE BIT(0) /* 1 = Increment address, 0 = Fixed */ 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ci/* DM_CM_DTRAN_CTRL */ 4362306a36Sopenharmony_ci#define DTRAN_CTRL_DM_START BIT(0) 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_ci/* DM_CM_RST */ 4662306a36Sopenharmony_ci#define RST_DTRANRST1 BIT(9) 4762306a36Sopenharmony_ci#define RST_DTRANRST0 BIT(8) 4862306a36Sopenharmony_ci#define RST_RESERVED_BITS GENMASK_ULL(31, 0) 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_ci/* DM_CM_INFO1 and DM_CM_INFO1_MASK */ 5162306a36Sopenharmony_ci#define INFO1_MASK_CLEAR GENMASK_ULL(31, 0) 5262306a36Sopenharmony_ci#define INFO1_DTRANEND1 BIT(20) 5362306a36Sopenharmony_ci#define INFO1_DTRANEND1_OLD BIT(17) 5462306a36Sopenharmony_ci#define INFO1_DTRANEND0 BIT(16) 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci/* DM_CM_INFO2 and DM_CM_INFO2_MASK */ 5762306a36Sopenharmony_ci#define INFO2_MASK_CLEAR GENMASK_ULL(31, 0) 5862306a36Sopenharmony_ci#define INFO2_DTRANERR1 BIT(17) 5962306a36Sopenharmony_ci#define INFO2_DTRANERR0 BIT(16) 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_cienum renesas_sdhi_dma_cookie { 6262306a36Sopenharmony_ci COOKIE_UNMAPPED, 6362306a36Sopenharmony_ci COOKIE_PRE_MAPPED, 6462306a36Sopenharmony_ci COOKIE_MAPPED, 6562306a36Sopenharmony_ci}; 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci/* 6862306a36Sopenharmony_ci * Specification of this driver: 6962306a36Sopenharmony_ci * - host->chan_{rx,tx} will be used as a flag of enabling/disabling the dma 7062306a36Sopenharmony_ci * - Since this SDHI DMAC register set has 16 but 32-bit width, we 7162306a36Sopenharmony_ci * need a custom accessor. 7262306a36Sopenharmony_ci */ 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_cistatic unsigned long global_flags; 7562306a36Sopenharmony_ci/* 7662306a36Sopenharmony_ci * Workaround for avoiding to use RX DMAC by multiple channels. On R-Car M3-W 7762306a36Sopenharmony_ci * ES1.0, when multiple SDHI channels use RX DMAC simultaneously, sometimes 7862306a36Sopenharmony_ci * hundreds of data bytes are not stored into the system memory even if the 7962306a36Sopenharmony_ci * DMAC interrupt happened. So, this driver then uses one RX DMAC channel only. 8062306a36Sopenharmony_ci */ 8162306a36Sopenharmony_ci#define SDHI_INTERNAL_DMAC_RX_IN_USE 0 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci/* Definitions for sampling clocks */ 8462306a36Sopenharmony_cistatic struct renesas_sdhi_scc rcar_gen3_scc_taps[] = { 8562306a36Sopenharmony_ci { 8662306a36Sopenharmony_ci .clk_rate = 0, 8762306a36Sopenharmony_ci .tap = 0x00000300, 8862306a36Sopenharmony_ci .tap_hs400_4tap = 0x00000100, 8962306a36Sopenharmony_ci }, 9062306a36Sopenharmony_ci}; 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_cistatic const struct renesas_sdhi_of_data of_data_rza2 = { 9362306a36Sopenharmony_ci .tmio_flags = TMIO_MMC_HAS_IDLE_WAIT | TMIO_MMC_CLK_ACTUAL | 9462306a36Sopenharmony_ci TMIO_MMC_HAVE_CBSY, 9562306a36Sopenharmony_ci .tmio_ocr_mask = MMC_VDD_32_33, 9662306a36Sopenharmony_ci .capabilities = MMC_CAP_SD_HIGHSPEED | MMC_CAP_SDIO_IRQ | 9762306a36Sopenharmony_ci MMC_CAP_CMD23 | MMC_CAP_WAIT_WHILE_BUSY, 9862306a36Sopenharmony_ci .bus_shift = 2, 9962306a36Sopenharmony_ci .scc_offset = 0 - 0x1000, 10062306a36Sopenharmony_ci .taps = rcar_gen3_scc_taps, 10162306a36Sopenharmony_ci .taps_num = ARRAY_SIZE(rcar_gen3_scc_taps), 10262306a36Sopenharmony_ci /* DMAC can handle 32bit blk count but only 1 segment */ 10362306a36Sopenharmony_ci .max_blk_count = UINT_MAX / TMIO_MAX_BLK_SIZE, 10462306a36Sopenharmony_ci .max_segs = 1, 10562306a36Sopenharmony_ci}; 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_cistatic const struct renesas_sdhi_of_data of_data_rcar_gen3 = { 10862306a36Sopenharmony_ci .tmio_flags = TMIO_MMC_HAS_IDLE_WAIT | TMIO_MMC_CLK_ACTUAL | 10962306a36Sopenharmony_ci TMIO_MMC_HAVE_CBSY | TMIO_MMC_MIN_RCAR2, 11062306a36Sopenharmony_ci .capabilities = MMC_CAP_SD_HIGHSPEED | MMC_CAP_SDIO_IRQ | 11162306a36Sopenharmony_ci MMC_CAP_CMD23 | MMC_CAP_WAIT_WHILE_BUSY, 11262306a36Sopenharmony_ci .capabilities2 = MMC_CAP2_NO_WRITE_PROTECT | MMC_CAP2_MERGE_CAPABLE, 11362306a36Sopenharmony_ci .bus_shift = 2, 11462306a36Sopenharmony_ci .scc_offset = 0x1000, 11562306a36Sopenharmony_ci .taps = rcar_gen3_scc_taps, 11662306a36Sopenharmony_ci .taps_num = ARRAY_SIZE(rcar_gen3_scc_taps), 11762306a36Sopenharmony_ci /* DMAC can handle 32bit blk count but only 1 segment */ 11862306a36Sopenharmony_ci .max_blk_count = UINT_MAX / TMIO_MAX_BLK_SIZE, 11962306a36Sopenharmony_ci .max_segs = 1, 12062306a36Sopenharmony_ci .sdhi_flags = SDHI_FLAG_NEED_CLKH_FALLBACK, 12162306a36Sopenharmony_ci}; 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_cistatic const struct renesas_sdhi_of_data of_data_rcar_gen3_no_sdh_fallback = { 12462306a36Sopenharmony_ci .tmio_flags = TMIO_MMC_HAS_IDLE_WAIT | TMIO_MMC_CLK_ACTUAL | 12562306a36Sopenharmony_ci TMIO_MMC_HAVE_CBSY | TMIO_MMC_MIN_RCAR2, 12662306a36Sopenharmony_ci .capabilities = MMC_CAP_SD_HIGHSPEED | MMC_CAP_SDIO_IRQ | 12762306a36Sopenharmony_ci MMC_CAP_CMD23 | MMC_CAP_WAIT_WHILE_BUSY, 12862306a36Sopenharmony_ci .capabilities2 = MMC_CAP2_NO_WRITE_PROTECT | MMC_CAP2_MERGE_CAPABLE, 12962306a36Sopenharmony_ci .bus_shift = 2, 13062306a36Sopenharmony_ci .scc_offset = 0x1000, 13162306a36Sopenharmony_ci .taps = rcar_gen3_scc_taps, 13262306a36Sopenharmony_ci .taps_num = ARRAY_SIZE(rcar_gen3_scc_taps), 13362306a36Sopenharmony_ci /* DMAC can handle 32bit blk count but only 1 segment */ 13462306a36Sopenharmony_ci .max_blk_count = UINT_MAX / TMIO_MAX_BLK_SIZE, 13562306a36Sopenharmony_ci .max_segs = 1, 13662306a36Sopenharmony_ci}; 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_cistatic const u8 r8a7796_es13_calib_table[2][SDHI_CALIB_TABLE_MAX] = { 13962306a36Sopenharmony_ci { 3, 3, 3, 3, 3, 3, 3, 4, 4, 5, 6, 7, 8, 9, 10, 15, 14062306a36Sopenharmony_ci 16, 16, 16, 16, 16, 16, 17, 18, 18, 19, 20, 21, 22, 23, 24, 25 }, 14162306a36Sopenharmony_ci { 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 7, 8, 11, 14262306a36Sopenharmony_ci 12, 17, 18, 18, 18, 18, 18, 18, 18, 19, 20, 21, 22, 23, 25, 25 } 14362306a36Sopenharmony_ci}; 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_cistatic const u8 r8a77965_calib_table[2][SDHI_CALIB_TABLE_MAX] = { 14662306a36Sopenharmony_ci { 1, 2, 6, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 15, 15, 16, 14762306a36Sopenharmony_ci 17, 18, 19, 20, 21, 22, 23, 24, 25, 25, 26, 27, 28, 29, 30, 31 }, 14862306a36Sopenharmony_ci { 2, 3, 4, 4, 5, 6, 7, 9, 10, 11, 12, 13, 14, 15, 16, 17, 14962306a36Sopenharmony_ci 17, 17, 20, 21, 22, 23, 24, 25, 27, 28, 29, 30, 31, 31, 31, 31 } 15062306a36Sopenharmony_ci}; 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_cistatic const u8 r8a77990_calib_table[2][SDHI_CALIB_TABLE_MAX] = { 15362306a36Sopenharmony_ci { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15462306a36Sopenharmony_ci 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, 15562306a36Sopenharmony_ci { 0, 0, 0, 1, 2, 3, 3, 4, 4, 4, 5, 5, 6, 8, 9, 10, 15662306a36Sopenharmony_ci 11, 12, 13, 15, 16, 17, 17, 18, 18, 19, 20, 22, 24, 25, 26, 26 } 15762306a36Sopenharmony_ci}; 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_cistatic const struct renesas_sdhi_quirks sdhi_quirks_4tap_nohs400 = { 16062306a36Sopenharmony_ci .hs400_disabled = true, 16162306a36Sopenharmony_ci .hs400_4taps = true, 16262306a36Sopenharmony_ci}; 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_cistatic const struct renesas_sdhi_quirks sdhi_quirks_4tap_nohs400_one_rx = { 16562306a36Sopenharmony_ci .hs400_disabled = true, 16662306a36Sopenharmony_ci .hs400_4taps = true, 16762306a36Sopenharmony_ci .dma_one_rx_only = true, 16862306a36Sopenharmony_ci .old_info1_layout = true, 16962306a36Sopenharmony_ci}; 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_cistatic const struct renesas_sdhi_quirks sdhi_quirks_4tap = { 17262306a36Sopenharmony_ci .hs400_4taps = true, 17362306a36Sopenharmony_ci .hs400_bad_taps = BIT(2) | BIT(3) | BIT(6) | BIT(7), 17462306a36Sopenharmony_ci .manual_tap_correction = true, 17562306a36Sopenharmony_ci}; 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_cistatic const struct renesas_sdhi_quirks sdhi_quirks_nohs400 = { 17862306a36Sopenharmony_ci .hs400_disabled = true, 17962306a36Sopenharmony_ci}; 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_cistatic const struct renesas_sdhi_quirks sdhi_quirks_fixed_addr = { 18262306a36Sopenharmony_ci .fixed_addr_mode = true, 18362306a36Sopenharmony_ci}; 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_cistatic const struct renesas_sdhi_quirks sdhi_quirks_bad_taps1357 = { 18662306a36Sopenharmony_ci .hs400_bad_taps = BIT(1) | BIT(3) | BIT(5) | BIT(7), 18762306a36Sopenharmony_ci .manual_tap_correction = true, 18862306a36Sopenharmony_ci}; 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_cistatic const struct renesas_sdhi_quirks sdhi_quirks_bad_taps2367 = { 19162306a36Sopenharmony_ci .hs400_bad_taps = BIT(2) | BIT(3) | BIT(6) | BIT(7), 19262306a36Sopenharmony_ci .manual_tap_correction = true, 19362306a36Sopenharmony_ci}; 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_cistatic const struct renesas_sdhi_quirks sdhi_quirks_r8a7796_es13 = { 19662306a36Sopenharmony_ci .hs400_4taps = true, 19762306a36Sopenharmony_ci .hs400_bad_taps = BIT(2) | BIT(3) | BIT(6) | BIT(7), 19862306a36Sopenharmony_ci .hs400_calib_table = r8a7796_es13_calib_table, 19962306a36Sopenharmony_ci .manual_tap_correction = true, 20062306a36Sopenharmony_ci}; 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_cistatic const struct renesas_sdhi_quirks sdhi_quirks_r8a77965 = { 20362306a36Sopenharmony_ci .hs400_bad_taps = BIT(2) | BIT(3) | BIT(6) | BIT(7), 20462306a36Sopenharmony_ci .hs400_calib_table = r8a77965_calib_table, 20562306a36Sopenharmony_ci .manual_tap_correction = true, 20662306a36Sopenharmony_ci}; 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_cistatic const struct renesas_sdhi_quirks sdhi_quirks_r8a77990 = { 20962306a36Sopenharmony_ci .hs400_calib_table = r8a77990_calib_table, 21062306a36Sopenharmony_ci .manual_tap_correction = true, 21162306a36Sopenharmony_ci}; 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_cistatic const struct renesas_sdhi_quirks sdhi_quirks_r9a09g011 = { 21462306a36Sopenharmony_ci .fixed_addr_mode = true, 21562306a36Sopenharmony_ci .hs400_disabled = true, 21662306a36Sopenharmony_ci}; 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_ci/* 21962306a36Sopenharmony_ci * Note for r8a7796 / r8a774a1: we can't distinguish ES1.1 and 1.2 as of now. 22062306a36Sopenharmony_ci * So, we want to treat them equally and only have a match for ES1.2 to enforce 22162306a36Sopenharmony_ci * this if there ever will be a way to distinguish ES1.2. 22262306a36Sopenharmony_ci */ 22362306a36Sopenharmony_cistatic const struct soc_device_attribute sdhi_quirks_match[] = { 22462306a36Sopenharmony_ci { .soc_id = "r8a774a1", .revision = "ES1.[012]", .data = &sdhi_quirks_4tap_nohs400 }, 22562306a36Sopenharmony_ci { .soc_id = "r8a7795", .revision = "ES2.0", .data = &sdhi_quirks_4tap }, 22662306a36Sopenharmony_ci { .soc_id = "r8a7796", .revision = "ES1.0", .data = &sdhi_quirks_4tap_nohs400_one_rx }, 22762306a36Sopenharmony_ci { .soc_id = "r8a7796", .revision = "ES1.[12]", .data = &sdhi_quirks_4tap_nohs400 }, 22862306a36Sopenharmony_ci { .soc_id = "r8a7796", .revision = "ES1.*", .data = &sdhi_quirks_r8a7796_es13 }, 22962306a36Sopenharmony_ci { .soc_id = "r8a77980", .revision = "ES1.*", .data = &sdhi_quirks_nohs400 }, 23062306a36Sopenharmony_ci { /* Sentinel. */ } 23162306a36Sopenharmony_ci}; 23262306a36Sopenharmony_ci 23362306a36Sopenharmony_cistatic const struct renesas_sdhi_of_data_with_quirks of_r8a7795_compatible = { 23462306a36Sopenharmony_ci .of_data = &of_data_rcar_gen3, 23562306a36Sopenharmony_ci .quirks = &sdhi_quirks_bad_taps2367, 23662306a36Sopenharmony_ci}; 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_cistatic const struct renesas_sdhi_of_data_with_quirks of_r8a77961_compatible = { 23962306a36Sopenharmony_ci .of_data = &of_data_rcar_gen3, 24062306a36Sopenharmony_ci .quirks = &sdhi_quirks_bad_taps1357, 24162306a36Sopenharmony_ci}; 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_cistatic const struct renesas_sdhi_of_data_with_quirks of_r8a77965_compatible = { 24462306a36Sopenharmony_ci .of_data = &of_data_rcar_gen3, 24562306a36Sopenharmony_ci .quirks = &sdhi_quirks_r8a77965, 24662306a36Sopenharmony_ci}; 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_cistatic const struct renesas_sdhi_of_data_with_quirks of_r8a77970_compatible = { 24962306a36Sopenharmony_ci .of_data = &of_data_rcar_gen3_no_sdh_fallback, 25062306a36Sopenharmony_ci .quirks = &sdhi_quirks_nohs400, 25162306a36Sopenharmony_ci}; 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_cistatic const struct renesas_sdhi_of_data_with_quirks of_r8a77990_compatible = { 25462306a36Sopenharmony_ci .of_data = &of_data_rcar_gen3, 25562306a36Sopenharmony_ci .quirks = &sdhi_quirks_r8a77990, 25662306a36Sopenharmony_ci}; 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_cistatic const struct renesas_sdhi_of_data_with_quirks of_r9a09g011_compatible = { 25962306a36Sopenharmony_ci .of_data = &of_data_rcar_gen3, 26062306a36Sopenharmony_ci .quirks = &sdhi_quirks_r9a09g011, 26162306a36Sopenharmony_ci}; 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_cistatic const struct renesas_sdhi_of_data_with_quirks of_rcar_gen3_compatible = { 26462306a36Sopenharmony_ci .of_data = &of_data_rcar_gen3, 26562306a36Sopenharmony_ci}; 26662306a36Sopenharmony_ci 26762306a36Sopenharmony_cistatic const struct renesas_sdhi_of_data_with_quirks of_rcar_gen3_nohs400_compatible = { 26862306a36Sopenharmony_ci .of_data = &of_data_rcar_gen3, 26962306a36Sopenharmony_ci .quirks = &sdhi_quirks_nohs400, 27062306a36Sopenharmony_ci}; 27162306a36Sopenharmony_ci 27262306a36Sopenharmony_cistatic const struct renesas_sdhi_of_data_with_quirks of_rza2_compatible = { 27362306a36Sopenharmony_ci .of_data = &of_data_rza2, 27462306a36Sopenharmony_ci .quirks = &sdhi_quirks_fixed_addr, 27562306a36Sopenharmony_ci}; 27662306a36Sopenharmony_ci 27762306a36Sopenharmony_cistatic const struct of_device_id renesas_sdhi_internal_dmac_of_match[] = { 27862306a36Sopenharmony_ci { .compatible = "renesas,sdhi-r7s9210", .data = &of_rza2_compatible, }, 27962306a36Sopenharmony_ci { .compatible = "renesas,sdhi-mmc-r8a77470", .data = &of_rcar_gen3_compatible, }, 28062306a36Sopenharmony_ci { .compatible = "renesas,sdhi-r8a7795", .data = &of_r8a7795_compatible, }, 28162306a36Sopenharmony_ci { .compatible = "renesas,sdhi-r8a77961", .data = &of_r8a77961_compatible, }, 28262306a36Sopenharmony_ci { .compatible = "renesas,sdhi-r8a77965", .data = &of_r8a77965_compatible, }, 28362306a36Sopenharmony_ci { .compatible = "renesas,sdhi-r8a77970", .data = &of_r8a77970_compatible, }, 28462306a36Sopenharmony_ci { .compatible = "renesas,sdhi-r8a77990", .data = &of_r8a77990_compatible, }, 28562306a36Sopenharmony_ci { .compatible = "renesas,sdhi-r8a77995", .data = &of_rcar_gen3_nohs400_compatible, }, 28662306a36Sopenharmony_ci { .compatible = "renesas,sdhi-r9a09g011", .data = &of_r9a09g011_compatible, }, 28762306a36Sopenharmony_ci { .compatible = "renesas,rcar-gen3-sdhi", .data = &of_rcar_gen3_compatible, }, 28862306a36Sopenharmony_ci { .compatible = "renesas,rcar-gen4-sdhi", .data = &of_rcar_gen3_compatible, }, 28962306a36Sopenharmony_ci {}, 29062306a36Sopenharmony_ci}; 29162306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, renesas_sdhi_internal_dmac_of_match); 29262306a36Sopenharmony_ci 29362306a36Sopenharmony_cistatic void 29462306a36Sopenharmony_cirenesas_sdhi_internal_dmac_enable_dma(struct tmio_mmc_host *host, bool enable) 29562306a36Sopenharmony_ci{ 29662306a36Sopenharmony_ci struct renesas_sdhi *priv = host_to_priv(host); 29762306a36Sopenharmony_ci u32 dma_irqs = INFO1_DTRANEND0 | 29862306a36Sopenharmony_ci (sdhi_has_quirk(priv, old_info1_layout) ? 29962306a36Sopenharmony_ci INFO1_DTRANEND1_OLD : INFO1_DTRANEND1); 30062306a36Sopenharmony_ci 30162306a36Sopenharmony_ci if (!host->chan_tx || !host->chan_rx) 30262306a36Sopenharmony_ci return; 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_ci writel(enable ? ~dma_irqs : INFO1_MASK_CLEAR, host->ctl + DM_CM_INFO1_MASK); 30562306a36Sopenharmony_ci 30662306a36Sopenharmony_ci if (priv->dma_priv.enable) 30762306a36Sopenharmony_ci priv->dma_priv.enable(host, enable); 30862306a36Sopenharmony_ci} 30962306a36Sopenharmony_ci 31062306a36Sopenharmony_cistatic void 31162306a36Sopenharmony_cirenesas_sdhi_internal_dmac_abort_dma(struct tmio_mmc_host *host) 31262306a36Sopenharmony_ci{ 31362306a36Sopenharmony_ci u64 val = RST_DTRANRST1 | RST_DTRANRST0; 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_ci renesas_sdhi_internal_dmac_enable_dma(host, false); 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_ci writel(RST_RESERVED_BITS & ~val, host->ctl + DM_CM_RST); 31862306a36Sopenharmony_ci writel(RST_RESERVED_BITS | val, host->ctl + DM_CM_RST); 31962306a36Sopenharmony_ci 32062306a36Sopenharmony_ci clear_bit(SDHI_INTERNAL_DMAC_RX_IN_USE, &global_flags); 32162306a36Sopenharmony_ci 32262306a36Sopenharmony_ci renesas_sdhi_internal_dmac_enable_dma(host, true); 32362306a36Sopenharmony_ci} 32462306a36Sopenharmony_ci 32562306a36Sopenharmony_cistatic bool renesas_sdhi_internal_dmac_dma_irq(struct tmio_mmc_host *host) 32662306a36Sopenharmony_ci{ 32762306a36Sopenharmony_ci struct renesas_sdhi *priv = host_to_priv(host); 32862306a36Sopenharmony_ci struct renesas_sdhi_dma *dma_priv = &priv->dma_priv; 32962306a36Sopenharmony_ci 33062306a36Sopenharmony_ci u32 dma_irqs = INFO1_DTRANEND0 | 33162306a36Sopenharmony_ci (sdhi_has_quirk(priv, old_info1_layout) ? 33262306a36Sopenharmony_ci INFO1_DTRANEND1_OLD : INFO1_DTRANEND1); 33362306a36Sopenharmony_ci u32 status = readl(host->ctl + DM_CM_INFO1); 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_ci if (status & dma_irqs) { 33662306a36Sopenharmony_ci writel(status ^ dma_irqs, host->ctl + DM_CM_INFO1); 33762306a36Sopenharmony_ci set_bit(SDHI_DMA_END_FLAG_DMA, &dma_priv->end_flags); 33862306a36Sopenharmony_ci if (test_bit(SDHI_DMA_END_FLAG_ACCESS, &dma_priv->end_flags)) 33962306a36Sopenharmony_ci tasklet_schedule(&dma_priv->dma_complete); 34062306a36Sopenharmony_ci } 34162306a36Sopenharmony_ci 34262306a36Sopenharmony_ci return status & dma_irqs; 34362306a36Sopenharmony_ci} 34462306a36Sopenharmony_ci 34562306a36Sopenharmony_cistatic void 34662306a36Sopenharmony_cirenesas_sdhi_internal_dmac_dataend_dma(struct tmio_mmc_host *host) 34762306a36Sopenharmony_ci{ 34862306a36Sopenharmony_ci struct renesas_sdhi *priv = host_to_priv(host); 34962306a36Sopenharmony_ci struct renesas_sdhi_dma *dma_priv = &priv->dma_priv; 35062306a36Sopenharmony_ci 35162306a36Sopenharmony_ci set_bit(SDHI_DMA_END_FLAG_ACCESS, &dma_priv->end_flags); 35262306a36Sopenharmony_ci if (test_bit(SDHI_DMA_END_FLAG_DMA, &dma_priv->end_flags) || 35362306a36Sopenharmony_ci host->data->error) 35462306a36Sopenharmony_ci tasklet_schedule(&dma_priv->dma_complete); 35562306a36Sopenharmony_ci} 35662306a36Sopenharmony_ci 35762306a36Sopenharmony_ci/* 35862306a36Sopenharmony_ci * renesas_sdhi_internal_dmac_map() will be called with two different 35962306a36Sopenharmony_ci * sg pointers in two mmc_data by .pre_req(), but tmio host can have a single 36062306a36Sopenharmony_ci * sg_ptr only. So, renesas_sdhi_internal_dmac_{un}map() should use a sg 36162306a36Sopenharmony_ci * pointer in a mmc_data instead of host->sg_ptr. 36262306a36Sopenharmony_ci */ 36362306a36Sopenharmony_cistatic void 36462306a36Sopenharmony_cirenesas_sdhi_internal_dmac_unmap(struct tmio_mmc_host *host, 36562306a36Sopenharmony_ci struct mmc_data *data, 36662306a36Sopenharmony_ci enum renesas_sdhi_dma_cookie cookie) 36762306a36Sopenharmony_ci{ 36862306a36Sopenharmony_ci bool unmap = cookie == COOKIE_UNMAPPED ? (data->host_cookie != cookie) : 36962306a36Sopenharmony_ci (data->host_cookie == cookie); 37062306a36Sopenharmony_ci 37162306a36Sopenharmony_ci if (unmap) { 37262306a36Sopenharmony_ci dma_unmap_sg(&host->pdev->dev, data->sg, data->sg_len, 37362306a36Sopenharmony_ci mmc_get_dma_dir(data)); 37462306a36Sopenharmony_ci data->host_cookie = COOKIE_UNMAPPED; 37562306a36Sopenharmony_ci } 37662306a36Sopenharmony_ci} 37762306a36Sopenharmony_ci 37862306a36Sopenharmony_cistatic bool 37962306a36Sopenharmony_cirenesas_sdhi_internal_dmac_map(struct tmio_mmc_host *host, 38062306a36Sopenharmony_ci struct mmc_data *data, 38162306a36Sopenharmony_ci enum renesas_sdhi_dma_cookie cookie) 38262306a36Sopenharmony_ci{ 38362306a36Sopenharmony_ci if (data->host_cookie == COOKIE_PRE_MAPPED) 38462306a36Sopenharmony_ci return true; 38562306a36Sopenharmony_ci 38662306a36Sopenharmony_ci if (!dma_map_sg(&host->pdev->dev, data->sg, data->sg_len, 38762306a36Sopenharmony_ci mmc_get_dma_dir(data))) 38862306a36Sopenharmony_ci return false; 38962306a36Sopenharmony_ci 39062306a36Sopenharmony_ci data->host_cookie = cookie; 39162306a36Sopenharmony_ci 39262306a36Sopenharmony_ci /* This DMAC needs buffers to be 128-byte aligned */ 39362306a36Sopenharmony_ci if (!IS_ALIGNED(sg_dma_address(data->sg), 128)) { 39462306a36Sopenharmony_ci renesas_sdhi_internal_dmac_unmap(host, data, cookie); 39562306a36Sopenharmony_ci return false; 39662306a36Sopenharmony_ci } 39762306a36Sopenharmony_ci 39862306a36Sopenharmony_ci return true; 39962306a36Sopenharmony_ci} 40062306a36Sopenharmony_ci 40162306a36Sopenharmony_cistatic void 40262306a36Sopenharmony_cirenesas_sdhi_internal_dmac_start_dma(struct tmio_mmc_host *host, 40362306a36Sopenharmony_ci struct mmc_data *data) 40462306a36Sopenharmony_ci{ 40562306a36Sopenharmony_ci struct renesas_sdhi *priv = host_to_priv(host); 40662306a36Sopenharmony_ci struct scatterlist *sg = host->sg_ptr; 40762306a36Sopenharmony_ci u32 dtran_mode = DTRAN_MODE_BUS_WIDTH; 40862306a36Sopenharmony_ci 40962306a36Sopenharmony_ci if (!sdhi_has_quirk(priv, fixed_addr_mode)) 41062306a36Sopenharmony_ci dtran_mode |= DTRAN_MODE_ADDR_MODE; 41162306a36Sopenharmony_ci 41262306a36Sopenharmony_ci if (!renesas_sdhi_internal_dmac_map(host, data, COOKIE_MAPPED)) 41362306a36Sopenharmony_ci goto force_pio; 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_ci if (data->flags & MMC_DATA_READ) { 41662306a36Sopenharmony_ci dtran_mode |= DTRAN_MODE_CH_NUM_CH1; 41762306a36Sopenharmony_ci if (sdhi_has_quirk(priv, dma_one_rx_only) && 41862306a36Sopenharmony_ci test_and_set_bit(SDHI_INTERNAL_DMAC_RX_IN_USE, &global_flags)) 41962306a36Sopenharmony_ci goto force_pio_with_unmap; 42062306a36Sopenharmony_ci } else { 42162306a36Sopenharmony_ci dtran_mode |= DTRAN_MODE_CH_NUM_CH0; 42262306a36Sopenharmony_ci } 42362306a36Sopenharmony_ci 42462306a36Sopenharmony_ci priv->dma_priv.end_flags = 0; 42562306a36Sopenharmony_ci renesas_sdhi_internal_dmac_enable_dma(host, true); 42662306a36Sopenharmony_ci 42762306a36Sopenharmony_ci /* set dma parameters */ 42862306a36Sopenharmony_ci writel(dtran_mode, host->ctl + DM_CM_DTRAN_MODE); 42962306a36Sopenharmony_ci writel(sg_dma_address(sg), host->ctl + DM_DTRAN_ADDR); 43062306a36Sopenharmony_ci 43162306a36Sopenharmony_ci host->dma_on = true; 43262306a36Sopenharmony_ci 43362306a36Sopenharmony_ci return; 43462306a36Sopenharmony_ci 43562306a36Sopenharmony_ciforce_pio_with_unmap: 43662306a36Sopenharmony_ci renesas_sdhi_internal_dmac_unmap(host, data, COOKIE_UNMAPPED); 43762306a36Sopenharmony_ci 43862306a36Sopenharmony_ciforce_pio: 43962306a36Sopenharmony_ci renesas_sdhi_internal_dmac_enable_dma(host, false); 44062306a36Sopenharmony_ci} 44162306a36Sopenharmony_ci 44262306a36Sopenharmony_cistatic void renesas_sdhi_internal_dmac_issue_tasklet_fn(unsigned long arg) 44362306a36Sopenharmony_ci{ 44462306a36Sopenharmony_ci struct tmio_mmc_host *host = (struct tmio_mmc_host *)arg; 44562306a36Sopenharmony_ci struct renesas_sdhi *priv = host_to_priv(host); 44662306a36Sopenharmony_ci 44762306a36Sopenharmony_ci tmio_mmc_enable_mmc_irqs(host, TMIO_STAT_DATAEND); 44862306a36Sopenharmony_ci 44962306a36Sopenharmony_ci if (!host->cmd->error) { 45062306a36Sopenharmony_ci /* start the DMAC */ 45162306a36Sopenharmony_ci writel(DTRAN_CTRL_DM_START, host->ctl + DM_CM_DTRAN_CTRL); 45262306a36Sopenharmony_ci } else { 45362306a36Sopenharmony_ci /* on CMD errors, simulate DMA end immediately */ 45462306a36Sopenharmony_ci set_bit(SDHI_DMA_END_FLAG_DMA, &priv->dma_priv.end_flags); 45562306a36Sopenharmony_ci if (test_bit(SDHI_DMA_END_FLAG_ACCESS, &priv->dma_priv.end_flags)) 45662306a36Sopenharmony_ci tasklet_schedule(&priv->dma_priv.dma_complete); 45762306a36Sopenharmony_ci } 45862306a36Sopenharmony_ci} 45962306a36Sopenharmony_ci 46062306a36Sopenharmony_cistatic bool renesas_sdhi_internal_dmac_complete(struct tmio_mmc_host *host) 46162306a36Sopenharmony_ci{ 46262306a36Sopenharmony_ci enum dma_data_direction dir; 46362306a36Sopenharmony_ci 46462306a36Sopenharmony_ci if (!host->dma_on) 46562306a36Sopenharmony_ci return false; 46662306a36Sopenharmony_ci 46762306a36Sopenharmony_ci if (!host->data) 46862306a36Sopenharmony_ci return false; 46962306a36Sopenharmony_ci 47062306a36Sopenharmony_ci if (host->data->flags & MMC_DATA_READ) 47162306a36Sopenharmony_ci dir = DMA_FROM_DEVICE; 47262306a36Sopenharmony_ci else 47362306a36Sopenharmony_ci dir = DMA_TO_DEVICE; 47462306a36Sopenharmony_ci 47562306a36Sopenharmony_ci renesas_sdhi_internal_dmac_enable_dma(host, false); 47662306a36Sopenharmony_ci renesas_sdhi_internal_dmac_unmap(host, host->data, COOKIE_MAPPED); 47762306a36Sopenharmony_ci 47862306a36Sopenharmony_ci if (dir == DMA_FROM_DEVICE) 47962306a36Sopenharmony_ci clear_bit(SDHI_INTERNAL_DMAC_RX_IN_USE, &global_flags); 48062306a36Sopenharmony_ci 48162306a36Sopenharmony_ci host->dma_on = false; 48262306a36Sopenharmony_ci 48362306a36Sopenharmony_ci return true; 48462306a36Sopenharmony_ci} 48562306a36Sopenharmony_ci 48662306a36Sopenharmony_cistatic void renesas_sdhi_internal_dmac_complete_tasklet_fn(unsigned long arg) 48762306a36Sopenharmony_ci{ 48862306a36Sopenharmony_ci struct tmio_mmc_host *host = (struct tmio_mmc_host *)arg; 48962306a36Sopenharmony_ci 49062306a36Sopenharmony_ci spin_lock_irq(&host->lock); 49162306a36Sopenharmony_ci if (!renesas_sdhi_internal_dmac_complete(host)) 49262306a36Sopenharmony_ci goto out; 49362306a36Sopenharmony_ci 49462306a36Sopenharmony_ci tmio_mmc_do_data_irq(host); 49562306a36Sopenharmony_ciout: 49662306a36Sopenharmony_ci spin_unlock_irq(&host->lock); 49762306a36Sopenharmony_ci} 49862306a36Sopenharmony_ci 49962306a36Sopenharmony_cistatic void renesas_sdhi_internal_dmac_end_dma(struct tmio_mmc_host *host) 50062306a36Sopenharmony_ci{ 50162306a36Sopenharmony_ci if (host->data) 50262306a36Sopenharmony_ci renesas_sdhi_internal_dmac_complete(host); 50362306a36Sopenharmony_ci} 50462306a36Sopenharmony_ci 50562306a36Sopenharmony_cistatic void renesas_sdhi_internal_dmac_post_req(struct mmc_host *mmc, 50662306a36Sopenharmony_ci struct mmc_request *mrq, 50762306a36Sopenharmony_ci int err) 50862306a36Sopenharmony_ci{ 50962306a36Sopenharmony_ci struct tmio_mmc_host *host = mmc_priv(mmc); 51062306a36Sopenharmony_ci struct mmc_data *data = mrq->data; 51162306a36Sopenharmony_ci 51262306a36Sopenharmony_ci if (!data) 51362306a36Sopenharmony_ci return; 51462306a36Sopenharmony_ci 51562306a36Sopenharmony_ci renesas_sdhi_internal_dmac_unmap(host, data, COOKIE_UNMAPPED); 51662306a36Sopenharmony_ci} 51762306a36Sopenharmony_ci 51862306a36Sopenharmony_cistatic void renesas_sdhi_internal_dmac_pre_req(struct mmc_host *mmc, 51962306a36Sopenharmony_ci struct mmc_request *mrq) 52062306a36Sopenharmony_ci{ 52162306a36Sopenharmony_ci struct tmio_mmc_host *host = mmc_priv(mmc); 52262306a36Sopenharmony_ci struct mmc_data *data = mrq->data; 52362306a36Sopenharmony_ci 52462306a36Sopenharmony_ci if (!data) 52562306a36Sopenharmony_ci return; 52662306a36Sopenharmony_ci 52762306a36Sopenharmony_ci data->host_cookie = COOKIE_UNMAPPED; 52862306a36Sopenharmony_ci renesas_sdhi_internal_dmac_map(host, data, COOKIE_PRE_MAPPED); 52962306a36Sopenharmony_ci} 53062306a36Sopenharmony_ci 53162306a36Sopenharmony_cistatic void 53262306a36Sopenharmony_cirenesas_sdhi_internal_dmac_request_dma(struct tmio_mmc_host *host, 53362306a36Sopenharmony_ci struct tmio_mmc_data *pdata) 53462306a36Sopenharmony_ci{ 53562306a36Sopenharmony_ci struct renesas_sdhi *priv = host_to_priv(host); 53662306a36Sopenharmony_ci 53762306a36Sopenharmony_ci /* Disable DMAC interrupts initially */ 53862306a36Sopenharmony_ci writel(INFO1_MASK_CLEAR, host->ctl + DM_CM_INFO1_MASK); 53962306a36Sopenharmony_ci writel(INFO2_MASK_CLEAR, host->ctl + DM_CM_INFO2_MASK); 54062306a36Sopenharmony_ci writel(0, host->ctl + DM_CM_INFO1); 54162306a36Sopenharmony_ci writel(0, host->ctl + DM_CM_INFO2); 54262306a36Sopenharmony_ci 54362306a36Sopenharmony_ci /* Each value is set to non-zero to assume "enabling" each DMA */ 54462306a36Sopenharmony_ci host->chan_rx = host->chan_tx = (void *)0xdeadbeaf; 54562306a36Sopenharmony_ci 54662306a36Sopenharmony_ci tasklet_init(&priv->dma_priv.dma_complete, 54762306a36Sopenharmony_ci renesas_sdhi_internal_dmac_complete_tasklet_fn, 54862306a36Sopenharmony_ci (unsigned long)host); 54962306a36Sopenharmony_ci tasklet_init(&host->dma_issue, 55062306a36Sopenharmony_ci renesas_sdhi_internal_dmac_issue_tasklet_fn, 55162306a36Sopenharmony_ci (unsigned long)host); 55262306a36Sopenharmony_ci 55362306a36Sopenharmony_ci /* Add pre_req and post_req */ 55462306a36Sopenharmony_ci host->ops.pre_req = renesas_sdhi_internal_dmac_pre_req; 55562306a36Sopenharmony_ci host->ops.post_req = renesas_sdhi_internal_dmac_post_req; 55662306a36Sopenharmony_ci} 55762306a36Sopenharmony_ci 55862306a36Sopenharmony_cistatic void 55962306a36Sopenharmony_cirenesas_sdhi_internal_dmac_release_dma(struct tmio_mmc_host *host) 56062306a36Sopenharmony_ci{ 56162306a36Sopenharmony_ci /* Each value is set to zero to assume "disabling" each DMA */ 56262306a36Sopenharmony_ci host->chan_rx = host->chan_tx = NULL; 56362306a36Sopenharmony_ci} 56462306a36Sopenharmony_ci 56562306a36Sopenharmony_cistatic const struct tmio_mmc_dma_ops renesas_sdhi_internal_dmac_dma_ops = { 56662306a36Sopenharmony_ci .start = renesas_sdhi_internal_dmac_start_dma, 56762306a36Sopenharmony_ci .enable = renesas_sdhi_internal_dmac_enable_dma, 56862306a36Sopenharmony_ci .request = renesas_sdhi_internal_dmac_request_dma, 56962306a36Sopenharmony_ci .release = renesas_sdhi_internal_dmac_release_dma, 57062306a36Sopenharmony_ci .abort = renesas_sdhi_internal_dmac_abort_dma, 57162306a36Sopenharmony_ci .dataend = renesas_sdhi_internal_dmac_dataend_dma, 57262306a36Sopenharmony_ci .end = renesas_sdhi_internal_dmac_end_dma, 57362306a36Sopenharmony_ci .dma_irq = renesas_sdhi_internal_dmac_dma_irq, 57462306a36Sopenharmony_ci}; 57562306a36Sopenharmony_ci 57662306a36Sopenharmony_cistatic int renesas_sdhi_internal_dmac_probe(struct platform_device *pdev) 57762306a36Sopenharmony_ci{ 57862306a36Sopenharmony_ci const struct soc_device_attribute *attr; 57962306a36Sopenharmony_ci const struct renesas_sdhi_of_data_with_quirks *of_data_quirks; 58062306a36Sopenharmony_ci const struct renesas_sdhi_quirks *quirks; 58162306a36Sopenharmony_ci struct device *dev = &pdev->dev; 58262306a36Sopenharmony_ci 58362306a36Sopenharmony_ci of_data_quirks = of_device_get_match_data(&pdev->dev); 58462306a36Sopenharmony_ci quirks = of_data_quirks->quirks; 58562306a36Sopenharmony_ci 58662306a36Sopenharmony_ci attr = soc_device_match(sdhi_quirks_match); 58762306a36Sopenharmony_ci if (attr) 58862306a36Sopenharmony_ci quirks = attr->data; 58962306a36Sopenharmony_ci 59062306a36Sopenharmony_ci /* value is max of SD_SECCNT. Confirmed by HW engineers */ 59162306a36Sopenharmony_ci dma_set_max_seg_size(dev, 0xffffffff); 59262306a36Sopenharmony_ci 59362306a36Sopenharmony_ci return renesas_sdhi_probe(pdev, &renesas_sdhi_internal_dmac_dma_ops, 59462306a36Sopenharmony_ci of_data_quirks->of_data, quirks); 59562306a36Sopenharmony_ci} 59662306a36Sopenharmony_ci 59762306a36Sopenharmony_cistatic const struct dev_pm_ops renesas_sdhi_internal_dmac_dev_pm_ops = { 59862306a36Sopenharmony_ci SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, 59962306a36Sopenharmony_ci pm_runtime_force_resume) 60062306a36Sopenharmony_ci SET_RUNTIME_PM_OPS(tmio_mmc_host_runtime_suspend, 60162306a36Sopenharmony_ci tmio_mmc_host_runtime_resume, 60262306a36Sopenharmony_ci NULL) 60362306a36Sopenharmony_ci}; 60462306a36Sopenharmony_ci 60562306a36Sopenharmony_cistatic struct platform_driver renesas_internal_dmac_sdhi_driver = { 60662306a36Sopenharmony_ci .driver = { 60762306a36Sopenharmony_ci .name = "renesas_sdhi_internal_dmac", 60862306a36Sopenharmony_ci .probe_type = PROBE_PREFER_ASYNCHRONOUS, 60962306a36Sopenharmony_ci .pm = &renesas_sdhi_internal_dmac_dev_pm_ops, 61062306a36Sopenharmony_ci .of_match_table = renesas_sdhi_internal_dmac_of_match, 61162306a36Sopenharmony_ci }, 61262306a36Sopenharmony_ci .probe = renesas_sdhi_internal_dmac_probe, 61362306a36Sopenharmony_ci .remove_new = renesas_sdhi_remove, 61462306a36Sopenharmony_ci}; 61562306a36Sopenharmony_ci 61662306a36Sopenharmony_cimodule_platform_driver(renesas_internal_dmac_sdhi_driver); 61762306a36Sopenharmony_ci 61862306a36Sopenharmony_ciMODULE_DESCRIPTION("Renesas SDHI driver for internal DMAC"); 61962306a36Sopenharmony_ciMODULE_AUTHOR("Yoshihiro Shimoda"); 62062306a36Sopenharmony_ciMODULE_LICENSE("GPL v2"); 621