xref: /openbmc/u-boot/drivers/mmc/sh_mmcif.c (revision 21ea3503)
1afb35666SYoshihiro Shimoda /*
2afb35666SYoshihiro Shimoda  * MMCIF driver.
3afb35666SYoshihiro Shimoda  *
4afb35666SYoshihiro Shimoda  * Copyright (C)  2011 Renesas Solutions Corp.
5afb35666SYoshihiro Shimoda  *
6afb35666SYoshihiro Shimoda  * This program is free software; you can redistribute it and/or modify
7afb35666SYoshihiro Shimoda  * it under the terms of the GNU General Public License as published by
8afb35666SYoshihiro Shimoda  * the Free Software Foundation; either version 2 of the License.
9afb35666SYoshihiro Shimoda  */
10afb35666SYoshihiro Shimoda 
11afb35666SYoshihiro Shimoda #include <config.h>
12afb35666SYoshihiro Shimoda #include <common.h>
13afb35666SYoshihiro Shimoda #include <watchdog.h>
14afb35666SYoshihiro Shimoda #include <command.h>
15afb35666SYoshihiro Shimoda #include <mmc.h>
16afb35666SYoshihiro Shimoda #include <malloc.h>
17afb35666SYoshihiro Shimoda #include <asm/errno.h>
18afb35666SYoshihiro Shimoda #include <asm/io.h>
19afb35666SYoshihiro Shimoda #include "sh_mmcif.h"
20afb35666SYoshihiro Shimoda 
21afb35666SYoshihiro Shimoda #define DRIVER_NAME	"sh_mmcif"
22afb35666SYoshihiro Shimoda 
23afb35666SYoshihiro Shimoda static int sh_mmcif_intr(void *dev_id)
24afb35666SYoshihiro Shimoda {
25afb35666SYoshihiro Shimoda 	struct sh_mmcif_host *host = dev_id;
26afb35666SYoshihiro Shimoda 	u32 state = 0;
27afb35666SYoshihiro Shimoda 
28afb35666SYoshihiro Shimoda 	state = sh_mmcif_read(&host->regs->ce_int);
29afb35666SYoshihiro Shimoda 	state &= sh_mmcif_read(&host->regs->ce_int_mask);
30afb35666SYoshihiro Shimoda 
31afb35666SYoshihiro Shimoda 	if (state & INT_RBSYE) {
32afb35666SYoshihiro Shimoda 		sh_mmcif_write(~(INT_RBSYE | INT_CRSPE), &host->regs->ce_int);
33afb35666SYoshihiro Shimoda 		sh_mmcif_bitclr(MASK_MRBSYE, &host->regs->ce_int_mask);
34afb35666SYoshihiro Shimoda 		goto end;
35afb35666SYoshihiro Shimoda 	} else if (state & INT_CRSPE) {
36afb35666SYoshihiro Shimoda 		sh_mmcif_write(~INT_CRSPE, &host->regs->ce_int);
37afb35666SYoshihiro Shimoda 		sh_mmcif_bitclr(MASK_MCRSPE, &host->regs->ce_int_mask);
38afb35666SYoshihiro Shimoda 		/* one more interrupt (INT_RBSYE) */
39afb35666SYoshihiro Shimoda 		if (sh_mmcif_read(&host->regs->ce_cmd_set) & CMD_SET_RBSY)
40afb35666SYoshihiro Shimoda 			return -EAGAIN;
41afb35666SYoshihiro Shimoda 		goto end;
42afb35666SYoshihiro Shimoda 	} else if (state & INT_BUFREN) {
43afb35666SYoshihiro Shimoda 		sh_mmcif_write(~INT_BUFREN, &host->regs->ce_int);
44afb35666SYoshihiro Shimoda 		sh_mmcif_bitclr(MASK_MBUFREN, &host->regs->ce_int_mask);
45afb35666SYoshihiro Shimoda 		goto end;
46afb35666SYoshihiro Shimoda 	} else if (state & INT_BUFWEN) {
47afb35666SYoshihiro Shimoda 		sh_mmcif_write(~INT_BUFWEN, &host->regs->ce_int);
48afb35666SYoshihiro Shimoda 		sh_mmcif_bitclr(MASK_MBUFWEN, &host->regs->ce_int_mask);
49afb35666SYoshihiro Shimoda 		goto end;
50afb35666SYoshihiro Shimoda 	} else if (state & INT_CMD12DRE) {
51afb35666SYoshihiro Shimoda 		sh_mmcif_write(~(INT_CMD12DRE | INT_CMD12RBE | INT_CMD12CRE |
52afb35666SYoshihiro Shimoda 				  INT_BUFRE), &host->regs->ce_int);
53afb35666SYoshihiro Shimoda 		sh_mmcif_bitclr(MASK_MCMD12DRE, &host->regs->ce_int_mask);
54afb35666SYoshihiro Shimoda 		goto end;
55afb35666SYoshihiro Shimoda 	} else if (state & INT_BUFRE) {
56afb35666SYoshihiro Shimoda 		sh_mmcif_write(~INT_BUFRE, &host->regs->ce_int);
57afb35666SYoshihiro Shimoda 		sh_mmcif_bitclr(MASK_MBUFRE, &host->regs->ce_int_mask);
58afb35666SYoshihiro Shimoda 		goto end;
59afb35666SYoshihiro Shimoda 	} else if (state & INT_DTRANE) {
60afb35666SYoshihiro Shimoda 		sh_mmcif_write(~INT_DTRANE, &host->regs->ce_int);
61afb35666SYoshihiro Shimoda 		sh_mmcif_bitclr(MASK_MDTRANE, &host->regs->ce_int_mask);
62afb35666SYoshihiro Shimoda 		goto end;
63afb35666SYoshihiro Shimoda 	} else if (state & INT_CMD12RBE) {
64afb35666SYoshihiro Shimoda 		sh_mmcif_write(~(INT_CMD12RBE | INT_CMD12CRE),
65afb35666SYoshihiro Shimoda 				&host->regs->ce_int);
66afb35666SYoshihiro Shimoda 		sh_mmcif_bitclr(MASK_MCMD12RBE, &host->regs->ce_int_mask);
67afb35666SYoshihiro Shimoda 		goto end;
68afb35666SYoshihiro Shimoda 	} else if (state & INT_ERR_STS) {
69afb35666SYoshihiro Shimoda 		/* err interrupts */
70afb35666SYoshihiro Shimoda 		sh_mmcif_write(~state, &host->regs->ce_int);
71afb35666SYoshihiro Shimoda 		sh_mmcif_bitclr(state, &host->regs->ce_int_mask);
72afb35666SYoshihiro Shimoda 		goto err;
73afb35666SYoshihiro Shimoda 	} else
74afb35666SYoshihiro Shimoda 		return -EAGAIN;
75afb35666SYoshihiro Shimoda 
76afb35666SYoshihiro Shimoda err:
77afb35666SYoshihiro Shimoda 	host->sd_error = 1;
78afb35666SYoshihiro Shimoda 	debug("%s: int err state = %08x\n", DRIVER_NAME, state);
79afb35666SYoshihiro Shimoda end:
80afb35666SYoshihiro Shimoda 	host->wait_int = 1;
81afb35666SYoshihiro Shimoda 	return 0;
82afb35666SYoshihiro Shimoda }
83afb35666SYoshihiro Shimoda 
84afb35666SYoshihiro Shimoda static int mmcif_wait_interrupt_flag(struct sh_mmcif_host *host)
85afb35666SYoshihiro Shimoda {
86afb35666SYoshihiro Shimoda 	int timeout = 10000000;
87afb35666SYoshihiro Shimoda 
88afb35666SYoshihiro Shimoda 	while (1) {
89afb35666SYoshihiro Shimoda 		timeout--;
90afb35666SYoshihiro Shimoda 		if (timeout < 0) {
91afb35666SYoshihiro Shimoda 			printf("timeout\n");
92afb35666SYoshihiro Shimoda 			return 0;
93afb35666SYoshihiro Shimoda 		}
94afb35666SYoshihiro Shimoda 
95afb35666SYoshihiro Shimoda 		if (!sh_mmcif_intr(host))
96afb35666SYoshihiro Shimoda 			break;
97afb35666SYoshihiro Shimoda 
98afb35666SYoshihiro Shimoda 		udelay(1);	/* 1 usec */
99afb35666SYoshihiro Shimoda 	}
100afb35666SYoshihiro Shimoda 
101afb35666SYoshihiro Shimoda 	return 1;	/* Return value: NOT 0 = complete waiting */
102afb35666SYoshihiro Shimoda }
103afb35666SYoshihiro Shimoda 
104afb35666SYoshihiro Shimoda static void sh_mmcif_clock_control(struct sh_mmcif_host *host, unsigned int clk)
105afb35666SYoshihiro Shimoda {
106afb35666SYoshihiro Shimoda 	sh_mmcif_bitclr(CLK_ENABLE, &host->regs->ce_clk_ctrl);
107afb35666SYoshihiro Shimoda 	sh_mmcif_bitclr(CLK_CLEAR, &host->regs->ce_clk_ctrl);
108afb35666SYoshihiro Shimoda 
109afb35666SYoshihiro Shimoda 	if (!clk)
110afb35666SYoshihiro Shimoda 		return;
111*21ea3503SNobuhiro Iwamatsu 
112*21ea3503SNobuhiro Iwamatsu 	if (clk == CLKDEV_EMMC_DATA)
113afb35666SYoshihiro Shimoda 		sh_mmcif_bitset(CLK_PCLK, &host->regs->ce_clk_ctrl);
114*21ea3503SNobuhiro Iwamatsu 	else
115*21ea3503SNobuhiro Iwamatsu 		sh_mmcif_bitset((fls(DIV_ROUND_UP(host->clk,
116*21ea3503SNobuhiro Iwamatsu 						  clk) - 1) - 1) << 16,
117*21ea3503SNobuhiro Iwamatsu 				&host->regs->ce_clk_ctrl);
118afb35666SYoshihiro Shimoda 	sh_mmcif_bitset(CLK_ENABLE, &host->regs->ce_clk_ctrl);
119afb35666SYoshihiro Shimoda }
120afb35666SYoshihiro Shimoda 
121afb35666SYoshihiro Shimoda static void sh_mmcif_sync_reset(struct sh_mmcif_host *host)
122afb35666SYoshihiro Shimoda {
123afb35666SYoshihiro Shimoda 	u32 tmp;
124afb35666SYoshihiro Shimoda 
125afb35666SYoshihiro Shimoda 	tmp = sh_mmcif_read(&host->regs->ce_clk_ctrl) & (CLK_ENABLE |
126afb35666SYoshihiro Shimoda 							 CLK_CLEAR);
127afb35666SYoshihiro Shimoda 
128afb35666SYoshihiro Shimoda 	sh_mmcif_write(SOFT_RST_ON, &host->regs->ce_version);
129afb35666SYoshihiro Shimoda 	sh_mmcif_write(SOFT_RST_OFF, &host->regs->ce_version);
130afb35666SYoshihiro Shimoda 	sh_mmcif_bitset(tmp | SRSPTO_256 | SRBSYTO_29 | SRWDTO_29 | SCCSTO_29,
131afb35666SYoshihiro Shimoda 			&host->regs->ce_clk_ctrl);
132afb35666SYoshihiro Shimoda 	/* byte swap on */
133afb35666SYoshihiro Shimoda 	sh_mmcif_bitset(BUF_ACC_ATYP, &host->regs->ce_buf_acc);
134afb35666SYoshihiro Shimoda }
135afb35666SYoshihiro Shimoda 
136afb35666SYoshihiro Shimoda static int sh_mmcif_error_manage(struct sh_mmcif_host *host)
137afb35666SYoshihiro Shimoda {
138afb35666SYoshihiro Shimoda 	u32 state1, state2;
139afb35666SYoshihiro Shimoda 	int ret, timeout = 10000000;
140afb35666SYoshihiro Shimoda 
141afb35666SYoshihiro Shimoda 	host->sd_error = 0;
142afb35666SYoshihiro Shimoda 	host->wait_int = 0;
143afb35666SYoshihiro Shimoda 
144afb35666SYoshihiro Shimoda 	state1 = sh_mmcif_read(&host->regs->ce_host_sts1);
145afb35666SYoshihiro Shimoda 	state2 = sh_mmcif_read(&host->regs->ce_host_sts2);
146afb35666SYoshihiro Shimoda 	debug("%s: ERR HOST_STS1 = %08x\n", \
147afb35666SYoshihiro Shimoda 			DRIVER_NAME, sh_mmcif_read(&host->regs->ce_host_sts1));
148afb35666SYoshihiro Shimoda 	debug("%s: ERR HOST_STS2 = %08x\n", \
149afb35666SYoshihiro Shimoda 			DRIVER_NAME, sh_mmcif_read(&host->regs->ce_host_sts2));
150afb35666SYoshihiro Shimoda 
151afb35666SYoshihiro Shimoda 	if (state1 & STS1_CMDSEQ) {
152afb35666SYoshihiro Shimoda 		debug("%s: Forced end of command sequence\n", DRIVER_NAME);
153afb35666SYoshihiro Shimoda 		sh_mmcif_bitset(CMD_CTRL_BREAK, &host->regs->ce_cmd_ctrl);
154afb35666SYoshihiro Shimoda 		sh_mmcif_bitset(~CMD_CTRL_BREAK, &host->regs->ce_cmd_ctrl);
155afb35666SYoshihiro Shimoda 		while (1) {
156afb35666SYoshihiro Shimoda 			timeout--;
157afb35666SYoshihiro Shimoda 			if (timeout < 0) {
158afb35666SYoshihiro Shimoda 				printf(DRIVER_NAME": Forceed end of " \
159afb35666SYoshihiro Shimoda 					"command sequence timeout err\n");
160afb35666SYoshihiro Shimoda 				return -EILSEQ;
161afb35666SYoshihiro Shimoda 			}
162afb35666SYoshihiro Shimoda 			if (!(sh_mmcif_read(&host->regs->ce_host_sts1)
163afb35666SYoshihiro Shimoda 								& STS1_CMDSEQ))
164afb35666SYoshihiro Shimoda 				break;
165afb35666SYoshihiro Shimoda 		}
166afb35666SYoshihiro Shimoda 		sh_mmcif_sync_reset(host);
167afb35666SYoshihiro Shimoda 		return -EILSEQ;
168afb35666SYoshihiro Shimoda 	}
169afb35666SYoshihiro Shimoda 
170afb35666SYoshihiro Shimoda 	if (state2 & STS2_CRC_ERR)
171afb35666SYoshihiro Shimoda 		ret = -EILSEQ;
172afb35666SYoshihiro Shimoda 	else if (state2 & STS2_TIMEOUT_ERR)
173afb35666SYoshihiro Shimoda 		ret = TIMEOUT;
174afb35666SYoshihiro Shimoda 	else
175afb35666SYoshihiro Shimoda 		ret = -EILSEQ;
176afb35666SYoshihiro Shimoda 	return ret;
177afb35666SYoshihiro Shimoda }
178afb35666SYoshihiro Shimoda 
179afb35666SYoshihiro Shimoda static int sh_mmcif_single_read(struct sh_mmcif_host *host,
180afb35666SYoshihiro Shimoda 				struct mmc_data *data)
181afb35666SYoshihiro Shimoda {
182afb35666SYoshihiro Shimoda 	long time;
183afb35666SYoshihiro Shimoda 	u32 blocksize, i;
184afb35666SYoshihiro Shimoda 	unsigned long *p = (unsigned long *)data->dest;
185afb35666SYoshihiro Shimoda 
186afb35666SYoshihiro Shimoda 	if ((unsigned long)p & 0x00000001) {
187afb35666SYoshihiro Shimoda 		printf("%s: The data pointer is unaligned.", __func__);
188afb35666SYoshihiro Shimoda 		return -EIO;
189afb35666SYoshihiro Shimoda 	}
190afb35666SYoshihiro Shimoda 
191afb35666SYoshihiro Shimoda 	host->wait_int = 0;
192afb35666SYoshihiro Shimoda 
193afb35666SYoshihiro Shimoda 	/* buf read enable */
194afb35666SYoshihiro Shimoda 	sh_mmcif_bitset(MASK_MBUFREN, &host->regs->ce_int_mask);
195afb35666SYoshihiro Shimoda 	time = mmcif_wait_interrupt_flag(host);
196afb35666SYoshihiro Shimoda 	if (time == 0 || host->sd_error != 0)
197afb35666SYoshihiro Shimoda 		return sh_mmcif_error_manage(host);
198afb35666SYoshihiro Shimoda 
199afb35666SYoshihiro Shimoda 	host->wait_int = 0;
200afb35666SYoshihiro Shimoda 	blocksize = (BLOCK_SIZE_MASK &
201afb35666SYoshihiro Shimoda 			sh_mmcif_read(&host->regs->ce_block_set)) + 3;
202afb35666SYoshihiro Shimoda 	for (i = 0; i < blocksize / 4; i++)
203afb35666SYoshihiro Shimoda 		*p++ = sh_mmcif_read(&host->regs->ce_data);
204afb35666SYoshihiro Shimoda 
205afb35666SYoshihiro Shimoda 	/* buffer read end */
206afb35666SYoshihiro Shimoda 	sh_mmcif_bitset(MASK_MBUFRE, &host->regs->ce_int_mask);
207afb35666SYoshihiro Shimoda 	time = mmcif_wait_interrupt_flag(host);
208afb35666SYoshihiro Shimoda 	if (time == 0 || host->sd_error != 0)
209afb35666SYoshihiro Shimoda 		return sh_mmcif_error_manage(host);
210afb35666SYoshihiro Shimoda 
211afb35666SYoshihiro Shimoda 	host->wait_int = 0;
212afb35666SYoshihiro Shimoda 	return 0;
213afb35666SYoshihiro Shimoda }
214afb35666SYoshihiro Shimoda 
215afb35666SYoshihiro Shimoda static int sh_mmcif_multi_read(struct sh_mmcif_host *host,
216afb35666SYoshihiro Shimoda 				struct mmc_data *data)
217afb35666SYoshihiro Shimoda {
218afb35666SYoshihiro Shimoda 	long time;
219afb35666SYoshihiro Shimoda 	u32 blocksize, i, j;
220afb35666SYoshihiro Shimoda 	unsigned long *p = (unsigned long *)data->dest;
221afb35666SYoshihiro Shimoda 
222afb35666SYoshihiro Shimoda 	if ((unsigned long)p & 0x00000001) {
223afb35666SYoshihiro Shimoda 		printf("%s: The data pointer is unaligned.", __func__);
224afb35666SYoshihiro Shimoda 		return -EIO;
225afb35666SYoshihiro Shimoda 	}
226afb35666SYoshihiro Shimoda 
227afb35666SYoshihiro Shimoda 	host->wait_int = 0;
228afb35666SYoshihiro Shimoda 	blocksize = BLOCK_SIZE_MASK & sh_mmcif_read(&host->regs->ce_block_set);
229afb35666SYoshihiro Shimoda 	for (j = 0; j < data->blocks; j++) {
230afb35666SYoshihiro Shimoda 		sh_mmcif_bitset(MASK_MBUFREN, &host->regs->ce_int_mask);
231afb35666SYoshihiro Shimoda 		time = mmcif_wait_interrupt_flag(host);
232afb35666SYoshihiro Shimoda 		if (time == 0 || host->sd_error != 0)
233afb35666SYoshihiro Shimoda 			return sh_mmcif_error_manage(host);
234afb35666SYoshihiro Shimoda 
235afb35666SYoshihiro Shimoda 		host->wait_int = 0;
236afb35666SYoshihiro Shimoda 		for (i = 0; i < blocksize / 4; i++)
237afb35666SYoshihiro Shimoda 			*p++ = sh_mmcif_read(&host->regs->ce_data);
238afb35666SYoshihiro Shimoda 
239afb35666SYoshihiro Shimoda 		WATCHDOG_RESET();
240afb35666SYoshihiro Shimoda 	}
241afb35666SYoshihiro Shimoda 	return 0;
242afb35666SYoshihiro Shimoda }
243afb35666SYoshihiro Shimoda 
244afb35666SYoshihiro Shimoda static int sh_mmcif_single_write(struct sh_mmcif_host *host,
245afb35666SYoshihiro Shimoda 				 struct mmc_data *data)
246afb35666SYoshihiro Shimoda {
247afb35666SYoshihiro Shimoda 	long time;
248afb35666SYoshihiro Shimoda 	u32 blocksize, i;
249afb35666SYoshihiro Shimoda 	const unsigned long *p = (unsigned long *)data->dest;
250afb35666SYoshihiro Shimoda 
251afb35666SYoshihiro Shimoda 	if ((unsigned long)p & 0x00000001) {
252afb35666SYoshihiro Shimoda 		printf("%s: The data pointer is unaligned.", __func__);
253afb35666SYoshihiro Shimoda 		return -EIO;
254afb35666SYoshihiro Shimoda 	}
255afb35666SYoshihiro Shimoda 
256afb35666SYoshihiro Shimoda 	host->wait_int = 0;
257afb35666SYoshihiro Shimoda 	sh_mmcif_bitset(MASK_MBUFWEN, &host->regs->ce_int_mask);
258afb35666SYoshihiro Shimoda 
259afb35666SYoshihiro Shimoda 	time = mmcif_wait_interrupt_flag(host);
260afb35666SYoshihiro Shimoda 	if (time == 0 || host->sd_error != 0)
261afb35666SYoshihiro Shimoda 		return sh_mmcif_error_manage(host);
262afb35666SYoshihiro Shimoda 
263afb35666SYoshihiro Shimoda 	host->wait_int = 0;
264afb35666SYoshihiro Shimoda 	blocksize = (BLOCK_SIZE_MASK &
265afb35666SYoshihiro Shimoda 			sh_mmcif_read(&host->regs->ce_block_set)) + 3;
266afb35666SYoshihiro Shimoda 	for (i = 0; i < blocksize / 4; i++)
267afb35666SYoshihiro Shimoda 		sh_mmcif_write(*p++, &host->regs->ce_data);
268afb35666SYoshihiro Shimoda 
269afb35666SYoshihiro Shimoda 	/* buffer write end */
270afb35666SYoshihiro Shimoda 	sh_mmcif_bitset(MASK_MDTRANE, &host->regs->ce_int_mask);
271afb35666SYoshihiro Shimoda 
272afb35666SYoshihiro Shimoda 	time = mmcif_wait_interrupt_flag(host);
273afb35666SYoshihiro Shimoda 	if (time == 0 || host->sd_error != 0)
274afb35666SYoshihiro Shimoda 		return sh_mmcif_error_manage(host);
275afb35666SYoshihiro Shimoda 
276afb35666SYoshihiro Shimoda 	host->wait_int = 0;
277afb35666SYoshihiro Shimoda 	return 0;
278afb35666SYoshihiro Shimoda }
279afb35666SYoshihiro Shimoda 
280afb35666SYoshihiro Shimoda static int sh_mmcif_multi_write(struct sh_mmcif_host *host,
281afb35666SYoshihiro Shimoda 				struct mmc_data *data)
282afb35666SYoshihiro Shimoda {
283afb35666SYoshihiro Shimoda 	long time;
284afb35666SYoshihiro Shimoda 	u32 i, j, blocksize;
285afb35666SYoshihiro Shimoda 	const unsigned long *p = (unsigned long *)data->dest;
286afb35666SYoshihiro Shimoda 
287afb35666SYoshihiro Shimoda 	if ((unsigned long)p & 0x00000001) {
288afb35666SYoshihiro Shimoda 		printf("%s: The data pointer is unaligned.", __func__);
289afb35666SYoshihiro Shimoda 		return -EIO;
290afb35666SYoshihiro Shimoda 	}
291afb35666SYoshihiro Shimoda 
292afb35666SYoshihiro Shimoda 	host->wait_int = 0;
293afb35666SYoshihiro Shimoda 	blocksize = BLOCK_SIZE_MASK & sh_mmcif_read(&host->regs->ce_block_set);
294afb35666SYoshihiro Shimoda 	for (j = 0; j < data->blocks; j++) {
295afb35666SYoshihiro Shimoda 		sh_mmcif_bitset(MASK_MBUFWEN, &host->regs->ce_int_mask);
296afb35666SYoshihiro Shimoda 
297afb35666SYoshihiro Shimoda 		time = mmcif_wait_interrupt_flag(host);
298afb35666SYoshihiro Shimoda 
299afb35666SYoshihiro Shimoda 		if (time == 0 || host->sd_error != 0)
300afb35666SYoshihiro Shimoda 			return sh_mmcif_error_manage(host);
301afb35666SYoshihiro Shimoda 
302afb35666SYoshihiro Shimoda 		host->wait_int = 0;
303afb35666SYoshihiro Shimoda 		for (i = 0; i < blocksize / 4; i++)
304afb35666SYoshihiro Shimoda 			sh_mmcif_write(*p++, &host->regs->ce_data);
305afb35666SYoshihiro Shimoda 
306afb35666SYoshihiro Shimoda 		WATCHDOG_RESET();
307afb35666SYoshihiro Shimoda 	}
308afb35666SYoshihiro Shimoda 	return 0;
309afb35666SYoshihiro Shimoda }
310afb35666SYoshihiro Shimoda 
311afb35666SYoshihiro Shimoda static void sh_mmcif_get_response(struct sh_mmcif_host *host,
312afb35666SYoshihiro Shimoda 					struct mmc_cmd *cmd)
313afb35666SYoshihiro Shimoda {
314afb35666SYoshihiro Shimoda 	if (cmd->resp_type & MMC_RSP_136) {
315afb35666SYoshihiro Shimoda 		cmd->response[0] = sh_mmcif_read(&host->regs->ce_resp3);
316afb35666SYoshihiro Shimoda 		cmd->response[1] = sh_mmcif_read(&host->regs->ce_resp2);
317afb35666SYoshihiro Shimoda 		cmd->response[2] = sh_mmcif_read(&host->regs->ce_resp1);
318afb35666SYoshihiro Shimoda 		cmd->response[3] = sh_mmcif_read(&host->regs->ce_resp0);
319afb35666SYoshihiro Shimoda 		debug(" RESP %08x, %08x, %08x, %08x\n", cmd->response[0],
320afb35666SYoshihiro Shimoda 			 cmd->response[1], cmd->response[2], cmd->response[3]);
321afb35666SYoshihiro Shimoda 	} else {
322afb35666SYoshihiro Shimoda 		cmd->response[0] = sh_mmcif_read(&host->regs->ce_resp0);
323afb35666SYoshihiro Shimoda 	}
324afb35666SYoshihiro Shimoda }
325afb35666SYoshihiro Shimoda 
326afb35666SYoshihiro Shimoda static void sh_mmcif_get_cmd12response(struct sh_mmcif_host *host,
327afb35666SYoshihiro Shimoda 					struct mmc_cmd *cmd)
328afb35666SYoshihiro Shimoda {
329afb35666SYoshihiro Shimoda 	cmd->response[0] = sh_mmcif_read(&host->regs->ce_resp_cmd12);
330afb35666SYoshihiro Shimoda }
331afb35666SYoshihiro Shimoda 
332afb35666SYoshihiro Shimoda static u32 sh_mmcif_set_cmd(struct sh_mmcif_host *host,
333afb35666SYoshihiro Shimoda 				struct mmc_data *data, struct mmc_cmd *cmd)
334afb35666SYoshihiro Shimoda {
335afb35666SYoshihiro Shimoda 	u32 tmp = 0;
336afb35666SYoshihiro Shimoda 	u32 opc = cmd->cmdidx;
337afb35666SYoshihiro Shimoda 
338afb35666SYoshihiro Shimoda 	/* Response Type check */
339afb35666SYoshihiro Shimoda 	switch (cmd->resp_type) {
340afb35666SYoshihiro Shimoda 	case MMC_RSP_NONE:
341afb35666SYoshihiro Shimoda 		tmp |= CMD_SET_RTYP_NO;
342afb35666SYoshihiro Shimoda 		break;
343afb35666SYoshihiro Shimoda 	case MMC_RSP_R1:
344afb35666SYoshihiro Shimoda 	case MMC_RSP_R1b:
345afb35666SYoshihiro Shimoda 	case MMC_RSP_R3:
346afb35666SYoshihiro Shimoda 		tmp |= CMD_SET_RTYP_6B;
347afb35666SYoshihiro Shimoda 		break;
348afb35666SYoshihiro Shimoda 	case MMC_RSP_R2:
349afb35666SYoshihiro Shimoda 		tmp |= CMD_SET_RTYP_17B;
350afb35666SYoshihiro Shimoda 		break;
351afb35666SYoshihiro Shimoda 	default:
352afb35666SYoshihiro Shimoda 		printf(DRIVER_NAME": Not support type response.\n");
353afb35666SYoshihiro Shimoda 		break;
354afb35666SYoshihiro Shimoda 	}
355afb35666SYoshihiro Shimoda 
356afb35666SYoshihiro Shimoda 	/* RBSY */
357afb35666SYoshihiro Shimoda 	if (opc == MMC_CMD_SWITCH)
358afb35666SYoshihiro Shimoda 		tmp |= CMD_SET_RBSY;
359afb35666SYoshihiro Shimoda 
360afb35666SYoshihiro Shimoda 	/* WDAT / DATW */
361afb35666SYoshihiro Shimoda 	if (host->data) {
362afb35666SYoshihiro Shimoda 		tmp |= CMD_SET_WDAT;
363afb35666SYoshihiro Shimoda 		switch (host->bus_width) {
364afb35666SYoshihiro Shimoda 		case MMC_BUS_WIDTH_1:
365afb35666SYoshihiro Shimoda 			tmp |= CMD_SET_DATW_1;
366afb35666SYoshihiro Shimoda 			break;
367afb35666SYoshihiro Shimoda 		case MMC_BUS_WIDTH_4:
368afb35666SYoshihiro Shimoda 			tmp |= CMD_SET_DATW_4;
369afb35666SYoshihiro Shimoda 			break;
370afb35666SYoshihiro Shimoda 		case MMC_BUS_WIDTH_8:
371afb35666SYoshihiro Shimoda 			tmp |= CMD_SET_DATW_8;
372afb35666SYoshihiro Shimoda 			break;
373afb35666SYoshihiro Shimoda 		default:
374afb35666SYoshihiro Shimoda 			printf(DRIVER_NAME": Not support bus width.\n");
375afb35666SYoshihiro Shimoda 			break;
376afb35666SYoshihiro Shimoda 		}
377afb35666SYoshihiro Shimoda 	}
378afb35666SYoshihiro Shimoda 	/* DWEN */
379afb35666SYoshihiro Shimoda 	if (opc == MMC_CMD_WRITE_SINGLE_BLOCK ||
380afb35666SYoshihiro Shimoda 	    opc == MMC_CMD_WRITE_MULTIPLE_BLOCK)
381afb35666SYoshihiro Shimoda 		tmp |= CMD_SET_DWEN;
382afb35666SYoshihiro Shimoda 	/* CMLTE/CMD12EN */
383afb35666SYoshihiro Shimoda 	if (opc == MMC_CMD_READ_MULTIPLE_BLOCK ||
384afb35666SYoshihiro Shimoda 	    opc == MMC_CMD_WRITE_MULTIPLE_BLOCK) {
385afb35666SYoshihiro Shimoda 		tmp |= CMD_SET_CMLTE | CMD_SET_CMD12EN;
386afb35666SYoshihiro Shimoda 		sh_mmcif_bitset(data->blocks << 16, &host->regs->ce_block_set);
387afb35666SYoshihiro Shimoda 	}
388afb35666SYoshihiro Shimoda 	/* RIDXC[1:0] check bits */
389afb35666SYoshihiro Shimoda 	if (opc == MMC_CMD_SEND_OP_COND || opc == MMC_CMD_ALL_SEND_CID ||
390afb35666SYoshihiro Shimoda 	    opc == MMC_CMD_SEND_CSD || opc == MMC_CMD_SEND_CID)
391afb35666SYoshihiro Shimoda 		tmp |= CMD_SET_RIDXC_BITS;
392afb35666SYoshihiro Shimoda 	/* RCRC7C[1:0] check bits */
393afb35666SYoshihiro Shimoda 	if (opc == MMC_CMD_SEND_OP_COND)
394afb35666SYoshihiro Shimoda 		tmp |= CMD_SET_CRC7C_BITS;
395afb35666SYoshihiro Shimoda 	/* RCRC7C[1:0] internal CRC7 */
396afb35666SYoshihiro Shimoda 	if (opc == MMC_CMD_ALL_SEND_CID ||
397afb35666SYoshihiro Shimoda 		opc == MMC_CMD_SEND_CSD || opc == MMC_CMD_SEND_CID)
398afb35666SYoshihiro Shimoda 		tmp |= CMD_SET_CRC7C_INTERNAL;
399afb35666SYoshihiro Shimoda 
400afb35666SYoshihiro Shimoda 	return opc = ((opc << 24) | tmp);
401afb35666SYoshihiro Shimoda }
402afb35666SYoshihiro Shimoda 
403afb35666SYoshihiro Shimoda static u32 sh_mmcif_data_trans(struct sh_mmcif_host *host,
404afb35666SYoshihiro Shimoda 				struct mmc_data *data, u16 opc)
405afb35666SYoshihiro Shimoda {
406afb35666SYoshihiro Shimoda 	u32 ret;
407afb35666SYoshihiro Shimoda 
408afb35666SYoshihiro Shimoda 	switch (opc) {
409afb35666SYoshihiro Shimoda 	case MMC_CMD_READ_MULTIPLE_BLOCK:
410afb35666SYoshihiro Shimoda 		ret = sh_mmcif_multi_read(host, data);
411afb35666SYoshihiro Shimoda 		break;
412afb35666SYoshihiro Shimoda 	case MMC_CMD_WRITE_MULTIPLE_BLOCK:
413afb35666SYoshihiro Shimoda 		ret = sh_mmcif_multi_write(host, data);
414afb35666SYoshihiro Shimoda 		break;
415afb35666SYoshihiro Shimoda 	case MMC_CMD_WRITE_SINGLE_BLOCK:
416afb35666SYoshihiro Shimoda 		ret = sh_mmcif_single_write(host, data);
417afb35666SYoshihiro Shimoda 		break;
418afb35666SYoshihiro Shimoda 	case MMC_CMD_READ_SINGLE_BLOCK:
419afb35666SYoshihiro Shimoda 	case MMC_CMD_SEND_EXT_CSD:
420afb35666SYoshihiro Shimoda 		ret = sh_mmcif_single_read(host, data);
421afb35666SYoshihiro Shimoda 		break;
422afb35666SYoshihiro Shimoda 	default:
423afb35666SYoshihiro Shimoda 		printf(DRIVER_NAME": NOT SUPPORT CMD = d'%08d\n", opc);
424afb35666SYoshihiro Shimoda 		ret = -EINVAL;
425afb35666SYoshihiro Shimoda 		break;
426afb35666SYoshihiro Shimoda 	}
427afb35666SYoshihiro Shimoda 	return ret;
428afb35666SYoshihiro Shimoda }
429afb35666SYoshihiro Shimoda 
430afb35666SYoshihiro Shimoda static int sh_mmcif_start_cmd(struct sh_mmcif_host *host,
431afb35666SYoshihiro Shimoda 				struct mmc_data *data, struct mmc_cmd *cmd)
432afb35666SYoshihiro Shimoda {
433afb35666SYoshihiro Shimoda 	long time;
434afb35666SYoshihiro Shimoda 	int ret = 0, mask = 0;
435afb35666SYoshihiro Shimoda 	u32 opc = cmd->cmdidx;
436afb35666SYoshihiro Shimoda 
437afb35666SYoshihiro Shimoda 	if (opc == MMC_CMD_STOP_TRANSMISSION) {
438afb35666SYoshihiro Shimoda 		/* MMCIF sends the STOP command automatically */
439afb35666SYoshihiro Shimoda 		if (host->last_cmd == MMC_CMD_READ_MULTIPLE_BLOCK)
440afb35666SYoshihiro Shimoda 			sh_mmcif_bitset(MASK_MCMD12DRE,
441afb35666SYoshihiro Shimoda 					&host->regs->ce_int_mask);
442afb35666SYoshihiro Shimoda 		else
443afb35666SYoshihiro Shimoda 			sh_mmcif_bitset(MASK_MCMD12RBE,
444afb35666SYoshihiro Shimoda 					&host->regs->ce_int_mask);
445afb35666SYoshihiro Shimoda 
446afb35666SYoshihiro Shimoda 		time = mmcif_wait_interrupt_flag(host);
447afb35666SYoshihiro Shimoda 		if (time == 0 || host->sd_error != 0)
448afb35666SYoshihiro Shimoda 			return sh_mmcif_error_manage(host);
449afb35666SYoshihiro Shimoda 
450afb35666SYoshihiro Shimoda 		sh_mmcif_get_cmd12response(host, cmd);
451afb35666SYoshihiro Shimoda 		return 0;
452afb35666SYoshihiro Shimoda 	}
453afb35666SYoshihiro Shimoda 	if (opc == MMC_CMD_SWITCH)
454afb35666SYoshihiro Shimoda 		mask = MASK_MRBSYE;
455afb35666SYoshihiro Shimoda 	else
456afb35666SYoshihiro Shimoda 		mask = MASK_MCRSPE;
457afb35666SYoshihiro Shimoda 
458afb35666SYoshihiro Shimoda 	mask |=	MASK_MCMDVIO | MASK_MBUFVIO | MASK_MWDATERR |
459afb35666SYoshihiro Shimoda 		MASK_MRDATERR | MASK_MRIDXERR | MASK_MRSPERR |
460afb35666SYoshihiro Shimoda 		MASK_MCCSTO | MASK_MCRCSTO | MASK_MWDATTO |
461afb35666SYoshihiro Shimoda 		MASK_MRDATTO | MASK_MRBSYTO | MASK_MRSPTO;
462afb35666SYoshihiro Shimoda 
463afb35666SYoshihiro Shimoda 	if (host->data) {
464afb35666SYoshihiro Shimoda 		sh_mmcif_write(0, &host->regs->ce_block_set);
465afb35666SYoshihiro Shimoda 		sh_mmcif_write(data->blocksize, &host->regs->ce_block_set);
466afb35666SYoshihiro Shimoda 	}
467afb35666SYoshihiro Shimoda 	opc = sh_mmcif_set_cmd(host, data, cmd);
468afb35666SYoshihiro Shimoda 
469afb35666SYoshihiro Shimoda 	sh_mmcif_write(INT_START_MAGIC, &host->regs->ce_int);
470afb35666SYoshihiro Shimoda 	sh_mmcif_write(mask, &host->regs->ce_int_mask);
471afb35666SYoshihiro Shimoda 
472afb35666SYoshihiro Shimoda 	debug("CMD%d ARG:%08x\n", cmd->cmdidx, cmd->cmdarg);
473afb35666SYoshihiro Shimoda 	/* set arg */
474afb35666SYoshihiro Shimoda 	sh_mmcif_write(cmd->cmdarg, &host->regs->ce_arg);
475afb35666SYoshihiro Shimoda 	host->wait_int = 0;
476afb35666SYoshihiro Shimoda 	/* set cmd */
477afb35666SYoshihiro Shimoda 	sh_mmcif_write(opc, &host->regs->ce_cmd_set);
478afb35666SYoshihiro Shimoda 
479afb35666SYoshihiro Shimoda 	time = mmcif_wait_interrupt_flag(host);
480afb35666SYoshihiro Shimoda 	if (time == 0)
481afb35666SYoshihiro Shimoda 		return sh_mmcif_error_manage(host);
482afb35666SYoshihiro Shimoda 
483afb35666SYoshihiro Shimoda 	if (host->sd_error) {
484afb35666SYoshihiro Shimoda 		switch (cmd->cmdidx) {
485afb35666SYoshihiro Shimoda 		case MMC_CMD_ALL_SEND_CID:
486afb35666SYoshihiro Shimoda 		case MMC_CMD_SELECT_CARD:
487afb35666SYoshihiro Shimoda 		case MMC_CMD_APP_CMD:
488afb35666SYoshihiro Shimoda 			ret = TIMEOUT;
489afb35666SYoshihiro Shimoda 			break;
490afb35666SYoshihiro Shimoda 		default:
491afb35666SYoshihiro Shimoda 			printf(DRIVER_NAME": Cmd(d'%d) err\n", cmd->cmdidx);
492afb35666SYoshihiro Shimoda 			ret = sh_mmcif_error_manage(host);
493afb35666SYoshihiro Shimoda 			break;
494afb35666SYoshihiro Shimoda 		}
495afb35666SYoshihiro Shimoda 		host->sd_error = 0;
496afb35666SYoshihiro Shimoda 		host->wait_int = 0;
497afb35666SYoshihiro Shimoda 		return ret;
498afb35666SYoshihiro Shimoda 	}
499afb35666SYoshihiro Shimoda 
500afb35666SYoshihiro Shimoda 	/* if no response */
501afb35666SYoshihiro Shimoda 	if (!(opc & 0x00C00000))
502afb35666SYoshihiro Shimoda 		return 0;
503afb35666SYoshihiro Shimoda 
504afb35666SYoshihiro Shimoda 	if (host->wait_int == 1) {
505afb35666SYoshihiro Shimoda 		sh_mmcif_get_response(host, cmd);
506afb35666SYoshihiro Shimoda 		host->wait_int = 0;
507afb35666SYoshihiro Shimoda 	}
508afb35666SYoshihiro Shimoda 	if (host->data)
509afb35666SYoshihiro Shimoda 		ret = sh_mmcif_data_trans(host, data, cmd->cmdidx);
510afb35666SYoshihiro Shimoda 	host->last_cmd = cmd->cmdidx;
511afb35666SYoshihiro Shimoda 
512afb35666SYoshihiro Shimoda 	return ret;
513afb35666SYoshihiro Shimoda }
514afb35666SYoshihiro Shimoda 
515afb35666SYoshihiro Shimoda static int sh_mmcif_request(struct mmc *mmc, struct mmc_cmd *cmd,
516afb35666SYoshihiro Shimoda 			    struct mmc_data *data)
517afb35666SYoshihiro Shimoda {
51893bfd616SPantelis Antoniou 	struct sh_mmcif_host *host = mmc->priv;
519afb35666SYoshihiro Shimoda 	int ret;
520afb35666SYoshihiro Shimoda 
521afb35666SYoshihiro Shimoda 	WATCHDOG_RESET();
522afb35666SYoshihiro Shimoda 
523afb35666SYoshihiro Shimoda 	switch (cmd->cmdidx) {
524afb35666SYoshihiro Shimoda 	case MMC_CMD_APP_CMD:
525afb35666SYoshihiro Shimoda 		return TIMEOUT;
526afb35666SYoshihiro Shimoda 	case MMC_CMD_SEND_EXT_CSD: /* = SD_SEND_IF_COND (8) */
527afb35666SYoshihiro Shimoda 		if (data)
528afb35666SYoshihiro Shimoda 			/* ext_csd */
529afb35666SYoshihiro Shimoda 			break;
530afb35666SYoshihiro Shimoda 		else
531afb35666SYoshihiro Shimoda 			/* send_if_cond cmd (not support) */
532afb35666SYoshihiro Shimoda 			return TIMEOUT;
533afb35666SYoshihiro Shimoda 	default:
534afb35666SYoshihiro Shimoda 		break;
535afb35666SYoshihiro Shimoda 	}
536afb35666SYoshihiro Shimoda 	host->sd_error = 0;
537afb35666SYoshihiro Shimoda 	host->data = data;
538afb35666SYoshihiro Shimoda 	ret = sh_mmcif_start_cmd(host, data, cmd);
539afb35666SYoshihiro Shimoda 	host->data = NULL;
540afb35666SYoshihiro Shimoda 
541afb35666SYoshihiro Shimoda 	return ret;
542afb35666SYoshihiro Shimoda }
543afb35666SYoshihiro Shimoda 
544afb35666SYoshihiro Shimoda static void sh_mmcif_set_ios(struct mmc *mmc)
545afb35666SYoshihiro Shimoda {
54693bfd616SPantelis Antoniou 	struct sh_mmcif_host *host = mmc->priv;
547afb35666SYoshihiro Shimoda 
548afb35666SYoshihiro Shimoda 	if (mmc->clock)
549afb35666SYoshihiro Shimoda 		sh_mmcif_clock_control(host, mmc->clock);
550afb35666SYoshihiro Shimoda 
551afb35666SYoshihiro Shimoda 	if (mmc->bus_width == 8)
552afb35666SYoshihiro Shimoda 		host->bus_width = MMC_BUS_WIDTH_8;
553afb35666SYoshihiro Shimoda 	else if (mmc->bus_width == 4)
554afb35666SYoshihiro Shimoda 		host->bus_width = MMC_BUS_WIDTH_4;
555afb35666SYoshihiro Shimoda 	else
556afb35666SYoshihiro Shimoda 		host->bus_width = MMC_BUS_WIDTH_1;
557afb35666SYoshihiro Shimoda 
558afb35666SYoshihiro Shimoda 	debug("clock = %d, buswidth = %d\n", mmc->clock, mmc->bus_width);
559afb35666SYoshihiro Shimoda }
560afb35666SYoshihiro Shimoda 
561afb35666SYoshihiro Shimoda static int sh_mmcif_init(struct mmc *mmc)
562afb35666SYoshihiro Shimoda {
56393bfd616SPantelis Antoniou 	struct sh_mmcif_host *host = mmc->priv;
564afb35666SYoshihiro Shimoda 
565afb35666SYoshihiro Shimoda 	sh_mmcif_sync_reset(host);
566afb35666SYoshihiro Shimoda 	sh_mmcif_write(MASK_ALL, &host->regs->ce_int_mask);
567afb35666SYoshihiro Shimoda 	return 0;
568afb35666SYoshihiro Shimoda }
569afb35666SYoshihiro Shimoda 
570ab769f22SPantelis Antoniou static const struct mmc_ops sh_mmcif_ops = {
571ab769f22SPantelis Antoniou 	.send_cmd	= sh_mmcif_request,
572ab769f22SPantelis Antoniou 	.set_ios	= sh_mmcif_set_ios,
573ab769f22SPantelis Antoniou 	.init		= sh_mmcif_init,
574ab769f22SPantelis Antoniou };
575ab769f22SPantelis Antoniou 
57693bfd616SPantelis Antoniou static struct mmc_config sh_mmcif_cfg = {
57793bfd616SPantelis Antoniou 	.name		= DRIVER_NAME,
57893bfd616SPantelis Antoniou 	.ops		= &sh_mmcif_ops,
57993bfd616SPantelis Antoniou 	.host_caps	= MMC_MODE_HS | MMC_MODE_HS_52MHz | MMC_MODE_4BIT |
58093bfd616SPantelis Antoniou 			  MMC_MODE_8BIT | MMC_MODE_HC,
581cd2bf484SNobuhiro Iwamatsu 	.voltages	= MMC_VDD_32_33 | MMC_VDD_33_34,
58293bfd616SPantelis Antoniou 	.f_min		= CLKDEV_MMC_INIT,
58393bfd616SPantelis Antoniou 	.f_max		= CLKDEV_EMMC_DATA,
58493bfd616SPantelis Antoniou 	.b_max		= CONFIG_SYS_MMC_MAX_BLK_COUNT,
58593bfd616SPantelis Antoniou };
58693bfd616SPantelis Antoniou 
587afb35666SYoshihiro Shimoda int mmcif_mmc_init(void)
588afb35666SYoshihiro Shimoda {
589afb35666SYoshihiro Shimoda 	struct mmc *mmc;
590afb35666SYoshihiro Shimoda 	struct sh_mmcif_host *host = NULL;
591afb35666SYoshihiro Shimoda 
592afb35666SYoshihiro Shimoda 	host = malloc(sizeof(struct sh_mmcif_host));
593afb35666SYoshihiro Shimoda 	if (!host)
59474c32ef5SNobuhiro Iwamatsu 		return -ENOMEM;
595afb35666SYoshihiro Shimoda 	memset(host, 0, sizeof(*host));
596afb35666SYoshihiro Shimoda 
597afb35666SYoshihiro Shimoda 	host->regs = (struct sh_mmcif_regs *)CONFIG_SH_MMCIF_ADDR;
598afb35666SYoshihiro Shimoda 	host->clk = CONFIG_SH_MMCIF_CLK;
599afb35666SYoshihiro Shimoda 
60093bfd616SPantelis Antoniou 	mmc = mmc_create(&sh_mmcif_cfg, host);
60193bfd616SPantelis Antoniou 	if (mmc == NULL) {
60293bfd616SPantelis Antoniou 		free(host);
60393bfd616SPantelis Antoniou 		return -ENOMEM;
60493bfd616SPantelis Antoniou 	}
605afb35666SYoshihiro Shimoda 
60693bfd616SPantelis Antoniou 	return 0;
607afb35666SYoshihiro Shimoda }
608