xref: /arm-trusted-firmware/drivers/synopsys/emmc/dw_mmc.c (revision 91f16700b400a8c0651d24a598fc48ee2997a0d7)
1*91f16700Schasinglulu /*
2*91f16700Schasinglulu  * Copyright (c) 2016-2017, ARM Limited and Contributors. All rights reserved.
3*91f16700Schasinglulu  *
4*91f16700Schasinglulu  * SPDX-License-Identifier: BSD-3-Clause
5*91f16700Schasinglulu  */
6*91f16700Schasinglulu 
7*91f16700Schasinglulu #include <assert.h>
8*91f16700Schasinglulu #include <errno.h>
9*91f16700Schasinglulu #include <string.h>
10*91f16700Schasinglulu 
11*91f16700Schasinglulu #include <arch.h>
12*91f16700Schasinglulu #include <arch_helpers.h>
13*91f16700Schasinglulu #include <common/debug.h>
14*91f16700Schasinglulu #include <drivers/delay_timer.h>
15*91f16700Schasinglulu #include <drivers/mmc.h>
16*91f16700Schasinglulu #include <drivers/synopsys/dw_mmc.h>
17*91f16700Schasinglulu #include <lib/utils_def.h>
18*91f16700Schasinglulu #include <lib/mmio.h>
19*91f16700Schasinglulu 
20*91f16700Schasinglulu #define DWMMC_CTRL			(0x00)
21*91f16700Schasinglulu #define CTRL_IDMAC_EN			(1 << 25)
22*91f16700Schasinglulu #define CTRL_DMA_EN			(1 << 5)
23*91f16700Schasinglulu #define CTRL_INT_EN			(1 << 4)
24*91f16700Schasinglulu #define CTRL_DMA_RESET			(1 << 2)
25*91f16700Schasinglulu #define CTRL_FIFO_RESET			(1 << 1)
26*91f16700Schasinglulu #define CTRL_RESET			(1 << 0)
27*91f16700Schasinglulu #define CTRL_RESET_ALL			(CTRL_DMA_RESET | CTRL_FIFO_RESET | \
28*91f16700Schasinglulu 					 CTRL_RESET)
29*91f16700Schasinglulu 
30*91f16700Schasinglulu #define DWMMC_PWREN			(0x04)
31*91f16700Schasinglulu #define DWMMC_CLKDIV			(0x08)
32*91f16700Schasinglulu #define DWMMC_CLKSRC			(0x0c)
33*91f16700Schasinglulu #define DWMMC_CLKENA			(0x10)
34*91f16700Schasinglulu #define DWMMC_TMOUT			(0x14)
35*91f16700Schasinglulu #define DWMMC_CTYPE			(0x18)
36*91f16700Schasinglulu #define CTYPE_8BIT			(1 << 16)
37*91f16700Schasinglulu #define CTYPE_4BIT			(1)
38*91f16700Schasinglulu #define CTYPE_1BIT			(0)
39*91f16700Schasinglulu 
40*91f16700Schasinglulu #define DWMMC_BLKSIZ			(0x1c)
41*91f16700Schasinglulu #define DWMMC_BYTCNT			(0x20)
42*91f16700Schasinglulu #define DWMMC_INTMASK			(0x24)
43*91f16700Schasinglulu #define INT_EBE				(1 << 15)
44*91f16700Schasinglulu #define INT_SBE				(1 << 13)
45*91f16700Schasinglulu #define INT_HLE				(1 << 12)
46*91f16700Schasinglulu #define INT_FRUN			(1 << 11)
47*91f16700Schasinglulu #define INT_DRT				(1 << 9)
48*91f16700Schasinglulu #define INT_RTO				(1 << 8)
49*91f16700Schasinglulu #define INT_DCRC			(1 << 7)
50*91f16700Schasinglulu #define INT_RCRC			(1 << 6)
51*91f16700Schasinglulu #define INT_RXDR			(1 << 5)
52*91f16700Schasinglulu #define INT_TXDR			(1 << 4)
53*91f16700Schasinglulu #define INT_DTO				(1 << 3)
54*91f16700Schasinglulu #define INT_CMD_DONE			(1 << 2)
55*91f16700Schasinglulu #define INT_RE				(1 << 1)
56*91f16700Schasinglulu 
57*91f16700Schasinglulu #define DWMMC_CMDARG			(0x28)
58*91f16700Schasinglulu #define DWMMC_CMD			(0x2c)
59*91f16700Schasinglulu #define CMD_START			(U(1) << 31)
60*91f16700Schasinglulu #define CMD_USE_HOLD_REG		(1 << 29)	/* 0 if SDR50/100 */
61*91f16700Schasinglulu #define CMD_UPDATE_CLK_ONLY		(1 << 21)
62*91f16700Schasinglulu #define CMD_SEND_INIT			(1 << 15)
63*91f16700Schasinglulu #define CMD_STOP_ABORT_CMD		(1 << 14)
64*91f16700Schasinglulu #define CMD_WAIT_PRVDATA_COMPLETE	(1 << 13)
65*91f16700Schasinglulu #define CMD_WRITE			(1 << 10)
66*91f16700Schasinglulu #define CMD_DATA_TRANS_EXPECT		(1 << 9)
67*91f16700Schasinglulu #define CMD_CHECK_RESP_CRC		(1 << 8)
68*91f16700Schasinglulu #define CMD_RESP_LEN			(1 << 7)
69*91f16700Schasinglulu #define CMD_RESP_EXPECT			(1 << 6)
70*91f16700Schasinglulu #define CMD(x)				(x & 0x3f)
71*91f16700Schasinglulu 
72*91f16700Schasinglulu #define DWMMC_RESP0			(0x30)
73*91f16700Schasinglulu #define DWMMC_RESP1			(0x34)
74*91f16700Schasinglulu #define DWMMC_RESP2			(0x38)
75*91f16700Schasinglulu #define DWMMC_RESP3			(0x3c)
76*91f16700Schasinglulu #define DWMMC_RINTSTS			(0x44)
77*91f16700Schasinglulu #define DWMMC_STATUS			(0x48)
78*91f16700Schasinglulu #define STATUS_DATA_BUSY		(1 << 9)
79*91f16700Schasinglulu 
80*91f16700Schasinglulu #define DWMMC_FIFOTH			(0x4c)
81*91f16700Schasinglulu #define FIFOTH_TWMARK(x)		(x & 0xfff)
82*91f16700Schasinglulu #define FIFOTH_RWMARK(x)		((x & 0x1ff) << 16)
83*91f16700Schasinglulu #define FIFOTH_DMA_BURST_SIZE(x)	((x & 0x7) << 28)
84*91f16700Schasinglulu 
85*91f16700Schasinglulu #define DWMMC_DEBNCE			(0x64)
86*91f16700Schasinglulu #define DWMMC_BMOD			(0x80)
87*91f16700Schasinglulu #define BMOD_ENABLE			(1 << 7)
88*91f16700Schasinglulu #define BMOD_FB				(1 << 1)
89*91f16700Schasinglulu #define BMOD_SWRESET			(1 << 0)
90*91f16700Schasinglulu 
91*91f16700Schasinglulu #define DWMMC_DBADDR			(0x88)
92*91f16700Schasinglulu #define DWMMC_IDSTS			(0x8c)
93*91f16700Schasinglulu #define DWMMC_IDINTEN			(0x90)
94*91f16700Schasinglulu #define DWMMC_CARDTHRCTL		(0x100)
95*91f16700Schasinglulu #define CARDTHRCTL_RD_THR(x)		((x & 0xfff) << 16)
96*91f16700Schasinglulu #define CARDTHRCTL_RD_THR_EN		(1 << 0)
97*91f16700Schasinglulu 
98*91f16700Schasinglulu #define IDMAC_DES0_DIC			(1 << 1)
99*91f16700Schasinglulu #define IDMAC_DES0_LD			(1 << 2)
100*91f16700Schasinglulu #define IDMAC_DES0_FS			(1 << 3)
101*91f16700Schasinglulu #define IDMAC_DES0_CH			(1 << 4)
102*91f16700Schasinglulu #define IDMAC_DES0_ER			(1 << 5)
103*91f16700Schasinglulu #define IDMAC_DES0_CES			(1 << 30)
104*91f16700Schasinglulu #define IDMAC_DES0_OWN			(U(1) << 31)
105*91f16700Schasinglulu #define IDMAC_DES1_BS1(x)		((x) & 0x1fff)
106*91f16700Schasinglulu #define IDMAC_DES2_BS2(x)		(((x) & 0x1fff) << 13)
107*91f16700Schasinglulu 
108*91f16700Schasinglulu #define DWMMC_DMA_MAX_BUFFER_SIZE	(512 * 8)
109*91f16700Schasinglulu 
110*91f16700Schasinglulu #define DWMMC_8BIT_MODE			(1 << 6)
111*91f16700Schasinglulu 
112*91f16700Schasinglulu #define DWMMC_ADDRESS_MASK		U(0x0f)
113*91f16700Schasinglulu 
114*91f16700Schasinglulu #define TIMEOUT				100000
115*91f16700Schasinglulu 
116*91f16700Schasinglulu struct dw_idmac_desc {
117*91f16700Schasinglulu 	unsigned int	des0;
118*91f16700Schasinglulu 	unsigned int	des1;
119*91f16700Schasinglulu 	unsigned int	des2;
120*91f16700Schasinglulu 	unsigned int	des3;
121*91f16700Schasinglulu };
122*91f16700Schasinglulu 
123*91f16700Schasinglulu static void dw_init(void);
124*91f16700Schasinglulu static int dw_send_cmd(struct mmc_cmd *cmd);
125*91f16700Schasinglulu static int dw_set_ios(unsigned int clk, unsigned int width);
126*91f16700Schasinglulu static int dw_prepare(int lba, uintptr_t buf, size_t size);
127*91f16700Schasinglulu static int dw_read(int lba, uintptr_t buf, size_t size);
128*91f16700Schasinglulu static int dw_write(int lba, uintptr_t buf, size_t size);
129*91f16700Schasinglulu 
130*91f16700Schasinglulu static const struct mmc_ops dw_mmc_ops = {
131*91f16700Schasinglulu 	.init		= dw_init,
132*91f16700Schasinglulu 	.send_cmd	= dw_send_cmd,
133*91f16700Schasinglulu 	.set_ios	= dw_set_ios,
134*91f16700Schasinglulu 	.prepare	= dw_prepare,
135*91f16700Schasinglulu 	.read		= dw_read,
136*91f16700Schasinglulu 	.write		= dw_write,
137*91f16700Schasinglulu };
138*91f16700Schasinglulu 
139*91f16700Schasinglulu static dw_mmc_params_t dw_params;
140*91f16700Schasinglulu 
141*91f16700Schasinglulu static void dw_update_clk(void)
142*91f16700Schasinglulu {
143*91f16700Schasinglulu 	unsigned int data;
144*91f16700Schasinglulu 
145*91f16700Schasinglulu 	mmio_write_32(dw_params.reg_base + DWMMC_CMD,
146*91f16700Schasinglulu 		      CMD_WAIT_PRVDATA_COMPLETE | CMD_UPDATE_CLK_ONLY |
147*91f16700Schasinglulu 		      CMD_START);
148*91f16700Schasinglulu 	while (1) {
149*91f16700Schasinglulu 		data = mmio_read_32(dw_params.reg_base + DWMMC_CMD);
150*91f16700Schasinglulu 		if ((data & CMD_START) == 0)
151*91f16700Schasinglulu 			break;
152*91f16700Schasinglulu 		data = mmio_read_32(dw_params.reg_base + DWMMC_RINTSTS);
153*91f16700Schasinglulu 		assert((data & INT_HLE) == 0);
154*91f16700Schasinglulu 	}
155*91f16700Schasinglulu }
156*91f16700Schasinglulu 
157*91f16700Schasinglulu static void dw_set_clk(int clk)
158*91f16700Schasinglulu {
159*91f16700Schasinglulu 	unsigned int data;
160*91f16700Schasinglulu 	int div;
161*91f16700Schasinglulu 
162*91f16700Schasinglulu 	assert(clk > 0);
163*91f16700Schasinglulu 
164*91f16700Schasinglulu 	for (div = 1; div < 256; div++) {
165*91f16700Schasinglulu 		if ((dw_params.clk_rate / (2 * div)) <= clk) {
166*91f16700Schasinglulu 			break;
167*91f16700Schasinglulu 		}
168*91f16700Schasinglulu 	}
169*91f16700Schasinglulu 	assert(div < 256);
170*91f16700Schasinglulu 
171*91f16700Schasinglulu 	/* wait until controller is idle */
172*91f16700Schasinglulu 	do {
173*91f16700Schasinglulu 		data = mmio_read_32(dw_params.reg_base + DWMMC_STATUS);
174*91f16700Schasinglulu 	} while (data & STATUS_DATA_BUSY);
175*91f16700Schasinglulu 
176*91f16700Schasinglulu 	/* disable clock before change clock rate */
177*91f16700Schasinglulu 	mmio_write_32(dw_params.reg_base + DWMMC_CLKENA, 0);
178*91f16700Schasinglulu 	dw_update_clk();
179*91f16700Schasinglulu 
180*91f16700Schasinglulu 	mmio_write_32(dw_params.reg_base + DWMMC_CLKDIV, div);
181*91f16700Schasinglulu 	dw_update_clk();
182*91f16700Schasinglulu 
183*91f16700Schasinglulu 	/* enable clock */
184*91f16700Schasinglulu 	mmio_write_32(dw_params.reg_base + DWMMC_CLKENA, 1);
185*91f16700Schasinglulu 	mmio_write_32(dw_params.reg_base + DWMMC_CLKSRC, 0);
186*91f16700Schasinglulu 	dw_update_clk();
187*91f16700Schasinglulu }
188*91f16700Schasinglulu 
189*91f16700Schasinglulu static void dw_init(void)
190*91f16700Schasinglulu {
191*91f16700Schasinglulu 	unsigned int data;
192*91f16700Schasinglulu 	uintptr_t base;
193*91f16700Schasinglulu 
194*91f16700Schasinglulu 	assert((dw_params.reg_base & MMC_BLOCK_MASK) == 0);
195*91f16700Schasinglulu 
196*91f16700Schasinglulu 	base = dw_params.reg_base;
197*91f16700Schasinglulu 	mmio_write_32(base + DWMMC_PWREN, 1);
198*91f16700Schasinglulu 	mmio_write_32(base + DWMMC_CTRL, CTRL_RESET_ALL);
199*91f16700Schasinglulu 	do {
200*91f16700Schasinglulu 		data = mmio_read_32(base + DWMMC_CTRL);
201*91f16700Schasinglulu 	} while (data);
202*91f16700Schasinglulu 
203*91f16700Schasinglulu 	/* enable DMA in CTRL */
204*91f16700Schasinglulu 	data = CTRL_INT_EN | CTRL_DMA_EN | CTRL_IDMAC_EN;
205*91f16700Schasinglulu 	mmio_write_32(base + DWMMC_CTRL, data);
206*91f16700Schasinglulu 	mmio_write_32(base + DWMMC_RINTSTS, ~0);
207*91f16700Schasinglulu 	mmio_write_32(base + DWMMC_INTMASK, 0);
208*91f16700Schasinglulu 	mmio_write_32(base + DWMMC_TMOUT, ~0);
209*91f16700Schasinglulu 	mmio_write_32(base + DWMMC_IDINTEN, ~0);
210*91f16700Schasinglulu 	mmio_write_32(base + DWMMC_BLKSIZ, MMC_BLOCK_SIZE);
211*91f16700Schasinglulu 	mmio_write_32(base + DWMMC_BYTCNT, 256 * 1024);
212*91f16700Schasinglulu 	mmio_write_32(base + DWMMC_DEBNCE, 0x00ffffff);
213*91f16700Schasinglulu 	mmio_write_32(base + DWMMC_BMOD, BMOD_SWRESET);
214*91f16700Schasinglulu 	do {
215*91f16700Schasinglulu 		data = mmio_read_32(base + DWMMC_BMOD);
216*91f16700Schasinglulu 	} while (data & BMOD_SWRESET);
217*91f16700Schasinglulu 	/* enable DMA in BMOD */
218*91f16700Schasinglulu 	data |= BMOD_ENABLE | BMOD_FB;
219*91f16700Schasinglulu 	mmio_write_32(base + DWMMC_BMOD, data);
220*91f16700Schasinglulu 
221*91f16700Schasinglulu 	udelay(100);
222*91f16700Schasinglulu 	dw_set_clk(MMC_BOOT_CLK_RATE);
223*91f16700Schasinglulu 	udelay(100);
224*91f16700Schasinglulu }
225*91f16700Schasinglulu 
226*91f16700Schasinglulu static int dw_send_cmd(struct mmc_cmd *cmd)
227*91f16700Schasinglulu {
228*91f16700Schasinglulu 	unsigned int op, data, err_mask;
229*91f16700Schasinglulu 	uintptr_t base;
230*91f16700Schasinglulu 	int timeout;
231*91f16700Schasinglulu 
232*91f16700Schasinglulu 	assert(cmd);
233*91f16700Schasinglulu 
234*91f16700Schasinglulu 	base = dw_params.reg_base;
235*91f16700Schasinglulu 
236*91f16700Schasinglulu 	switch (cmd->cmd_idx) {
237*91f16700Schasinglulu 	case 0:
238*91f16700Schasinglulu 		op = CMD_SEND_INIT;
239*91f16700Schasinglulu 		break;
240*91f16700Schasinglulu 	case 12:
241*91f16700Schasinglulu 		op = CMD_STOP_ABORT_CMD;
242*91f16700Schasinglulu 		break;
243*91f16700Schasinglulu 	case 13:
244*91f16700Schasinglulu 		op = CMD_WAIT_PRVDATA_COMPLETE;
245*91f16700Schasinglulu 		break;
246*91f16700Schasinglulu 	case 8:
247*91f16700Schasinglulu 		if (dw_params.mmc_dev_type == MMC_IS_EMMC)
248*91f16700Schasinglulu 			op = CMD_DATA_TRANS_EXPECT | CMD_WAIT_PRVDATA_COMPLETE;
249*91f16700Schasinglulu 		else
250*91f16700Schasinglulu 			op = CMD_WAIT_PRVDATA_COMPLETE;
251*91f16700Schasinglulu 		break;
252*91f16700Schasinglulu 	case 17:
253*91f16700Schasinglulu 	case 18:
254*91f16700Schasinglulu 		op = CMD_DATA_TRANS_EXPECT | CMD_WAIT_PRVDATA_COMPLETE;
255*91f16700Schasinglulu 		break;
256*91f16700Schasinglulu 	case 24:
257*91f16700Schasinglulu 	case 25:
258*91f16700Schasinglulu 		op = CMD_WRITE | CMD_DATA_TRANS_EXPECT |
259*91f16700Schasinglulu 		     CMD_WAIT_PRVDATA_COMPLETE;
260*91f16700Schasinglulu 		break;
261*91f16700Schasinglulu 	case 51:
262*91f16700Schasinglulu 		op = CMD_DATA_TRANS_EXPECT;
263*91f16700Schasinglulu 		break;
264*91f16700Schasinglulu 	default:
265*91f16700Schasinglulu 		op = 0;
266*91f16700Schasinglulu 		break;
267*91f16700Schasinglulu 	}
268*91f16700Schasinglulu 	op |= CMD_USE_HOLD_REG | CMD_START;
269*91f16700Schasinglulu 	switch (cmd->resp_type) {
270*91f16700Schasinglulu 	case 0:
271*91f16700Schasinglulu 		break;
272*91f16700Schasinglulu 	case MMC_RESPONSE_R2:
273*91f16700Schasinglulu 		op |= CMD_RESP_EXPECT | CMD_CHECK_RESP_CRC |
274*91f16700Schasinglulu 		      CMD_RESP_LEN;
275*91f16700Schasinglulu 		break;
276*91f16700Schasinglulu 	case MMC_RESPONSE_R3:
277*91f16700Schasinglulu 		op |= CMD_RESP_EXPECT;
278*91f16700Schasinglulu 		break;
279*91f16700Schasinglulu 	default:
280*91f16700Schasinglulu 		op |= CMD_RESP_EXPECT | CMD_CHECK_RESP_CRC;
281*91f16700Schasinglulu 		break;
282*91f16700Schasinglulu 	}
283*91f16700Schasinglulu 	timeout = TIMEOUT;
284*91f16700Schasinglulu 	do {
285*91f16700Schasinglulu 		data = mmio_read_32(base + DWMMC_STATUS);
286*91f16700Schasinglulu 		if (--timeout <= 0)
287*91f16700Schasinglulu 			panic();
288*91f16700Schasinglulu 	} while (data & STATUS_DATA_BUSY);
289*91f16700Schasinglulu 
290*91f16700Schasinglulu 	mmio_write_32(base + DWMMC_RINTSTS, ~0);
291*91f16700Schasinglulu 	mmio_write_32(base + DWMMC_CMDARG, cmd->cmd_arg);
292*91f16700Schasinglulu 	mmio_write_32(base + DWMMC_CMD, op | cmd->cmd_idx);
293*91f16700Schasinglulu 
294*91f16700Schasinglulu 	err_mask = INT_EBE | INT_HLE | INT_RTO | INT_RCRC | INT_RE |
295*91f16700Schasinglulu 		   INT_DCRC | INT_DRT | INT_SBE;
296*91f16700Schasinglulu 	timeout = TIMEOUT;
297*91f16700Schasinglulu 	do {
298*91f16700Schasinglulu 		udelay(500);
299*91f16700Schasinglulu 		data = mmio_read_32(base + DWMMC_RINTSTS);
300*91f16700Schasinglulu 
301*91f16700Schasinglulu 		if (data & err_mask)
302*91f16700Schasinglulu 			return -EIO;
303*91f16700Schasinglulu 		if (data & INT_DTO)
304*91f16700Schasinglulu 			break;
305*91f16700Schasinglulu 		if (--timeout == 0) {
306*91f16700Schasinglulu 			ERROR("%s, RINTSTS:0x%x\n", __func__, data);
307*91f16700Schasinglulu 			panic();
308*91f16700Schasinglulu 		}
309*91f16700Schasinglulu 	} while (!(data & INT_CMD_DONE));
310*91f16700Schasinglulu 
311*91f16700Schasinglulu 	if (op & CMD_RESP_EXPECT) {
312*91f16700Schasinglulu 		cmd->resp_data[0] = mmio_read_32(base + DWMMC_RESP0);
313*91f16700Schasinglulu 		if (op & CMD_RESP_LEN) {
314*91f16700Schasinglulu 			cmd->resp_data[1] = mmio_read_32(base + DWMMC_RESP1);
315*91f16700Schasinglulu 			cmd->resp_data[2] = mmio_read_32(base + DWMMC_RESP2);
316*91f16700Schasinglulu 			cmd->resp_data[3] = mmio_read_32(base + DWMMC_RESP3);
317*91f16700Schasinglulu 		}
318*91f16700Schasinglulu 	}
319*91f16700Schasinglulu 	return 0;
320*91f16700Schasinglulu }
321*91f16700Schasinglulu 
322*91f16700Schasinglulu static int dw_set_ios(unsigned int clk, unsigned int width)
323*91f16700Schasinglulu {
324*91f16700Schasinglulu 	switch (width) {
325*91f16700Schasinglulu 	case MMC_BUS_WIDTH_1:
326*91f16700Schasinglulu 		mmio_write_32(dw_params.reg_base + DWMMC_CTYPE, CTYPE_1BIT);
327*91f16700Schasinglulu 		break;
328*91f16700Schasinglulu 	case MMC_BUS_WIDTH_4:
329*91f16700Schasinglulu 		mmio_write_32(dw_params.reg_base + DWMMC_CTYPE, CTYPE_4BIT);
330*91f16700Schasinglulu 		break;
331*91f16700Schasinglulu 	case MMC_BUS_WIDTH_8:
332*91f16700Schasinglulu 		mmio_write_32(dw_params.reg_base + DWMMC_CTYPE, CTYPE_8BIT);
333*91f16700Schasinglulu 		break;
334*91f16700Schasinglulu 	default:
335*91f16700Schasinglulu 		assert(0);
336*91f16700Schasinglulu 		break;
337*91f16700Schasinglulu 	}
338*91f16700Schasinglulu 	dw_set_clk(clk);
339*91f16700Schasinglulu 	return 0;
340*91f16700Schasinglulu }
341*91f16700Schasinglulu 
342*91f16700Schasinglulu static int dw_prepare(int lba, uintptr_t buf, size_t size)
343*91f16700Schasinglulu {
344*91f16700Schasinglulu 	struct dw_idmac_desc *desc;
345*91f16700Schasinglulu 	int desc_cnt, i, last;
346*91f16700Schasinglulu 	uintptr_t base;
347*91f16700Schasinglulu 
348*91f16700Schasinglulu 	assert(((buf & DWMMC_ADDRESS_MASK) == 0) &&
349*91f16700Schasinglulu 	       (dw_params.desc_size > 0) &&
350*91f16700Schasinglulu 	       ((dw_params.reg_base & MMC_BLOCK_MASK) == 0) &&
351*91f16700Schasinglulu 	       ((dw_params.desc_base & MMC_BLOCK_MASK) == 0) &&
352*91f16700Schasinglulu 	       ((dw_params.desc_size & MMC_BLOCK_MASK) == 0));
353*91f16700Schasinglulu 
354*91f16700Schasinglulu 	flush_dcache_range(buf, size);
355*91f16700Schasinglulu 
356*91f16700Schasinglulu 	desc_cnt = (size + DWMMC_DMA_MAX_BUFFER_SIZE - 1) /
357*91f16700Schasinglulu 		   DWMMC_DMA_MAX_BUFFER_SIZE;
358*91f16700Schasinglulu 	assert(desc_cnt * sizeof(struct dw_idmac_desc) < dw_params.desc_size);
359*91f16700Schasinglulu 
360*91f16700Schasinglulu 	base = dw_params.reg_base;
361*91f16700Schasinglulu 	desc = (struct dw_idmac_desc *)dw_params.desc_base;
362*91f16700Schasinglulu 	mmio_write_32(base + DWMMC_BYTCNT, size);
363*91f16700Schasinglulu 
364*91f16700Schasinglulu 	if (size < MMC_BLOCK_SIZE)
365*91f16700Schasinglulu 		mmio_write_32(base + DWMMC_BLKSIZ, size);
366*91f16700Schasinglulu 	else
367*91f16700Schasinglulu 		mmio_write_32(base + DWMMC_BLKSIZ, MMC_BLOCK_SIZE);
368*91f16700Schasinglulu 
369*91f16700Schasinglulu 	mmio_write_32(base + DWMMC_RINTSTS, ~0);
370*91f16700Schasinglulu 	for (i = 0; i < desc_cnt; i++) {
371*91f16700Schasinglulu 		desc[i].des0 = IDMAC_DES0_OWN | IDMAC_DES0_CH | IDMAC_DES0_DIC;
372*91f16700Schasinglulu 		desc[i].des1 = IDMAC_DES1_BS1(DWMMC_DMA_MAX_BUFFER_SIZE);
373*91f16700Schasinglulu 		desc[i].des2 = buf + DWMMC_DMA_MAX_BUFFER_SIZE * i;
374*91f16700Schasinglulu 		desc[i].des3 = dw_params.desc_base +
375*91f16700Schasinglulu 			       (sizeof(struct dw_idmac_desc)) * (i + 1);
376*91f16700Schasinglulu 	}
377*91f16700Schasinglulu 	/* first descriptor */
378*91f16700Schasinglulu 	desc->des0 |= IDMAC_DES0_FS;
379*91f16700Schasinglulu 	/* last descriptor */
380*91f16700Schasinglulu 	last = desc_cnt - 1;
381*91f16700Schasinglulu 	(desc + last)->des0 |= IDMAC_DES0_LD;
382*91f16700Schasinglulu 	(desc + last)->des0 &= ~(IDMAC_DES0_DIC | IDMAC_DES0_CH);
383*91f16700Schasinglulu 	(desc + last)->des1 = IDMAC_DES1_BS1(size - (last *
384*91f16700Schasinglulu 				  DWMMC_DMA_MAX_BUFFER_SIZE));
385*91f16700Schasinglulu 	/* set next descriptor address as 0 */
386*91f16700Schasinglulu 	(desc + last)->des3 = 0;
387*91f16700Schasinglulu 
388*91f16700Schasinglulu 	mmio_write_32(base + DWMMC_DBADDR, dw_params.desc_base);
389*91f16700Schasinglulu 	flush_dcache_range(dw_params.desc_base,
390*91f16700Schasinglulu 			   desc_cnt * DWMMC_DMA_MAX_BUFFER_SIZE);
391*91f16700Schasinglulu 
392*91f16700Schasinglulu 
393*91f16700Schasinglulu 	return 0;
394*91f16700Schasinglulu }
395*91f16700Schasinglulu 
396*91f16700Schasinglulu static int dw_read(int lba, uintptr_t buf, size_t size)
397*91f16700Schasinglulu {
398*91f16700Schasinglulu 	uint32_t data = 0;
399*91f16700Schasinglulu 	int timeout = TIMEOUT;
400*91f16700Schasinglulu 
401*91f16700Schasinglulu 	do {
402*91f16700Schasinglulu 		data = mmio_read_32(dw_params.reg_base + DWMMC_RINTSTS);
403*91f16700Schasinglulu 		udelay(50);
404*91f16700Schasinglulu 	} while (!(data & INT_DTO) && timeout-- > 0);
405*91f16700Schasinglulu 
406*91f16700Schasinglulu 	inv_dcache_range(buf, size);
407*91f16700Schasinglulu 
408*91f16700Schasinglulu 	return 0;
409*91f16700Schasinglulu }
410*91f16700Schasinglulu 
411*91f16700Schasinglulu static int dw_write(int lba, uintptr_t buf, size_t size)
412*91f16700Schasinglulu {
413*91f16700Schasinglulu 	return 0;
414*91f16700Schasinglulu }
415*91f16700Schasinglulu 
416*91f16700Schasinglulu void dw_mmc_init(dw_mmc_params_t *params, struct mmc_device_info *info)
417*91f16700Schasinglulu {
418*91f16700Schasinglulu 	assert((params != 0) &&
419*91f16700Schasinglulu 	       ((params->reg_base & MMC_BLOCK_MASK) == 0) &&
420*91f16700Schasinglulu 	       ((params->desc_base & MMC_BLOCK_MASK) == 0) &&
421*91f16700Schasinglulu 	       ((params->desc_size & MMC_BLOCK_MASK) == 0) &&
422*91f16700Schasinglulu 	       (params->desc_size > 0) &&
423*91f16700Schasinglulu 	       (params->clk_rate > 0) &&
424*91f16700Schasinglulu 	       ((params->bus_width == MMC_BUS_WIDTH_1) ||
425*91f16700Schasinglulu 		(params->bus_width == MMC_BUS_WIDTH_4) ||
426*91f16700Schasinglulu 		(params->bus_width == MMC_BUS_WIDTH_8)));
427*91f16700Schasinglulu 
428*91f16700Schasinglulu 	memcpy(&dw_params, params, sizeof(dw_mmc_params_t));
429*91f16700Schasinglulu 	dw_params.mmc_dev_type = info->mmc_dev_type;
430*91f16700Schasinglulu 	mmc_init(&dw_mmc_ops, params->clk_rate, params->bus_width,
431*91f16700Schasinglulu 		 params->flags, info);
432*91f16700Schasinglulu }
433