xref: /openbmc/u-boot/drivers/mmc/sh_mmcif.c (revision 48f54a2d)
1afb35666SYoshihiro Shimoda /*
2afb35666SYoshihiro Shimoda  * MMCIF driver.
3afb35666SYoshihiro Shimoda  *
4afb35666SYoshihiro Shimoda  * Copyright (C)  2011 Renesas Solutions Corp.
5afb35666SYoshihiro Shimoda  *
65b8031ccSTom Rini  * SPDX-License-Identifier:	GPL-2.0
7afb35666SYoshihiro Shimoda  */
8afb35666SYoshihiro Shimoda 
9afb35666SYoshihiro Shimoda #include <config.h>
10afb35666SYoshihiro Shimoda #include <common.h>
11afb35666SYoshihiro Shimoda #include <watchdog.h>
12afb35666SYoshihiro Shimoda #include <command.h>
13afb35666SYoshihiro Shimoda #include <mmc.h>
14*48f54a2dSMarek Vasut #include <clk.h>
15*48f54a2dSMarek Vasut #include <dm.h>
16afb35666SYoshihiro Shimoda #include <malloc.h>
171221ce45SMasahiro Yamada #include <linux/errno.h>
18*48f54a2dSMarek Vasut #include <linux/compat.h>
19*48f54a2dSMarek Vasut #include <linux/io.h>
20*48f54a2dSMarek Vasut #include <linux/sizes.h>
21afb35666SYoshihiro Shimoda #include "sh_mmcif.h"
22afb35666SYoshihiro Shimoda 
23afb35666SYoshihiro Shimoda #define DRIVER_NAME	"sh_mmcif"
24afb35666SYoshihiro Shimoda 
25afb35666SYoshihiro Shimoda static int sh_mmcif_intr(void *dev_id)
26afb35666SYoshihiro Shimoda {
27afb35666SYoshihiro Shimoda 	struct sh_mmcif_host *host = dev_id;
28afb35666SYoshihiro Shimoda 	u32 state = 0;
29afb35666SYoshihiro Shimoda 
30afb35666SYoshihiro Shimoda 	state = sh_mmcif_read(&host->regs->ce_int);
31afb35666SYoshihiro Shimoda 	state &= sh_mmcif_read(&host->regs->ce_int_mask);
32afb35666SYoshihiro Shimoda 
33afb35666SYoshihiro Shimoda 	if (state & INT_RBSYE) {
34afb35666SYoshihiro Shimoda 		sh_mmcif_write(~(INT_RBSYE | INT_CRSPE), &host->regs->ce_int);
35afb35666SYoshihiro Shimoda 		sh_mmcif_bitclr(MASK_MRBSYE, &host->regs->ce_int_mask);
36afb35666SYoshihiro Shimoda 		goto end;
37afb35666SYoshihiro Shimoda 	} else if (state & INT_CRSPE) {
38afb35666SYoshihiro Shimoda 		sh_mmcif_write(~INT_CRSPE, &host->regs->ce_int);
39afb35666SYoshihiro Shimoda 		sh_mmcif_bitclr(MASK_MCRSPE, &host->regs->ce_int_mask);
40afb35666SYoshihiro Shimoda 		/* one more interrupt (INT_RBSYE) */
41afb35666SYoshihiro Shimoda 		if (sh_mmcif_read(&host->regs->ce_cmd_set) & CMD_SET_RBSY)
42afb35666SYoshihiro Shimoda 			return -EAGAIN;
43afb35666SYoshihiro Shimoda 		goto end;
44afb35666SYoshihiro Shimoda 	} else if (state & INT_BUFREN) {
45afb35666SYoshihiro Shimoda 		sh_mmcif_write(~INT_BUFREN, &host->regs->ce_int);
46afb35666SYoshihiro Shimoda 		sh_mmcif_bitclr(MASK_MBUFREN, &host->regs->ce_int_mask);
47afb35666SYoshihiro Shimoda 		goto end;
48afb35666SYoshihiro Shimoda 	} else if (state & INT_BUFWEN) {
49afb35666SYoshihiro Shimoda 		sh_mmcif_write(~INT_BUFWEN, &host->regs->ce_int);
50afb35666SYoshihiro Shimoda 		sh_mmcif_bitclr(MASK_MBUFWEN, &host->regs->ce_int_mask);
51afb35666SYoshihiro Shimoda 		goto end;
52afb35666SYoshihiro Shimoda 	} else if (state & INT_CMD12DRE) {
53afb35666SYoshihiro Shimoda 		sh_mmcif_write(~(INT_CMD12DRE | INT_CMD12RBE | INT_CMD12CRE |
54afb35666SYoshihiro Shimoda 				  INT_BUFRE), &host->regs->ce_int);
55afb35666SYoshihiro Shimoda 		sh_mmcif_bitclr(MASK_MCMD12DRE, &host->regs->ce_int_mask);
56afb35666SYoshihiro Shimoda 		goto end;
57afb35666SYoshihiro Shimoda 	} else if (state & INT_BUFRE) {
58afb35666SYoshihiro Shimoda 		sh_mmcif_write(~INT_BUFRE, &host->regs->ce_int);
59afb35666SYoshihiro Shimoda 		sh_mmcif_bitclr(MASK_MBUFRE, &host->regs->ce_int_mask);
60afb35666SYoshihiro Shimoda 		goto end;
61afb35666SYoshihiro Shimoda 	} else if (state & INT_DTRANE) {
62afb35666SYoshihiro Shimoda 		sh_mmcif_write(~INT_DTRANE, &host->regs->ce_int);
63afb35666SYoshihiro Shimoda 		sh_mmcif_bitclr(MASK_MDTRANE, &host->regs->ce_int_mask);
64afb35666SYoshihiro Shimoda 		goto end;
65afb35666SYoshihiro Shimoda 	} else if (state & INT_CMD12RBE) {
66afb35666SYoshihiro Shimoda 		sh_mmcif_write(~(INT_CMD12RBE | INT_CMD12CRE),
67afb35666SYoshihiro Shimoda 				&host->regs->ce_int);
68afb35666SYoshihiro Shimoda 		sh_mmcif_bitclr(MASK_MCMD12RBE, &host->regs->ce_int_mask);
69afb35666SYoshihiro Shimoda 		goto end;
70afb35666SYoshihiro Shimoda 	} else if (state & INT_ERR_STS) {
71afb35666SYoshihiro Shimoda 		/* err interrupts */
72afb35666SYoshihiro Shimoda 		sh_mmcif_write(~state, &host->regs->ce_int);
73afb35666SYoshihiro Shimoda 		sh_mmcif_bitclr(state, &host->regs->ce_int_mask);
74afb35666SYoshihiro Shimoda 		goto err;
75afb35666SYoshihiro Shimoda 	} else
76afb35666SYoshihiro Shimoda 		return -EAGAIN;
77afb35666SYoshihiro Shimoda 
78afb35666SYoshihiro Shimoda err:
79afb35666SYoshihiro Shimoda 	host->sd_error = 1;
80afb35666SYoshihiro Shimoda 	debug("%s: int err state = %08x\n", DRIVER_NAME, state);
81afb35666SYoshihiro Shimoda end:
82afb35666SYoshihiro Shimoda 	host->wait_int = 1;
83afb35666SYoshihiro Shimoda 	return 0;
84afb35666SYoshihiro Shimoda }
85afb35666SYoshihiro Shimoda 
86afb35666SYoshihiro Shimoda static int mmcif_wait_interrupt_flag(struct sh_mmcif_host *host)
87afb35666SYoshihiro Shimoda {
88afb35666SYoshihiro Shimoda 	int timeout = 10000000;
89afb35666SYoshihiro Shimoda 
90afb35666SYoshihiro Shimoda 	while (1) {
91afb35666SYoshihiro Shimoda 		timeout--;
92afb35666SYoshihiro Shimoda 		if (timeout < 0) {
93afb35666SYoshihiro Shimoda 			printf("timeout\n");
94afb35666SYoshihiro Shimoda 			return 0;
95afb35666SYoshihiro Shimoda 		}
96afb35666SYoshihiro Shimoda 
97afb35666SYoshihiro Shimoda 		if (!sh_mmcif_intr(host))
98afb35666SYoshihiro Shimoda 			break;
99afb35666SYoshihiro Shimoda 
100afb35666SYoshihiro Shimoda 		udelay(1);	/* 1 usec */
101afb35666SYoshihiro Shimoda 	}
102afb35666SYoshihiro Shimoda 
103afb35666SYoshihiro Shimoda 	return 1;	/* Return value: NOT 0 = complete waiting */
104afb35666SYoshihiro Shimoda }
105afb35666SYoshihiro Shimoda 
106afb35666SYoshihiro Shimoda static void sh_mmcif_clock_control(struct sh_mmcif_host *host, unsigned int clk)
107afb35666SYoshihiro Shimoda {
108afb35666SYoshihiro Shimoda 	sh_mmcif_bitclr(CLK_ENABLE, &host->regs->ce_clk_ctrl);
109afb35666SYoshihiro Shimoda 	sh_mmcif_bitclr(CLK_CLEAR, &host->regs->ce_clk_ctrl);
110afb35666SYoshihiro Shimoda 
111afb35666SYoshihiro Shimoda 	if (!clk)
112afb35666SYoshihiro Shimoda 		return;
11321ea3503SNobuhiro Iwamatsu 
11421ea3503SNobuhiro Iwamatsu 	if (clk == CLKDEV_EMMC_DATA)
115afb35666SYoshihiro Shimoda 		sh_mmcif_bitset(CLK_PCLK, &host->regs->ce_clk_ctrl);
11621ea3503SNobuhiro Iwamatsu 	else
11721ea3503SNobuhiro Iwamatsu 		sh_mmcif_bitset((fls(DIV_ROUND_UP(host->clk,
11821ea3503SNobuhiro Iwamatsu 						  clk) - 1) - 1) << 16,
11921ea3503SNobuhiro Iwamatsu 				&host->regs->ce_clk_ctrl);
120afb35666SYoshihiro Shimoda 	sh_mmcif_bitset(CLK_ENABLE, &host->regs->ce_clk_ctrl);
121afb35666SYoshihiro Shimoda }
122afb35666SYoshihiro Shimoda 
123afb35666SYoshihiro Shimoda static void sh_mmcif_sync_reset(struct sh_mmcif_host *host)
124afb35666SYoshihiro Shimoda {
125afb35666SYoshihiro Shimoda 	u32 tmp;
126afb35666SYoshihiro Shimoda 
127afb35666SYoshihiro Shimoda 	tmp = sh_mmcif_read(&host->regs->ce_clk_ctrl) & (CLK_ENABLE |
128afb35666SYoshihiro Shimoda 							 CLK_CLEAR);
129afb35666SYoshihiro Shimoda 
130afb35666SYoshihiro Shimoda 	sh_mmcif_write(SOFT_RST_ON, &host->regs->ce_version);
131afb35666SYoshihiro Shimoda 	sh_mmcif_write(SOFT_RST_OFF, &host->regs->ce_version);
132afb35666SYoshihiro Shimoda 	sh_mmcif_bitset(tmp | SRSPTO_256 | SRBSYTO_29 | SRWDTO_29 | SCCSTO_29,
133afb35666SYoshihiro Shimoda 			&host->regs->ce_clk_ctrl);
134afb35666SYoshihiro Shimoda 	/* byte swap on */
135afb35666SYoshihiro Shimoda 	sh_mmcif_bitset(BUF_ACC_ATYP, &host->regs->ce_buf_acc);
136afb35666SYoshihiro Shimoda }
137afb35666SYoshihiro Shimoda 
138afb35666SYoshihiro Shimoda static int sh_mmcif_error_manage(struct sh_mmcif_host *host)
139afb35666SYoshihiro Shimoda {
140afb35666SYoshihiro Shimoda 	u32 state1, state2;
141afb35666SYoshihiro Shimoda 	int ret, timeout = 10000000;
142afb35666SYoshihiro Shimoda 
143afb35666SYoshihiro Shimoda 	host->sd_error = 0;
144afb35666SYoshihiro Shimoda 	host->wait_int = 0;
145afb35666SYoshihiro Shimoda 
146afb35666SYoshihiro Shimoda 	state1 = sh_mmcif_read(&host->regs->ce_host_sts1);
147afb35666SYoshihiro Shimoda 	state2 = sh_mmcif_read(&host->regs->ce_host_sts2);
148afb35666SYoshihiro Shimoda 	debug("%s: ERR HOST_STS1 = %08x\n", \
149afb35666SYoshihiro Shimoda 			DRIVER_NAME, sh_mmcif_read(&host->regs->ce_host_sts1));
150afb35666SYoshihiro Shimoda 	debug("%s: ERR HOST_STS2 = %08x\n", \
151afb35666SYoshihiro Shimoda 			DRIVER_NAME, sh_mmcif_read(&host->regs->ce_host_sts2));
152afb35666SYoshihiro Shimoda 
153afb35666SYoshihiro Shimoda 	if (state1 & STS1_CMDSEQ) {
154afb35666SYoshihiro Shimoda 		debug("%s: Forced end of command sequence\n", DRIVER_NAME);
155afb35666SYoshihiro Shimoda 		sh_mmcif_bitset(CMD_CTRL_BREAK, &host->regs->ce_cmd_ctrl);
156afb35666SYoshihiro Shimoda 		sh_mmcif_bitset(~CMD_CTRL_BREAK, &host->regs->ce_cmd_ctrl);
157afb35666SYoshihiro Shimoda 		while (1) {
158afb35666SYoshihiro Shimoda 			timeout--;
159afb35666SYoshihiro Shimoda 			if (timeout < 0) {
160afb35666SYoshihiro Shimoda 				printf(DRIVER_NAME": Forceed end of " \
161afb35666SYoshihiro Shimoda 					"command sequence timeout err\n");
162afb35666SYoshihiro Shimoda 				return -EILSEQ;
163afb35666SYoshihiro Shimoda 			}
164afb35666SYoshihiro Shimoda 			if (!(sh_mmcif_read(&host->regs->ce_host_sts1)
165afb35666SYoshihiro Shimoda 								& STS1_CMDSEQ))
166afb35666SYoshihiro Shimoda 				break;
167afb35666SYoshihiro Shimoda 		}
168afb35666SYoshihiro Shimoda 		sh_mmcif_sync_reset(host);
169afb35666SYoshihiro Shimoda 		return -EILSEQ;
170afb35666SYoshihiro Shimoda 	}
171afb35666SYoshihiro Shimoda 
172afb35666SYoshihiro Shimoda 	if (state2 & STS2_CRC_ERR)
173afb35666SYoshihiro Shimoda 		ret = -EILSEQ;
174afb35666SYoshihiro Shimoda 	else if (state2 & STS2_TIMEOUT_ERR)
175915ffa52SJaehoon Chung 		ret = -ETIMEDOUT;
176afb35666SYoshihiro Shimoda 	else
177afb35666SYoshihiro Shimoda 		ret = -EILSEQ;
178afb35666SYoshihiro Shimoda 	return ret;
179afb35666SYoshihiro Shimoda }
180afb35666SYoshihiro Shimoda 
181afb35666SYoshihiro Shimoda static int sh_mmcif_single_read(struct sh_mmcif_host *host,
182afb35666SYoshihiro Shimoda 				struct mmc_data *data)
183afb35666SYoshihiro Shimoda {
184afb35666SYoshihiro Shimoda 	long time;
185afb35666SYoshihiro Shimoda 	u32 blocksize, i;
186afb35666SYoshihiro Shimoda 	unsigned long *p = (unsigned long *)data->dest;
187afb35666SYoshihiro Shimoda 
188afb35666SYoshihiro Shimoda 	if ((unsigned long)p & 0x00000001) {
189afb35666SYoshihiro Shimoda 		printf("%s: The data pointer is unaligned.", __func__);
190afb35666SYoshihiro Shimoda 		return -EIO;
191afb35666SYoshihiro Shimoda 	}
192afb35666SYoshihiro Shimoda 
193afb35666SYoshihiro Shimoda 	host->wait_int = 0;
194afb35666SYoshihiro Shimoda 
195afb35666SYoshihiro Shimoda 	/* buf read enable */
196afb35666SYoshihiro Shimoda 	sh_mmcif_bitset(MASK_MBUFREN, &host->regs->ce_int_mask);
197afb35666SYoshihiro Shimoda 	time = mmcif_wait_interrupt_flag(host);
198afb35666SYoshihiro Shimoda 	if (time == 0 || host->sd_error != 0)
199afb35666SYoshihiro Shimoda 		return sh_mmcif_error_manage(host);
200afb35666SYoshihiro Shimoda 
201afb35666SYoshihiro Shimoda 	host->wait_int = 0;
202afb35666SYoshihiro Shimoda 	blocksize = (BLOCK_SIZE_MASK &
203afb35666SYoshihiro Shimoda 			sh_mmcif_read(&host->regs->ce_block_set)) + 3;
204afb35666SYoshihiro Shimoda 	for (i = 0; i < blocksize / 4; i++)
205afb35666SYoshihiro Shimoda 		*p++ = sh_mmcif_read(&host->regs->ce_data);
206afb35666SYoshihiro Shimoda 
207afb35666SYoshihiro Shimoda 	/* buffer read end */
208afb35666SYoshihiro Shimoda 	sh_mmcif_bitset(MASK_MBUFRE, &host->regs->ce_int_mask);
209afb35666SYoshihiro Shimoda 	time = mmcif_wait_interrupt_flag(host);
210afb35666SYoshihiro Shimoda 	if (time == 0 || host->sd_error != 0)
211afb35666SYoshihiro Shimoda 		return sh_mmcif_error_manage(host);
212afb35666SYoshihiro Shimoda 
213afb35666SYoshihiro Shimoda 	host->wait_int = 0;
214afb35666SYoshihiro Shimoda 	return 0;
215afb35666SYoshihiro Shimoda }
216afb35666SYoshihiro Shimoda 
217afb35666SYoshihiro Shimoda static int sh_mmcif_multi_read(struct sh_mmcif_host *host,
218afb35666SYoshihiro Shimoda 				struct mmc_data *data)
219afb35666SYoshihiro Shimoda {
220afb35666SYoshihiro Shimoda 	long time;
221afb35666SYoshihiro Shimoda 	u32 blocksize, i, j;
222afb35666SYoshihiro Shimoda 	unsigned long *p = (unsigned long *)data->dest;
223afb35666SYoshihiro Shimoda 
224afb35666SYoshihiro Shimoda 	if ((unsigned long)p & 0x00000001) {
225afb35666SYoshihiro Shimoda 		printf("%s: The data pointer is unaligned.", __func__);
226afb35666SYoshihiro Shimoda 		return -EIO;
227afb35666SYoshihiro Shimoda 	}
228afb35666SYoshihiro Shimoda 
229afb35666SYoshihiro Shimoda 	host->wait_int = 0;
230afb35666SYoshihiro Shimoda 	blocksize = BLOCK_SIZE_MASK & sh_mmcif_read(&host->regs->ce_block_set);
231afb35666SYoshihiro Shimoda 	for (j = 0; j < data->blocks; j++) {
232afb35666SYoshihiro Shimoda 		sh_mmcif_bitset(MASK_MBUFREN, &host->regs->ce_int_mask);
233afb35666SYoshihiro Shimoda 		time = mmcif_wait_interrupt_flag(host);
234afb35666SYoshihiro Shimoda 		if (time == 0 || host->sd_error != 0)
235afb35666SYoshihiro Shimoda 			return sh_mmcif_error_manage(host);
236afb35666SYoshihiro Shimoda 
237afb35666SYoshihiro Shimoda 		host->wait_int = 0;
238afb35666SYoshihiro Shimoda 		for (i = 0; i < blocksize / 4; i++)
239afb35666SYoshihiro Shimoda 			*p++ = sh_mmcif_read(&host->regs->ce_data);
240afb35666SYoshihiro Shimoda 
241afb35666SYoshihiro Shimoda 		WATCHDOG_RESET();
242afb35666SYoshihiro Shimoda 	}
243afb35666SYoshihiro Shimoda 	return 0;
244afb35666SYoshihiro Shimoda }
245afb35666SYoshihiro Shimoda 
246afb35666SYoshihiro Shimoda static int sh_mmcif_single_write(struct sh_mmcif_host *host,
247afb35666SYoshihiro Shimoda 				 struct mmc_data *data)
248afb35666SYoshihiro Shimoda {
249afb35666SYoshihiro Shimoda 	long time;
250afb35666SYoshihiro Shimoda 	u32 blocksize, i;
251afb35666SYoshihiro Shimoda 	const unsigned long *p = (unsigned long *)data->dest;
252afb35666SYoshihiro Shimoda 
253afb35666SYoshihiro Shimoda 	if ((unsigned long)p & 0x00000001) {
254afb35666SYoshihiro Shimoda 		printf("%s: The data pointer is unaligned.", __func__);
255afb35666SYoshihiro Shimoda 		return -EIO;
256afb35666SYoshihiro Shimoda 	}
257afb35666SYoshihiro Shimoda 
258afb35666SYoshihiro Shimoda 	host->wait_int = 0;
259afb35666SYoshihiro Shimoda 	sh_mmcif_bitset(MASK_MBUFWEN, &host->regs->ce_int_mask);
260afb35666SYoshihiro Shimoda 
261afb35666SYoshihiro Shimoda 	time = mmcif_wait_interrupt_flag(host);
262afb35666SYoshihiro Shimoda 	if (time == 0 || host->sd_error != 0)
263afb35666SYoshihiro Shimoda 		return sh_mmcif_error_manage(host);
264afb35666SYoshihiro Shimoda 
265afb35666SYoshihiro Shimoda 	host->wait_int = 0;
266afb35666SYoshihiro Shimoda 	blocksize = (BLOCK_SIZE_MASK &
267afb35666SYoshihiro Shimoda 			sh_mmcif_read(&host->regs->ce_block_set)) + 3;
268afb35666SYoshihiro Shimoda 	for (i = 0; i < blocksize / 4; i++)
269afb35666SYoshihiro Shimoda 		sh_mmcif_write(*p++, &host->regs->ce_data);
270afb35666SYoshihiro Shimoda 
271afb35666SYoshihiro Shimoda 	/* buffer write end */
272afb35666SYoshihiro Shimoda 	sh_mmcif_bitset(MASK_MDTRANE, &host->regs->ce_int_mask);
273afb35666SYoshihiro Shimoda 
274afb35666SYoshihiro Shimoda 	time = mmcif_wait_interrupt_flag(host);
275afb35666SYoshihiro Shimoda 	if (time == 0 || host->sd_error != 0)
276afb35666SYoshihiro Shimoda 		return sh_mmcif_error_manage(host);
277afb35666SYoshihiro Shimoda 
278afb35666SYoshihiro Shimoda 	host->wait_int = 0;
279afb35666SYoshihiro Shimoda 	return 0;
280afb35666SYoshihiro Shimoda }
281afb35666SYoshihiro Shimoda 
282afb35666SYoshihiro Shimoda static int sh_mmcif_multi_write(struct sh_mmcif_host *host,
283afb35666SYoshihiro Shimoda 				struct mmc_data *data)
284afb35666SYoshihiro Shimoda {
285afb35666SYoshihiro Shimoda 	long time;
286afb35666SYoshihiro Shimoda 	u32 i, j, blocksize;
287afb35666SYoshihiro Shimoda 	const unsigned long *p = (unsigned long *)data->dest;
288afb35666SYoshihiro Shimoda 
289afb35666SYoshihiro Shimoda 	if ((unsigned long)p & 0x00000001) {
290afb35666SYoshihiro Shimoda 		printf("%s: The data pointer is unaligned.", __func__);
291afb35666SYoshihiro Shimoda 		return -EIO;
292afb35666SYoshihiro Shimoda 	}
293afb35666SYoshihiro Shimoda 
294afb35666SYoshihiro Shimoda 	host->wait_int = 0;
295afb35666SYoshihiro Shimoda 	blocksize = BLOCK_SIZE_MASK & sh_mmcif_read(&host->regs->ce_block_set);
296afb35666SYoshihiro Shimoda 	for (j = 0; j < data->blocks; j++) {
297afb35666SYoshihiro Shimoda 		sh_mmcif_bitset(MASK_MBUFWEN, &host->regs->ce_int_mask);
298afb35666SYoshihiro Shimoda 
299afb35666SYoshihiro Shimoda 		time = mmcif_wait_interrupt_flag(host);
300afb35666SYoshihiro Shimoda 
301afb35666SYoshihiro Shimoda 		if (time == 0 || host->sd_error != 0)
302afb35666SYoshihiro Shimoda 			return sh_mmcif_error_manage(host);
303afb35666SYoshihiro Shimoda 
304afb35666SYoshihiro Shimoda 		host->wait_int = 0;
305afb35666SYoshihiro Shimoda 		for (i = 0; i < blocksize / 4; i++)
306afb35666SYoshihiro Shimoda 			sh_mmcif_write(*p++, &host->regs->ce_data);
307afb35666SYoshihiro Shimoda 
308afb35666SYoshihiro Shimoda 		WATCHDOG_RESET();
309afb35666SYoshihiro Shimoda 	}
310afb35666SYoshihiro Shimoda 	return 0;
311afb35666SYoshihiro Shimoda }
312afb35666SYoshihiro Shimoda 
313afb35666SYoshihiro Shimoda static void sh_mmcif_get_response(struct sh_mmcif_host *host,
314afb35666SYoshihiro Shimoda 					struct mmc_cmd *cmd)
315afb35666SYoshihiro Shimoda {
316afb35666SYoshihiro Shimoda 	if (cmd->resp_type & MMC_RSP_136) {
317afb35666SYoshihiro Shimoda 		cmd->response[0] = sh_mmcif_read(&host->regs->ce_resp3);
318afb35666SYoshihiro Shimoda 		cmd->response[1] = sh_mmcif_read(&host->regs->ce_resp2);
319afb35666SYoshihiro Shimoda 		cmd->response[2] = sh_mmcif_read(&host->regs->ce_resp1);
320afb35666SYoshihiro Shimoda 		cmd->response[3] = sh_mmcif_read(&host->regs->ce_resp0);
321afb35666SYoshihiro Shimoda 		debug(" RESP %08x, %08x, %08x, %08x\n", cmd->response[0],
322afb35666SYoshihiro Shimoda 			 cmd->response[1], cmd->response[2], cmd->response[3]);
323afb35666SYoshihiro Shimoda 	} else {
324afb35666SYoshihiro Shimoda 		cmd->response[0] = sh_mmcif_read(&host->regs->ce_resp0);
325afb35666SYoshihiro Shimoda 	}
326afb35666SYoshihiro Shimoda }
327afb35666SYoshihiro Shimoda 
328afb35666SYoshihiro Shimoda static void sh_mmcif_get_cmd12response(struct sh_mmcif_host *host,
329afb35666SYoshihiro Shimoda 					struct mmc_cmd *cmd)
330afb35666SYoshihiro Shimoda {
331afb35666SYoshihiro Shimoda 	cmd->response[0] = sh_mmcif_read(&host->regs->ce_resp_cmd12);
332afb35666SYoshihiro Shimoda }
333afb35666SYoshihiro Shimoda 
334afb35666SYoshihiro Shimoda static u32 sh_mmcif_set_cmd(struct sh_mmcif_host *host,
335afb35666SYoshihiro Shimoda 				struct mmc_data *data, struct mmc_cmd *cmd)
336afb35666SYoshihiro Shimoda {
337afb35666SYoshihiro Shimoda 	u32 tmp = 0;
338afb35666SYoshihiro Shimoda 	u32 opc = cmd->cmdidx;
339afb35666SYoshihiro Shimoda 
340afb35666SYoshihiro Shimoda 	/* Response Type check */
341afb35666SYoshihiro Shimoda 	switch (cmd->resp_type) {
342afb35666SYoshihiro Shimoda 	case MMC_RSP_NONE:
343afb35666SYoshihiro Shimoda 		tmp |= CMD_SET_RTYP_NO;
344afb35666SYoshihiro Shimoda 		break;
345afb35666SYoshihiro Shimoda 	case MMC_RSP_R1:
346afb35666SYoshihiro Shimoda 	case MMC_RSP_R1b:
347afb35666SYoshihiro Shimoda 	case MMC_RSP_R3:
348afb35666SYoshihiro Shimoda 		tmp |= CMD_SET_RTYP_6B;
349afb35666SYoshihiro Shimoda 		break;
350afb35666SYoshihiro Shimoda 	case MMC_RSP_R2:
351afb35666SYoshihiro Shimoda 		tmp |= CMD_SET_RTYP_17B;
352afb35666SYoshihiro Shimoda 		break;
353afb35666SYoshihiro Shimoda 	default:
354afb35666SYoshihiro Shimoda 		printf(DRIVER_NAME": Not support type response.\n");
355afb35666SYoshihiro Shimoda 		break;
356afb35666SYoshihiro Shimoda 	}
357afb35666SYoshihiro Shimoda 
358afb35666SYoshihiro Shimoda 	/* RBSY */
359afb35666SYoshihiro Shimoda 	if (opc == MMC_CMD_SWITCH)
360afb35666SYoshihiro Shimoda 		tmp |= CMD_SET_RBSY;
361afb35666SYoshihiro Shimoda 
362afb35666SYoshihiro Shimoda 	/* WDAT / DATW */
363afb35666SYoshihiro Shimoda 	if (host->data) {
364afb35666SYoshihiro Shimoda 		tmp |= CMD_SET_WDAT;
365afb35666SYoshihiro Shimoda 		switch (host->bus_width) {
366afb35666SYoshihiro Shimoda 		case MMC_BUS_WIDTH_1:
367afb35666SYoshihiro Shimoda 			tmp |= CMD_SET_DATW_1;
368afb35666SYoshihiro Shimoda 			break;
369afb35666SYoshihiro Shimoda 		case MMC_BUS_WIDTH_4:
370afb35666SYoshihiro Shimoda 			tmp |= CMD_SET_DATW_4;
371afb35666SYoshihiro Shimoda 			break;
372afb35666SYoshihiro Shimoda 		case MMC_BUS_WIDTH_8:
373afb35666SYoshihiro Shimoda 			tmp |= CMD_SET_DATW_8;
374afb35666SYoshihiro Shimoda 			break;
375afb35666SYoshihiro Shimoda 		default:
376afb35666SYoshihiro Shimoda 			printf(DRIVER_NAME": Not support bus width.\n");
377afb35666SYoshihiro Shimoda 			break;
378afb35666SYoshihiro Shimoda 		}
379afb35666SYoshihiro Shimoda 	}
380afb35666SYoshihiro Shimoda 	/* DWEN */
381afb35666SYoshihiro Shimoda 	if (opc == MMC_CMD_WRITE_SINGLE_BLOCK ||
382afb35666SYoshihiro Shimoda 	    opc == MMC_CMD_WRITE_MULTIPLE_BLOCK)
383afb35666SYoshihiro Shimoda 		tmp |= CMD_SET_DWEN;
384afb35666SYoshihiro Shimoda 	/* CMLTE/CMD12EN */
385afb35666SYoshihiro Shimoda 	if (opc == MMC_CMD_READ_MULTIPLE_BLOCK ||
386afb35666SYoshihiro Shimoda 	    opc == MMC_CMD_WRITE_MULTIPLE_BLOCK) {
387afb35666SYoshihiro Shimoda 		tmp |= CMD_SET_CMLTE | CMD_SET_CMD12EN;
388afb35666SYoshihiro Shimoda 		sh_mmcif_bitset(data->blocks << 16, &host->regs->ce_block_set);
389afb35666SYoshihiro Shimoda 	}
390afb35666SYoshihiro Shimoda 	/* RIDXC[1:0] check bits */
391afb35666SYoshihiro Shimoda 	if (opc == MMC_CMD_SEND_OP_COND || opc == MMC_CMD_ALL_SEND_CID ||
392afb35666SYoshihiro Shimoda 	    opc == MMC_CMD_SEND_CSD || opc == MMC_CMD_SEND_CID)
393afb35666SYoshihiro Shimoda 		tmp |= CMD_SET_RIDXC_BITS;
394afb35666SYoshihiro Shimoda 	/* RCRC7C[1:0] check bits */
395afb35666SYoshihiro Shimoda 	if (opc == MMC_CMD_SEND_OP_COND)
396afb35666SYoshihiro Shimoda 		tmp |= CMD_SET_CRC7C_BITS;
397afb35666SYoshihiro Shimoda 	/* RCRC7C[1:0] internal CRC7 */
398afb35666SYoshihiro Shimoda 	if (opc == MMC_CMD_ALL_SEND_CID ||
399afb35666SYoshihiro Shimoda 		opc == MMC_CMD_SEND_CSD || opc == MMC_CMD_SEND_CID)
400afb35666SYoshihiro Shimoda 		tmp |= CMD_SET_CRC7C_INTERNAL;
401afb35666SYoshihiro Shimoda 
402afb35666SYoshihiro Shimoda 	return opc = ((opc << 24) | tmp);
403afb35666SYoshihiro Shimoda }
404afb35666SYoshihiro Shimoda 
405afb35666SYoshihiro Shimoda static u32 sh_mmcif_data_trans(struct sh_mmcif_host *host,
406afb35666SYoshihiro Shimoda 				struct mmc_data *data, u16 opc)
407afb35666SYoshihiro Shimoda {
408afb35666SYoshihiro Shimoda 	u32 ret;
409afb35666SYoshihiro Shimoda 
410afb35666SYoshihiro Shimoda 	switch (opc) {
411afb35666SYoshihiro Shimoda 	case MMC_CMD_READ_MULTIPLE_BLOCK:
412afb35666SYoshihiro Shimoda 		ret = sh_mmcif_multi_read(host, data);
413afb35666SYoshihiro Shimoda 		break;
414afb35666SYoshihiro Shimoda 	case MMC_CMD_WRITE_MULTIPLE_BLOCK:
415afb35666SYoshihiro Shimoda 		ret = sh_mmcif_multi_write(host, data);
416afb35666SYoshihiro Shimoda 		break;
417afb35666SYoshihiro Shimoda 	case MMC_CMD_WRITE_SINGLE_BLOCK:
418afb35666SYoshihiro Shimoda 		ret = sh_mmcif_single_write(host, data);
419afb35666SYoshihiro Shimoda 		break;
420afb35666SYoshihiro Shimoda 	case MMC_CMD_READ_SINGLE_BLOCK:
421afb35666SYoshihiro Shimoda 	case MMC_CMD_SEND_EXT_CSD:
422afb35666SYoshihiro Shimoda 		ret = sh_mmcif_single_read(host, data);
423afb35666SYoshihiro Shimoda 		break;
424afb35666SYoshihiro Shimoda 	default:
425afb35666SYoshihiro Shimoda 		printf(DRIVER_NAME": NOT SUPPORT CMD = d'%08d\n", opc);
426afb35666SYoshihiro Shimoda 		ret = -EINVAL;
427afb35666SYoshihiro Shimoda 		break;
428afb35666SYoshihiro Shimoda 	}
429afb35666SYoshihiro Shimoda 	return ret;
430afb35666SYoshihiro Shimoda }
431afb35666SYoshihiro Shimoda 
432afb35666SYoshihiro Shimoda static int sh_mmcif_start_cmd(struct sh_mmcif_host *host,
433afb35666SYoshihiro Shimoda 				struct mmc_data *data, struct mmc_cmd *cmd)
434afb35666SYoshihiro Shimoda {
435afb35666SYoshihiro Shimoda 	long time;
436afb35666SYoshihiro Shimoda 	int ret = 0, mask = 0;
437afb35666SYoshihiro Shimoda 	u32 opc = cmd->cmdidx;
438afb35666SYoshihiro Shimoda 
439afb35666SYoshihiro Shimoda 	if (opc == MMC_CMD_STOP_TRANSMISSION) {
440afb35666SYoshihiro Shimoda 		/* MMCIF sends the STOP command automatically */
441afb35666SYoshihiro Shimoda 		if (host->last_cmd == MMC_CMD_READ_MULTIPLE_BLOCK)
442afb35666SYoshihiro Shimoda 			sh_mmcif_bitset(MASK_MCMD12DRE,
443afb35666SYoshihiro Shimoda 					&host->regs->ce_int_mask);
444afb35666SYoshihiro Shimoda 		else
445afb35666SYoshihiro Shimoda 			sh_mmcif_bitset(MASK_MCMD12RBE,
446afb35666SYoshihiro Shimoda 					&host->regs->ce_int_mask);
447afb35666SYoshihiro Shimoda 
448afb35666SYoshihiro Shimoda 		time = mmcif_wait_interrupt_flag(host);
449afb35666SYoshihiro Shimoda 		if (time == 0 || host->sd_error != 0)
450afb35666SYoshihiro Shimoda 			return sh_mmcif_error_manage(host);
451afb35666SYoshihiro Shimoda 
452afb35666SYoshihiro Shimoda 		sh_mmcif_get_cmd12response(host, cmd);
453afb35666SYoshihiro Shimoda 		return 0;
454afb35666SYoshihiro Shimoda 	}
455afb35666SYoshihiro Shimoda 	if (opc == MMC_CMD_SWITCH)
456afb35666SYoshihiro Shimoda 		mask = MASK_MRBSYE;
457afb35666SYoshihiro Shimoda 	else
458afb35666SYoshihiro Shimoda 		mask = MASK_MCRSPE;
459afb35666SYoshihiro Shimoda 
460afb35666SYoshihiro Shimoda 	mask |=	MASK_MCMDVIO | MASK_MBUFVIO | MASK_MWDATERR |
461afb35666SYoshihiro Shimoda 		MASK_MRDATERR | MASK_MRIDXERR | MASK_MRSPERR |
462afb35666SYoshihiro Shimoda 		MASK_MCCSTO | MASK_MCRCSTO | MASK_MWDATTO |
463afb35666SYoshihiro Shimoda 		MASK_MRDATTO | MASK_MRBSYTO | MASK_MRSPTO;
464afb35666SYoshihiro Shimoda 
465afb35666SYoshihiro Shimoda 	if (host->data) {
466afb35666SYoshihiro Shimoda 		sh_mmcif_write(0, &host->regs->ce_block_set);
467afb35666SYoshihiro Shimoda 		sh_mmcif_write(data->blocksize, &host->regs->ce_block_set);
468afb35666SYoshihiro Shimoda 	}
469afb35666SYoshihiro Shimoda 	opc = sh_mmcif_set_cmd(host, data, cmd);
470afb35666SYoshihiro Shimoda 
471afb35666SYoshihiro Shimoda 	sh_mmcif_write(INT_START_MAGIC, &host->regs->ce_int);
472afb35666SYoshihiro Shimoda 	sh_mmcif_write(mask, &host->regs->ce_int_mask);
473afb35666SYoshihiro Shimoda 
474afb35666SYoshihiro Shimoda 	debug("CMD%d ARG:%08x\n", cmd->cmdidx, cmd->cmdarg);
475afb35666SYoshihiro Shimoda 	/* set arg */
476afb35666SYoshihiro Shimoda 	sh_mmcif_write(cmd->cmdarg, &host->regs->ce_arg);
477afb35666SYoshihiro Shimoda 	host->wait_int = 0;
478afb35666SYoshihiro Shimoda 	/* set cmd */
479afb35666SYoshihiro Shimoda 	sh_mmcif_write(opc, &host->regs->ce_cmd_set);
480afb35666SYoshihiro Shimoda 
481afb35666SYoshihiro Shimoda 	time = mmcif_wait_interrupt_flag(host);
482afb35666SYoshihiro Shimoda 	if (time == 0)
483afb35666SYoshihiro Shimoda 		return sh_mmcif_error_manage(host);
484afb35666SYoshihiro Shimoda 
485afb35666SYoshihiro Shimoda 	if (host->sd_error) {
486afb35666SYoshihiro Shimoda 		switch (cmd->cmdidx) {
487afb35666SYoshihiro Shimoda 		case MMC_CMD_ALL_SEND_CID:
488afb35666SYoshihiro Shimoda 		case MMC_CMD_SELECT_CARD:
489afb35666SYoshihiro Shimoda 		case MMC_CMD_APP_CMD:
490915ffa52SJaehoon Chung 			ret = -ETIMEDOUT;
491afb35666SYoshihiro Shimoda 			break;
492afb35666SYoshihiro Shimoda 		default:
493afb35666SYoshihiro Shimoda 			printf(DRIVER_NAME": Cmd(d'%d) err\n", cmd->cmdidx);
494afb35666SYoshihiro Shimoda 			ret = sh_mmcif_error_manage(host);
495afb35666SYoshihiro Shimoda 			break;
496afb35666SYoshihiro Shimoda 		}
497afb35666SYoshihiro Shimoda 		host->sd_error = 0;
498afb35666SYoshihiro Shimoda 		host->wait_int = 0;
499afb35666SYoshihiro Shimoda 		return ret;
500afb35666SYoshihiro Shimoda 	}
501afb35666SYoshihiro Shimoda 
502afb35666SYoshihiro Shimoda 	/* if no response */
503afb35666SYoshihiro Shimoda 	if (!(opc & 0x00C00000))
504afb35666SYoshihiro Shimoda 		return 0;
505afb35666SYoshihiro Shimoda 
506afb35666SYoshihiro Shimoda 	if (host->wait_int == 1) {
507afb35666SYoshihiro Shimoda 		sh_mmcif_get_response(host, cmd);
508afb35666SYoshihiro Shimoda 		host->wait_int = 0;
509afb35666SYoshihiro Shimoda 	}
510afb35666SYoshihiro Shimoda 	if (host->data)
511afb35666SYoshihiro Shimoda 		ret = sh_mmcif_data_trans(host, data, cmd->cmdidx);
512afb35666SYoshihiro Shimoda 	host->last_cmd = cmd->cmdidx;
513afb35666SYoshihiro Shimoda 
514afb35666SYoshihiro Shimoda 	return ret;
515afb35666SYoshihiro Shimoda }
516afb35666SYoshihiro Shimoda 
517*48f54a2dSMarek Vasut static int sh_mmcif_send_cmd_common(struct sh_mmcif_host *host,
518*48f54a2dSMarek Vasut 				    struct mmc_cmd *cmd, struct mmc_data *data)
519afb35666SYoshihiro Shimoda {
520afb35666SYoshihiro Shimoda 	int ret;
521afb35666SYoshihiro Shimoda 
522afb35666SYoshihiro Shimoda 	WATCHDOG_RESET();
523afb35666SYoshihiro Shimoda 
524afb35666SYoshihiro Shimoda 	switch (cmd->cmdidx) {
525afb35666SYoshihiro Shimoda 	case MMC_CMD_APP_CMD:
526915ffa52SJaehoon Chung 		return -ETIMEDOUT;
527afb35666SYoshihiro Shimoda 	case MMC_CMD_SEND_EXT_CSD: /* = SD_SEND_IF_COND (8) */
528afb35666SYoshihiro Shimoda 		if (data)
529afb35666SYoshihiro Shimoda 			/* ext_csd */
530afb35666SYoshihiro Shimoda 			break;
531afb35666SYoshihiro Shimoda 		else
532afb35666SYoshihiro Shimoda 			/* send_if_cond cmd (not support) */
533915ffa52SJaehoon Chung 			return -ETIMEDOUT;
534afb35666SYoshihiro Shimoda 	default:
535afb35666SYoshihiro Shimoda 		break;
536afb35666SYoshihiro Shimoda 	}
537afb35666SYoshihiro Shimoda 	host->sd_error = 0;
538afb35666SYoshihiro Shimoda 	host->data = data;
539afb35666SYoshihiro Shimoda 	ret = sh_mmcif_start_cmd(host, data, cmd);
540afb35666SYoshihiro Shimoda 	host->data = NULL;
541afb35666SYoshihiro Shimoda 
542afb35666SYoshihiro Shimoda 	return ret;
543afb35666SYoshihiro Shimoda }
544afb35666SYoshihiro Shimoda 
545*48f54a2dSMarek Vasut static int sh_mmcif_set_ios_common(struct sh_mmcif_host *host, struct mmc *mmc)
546afb35666SYoshihiro Shimoda {
547afb35666SYoshihiro Shimoda 	if (mmc->clock)
548afb35666SYoshihiro Shimoda 		sh_mmcif_clock_control(host, mmc->clock);
549afb35666SYoshihiro Shimoda 
550afb35666SYoshihiro Shimoda 	if (mmc->bus_width == 8)
551afb35666SYoshihiro Shimoda 		host->bus_width = MMC_BUS_WIDTH_8;
552afb35666SYoshihiro Shimoda 	else if (mmc->bus_width == 4)
553afb35666SYoshihiro Shimoda 		host->bus_width = MMC_BUS_WIDTH_4;
554afb35666SYoshihiro Shimoda 	else
555afb35666SYoshihiro Shimoda 		host->bus_width = MMC_BUS_WIDTH_1;
556afb35666SYoshihiro Shimoda 
557afb35666SYoshihiro Shimoda 	debug("clock = %d, buswidth = %d\n", mmc->clock, mmc->bus_width);
55807b0b9c0SJaehoon Chung 
55907b0b9c0SJaehoon Chung 	return 0;
560afb35666SYoshihiro Shimoda }
561afb35666SYoshihiro Shimoda 
562*48f54a2dSMarek Vasut static int sh_mmcif_initialize_common(struct sh_mmcif_host *host)
563afb35666SYoshihiro Shimoda {
564afb35666SYoshihiro Shimoda 	sh_mmcif_sync_reset(host);
565afb35666SYoshihiro Shimoda 	sh_mmcif_write(MASK_ALL, &host->regs->ce_int_mask);
566afb35666SYoshihiro Shimoda 	return 0;
567afb35666SYoshihiro Shimoda }
568afb35666SYoshihiro Shimoda 
569*48f54a2dSMarek Vasut #ifndef CONFIG_DM_MMC
570*48f54a2dSMarek Vasut static void *mmc_priv(struct mmc *mmc)
571*48f54a2dSMarek Vasut {
572*48f54a2dSMarek Vasut 	return (void *)mmc->priv;
573*48f54a2dSMarek Vasut }
574*48f54a2dSMarek Vasut 
575*48f54a2dSMarek Vasut static int sh_mmcif_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd,
576*48f54a2dSMarek Vasut 			    struct mmc_data *data)
577*48f54a2dSMarek Vasut {
578*48f54a2dSMarek Vasut 	struct sh_mmcif_host *host = mmc_priv(mmc);
579*48f54a2dSMarek Vasut 
580*48f54a2dSMarek Vasut 	return sh_mmcif_send_cmd_common(host, cmd, data);
581*48f54a2dSMarek Vasut }
582*48f54a2dSMarek Vasut 
583*48f54a2dSMarek Vasut static int sh_mmcif_set_ios(struct mmc *mmc)
584*48f54a2dSMarek Vasut {
585*48f54a2dSMarek Vasut 	struct sh_mmcif_host *host = mmc_priv(mmc);
586*48f54a2dSMarek Vasut 
587*48f54a2dSMarek Vasut 	return sh_mmcif_set_ios_common(host, mmc);
588*48f54a2dSMarek Vasut }
589*48f54a2dSMarek Vasut 
590*48f54a2dSMarek Vasut static int sh_mmcif_initialize(struct mmc *mmc)
591*48f54a2dSMarek Vasut {
592*48f54a2dSMarek Vasut 	struct sh_mmcif_host *host = mmc_priv(mmc);
593*48f54a2dSMarek Vasut 
594*48f54a2dSMarek Vasut 	return sh_mmcif_initialize_common(host);
595*48f54a2dSMarek Vasut }
596*48f54a2dSMarek Vasut 
597ab769f22SPantelis Antoniou static const struct mmc_ops sh_mmcif_ops = {
598*48f54a2dSMarek Vasut 	.send_cmd       = sh_mmcif_send_cmd,
599ab769f22SPantelis Antoniou 	.set_ios        = sh_mmcif_set_ios,
600*48f54a2dSMarek Vasut 	.init           = sh_mmcif_initialize,
601ab769f22SPantelis Antoniou };
602ab769f22SPantelis Antoniou 
60393bfd616SPantelis Antoniou static struct mmc_config sh_mmcif_cfg = {
60493bfd616SPantelis Antoniou 	.name		= DRIVER_NAME,
60593bfd616SPantelis Antoniou 	.ops		= &sh_mmcif_ops,
60693bfd616SPantelis Antoniou 	.host_caps	= MMC_MODE_HS | MMC_MODE_HS_52MHz | MMC_MODE_4BIT |
6075a20397bSRob Herring 			  MMC_MODE_8BIT,
608cd2bf484SNobuhiro Iwamatsu 	.voltages	= MMC_VDD_32_33 | MMC_VDD_33_34,
60993bfd616SPantelis Antoniou 	.b_max		= CONFIG_SYS_MMC_MAX_BLK_COUNT,
61093bfd616SPantelis Antoniou };
61193bfd616SPantelis Antoniou 
612afb35666SYoshihiro Shimoda int mmcif_mmc_init(void)
613afb35666SYoshihiro Shimoda {
614afb35666SYoshihiro Shimoda 	struct mmc *mmc;
615afb35666SYoshihiro Shimoda 	struct sh_mmcif_host *host = NULL;
616afb35666SYoshihiro Shimoda 
617afb35666SYoshihiro Shimoda 	host = malloc(sizeof(struct sh_mmcif_host));
618afb35666SYoshihiro Shimoda 	if (!host)
61974c32ef5SNobuhiro Iwamatsu 		return -ENOMEM;
620afb35666SYoshihiro Shimoda 	memset(host, 0, sizeof(*host));
621afb35666SYoshihiro Shimoda 
622afb35666SYoshihiro Shimoda 	host->regs = (struct sh_mmcif_regs *)CONFIG_SH_MMCIF_ADDR;
623afb35666SYoshihiro Shimoda 	host->clk = CONFIG_SH_MMCIF_CLK;
624afb35666SYoshihiro Shimoda 
6257a7eb983SNobuhiro Iwamatsu 	sh_mmcif_cfg.f_min = MMC_CLK_DIV_MIN(host->clk);
6269675f610SNobuhiro Iwamatsu 	sh_mmcif_cfg.f_max = MMC_CLK_DIV_MAX(host->clk);
6277a7eb983SNobuhiro Iwamatsu 
62893bfd616SPantelis Antoniou 	mmc = mmc_create(&sh_mmcif_cfg, host);
62993bfd616SPantelis Antoniou 	if (mmc == NULL) {
63093bfd616SPantelis Antoniou 		free(host);
63193bfd616SPantelis Antoniou 		return -ENOMEM;
63293bfd616SPantelis Antoniou 	}
633afb35666SYoshihiro Shimoda 
63493bfd616SPantelis Antoniou 	return 0;
635afb35666SYoshihiro Shimoda }
636*48f54a2dSMarek Vasut 
637*48f54a2dSMarek Vasut #else
638*48f54a2dSMarek Vasut struct sh_mmcif_plat {
639*48f54a2dSMarek Vasut 	struct mmc_config cfg;
640*48f54a2dSMarek Vasut 	struct mmc mmc;
641*48f54a2dSMarek Vasut };
642*48f54a2dSMarek Vasut 
643*48f54a2dSMarek Vasut int sh_mmcif_dm_send_cmd(struct udevice *dev, struct mmc_cmd *cmd,
644*48f54a2dSMarek Vasut 			struct mmc_data *data)
645*48f54a2dSMarek Vasut {
646*48f54a2dSMarek Vasut 	struct sh_mmcif_host *host = dev_get_priv(dev);
647*48f54a2dSMarek Vasut 
648*48f54a2dSMarek Vasut 	return sh_mmcif_send_cmd_common(host, cmd, data);
649*48f54a2dSMarek Vasut }
650*48f54a2dSMarek Vasut 
651*48f54a2dSMarek Vasut int sh_mmcif_dm_set_ios(struct udevice *dev)
652*48f54a2dSMarek Vasut {
653*48f54a2dSMarek Vasut 	struct sh_mmcif_host *host = dev_get_priv(dev);
654*48f54a2dSMarek Vasut 	struct mmc *mmc = mmc_get_mmc_dev(dev);
655*48f54a2dSMarek Vasut 
656*48f54a2dSMarek Vasut 	return sh_mmcif_set_ios_common(host, mmc);
657*48f54a2dSMarek Vasut }
658*48f54a2dSMarek Vasut 
659*48f54a2dSMarek Vasut static const struct dm_mmc_ops sh_mmcif_dm_ops = {
660*48f54a2dSMarek Vasut 	.send_cmd	= sh_mmcif_dm_send_cmd,
661*48f54a2dSMarek Vasut 	.set_ios	= sh_mmcif_dm_set_ios,
662*48f54a2dSMarek Vasut };
663*48f54a2dSMarek Vasut 
664*48f54a2dSMarek Vasut static int sh_mmcif_dm_bind(struct udevice *dev)
665*48f54a2dSMarek Vasut {
666*48f54a2dSMarek Vasut 	struct sh_mmcif_plat *plat = dev_get_platdata(dev);
667*48f54a2dSMarek Vasut 
668*48f54a2dSMarek Vasut 	return mmc_bind(dev, &plat->mmc, &plat->cfg);
669*48f54a2dSMarek Vasut }
670*48f54a2dSMarek Vasut 
671*48f54a2dSMarek Vasut static int sh_mmcif_dm_probe(struct udevice *dev)
672*48f54a2dSMarek Vasut {
673*48f54a2dSMarek Vasut 	struct sh_mmcif_plat *plat = dev_get_platdata(dev);
674*48f54a2dSMarek Vasut 	struct sh_mmcif_host *host = dev_get_priv(dev);
675*48f54a2dSMarek Vasut 	struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev);
676*48f54a2dSMarek Vasut 	struct clk sh_mmcif_clk;
677*48f54a2dSMarek Vasut 	fdt_addr_t base;
678*48f54a2dSMarek Vasut 	int ret;
679*48f54a2dSMarek Vasut 
680*48f54a2dSMarek Vasut 	base = devfdt_get_addr(dev);
681*48f54a2dSMarek Vasut 	if (base == FDT_ADDR_T_NONE)
682*48f54a2dSMarek Vasut 		return -EINVAL;
683*48f54a2dSMarek Vasut 
684*48f54a2dSMarek Vasut 	host->regs = (struct sh_mmcif_regs *)devm_ioremap(dev, base, SZ_2K);
685*48f54a2dSMarek Vasut 	if (!host->regs)
686*48f54a2dSMarek Vasut 		return -ENOMEM;
687*48f54a2dSMarek Vasut 
688*48f54a2dSMarek Vasut 	ret = clk_get_by_index(dev, 0, &sh_mmcif_clk);
689*48f54a2dSMarek Vasut 	if (ret) {
690*48f54a2dSMarek Vasut 		debug("failed to get clock, ret=%d\n", ret);
691*48f54a2dSMarek Vasut 		return ret;
692*48f54a2dSMarek Vasut 	}
693*48f54a2dSMarek Vasut 
694*48f54a2dSMarek Vasut 	ret = clk_enable(&sh_mmcif_clk);
695*48f54a2dSMarek Vasut 	if (ret) {
696*48f54a2dSMarek Vasut 		debug("failed to enable clock, ret=%d\n", ret);
697*48f54a2dSMarek Vasut 		return ret;
698*48f54a2dSMarek Vasut 	}
699*48f54a2dSMarek Vasut 
700*48f54a2dSMarek Vasut 	host->clk = clk_get_rate(&sh_mmcif_clk);
701*48f54a2dSMarek Vasut 
702*48f54a2dSMarek Vasut 	plat->cfg.name = dev->name;
703*48f54a2dSMarek Vasut 	plat->cfg.host_caps = MMC_MODE_HS_52MHz | MMC_MODE_HS;
704*48f54a2dSMarek Vasut 
705*48f54a2dSMarek Vasut 	switch (fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev), "bus-width",
706*48f54a2dSMarek Vasut 			       1)) {
707*48f54a2dSMarek Vasut 	case 8:
708*48f54a2dSMarek Vasut 		plat->cfg.host_caps |= MMC_MODE_8BIT;
709*48f54a2dSMarek Vasut 		break;
710*48f54a2dSMarek Vasut 	case 4:
711*48f54a2dSMarek Vasut 		plat->cfg.host_caps |= MMC_MODE_4BIT;
712*48f54a2dSMarek Vasut 		break;
713*48f54a2dSMarek Vasut 	case 1:
714*48f54a2dSMarek Vasut 		break;
715*48f54a2dSMarek Vasut 	default:
716*48f54a2dSMarek Vasut 		dev_err(dev, "Invalid \"bus-width\" value\n");
717*48f54a2dSMarek Vasut 		return -EINVAL;
718*48f54a2dSMarek Vasut 	}
719*48f54a2dSMarek Vasut 
720*48f54a2dSMarek Vasut 	sh_mmcif_initialize_common(host);
721*48f54a2dSMarek Vasut 
722*48f54a2dSMarek Vasut 	plat->cfg.voltages = MMC_VDD_165_195 | MMC_VDD_32_33 | MMC_VDD_33_34;
723*48f54a2dSMarek Vasut 	plat->cfg.f_min = MMC_CLK_DIV_MIN(host->clk);
724*48f54a2dSMarek Vasut 	plat->cfg.f_max = MMC_CLK_DIV_MAX(host->clk);
725*48f54a2dSMarek Vasut 	plat->cfg.b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT;
726*48f54a2dSMarek Vasut 
727*48f54a2dSMarek Vasut 	upriv->mmc = &plat->mmc;
728*48f54a2dSMarek Vasut 
729*48f54a2dSMarek Vasut 	return 0;
730*48f54a2dSMarek Vasut }
731*48f54a2dSMarek Vasut 
732*48f54a2dSMarek Vasut static const struct udevice_id sh_mmcif_sd_match[] = {
733*48f54a2dSMarek Vasut 	{ .compatible = "renesas,sh-mmcif" },
734*48f54a2dSMarek Vasut 	{ /* sentinel */ }
735*48f54a2dSMarek Vasut };
736*48f54a2dSMarek Vasut 
737*48f54a2dSMarek Vasut U_BOOT_DRIVER(sh_mmcif_mmc) = {
738*48f54a2dSMarek Vasut 	.name			= "sh-mmcif",
739*48f54a2dSMarek Vasut 	.id			= UCLASS_MMC,
740*48f54a2dSMarek Vasut 	.of_match		= sh_mmcif_sd_match,
741*48f54a2dSMarek Vasut 	.bind			= sh_mmcif_dm_bind,
742*48f54a2dSMarek Vasut 	.probe			= sh_mmcif_dm_probe,
743*48f54a2dSMarek Vasut 	.priv_auto_alloc_size	= sizeof(struct sh_mmcif_host),
744*48f54a2dSMarek Vasut 	.platdata_auto_alloc_size = sizeof(struct sh_mmcif_plat),
745*48f54a2dSMarek Vasut 	.ops			= &sh_mmcif_dm_ops,
746*48f54a2dSMarek Vasut };
747*48f54a2dSMarek Vasut #endif
748