mmc: rmobile: add a compiler barrier
[platform/kernel/u-boot.git] / drivers / mmc / sh_sdhi.c
1 /*
2  * drivers/mmc/sh_sdhi.c
3  *
4  * SD/MMC driver for Renesas rmobile ARM SoCs.
5  *
6  * Copyright (C) 2011,2013-2014 Renesas Electronics Corporation
7  * Copyright (C) 2014 Nobuhiro Iwamatsu <nobuhiro.iwamatsu.yj@renesas.com>
8  * Copyright (C) 2008-2009 Renesas Solutions Corp.
9  *
10  * SPDX-License-Identifier:     GPL-2.0
11  */
12
13 #include <common.h>
14 #include <malloc.h>
15 #include <mmc.h>
16 #include <asm/errno.h>
17 #include <asm/io.h>
18 #include <asm/arch/rmobile.h>
19 #include <asm/arch/sh_sdhi.h>
20
21 #define DRIVER_NAME "sh-sdhi"
22
23 struct sh_sdhi_host {
24         unsigned long addr;
25         int ch;
26         int bus_shift;
27         unsigned long quirks;
28         unsigned char wait_int;
29         unsigned char sd_error;
30         unsigned char detect_waiting;
31 };
32 static inline void sh_sdhi_writew(struct sh_sdhi_host *host, int reg, u16 val)
33 {
34         writew(val, host->addr + (reg << host->bus_shift));
35 }
36
37 static inline u16 sh_sdhi_readw(struct sh_sdhi_host *host, int reg)
38 {
39         return readw(host->addr + (reg << host->bus_shift));
40 }
41
42 static void *mmc_priv(struct mmc *mmc)
43 {
44         return (void *)mmc->priv;
45 }
46
47 static void sh_sdhi_detect(struct sh_sdhi_host *host)
48 {
49         sh_sdhi_writew(host, SDHI_OPTION,
50                        OPT_BUS_WIDTH_1 | sh_sdhi_readw(host, SDHI_OPTION));
51
52         host->detect_waiting = 0;
53 }
54
55 static int sh_sdhi_intr(void *dev_id)
56 {
57         struct sh_sdhi_host *host = dev_id;
58         int state1 = 0, state2 = 0;
59
60         state1 = sh_sdhi_readw(host, SDHI_INFO1);
61         state2 = sh_sdhi_readw(host, SDHI_INFO2);
62
63         debug("%s: state1 = %x, state2 = %x\n", __func__, state1, state2);
64
65         /* CARD Insert */
66         if (state1 & INFO1_CARD_IN) {
67                 sh_sdhi_writew(host, SDHI_INFO1, ~INFO1_CARD_IN);
68                 if (!host->detect_waiting) {
69                         host->detect_waiting = 1;
70                         sh_sdhi_detect(host);
71                 }
72                 sh_sdhi_writew(host, SDHI_INFO1_MASK, INFO1M_RESP_END |
73                                INFO1M_ACCESS_END | INFO1M_CARD_IN |
74                                INFO1M_DATA3_CARD_RE | INFO1M_DATA3_CARD_IN);
75                 return -EAGAIN;
76         }
77         /* CARD Removal */
78         if (state1 & INFO1_CARD_RE) {
79                 sh_sdhi_writew(host, SDHI_INFO1, ~INFO1_CARD_RE);
80                 if (!host->detect_waiting) {
81                         host->detect_waiting = 1;
82                         sh_sdhi_detect(host);
83                 }
84                 sh_sdhi_writew(host, SDHI_INFO1_MASK, INFO1M_RESP_END |
85                                INFO1M_ACCESS_END | INFO1M_CARD_RE |
86                                INFO1M_DATA3_CARD_RE | INFO1M_DATA3_CARD_IN);
87                 sh_sdhi_writew(host, SDHI_SDIO_INFO1_MASK, SDIO_INFO1M_ON);
88                 sh_sdhi_writew(host, SDHI_SDIO_MODE, SDIO_MODE_OFF);
89                 return -EAGAIN;
90         }
91
92         if (state2 & INFO2_ALL_ERR) {
93                 sh_sdhi_writew(host, SDHI_INFO2,
94                                (unsigned short)~(INFO2_ALL_ERR));
95                 sh_sdhi_writew(host, SDHI_INFO2_MASK,
96                                INFO2M_ALL_ERR |
97                                sh_sdhi_readw(host, SDHI_INFO2_MASK));
98                 host->sd_error = 1;
99                 host->wait_int = 1;
100                 return 0;
101         }
102         /* Respons End */
103         if (state1 & INFO1_RESP_END) {
104                 sh_sdhi_writew(host, SDHI_INFO1, ~INFO1_RESP_END);
105                 sh_sdhi_writew(host, SDHI_INFO1_MASK,
106                                INFO1M_RESP_END |
107                                sh_sdhi_readw(host, SDHI_INFO1_MASK));
108                 host->wait_int = 1;
109                 return 0;
110         }
111         /* SD_BUF Read Enable */
112         if (state2 & INFO2_BRE_ENABLE) {
113                 sh_sdhi_writew(host, SDHI_INFO2, ~INFO2_BRE_ENABLE);
114                 sh_sdhi_writew(host, SDHI_INFO2_MASK,
115                                INFO2M_BRE_ENABLE | INFO2M_BUF_ILL_READ |
116                                sh_sdhi_readw(host, SDHI_INFO2_MASK));
117                 host->wait_int = 1;
118                 return 0;
119         }
120         /* SD_BUF Write Enable */
121         if (state2 & INFO2_BWE_ENABLE) {
122                 sh_sdhi_writew(host, SDHI_INFO2, ~INFO2_BWE_ENABLE);
123                 sh_sdhi_writew(host, SDHI_INFO2_MASK,
124                                INFO2_BWE_ENABLE | INFO2M_BUF_ILL_WRITE |
125                                sh_sdhi_readw(host, SDHI_INFO2_MASK));
126                 host->wait_int = 1;
127                 return 0;
128         }
129         /* Access End */
130         if (state1 & INFO1_ACCESS_END) {
131                 sh_sdhi_writew(host, SDHI_INFO1, ~INFO1_ACCESS_END);
132                 sh_sdhi_writew(host, SDHI_INFO1_MASK,
133                                INFO1_ACCESS_END |
134                                sh_sdhi_readw(host, SDHI_INFO1_MASK));
135                 host->wait_int = 1;
136                 return 0;
137         }
138         return -EAGAIN;
139 }
140
141 static int sh_sdhi_wait_interrupt_flag(struct sh_sdhi_host *host)
142 {
143         int timeout = 10000000;
144
145         while (1) {
146                 timeout--;
147                 if (timeout < 0) {
148                         debug(DRIVER_NAME": %s timeout\n", __func__);
149                         return 0;
150                 }
151
152                 if (!sh_sdhi_intr(host))
153                         break;
154
155                 udelay(1);      /* 1 usec */
156         }
157
158         return 1; /* Return value: NOT 0 = complete waiting */
159 }
160
161 static int sh_sdhi_clock_control(struct sh_sdhi_host *host, unsigned long clk)
162 {
163         u32 clkdiv, i, timeout;
164
165         if (sh_sdhi_readw(host, SDHI_INFO2) & (1 << 14)) {
166                 printf(DRIVER_NAME": Busy state ! Cannot change the clock\n");
167                 return -EBUSY;
168         }
169
170         sh_sdhi_writew(host, SDHI_CLK_CTRL,
171                        ~CLK_ENABLE & sh_sdhi_readw(host, SDHI_CLK_CTRL));
172
173         if (clk == 0)
174                 return -EIO;
175
176         clkdiv = 0x80;
177         i = CONFIG_SH_SDHI_FREQ >> (0x8 + 1);
178         for (; clkdiv && clk >= (i << 1); (clkdiv >>= 1))
179                 i <<= 1;
180
181         sh_sdhi_writew(host, SDHI_CLK_CTRL, clkdiv);
182
183         timeout = 100000;
184         /* Waiting for SD Bus busy to be cleared */
185         while (timeout--) {
186                 if ((sh_sdhi_readw(host, SDHI_INFO2) & 0x2000))
187                         break;
188         }
189
190         if (timeout)
191                 sh_sdhi_writew(host, SDHI_CLK_CTRL,
192                                CLK_ENABLE | sh_sdhi_readw(host, SDHI_CLK_CTRL));
193         else
194                 return -EBUSY;
195
196         return 0;
197 }
198
199 static int sh_sdhi_sync_reset(struct sh_sdhi_host *host)
200 {
201         u32 timeout;
202         sh_sdhi_writew(host, SDHI_SOFT_RST, SOFT_RST_ON);
203         sh_sdhi_writew(host, SDHI_SOFT_RST, SOFT_RST_OFF);
204         sh_sdhi_writew(host, SDHI_CLK_CTRL,
205                        CLK_ENABLE | sh_sdhi_readw(host, SDHI_CLK_CTRL));
206
207         timeout = 100000;
208         while (timeout--) {
209                 if (!(sh_sdhi_readw(host, SDHI_INFO2) & INFO2_CBUSY))
210                         break;
211                 udelay(100);
212         }
213
214         if (!timeout)
215                 return -EBUSY;
216
217         if (host->quirks & SH_SDHI_QUIRK_16BIT_BUF)
218                 sh_sdhi_writew(host, SDHI_HOST_MODE, 1);
219
220         return 0;
221 }
222
223 static int sh_sdhi_error_manage(struct sh_sdhi_host *host)
224 {
225         unsigned short e_state1, e_state2;
226         int ret;
227
228         host->sd_error = 0;
229         host->wait_int = 0;
230
231         e_state1 = sh_sdhi_readw(host, SDHI_ERR_STS1);
232         e_state2 = sh_sdhi_readw(host, SDHI_ERR_STS2);
233         if (e_state2 & ERR_STS2_SYS_ERROR) {
234                 if (e_state2 & ERR_STS2_RES_STOP_TIMEOUT)
235                         ret = TIMEOUT;
236                 else
237                         ret = -EILSEQ;
238                 debug("%s: ERR_STS2 = %04x\n",
239                       DRIVER_NAME, sh_sdhi_readw(host, SDHI_ERR_STS2));
240                 sh_sdhi_sync_reset(host);
241
242                 sh_sdhi_writew(host, SDHI_INFO1_MASK,
243                                INFO1M_DATA3_CARD_RE | INFO1M_DATA3_CARD_IN);
244                 return ret;
245         }
246         if (e_state1 & ERR_STS1_CRC_ERROR || e_state1 & ERR_STS1_CMD_ERROR)
247                 ret = -EILSEQ;
248         else
249                 ret = TIMEOUT;
250
251         debug("%s: ERR_STS1 = %04x\n",
252               DRIVER_NAME, sh_sdhi_readw(host, SDHI_ERR_STS1));
253         sh_sdhi_sync_reset(host);
254         sh_sdhi_writew(host, SDHI_INFO1_MASK,
255                        INFO1M_DATA3_CARD_RE | INFO1M_DATA3_CARD_IN);
256         return ret;
257 }
258
259 static int sh_sdhi_single_read(struct sh_sdhi_host *host, struct mmc_data *data)
260 {
261         long time;
262         unsigned short blocksize, i;
263         unsigned short *p = (unsigned short *)data->dest;
264
265         if ((unsigned long)p & 0x00000001) {
266                 debug(DRIVER_NAME": %s: The data pointer is unaligned.",
267                       __func__);
268                 return -EIO;
269         }
270
271         host->wait_int = 0;
272         sh_sdhi_writew(host, SDHI_INFO2_MASK,
273                        ~(INFO2M_BRE_ENABLE | INFO2M_BUF_ILL_READ) &
274                        sh_sdhi_readw(host, SDHI_INFO2_MASK));
275         sh_sdhi_writew(host, SDHI_INFO1_MASK,
276                        ~INFO1M_ACCESS_END &
277                        sh_sdhi_readw(host, SDHI_INFO1_MASK));
278         time = sh_sdhi_wait_interrupt_flag(host);
279         if (time == 0 || host->sd_error != 0)
280                 return sh_sdhi_error_manage(host);
281
282         host->wait_int = 0;
283         blocksize = sh_sdhi_readw(host, SDHI_SIZE);
284         for (i = 0; i < blocksize / 2; i++)
285                 *p++ = sh_sdhi_readw(host, SDHI_BUF0);
286
287         time = sh_sdhi_wait_interrupt_flag(host);
288         if (time == 0 || host->sd_error != 0)
289                 return sh_sdhi_error_manage(host);
290
291         host->wait_int = 0;
292         return 0;
293 }
294
295 static int sh_sdhi_multi_read(struct sh_sdhi_host *host, struct mmc_data *data)
296 {
297         long time;
298         unsigned short blocksize, i, sec;
299         unsigned short *p = (unsigned short *)data->dest;
300
301         if ((unsigned long)p & 0x00000001) {
302                 debug(DRIVER_NAME": %s: The data pointer is unaligned.",
303                       __func__);
304                 return -EIO;
305         }
306
307         debug("%s: blocks = %d, blocksize = %d\n",
308               __func__, data->blocks, data->blocksize);
309
310         host->wait_int = 0;
311         for (sec = 0; sec < data->blocks; sec++) {
312                 sh_sdhi_writew(host, SDHI_INFO2_MASK,
313                                ~(INFO2M_BRE_ENABLE | INFO2M_BUF_ILL_READ) &
314                                sh_sdhi_readw(host, SDHI_INFO2_MASK));
315
316                 time = sh_sdhi_wait_interrupt_flag(host);
317                 if (time == 0 || host->sd_error != 0)
318                         return sh_sdhi_error_manage(host);
319
320                 host->wait_int = 0;
321                 blocksize = sh_sdhi_readw(host, SDHI_SIZE);
322                 for (i = 0; i < blocksize / 2; i++)
323                         *p++ = sh_sdhi_readw(host, SDHI_BUF0);
324         }
325
326         return 0;
327 }
328
329 static int sh_sdhi_single_write(struct sh_sdhi_host *host,
330                 struct mmc_data *data)
331 {
332         long time;
333         unsigned short blocksize, i;
334         const unsigned short *p = (const unsigned short *)data->src;
335
336         if ((unsigned long)p & 0x00000001) {
337                 debug(DRIVER_NAME": %s: The data pointer is unaligned.",
338                       __func__);
339                 return -EIO;
340         }
341
342         debug("%s: blocks = %d, blocksize = %d\n",
343               __func__, data->blocks, data->blocksize);
344
345         host->wait_int = 0;
346         sh_sdhi_writew(host, SDHI_INFO2_MASK,
347                        ~(INFO2M_BWE_ENABLE | INFO2M_BUF_ILL_WRITE) &
348                        sh_sdhi_readw(host, SDHI_INFO2_MASK));
349         sh_sdhi_writew(host, SDHI_INFO1_MASK,
350                        ~INFO1M_ACCESS_END &
351                        sh_sdhi_readw(host, SDHI_INFO1_MASK));
352
353         time = sh_sdhi_wait_interrupt_flag(host);
354         if (time == 0 || host->sd_error != 0)
355                 return sh_sdhi_error_manage(host);
356
357         host->wait_int = 0;
358         blocksize = sh_sdhi_readw(host, SDHI_SIZE);
359         for (i = 0; i < blocksize / 2; i++)
360                 sh_sdhi_writew(host, SDHI_BUF0, *p++);
361
362         time = sh_sdhi_wait_interrupt_flag(host);
363         if (time == 0 || host->sd_error != 0)
364                 return sh_sdhi_error_manage(host);
365
366         host->wait_int = 0;
367         return 0;
368 }
369
370 static int sh_sdhi_multi_write(struct sh_sdhi_host *host, struct mmc_data *data)
371 {
372         long time;
373         unsigned short i, sec, blocksize;
374         const unsigned short *p = (const unsigned short *)data->src;
375
376         debug("%s: blocks = %d, blocksize = %d\n",
377               __func__, data->blocks, data->blocksize);
378
379         host->wait_int = 0;
380         for (sec = 0; sec < data->blocks; sec++) {
381                 sh_sdhi_writew(host, SDHI_INFO2_MASK,
382                                ~(INFO2M_BWE_ENABLE | INFO2M_BUF_ILL_WRITE) &
383                                sh_sdhi_readw(host, SDHI_INFO2_MASK));
384
385                 time = sh_sdhi_wait_interrupt_flag(host);
386                 if (time == 0 || host->sd_error != 0)
387                         return sh_sdhi_error_manage(host);
388
389                 host->wait_int = 0;
390                 blocksize = sh_sdhi_readw(host, SDHI_SIZE);
391                 for (i = 0; i < blocksize / 2; i++)
392                         sh_sdhi_writew(host, SDHI_BUF0, *p++);
393         }
394
395         return 0;
396 }
397
398 static void sh_sdhi_get_response(struct sh_sdhi_host *host, struct mmc_cmd *cmd)
399 {
400         unsigned short i, j, cnt = 1;
401         unsigned short resp[8];
402         unsigned long *p1, *p2;
403
404         if (cmd->resp_type & MMC_RSP_136) {
405                 cnt = 4;
406                 resp[0] = sh_sdhi_readw(host, SDHI_RSP00);
407                 resp[1] = sh_sdhi_readw(host, SDHI_RSP01);
408                 resp[2] = sh_sdhi_readw(host, SDHI_RSP02);
409                 resp[3] = sh_sdhi_readw(host, SDHI_RSP03);
410                 resp[4] = sh_sdhi_readw(host, SDHI_RSP04);
411                 resp[5] = sh_sdhi_readw(host, SDHI_RSP05);
412                 resp[6] = sh_sdhi_readw(host, SDHI_RSP06);
413                 resp[7] = sh_sdhi_readw(host, SDHI_RSP07);
414
415                 /* SDHI REGISTER SPECIFICATION */
416                 for (i = 7, j = 6; i > 0; i--) {
417                         resp[i] = (resp[i] << 8) & 0xff00;
418                         resp[i] |= (resp[j--] >> 8) & 0x00ff;
419                 }
420                 resp[0] = (resp[0] << 8) & 0xff00;
421
422                 /* SDHI REGISTER SPECIFICATION */
423                 p1 = ((unsigned long *)resp) + 3;
424
425         } else {
426                 resp[0] = sh_sdhi_readw(host, SDHI_RSP00);
427                 resp[1] = sh_sdhi_readw(host, SDHI_RSP01);
428
429                 p1 = ((unsigned long *)resp);
430         }
431
432         p2 = (unsigned long *)cmd->response;
433
434         barrier();
435
436 #if defined(__BIG_ENDIAN_BITFIELD)
437         for (i = 0; i < cnt; i++) {
438                 *p2++ = ((*p1 >> 16) & 0x0000ffff) |
439                                 ((*p1 << 16) & 0xffff0000);
440                 p1--;
441         }
442 #else
443         for (i = 0; i < cnt; i++)
444                 *p2++ = *p1--;
445 #endif /* __BIG_ENDIAN_BITFIELD */
446 }
447
448 static unsigned short sh_sdhi_set_cmd(struct sh_sdhi_host *host,
449                         struct mmc_data *data, unsigned short opc)
450 {
451         switch (opc) {
452         case SD_CMD_APP_SEND_OP_COND:
453         case SD_CMD_APP_SEND_SCR:
454                 opc |= SDHI_APP;
455                 break;
456         case SD_CMD_APP_SET_BUS_WIDTH:
457                  /* SD_APP_SET_BUS_WIDTH*/
458                 if (!data)
459                         opc |= SDHI_APP;
460                 else /* SD_SWITCH */
461                         opc = SDHI_SD_SWITCH;
462                 break;
463         default:
464                 break;
465         }
466         return opc;
467 }
468
469 static unsigned short sh_sdhi_data_trans(struct sh_sdhi_host *host,
470                         struct mmc_data *data, unsigned short opc)
471 {
472         unsigned short ret;
473
474         switch (opc) {
475         case MMC_CMD_READ_MULTIPLE_BLOCK:
476                 ret = sh_sdhi_multi_read(host, data);
477                 break;
478         case MMC_CMD_WRITE_MULTIPLE_BLOCK:
479                 ret = sh_sdhi_multi_write(host, data);
480                 break;
481         case MMC_CMD_WRITE_SINGLE_BLOCK:
482                 ret = sh_sdhi_single_write(host, data);
483                 break;
484         case MMC_CMD_READ_SINGLE_BLOCK:
485         case SDHI_SD_APP_SEND_SCR:
486         case SDHI_SD_SWITCH: /* SD_SWITCH */
487                 ret = sh_sdhi_single_read(host, data);
488                 break;
489         default:
490                 printf(DRIVER_NAME": SD: NOT SUPPORT CMD = d'%04d\n", opc);
491                 ret = -EINVAL;
492                 break;
493         }
494         return ret;
495 }
496
497 static int sh_sdhi_start_cmd(struct sh_sdhi_host *host,
498                         struct mmc_data *data, struct mmc_cmd *cmd)
499 {
500         long time;
501         unsigned short opc = cmd->cmdidx;
502         int ret = 0;
503         unsigned long timeout;
504
505         debug("opc = %d, arg = %x, resp_type = %x\n",
506               opc, cmd->cmdarg, cmd->resp_type);
507
508         if (opc == MMC_CMD_STOP_TRANSMISSION) {
509                 /* SDHI sends the STOP command automatically by STOP reg */
510                 sh_sdhi_writew(host, SDHI_INFO1_MASK, ~INFO1M_ACCESS_END &
511                                sh_sdhi_readw(host, SDHI_INFO1_MASK));
512
513                 time = sh_sdhi_wait_interrupt_flag(host);
514                 if (time == 0 || host->sd_error != 0)
515                         return sh_sdhi_error_manage(host);
516
517                 sh_sdhi_get_response(host, cmd);
518                 return 0;
519         }
520
521         if (data) {
522                 if ((opc == MMC_CMD_READ_MULTIPLE_BLOCK) ||
523                     opc == MMC_CMD_WRITE_MULTIPLE_BLOCK) {
524                         sh_sdhi_writew(host, SDHI_STOP, STOP_SEC_ENABLE);
525                         sh_sdhi_writew(host, SDHI_SECCNT, data->blocks);
526                 }
527                 sh_sdhi_writew(host, SDHI_SIZE, data->blocksize);
528         }
529         opc = sh_sdhi_set_cmd(host, data, opc);
530
531         /*
532          *  U-Boot cannot use interrupt.
533          *  So this flag may not be clear by timing
534          */
535         sh_sdhi_writew(host, SDHI_INFO1, ~INFO1_RESP_END);
536
537         sh_sdhi_writew(host, SDHI_INFO1_MASK,
538                        INFO1M_RESP_END | sh_sdhi_readw(host, SDHI_INFO1_MASK));
539         sh_sdhi_writew(host, SDHI_ARG0,
540                        (unsigned short)(cmd->cmdarg & ARG0_MASK));
541         sh_sdhi_writew(host, SDHI_ARG1,
542                        (unsigned short)((cmd->cmdarg >> 16) & ARG1_MASK));
543
544         timeout = 100000;
545         /* Waiting for SD Bus busy to be cleared */
546         while (timeout--) {
547                 if ((sh_sdhi_readw(host, SDHI_INFO2) & 0x2000))
548                         break;
549         }
550
551         sh_sdhi_writew(host, SDHI_CMD, (unsigned short)(opc & CMD_MASK));
552
553         host->wait_int = 0;
554         sh_sdhi_writew(host, SDHI_INFO1_MASK,
555                        ~INFO1M_RESP_END & sh_sdhi_readw(host, SDHI_INFO1_MASK));
556         sh_sdhi_writew(host, SDHI_INFO2_MASK,
557                        ~(INFO2M_CMD_ERROR | INFO2M_CRC_ERROR |
558                        INFO2M_END_ERROR | INFO2M_TIMEOUT |
559                        INFO2M_RESP_TIMEOUT | INFO2M_ILA) &
560                        sh_sdhi_readw(host, SDHI_INFO2_MASK));
561
562         time = sh_sdhi_wait_interrupt_flag(host);
563         if (!time)
564                 return sh_sdhi_error_manage(host);
565
566         if (host->sd_error) {
567                 switch (cmd->cmdidx) {
568                 case MMC_CMD_ALL_SEND_CID:
569                 case MMC_CMD_SELECT_CARD:
570                 case SD_CMD_SEND_IF_COND:
571                 case MMC_CMD_APP_CMD:
572                         ret = TIMEOUT;
573                         break;
574                 default:
575                         debug(DRIVER_NAME": Cmd(d'%d) err\n", opc);
576                         debug(DRIVER_NAME": cmdidx = %d\n", cmd->cmdidx);
577                         ret = sh_sdhi_error_manage(host);
578                         break;
579                 }
580                 host->sd_error = 0;
581                 host->wait_int = 0;
582                 return ret;
583         }
584         if (sh_sdhi_readw(host, SDHI_INFO1) & INFO1_RESP_END)
585                 return -EINVAL;
586
587         if (host->wait_int) {
588                 sh_sdhi_get_response(host, cmd);
589                 host->wait_int = 0;
590         }
591         if (data)
592                 ret = sh_sdhi_data_trans(host, data, opc);
593
594         debug("ret = %d, resp = %08x, %08x, %08x, %08x\n",
595               ret, cmd->response[0], cmd->response[1],
596               cmd->response[2], cmd->response[3]);
597         return ret;
598 }
599
600 static int sh_sdhi_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd,
601                         struct mmc_data *data)
602 {
603         struct sh_sdhi_host *host = mmc_priv(mmc);
604         int ret;
605
606         host->sd_error = 0;
607
608         ret = sh_sdhi_start_cmd(host, data, cmd);
609
610         return ret;
611 }
612
613 static void sh_sdhi_set_ios(struct mmc *mmc)
614 {
615         int ret;
616         struct sh_sdhi_host *host = mmc_priv(mmc);
617
618         ret = sh_sdhi_clock_control(host, mmc->clock);
619         if (ret)
620                 return;
621
622         if (mmc->bus_width == 4)
623                 sh_sdhi_writew(host, SDHI_OPTION, ~OPT_BUS_WIDTH_1 &
624                                sh_sdhi_readw(host, SDHI_OPTION));
625         else
626                 sh_sdhi_writew(host, SDHI_OPTION, OPT_BUS_WIDTH_1 |
627                                sh_sdhi_readw(host, SDHI_OPTION));
628
629         debug("clock = %d, buswidth = %d\n", mmc->clock, mmc->bus_width);
630 }
631
632 static int sh_sdhi_initialize(struct mmc *mmc)
633 {
634         struct sh_sdhi_host *host = mmc_priv(mmc);
635         int ret = sh_sdhi_sync_reset(host);
636
637         sh_sdhi_writew(host, SDHI_PORTSEL, USE_1PORT);
638
639 #if defined(__BIG_ENDIAN_BITFIELD)
640         sh_sdhi_writew(host, SDHI_EXT_SWAP, SET_SWAP);
641 #endif
642
643         sh_sdhi_writew(host, SDHI_INFO1_MASK, INFO1M_RESP_END |
644                        INFO1M_ACCESS_END | INFO1M_CARD_RE |
645                        INFO1M_DATA3_CARD_RE | INFO1M_DATA3_CARD_IN);
646
647         return ret;
648 }
649
650 static const struct mmc_ops sh_sdhi_ops = {
651         .send_cmd       = sh_sdhi_send_cmd,
652         .set_ios        = sh_sdhi_set_ios,
653         .init           = sh_sdhi_initialize,
654 };
655
656 static struct mmc_config sh_sdhi_cfg = {
657         .name           = DRIVER_NAME,
658         .ops            = &sh_sdhi_ops,
659         .f_min          = CLKDEV_INIT,
660         .f_max          = CLKDEV_HS_DATA,
661         .voltages       = MMC_VDD_32_33 | MMC_VDD_33_34,
662         .host_caps      = MMC_MODE_4BIT | MMC_MODE_HS,
663         .part_type      = PART_TYPE_DOS,
664         .b_max          = CONFIG_SYS_MMC_MAX_BLK_COUNT,
665 };
666
667 int sh_sdhi_init(unsigned long addr, int ch, unsigned long quirks)
668 {
669         int ret = 0;
670         struct mmc *mmc;
671         struct sh_sdhi_host *host = NULL;
672
673         if (ch >= CONFIG_SYS_SH_SDHI_NR_CHANNEL)
674                 return -ENODEV;
675
676         host = malloc(sizeof(struct sh_sdhi_host));
677         if (!host)
678                 return -ENOMEM;
679
680         mmc = mmc_create(&sh_sdhi_cfg, host);
681         if (!mmc) {
682                 ret = -1;
683                 goto error;
684         }
685
686         host->ch = ch;
687         host->addr = addr;
688         host->quirks = quirks;
689
690         if (host->quirks & SH_SDHI_QUIRK_16BIT_BUF)
691                 host->bus_shift = 1;
692
693         return ret;
694 error:
695         if (host)
696                 free(host);
697         return ret;
698 }