xref: /OK3568_Linux_fs/u-boot/drivers/mmc/sh_sdhi.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun  * drivers/mmc/sh_sdhi.c
3*4882a593Smuzhiyun  *
4*4882a593Smuzhiyun  * SD/MMC driver for Renesas rmobile ARM SoCs.
5*4882a593Smuzhiyun  *
6*4882a593Smuzhiyun  * Copyright (C) 2011,2013-2017 Renesas Electronics Corporation
7*4882a593Smuzhiyun  * Copyright (C) 2014 Nobuhiro Iwamatsu <nobuhiro.iwamatsu.yj@renesas.com>
8*4882a593Smuzhiyun  * Copyright (C) 2008-2009 Renesas Solutions Corp.
9*4882a593Smuzhiyun  *
10*4882a593Smuzhiyun  * SPDX-License-Identifier:	GPL-2.0
11*4882a593Smuzhiyun  */
12*4882a593Smuzhiyun 
13*4882a593Smuzhiyun #include <common.h>
14*4882a593Smuzhiyun #include <malloc.h>
15*4882a593Smuzhiyun #include <mmc.h>
16*4882a593Smuzhiyun #include <dm.h>
17*4882a593Smuzhiyun #include <linux/errno.h>
18*4882a593Smuzhiyun #include <linux/compat.h>
19*4882a593Smuzhiyun #include <linux/io.h>
20*4882a593Smuzhiyun #include <linux/sizes.h>
21*4882a593Smuzhiyun #include <asm/arch/rmobile.h>
22*4882a593Smuzhiyun #include <asm/arch/sh_sdhi.h>
23*4882a593Smuzhiyun #include <clk.h>
24*4882a593Smuzhiyun 
25*4882a593Smuzhiyun #define DRIVER_NAME "sh-sdhi"
26*4882a593Smuzhiyun 
27*4882a593Smuzhiyun struct sh_sdhi_host {
28*4882a593Smuzhiyun 	void __iomem *addr;
29*4882a593Smuzhiyun 	int ch;
30*4882a593Smuzhiyun 	int bus_shift;
31*4882a593Smuzhiyun 	unsigned long quirks;
32*4882a593Smuzhiyun 	unsigned char wait_int;
33*4882a593Smuzhiyun 	unsigned char sd_error;
34*4882a593Smuzhiyun 	unsigned char detect_waiting;
35*4882a593Smuzhiyun 	unsigned char app_cmd;
36*4882a593Smuzhiyun };
37*4882a593Smuzhiyun 
sh_sdhi_writeq(struct sh_sdhi_host * host,int reg,u64 val)38*4882a593Smuzhiyun static inline void sh_sdhi_writeq(struct sh_sdhi_host *host, int reg, u64 val)
39*4882a593Smuzhiyun {
40*4882a593Smuzhiyun 	writeq(val, host->addr + (reg << host->bus_shift));
41*4882a593Smuzhiyun }
42*4882a593Smuzhiyun 
sh_sdhi_readq(struct sh_sdhi_host * host,int reg)43*4882a593Smuzhiyun static inline u64 sh_sdhi_readq(struct sh_sdhi_host *host, int reg)
44*4882a593Smuzhiyun {
45*4882a593Smuzhiyun 	return readq(host->addr + (reg << host->bus_shift));
46*4882a593Smuzhiyun }
47*4882a593Smuzhiyun 
sh_sdhi_writew(struct sh_sdhi_host * host,int reg,u16 val)48*4882a593Smuzhiyun static inline void sh_sdhi_writew(struct sh_sdhi_host *host, int reg, u16 val)
49*4882a593Smuzhiyun {
50*4882a593Smuzhiyun 	writew(val, host->addr + (reg << host->bus_shift));
51*4882a593Smuzhiyun }
52*4882a593Smuzhiyun 
sh_sdhi_readw(struct sh_sdhi_host * host,int reg)53*4882a593Smuzhiyun static inline u16 sh_sdhi_readw(struct sh_sdhi_host *host, int reg)
54*4882a593Smuzhiyun {
55*4882a593Smuzhiyun 	return readw(host->addr + (reg << host->bus_shift));
56*4882a593Smuzhiyun }
57*4882a593Smuzhiyun 
sh_sdhi_detect(struct sh_sdhi_host * host)58*4882a593Smuzhiyun static void sh_sdhi_detect(struct sh_sdhi_host *host)
59*4882a593Smuzhiyun {
60*4882a593Smuzhiyun 	sh_sdhi_writew(host, SDHI_OPTION,
61*4882a593Smuzhiyun 		       OPT_BUS_WIDTH_1 | sh_sdhi_readw(host, SDHI_OPTION));
62*4882a593Smuzhiyun 
63*4882a593Smuzhiyun 	host->detect_waiting = 0;
64*4882a593Smuzhiyun }
65*4882a593Smuzhiyun 
sh_sdhi_intr(void * dev_id)66*4882a593Smuzhiyun static int sh_sdhi_intr(void *dev_id)
67*4882a593Smuzhiyun {
68*4882a593Smuzhiyun 	struct sh_sdhi_host *host = dev_id;
69*4882a593Smuzhiyun 	int state1 = 0, state2 = 0;
70*4882a593Smuzhiyun 
71*4882a593Smuzhiyun 	state1 = sh_sdhi_readw(host, SDHI_INFO1);
72*4882a593Smuzhiyun 	state2 = sh_sdhi_readw(host, SDHI_INFO2);
73*4882a593Smuzhiyun 
74*4882a593Smuzhiyun 	debug("%s: state1 = %x, state2 = %x\n", __func__, state1, state2);
75*4882a593Smuzhiyun 
76*4882a593Smuzhiyun 	/* CARD Insert */
77*4882a593Smuzhiyun 	if (state1 & INFO1_CARD_IN) {
78*4882a593Smuzhiyun 		sh_sdhi_writew(host, SDHI_INFO1, ~INFO1_CARD_IN);
79*4882a593Smuzhiyun 		if (!host->detect_waiting) {
80*4882a593Smuzhiyun 			host->detect_waiting = 1;
81*4882a593Smuzhiyun 			sh_sdhi_detect(host);
82*4882a593Smuzhiyun 		}
83*4882a593Smuzhiyun 		sh_sdhi_writew(host, SDHI_INFO1_MASK, INFO1M_RESP_END |
84*4882a593Smuzhiyun 			       INFO1M_ACCESS_END | INFO1M_CARD_IN |
85*4882a593Smuzhiyun 			       INFO1M_DATA3_CARD_RE | INFO1M_DATA3_CARD_IN);
86*4882a593Smuzhiyun 		return -EAGAIN;
87*4882a593Smuzhiyun 	}
88*4882a593Smuzhiyun 	/* CARD Removal */
89*4882a593Smuzhiyun 	if (state1 & INFO1_CARD_RE) {
90*4882a593Smuzhiyun 		sh_sdhi_writew(host, SDHI_INFO1, ~INFO1_CARD_RE);
91*4882a593Smuzhiyun 		if (!host->detect_waiting) {
92*4882a593Smuzhiyun 			host->detect_waiting = 1;
93*4882a593Smuzhiyun 			sh_sdhi_detect(host);
94*4882a593Smuzhiyun 		}
95*4882a593Smuzhiyun 		sh_sdhi_writew(host, SDHI_INFO1_MASK, INFO1M_RESP_END |
96*4882a593Smuzhiyun 			       INFO1M_ACCESS_END | INFO1M_CARD_RE |
97*4882a593Smuzhiyun 			       INFO1M_DATA3_CARD_RE | INFO1M_DATA3_CARD_IN);
98*4882a593Smuzhiyun 		sh_sdhi_writew(host, SDHI_SDIO_INFO1_MASK, SDIO_INFO1M_ON);
99*4882a593Smuzhiyun 		sh_sdhi_writew(host, SDHI_SDIO_MODE, SDIO_MODE_OFF);
100*4882a593Smuzhiyun 		return -EAGAIN;
101*4882a593Smuzhiyun 	}
102*4882a593Smuzhiyun 
103*4882a593Smuzhiyun 	if (state2 & INFO2_ALL_ERR) {
104*4882a593Smuzhiyun 		sh_sdhi_writew(host, SDHI_INFO2,
105*4882a593Smuzhiyun 			       (unsigned short)~(INFO2_ALL_ERR));
106*4882a593Smuzhiyun 		sh_sdhi_writew(host, SDHI_INFO2_MASK,
107*4882a593Smuzhiyun 			       INFO2M_ALL_ERR |
108*4882a593Smuzhiyun 			       sh_sdhi_readw(host, SDHI_INFO2_MASK));
109*4882a593Smuzhiyun 		host->sd_error = 1;
110*4882a593Smuzhiyun 		host->wait_int = 1;
111*4882a593Smuzhiyun 		return 0;
112*4882a593Smuzhiyun 	}
113*4882a593Smuzhiyun 	/* Respons End */
114*4882a593Smuzhiyun 	if (state1 & INFO1_RESP_END) {
115*4882a593Smuzhiyun 		sh_sdhi_writew(host, SDHI_INFO1, ~INFO1_RESP_END);
116*4882a593Smuzhiyun 		sh_sdhi_writew(host, SDHI_INFO1_MASK,
117*4882a593Smuzhiyun 			       INFO1M_RESP_END |
118*4882a593Smuzhiyun 			       sh_sdhi_readw(host, SDHI_INFO1_MASK));
119*4882a593Smuzhiyun 		host->wait_int = 1;
120*4882a593Smuzhiyun 		return 0;
121*4882a593Smuzhiyun 	}
122*4882a593Smuzhiyun 	/* SD_BUF Read Enable */
123*4882a593Smuzhiyun 	if (state2 & INFO2_BRE_ENABLE) {
124*4882a593Smuzhiyun 		sh_sdhi_writew(host, SDHI_INFO2, ~INFO2_BRE_ENABLE);
125*4882a593Smuzhiyun 		sh_sdhi_writew(host, SDHI_INFO2_MASK,
126*4882a593Smuzhiyun 			       INFO2M_BRE_ENABLE | INFO2M_BUF_ILL_READ |
127*4882a593Smuzhiyun 			       sh_sdhi_readw(host, SDHI_INFO2_MASK));
128*4882a593Smuzhiyun 		host->wait_int = 1;
129*4882a593Smuzhiyun 		return 0;
130*4882a593Smuzhiyun 	}
131*4882a593Smuzhiyun 	/* SD_BUF Write Enable */
132*4882a593Smuzhiyun 	if (state2 & INFO2_BWE_ENABLE) {
133*4882a593Smuzhiyun 		sh_sdhi_writew(host, SDHI_INFO2, ~INFO2_BWE_ENABLE);
134*4882a593Smuzhiyun 		sh_sdhi_writew(host, SDHI_INFO2_MASK,
135*4882a593Smuzhiyun 			       INFO2_BWE_ENABLE | INFO2M_BUF_ILL_WRITE |
136*4882a593Smuzhiyun 			       sh_sdhi_readw(host, SDHI_INFO2_MASK));
137*4882a593Smuzhiyun 		host->wait_int = 1;
138*4882a593Smuzhiyun 		return 0;
139*4882a593Smuzhiyun 	}
140*4882a593Smuzhiyun 	/* Access End */
141*4882a593Smuzhiyun 	if (state1 & INFO1_ACCESS_END) {
142*4882a593Smuzhiyun 		sh_sdhi_writew(host, SDHI_INFO1, ~INFO1_ACCESS_END);
143*4882a593Smuzhiyun 		sh_sdhi_writew(host, SDHI_INFO1_MASK,
144*4882a593Smuzhiyun 			       INFO1_ACCESS_END |
145*4882a593Smuzhiyun 			       sh_sdhi_readw(host, SDHI_INFO1_MASK));
146*4882a593Smuzhiyun 		host->wait_int = 1;
147*4882a593Smuzhiyun 		return 0;
148*4882a593Smuzhiyun 	}
149*4882a593Smuzhiyun 	return -EAGAIN;
150*4882a593Smuzhiyun }
151*4882a593Smuzhiyun 
sh_sdhi_wait_interrupt_flag(struct sh_sdhi_host * host)152*4882a593Smuzhiyun static int sh_sdhi_wait_interrupt_flag(struct sh_sdhi_host *host)
153*4882a593Smuzhiyun {
154*4882a593Smuzhiyun 	int timeout = 10000000;
155*4882a593Smuzhiyun 
156*4882a593Smuzhiyun 	while (1) {
157*4882a593Smuzhiyun 		timeout--;
158*4882a593Smuzhiyun 		if (timeout < 0) {
159*4882a593Smuzhiyun 			debug(DRIVER_NAME": %s timeout\n", __func__);
160*4882a593Smuzhiyun 			return 0;
161*4882a593Smuzhiyun 		}
162*4882a593Smuzhiyun 
163*4882a593Smuzhiyun 		if (!sh_sdhi_intr(host))
164*4882a593Smuzhiyun 			break;
165*4882a593Smuzhiyun 
166*4882a593Smuzhiyun 		udelay(1);	/* 1 usec */
167*4882a593Smuzhiyun 	}
168*4882a593Smuzhiyun 
169*4882a593Smuzhiyun 	return 1; /* Return value: NOT 0 = complete waiting */
170*4882a593Smuzhiyun }
171*4882a593Smuzhiyun 
sh_sdhi_clock_control(struct sh_sdhi_host * host,unsigned long clk)172*4882a593Smuzhiyun static int sh_sdhi_clock_control(struct sh_sdhi_host *host, unsigned long clk)
173*4882a593Smuzhiyun {
174*4882a593Smuzhiyun 	u32 clkdiv, i, timeout;
175*4882a593Smuzhiyun 
176*4882a593Smuzhiyun 	if (sh_sdhi_readw(host, SDHI_INFO2) & (1 << 14)) {
177*4882a593Smuzhiyun 		printf(DRIVER_NAME": Busy state ! Cannot change the clock\n");
178*4882a593Smuzhiyun 		return -EBUSY;
179*4882a593Smuzhiyun 	}
180*4882a593Smuzhiyun 
181*4882a593Smuzhiyun 	sh_sdhi_writew(host, SDHI_CLK_CTRL,
182*4882a593Smuzhiyun 		       ~CLK_ENABLE & sh_sdhi_readw(host, SDHI_CLK_CTRL));
183*4882a593Smuzhiyun 
184*4882a593Smuzhiyun 	if (clk == 0)
185*4882a593Smuzhiyun 		return -EIO;
186*4882a593Smuzhiyun 
187*4882a593Smuzhiyun 	clkdiv = 0x80;
188*4882a593Smuzhiyun 	i = CONFIG_SH_SDHI_FREQ >> (0x8 + 1);
189*4882a593Smuzhiyun 	for (; clkdiv && clk >= (i << 1); (clkdiv >>= 1))
190*4882a593Smuzhiyun 		i <<= 1;
191*4882a593Smuzhiyun 
192*4882a593Smuzhiyun 	sh_sdhi_writew(host, SDHI_CLK_CTRL, clkdiv);
193*4882a593Smuzhiyun 
194*4882a593Smuzhiyun 	timeout = 100000;
195*4882a593Smuzhiyun 	/* Waiting for SD Bus busy to be cleared */
196*4882a593Smuzhiyun 	while (timeout--) {
197*4882a593Smuzhiyun 		if ((sh_sdhi_readw(host, SDHI_INFO2) & 0x2000))
198*4882a593Smuzhiyun 			break;
199*4882a593Smuzhiyun 	}
200*4882a593Smuzhiyun 
201*4882a593Smuzhiyun 	if (timeout)
202*4882a593Smuzhiyun 		sh_sdhi_writew(host, SDHI_CLK_CTRL,
203*4882a593Smuzhiyun 			       CLK_ENABLE | sh_sdhi_readw(host, SDHI_CLK_CTRL));
204*4882a593Smuzhiyun 	else
205*4882a593Smuzhiyun 		return -EBUSY;
206*4882a593Smuzhiyun 
207*4882a593Smuzhiyun 	return 0;
208*4882a593Smuzhiyun }
209*4882a593Smuzhiyun 
sh_sdhi_sync_reset(struct sh_sdhi_host * host)210*4882a593Smuzhiyun static int sh_sdhi_sync_reset(struct sh_sdhi_host *host)
211*4882a593Smuzhiyun {
212*4882a593Smuzhiyun 	u32 timeout;
213*4882a593Smuzhiyun 	sh_sdhi_writew(host, SDHI_SOFT_RST, SOFT_RST_ON);
214*4882a593Smuzhiyun 	sh_sdhi_writew(host, SDHI_SOFT_RST, SOFT_RST_OFF);
215*4882a593Smuzhiyun 	sh_sdhi_writew(host, SDHI_CLK_CTRL,
216*4882a593Smuzhiyun 		       CLK_ENABLE | sh_sdhi_readw(host, SDHI_CLK_CTRL));
217*4882a593Smuzhiyun 
218*4882a593Smuzhiyun 	timeout = 100000;
219*4882a593Smuzhiyun 	while (timeout--) {
220*4882a593Smuzhiyun 		if (!(sh_sdhi_readw(host, SDHI_INFO2) & INFO2_CBUSY))
221*4882a593Smuzhiyun 			break;
222*4882a593Smuzhiyun 		udelay(100);
223*4882a593Smuzhiyun 	}
224*4882a593Smuzhiyun 
225*4882a593Smuzhiyun 	if (!timeout)
226*4882a593Smuzhiyun 		return -EBUSY;
227*4882a593Smuzhiyun 
228*4882a593Smuzhiyun 	if (host->quirks & SH_SDHI_QUIRK_16BIT_BUF)
229*4882a593Smuzhiyun 		sh_sdhi_writew(host, SDHI_HOST_MODE, 1);
230*4882a593Smuzhiyun 
231*4882a593Smuzhiyun 	return 0;
232*4882a593Smuzhiyun }
233*4882a593Smuzhiyun 
sh_sdhi_error_manage(struct sh_sdhi_host * host)234*4882a593Smuzhiyun static int sh_sdhi_error_manage(struct sh_sdhi_host *host)
235*4882a593Smuzhiyun {
236*4882a593Smuzhiyun 	unsigned short e_state1, e_state2;
237*4882a593Smuzhiyun 	int ret;
238*4882a593Smuzhiyun 
239*4882a593Smuzhiyun 	host->sd_error = 0;
240*4882a593Smuzhiyun 	host->wait_int = 0;
241*4882a593Smuzhiyun 
242*4882a593Smuzhiyun 	e_state1 = sh_sdhi_readw(host, SDHI_ERR_STS1);
243*4882a593Smuzhiyun 	e_state2 = sh_sdhi_readw(host, SDHI_ERR_STS2);
244*4882a593Smuzhiyun 	if (e_state2 & ERR_STS2_SYS_ERROR) {
245*4882a593Smuzhiyun 		if (e_state2 & ERR_STS2_RES_STOP_TIMEOUT)
246*4882a593Smuzhiyun 			ret = -ETIMEDOUT;
247*4882a593Smuzhiyun 		else
248*4882a593Smuzhiyun 			ret = -EILSEQ;
249*4882a593Smuzhiyun 		debug("%s: ERR_STS2 = %04x\n",
250*4882a593Smuzhiyun 		      DRIVER_NAME, sh_sdhi_readw(host, SDHI_ERR_STS2));
251*4882a593Smuzhiyun 		sh_sdhi_sync_reset(host);
252*4882a593Smuzhiyun 
253*4882a593Smuzhiyun 		sh_sdhi_writew(host, SDHI_INFO1_MASK,
254*4882a593Smuzhiyun 			       INFO1M_DATA3_CARD_RE | INFO1M_DATA3_CARD_IN);
255*4882a593Smuzhiyun 		return ret;
256*4882a593Smuzhiyun 	}
257*4882a593Smuzhiyun 	if (e_state1 & ERR_STS1_CRC_ERROR || e_state1 & ERR_STS1_CMD_ERROR)
258*4882a593Smuzhiyun 		ret = -EILSEQ;
259*4882a593Smuzhiyun 	else
260*4882a593Smuzhiyun 		ret = -ETIMEDOUT;
261*4882a593Smuzhiyun 
262*4882a593Smuzhiyun 	debug("%s: ERR_STS1 = %04x\n",
263*4882a593Smuzhiyun 	      DRIVER_NAME, sh_sdhi_readw(host, SDHI_ERR_STS1));
264*4882a593Smuzhiyun 	sh_sdhi_sync_reset(host);
265*4882a593Smuzhiyun 	sh_sdhi_writew(host, SDHI_INFO1_MASK,
266*4882a593Smuzhiyun 		       INFO1M_DATA3_CARD_RE | INFO1M_DATA3_CARD_IN);
267*4882a593Smuzhiyun 	return ret;
268*4882a593Smuzhiyun }
269*4882a593Smuzhiyun 
sh_sdhi_single_read(struct sh_sdhi_host * host,struct mmc_data * data)270*4882a593Smuzhiyun static int sh_sdhi_single_read(struct sh_sdhi_host *host, struct mmc_data *data)
271*4882a593Smuzhiyun {
272*4882a593Smuzhiyun 	long time;
273*4882a593Smuzhiyun 	unsigned short blocksize, i;
274*4882a593Smuzhiyun 	unsigned short *p = (unsigned short *)data->dest;
275*4882a593Smuzhiyun 	u64 *q = (u64 *)data->dest;
276*4882a593Smuzhiyun 
277*4882a593Smuzhiyun 	if ((unsigned long)p & 0x00000001) {
278*4882a593Smuzhiyun 		debug(DRIVER_NAME": %s: The data pointer is unaligned.",
279*4882a593Smuzhiyun 		      __func__);
280*4882a593Smuzhiyun 		return -EIO;
281*4882a593Smuzhiyun 	}
282*4882a593Smuzhiyun 
283*4882a593Smuzhiyun 	host->wait_int = 0;
284*4882a593Smuzhiyun 	sh_sdhi_writew(host, SDHI_INFO2_MASK,
285*4882a593Smuzhiyun 		       ~(INFO2M_BRE_ENABLE | INFO2M_BUF_ILL_READ) &
286*4882a593Smuzhiyun 		       sh_sdhi_readw(host, SDHI_INFO2_MASK));
287*4882a593Smuzhiyun 	sh_sdhi_writew(host, SDHI_INFO1_MASK,
288*4882a593Smuzhiyun 		       ~INFO1M_ACCESS_END &
289*4882a593Smuzhiyun 		       sh_sdhi_readw(host, SDHI_INFO1_MASK));
290*4882a593Smuzhiyun 	time = sh_sdhi_wait_interrupt_flag(host);
291*4882a593Smuzhiyun 	if (time == 0 || host->sd_error != 0)
292*4882a593Smuzhiyun 		return sh_sdhi_error_manage(host);
293*4882a593Smuzhiyun 
294*4882a593Smuzhiyun 	host->wait_int = 0;
295*4882a593Smuzhiyun 	blocksize = sh_sdhi_readw(host, SDHI_SIZE);
296*4882a593Smuzhiyun 	if (host->quirks & SH_SDHI_QUIRK_64BIT_BUF)
297*4882a593Smuzhiyun 		for (i = 0; i < blocksize / 8; i++)
298*4882a593Smuzhiyun 			*q++ = sh_sdhi_readq(host, SDHI_BUF0);
299*4882a593Smuzhiyun 	else
300*4882a593Smuzhiyun 		for (i = 0; i < blocksize / 2; i++)
301*4882a593Smuzhiyun 			*p++ = sh_sdhi_readw(host, SDHI_BUF0);
302*4882a593Smuzhiyun 
303*4882a593Smuzhiyun 	time = sh_sdhi_wait_interrupt_flag(host);
304*4882a593Smuzhiyun 	if (time == 0 || host->sd_error != 0)
305*4882a593Smuzhiyun 		return sh_sdhi_error_manage(host);
306*4882a593Smuzhiyun 
307*4882a593Smuzhiyun 	host->wait_int = 0;
308*4882a593Smuzhiyun 	return 0;
309*4882a593Smuzhiyun }
310*4882a593Smuzhiyun 
sh_sdhi_multi_read(struct sh_sdhi_host * host,struct mmc_data * data)311*4882a593Smuzhiyun static int sh_sdhi_multi_read(struct sh_sdhi_host *host, struct mmc_data *data)
312*4882a593Smuzhiyun {
313*4882a593Smuzhiyun 	long time;
314*4882a593Smuzhiyun 	unsigned short blocksize, i, sec;
315*4882a593Smuzhiyun 	unsigned short *p = (unsigned short *)data->dest;
316*4882a593Smuzhiyun 	u64 *q = (u64 *)data->dest;
317*4882a593Smuzhiyun 
318*4882a593Smuzhiyun 	if ((unsigned long)p & 0x00000001) {
319*4882a593Smuzhiyun 		debug(DRIVER_NAME": %s: The data pointer is unaligned.",
320*4882a593Smuzhiyun 		      __func__);
321*4882a593Smuzhiyun 		return -EIO;
322*4882a593Smuzhiyun 	}
323*4882a593Smuzhiyun 
324*4882a593Smuzhiyun 	debug("%s: blocks = %d, blocksize = %d\n",
325*4882a593Smuzhiyun 	      __func__, data->blocks, data->blocksize);
326*4882a593Smuzhiyun 
327*4882a593Smuzhiyun 	host->wait_int = 0;
328*4882a593Smuzhiyun 	for (sec = 0; sec < data->blocks; sec++) {
329*4882a593Smuzhiyun 		sh_sdhi_writew(host, SDHI_INFO2_MASK,
330*4882a593Smuzhiyun 			       ~(INFO2M_BRE_ENABLE | INFO2M_BUF_ILL_READ) &
331*4882a593Smuzhiyun 			       sh_sdhi_readw(host, SDHI_INFO2_MASK));
332*4882a593Smuzhiyun 
333*4882a593Smuzhiyun 		time = sh_sdhi_wait_interrupt_flag(host);
334*4882a593Smuzhiyun 		if (time == 0 || host->sd_error != 0)
335*4882a593Smuzhiyun 			return sh_sdhi_error_manage(host);
336*4882a593Smuzhiyun 
337*4882a593Smuzhiyun 		host->wait_int = 0;
338*4882a593Smuzhiyun 		blocksize = sh_sdhi_readw(host, SDHI_SIZE);
339*4882a593Smuzhiyun 		if (host->quirks & SH_SDHI_QUIRK_64BIT_BUF)
340*4882a593Smuzhiyun 			for (i = 0; i < blocksize / 8; i++)
341*4882a593Smuzhiyun 				*q++ = sh_sdhi_readq(host, SDHI_BUF0);
342*4882a593Smuzhiyun 		else
343*4882a593Smuzhiyun 			for (i = 0; i < blocksize / 2; i++)
344*4882a593Smuzhiyun 				*p++ = sh_sdhi_readw(host, SDHI_BUF0);
345*4882a593Smuzhiyun 	}
346*4882a593Smuzhiyun 
347*4882a593Smuzhiyun 	return 0;
348*4882a593Smuzhiyun }
349*4882a593Smuzhiyun 
sh_sdhi_single_write(struct sh_sdhi_host * host,struct mmc_data * data)350*4882a593Smuzhiyun static int sh_sdhi_single_write(struct sh_sdhi_host *host,
351*4882a593Smuzhiyun 		struct mmc_data *data)
352*4882a593Smuzhiyun {
353*4882a593Smuzhiyun 	long time;
354*4882a593Smuzhiyun 	unsigned short blocksize, i;
355*4882a593Smuzhiyun 	const unsigned short *p = (const unsigned short *)data->src;
356*4882a593Smuzhiyun 	const u64 *q = (const u64 *)data->src;
357*4882a593Smuzhiyun 
358*4882a593Smuzhiyun 	if ((unsigned long)p & 0x00000001) {
359*4882a593Smuzhiyun 		debug(DRIVER_NAME": %s: The data pointer is unaligned.",
360*4882a593Smuzhiyun 		      __func__);
361*4882a593Smuzhiyun 		return -EIO;
362*4882a593Smuzhiyun 	}
363*4882a593Smuzhiyun 
364*4882a593Smuzhiyun 	debug("%s: blocks = %d, blocksize = %d\n",
365*4882a593Smuzhiyun 	      __func__, data->blocks, data->blocksize);
366*4882a593Smuzhiyun 
367*4882a593Smuzhiyun 	host->wait_int = 0;
368*4882a593Smuzhiyun 	sh_sdhi_writew(host, SDHI_INFO2_MASK,
369*4882a593Smuzhiyun 		       ~(INFO2M_BWE_ENABLE | INFO2M_BUF_ILL_WRITE) &
370*4882a593Smuzhiyun 		       sh_sdhi_readw(host, SDHI_INFO2_MASK));
371*4882a593Smuzhiyun 	sh_sdhi_writew(host, SDHI_INFO1_MASK,
372*4882a593Smuzhiyun 		       ~INFO1M_ACCESS_END &
373*4882a593Smuzhiyun 		       sh_sdhi_readw(host, SDHI_INFO1_MASK));
374*4882a593Smuzhiyun 
375*4882a593Smuzhiyun 	time = sh_sdhi_wait_interrupt_flag(host);
376*4882a593Smuzhiyun 	if (time == 0 || host->sd_error != 0)
377*4882a593Smuzhiyun 		return sh_sdhi_error_manage(host);
378*4882a593Smuzhiyun 
379*4882a593Smuzhiyun 	host->wait_int = 0;
380*4882a593Smuzhiyun 	blocksize = sh_sdhi_readw(host, SDHI_SIZE);
381*4882a593Smuzhiyun 	if (host->quirks & SH_SDHI_QUIRK_64BIT_BUF)
382*4882a593Smuzhiyun 		for (i = 0; i < blocksize / 8; i++)
383*4882a593Smuzhiyun 			sh_sdhi_writeq(host, SDHI_BUF0, *q++);
384*4882a593Smuzhiyun 	else
385*4882a593Smuzhiyun 		for (i = 0; i < blocksize / 2; i++)
386*4882a593Smuzhiyun 			sh_sdhi_writew(host, SDHI_BUF0, *p++);
387*4882a593Smuzhiyun 
388*4882a593Smuzhiyun 	time = sh_sdhi_wait_interrupt_flag(host);
389*4882a593Smuzhiyun 	if (time == 0 || host->sd_error != 0)
390*4882a593Smuzhiyun 		return sh_sdhi_error_manage(host);
391*4882a593Smuzhiyun 
392*4882a593Smuzhiyun 	host->wait_int = 0;
393*4882a593Smuzhiyun 	return 0;
394*4882a593Smuzhiyun }
395*4882a593Smuzhiyun 
sh_sdhi_multi_write(struct sh_sdhi_host * host,struct mmc_data * data)396*4882a593Smuzhiyun static int sh_sdhi_multi_write(struct sh_sdhi_host *host, struct mmc_data *data)
397*4882a593Smuzhiyun {
398*4882a593Smuzhiyun 	long time;
399*4882a593Smuzhiyun 	unsigned short i, sec, blocksize;
400*4882a593Smuzhiyun 	const unsigned short *p = (const unsigned short *)data->src;
401*4882a593Smuzhiyun 	const u64 *q = (const u64 *)data->src;
402*4882a593Smuzhiyun 
403*4882a593Smuzhiyun 	debug("%s: blocks = %d, blocksize = %d\n",
404*4882a593Smuzhiyun 	      __func__, data->blocks, data->blocksize);
405*4882a593Smuzhiyun 
406*4882a593Smuzhiyun 	host->wait_int = 0;
407*4882a593Smuzhiyun 	for (sec = 0; sec < data->blocks; sec++) {
408*4882a593Smuzhiyun 		sh_sdhi_writew(host, SDHI_INFO2_MASK,
409*4882a593Smuzhiyun 			       ~(INFO2M_BWE_ENABLE | INFO2M_BUF_ILL_WRITE) &
410*4882a593Smuzhiyun 			       sh_sdhi_readw(host, SDHI_INFO2_MASK));
411*4882a593Smuzhiyun 
412*4882a593Smuzhiyun 		time = sh_sdhi_wait_interrupt_flag(host);
413*4882a593Smuzhiyun 		if (time == 0 || host->sd_error != 0)
414*4882a593Smuzhiyun 			return sh_sdhi_error_manage(host);
415*4882a593Smuzhiyun 
416*4882a593Smuzhiyun 		host->wait_int = 0;
417*4882a593Smuzhiyun 		blocksize = sh_sdhi_readw(host, SDHI_SIZE);
418*4882a593Smuzhiyun 		if (host->quirks & SH_SDHI_QUIRK_64BIT_BUF)
419*4882a593Smuzhiyun 			for (i = 0; i < blocksize / 8; i++)
420*4882a593Smuzhiyun 				sh_sdhi_writeq(host, SDHI_BUF0, *q++);
421*4882a593Smuzhiyun 		else
422*4882a593Smuzhiyun 			for (i = 0; i < blocksize / 2; i++)
423*4882a593Smuzhiyun 				sh_sdhi_writew(host, SDHI_BUF0, *p++);
424*4882a593Smuzhiyun 	}
425*4882a593Smuzhiyun 
426*4882a593Smuzhiyun 	return 0;
427*4882a593Smuzhiyun }
428*4882a593Smuzhiyun 
sh_sdhi_get_response(struct sh_sdhi_host * host,struct mmc_cmd * cmd)429*4882a593Smuzhiyun static void sh_sdhi_get_response(struct sh_sdhi_host *host, struct mmc_cmd *cmd)
430*4882a593Smuzhiyun {
431*4882a593Smuzhiyun 	unsigned short i, j, cnt = 1;
432*4882a593Smuzhiyun 	unsigned short resp[8];
433*4882a593Smuzhiyun 
434*4882a593Smuzhiyun 	if (cmd->resp_type & MMC_RSP_136) {
435*4882a593Smuzhiyun 		cnt = 4;
436*4882a593Smuzhiyun 		resp[0] = sh_sdhi_readw(host, SDHI_RSP00);
437*4882a593Smuzhiyun 		resp[1] = sh_sdhi_readw(host, SDHI_RSP01);
438*4882a593Smuzhiyun 		resp[2] = sh_sdhi_readw(host, SDHI_RSP02);
439*4882a593Smuzhiyun 		resp[3] = sh_sdhi_readw(host, SDHI_RSP03);
440*4882a593Smuzhiyun 		resp[4] = sh_sdhi_readw(host, SDHI_RSP04);
441*4882a593Smuzhiyun 		resp[5] = sh_sdhi_readw(host, SDHI_RSP05);
442*4882a593Smuzhiyun 		resp[6] = sh_sdhi_readw(host, SDHI_RSP06);
443*4882a593Smuzhiyun 		resp[7] = sh_sdhi_readw(host, SDHI_RSP07);
444*4882a593Smuzhiyun 
445*4882a593Smuzhiyun 		/* SDHI REGISTER SPECIFICATION */
446*4882a593Smuzhiyun 		for (i = 7, j = 6; i > 0; i--) {
447*4882a593Smuzhiyun 			resp[i] = (resp[i] << 8) & 0xff00;
448*4882a593Smuzhiyun 			resp[i] |= (resp[j--] >> 8) & 0x00ff;
449*4882a593Smuzhiyun 		}
450*4882a593Smuzhiyun 		resp[0] = (resp[0] << 8) & 0xff00;
451*4882a593Smuzhiyun 	} else {
452*4882a593Smuzhiyun 		resp[0] = sh_sdhi_readw(host, SDHI_RSP00);
453*4882a593Smuzhiyun 		resp[1] = sh_sdhi_readw(host, SDHI_RSP01);
454*4882a593Smuzhiyun 	}
455*4882a593Smuzhiyun 
456*4882a593Smuzhiyun #if defined(__BIG_ENDIAN_BITFIELD)
457*4882a593Smuzhiyun 	if (cnt == 4) {
458*4882a593Smuzhiyun 		cmd->response[0] = (resp[6] << 16) | resp[7];
459*4882a593Smuzhiyun 		cmd->response[1] = (resp[4] << 16) | resp[5];
460*4882a593Smuzhiyun 		cmd->response[2] = (resp[2] << 16) | resp[3];
461*4882a593Smuzhiyun 		cmd->response[3] = (resp[0] << 16) | resp[1];
462*4882a593Smuzhiyun 	} else {
463*4882a593Smuzhiyun 		cmd->response[0] = (resp[0] << 16) | resp[1];
464*4882a593Smuzhiyun 	}
465*4882a593Smuzhiyun #else
466*4882a593Smuzhiyun 	if (cnt == 4) {
467*4882a593Smuzhiyun 		cmd->response[0] = (resp[7] << 16) | resp[6];
468*4882a593Smuzhiyun 		cmd->response[1] = (resp[5] << 16) | resp[4];
469*4882a593Smuzhiyun 		cmd->response[2] = (resp[3] << 16) | resp[2];
470*4882a593Smuzhiyun 		cmd->response[3] = (resp[1] << 16) | resp[0];
471*4882a593Smuzhiyun 	} else {
472*4882a593Smuzhiyun 		cmd->response[0] = (resp[1] << 16) | resp[0];
473*4882a593Smuzhiyun 	}
474*4882a593Smuzhiyun #endif /* __BIG_ENDIAN_BITFIELD */
475*4882a593Smuzhiyun }
476*4882a593Smuzhiyun 
sh_sdhi_set_cmd(struct sh_sdhi_host * host,struct mmc_data * data,unsigned short opc)477*4882a593Smuzhiyun static unsigned short sh_sdhi_set_cmd(struct sh_sdhi_host *host,
478*4882a593Smuzhiyun 			struct mmc_data *data, unsigned short opc)
479*4882a593Smuzhiyun {
480*4882a593Smuzhiyun 	if (host->app_cmd) {
481*4882a593Smuzhiyun 		if (!data)
482*4882a593Smuzhiyun 			host->app_cmd = 0;
483*4882a593Smuzhiyun 		return opc | BIT(6);
484*4882a593Smuzhiyun 	}
485*4882a593Smuzhiyun 
486*4882a593Smuzhiyun 	switch (opc) {
487*4882a593Smuzhiyun 	case MMC_CMD_SWITCH:
488*4882a593Smuzhiyun 		return opc | (data ? 0x1c00 : 0x40);
489*4882a593Smuzhiyun 	case MMC_CMD_SEND_EXT_CSD:
490*4882a593Smuzhiyun 		return opc | (data ? 0x1c00 : 0);
491*4882a593Smuzhiyun 	case MMC_CMD_SEND_OP_COND:
492*4882a593Smuzhiyun 		return opc | 0x0700;
493*4882a593Smuzhiyun 	case MMC_CMD_APP_CMD:
494*4882a593Smuzhiyun 		host->app_cmd = 1;
495*4882a593Smuzhiyun 	default:
496*4882a593Smuzhiyun 		return opc;
497*4882a593Smuzhiyun 	}
498*4882a593Smuzhiyun }
499*4882a593Smuzhiyun 
sh_sdhi_data_trans(struct sh_sdhi_host * host,struct mmc_data * data,unsigned short opc)500*4882a593Smuzhiyun static unsigned short sh_sdhi_data_trans(struct sh_sdhi_host *host,
501*4882a593Smuzhiyun 			struct mmc_data *data, unsigned short opc)
502*4882a593Smuzhiyun {
503*4882a593Smuzhiyun 	if (host->app_cmd) {
504*4882a593Smuzhiyun 		host->app_cmd = 0;
505*4882a593Smuzhiyun 		switch (opc) {
506*4882a593Smuzhiyun 		case SD_CMD_APP_SEND_SCR:
507*4882a593Smuzhiyun 		case SD_CMD_APP_SD_STATUS:
508*4882a593Smuzhiyun 			return sh_sdhi_single_read(host, data);
509*4882a593Smuzhiyun 		default:
510*4882a593Smuzhiyun 			printf(DRIVER_NAME": SD: NOT SUPPORT APP CMD = d'%04d\n",
511*4882a593Smuzhiyun 				opc);
512*4882a593Smuzhiyun 			return -EINVAL;
513*4882a593Smuzhiyun 		}
514*4882a593Smuzhiyun 	} else {
515*4882a593Smuzhiyun 		switch (opc) {
516*4882a593Smuzhiyun 		case MMC_CMD_WRITE_MULTIPLE_BLOCK:
517*4882a593Smuzhiyun 			return sh_sdhi_multi_write(host, data);
518*4882a593Smuzhiyun 		case MMC_CMD_READ_MULTIPLE_BLOCK:
519*4882a593Smuzhiyun 			return sh_sdhi_multi_read(host, data);
520*4882a593Smuzhiyun 		case MMC_CMD_WRITE_SINGLE_BLOCK:
521*4882a593Smuzhiyun 			return sh_sdhi_single_write(host, data);
522*4882a593Smuzhiyun 		case MMC_CMD_READ_SINGLE_BLOCK:
523*4882a593Smuzhiyun 		case MMC_CMD_SWITCH:
524*4882a593Smuzhiyun 		case MMC_CMD_SEND_EXT_CSD:;
525*4882a593Smuzhiyun 			return sh_sdhi_single_read(host, data);
526*4882a593Smuzhiyun 		default:
527*4882a593Smuzhiyun 			printf(DRIVER_NAME": SD: NOT SUPPORT CMD = d'%04d\n", opc);
528*4882a593Smuzhiyun 			return -EINVAL;
529*4882a593Smuzhiyun 		}
530*4882a593Smuzhiyun 	}
531*4882a593Smuzhiyun }
532*4882a593Smuzhiyun 
sh_sdhi_start_cmd(struct sh_sdhi_host * host,struct mmc_data * data,struct mmc_cmd * cmd)533*4882a593Smuzhiyun static int sh_sdhi_start_cmd(struct sh_sdhi_host *host,
534*4882a593Smuzhiyun 			struct mmc_data *data, struct mmc_cmd *cmd)
535*4882a593Smuzhiyun {
536*4882a593Smuzhiyun 	long time;
537*4882a593Smuzhiyun 	unsigned short shcmd, opc = cmd->cmdidx;
538*4882a593Smuzhiyun 	int ret = 0;
539*4882a593Smuzhiyun 	unsigned long timeout;
540*4882a593Smuzhiyun 
541*4882a593Smuzhiyun 	debug("opc = %d, arg = %x, resp_type = %x\n",
542*4882a593Smuzhiyun 	      opc, cmd->cmdarg, cmd->resp_type);
543*4882a593Smuzhiyun 
544*4882a593Smuzhiyun 	if (opc == MMC_CMD_STOP_TRANSMISSION) {
545*4882a593Smuzhiyun 		/* SDHI sends the STOP command automatically by STOP reg */
546*4882a593Smuzhiyun 		sh_sdhi_writew(host, SDHI_INFO1_MASK, ~INFO1M_ACCESS_END &
547*4882a593Smuzhiyun 			       sh_sdhi_readw(host, SDHI_INFO1_MASK));
548*4882a593Smuzhiyun 
549*4882a593Smuzhiyun 		time = sh_sdhi_wait_interrupt_flag(host);
550*4882a593Smuzhiyun 		if (time == 0 || host->sd_error != 0)
551*4882a593Smuzhiyun 			return sh_sdhi_error_manage(host);
552*4882a593Smuzhiyun 
553*4882a593Smuzhiyun 		sh_sdhi_get_response(host, cmd);
554*4882a593Smuzhiyun 		return 0;
555*4882a593Smuzhiyun 	}
556*4882a593Smuzhiyun 
557*4882a593Smuzhiyun 	if (data) {
558*4882a593Smuzhiyun 		if ((opc == MMC_CMD_READ_MULTIPLE_BLOCK) ||
559*4882a593Smuzhiyun 		    opc == MMC_CMD_WRITE_MULTIPLE_BLOCK) {
560*4882a593Smuzhiyun 			sh_sdhi_writew(host, SDHI_STOP, STOP_SEC_ENABLE);
561*4882a593Smuzhiyun 			sh_sdhi_writew(host, SDHI_SECCNT, data->blocks);
562*4882a593Smuzhiyun 		}
563*4882a593Smuzhiyun 		sh_sdhi_writew(host, SDHI_SIZE, data->blocksize);
564*4882a593Smuzhiyun 	}
565*4882a593Smuzhiyun 
566*4882a593Smuzhiyun 	shcmd = sh_sdhi_set_cmd(host, data, opc);
567*4882a593Smuzhiyun 
568*4882a593Smuzhiyun 	/*
569*4882a593Smuzhiyun 	 *  U-Boot cannot use interrupt.
570*4882a593Smuzhiyun 	 *  So this flag may not be clear by timing
571*4882a593Smuzhiyun 	 */
572*4882a593Smuzhiyun 	sh_sdhi_writew(host, SDHI_INFO1, ~INFO1_RESP_END);
573*4882a593Smuzhiyun 
574*4882a593Smuzhiyun 	sh_sdhi_writew(host, SDHI_INFO1_MASK,
575*4882a593Smuzhiyun 		       INFO1M_RESP_END | sh_sdhi_readw(host, SDHI_INFO1_MASK));
576*4882a593Smuzhiyun 	sh_sdhi_writew(host, SDHI_ARG0,
577*4882a593Smuzhiyun 		       (unsigned short)(cmd->cmdarg & ARG0_MASK));
578*4882a593Smuzhiyun 	sh_sdhi_writew(host, SDHI_ARG1,
579*4882a593Smuzhiyun 		       (unsigned short)((cmd->cmdarg >> 16) & ARG1_MASK));
580*4882a593Smuzhiyun 
581*4882a593Smuzhiyun 	timeout = 100000;
582*4882a593Smuzhiyun 	/* Waiting for SD Bus busy to be cleared */
583*4882a593Smuzhiyun 	while (timeout--) {
584*4882a593Smuzhiyun 		if ((sh_sdhi_readw(host, SDHI_INFO2) & 0x2000))
585*4882a593Smuzhiyun 			break;
586*4882a593Smuzhiyun 	}
587*4882a593Smuzhiyun 
588*4882a593Smuzhiyun 	host->wait_int = 0;
589*4882a593Smuzhiyun 	sh_sdhi_writew(host, SDHI_INFO1_MASK,
590*4882a593Smuzhiyun 		       ~INFO1M_RESP_END & sh_sdhi_readw(host, SDHI_INFO1_MASK));
591*4882a593Smuzhiyun 	sh_sdhi_writew(host, SDHI_INFO2_MASK,
592*4882a593Smuzhiyun 		       ~(INFO2M_CMD_ERROR | INFO2M_CRC_ERROR |
593*4882a593Smuzhiyun 		       INFO2M_END_ERROR | INFO2M_TIMEOUT |
594*4882a593Smuzhiyun 		       INFO2M_RESP_TIMEOUT | INFO2M_ILA) &
595*4882a593Smuzhiyun 		       sh_sdhi_readw(host, SDHI_INFO2_MASK));
596*4882a593Smuzhiyun 
597*4882a593Smuzhiyun 	sh_sdhi_writew(host, SDHI_CMD, (unsigned short)(shcmd & CMD_MASK));
598*4882a593Smuzhiyun 	time = sh_sdhi_wait_interrupt_flag(host);
599*4882a593Smuzhiyun 	if (!time) {
600*4882a593Smuzhiyun 		host->app_cmd = 0;
601*4882a593Smuzhiyun 		return sh_sdhi_error_manage(host);
602*4882a593Smuzhiyun 	}
603*4882a593Smuzhiyun 
604*4882a593Smuzhiyun 	if (host->sd_error) {
605*4882a593Smuzhiyun 		switch (cmd->cmdidx) {
606*4882a593Smuzhiyun 		case MMC_CMD_ALL_SEND_CID:
607*4882a593Smuzhiyun 		case MMC_CMD_SELECT_CARD:
608*4882a593Smuzhiyun 		case SD_CMD_SEND_IF_COND:
609*4882a593Smuzhiyun 		case MMC_CMD_APP_CMD:
610*4882a593Smuzhiyun 			ret = -ETIMEDOUT;
611*4882a593Smuzhiyun 			break;
612*4882a593Smuzhiyun 		default:
613*4882a593Smuzhiyun 			debug(DRIVER_NAME": Cmd(d'%d) err\n", opc);
614*4882a593Smuzhiyun 			debug(DRIVER_NAME": cmdidx = %d\n", cmd->cmdidx);
615*4882a593Smuzhiyun 			ret = sh_sdhi_error_manage(host);
616*4882a593Smuzhiyun 			break;
617*4882a593Smuzhiyun 		}
618*4882a593Smuzhiyun 		host->sd_error = 0;
619*4882a593Smuzhiyun 		host->wait_int = 0;
620*4882a593Smuzhiyun 		host->app_cmd = 0;
621*4882a593Smuzhiyun 		return ret;
622*4882a593Smuzhiyun 	}
623*4882a593Smuzhiyun 
624*4882a593Smuzhiyun 	if (sh_sdhi_readw(host, SDHI_INFO1) & INFO1_RESP_END) {
625*4882a593Smuzhiyun 		host->app_cmd = 0;
626*4882a593Smuzhiyun 		return -EINVAL;
627*4882a593Smuzhiyun 	}
628*4882a593Smuzhiyun 
629*4882a593Smuzhiyun 	if (host->wait_int) {
630*4882a593Smuzhiyun 		sh_sdhi_get_response(host, cmd);
631*4882a593Smuzhiyun 		host->wait_int = 0;
632*4882a593Smuzhiyun 	}
633*4882a593Smuzhiyun 
634*4882a593Smuzhiyun 	if (data)
635*4882a593Smuzhiyun 		ret = sh_sdhi_data_trans(host, data, opc);
636*4882a593Smuzhiyun 
637*4882a593Smuzhiyun 	debug("ret = %d, resp = %08x, %08x, %08x, %08x\n",
638*4882a593Smuzhiyun 	      ret, cmd->response[0], cmd->response[1],
639*4882a593Smuzhiyun 	      cmd->response[2], cmd->response[3]);
640*4882a593Smuzhiyun 	return ret;
641*4882a593Smuzhiyun }
642*4882a593Smuzhiyun 
sh_sdhi_send_cmd_common(struct sh_sdhi_host * host,struct mmc_cmd * cmd,struct mmc_data * data)643*4882a593Smuzhiyun static int sh_sdhi_send_cmd_common(struct sh_sdhi_host *host,
644*4882a593Smuzhiyun 				   struct mmc_cmd *cmd, struct mmc_data *data)
645*4882a593Smuzhiyun {
646*4882a593Smuzhiyun 	host->sd_error = 0;
647*4882a593Smuzhiyun 
648*4882a593Smuzhiyun 	return sh_sdhi_start_cmd(host, data, cmd);
649*4882a593Smuzhiyun }
650*4882a593Smuzhiyun 
sh_sdhi_set_ios_common(struct sh_sdhi_host * host,struct mmc * mmc)651*4882a593Smuzhiyun static int sh_sdhi_set_ios_common(struct sh_sdhi_host *host, struct mmc *mmc)
652*4882a593Smuzhiyun {
653*4882a593Smuzhiyun 	int ret;
654*4882a593Smuzhiyun 
655*4882a593Smuzhiyun 	ret = sh_sdhi_clock_control(host, mmc->clock);
656*4882a593Smuzhiyun 	if (ret)
657*4882a593Smuzhiyun 		return -EINVAL;
658*4882a593Smuzhiyun 
659*4882a593Smuzhiyun 	if (mmc->bus_width == 8)
660*4882a593Smuzhiyun 		sh_sdhi_writew(host, SDHI_OPTION,
661*4882a593Smuzhiyun 			       OPT_BUS_WIDTH_8 | (~OPT_BUS_WIDTH_M &
662*4882a593Smuzhiyun 			       sh_sdhi_readw(host, SDHI_OPTION)));
663*4882a593Smuzhiyun 	else if (mmc->bus_width == 4)
664*4882a593Smuzhiyun 		sh_sdhi_writew(host, SDHI_OPTION,
665*4882a593Smuzhiyun 			       OPT_BUS_WIDTH_4 | (~OPT_BUS_WIDTH_M &
666*4882a593Smuzhiyun 			       sh_sdhi_readw(host, SDHI_OPTION)));
667*4882a593Smuzhiyun 	else
668*4882a593Smuzhiyun 		sh_sdhi_writew(host, SDHI_OPTION,
669*4882a593Smuzhiyun 			       OPT_BUS_WIDTH_1 | (~OPT_BUS_WIDTH_M &
670*4882a593Smuzhiyun 			       sh_sdhi_readw(host, SDHI_OPTION)));
671*4882a593Smuzhiyun 
672*4882a593Smuzhiyun 	debug("clock = %d, buswidth = %d\n", mmc->clock, mmc->bus_width);
673*4882a593Smuzhiyun 
674*4882a593Smuzhiyun 	return 0;
675*4882a593Smuzhiyun }
676*4882a593Smuzhiyun 
sh_sdhi_initialize_common(struct sh_sdhi_host * host)677*4882a593Smuzhiyun static int sh_sdhi_initialize_common(struct sh_sdhi_host *host)
678*4882a593Smuzhiyun {
679*4882a593Smuzhiyun 	int ret = sh_sdhi_sync_reset(host);
680*4882a593Smuzhiyun 
681*4882a593Smuzhiyun 	sh_sdhi_writew(host, SDHI_PORTSEL, USE_1PORT);
682*4882a593Smuzhiyun 
683*4882a593Smuzhiyun #if defined(__BIG_ENDIAN_BITFIELD)
684*4882a593Smuzhiyun 	sh_sdhi_writew(host, SDHI_EXT_SWAP, SET_SWAP);
685*4882a593Smuzhiyun #endif
686*4882a593Smuzhiyun 
687*4882a593Smuzhiyun 	sh_sdhi_writew(host, SDHI_INFO1_MASK, INFO1M_RESP_END |
688*4882a593Smuzhiyun 		       INFO1M_ACCESS_END | INFO1M_CARD_RE |
689*4882a593Smuzhiyun 		       INFO1M_DATA3_CARD_RE | INFO1M_DATA3_CARD_IN);
690*4882a593Smuzhiyun 
691*4882a593Smuzhiyun 	return ret;
692*4882a593Smuzhiyun }
693*4882a593Smuzhiyun 
694*4882a593Smuzhiyun #ifndef CONFIG_DM_MMC
mmc_priv(struct mmc * mmc)695*4882a593Smuzhiyun static void *mmc_priv(struct mmc *mmc)
696*4882a593Smuzhiyun {
697*4882a593Smuzhiyun 	return (void *)mmc->priv;
698*4882a593Smuzhiyun }
699*4882a593Smuzhiyun 
sh_sdhi_send_cmd(struct mmc * mmc,struct mmc_cmd * cmd,struct mmc_data * data)700*4882a593Smuzhiyun static int sh_sdhi_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd,
701*4882a593Smuzhiyun 			    struct mmc_data *data)
702*4882a593Smuzhiyun {
703*4882a593Smuzhiyun 	struct sh_sdhi_host *host = mmc_priv(mmc);
704*4882a593Smuzhiyun 
705*4882a593Smuzhiyun 	return sh_sdhi_send_cmd_common(host, cmd, data);
706*4882a593Smuzhiyun }
707*4882a593Smuzhiyun 
sh_sdhi_set_ios(struct mmc * mmc)708*4882a593Smuzhiyun static int sh_sdhi_set_ios(struct mmc *mmc)
709*4882a593Smuzhiyun {
710*4882a593Smuzhiyun 	struct sh_sdhi_host *host = mmc_priv(mmc);
711*4882a593Smuzhiyun 
712*4882a593Smuzhiyun 	return sh_sdhi_set_ios_common(host, mmc);
713*4882a593Smuzhiyun }
714*4882a593Smuzhiyun 
sh_sdhi_initialize(struct mmc * mmc)715*4882a593Smuzhiyun static int sh_sdhi_initialize(struct mmc *mmc)
716*4882a593Smuzhiyun {
717*4882a593Smuzhiyun 	struct sh_sdhi_host *host = mmc_priv(mmc);
718*4882a593Smuzhiyun 
719*4882a593Smuzhiyun 	return sh_sdhi_initialize_common(host);
720*4882a593Smuzhiyun }
721*4882a593Smuzhiyun 
722*4882a593Smuzhiyun static const struct mmc_ops sh_sdhi_ops = {
723*4882a593Smuzhiyun 	.send_cmd       = sh_sdhi_send_cmd,
724*4882a593Smuzhiyun 	.set_ios        = sh_sdhi_set_ios,
725*4882a593Smuzhiyun 	.init           = sh_sdhi_initialize,
726*4882a593Smuzhiyun };
727*4882a593Smuzhiyun 
728*4882a593Smuzhiyun #ifdef CONFIG_RCAR_GEN3
729*4882a593Smuzhiyun static struct mmc_config sh_sdhi_cfg = {
730*4882a593Smuzhiyun 	.name           = DRIVER_NAME,
731*4882a593Smuzhiyun 	.ops            = &sh_sdhi_ops,
732*4882a593Smuzhiyun 	.f_min          = CLKDEV_INIT,
733*4882a593Smuzhiyun 	.f_max          = CLKDEV_HS_DATA,
734*4882a593Smuzhiyun 	.voltages       = MMC_VDD_165_195 | MMC_VDD_32_33 | MMC_VDD_33_34,
735*4882a593Smuzhiyun 	.host_caps      = MMC_MODE_4BIT | MMC_MODE_8BIT | MMC_MODE_HS |
736*4882a593Smuzhiyun 			  MMC_MODE_HS_52MHz,
737*4882a593Smuzhiyun 	.part_type      = PART_TYPE_DOS,
738*4882a593Smuzhiyun 	.b_max          = CONFIG_SYS_MMC_MAX_BLK_COUNT,
739*4882a593Smuzhiyun };
740*4882a593Smuzhiyun #else
741*4882a593Smuzhiyun static struct mmc_config sh_sdhi_cfg = {
742*4882a593Smuzhiyun 	.name           = DRIVER_NAME,
743*4882a593Smuzhiyun 	.ops            = &sh_sdhi_ops,
744*4882a593Smuzhiyun 	.f_min          = CLKDEV_INIT,
745*4882a593Smuzhiyun 	.f_max          = CLKDEV_HS_DATA,
746*4882a593Smuzhiyun 	.voltages       = MMC_VDD_32_33 | MMC_VDD_33_34,
747*4882a593Smuzhiyun 	.host_caps      = MMC_MODE_4BIT | MMC_MODE_HS,
748*4882a593Smuzhiyun 	.part_type      = PART_TYPE_DOS,
749*4882a593Smuzhiyun 	.b_max          = CONFIG_SYS_MMC_MAX_BLK_COUNT,
750*4882a593Smuzhiyun };
751*4882a593Smuzhiyun #endif
752*4882a593Smuzhiyun 
sh_sdhi_init(unsigned long addr,int ch,unsigned long quirks)753*4882a593Smuzhiyun int sh_sdhi_init(unsigned long addr, int ch, unsigned long quirks)
754*4882a593Smuzhiyun {
755*4882a593Smuzhiyun 	int ret = 0;
756*4882a593Smuzhiyun 	struct mmc *mmc;
757*4882a593Smuzhiyun 	struct sh_sdhi_host *host = NULL;
758*4882a593Smuzhiyun 
759*4882a593Smuzhiyun 	if (ch >= CONFIG_SYS_SH_SDHI_NR_CHANNEL)
760*4882a593Smuzhiyun 		return -ENODEV;
761*4882a593Smuzhiyun 
762*4882a593Smuzhiyun 	host = malloc(sizeof(struct sh_sdhi_host));
763*4882a593Smuzhiyun 	if (!host)
764*4882a593Smuzhiyun 		return -ENOMEM;
765*4882a593Smuzhiyun 
766*4882a593Smuzhiyun 	mmc = mmc_create(&sh_sdhi_cfg, host);
767*4882a593Smuzhiyun 	if (!mmc) {
768*4882a593Smuzhiyun 		ret = -1;
769*4882a593Smuzhiyun 		goto error;
770*4882a593Smuzhiyun 	}
771*4882a593Smuzhiyun 
772*4882a593Smuzhiyun 	host->ch = ch;
773*4882a593Smuzhiyun 	host->addr = (void __iomem *)addr;
774*4882a593Smuzhiyun 	host->quirks = quirks;
775*4882a593Smuzhiyun 
776*4882a593Smuzhiyun 	if (host->quirks & SH_SDHI_QUIRK_64BIT_BUF)
777*4882a593Smuzhiyun 		host->bus_shift = 2;
778*4882a593Smuzhiyun 	else if (host->quirks & SH_SDHI_QUIRK_16BIT_BUF)
779*4882a593Smuzhiyun 		host->bus_shift = 1;
780*4882a593Smuzhiyun 
781*4882a593Smuzhiyun 	return ret;
782*4882a593Smuzhiyun error:
783*4882a593Smuzhiyun 	if (host)
784*4882a593Smuzhiyun 		free(host);
785*4882a593Smuzhiyun 	return ret;
786*4882a593Smuzhiyun }
787*4882a593Smuzhiyun 
788*4882a593Smuzhiyun #else
789*4882a593Smuzhiyun 
790*4882a593Smuzhiyun struct sh_sdhi_plat {
791*4882a593Smuzhiyun 	struct mmc_config cfg;
792*4882a593Smuzhiyun 	struct mmc mmc;
793*4882a593Smuzhiyun };
794*4882a593Smuzhiyun 
sh_sdhi_dm_send_cmd(struct udevice * dev,struct mmc_cmd * cmd,struct mmc_data * data)795*4882a593Smuzhiyun int sh_sdhi_dm_send_cmd(struct udevice *dev, struct mmc_cmd *cmd,
796*4882a593Smuzhiyun 			struct mmc_data *data)
797*4882a593Smuzhiyun {
798*4882a593Smuzhiyun 	struct sh_sdhi_host *host = dev_get_priv(dev);
799*4882a593Smuzhiyun 
800*4882a593Smuzhiyun 	return sh_sdhi_send_cmd_common(host, cmd, data);
801*4882a593Smuzhiyun }
802*4882a593Smuzhiyun 
sh_sdhi_dm_set_ios(struct udevice * dev)803*4882a593Smuzhiyun int sh_sdhi_dm_set_ios(struct udevice *dev)
804*4882a593Smuzhiyun {
805*4882a593Smuzhiyun 	struct sh_sdhi_host *host = dev_get_priv(dev);
806*4882a593Smuzhiyun 	struct mmc *mmc = mmc_get_mmc_dev(dev);
807*4882a593Smuzhiyun 
808*4882a593Smuzhiyun 	return sh_sdhi_set_ios_common(host, mmc);
809*4882a593Smuzhiyun }
810*4882a593Smuzhiyun 
811*4882a593Smuzhiyun static const struct dm_mmc_ops sh_sdhi_dm_ops = {
812*4882a593Smuzhiyun 	.send_cmd	= sh_sdhi_dm_send_cmd,
813*4882a593Smuzhiyun 	.set_ios	= sh_sdhi_dm_set_ios,
814*4882a593Smuzhiyun };
815*4882a593Smuzhiyun 
sh_sdhi_dm_bind(struct udevice * dev)816*4882a593Smuzhiyun static int sh_sdhi_dm_bind(struct udevice *dev)
817*4882a593Smuzhiyun {
818*4882a593Smuzhiyun 	struct sh_sdhi_plat *plat = dev_get_platdata(dev);
819*4882a593Smuzhiyun 
820*4882a593Smuzhiyun 	return mmc_bind(dev, &plat->mmc, &plat->cfg);
821*4882a593Smuzhiyun }
822*4882a593Smuzhiyun 
sh_sdhi_dm_probe(struct udevice * dev)823*4882a593Smuzhiyun static int sh_sdhi_dm_probe(struct udevice *dev)
824*4882a593Smuzhiyun {
825*4882a593Smuzhiyun 	struct sh_sdhi_plat *plat = dev_get_platdata(dev);
826*4882a593Smuzhiyun 	struct sh_sdhi_host *host = dev_get_priv(dev);
827*4882a593Smuzhiyun 	struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev);
828*4882a593Smuzhiyun 	struct clk sh_sdhi_clk;
829*4882a593Smuzhiyun 	const u32 quirks = dev_get_driver_data(dev);
830*4882a593Smuzhiyun 	fdt_addr_t base;
831*4882a593Smuzhiyun 	int ret;
832*4882a593Smuzhiyun 
833*4882a593Smuzhiyun 	base = devfdt_get_addr(dev);
834*4882a593Smuzhiyun 	if (base == FDT_ADDR_T_NONE)
835*4882a593Smuzhiyun 		return -EINVAL;
836*4882a593Smuzhiyun 
837*4882a593Smuzhiyun 	host->addr = devm_ioremap(dev, base, SZ_2K);
838*4882a593Smuzhiyun 	if (!host->addr)
839*4882a593Smuzhiyun 		return -ENOMEM;
840*4882a593Smuzhiyun 
841*4882a593Smuzhiyun 	ret = clk_get_by_index(dev, 0, &sh_sdhi_clk);
842*4882a593Smuzhiyun 	if (ret) {
843*4882a593Smuzhiyun 		debug("failed to get clock, ret=%d\n", ret);
844*4882a593Smuzhiyun 		return ret;
845*4882a593Smuzhiyun 	}
846*4882a593Smuzhiyun 
847*4882a593Smuzhiyun 	ret = clk_enable(&sh_sdhi_clk);
848*4882a593Smuzhiyun 	if (ret) {
849*4882a593Smuzhiyun 		debug("failed to enable clock, ret=%d\n", ret);
850*4882a593Smuzhiyun 		return ret;
851*4882a593Smuzhiyun 	}
852*4882a593Smuzhiyun 
853*4882a593Smuzhiyun 	host->quirks = quirks;
854*4882a593Smuzhiyun 
855*4882a593Smuzhiyun 	if (host->quirks & SH_SDHI_QUIRK_64BIT_BUF)
856*4882a593Smuzhiyun 		host->bus_shift = 2;
857*4882a593Smuzhiyun 	else if (host->quirks & SH_SDHI_QUIRK_16BIT_BUF)
858*4882a593Smuzhiyun 		host->bus_shift = 1;
859*4882a593Smuzhiyun 
860*4882a593Smuzhiyun 	plat->cfg.name = dev->name;
861*4882a593Smuzhiyun 	plat->cfg.host_caps = MMC_MODE_HS_52MHz | MMC_MODE_HS;
862*4882a593Smuzhiyun 
863*4882a593Smuzhiyun 	switch (fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev), "bus-width",
864*4882a593Smuzhiyun 			       1)) {
865*4882a593Smuzhiyun 	case 8:
866*4882a593Smuzhiyun 		plat->cfg.host_caps |= MMC_MODE_8BIT;
867*4882a593Smuzhiyun 		break;
868*4882a593Smuzhiyun 	case 4:
869*4882a593Smuzhiyun 		plat->cfg.host_caps |= MMC_MODE_4BIT;
870*4882a593Smuzhiyun 		break;
871*4882a593Smuzhiyun 	case 1:
872*4882a593Smuzhiyun 		break;
873*4882a593Smuzhiyun 	default:
874*4882a593Smuzhiyun 		dev_err(dev, "Invalid \"bus-width\" value\n");
875*4882a593Smuzhiyun 		return -EINVAL;
876*4882a593Smuzhiyun 	}
877*4882a593Smuzhiyun 
878*4882a593Smuzhiyun 	sh_sdhi_initialize_common(host);
879*4882a593Smuzhiyun 
880*4882a593Smuzhiyun 	plat->cfg.voltages = MMC_VDD_165_195 | MMC_VDD_32_33 | MMC_VDD_33_34;
881*4882a593Smuzhiyun 	plat->cfg.f_min = CLKDEV_INIT;
882*4882a593Smuzhiyun 	plat->cfg.f_max = CLKDEV_HS_DATA;
883*4882a593Smuzhiyun 	plat->cfg.b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT;
884*4882a593Smuzhiyun 
885*4882a593Smuzhiyun 	upriv->mmc = &plat->mmc;
886*4882a593Smuzhiyun 
887*4882a593Smuzhiyun 	return 0;
888*4882a593Smuzhiyun }
889*4882a593Smuzhiyun 
890*4882a593Smuzhiyun static const struct udevice_id sh_sdhi_sd_match[] = {
891*4882a593Smuzhiyun 	{ .compatible = "renesas,sdhi-r8a7795", .data = SH_SDHI_QUIRK_64BIT_BUF },
892*4882a593Smuzhiyun 	{ .compatible = "renesas,sdhi-r8a7796", .data = SH_SDHI_QUIRK_64BIT_BUF },
893*4882a593Smuzhiyun 	{ /* sentinel */ }
894*4882a593Smuzhiyun };
895*4882a593Smuzhiyun 
896*4882a593Smuzhiyun U_BOOT_DRIVER(sh_sdhi_mmc) = {
897*4882a593Smuzhiyun 	.name			= "sh-sdhi-mmc",
898*4882a593Smuzhiyun 	.id			= UCLASS_MMC,
899*4882a593Smuzhiyun 	.of_match		= sh_sdhi_sd_match,
900*4882a593Smuzhiyun 	.bind			= sh_sdhi_dm_bind,
901*4882a593Smuzhiyun 	.probe			= sh_sdhi_dm_probe,
902*4882a593Smuzhiyun 	.priv_auto_alloc_size	= sizeof(struct sh_sdhi_host),
903*4882a593Smuzhiyun 	.platdata_auto_alloc_size = sizeof(struct sh_sdhi_plat),
904*4882a593Smuzhiyun 	.ops			= &sh_sdhi_dm_ops,
905*4882a593Smuzhiyun };
906*4882a593Smuzhiyun #endif
907