xref: /rk3399_ARM-atf/drivers/synopsys/emmc/dw_mmc.c (revision 5dbdb7da1cae6e58d8b1b47948c16bb7a6babd72)
1*5dbdb7daSHaojian Zhuang /*
2*5dbdb7daSHaojian Zhuang  * Copyright (c) 2016-2017, ARM Limited and Contributors. All rights reserved.
3*5dbdb7daSHaojian Zhuang  *
4*5dbdb7daSHaojian Zhuang  * Redistribution and use in source and binary forms, with or without
5*5dbdb7daSHaojian Zhuang  * modification, are permitted provided that the following conditions are met:
6*5dbdb7daSHaojian Zhuang  *
7*5dbdb7daSHaojian Zhuang  * Redistributions of source code must retain the above copyright notice, this
8*5dbdb7daSHaojian Zhuang  * list of conditions and the following disclaimer.
9*5dbdb7daSHaojian Zhuang  *
10*5dbdb7daSHaojian Zhuang  * Redistributions in binary form must reproduce the above copyright notice,
11*5dbdb7daSHaojian Zhuang  * this list of conditions and the following disclaimer in the documentation
12*5dbdb7daSHaojian Zhuang  * and/or other materials provided with the distribution.
13*5dbdb7daSHaojian Zhuang  *
14*5dbdb7daSHaojian Zhuang  * Neither the name of ARM nor the names of its contributors may be used
15*5dbdb7daSHaojian Zhuang  * to endorse or promote products derived from this software without specific
16*5dbdb7daSHaojian Zhuang  * prior written permission.
17*5dbdb7daSHaojian Zhuang  *
18*5dbdb7daSHaojian Zhuang  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19*5dbdb7daSHaojian Zhuang  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20*5dbdb7daSHaojian Zhuang  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21*5dbdb7daSHaojian Zhuang  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
22*5dbdb7daSHaojian Zhuang  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23*5dbdb7daSHaojian Zhuang  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24*5dbdb7daSHaojian Zhuang  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25*5dbdb7daSHaojian Zhuang  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26*5dbdb7daSHaojian Zhuang  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27*5dbdb7daSHaojian Zhuang  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28*5dbdb7daSHaojian Zhuang  * POSSIBILITY OF SUCH DAMAGE.
29*5dbdb7daSHaojian Zhuang  */
30*5dbdb7daSHaojian Zhuang 
31*5dbdb7daSHaojian Zhuang #include <arch.h>
32*5dbdb7daSHaojian Zhuang #include <arch_helpers.h>
33*5dbdb7daSHaojian Zhuang #include <assert.h>
34*5dbdb7daSHaojian Zhuang #include <debug.h>
35*5dbdb7daSHaojian Zhuang #include <delay_timer.h>
36*5dbdb7daSHaojian Zhuang #include <dw_mmc.h>
37*5dbdb7daSHaojian Zhuang #include <emmc.h>
38*5dbdb7daSHaojian Zhuang #include <errno.h>
39*5dbdb7daSHaojian Zhuang #include <mmio.h>
40*5dbdb7daSHaojian Zhuang #include <string.h>
41*5dbdb7daSHaojian Zhuang 
42*5dbdb7daSHaojian Zhuang #define DWMMC_CTRL			(0x00)
43*5dbdb7daSHaojian Zhuang #define CTRL_IDMAC_EN			(1 << 25)
44*5dbdb7daSHaojian Zhuang #define CTRL_DMA_EN			(1 << 5)
45*5dbdb7daSHaojian Zhuang #define CTRL_INT_EN			(1 << 4)
46*5dbdb7daSHaojian Zhuang #define CTRL_DMA_RESET			(1 << 2)
47*5dbdb7daSHaojian Zhuang #define CTRL_FIFO_RESET			(1 << 1)
48*5dbdb7daSHaojian Zhuang #define CTRL_RESET			(1 << 0)
49*5dbdb7daSHaojian Zhuang #define CTRL_RESET_ALL			(CTRL_DMA_RESET | CTRL_FIFO_RESET | \
50*5dbdb7daSHaojian Zhuang 					 CTRL_RESET)
51*5dbdb7daSHaojian Zhuang 
52*5dbdb7daSHaojian Zhuang #define DWMMC_PWREN			(0x04)
53*5dbdb7daSHaojian Zhuang #define DWMMC_CLKDIV			(0x08)
54*5dbdb7daSHaojian Zhuang #define DWMMC_CLKSRC			(0x0c)
55*5dbdb7daSHaojian Zhuang #define DWMMC_CLKENA			(0x10)
56*5dbdb7daSHaojian Zhuang #define DWMMC_TMOUT			(0x14)
57*5dbdb7daSHaojian Zhuang #define DWMMC_CTYPE			(0x18)
58*5dbdb7daSHaojian Zhuang #define CTYPE_8BIT			(1 << 16)
59*5dbdb7daSHaojian Zhuang #define CTYPE_4BIT			(1)
60*5dbdb7daSHaojian Zhuang #define CTYPE_1BIT			(0)
61*5dbdb7daSHaojian Zhuang 
62*5dbdb7daSHaojian Zhuang #define DWMMC_BLKSIZ			(0x1c)
63*5dbdb7daSHaojian Zhuang #define DWMMC_BYTCNT			(0x20)
64*5dbdb7daSHaojian Zhuang #define DWMMC_INTMASK			(0x24)
65*5dbdb7daSHaojian Zhuang #define INT_EBE				(1 << 15)
66*5dbdb7daSHaojian Zhuang #define INT_SBE				(1 << 13)
67*5dbdb7daSHaojian Zhuang #define INT_HLE				(1 << 12)
68*5dbdb7daSHaojian Zhuang #define INT_FRUN			(1 << 11)
69*5dbdb7daSHaojian Zhuang #define INT_DRT				(1 << 9)
70*5dbdb7daSHaojian Zhuang #define INT_RTO				(1 << 8)
71*5dbdb7daSHaojian Zhuang #define INT_DCRC			(1 << 7)
72*5dbdb7daSHaojian Zhuang #define INT_RCRC			(1 << 6)
73*5dbdb7daSHaojian Zhuang #define INT_RXDR			(1 << 5)
74*5dbdb7daSHaojian Zhuang #define INT_TXDR			(1 << 4)
75*5dbdb7daSHaojian Zhuang #define INT_DTO				(1 << 3)
76*5dbdb7daSHaojian Zhuang #define INT_CMD_DONE			(1 << 2)
77*5dbdb7daSHaojian Zhuang #define INT_RE				(1 << 1)
78*5dbdb7daSHaojian Zhuang 
79*5dbdb7daSHaojian Zhuang #define DWMMC_CMDARG			(0x28)
80*5dbdb7daSHaojian Zhuang #define DWMMC_CMD			(0x2c)
81*5dbdb7daSHaojian Zhuang #define CMD_START			(1 << 31)
82*5dbdb7daSHaojian Zhuang #define CMD_USE_HOLD_REG		(1 << 29)	/* 0 if SDR50/100 */
83*5dbdb7daSHaojian Zhuang #define CMD_UPDATE_CLK_ONLY		(1 << 21)
84*5dbdb7daSHaojian Zhuang #define CMD_SEND_INIT			(1 << 15)
85*5dbdb7daSHaojian Zhuang #define CMD_STOP_ABORT_CMD		(1 << 14)
86*5dbdb7daSHaojian Zhuang #define CMD_WAIT_PRVDATA_COMPLETE	(1 << 13)
87*5dbdb7daSHaojian Zhuang #define CMD_WRITE			(1 << 10)
88*5dbdb7daSHaojian Zhuang #define CMD_DATA_TRANS_EXPECT		(1 << 9)
89*5dbdb7daSHaojian Zhuang #define CMD_CHECK_RESP_CRC		(1 << 8)
90*5dbdb7daSHaojian Zhuang #define CMD_RESP_LEN			(1 << 7)
91*5dbdb7daSHaojian Zhuang #define CMD_RESP_EXPECT			(1 << 6)
92*5dbdb7daSHaojian Zhuang #define CMD(x)				(x & 0x3f)
93*5dbdb7daSHaojian Zhuang 
94*5dbdb7daSHaojian Zhuang #define DWMMC_RESP0			(0x30)
95*5dbdb7daSHaojian Zhuang #define DWMMC_RESP1			(0x34)
96*5dbdb7daSHaojian Zhuang #define DWMMC_RESP2			(0x38)
97*5dbdb7daSHaojian Zhuang #define DWMMC_RESP3			(0x3c)
98*5dbdb7daSHaojian Zhuang #define DWMMC_RINTSTS			(0x44)
99*5dbdb7daSHaojian Zhuang #define DWMMC_STATUS			(0x48)
100*5dbdb7daSHaojian Zhuang #define STATUS_DATA_BUSY		(1 << 9)
101*5dbdb7daSHaojian Zhuang 
102*5dbdb7daSHaojian Zhuang #define DWMMC_FIFOTH			(0x4c)
103*5dbdb7daSHaojian Zhuang #define FIFOTH_TWMARK(x)		(x & 0xfff)
104*5dbdb7daSHaojian Zhuang #define FIFOTH_RWMARK(x)		((x & 0x1ff) << 16)
105*5dbdb7daSHaojian Zhuang #define FIFOTH_DMA_BURST_SIZE(x)	((x & 0x7) << 28)
106*5dbdb7daSHaojian Zhuang 
107*5dbdb7daSHaojian Zhuang #define DWMMC_DEBNCE			(0x64)
108*5dbdb7daSHaojian Zhuang #define DWMMC_BMOD			(0x80)
109*5dbdb7daSHaojian Zhuang #define BMOD_ENABLE			(1 << 7)
110*5dbdb7daSHaojian Zhuang #define BMOD_FB				(1 << 1)
111*5dbdb7daSHaojian Zhuang #define BMOD_SWRESET			(1 << 0)
112*5dbdb7daSHaojian Zhuang 
113*5dbdb7daSHaojian Zhuang #define DWMMC_DBADDR			(0x88)
114*5dbdb7daSHaojian Zhuang #define DWMMC_IDSTS			(0x8c)
115*5dbdb7daSHaojian Zhuang #define DWMMC_IDINTEN			(0x90)
116*5dbdb7daSHaojian Zhuang #define DWMMC_CARDTHRCTL		(0x100)
117*5dbdb7daSHaojian Zhuang #define CARDTHRCTL_RD_THR(x)		((x & 0xfff) << 16)
118*5dbdb7daSHaojian Zhuang #define CARDTHRCTL_RD_THR_EN		(1 << 0)
119*5dbdb7daSHaojian Zhuang 
120*5dbdb7daSHaojian Zhuang #define IDMAC_DES0_DIC			(1 << 1)
121*5dbdb7daSHaojian Zhuang #define IDMAC_DES0_LD			(1 << 2)
122*5dbdb7daSHaojian Zhuang #define IDMAC_DES0_FS			(1 << 3)
123*5dbdb7daSHaojian Zhuang #define IDMAC_DES0_CH			(1 << 4)
124*5dbdb7daSHaojian Zhuang #define IDMAC_DES0_ER			(1 << 5)
125*5dbdb7daSHaojian Zhuang #define IDMAC_DES0_CES			(1 << 30)
126*5dbdb7daSHaojian Zhuang #define IDMAC_DES0_OWN			(1 << 31)
127*5dbdb7daSHaojian Zhuang #define IDMAC_DES1_BS1(x)		((x) & 0x1fff)
128*5dbdb7daSHaojian Zhuang #define IDMAC_DES2_BS2(x)		(((x) & 0x1fff) << 13)
129*5dbdb7daSHaojian Zhuang 
130*5dbdb7daSHaojian Zhuang #define DWMMC_DMA_MAX_BUFFER_SIZE	(512 * 8)
131*5dbdb7daSHaojian Zhuang 
132*5dbdb7daSHaojian Zhuang #define DWMMC_8BIT_MODE			(1 << 6)
133*5dbdb7daSHaojian Zhuang 
134*5dbdb7daSHaojian Zhuang #define TIMEOUT				100000
135*5dbdb7daSHaojian Zhuang 
136*5dbdb7daSHaojian Zhuang struct dw_idmac_desc {
137*5dbdb7daSHaojian Zhuang 	unsigned int	des0;
138*5dbdb7daSHaojian Zhuang 	unsigned int	des1;
139*5dbdb7daSHaojian Zhuang 	unsigned int	des2;
140*5dbdb7daSHaojian Zhuang 	unsigned int	des3;
141*5dbdb7daSHaojian Zhuang };
142*5dbdb7daSHaojian Zhuang 
143*5dbdb7daSHaojian Zhuang static void dw_init(void);
144*5dbdb7daSHaojian Zhuang static int dw_send_cmd(emmc_cmd_t *cmd);
145*5dbdb7daSHaojian Zhuang static int dw_set_ios(int clk, int width);
146*5dbdb7daSHaojian Zhuang static int dw_prepare(int lba, uintptr_t buf, size_t size);
147*5dbdb7daSHaojian Zhuang static int dw_read(int lba, uintptr_t buf, size_t size);
148*5dbdb7daSHaojian Zhuang static int dw_write(int lba, uintptr_t buf, size_t size);
149*5dbdb7daSHaojian Zhuang 
150*5dbdb7daSHaojian Zhuang static const emmc_ops_t dw_mmc_ops = {
151*5dbdb7daSHaojian Zhuang 	.init		= dw_init,
152*5dbdb7daSHaojian Zhuang 	.send_cmd	= dw_send_cmd,
153*5dbdb7daSHaojian Zhuang 	.set_ios	= dw_set_ios,
154*5dbdb7daSHaojian Zhuang 	.prepare	= dw_prepare,
155*5dbdb7daSHaojian Zhuang 	.read		= dw_read,
156*5dbdb7daSHaojian Zhuang 	.write		= dw_write,
157*5dbdb7daSHaojian Zhuang };
158*5dbdb7daSHaojian Zhuang 
159*5dbdb7daSHaojian Zhuang static dw_mmc_params_t dw_params;
160*5dbdb7daSHaojian Zhuang 
161*5dbdb7daSHaojian Zhuang static void dw_update_clk(void)
162*5dbdb7daSHaojian Zhuang {
163*5dbdb7daSHaojian Zhuang 	unsigned int data;
164*5dbdb7daSHaojian Zhuang 
165*5dbdb7daSHaojian Zhuang 	mmio_write_32(dw_params.reg_base + DWMMC_CMD,
166*5dbdb7daSHaojian Zhuang 		      CMD_WAIT_PRVDATA_COMPLETE | CMD_UPDATE_CLK_ONLY |
167*5dbdb7daSHaojian Zhuang 		      CMD_START);
168*5dbdb7daSHaojian Zhuang 	while (1) {
169*5dbdb7daSHaojian Zhuang 		data = mmio_read_32(dw_params.reg_base + DWMMC_CMD);
170*5dbdb7daSHaojian Zhuang 		if ((data & CMD_START) == 0)
171*5dbdb7daSHaojian Zhuang 			break;
172*5dbdb7daSHaojian Zhuang 		data = mmio_read_32(dw_params.reg_base + DWMMC_RINTSTS);
173*5dbdb7daSHaojian Zhuang 		assert(data & INT_HLE);
174*5dbdb7daSHaojian Zhuang 	}
175*5dbdb7daSHaojian Zhuang }
176*5dbdb7daSHaojian Zhuang 
177*5dbdb7daSHaojian Zhuang static void dw_set_clk(int clk)
178*5dbdb7daSHaojian Zhuang {
179*5dbdb7daSHaojian Zhuang 	unsigned int data;
180*5dbdb7daSHaojian Zhuang 	int div;
181*5dbdb7daSHaojian Zhuang 
182*5dbdb7daSHaojian Zhuang 	assert(clk > 0);
183*5dbdb7daSHaojian Zhuang 
184*5dbdb7daSHaojian Zhuang 	for (div = 1; div < 256; div++) {
185*5dbdb7daSHaojian Zhuang 		if ((dw_params.clk_rate / (2 * div)) <= clk) {
186*5dbdb7daSHaojian Zhuang 			break;
187*5dbdb7daSHaojian Zhuang 		}
188*5dbdb7daSHaojian Zhuang 	}
189*5dbdb7daSHaojian Zhuang 	assert(div < 256);
190*5dbdb7daSHaojian Zhuang 
191*5dbdb7daSHaojian Zhuang 	/* wait until controller is idle */
192*5dbdb7daSHaojian Zhuang 	do {
193*5dbdb7daSHaojian Zhuang 		data = mmio_read_32(dw_params.reg_base + DWMMC_STATUS);
194*5dbdb7daSHaojian Zhuang 	} while (data & STATUS_DATA_BUSY);
195*5dbdb7daSHaojian Zhuang 
196*5dbdb7daSHaojian Zhuang 	/* disable clock before change clock rate */
197*5dbdb7daSHaojian Zhuang 	mmio_write_32(dw_params.reg_base + DWMMC_CLKENA, 0);
198*5dbdb7daSHaojian Zhuang 	dw_update_clk();
199*5dbdb7daSHaojian Zhuang 
200*5dbdb7daSHaojian Zhuang 	mmio_write_32(dw_params.reg_base + DWMMC_CLKDIV, div);
201*5dbdb7daSHaojian Zhuang 	dw_update_clk();
202*5dbdb7daSHaojian Zhuang 
203*5dbdb7daSHaojian Zhuang 	/* enable clock */
204*5dbdb7daSHaojian Zhuang 	mmio_write_32(dw_params.reg_base + DWMMC_CLKENA, 1);
205*5dbdb7daSHaojian Zhuang 	mmio_write_32(dw_params.reg_base + DWMMC_CLKSRC, 0);
206*5dbdb7daSHaojian Zhuang 	dw_update_clk();
207*5dbdb7daSHaojian Zhuang }
208*5dbdb7daSHaojian Zhuang 
209*5dbdb7daSHaojian Zhuang static void dw_init(void)
210*5dbdb7daSHaojian Zhuang {
211*5dbdb7daSHaojian Zhuang 	unsigned int data;
212*5dbdb7daSHaojian Zhuang 	uintptr_t base;
213*5dbdb7daSHaojian Zhuang 
214*5dbdb7daSHaojian Zhuang 	assert((dw_params.reg_base & EMMC_BLOCK_MASK) == 0);
215*5dbdb7daSHaojian Zhuang 
216*5dbdb7daSHaojian Zhuang 	base = dw_params.reg_base;
217*5dbdb7daSHaojian Zhuang 	mmio_write_32(base + DWMMC_PWREN, 1);
218*5dbdb7daSHaojian Zhuang 	mmio_write_32(base + DWMMC_CTRL, CTRL_RESET_ALL);
219*5dbdb7daSHaojian Zhuang 	do {
220*5dbdb7daSHaojian Zhuang 		data = mmio_read_32(base + DWMMC_CTRL);
221*5dbdb7daSHaojian Zhuang 	} while (data);
222*5dbdb7daSHaojian Zhuang 
223*5dbdb7daSHaojian Zhuang 	/* enable DMA in CTRL */
224*5dbdb7daSHaojian Zhuang 	data = CTRL_INT_EN | CTRL_DMA_EN | CTRL_IDMAC_EN;
225*5dbdb7daSHaojian Zhuang 	mmio_write_32(base + DWMMC_CTRL, data);
226*5dbdb7daSHaojian Zhuang 	mmio_write_32(base + DWMMC_RINTSTS, ~0);
227*5dbdb7daSHaojian Zhuang 	mmio_write_32(base + DWMMC_INTMASK, 0);
228*5dbdb7daSHaojian Zhuang 	mmio_write_32(base + DWMMC_TMOUT, ~0);
229*5dbdb7daSHaojian Zhuang 	mmio_write_32(base + DWMMC_IDINTEN, ~0);
230*5dbdb7daSHaojian Zhuang 	mmio_write_32(base + DWMMC_BLKSIZ, EMMC_BLOCK_SIZE);
231*5dbdb7daSHaojian Zhuang 	mmio_write_32(base + DWMMC_BYTCNT, 256 * 1024);
232*5dbdb7daSHaojian Zhuang 	mmio_write_32(base + DWMMC_DEBNCE, 0x00ffffff);
233*5dbdb7daSHaojian Zhuang 	mmio_write_32(base + DWMMC_BMOD, BMOD_SWRESET);
234*5dbdb7daSHaojian Zhuang 	do {
235*5dbdb7daSHaojian Zhuang 		data = mmio_read_32(base + DWMMC_BMOD);
236*5dbdb7daSHaojian Zhuang 	} while (data & BMOD_SWRESET);
237*5dbdb7daSHaojian Zhuang 	/* enable DMA in BMOD */
238*5dbdb7daSHaojian Zhuang 	data |= BMOD_ENABLE | BMOD_FB;
239*5dbdb7daSHaojian Zhuang 	mmio_write_32(base + DWMMC_BMOD, data);
240*5dbdb7daSHaojian Zhuang 
241*5dbdb7daSHaojian Zhuang 	udelay(100);
242*5dbdb7daSHaojian Zhuang 	dw_set_clk(EMMC_BOOT_CLK_RATE);
243*5dbdb7daSHaojian Zhuang 	udelay(100);
244*5dbdb7daSHaojian Zhuang }
245*5dbdb7daSHaojian Zhuang 
246*5dbdb7daSHaojian Zhuang static int dw_send_cmd(emmc_cmd_t *cmd)
247*5dbdb7daSHaojian Zhuang {
248*5dbdb7daSHaojian Zhuang 	unsigned int op, data, err_mask;
249*5dbdb7daSHaojian Zhuang 	uintptr_t base;
250*5dbdb7daSHaojian Zhuang 	int timeout;
251*5dbdb7daSHaojian Zhuang 
252*5dbdb7daSHaojian Zhuang 	assert(cmd);
253*5dbdb7daSHaojian Zhuang 
254*5dbdb7daSHaojian Zhuang 	base = dw_params.reg_base;
255*5dbdb7daSHaojian Zhuang 
256*5dbdb7daSHaojian Zhuang 	switch (cmd->cmd_idx) {
257*5dbdb7daSHaojian Zhuang 	case EMMC_CMD0:
258*5dbdb7daSHaojian Zhuang 		op = CMD_SEND_INIT;
259*5dbdb7daSHaojian Zhuang 		break;
260*5dbdb7daSHaojian Zhuang 	case EMMC_CMD12:
261*5dbdb7daSHaojian Zhuang 		op = CMD_STOP_ABORT_CMD;
262*5dbdb7daSHaojian Zhuang 		break;
263*5dbdb7daSHaojian Zhuang 	case EMMC_CMD13:
264*5dbdb7daSHaojian Zhuang 		op = CMD_WAIT_PRVDATA_COMPLETE;
265*5dbdb7daSHaojian Zhuang 		break;
266*5dbdb7daSHaojian Zhuang 	case EMMC_CMD8:
267*5dbdb7daSHaojian Zhuang 	case EMMC_CMD17:
268*5dbdb7daSHaojian Zhuang 	case EMMC_CMD18:
269*5dbdb7daSHaojian Zhuang 		op = CMD_DATA_TRANS_EXPECT | CMD_WAIT_PRVDATA_COMPLETE;
270*5dbdb7daSHaojian Zhuang 		break;
271*5dbdb7daSHaojian Zhuang 	case EMMC_CMD24:
272*5dbdb7daSHaojian Zhuang 	case EMMC_CMD25:
273*5dbdb7daSHaojian Zhuang 		op = CMD_WRITE | CMD_DATA_TRANS_EXPECT |
274*5dbdb7daSHaojian Zhuang 		     CMD_WAIT_PRVDATA_COMPLETE;
275*5dbdb7daSHaojian Zhuang 		break;
276*5dbdb7daSHaojian Zhuang 	default:
277*5dbdb7daSHaojian Zhuang 		op = 0;
278*5dbdb7daSHaojian Zhuang 		break;
279*5dbdb7daSHaojian Zhuang 	}
280*5dbdb7daSHaojian Zhuang 	op |= CMD_USE_HOLD_REG | CMD_START;
281*5dbdb7daSHaojian Zhuang 	switch (cmd->resp_type) {
282*5dbdb7daSHaojian Zhuang 	case 0:
283*5dbdb7daSHaojian Zhuang 		break;
284*5dbdb7daSHaojian Zhuang 	case EMMC_RESPONSE_R2:
285*5dbdb7daSHaojian Zhuang 		op |= CMD_RESP_EXPECT | CMD_CHECK_RESP_CRC |
286*5dbdb7daSHaojian Zhuang 		      CMD_RESP_LEN;
287*5dbdb7daSHaojian Zhuang 		break;
288*5dbdb7daSHaojian Zhuang 	case EMMC_RESPONSE_R3:
289*5dbdb7daSHaojian Zhuang 		op |= CMD_RESP_EXPECT;
290*5dbdb7daSHaojian Zhuang 		break;
291*5dbdb7daSHaojian Zhuang 	default:
292*5dbdb7daSHaojian Zhuang 		op |= CMD_RESP_EXPECT | CMD_CHECK_RESP_CRC;
293*5dbdb7daSHaojian Zhuang 		break;
294*5dbdb7daSHaojian Zhuang 	}
295*5dbdb7daSHaojian Zhuang 	timeout = TIMEOUT;
296*5dbdb7daSHaojian Zhuang 	do {
297*5dbdb7daSHaojian Zhuang 		data = mmio_read_32(base + DWMMC_STATUS);
298*5dbdb7daSHaojian Zhuang 		if (--timeout <= 0)
299*5dbdb7daSHaojian Zhuang 			panic();
300*5dbdb7daSHaojian Zhuang 	} while (data & STATUS_DATA_BUSY);
301*5dbdb7daSHaojian Zhuang 
302*5dbdb7daSHaojian Zhuang 	mmio_write_32(base + DWMMC_RINTSTS, ~0);
303*5dbdb7daSHaojian Zhuang 	mmio_write_32(base + DWMMC_CMDARG, cmd->cmd_arg);
304*5dbdb7daSHaojian Zhuang 	mmio_write_32(base + DWMMC_CMD, op | cmd->cmd_idx);
305*5dbdb7daSHaojian Zhuang 
306*5dbdb7daSHaojian Zhuang 	err_mask = INT_EBE | INT_HLE | INT_RTO | INT_RCRC | INT_RE |
307*5dbdb7daSHaojian Zhuang 		   INT_DCRC | INT_DRT | INT_SBE;
308*5dbdb7daSHaojian Zhuang 	timeout = TIMEOUT;
309*5dbdb7daSHaojian Zhuang 	do {
310*5dbdb7daSHaojian Zhuang 		udelay(500);
311*5dbdb7daSHaojian Zhuang 		data = mmio_read_32(base + DWMMC_RINTSTS);
312*5dbdb7daSHaojian Zhuang 
313*5dbdb7daSHaojian Zhuang 		if (data & err_mask)
314*5dbdb7daSHaojian Zhuang 			return -EIO;
315*5dbdb7daSHaojian Zhuang 		if (data & INT_DTO)
316*5dbdb7daSHaojian Zhuang 			break;
317*5dbdb7daSHaojian Zhuang 		if (--timeout == 0) {
318*5dbdb7daSHaojian Zhuang 			ERROR("%s, RINTSTS:0x%x\n", __func__, data);
319*5dbdb7daSHaojian Zhuang 			panic();
320*5dbdb7daSHaojian Zhuang 		}
321*5dbdb7daSHaojian Zhuang 	} while (!(data & INT_CMD_DONE));
322*5dbdb7daSHaojian Zhuang 
323*5dbdb7daSHaojian Zhuang 	if (op & CMD_RESP_EXPECT) {
324*5dbdb7daSHaojian Zhuang 		cmd->resp_data[0] = mmio_read_32(base + DWMMC_RESP0);
325*5dbdb7daSHaojian Zhuang 		if (op & CMD_RESP_LEN) {
326*5dbdb7daSHaojian Zhuang 			cmd->resp_data[1] = mmio_read_32(base + DWMMC_RESP1);
327*5dbdb7daSHaojian Zhuang 			cmd->resp_data[2] = mmio_read_32(base + DWMMC_RESP2);
328*5dbdb7daSHaojian Zhuang 			cmd->resp_data[3] = mmio_read_32(base + DWMMC_RESP3);
329*5dbdb7daSHaojian Zhuang 		}
330*5dbdb7daSHaojian Zhuang 	}
331*5dbdb7daSHaojian Zhuang 	return 0;
332*5dbdb7daSHaojian Zhuang }
333*5dbdb7daSHaojian Zhuang 
334*5dbdb7daSHaojian Zhuang static int dw_set_ios(int clk, int width)
335*5dbdb7daSHaojian Zhuang {
336*5dbdb7daSHaojian Zhuang 	switch (width) {
337*5dbdb7daSHaojian Zhuang 	case EMMC_BUS_WIDTH_1:
338*5dbdb7daSHaojian Zhuang 		mmio_write_32(dw_params.reg_base + DWMMC_CTYPE, CTYPE_1BIT);
339*5dbdb7daSHaojian Zhuang 		break;
340*5dbdb7daSHaojian Zhuang 	case EMMC_BUS_WIDTH_4:
341*5dbdb7daSHaojian Zhuang 		mmio_write_32(dw_params.reg_base + DWMMC_CTYPE, CTYPE_4BIT);
342*5dbdb7daSHaojian Zhuang 		break;
343*5dbdb7daSHaojian Zhuang 	case EMMC_BUS_WIDTH_8:
344*5dbdb7daSHaojian Zhuang 		mmio_write_32(dw_params.reg_base + DWMMC_CTYPE, CTYPE_8BIT);
345*5dbdb7daSHaojian Zhuang 		break;
346*5dbdb7daSHaojian Zhuang 	default:
347*5dbdb7daSHaojian Zhuang 		assert(0);
348*5dbdb7daSHaojian Zhuang 	}
349*5dbdb7daSHaojian Zhuang 	dw_set_clk(clk);
350*5dbdb7daSHaojian Zhuang 	return 0;
351*5dbdb7daSHaojian Zhuang }
352*5dbdb7daSHaojian Zhuang 
353*5dbdb7daSHaojian Zhuang static int dw_prepare(int lba, uintptr_t buf, size_t size)
354*5dbdb7daSHaojian Zhuang {
355*5dbdb7daSHaojian Zhuang 	struct dw_idmac_desc *desc;
356*5dbdb7daSHaojian Zhuang 	int desc_cnt, i, last;
357*5dbdb7daSHaojian Zhuang 	uintptr_t base;
358*5dbdb7daSHaojian Zhuang 
359*5dbdb7daSHaojian Zhuang 	assert(((buf & EMMC_BLOCK_MASK) == 0) &&
360*5dbdb7daSHaojian Zhuang 	       ((size % EMMC_BLOCK_SIZE) == 0) &&
361*5dbdb7daSHaojian Zhuang 	       (dw_params.desc_size > 0) &&
362*5dbdb7daSHaojian Zhuang 	       ((dw_params.reg_base & EMMC_BLOCK_MASK) == 0) &&
363*5dbdb7daSHaojian Zhuang 	       ((dw_params.desc_base & EMMC_BLOCK_MASK) == 0) &&
364*5dbdb7daSHaojian Zhuang 	       ((dw_params.desc_size & EMMC_BLOCK_MASK) == 0));
365*5dbdb7daSHaojian Zhuang 
366*5dbdb7daSHaojian Zhuang 	desc_cnt = (size + DWMMC_DMA_MAX_BUFFER_SIZE - 1) /
367*5dbdb7daSHaojian Zhuang 		   DWMMC_DMA_MAX_BUFFER_SIZE;
368*5dbdb7daSHaojian Zhuang 	assert(desc_cnt * sizeof(struct dw_idmac_desc) < dw_params.desc_size);
369*5dbdb7daSHaojian Zhuang 
370*5dbdb7daSHaojian Zhuang 	base = dw_params.reg_base;
371*5dbdb7daSHaojian Zhuang 	desc = (struct dw_idmac_desc *)dw_params.desc_base;
372*5dbdb7daSHaojian Zhuang 	mmio_write_32(base + DWMMC_BYTCNT, size);
373*5dbdb7daSHaojian Zhuang 	mmio_write_32(base + DWMMC_RINTSTS, ~0);
374*5dbdb7daSHaojian Zhuang 	for (i = 0; i < desc_cnt; i++) {
375*5dbdb7daSHaojian Zhuang 		desc[i].des0 = IDMAC_DES0_OWN | IDMAC_DES0_CH | IDMAC_DES0_DIC;
376*5dbdb7daSHaojian Zhuang 		desc[i].des1 = IDMAC_DES1_BS1(DWMMC_DMA_MAX_BUFFER_SIZE);
377*5dbdb7daSHaojian Zhuang 		desc[i].des2 = buf + DWMMC_DMA_MAX_BUFFER_SIZE * i;
378*5dbdb7daSHaojian Zhuang 		desc[i].des3 = dw_params.desc_base +
379*5dbdb7daSHaojian Zhuang 			       (sizeof(struct dw_idmac_desc)) * (i + 1);
380*5dbdb7daSHaojian Zhuang 	}
381*5dbdb7daSHaojian Zhuang 	/* first descriptor */
382*5dbdb7daSHaojian Zhuang 	desc->des0 |= IDMAC_DES0_FS;
383*5dbdb7daSHaojian Zhuang 	/* last descriptor */
384*5dbdb7daSHaojian Zhuang 	last = desc_cnt - 1;
385*5dbdb7daSHaojian Zhuang 	(desc + last)->des0 |= IDMAC_DES0_LD;
386*5dbdb7daSHaojian Zhuang 	(desc + last)->des0 &= ~(IDMAC_DES0_DIC | IDMAC_DES0_CH);
387*5dbdb7daSHaojian Zhuang 	(desc + last)->des1 = IDMAC_DES1_BS1(size - (last *
388*5dbdb7daSHaojian Zhuang 				  DWMMC_DMA_MAX_BUFFER_SIZE));
389*5dbdb7daSHaojian Zhuang 	/* set next descriptor address as 0 */
390*5dbdb7daSHaojian Zhuang 	(desc + last)->des3 = 0;
391*5dbdb7daSHaojian Zhuang 
392*5dbdb7daSHaojian Zhuang 	mmio_write_32(base + DWMMC_DBADDR, dw_params.desc_base);
393*5dbdb7daSHaojian Zhuang 	clean_dcache_range(dw_params.desc_base,
394*5dbdb7daSHaojian Zhuang 			   desc_cnt * DWMMC_DMA_MAX_BUFFER_SIZE);
395*5dbdb7daSHaojian Zhuang 
396*5dbdb7daSHaojian Zhuang 	return 0;
397*5dbdb7daSHaojian Zhuang }
398*5dbdb7daSHaojian Zhuang 
399*5dbdb7daSHaojian Zhuang static int dw_read(int lba, uintptr_t buf, size_t size)
400*5dbdb7daSHaojian Zhuang {
401*5dbdb7daSHaojian Zhuang 	return 0;
402*5dbdb7daSHaojian Zhuang }
403*5dbdb7daSHaojian Zhuang 
404*5dbdb7daSHaojian Zhuang static int dw_write(int lba, uintptr_t buf, size_t size)
405*5dbdb7daSHaojian Zhuang {
406*5dbdb7daSHaojian Zhuang 	return 0;
407*5dbdb7daSHaojian Zhuang }
408*5dbdb7daSHaojian Zhuang 
409*5dbdb7daSHaojian Zhuang void dw_mmc_init(dw_mmc_params_t *params)
410*5dbdb7daSHaojian Zhuang {
411*5dbdb7daSHaojian Zhuang 	assert((params != 0) &&
412*5dbdb7daSHaojian Zhuang 	       ((params->reg_base & EMMC_BLOCK_MASK) == 0) &&
413*5dbdb7daSHaojian Zhuang 	       ((params->desc_base & EMMC_BLOCK_MASK) == 0) &&
414*5dbdb7daSHaojian Zhuang 	       ((params->desc_size & EMMC_BLOCK_MASK) == 0) &&
415*5dbdb7daSHaojian Zhuang 	       (params->desc_size > 0) &&
416*5dbdb7daSHaojian Zhuang 	       (params->clk_rate > 0) &&
417*5dbdb7daSHaojian Zhuang 	       ((params->bus_width == EMMC_BUS_WIDTH_1) ||
418*5dbdb7daSHaojian Zhuang 		(params->bus_width == EMMC_BUS_WIDTH_4) ||
419*5dbdb7daSHaojian Zhuang 		(params->bus_width == EMMC_BUS_WIDTH_8)));
420*5dbdb7daSHaojian Zhuang 
421*5dbdb7daSHaojian Zhuang 	memcpy(&dw_params, params, sizeof(dw_mmc_params_t));
422*5dbdb7daSHaojian Zhuang 	emmc_init(&dw_mmc_ops, params->clk_rate, params->bus_width,
423*5dbdb7daSHaojian Zhuang 		  params->flags);
424*5dbdb7daSHaojian Zhuang }
425