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