]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - drivers/mmc/sh_sdhi.c
karo: tx6ul: proper initialize second FEC if available
[karo-tx-uboot.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 #if defined(__BIG_ENDIAN_BITFIELD)
434         for (i = 0; i < cnt; i++) {
435                 *p2++ = ((*p1 >> 16) & 0x0000ffff) |
436                                 ((*p1 << 16) & 0xffff0000);
437                 p1--;
438         }
439 #else
440         for (i = 0; i < cnt; i++)
441                 *p2++ = *p1--;
442 #endif /* __BIG_ENDIAN_BITFIELD */
443 }
444
445 static unsigned short sh_sdhi_set_cmd(struct sh_sdhi_host *host,
446                         struct mmc_data *data, unsigned short opc)
447 {
448         switch (opc) {
449         case SD_CMD_APP_SEND_OP_COND:
450         case SD_CMD_APP_SEND_SCR:
451                 opc |= SDHI_APP;
452                 break;
453         case SD_CMD_APP_SET_BUS_WIDTH:
454                  /* SD_APP_SET_BUS_WIDTH*/
455                 if (!data)
456                         opc |= SDHI_APP;
457                 else /* SD_SWITCH */
458                         opc = SDHI_SD_SWITCH;
459                 break;
460         default:
461                 break;
462         }
463         return opc;
464 }
465
466 static unsigned short sh_sdhi_data_trans(struct sh_sdhi_host *host,
467                         struct mmc_data *data, unsigned short opc)
468 {
469         unsigned short ret;
470
471         switch (opc) {
472         case MMC_CMD_READ_MULTIPLE_BLOCK:
473                 ret = sh_sdhi_multi_read(host, data);
474                 break;
475         case MMC_CMD_WRITE_MULTIPLE_BLOCK:
476                 ret = sh_sdhi_multi_write(host, data);
477                 break;
478         case MMC_CMD_WRITE_SINGLE_BLOCK:
479                 ret = sh_sdhi_single_write(host, data);
480                 break;
481         case MMC_CMD_READ_SINGLE_BLOCK:
482         case SDHI_SD_APP_SEND_SCR:
483         case SDHI_SD_SWITCH: /* SD_SWITCH */
484                 ret = sh_sdhi_single_read(host, data);
485                 break;
486         default:
487                 printf(DRIVER_NAME": SD: NOT SUPPORT CMD = d'%04d\n", opc);
488                 ret = -EINVAL;
489                 break;
490         }
491         return ret;
492 }
493
494 static int sh_sdhi_start_cmd(struct sh_sdhi_host *host,
495                         struct mmc_data *data, struct mmc_cmd *cmd)
496 {
497         long time;
498         unsigned short opc = cmd->cmdidx;
499         int ret = 0;
500         unsigned long timeout;
501
502         debug("opc = %d, arg = %x, resp_type = %x\n",
503               opc, cmd->cmdarg, cmd->resp_type);
504
505         if (opc == MMC_CMD_STOP_TRANSMISSION) {
506                 /* SDHI sends the STOP command automatically by STOP reg */
507                 sh_sdhi_writew(host, SDHI_INFO1_MASK, ~INFO1M_ACCESS_END &
508                                sh_sdhi_readw(host, SDHI_INFO1_MASK));
509
510                 time = sh_sdhi_wait_interrupt_flag(host);
511                 if (time == 0 || host->sd_error != 0)
512                         return sh_sdhi_error_manage(host);
513
514                 sh_sdhi_get_response(host, cmd);
515                 return 0;
516         }
517
518         if (data) {
519                 if ((opc == MMC_CMD_READ_MULTIPLE_BLOCK) ||
520                     opc == MMC_CMD_WRITE_MULTIPLE_BLOCK) {
521                         sh_sdhi_writew(host, SDHI_STOP, STOP_SEC_ENABLE);
522                         sh_sdhi_writew(host, SDHI_SECCNT, data->blocks);
523                 }
524                 sh_sdhi_writew(host, SDHI_SIZE, data->blocksize);
525         }
526         opc = sh_sdhi_set_cmd(host, data, opc);
527
528         /*
529          *  U-boot cannot use interrupt.
530          *  So this flag may not be clear by timing
531          */
532         sh_sdhi_writew(host, SDHI_INFO1, ~INFO1_RESP_END);
533
534         sh_sdhi_writew(host, SDHI_INFO1_MASK,
535                        INFO1M_RESP_END | sh_sdhi_readw(host, SDHI_INFO1_MASK));
536         sh_sdhi_writew(host, SDHI_ARG0,
537                        (unsigned short)(cmd->cmdarg & ARG0_MASK));
538         sh_sdhi_writew(host, SDHI_ARG1,
539                        (unsigned short)((cmd->cmdarg >> 16) & ARG1_MASK));
540
541         timeout = 100000;
542         /* Waiting for SD Bus busy to be cleared */
543         while (timeout--) {
544                 if ((sh_sdhi_readw(host, SDHI_INFO2) & 0x2000))
545                         break;
546         }
547
548         sh_sdhi_writew(host, SDHI_CMD, (unsigned short)(opc & CMD_MASK));
549
550         host->wait_int = 0;
551         sh_sdhi_writew(host, SDHI_INFO1_MASK,
552                        ~INFO1M_RESP_END & sh_sdhi_readw(host, SDHI_INFO1_MASK));
553         sh_sdhi_writew(host, SDHI_INFO2_MASK,
554                        ~(INFO2M_CMD_ERROR | INFO2M_CRC_ERROR |
555                        INFO2M_END_ERROR | INFO2M_TIMEOUT |
556                        INFO2M_RESP_TIMEOUT | INFO2M_ILA) &
557                        sh_sdhi_readw(host, SDHI_INFO2_MASK));
558
559         time = sh_sdhi_wait_interrupt_flag(host);
560         if (!time)
561                 return sh_sdhi_error_manage(host);
562
563         if (host->sd_error) {
564                 switch (cmd->cmdidx) {
565                 case MMC_CMD_ALL_SEND_CID:
566                 case MMC_CMD_SELECT_CARD:
567                 case SD_CMD_SEND_IF_COND:
568                 case MMC_CMD_APP_CMD:
569                         ret = TIMEOUT;
570                         break;
571                 default:
572                         debug(DRIVER_NAME": Cmd(d'%d) err\n", opc);
573                         debug(DRIVER_NAME": cmdidx = %d\n", cmd->cmdidx);
574                         ret = sh_sdhi_error_manage(host);
575                         break;
576                 }
577                 host->sd_error = 0;
578                 host->wait_int = 0;
579                 return ret;
580         }
581         if (sh_sdhi_readw(host, SDHI_INFO1) & INFO1_RESP_END)
582                 return -EINVAL;
583
584         if (host->wait_int) {
585                 sh_sdhi_get_response(host, cmd);
586                 host->wait_int = 0;
587         }
588         if (data)
589                 ret = sh_sdhi_data_trans(host, data, opc);
590
591         debug("ret = %d, resp = %08x, %08x, %08x, %08x\n",
592               ret, cmd->response[0], cmd->response[1],
593               cmd->response[2], cmd->response[3]);
594         return ret;
595 }
596
597 static int sh_sdhi_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd,
598                         struct mmc_data *data)
599 {
600         struct sh_sdhi_host *host = mmc_priv(mmc);
601         int ret;
602
603         host->sd_error = 0;
604
605         ret = sh_sdhi_start_cmd(host, data, cmd);
606
607         return ret;
608 }
609
610 static void sh_sdhi_set_ios(struct mmc *mmc)
611 {
612         int ret;
613         struct sh_sdhi_host *host = mmc_priv(mmc);
614
615         ret = sh_sdhi_clock_control(host, mmc->clock);
616         if (ret)
617                 return;
618
619         if (mmc->bus_width == 4)
620                 sh_sdhi_writew(host, SDHI_OPTION, ~OPT_BUS_WIDTH_1 &
621                                sh_sdhi_readw(host, SDHI_OPTION));
622         else
623                 sh_sdhi_writew(host, SDHI_OPTION, OPT_BUS_WIDTH_1 |
624                                sh_sdhi_readw(host, SDHI_OPTION));
625
626         debug("clock = %d, buswidth = %d\n", mmc->clock, mmc->bus_width);
627 }
628
629 static int sh_sdhi_initialize(struct mmc *mmc)
630 {
631         struct sh_sdhi_host *host = mmc_priv(mmc);
632         int ret = sh_sdhi_sync_reset(host);
633
634         sh_sdhi_writew(host, SDHI_PORTSEL, USE_1PORT);
635
636 #if defined(__BIG_ENDIAN_BITFIELD)
637         sh_sdhi_writew(host, SDHI_EXT_SWAP, SET_SWAP);
638 #endif
639
640         sh_sdhi_writew(host, SDHI_INFO1_MASK, INFO1M_RESP_END |
641                        INFO1M_ACCESS_END | INFO1M_CARD_RE |
642                        INFO1M_DATA3_CARD_RE | INFO1M_DATA3_CARD_IN);
643
644         return ret;
645 }
646
647 static const struct mmc_ops sh_sdhi_ops = {
648         .send_cmd       = sh_sdhi_send_cmd,
649         .set_ios        = sh_sdhi_set_ios,
650         .init           = sh_sdhi_initialize,
651 };
652
653 static struct mmc_config sh_sdhi_cfg = {
654         .name           = DRIVER_NAME,
655         .ops            = &sh_sdhi_ops,
656         .f_min          = CLKDEV_INIT,
657         .f_max          = CLKDEV_HS_DATA,
658         .voltages       = MMC_VDD_32_33 | MMC_VDD_33_34,
659         .host_caps      = MMC_MODE_4BIT | MMC_MODE_HS,
660         .part_type      = PART_TYPE_DOS,
661         .b_max          = CONFIG_SYS_MMC_MAX_BLK_COUNT,
662 };
663
664 int sh_sdhi_init(unsigned long addr, int ch, unsigned long quirks)
665 {
666         int ret = 0;
667         struct mmc *mmc;
668         struct sh_sdhi_host *host = NULL;
669
670         if (ch >= CONFIG_SYS_SH_SDHI_NR_CHANNEL)
671                 return -ENODEV;
672
673         host = malloc(sizeof(struct sh_sdhi_host));
674         if (!host)
675                 return -ENOMEM;
676
677         mmc = mmc_create(&sh_sdhi_cfg, host);
678         if (!mmc) {
679                 ret = -1;
680                 goto error;
681         }
682
683         host->ch = ch;
684         host->addr = addr;
685         host->quirks = quirks;
686
687         if (host->quirks & SH_SDHI_QUIRK_16BIT_BUF)
688                 host->bus_shift = 1;
689
690         return ret;
691 error:
692         if (host)
693                 free(host);
694         return ret;
695 }