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