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