blob: 42f0e0ce55bc9c2c16683d0b15e584c90fe58b66 [file] [log] [blame]
Macpaul Lin6d18f5e2011-07-20 21:29:58 +00001/*
2 * Copyright (C) 2011 Andes Technology Corporation
3 * Macpaul Lin, Andes Technology Corporation <macpaul@andestech.com>
4 *
5 * See file CREDITS for list of people who contributed to this
6 * project.
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License as
10 * published by the Free Software Foundation; either version 2 of
11 * the License, or (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
21 * MA 02111-1307 USA
22 */
23
24#include <config.h>
25#include <common.h>
26#include <mmc.h>
27
28#include <asm/io.h>
29#include <faraday/ftsdc010.h>
30
31/*
32 * supported mmc hosts
33 * setting the number CONFIG_FTSDC010_NUMBER in your configuration file.
34 */
35static struct mmc ftsdc010_dev[CONFIG_FTSDC010_NUMBER];
36static struct mmc_host ftsdc010_host[CONFIG_FTSDC010_NUMBER];
37
38static struct ftsdc010_mmc *ftsdc010_get_base_mmc(int dev_index)
39{
40 return (struct ftsdc010_mmc *)CONFIG_FTSDC010_BASE + dev_index;
41}
42
43#ifdef DEBUG
44static void ftsdc010_dump_reg(struct mmc_host *host)
45{
46 debug("cmd: %08x\n", readl(&host->reg->cmd));
47 debug("argu: %08x\n", readl(&host->reg->argu));
48 debug("rsp0: %08x\n", readl(&host->reg->rsp0));
49 debug("rsp1: %08x\n", readl(&host->reg->rsp1));
50 debug("rsp2: %08x\n", readl(&host->reg->rsp2));
51 debug("rsp3: %08x\n", readl(&host->reg->rsp3));
52 debug("rsp_cmd: %08x\n", readl(&host->reg->rsp_cmd));
53 debug("dcr: %08x\n", readl(&host->reg->dcr));
54 debug("dtr: %08x\n", readl(&host->reg->dtr));
55 debug("dlr: %08x\n", readl(&host->reg->dlr));
56 debug("status: %08x\n", readl(&host->reg->status));
57 debug("clr: %08x\n", readl(&host->reg->clr));
58 debug("int_mask: %08x\n", readl(&host->reg->int_mask));
59 debug("pcr: %08x\n", readl(&host->reg->pcr));
60 debug("ccr: %08x\n", readl(&host->reg->ccr));
61 debug("bwr: %08x\n", readl(&host->reg->bwr));
62 debug("dwr: %08x\n", readl(&host->reg->dwr));
63 debug("feature: %08x\n", readl(&host->reg->feature));
64 debug("rev: %08x\n", readl(&host->reg->rev));
65}
66#endif
67
68static unsigned int enable_imask(struct ftsdc010_mmc *reg, unsigned int imask)
69{
70 unsigned int newmask;
71
72 newmask = readl(&reg->int_mask);
73 newmask |= imask;
74
75 writel(newmask, &reg->int_mask);
76
77 return newmask;
78}
79
80static void ftsdc010_pio_read(struct mmc_host *host, char *buf, unsigned int size)
81{
82 unsigned int fifo;
83 unsigned int fifo_words;
84 unsigned int *ptr;
85 unsigned int status;
86 unsigned int retry = 0;
87
88 /* get_data_buffer */
89 ptr = (unsigned int *)buf;
90
91 while (size) {
92 status = readl(&host->reg->status);
Macpaul Lin1a18a3e2011-11-28 17:30:17 +000093 debug("%s: size: %08x\n", __func__, size);
Macpaul Lin6d18f5e2011-07-20 21:29:58 +000094
95 if (status & FTSDC010_STATUS_FIFO_ORUN) {
Macpaul Lin1a18a3e2011-11-28 17:30:17 +000096
97 debug("%s: FIFO OVERRUN: sta: %08x\n",
98 __func__, status);
99
Macpaul Lin6d18f5e2011-07-20 21:29:58 +0000100 fifo = host->fifo_len > size ?
101 size : host->fifo_len;
102
103 size -= fifo;
104
105 fifo_words = fifo >> 2;
106
107 while (fifo_words--)
108 *ptr++ = readl(&host->reg->dwr);
109
110 /*
111 * for adding some delays for SD card to put
112 * data into FIFO again
113 */
114 udelay(4*FTSDC010_DELAY_UNIT);
115
116#ifdef CONFIG_FTSDC010_SDIO
117 /* sdio allow non-power-of-2 blksz */
118 if (fifo & 3) {
119 unsigned int n = fifo & 3;
120 unsigned int data = readl(&host->reg->dwr);
121
122 unsigned char *p = (unsigned char *)ptr;
123
124 while (n--) {
125 *p++ = data;
126 data >>= 8;
127 }
128 }
129#endif
130 } else {
131 udelay(1);
132 if (++retry >= FTSDC010_PIO_RETRY) {
133 debug("%s: PIO_RETRY timeout\n", __func__);
134 return;
135 }
136 }
137 }
138}
139
140static void ftsdc010_pio_write(struct mmc_host *host, const char *buf,
141 unsigned int size)
142{
143 unsigned int fifo;
144 unsigned int *ptr;
145 unsigned int status;
146 unsigned int retry = 0;
147
148 /* get data buffer */
149 ptr = (unsigned int *)buf;
150
151 while (size) {
152 status = readl(&host->reg->status);
153
Macpaul Lin1a18a3e2011-11-28 17:30:17 +0000154 if (status & FTSDC010_STATUS_FIFO_URUN) {
Macpaul Lin6d18f5e2011-07-20 21:29:58 +0000155 fifo = host->fifo_len > size ?
156 size : host->fifo_len;
157
158 size -= fifo;
159
160 fifo = (fifo + 3) >> 2;
161
162 while (fifo--) {
163 writel(*ptr, &host->reg->dwr);
164 ptr++;
165 }
Macpaul Lin6d18f5e2011-07-20 21:29:58 +0000166 } else {
167 udelay(1);
168 if (++retry >= FTSDC010_PIO_RETRY) {
169 debug("%s: PIO_RETRY timeout\n", __func__);
170 return;
171 }
172 }
173 }
174}
175
Macpaul Lin1a18a3e2011-11-28 17:30:17 +0000176static int ftsdc010_check_rsp(struct mmc *mmc, struct mmc_cmd *cmd,
Macpaul Lin6d18f5e2011-07-20 21:29:58 +0000177 struct mmc_data *data)
178{
179 struct mmc_host *host = mmc->priv;
Macpaul Lin6d18f5e2011-07-20 21:29:58 +0000180 unsigned int sta, clear;
Macpaul Lin6d18f5e2011-07-20 21:29:58 +0000181
Macpaul Lin1a18a3e2011-11-28 17:30:17 +0000182 sta = readl(&host->reg->status);
183 debug("%s: sta: %08x cmd %d\n", __func__, sta, cmd->cmdidx);
Macpaul Lin6d18f5e2011-07-20 21:29:58 +0000184
185 /* check RSP TIMEOUT or FAIL */
186 if (sta & FTSDC010_STATUS_RSP_TIMEOUT) {
187 /* RSP TIMEOUT */
Macpaul Lin1a18a3e2011-11-28 17:30:17 +0000188 debug("%s: RSP timeout: sta: %08x\n", __func__, sta);
Macpaul Lin6d18f5e2011-07-20 21:29:58 +0000189
190 clear |= FTSDC010_CLR_RSP_TIMEOUT;
191 writel(clear, &host->reg->clr);
192
193 return TIMEOUT;
194 } else if (sta & FTSDC010_STATUS_RSP_CRC_FAIL) {
195 /* clear response fail bit */
Macpaul Lin1a18a3e2011-11-28 17:30:17 +0000196 debug("%s: RSP CRC FAIL: sta: %08x\n", __func__, sta);
Macpaul Lin6d18f5e2011-07-20 21:29:58 +0000197
198 clear |= FTSDC010_CLR_RSP_CRC_FAIL;
199 writel(clear, &host->reg->clr);
200
Macpaul Lin1a18a3e2011-11-28 17:30:17 +0000201 return COMM_ERR;
Macpaul Lin6d18f5e2011-07-20 21:29:58 +0000202 } else if (sta & FTSDC010_STATUS_RSP_CRC_OK) {
203
204 /* clear response CRC OK bit */
205 clear |= FTSDC010_CLR_RSP_CRC_OK;
206 }
207
Macpaul Lin1a18a3e2011-11-28 17:30:17 +0000208 writel(clear, &host->reg->clr);
209 return 0;
210}
211
212static int ftsdc010_check_data(struct mmc *mmc, struct mmc_cmd *cmd,
213 struct mmc_data *data)
214{
215 struct mmc_host *host = mmc->priv;
216 unsigned int sta, clear;
217
218 sta = readl(&host->reg->status);
219 debug("%s: sta: %08x cmd %d\n", __func__, sta, cmd->cmdidx);
220
Macpaul Lin6d18f5e2011-07-20 21:29:58 +0000221 /* check DATA TIMEOUT or FAIL */
222 if (data) {
Macpaul Lin1a18a3e2011-11-28 17:30:17 +0000223
224 /* Transfer Complete */
225 if (sta & FTSDC010_STATUS_DATA_END)
226 clear |= FTSDC010_STATUS_DATA_END;
227
228 /* Data CRC_OK */
229 if (sta & FTSDC010_STATUS_DATA_CRC_OK)
230 clear |= FTSDC010_STATUS_DATA_CRC_OK;
231
232 /* DATA TIMEOUT or DATA CRC FAIL */
Macpaul Lin6d18f5e2011-07-20 21:29:58 +0000233 if (sta & FTSDC010_STATUS_DATA_TIMEOUT) {
234 /* DATA TIMEOUT */
Macpaul Lin1a18a3e2011-11-28 17:30:17 +0000235 debug("%s: DATA TIMEOUT: sta: %08x\n", __func__, sta);
Macpaul Lin6d18f5e2011-07-20 21:29:58 +0000236
237 clear |= FTSDC010_STATUS_DATA_TIMEOUT;
Macpaul Lin1a18a3e2011-11-28 17:30:17 +0000238 writel(clear, &host->reg->clr);
239
Macpaul Lin6d18f5e2011-07-20 21:29:58 +0000240 return TIMEOUT;
241 } else if (sta & FTSDC010_STATUS_DATA_CRC_FAIL) {
Macpaul Lin1a18a3e2011-11-28 17:30:17 +0000242 /* DATA CRC FAIL */
243 debug("%s: DATA CRC FAIL: sta: %08x\n", __func__, sta);
Macpaul Lin6d18f5e2011-07-20 21:29:58 +0000244
245 clear |= FTSDC010_STATUS_DATA_CRC_FAIL;
246 writel(clear, &host->reg->clr);
247
Macpaul Lin1a18a3e2011-11-28 17:30:17 +0000248 return COMM_ERR;
Macpaul Lin6d18f5e2011-07-20 21:29:58 +0000249 }
Macpaul Lin1a18a3e2011-11-28 17:30:17 +0000250 writel(clear, &host->reg->clr);
Macpaul Lin6d18f5e2011-07-20 21:29:58 +0000251 }
Macpaul Lin6d18f5e2011-07-20 21:29:58 +0000252 return 0;
253}
254
255static int ftsdc010_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd,
256 struct mmc_data *data)
257{
258 struct mmc_host *host = mmc->priv;
259
260#ifdef CONFIG_FTSDC010_SDIO
261 unsigned int scon;
262#endif
263 unsigned int ccon;
264 unsigned int mask, tmpmask;
265 unsigned int ret;
Macpaul Lin1a18a3e2011-11-28 17:30:17 +0000266 unsigned int sta, i;
267
268 ret = 0;
Macpaul Lin6d18f5e2011-07-20 21:29:58 +0000269
270 if (data)
271 mask = FTSDC010_INT_MASK_RSP_TIMEOUT;
272 else if (cmd->resp_type & MMC_RSP_PRESENT)
273 mask = FTSDC010_INT_MASK_RSP_TIMEOUT;
274 else
275 mask = FTSDC010_INT_MASK_CMD_SEND;
276
277 /* write argu reg */
Macpaul Lin1a18a3e2011-11-28 17:30:17 +0000278 debug("%s: argu: %08x\n", __func__, host->reg->argu);
Macpaul Lin6d18f5e2011-07-20 21:29:58 +0000279 writel(cmd->cmdarg, &host->reg->argu);
280
Macpaul Lin6d18f5e2011-07-20 21:29:58 +0000281 /* setup commnad */
282 ccon = FTSDC010_CMD_IDX(cmd->cmdidx);
283
284 /* setup command flags */
285 ccon |= FTSDC010_CMD_CMD_EN;
286
287 /*
288 * This hardware didn't support specific commands for mapping
289 * MMC_RSP_BUSY and MMC_RSP_OPCODE. Hence we don't deal with it.
290 */
291 if (cmd->resp_type & MMC_RSP_PRESENT) {
292 ccon |= FTSDC010_CMD_NEED_RSP;
293 mask |= FTSDC010_INT_MASK_RSP_CRC_OK |
294 FTSDC010_INT_MASK_RSP_CRC_FAIL;
295 }
296
297 if (cmd->resp_type & MMC_RSP_136)
298 ccon |= FTSDC010_CMD_LONG_RSP;
299
300 /* In Linux driver, MMC_CMD_APP_CMD is checked in last_opcode */
301 if (host->last_opcode == MMC_CMD_APP_CMD)
302 ccon |= FTSDC010_CMD_APP_CMD;
303
304#ifdef CONFIG_FTSDC010_SDIO
305 scon = readl(&host->reg->sdio_ctrl1);
306 if (host->card_type == MMC_TYPE_SDIO)
307 scon |= FTSDC010_SDIO_CTRL1_SDIO_ENABLE;
308 else
309 scon &= ~FTSDC010_SDIO_CTRL1_SDIO_ENABLE;
310 writel(scon, &host->reg->sdio_ctrl1);
311#endif
312
313 /* record last opcode for specifing the command type to hardware */
314 host->last_opcode = cmd->cmdidx;
315
316 /* write int_mask reg */
317 tmpmask = readl(&host->reg->int_mask);
318 tmpmask |= mask;
319 writel(tmpmask, &host->reg->int_mask);
320
321 /* write cmd reg */
322 debug("%s: ccon: %08x\n", __func__, ccon);
323 writel(ccon, &host->reg->cmd);
Macpaul Lin1a18a3e2011-11-28 17:30:17 +0000324
325 /* check CMD_SEND */
326 for (i = 0; i < FTSDC010_CMD_RETRY; i++) {
327 /*
328 * If we read status register too fast
329 * will lead hardware error and the RSP_TIMEOUT
330 * flag will be raised incorrectly.
331 */
332 udelay(16*FTSDC010_DELAY_UNIT);
333 sta = readl(&host->reg->status);
334
335 /* Command Complete */
336 /*
337 * Note:
338 * Do not clear FTSDC010_CLR_CMD_SEND flag.
339 * (by writing FTSDC010_CLR_CMD_SEND bit to clear register)
340 * It will make the driver becomes very slow.
341 * If the operation hasn't been finished, hardware will
342 * clear this bit automatically.
343 * In origin, the driver will clear this flag if there is
344 * no data need to be read.
345 */
346 if (sta & FTSDC010_STATUS_CMD_SEND)
347 break;
348 }
349
350 if (i > FTSDC010_CMD_RETRY) {
351 printf("%s: send command timeout\n", __func__);
352 return TIMEOUT;
353 }
354
355 /* check rsp status */
356 ret = ftsdc010_check_rsp(mmc, cmd, data);
357 if (ret)
358 return ret;
359
360 /* read response if we have RSP_OK */
361 if (ccon & FTSDC010_CMD_LONG_RSP) {
362 cmd->response[0] = readl(&host->reg->rsp3);
363 cmd->response[1] = readl(&host->reg->rsp2);
364 cmd->response[2] = readl(&host->reg->rsp1);
365 cmd->response[3] = readl(&host->reg->rsp0);
366 } else {
367 cmd->response[0] = readl(&host->reg->rsp0);
368 }
Macpaul Lin6d18f5e2011-07-20 21:29:58 +0000369
370 /* read/write data */
371 if (data && (data->flags & MMC_DATA_READ)) {
372 ftsdc010_pio_read(host, data->dest,
373 data->blocksize * data->blocks);
374 } else if (data && (data->flags & MMC_DATA_WRITE)) {
375 ftsdc010_pio_write(host, data->src,
376 data->blocksize * data->blocks);
377 }
378
Macpaul Lin1a18a3e2011-11-28 17:30:17 +0000379 /* check data status */
380 if (data) {
381 ret = ftsdc010_check_data(mmc, cmd, data);
382 if (ret)
383 return ret;
Macpaul Lin6d18f5e2011-07-20 21:29:58 +0000384 }
385
386 udelay(FTSDC010_DELAY_UNIT);
387 return ret;
388}
389
390static unsigned int cal_blksz(unsigned int blksz)
391{
392 unsigned int blksztwo = 0;
393
394 while (blksz >>= 1)
395 blksztwo++;
396
397 return blksztwo;
398}
399
400static int ftsdc010_setup_data(struct mmc *mmc, struct mmc_data *data)
401{
402 struct mmc_host *host = mmc->priv;
403 unsigned int dcon, newmask;
404
405 /* configure data transfer paramter */
406 if (!data)
407 return 0;
408
409 if (((data->blocksize - 1) & data->blocksize) != 0) {
410 printf("%s: can't do non-power-of 2 sized block transfers"
411 " (blksz %d)\n", __func__, data->blocksize);
412 return -1;
413 }
414
415 /*
416 * We cannot deal with unaligned blocks with more than
417 * one block being transfered.
418 */
419 if ((data->blocksize <= 2) && (data->blocks > 1)) {
420 printf("%s: can't do non-word sized block transfers"
421 " (blksz %d)\n", __func__, data->blocksize);
422 return -1;
423 }
424
425 /* data length */
426 dcon = data->blocksize * data->blocks;
427 writel(dcon, &host->reg->dlr);
428
429 /* write data control */
430 dcon = cal_blksz(data->blocksize);
431
432 /* add to IMASK register */
433 newmask = (FTSDC010_STATUS_RSP_CRC_FAIL | FTSDC010_STATUS_DATA_TIMEOUT);
434
435 /*
436 * enable UNDERRUN will trigger interrupt immediatedly
437 * So setup it when rsp is received successfully
438 */
439 if (data->flags & MMC_DATA_WRITE) {
440 dcon |= FTSDC010_DCR_DATA_WRITE;
441 } else {
442 dcon &= ~FTSDC010_DCR_DATA_WRITE;
443 newmask |= FTSDC010_STATUS_FIFO_ORUN;
444 }
445 enable_imask(host->reg, newmask);
446
447#ifdef CONFIG_FTSDC010_SDIO
448 /* always reset fifo since last transfer may fail */
449 dcon |= FTSDC010_DCR_FIFO_RST;
450
Macpaul Lin6d18f5e2011-07-20 21:29:58 +0000451 if (data->blocks > 1)
452 dcon |= FTSDC010_SDIO_CTRL1_SDIO_BLK_MODE;
453#endif
454
455 /* enable data transfer which will be pended until cmd is send */
456 dcon |= FTSDC010_DCR_DATA_EN;
457 writel(dcon, &host->reg->dcr);
458
459 return 0;
460}
461
462static int ftsdc010_send_request(struct mmc *mmc, struct mmc_cmd *cmd,
463 struct mmc_data *data)
464{
465 int ret;
466
467 if (data) {
468 ret = ftsdc010_setup_data(mmc, data);
469
470 if (ret) {
471 printf("%s: setup data error\n", __func__);
472 return -1;
473 }
474
475 if ((data->flags & MMC_DATA_BOTH_DIR) == MMC_DATA_BOTH_DIR) {
476 printf("%s: data is both direction\n", __func__);
477 return -1;
478 }
479 }
480
481 /* Send command */
482 ret = ftsdc010_send_cmd(mmc, cmd, data);
483 return ret;
484}
485
486static int ftsdc010_card_detect(struct mmc *mmc)
487{
488 struct mmc_host *host = mmc->priv;
489 unsigned int sta;
490
491 sta = readl(&host->reg->status);
492 debug("%s: card status: %08x\n", __func__, sta);
493
494 return (sta & FTSDC010_STATUS_CARD_DETECT) ? 0 : 1;
495}
496
497static int ftsdc010_request(struct mmc *mmc, struct mmc_cmd *cmd,
498 struct mmc_data *data)
499{
500 int ret;
501
502 if (ftsdc010_card_detect(mmc) == 0) {
503 printf("%s: no medium present\n", __func__);
504 return -1;
505 } else {
506 ret = ftsdc010_send_request(mmc, cmd, data);
507 return ret;
508 }
509}
510
511static void ftsdc010_set_clk(struct mmc *mmc)
512{
513 struct mmc_host *host = mmc->priv;
514 unsigned char clk_div;
Macpaul Lin1a18a3e2011-11-28 17:30:17 +0000515 unsigned int real_rate;
Macpaul Lin6d18f5e2011-07-20 21:29:58 +0000516 unsigned int clock;
517
518 debug("%s: mmc_set_clock: %x\n", __func__, mmc->clock);
519 clock = readl(&host->reg->ccr);
520
521 if (mmc->clock == 0) {
522 real_rate = 0;
523 clock |= FTSDC010_CCR_CLK_DIS;
524 } else {
525 debug("%s, mmc->clock: %08x, origin clock: %08x\n",
526 __func__, mmc->clock, clock);
527
528 for (clk_div = 0; clk_div <= 127; clk_div++) {
529 real_rate = (CONFIG_SYS_CLK_FREQ / 2) /
530 (2 * (clk_div + 1));
531
532 if (real_rate <= mmc->clock)
533 break;
534 }
535
Macpaul Lin1a18a3e2011-11-28 17:30:17 +0000536 debug("%s: computed real_rate: %x, clk_div: %x\n",
Macpaul Lin6d18f5e2011-07-20 21:29:58 +0000537 __func__, real_rate, clk_div);
538
539 if (clk_div > 127)
540 debug("%s: no match clock rate, %x\n",
541 __func__, mmc->clock);
542
543 clock = (clock & ~FTSDC010_CCR_CLK_DIV(0x7f)) |
544 FTSDC010_CCR_CLK_DIV(clk_div);
545
546 clock &= ~FTSDC010_CCR_CLK_DIS;
547 }
548
549 debug("%s, set clock: %08x\n", __func__, clock);
550 writel(clock, &host->reg->ccr);
551}
552
553static void ftsdc010_set_ios(struct mmc *mmc)
554{
555 struct mmc_host *host = mmc->priv;
556 unsigned int power;
557 unsigned long val;
558 unsigned int bus_width;
559
560 debug("%s: bus_width: %x, clock: %d\n",
561 __func__, mmc->bus_width, mmc->clock);
562
563 /* set pcr: power on */
564 power = readl(&host->reg->pcr);
565 power |= FTSDC010_PCR_POWER_ON;
566 writel(power, &host->reg->pcr);
567
568 if (mmc->clock)
569 ftsdc010_set_clk(mmc);
570
571 /* set bwr: bus width reg */
572 bus_width = readl(&host->reg->bwr);
573 bus_width &= ~(FTSDC010_BWR_WIDE_8_BUS | FTSDC010_BWR_WIDE_4_BUS |
574 FTSDC010_BWR_SINGLE_BUS);
575
576 if (mmc->bus_width == 8)
577 bus_width |= FTSDC010_BWR_WIDE_8_BUS;
578 else if (mmc->bus_width == 4)
579 bus_width |= FTSDC010_BWR_WIDE_4_BUS;
580 else
581 bus_width |= FTSDC010_BWR_SINGLE_BUS;
582
583 writel(bus_width, &host->reg->bwr);
584
585 /* set fifo depth */
586 val = readl(&host->reg->feature);
587 host->fifo_len = FTSDC010_FEATURE_FIFO_DEPTH(val) * 4; /* 4 bytes */
588
589 /* set data timeout register */
590 val = -1;
591 writel(val, &host->reg->dtr);
592}
593
594static void ftsdc010_reset(struct mmc_host *host)
595{
596 unsigned int timeout;
Macpaul Lin1a18a3e2011-11-28 17:30:17 +0000597 unsigned int sta;
Macpaul Lin6d18f5e2011-07-20 21:29:58 +0000598
599 /* Do SDC_RST: Software reset for all register */
600 writel(FTSDC010_CMD_SDC_RST, &host->reg->cmd);
601
602 host->clock = 0;
603
604 /* this hardware has no reset finish flag to read */
605 /* wait 100ms maximum */
606 timeout = 100;
607
608 /* hw clears the bit when it's done */
609 while (readl(&host->reg->dtr) != 0) {
610 if (timeout == 0) {
611 printf("%s: reset timeout error\n", __func__);
612 return;
613 }
614 timeout--;
615 udelay(10*FTSDC010_DELAY_UNIT);
616 }
Macpaul Lin1a18a3e2011-11-28 17:30:17 +0000617
618 sta = readl(&host->reg->status);
619 if (sta & FTSDC010_STATUS_CARD_CHANGE)
620 writel(FTSDC010_CLR_CARD_CHANGE, &host->reg->clr);
Macpaul Lin6d18f5e2011-07-20 21:29:58 +0000621}
622
623static int ftsdc010_core_init(struct mmc *mmc)
624{
625 struct mmc_host *host = mmc->priv;
626 unsigned int mask;
627 unsigned int major, minor, revision;
628
629 /* get hardware version */
630 host->version = readl(&host->reg->rev);
631
632 major = FTSDC010_REV_MAJOR(host->version);
633 minor = FTSDC010_REV_MINOR(host->version);
634 revision = FTSDC010_REV_REVISION(host->version);
635
636 printf("ftsdc010 hardware ver: %d_%d_r%d\n", major, minor, revision);
637
638 /* Interrupt MASK register init - mask all */
639 writel(0x0, &host->reg->int_mask);
640
641 mask = FTSDC010_INT_MASK_CMD_SEND |
642 FTSDC010_INT_MASK_DATA_END |
643 FTSDC010_INT_MASK_CARD_CHANGE;
644#ifdef CONFIG_FTSDC010_SDIO
645 mask |= FTSDC010_INT_MASK_CP_READY |
646 FTSDC010_INT_MASK_CP_BUF_READY |
647 FTSDC010_INT_MASK_PLAIN_TEXT_READY |
648 FTSDC010_INT_MASK_SDIO_IRPT;
649#endif
650
651 writel(mask, &host->reg->int_mask);
652
653 return 0;
654}
655
656int ftsdc010_mmc_init(int dev_index)
657{
658 struct mmc *mmc;
659 struct mmc_host *host;
660
661 mmc = &ftsdc010_dev[dev_index];
662
663 sprintf(mmc->name, "FTSDC010 SD/MMC");
664 mmc->priv = &ftsdc010_host[dev_index];
665 mmc->send_cmd = ftsdc010_request;
666 mmc->set_ios = ftsdc010_set_ios;
667 mmc->init = ftsdc010_core_init;
Thierry Redingb9c8b772012-01-02 01:15:37 +0000668 mmc->getcd = NULL;
Nikita Kiryanov020f2612012-12-03 02:19:46 +0000669 mmc->getwp = NULL;
Macpaul Lin6d18f5e2011-07-20 21:29:58 +0000670
671 mmc->voltages = MMC_VDD_32_33 | MMC_VDD_33_34;
672
673 mmc->host_caps = MMC_MODE_4BIT | MMC_MODE_8BIT;
674
Macpaul Lin6d18f5e2011-07-20 21:29:58 +0000675 mmc->f_min = CONFIG_SYS_CLK_FREQ / 2 / (2*128);
676 mmc->f_max = CONFIG_SYS_CLK_FREQ / 2 / 2;
677
678 ftsdc010_host[dev_index].clock = 0;
679 ftsdc010_host[dev_index].reg = ftsdc010_get_base_mmc(dev_index);
680 mmc_register(mmc);
681
682 /* reset mmc */
683 host = (struct mmc_host *)mmc->priv;
684 ftsdc010_reset(host);
685
686 return 0;
687}