xref: /OK3568_Linux_fs/kernel/drivers/mmc/host/renesas_sdhi_internal_dmac.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * DMA support for Internal DMAC with SDHI SD/SDIO controller
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  * Copyright (C) 2016-19 Renesas Electronics Corporation
6*4882a593Smuzhiyun  * Copyright (C) 2016-17 Horms Solutions, Simon Horman
7*4882a593Smuzhiyun  * Copyright (C) 2018-19 Sang Engineering, Wolfram Sang
8*4882a593Smuzhiyun  */
9*4882a593Smuzhiyun 
10*4882a593Smuzhiyun #include <linux/bitops.h>
11*4882a593Smuzhiyun #include <linux/device.h>
12*4882a593Smuzhiyun #include <linux/dma-mapping.h>
13*4882a593Smuzhiyun #include <linux/io-64-nonatomic-hi-lo.h>
14*4882a593Smuzhiyun #include <linux/mfd/tmio.h>
15*4882a593Smuzhiyun #include <linux/mmc/host.h>
16*4882a593Smuzhiyun #include <linux/mod_devicetable.h>
17*4882a593Smuzhiyun #include <linux/module.h>
18*4882a593Smuzhiyun #include <linux/pagemap.h>
19*4882a593Smuzhiyun #include <linux/scatterlist.h>
20*4882a593Smuzhiyun #include <linux/sys_soc.h>
21*4882a593Smuzhiyun 
22*4882a593Smuzhiyun #include "renesas_sdhi.h"
23*4882a593Smuzhiyun #include "tmio_mmc.h"
24*4882a593Smuzhiyun 
25*4882a593Smuzhiyun #define DM_CM_DTRAN_MODE	0x820
26*4882a593Smuzhiyun #define DM_CM_DTRAN_CTRL	0x828
27*4882a593Smuzhiyun #define DM_CM_RST		0x830
28*4882a593Smuzhiyun #define DM_CM_INFO1		0x840
29*4882a593Smuzhiyun #define DM_CM_INFO1_MASK	0x848
30*4882a593Smuzhiyun #define DM_CM_INFO2		0x850
31*4882a593Smuzhiyun #define DM_CM_INFO2_MASK	0x858
32*4882a593Smuzhiyun #define DM_DTRAN_ADDR		0x880
33*4882a593Smuzhiyun 
34*4882a593Smuzhiyun /* DM_CM_DTRAN_MODE */
35*4882a593Smuzhiyun #define DTRAN_MODE_CH_NUM_CH0	0	/* "downstream" = for write commands */
36*4882a593Smuzhiyun #define DTRAN_MODE_CH_NUM_CH1	BIT(16)	/* "upstream" = for read commands */
37*4882a593Smuzhiyun #define DTRAN_MODE_BUS_WIDTH	(BIT(5) | BIT(4))
38*4882a593Smuzhiyun #define DTRAN_MODE_ADDR_MODE	BIT(0)	/* 1 = Increment address, 0 = Fixed */
39*4882a593Smuzhiyun 
40*4882a593Smuzhiyun /* DM_CM_DTRAN_CTRL */
41*4882a593Smuzhiyun #define DTRAN_CTRL_DM_START	BIT(0)
42*4882a593Smuzhiyun 
43*4882a593Smuzhiyun /* DM_CM_RST */
44*4882a593Smuzhiyun #define RST_DTRANRST1		BIT(9)
45*4882a593Smuzhiyun #define RST_DTRANRST0		BIT(8)
46*4882a593Smuzhiyun #define RST_RESERVED_BITS	GENMASK_ULL(31, 0)
47*4882a593Smuzhiyun 
48*4882a593Smuzhiyun /* DM_CM_INFO1 and DM_CM_INFO1_MASK */
49*4882a593Smuzhiyun #define INFO1_CLEAR		0
50*4882a593Smuzhiyun #define INFO1_MASK_CLEAR	GENMASK_ULL(31, 0)
51*4882a593Smuzhiyun #define INFO1_DTRANEND1		BIT(17)
52*4882a593Smuzhiyun #define INFO1_DTRANEND0		BIT(16)
53*4882a593Smuzhiyun 
54*4882a593Smuzhiyun /* DM_CM_INFO2 and DM_CM_INFO2_MASK */
55*4882a593Smuzhiyun #define INFO2_MASK_CLEAR	GENMASK_ULL(31, 0)
56*4882a593Smuzhiyun #define INFO2_DTRANERR1		BIT(17)
57*4882a593Smuzhiyun #define INFO2_DTRANERR0		BIT(16)
58*4882a593Smuzhiyun 
59*4882a593Smuzhiyun /*
60*4882a593Smuzhiyun  * Specification of this driver:
61*4882a593Smuzhiyun  * - host->chan_{rx,tx} will be used as a flag of enabling/disabling the dma
62*4882a593Smuzhiyun  * - Since this SDHI DMAC register set has 16 but 32-bit width, we
63*4882a593Smuzhiyun  *   need a custom accessor.
64*4882a593Smuzhiyun  */
65*4882a593Smuzhiyun 
66*4882a593Smuzhiyun static unsigned long global_flags;
67*4882a593Smuzhiyun /*
68*4882a593Smuzhiyun  * Workaround for avoiding to use RX DMAC by multiple channels.
69*4882a593Smuzhiyun  * On R-Car H3 ES1.* and M3-W ES1.0, when multiple SDHI channels use
70*4882a593Smuzhiyun  * RX DMAC simultaneously, sometimes hundreds of bytes data are not
71*4882a593Smuzhiyun  * stored into the system memory even if the DMAC interrupt happened.
72*4882a593Smuzhiyun  * So, this driver then uses one RX DMAC channel only.
73*4882a593Smuzhiyun  */
74*4882a593Smuzhiyun #define SDHI_INTERNAL_DMAC_ONE_RX_ONLY	0
75*4882a593Smuzhiyun #define SDHI_INTERNAL_DMAC_RX_IN_USE	1
76*4882a593Smuzhiyun 
77*4882a593Smuzhiyun /* RZ/A2 does not have the ADRR_MODE bit */
78*4882a593Smuzhiyun #define SDHI_INTERNAL_DMAC_ADDR_MODE_FIXED_ONLY 2
79*4882a593Smuzhiyun 
80*4882a593Smuzhiyun /* Definitions for sampling clocks */
81*4882a593Smuzhiyun static struct renesas_sdhi_scc rcar_gen3_scc_taps[] = {
82*4882a593Smuzhiyun 	{
83*4882a593Smuzhiyun 		.clk_rate = 0,
84*4882a593Smuzhiyun 		.tap = 0x00000300,
85*4882a593Smuzhiyun 		.tap_hs400_4tap = 0x00000100,
86*4882a593Smuzhiyun 	},
87*4882a593Smuzhiyun };
88*4882a593Smuzhiyun 
89*4882a593Smuzhiyun static const struct renesas_sdhi_of_data of_rza2_compatible = {
90*4882a593Smuzhiyun 	.tmio_flags	= TMIO_MMC_HAS_IDLE_WAIT | TMIO_MMC_CLK_ACTUAL |
91*4882a593Smuzhiyun 			  TMIO_MMC_HAVE_CBSY,
92*4882a593Smuzhiyun 	.tmio_ocr_mask	= MMC_VDD_32_33,
93*4882a593Smuzhiyun 	.capabilities	= MMC_CAP_SD_HIGHSPEED | MMC_CAP_SDIO_IRQ |
94*4882a593Smuzhiyun 			  MMC_CAP_CMD23,
95*4882a593Smuzhiyun 	.bus_shift	= 2,
96*4882a593Smuzhiyun 	.scc_offset	= 0 - 0x1000,
97*4882a593Smuzhiyun 	.taps		= rcar_gen3_scc_taps,
98*4882a593Smuzhiyun 	.taps_num	= ARRAY_SIZE(rcar_gen3_scc_taps),
99*4882a593Smuzhiyun 	/* DMAC can handle 32bit blk count but only 1 segment */
100*4882a593Smuzhiyun 	.max_blk_count	= UINT_MAX / TMIO_MAX_BLK_SIZE,
101*4882a593Smuzhiyun 	.max_segs	= 1,
102*4882a593Smuzhiyun };
103*4882a593Smuzhiyun 
104*4882a593Smuzhiyun static const struct renesas_sdhi_of_data of_rcar_gen3_compatible = {
105*4882a593Smuzhiyun 	.tmio_flags	= TMIO_MMC_HAS_IDLE_WAIT | TMIO_MMC_CLK_ACTUAL |
106*4882a593Smuzhiyun 			  TMIO_MMC_HAVE_CBSY | TMIO_MMC_MIN_RCAR2,
107*4882a593Smuzhiyun 	.capabilities	= MMC_CAP_SD_HIGHSPEED | MMC_CAP_SDIO_IRQ |
108*4882a593Smuzhiyun 			  MMC_CAP_CMD23,
109*4882a593Smuzhiyun 	.capabilities2	= MMC_CAP2_NO_WRITE_PROTECT | MMC_CAP2_MERGE_CAPABLE,
110*4882a593Smuzhiyun 	.bus_shift	= 2,
111*4882a593Smuzhiyun 	.scc_offset	= 0x1000,
112*4882a593Smuzhiyun 	.taps		= rcar_gen3_scc_taps,
113*4882a593Smuzhiyun 	.taps_num	= ARRAY_SIZE(rcar_gen3_scc_taps),
114*4882a593Smuzhiyun 	/* DMAC can handle 32bit blk count but only 1 segment */
115*4882a593Smuzhiyun 	.max_blk_count	= UINT_MAX / TMIO_MAX_BLK_SIZE,
116*4882a593Smuzhiyun 	.max_segs	= 1,
117*4882a593Smuzhiyun };
118*4882a593Smuzhiyun 
119*4882a593Smuzhiyun static const struct of_device_id renesas_sdhi_internal_dmac_of_match[] = {
120*4882a593Smuzhiyun 	{ .compatible = "renesas,sdhi-r7s9210", .data = &of_rza2_compatible, },
121*4882a593Smuzhiyun 	{ .compatible = "renesas,sdhi-mmc-r8a77470", .data = &of_rcar_gen3_compatible, },
122*4882a593Smuzhiyun 	{ .compatible = "renesas,sdhi-r8a7795", .data = &of_rcar_gen3_compatible, },
123*4882a593Smuzhiyun 	{ .compatible = "renesas,sdhi-r8a7796", .data = &of_rcar_gen3_compatible, },
124*4882a593Smuzhiyun 	{ .compatible = "renesas,rcar-gen3-sdhi", .data = &of_rcar_gen3_compatible, },
125*4882a593Smuzhiyun 	{},
126*4882a593Smuzhiyun };
127*4882a593Smuzhiyun MODULE_DEVICE_TABLE(of, renesas_sdhi_internal_dmac_of_match);
128*4882a593Smuzhiyun 
129*4882a593Smuzhiyun static void
renesas_sdhi_internal_dmac_dm_write(struct tmio_mmc_host * host,int addr,u64 val)130*4882a593Smuzhiyun renesas_sdhi_internal_dmac_dm_write(struct tmio_mmc_host *host,
131*4882a593Smuzhiyun 				    int addr, u64 val)
132*4882a593Smuzhiyun {
133*4882a593Smuzhiyun 	writeq(val, host->ctl + addr);
134*4882a593Smuzhiyun }
135*4882a593Smuzhiyun 
136*4882a593Smuzhiyun static void
renesas_sdhi_internal_dmac_enable_dma(struct tmio_mmc_host * host,bool enable)137*4882a593Smuzhiyun renesas_sdhi_internal_dmac_enable_dma(struct tmio_mmc_host *host, bool enable)
138*4882a593Smuzhiyun {
139*4882a593Smuzhiyun 	struct renesas_sdhi *priv = host_to_priv(host);
140*4882a593Smuzhiyun 
141*4882a593Smuzhiyun 	if (!host->chan_tx || !host->chan_rx)
142*4882a593Smuzhiyun 		return;
143*4882a593Smuzhiyun 
144*4882a593Smuzhiyun 	if (!enable)
145*4882a593Smuzhiyun 		renesas_sdhi_internal_dmac_dm_write(host, DM_CM_INFO1,
146*4882a593Smuzhiyun 						    INFO1_CLEAR);
147*4882a593Smuzhiyun 
148*4882a593Smuzhiyun 	if (priv->dma_priv.enable)
149*4882a593Smuzhiyun 		priv->dma_priv.enable(host, enable);
150*4882a593Smuzhiyun }
151*4882a593Smuzhiyun 
152*4882a593Smuzhiyun static void
renesas_sdhi_internal_dmac_abort_dma(struct tmio_mmc_host * host)153*4882a593Smuzhiyun renesas_sdhi_internal_dmac_abort_dma(struct tmio_mmc_host *host) {
154*4882a593Smuzhiyun 	u64 val = RST_DTRANRST1 | RST_DTRANRST0;
155*4882a593Smuzhiyun 
156*4882a593Smuzhiyun 	renesas_sdhi_internal_dmac_enable_dma(host, false);
157*4882a593Smuzhiyun 
158*4882a593Smuzhiyun 	renesas_sdhi_internal_dmac_dm_write(host, DM_CM_RST,
159*4882a593Smuzhiyun 					    RST_RESERVED_BITS & ~val);
160*4882a593Smuzhiyun 	renesas_sdhi_internal_dmac_dm_write(host, DM_CM_RST,
161*4882a593Smuzhiyun 					    RST_RESERVED_BITS | val);
162*4882a593Smuzhiyun 
163*4882a593Smuzhiyun 	clear_bit(SDHI_INTERNAL_DMAC_RX_IN_USE, &global_flags);
164*4882a593Smuzhiyun 
165*4882a593Smuzhiyun 	renesas_sdhi_internal_dmac_enable_dma(host, true);
166*4882a593Smuzhiyun }
167*4882a593Smuzhiyun 
168*4882a593Smuzhiyun static void
renesas_sdhi_internal_dmac_dataend_dma(struct tmio_mmc_host * host)169*4882a593Smuzhiyun renesas_sdhi_internal_dmac_dataend_dma(struct tmio_mmc_host *host) {
170*4882a593Smuzhiyun 	struct renesas_sdhi *priv = host_to_priv(host);
171*4882a593Smuzhiyun 
172*4882a593Smuzhiyun 	tasklet_schedule(&priv->dma_priv.dma_complete);
173*4882a593Smuzhiyun }
174*4882a593Smuzhiyun 
175*4882a593Smuzhiyun static void
renesas_sdhi_internal_dmac_start_dma(struct tmio_mmc_host * host,struct mmc_data * data)176*4882a593Smuzhiyun renesas_sdhi_internal_dmac_start_dma(struct tmio_mmc_host *host,
177*4882a593Smuzhiyun 				     struct mmc_data *data)
178*4882a593Smuzhiyun {
179*4882a593Smuzhiyun 	struct scatterlist *sg = host->sg_ptr;
180*4882a593Smuzhiyun 	u32 dtran_mode = DTRAN_MODE_BUS_WIDTH;
181*4882a593Smuzhiyun 
182*4882a593Smuzhiyun 	if (!test_bit(SDHI_INTERNAL_DMAC_ADDR_MODE_FIXED_ONLY, &global_flags))
183*4882a593Smuzhiyun 		dtran_mode |= DTRAN_MODE_ADDR_MODE;
184*4882a593Smuzhiyun 
185*4882a593Smuzhiyun 	if (!dma_map_sg(&host->pdev->dev, sg, host->sg_len,
186*4882a593Smuzhiyun 			mmc_get_dma_dir(data)))
187*4882a593Smuzhiyun 		goto force_pio;
188*4882a593Smuzhiyun 
189*4882a593Smuzhiyun 	/* This DMAC cannot handle if buffer is not 128-bytes alignment */
190*4882a593Smuzhiyun 	if (!IS_ALIGNED(sg_dma_address(sg), 128))
191*4882a593Smuzhiyun 		goto force_pio_with_unmap;
192*4882a593Smuzhiyun 
193*4882a593Smuzhiyun 	if (data->flags & MMC_DATA_READ) {
194*4882a593Smuzhiyun 		dtran_mode |= DTRAN_MODE_CH_NUM_CH1;
195*4882a593Smuzhiyun 		if (test_bit(SDHI_INTERNAL_DMAC_ONE_RX_ONLY, &global_flags) &&
196*4882a593Smuzhiyun 		    test_and_set_bit(SDHI_INTERNAL_DMAC_RX_IN_USE, &global_flags))
197*4882a593Smuzhiyun 			goto force_pio_with_unmap;
198*4882a593Smuzhiyun 	} else {
199*4882a593Smuzhiyun 		dtran_mode |= DTRAN_MODE_CH_NUM_CH0;
200*4882a593Smuzhiyun 	}
201*4882a593Smuzhiyun 
202*4882a593Smuzhiyun 	renesas_sdhi_internal_dmac_enable_dma(host, true);
203*4882a593Smuzhiyun 
204*4882a593Smuzhiyun 	/* set dma parameters */
205*4882a593Smuzhiyun 	renesas_sdhi_internal_dmac_dm_write(host, DM_CM_DTRAN_MODE,
206*4882a593Smuzhiyun 					    dtran_mode);
207*4882a593Smuzhiyun 	renesas_sdhi_internal_dmac_dm_write(host, DM_DTRAN_ADDR,
208*4882a593Smuzhiyun 					    sg_dma_address(sg));
209*4882a593Smuzhiyun 
210*4882a593Smuzhiyun 	host->dma_on = true;
211*4882a593Smuzhiyun 
212*4882a593Smuzhiyun 	return;
213*4882a593Smuzhiyun 
214*4882a593Smuzhiyun force_pio_with_unmap:
215*4882a593Smuzhiyun 	dma_unmap_sg(&host->pdev->dev, sg, host->sg_len, mmc_get_dma_dir(data));
216*4882a593Smuzhiyun 
217*4882a593Smuzhiyun force_pio:
218*4882a593Smuzhiyun 	renesas_sdhi_internal_dmac_enable_dma(host, false);
219*4882a593Smuzhiyun }
220*4882a593Smuzhiyun 
renesas_sdhi_internal_dmac_issue_tasklet_fn(unsigned long arg)221*4882a593Smuzhiyun static void renesas_sdhi_internal_dmac_issue_tasklet_fn(unsigned long arg)
222*4882a593Smuzhiyun {
223*4882a593Smuzhiyun 	struct tmio_mmc_host *host = (struct tmio_mmc_host *)arg;
224*4882a593Smuzhiyun 
225*4882a593Smuzhiyun 	tmio_mmc_enable_mmc_irqs(host, TMIO_STAT_DATAEND);
226*4882a593Smuzhiyun 
227*4882a593Smuzhiyun 	/* start the DMAC */
228*4882a593Smuzhiyun 	renesas_sdhi_internal_dmac_dm_write(host, DM_CM_DTRAN_CTRL,
229*4882a593Smuzhiyun 					    DTRAN_CTRL_DM_START);
230*4882a593Smuzhiyun }
231*4882a593Smuzhiyun 
renesas_sdhi_internal_dmac_complete(struct tmio_mmc_host * host)232*4882a593Smuzhiyun static bool renesas_sdhi_internal_dmac_complete(struct tmio_mmc_host *host)
233*4882a593Smuzhiyun {
234*4882a593Smuzhiyun 	enum dma_data_direction dir;
235*4882a593Smuzhiyun 
236*4882a593Smuzhiyun 	if (!host->dma_on)
237*4882a593Smuzhiyun 		return false;
238*4882a593Smuzhiyun 
239*4882a593Smuzhiyun 	if (!host->data)
240*4882a593Smuzhiyun 		return false;
241*4882a593Smuzhiyun 
242*4882a593Smuzhiyun 	if (host->data->flags & MMC_DATA_READ)
243*4882a593Smuzhiyun 		dir = DMA_FROM_DEVICE;
244*4882a593Smuzhiyun 	else
245*4882a593Smuzhiyun 		dir = DMA_TO_DEVICE;
246*4882a593Smuzhiyun 
247*4882a593Smuzhiyun 	renesas_sdhi_internal_dmac_enable_dma(host, false);
248*4882a593Smuzhiyun 	dma_unmap_sg(&host->pdev->dev, host->sg_ptr, host->sg_len, dir);
249*4882a593Smuzhiyun 
250*4882a593Smuzhiyun 	if (dir == DMA_FROM_DEVICE)
251*4882a593Smuzhiyun 		clear_bit(SDHI_INTERNAL_DMAC_RX_IN_USE, &global_flags);
252*4882a593Smuzhiyun 
253*4882a593Smuzhiyun 	host->dma_on = false;
254*4882a593Smuzhiyun 
255*4882a593Smuzhiyun 	return true;
256*4882a593Smuzhiyun }
257*4882a593Smuzhiyun 
renesas_sdhi_internal_dmac_complete_tasklet_fn(unsigned long arg)258*4882a593Smuzhiyun static void renesas_sdhi_internal_dmac_complete_tasklet_fn(unsigned long arg)
259*4882a593Smuzhiyun {
260*4882a593Smuzhiyun 	struct tmio_mmc_host *host = (struct tmio_mmc_host *)arg;
261*4882a593Smuzhiyun 
262*4882a593Smuzhiyun 	spin_lock_irq(&host->lock);
263*4882a593Smuzhiyun 	if (!renesas_sdhi_internal_dmac_complete(host))
264*4882a593Smuzhiyun 		goto out;
265*4882a593Smuzhiyun 
266*4882a593Smuzhiyun 	tmio_mmc_do_data_irq(host);
267*4882a593Smuzhiyun out:
268*4882a593Smuzhiyun 	spin_unlock_irq(&host->lock);
269*4882a593Smuzhiyun }
270*4882a593Smuzhiyun 
renesas_sdhi_internal_dmac_end_dma(struct tmio_mmc_host * host)271*4882a593Smuzhiyun static void renesas_sdhi_internal_dmac_end_dma(struct tmio_mmc_host *host)
272*4882a593Smuzhiyun {
273*4882a593Smuzhiyun 	if (host->data)
274*4882a593Smuzhiyun 		renesas_sdhi_internal_dmac_complete(host);
275*4882a593Smuzhiyun }
276*4882a593Smuzhiyun 
277*4882a593Smuzhiyun static void
renesas_sdhi_internal_dmac_request_dma(struct tmio_mmc_host * host,struct tmio_mmc_data * pdata)278*4882a593Smuzhiyun renesas_sdhi_internal_dmac_request_dma(struct tmio_mmc_host *host,
279*4882a593Smuzhiyun 				       struct tmio_mmc_data *pdata)
280*4882a593Smuzhiyun {
281*4882a593Smuzhiyun 	struct renesas_sdhi *priv = host_to_priv(host);
282*4882a593Smuzhiyun 
283*4882a593Smuzhiyun 	/* Disable DMAC interrupts, we don't use them */
284*4882a593Smuzhiyun 	renesas_sdhi_internal_dmac_dm_write(host, DM_CM_INFO1_MASK,
285*4882a593Smuzhiyun 					    INFO1_MASK_CLEAR);
286*4882a593Smuzhiyun 	renesas_sdhi_internal_dmac_dm_write(host, DM_CM_INFO2_MASK,
287*4882a593Smuzhiyun 					    INFO2_MASK_CLEAR);
288*4882a593Smuzhiyun 
289*4882a593Smuzhiyun 	/* Each value is set to non-zero to assume "enabling" each DMA */
290*4882a593Smuzhiyun 	host->chan_rx = host->chan_tx = (void *)0xdeadbeaf;
291*4882a593Smuzhiyun 
292*4882a593Smuzhiyun 	tasklet_init(&priv->dma_priv.dma_complete,
293*4882a593Smuzhiyun 		     renesas_sdhi_internal_dmac_complete_tasklet_fn,
294*4882a593Smuzhiyun 		     (unsigned long)host);
295*4882a593Smuzhiyun 	tasklet_init(&host->dma_issue,
296*4882a593Smuzhiyun 		     renesas_sdhi_internal_dmac_issue_tasklet_fn,
297*4882a593Smuzhiyun 		     (unsigned long)host);
298*4882a593Smuzhiyun }
299*4882a593Smuzhiyun 
300*4882a593Smuzhiyun static void
renesas_sdhi_internal_dmac_release_dma(struct tmio_mmc_host * host)301*4882a593Smuzhiyun renesas_sdhi_internal_dmac_release_dma(struct tmio_mmc_host *host)
302*4882a593Smuzhiyun {
303*4882a593Smuzhiyun 	/* Each value is set to zero to assume "disabling" each DMA */
304*4882a593Smuzhiyun 	host->chan_rx = host->chan_tx = NULL;
305*4882a593Smuzhiyun }
306*4882a593Smuzhiyun 
307*4882a593Smuzhiyun static const struct tmio_mmc_dma_ops renesas_sdhi_internal_dmac_dma_ops = {
308*4882a593Smuzhiyun 	.start = renesas_sdhi_internal_dmac_start_dma,
309*4882a593Smuzhiyun 	.enable = renesas_sdhi_internal_dmac_enable_dma,
310*4882a593Smuzhiyun 	.request = renesas_sdhi_internal_dmac_request_dma,
311*4882a593Smuzhiyun 	.release = renesas_sdhi_internal_dmac_release_dma,
312*4882a593Smuzhiyun 	.abort = renesas_sdhi_internal_dmac_abort_dma,
313*4882a593Smuzhiyun 	.dataend = renesas_sdhi_internal_dmac_dataend_dma,
314*4882a593Smuzhiyun 	.end = renesas_sdhi_internal_dmac_end_dma,
315*4882a593Smuzhiyun };
316*4882a593Smuzhiyun 
317*4882a593Smuzhiyun /*
318*4882a593Smuzhiyun  * Whitelist of specific R-Car Gen3 SoC ES versions to use this DMAC
319*4882a593Smuzhiyun  * implementation as others may use a different implementation.
320*4882a593Smuzhiyun  */
321*4882a593Smuzhiyun static const struct soc_device_attribute soc_dma_quirks[] = {
322*4882a593Smuzhiyun 	{ .soc_id = "r7s9210",
323*4882a593Smuzhiyun 	  .data = (void *)BIT(SDHI_INTERNAL_DMAC_ADDR_MODE_FIXED_ONLY) },
324*4882a593Smuzhiyun 	{ .soc_id = "r8a7795", .revision = "ES1.*",
325*4882a593Smuzhiyun 	  .data = (void *)BIT(SDHI_INTERNAL_DMAC_ONE_RX_ONLY) },
326*4882a593Smuzhiyun 	{ .soc_id = "r8a7796", .revision = "ES1.0",
327*4882a593Smuzhiyun 	  .data = (void *)BIT(SDHI_INTERNAL_DMAC_ONE_RX_ONLY) },
328*4882a593Smuzhiyun 	{ /* sentinel */ }
329*4882a593Smuzhiyun };
330*4882a593Smuzhiyun 
renesas_sdhi_internal_dmac_probe(struct platform_device * pdev)331*4882a593Smuzhiyun static int renesas_sdhi_internal_dmac_probe(struct platform_device *pdev)
332*4882a593Smuzhiyun {
333*4882a593Smuzhiyun 	const struct soc_device_attribute *soc = soc_device_match(soc_dma_quirks);
334*4882a593Smuzhiyun 	struct device *dev = &pdev->dev;
335*4882a593Smuzhiyun 
336*4882a593Smuzhiyun 	if (soc)
337*4882a593Smuzhiyun 		global_flags |= (unsigned long)soc->data;
338*4882a593Smuzhiyun 
339*4882a593Smuzhiyun 	/* value is max of SD_SECCNT. Confirmed by HW engineers */
340*4882a593Smuzhiyun 	dma_set_max_seg_size(dev, 0xffffffff);
341*4882a593Smuzhiyun 
342*4882a593Smuzhiyun 	return renesas_sdhi_probe(pdev, &renesas_sdhi_internal_dmac_dma_ops);
343*4882a593Smuzhiyun }
344*4882a593Smuzhiyun 
345*4882a593Smuzhiyun static const struct dev_pm_ops renesas_sdhi_internal_dmac_dev_pm_ops = {
346*4882a593Smuzhiyun 	SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
347*4882a593Smuzhiyun 				pm_runtime_force_resume)
348*4882a593Smuzhiyun 	SET_RUNTIME_PM_OPS(tmio_mmc_host_runtime_suspend,
349*4882a593Smuzhiyun 			   tmio_mmc_host_runtime_resume,
350*4882a593Smuzhiyun 			   NULL)
351*4882a593Smuzhiyun };
352*4882a593Smuzhiyun 
353*4882a593Smuzhiyun static struct platform_driver renesas_internal_dmac_sdhi_driver = {
354*4882a593Smuzhiyun 	.driver		= {
355*4882a593Smuzhiyun 		.name	= "renesas_sdhi_internal_dmac",
356*4882a593Smuzhiyun 		.probe_type = PROBE_PREFER_ASYNCHRONOUS,
357*4882a593Smuzhiyun 		.pm	= &renesas_sdhi_internal_dmac_dev_pm_ops,
358*4882a593Smuzhiyun 		.of_match_table = renesas_sdhi_internal_dmac_of_match,
359*4882a593Smuzhiyun 	},
360*4882a593Smuzhiyun 	.probe		= renesas_sdhi_internal_dmac_probe,
361*4882a593Smuzhiyun 	.remove		= renesas_sdhi_remove,
362*4882a593Smuzhiyun };
363*4882a593Smuzhiyun 
364*4882a593Smuzhiyun module_platform_driver(renesas_internal_dmac_sdhi_driver);
365*4882a593Smuzhiyun 
366*4882a593Smuzhiyun MODULE_DESCRIPTION("Renesas SDHI driver for internal DMAC");
367*4882a593Smuzhiyun MODULE_AUTHOR("Yoshihiro Shimoda");
368*4882a593Smuzhiyun MODULE_LICENSE("GPL v2");
369