]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - drivers/mmc/ftsdc010_mci.c
Merge branch 'master' of git://git.denx.de/u-boot-video
[karo-tx-uboot.git] / drivers / mmc / ftsdc010_mci.c
1 /*
2  * Faraday MMC/SD Host Controller
3  *
4  * (C) Copyright 2010 Faraday Technology
5  * Dante Su <dantesu@faraday-tech.com>
6  *
7  * This file is released under the terms of GPL v2 and any later version.
8  * See the file COPYING in the root directory of the source tree for details.
9  */
10
11 #include <common.h>
12 #include <malloc.h>
13 #include <part.h>
14 #include <mmc.h>
15
16 #include <asm/io.h>
17 #include <asm/errno.h>
18 #include <asm/byteorder.h>
19 #include <faraday/ftsdc010.h>
20
21 #define CFG_CMD_TIMEOUT (CONFIG_SYS_HZ >> 4) /* 250 ms */
22 #define CFG_RST_TIMEOUT CONFIG_SYS_HZ /* 1 sec reset timeout */
23
24 struct ftsdc010_chip {
25         void __iomem *regs;
26         uint32_t wprot;   /* write protected (locked) */
27         uint32_t rate;    /* actual SD clock in Hz */
28         uint32_t sclk;    /* FTSDC010 source clock in Hz */
29         uint32_t fifo;    /* fifo depth in bytes */
30         uint32_t acmd;
31 };
32
33 static inline int ftsdc010_send_cmd(struct mmc *mmc, struct mmc_cmd *mmc_cmd)
34 {
35         struct ftsdc010_chip *chip = mmc->priv;
36         struct ftsdc010_mmc __iomem *regs = chip->regs;
37         int ret = TIMEOUT;
38         uint32_t ts, st;
39         uint32_t cmd   = FTSDC010_CMD_IDX(mmc_cmd->cmdidx);
40         uint32_t arg   = mmc_cmd->cmdarg;
41         uint32_t flags = mmc_cmd->resp_type;
42
43         cmd |= FTSDC010_CMD_CMD_EN;
44
45         if (chip->acmd) {
46                 cmd |= FTSDC010_CMD_APP_CMD;
47                 chip->acmd = 0;
48         }
49
50         if (flags & MMC_RSP_PRESENT)
51                 cmd |= FTSDC010_CMD_NEED_RSP;
52
53         if (flags & MMC_RSP_136)
54                 cmd |= FTSDC010_CMD_LONG_RSP;
55
56         writel(FTSDC010_STATUS_RSP_MASK | FTSDC010_STATUS_CMD_SEND,
57                 &regs->clr);
58         writel(arg, &regs->argu);
59         writel(cmd, &regs->cmd);
60
61         if (!(flags & (MMC_RSP_PRESENT | MMC_RSP_136))) {
62                 for (ts = get_timer(0); get_timer(ts) < CFG_CMD_TIMEOUT; ) {
63                         if (readl(&regs->status) & FTSDC010_STATUS_CMD_SEND) {
64                                 writel(FTSDC010_STATUS_CMD_SEND, &regs->clr);
65                                 ret = 0;
66                                 break;
67                         }
68                 }
69         } else {
70                 st = 0;
71                 for (ts = get_timer(0); get_timer(ts) < CFG_CMD_TIMEOUT; ) {
72                         st = readl(&regs->status);
73                         writel(st & FTSDC010_STATUS_RSP_MASK, &regs->clr);
74                         if (st & FTSDC010_STATUS_RSP_MASK)
75                                 break;
76                 }
77                 if (st & FTSDC010_STATUS_RSP_CRC_OK) {
78                         if (flags & MMC_RSP_136) {
79                                 mmc_cmd->response[0] = readl(&regs->rsp3);
80                                 mmc_cmd->response[1] = readl(&regs->rsp2);
81                                 mmc_cmd->response[2] = readl(&regs->rsp1);
82                                 mmc_cmd->response[3] = readl(&regs->rsp0);
83                         } else {
84                                 mmc_cmd->response[0] = readl(&regs->rsp0);
85                         }
86                         ret = 0;
87                 } else {
88                         debug("ftsdc010: rsp err (cmd=%d, st=0x%x)\n",
89                                 mmc_cmd->cmdidx, st);
90                 }
91         }
92
93         if (ret) {
94                 debug("ftsdc010: cmd timeout (op code=%d)\n",
95                         mmc_cmd->cmdidx);
96         } else if (mmc_cmd->cmdidx == MMC_CMD_APP_CMD) {
97                 chip->acmd = 1;
98         }
99
100         return ret;
101 }
102
103 static void ftsdc010_clkset(struct mmc *mmc, uint32_t rate)
104 {
105         struct ftsdc010_chip *chip = mmc->priv;
106         struct ftsdc010_mmc __iomem *regs = chip->regs;
107         uint32_t div;
108
109         for (div = 0; div < 0x7f; ++div) {
110                 if (rate >= chip->sclk / (2 * (div + 1)))
111                         break;
112         }
113         chip->rate = chip->sclk / (2 * (div + 1));
114
115         writel(FTSDC010_CCR_CLK_DIV(div), &regs->ccr);
116
117         if (IS_SD(mmc)) {
118                 setbits_le32(&regs->ccr, FTSDC010_CCR_CLK_SD);
119
120                 if (chip->rate > 25000000)
121                         setbits_le32(&regs->ccr, FTSDC010_CCR_CLK_HISPD);
122                 else
123                         clrbits_le32(&regs->ccr, FTSDC010_CCR_CLK_HISPD);
124         }
125 }
126
127 static inline int ftsdc010_is_ro(struct mmc *mmc)
128 {
129         struct ftsdc010_chip *chip = mmc->priv;
130         const uint8_t *csd = (const uint8_t *)mmc->csd;
131
132         return chip->wprot || (csd[1] & 0x30);
133 }
134
135 static int ftsdc010_wait(struct ftsdc010_mmc __iomem *regs, uint32_t mask)
136 {
137         int ret = TIMEOUT;
138         uint32_t st, ts;
139
140         for (ts = get_timer(0); get_timer(ts) < CFG_CMD_TIMEOUT; ) {
141                 st = readl(&regs->status);
142                 if (!(st & mask))
143                         continue;
144                 writel(st & mask, &regs->clr);
145                 ret = 0;
146                 break;
147         }
148
149         if (ret)
150                 debug("ftsdc010: wait st(0x%x) timeout\n", mask);
151
152         return ret;
153 }
154
155 /*
156  * u-boot mmc api
157  */
158
159 static int ftsdc010_request(struct mmc *mmc, struct mmc_cmd *cmd,
160         struct mmc_data *data)
161 {
162         int ret = UNUSABLE_ERR;
163         uint32_t len = 0;
164         struct ftsdc010_chip *chip = mmc->priv;
165         struct ftsdc010_mmc __iomem *regs = chip->regs;
166
167         if (data && (data->flags & MMC_DATA_WRITE) && chip->wprot) {
168                 printf("ftsdc010: the card is write protected!\n");
169                 return ret;
170         }
171
172         if (data) {
173                 uint32_t dcr;
174
175                 len = data->blocksize * data->blocks;
176
177                 /* 1. data disable + fifo reset */
178                 writel(FTSDC010_DCR_FIFO_RST, &regs->dcr);
179
180                 /* 2. clear status register */
181                 writel(FTSDC010_STATUS_DATA_MASK | FTSDC010_STATUS_FIFO_URUN
182                         | FTSDC010_STATUS_FIFO_ORUN, &regs->clr);
183
184                 /* 3. data timeout (1 sec) */
185                 writel(chip->rate, &regs->dtr);
186
187                 /* 4. data length (bytes) */
188                 writel(len, &regs->dlr);
189
190                 /* 5. data enable */
191                 dcr = (ffs(data->blocksize) - 1) | FTSDC010_DCR_DATA_EN;
192                 if (data->flags & MMC_DATA_WRITE)
193                         dcr |= FTSDC010_DCR_DATA_WRITE;
194                 writel(dcr, &regs->dcr);
195         }
196
197         ret = ftsdc010_send_cmd(mmc, cmd);
198         if (ret) {
199                 printf("ftsdc010: CMD%d failed\n", cmd->cmdidx);
200                 return ret;
201         }
202
203         if (!data)
204                 return ret;
205
206         if (data->flags & MMC_DATA_WRITE) {
207                 const uint8_t *buf = (const uint8_t *)data->src;
208
209                 while (len > 0) {
210                         int wlen;
211
212                         /* wait for tx ready */
213                         ret = ftsdc010_wait(regs, FTSDC010_STATUS_FIFO_URUN);
214                         if (ret)
215                                 break;
216
217                         /* write bytes to ftsdc010 */
218                         for (wlen = 0; wlen < len && wlen < chip->fifo; ) {
219                                 writel(*(uint32_t *)buf, &regs->dwr);
220                                 buf  += 4;
221                                 wlen += 4;
222                         }
223
224                         len -= wlen;
225                 }
226
227         } else {
228                 uint8_t *buf = (uint8_t *)data->dest;
229
230                 while (len > 0) {
231                         int rlen;
232
233                         /* wait for rx ready */
234                         ret = ftsdc010_wait(regs, FTSDC010_STATUS_FIFO_ORUN);
235                         if (ret)
236                                 break;
237
238                         /* fetch bytes from ftsdc010 */
239                         for (rlen = 0; rlen < len && rlen < chip->fifo; ) {
240                                 *(uint32_t *)buf = readl(&regs->dwr);
241                                 buf  += 4;
242                                 rlen += 4;
243                         }
244
245                         len -= rlen;
246                 }
247
248         }
249
250         if (!ret) {
251                 ret = ftsdc010_wait(regs,
252                         FTSDC010_STATUS_DATA_END | FTSDC010_STATUS_DATA_ERROR);
253         }
254
255         return ret;
256 }
257
258 static void ftsdc010_set_ios(struct mmc *mmc)
259 {
260         struct ftsdc010_chip *chip = mmc->priv;
261         struct ftsdc010_mmc __iomem *regs = chip->regs;
262
263         ftsdc010_clkset(mmc, mmc->clock);
264
265         clrbits_le32(&regs->bwr, FTSDC010_BWR_MODE_MASK);
266         switch (mmc->bus_width) {
267         case 4:
268                 setbits_le32(&regs->bwr, FTSDC010_BWR_MODE_4BIT);
269                 break;
270         case 8:
271                 setbits_le32(&regs->bwr, FTSDC010_BWR_MODE_8BIT);
272                 break;
273         default:
274                 setbits_le32(&regs->bwr, FTSDC010_BWR_MODE_1BIT);
275                 break;
276         }
277 }
278
279 static int ftsdc010_init(struct mmc *mmc)
280 {
281         struct ftsdc010_chip *chip = mmc->priv;
282         struct ftsdc010_mmc __iomem *regs = chip->regs;
283         uint32_t ts;
284
285         if (readl(&regs->status) & FTSDC010_STATUS_CARD_DETECT)
286                 return NO_CARD_ERR;
287
288         if (readl(&regs->status) & FTSDC010_STATUS_WRITE_PROT) {
289                 printf("ftsdc010: write protected\n");
290                 chip->wprot = 1;
291         }
292
293         chip->fifo = (readl(&regs->feature) & 0xff) << 2;
294
295         /* 1. chip reset */
296         writel(FTSDC010_CMD_SDC_RST, &regs->cmd);
297         for (ts = get_timer(0); get_timer(ts) < CFG_RST_TIMEOUT; ) {
298                 if (readl(&regs->cmd) & FTSDC010_CMD_SDC_RST)
299                         continue;
300                 break;
301         }
302         if (readl(&regs->cmd) & FTSDC010_CMD_SDC_RST) {
303                 printf("ftsdc010: reset failed\n");
304                 return UNUSABLE_ERR;
305         }
306
307         /* 2. enter low speed mode (400k card detection) */
308         ftsdc010_clkset(mmc, 400000);
309
310         /* 3. interrupt disabled */
311         writel(0, &regs->int_mask);
312
313         return 0;
314 }
315
316 int ftsdc010_mmc_init(int devid)
317 {
318         struct mmc *mmc;
319         struct ftsdc010_chip *chip;
320         struct ftsdc010_mmc __iomem *regs;
321 #ifdef CONFIG_FTSDC010_BASE_LIST
322         uint32_t base_list[] = CONFIG_FTSDC010_BASE_LIST;
323
324         if (devid < 0 || devid >= ARRAY_SIZE(base_list))
325                 return -1;
326         regs = (void __iomem *)base_list[devid];
327 #else
328         regs = (void __iomem *)(CONFIG_FTSDC010_BASE + (devid << 20));
329 #endif
330
331         mmc = malloc(sizeof(struct mmc));
332         if (!mmc)
333                 return -ENOMEM;
334         memset(mmc, 0, sizeof(struct mmc));
335
336         chip = malloc(sizeof(struct ftsdc010_chip));
337         if (!chip) {
338                 free(mmc);
339                 return -ENOMEM;
340         }
341         memset(chip, 0, sizeof(struct ftsdc010_chip));
342
343         chip->regs = regs;
344         mmc->priv  = chip;
345
346         sprintf(mmc->name, "ftsdc010");
347         mmc->send_cmd  = ftsdc010_request;
348         mmc->set_ios   = ftsdc010_set_ios;
349         mmc->init      = ftsdc010_init;
350
351         mmc->host_caps = MMC_MODE_HS | MMC_MODE_HS_52MHz;
352         switch (readl(&regs->bwr) & FTSDC010_BWR_CAPS_MASK) {
353         case FTSDC010_BWR_CAPS_4BIT:
354                 mmc->host_caps |= MMC_MODE_4BIT;
355                 break;
356         case FTSDC010_BWR_CAPS_8BIT:
357                 mmc->host_caps |= MMC_MODE_4BIT | MMC_MODE_8BIT;
358                 break;
359         default:
360                 break;
361         }
362
363 #ifdef CONFIG_SYS_CLK_FREQ
364         chip->sclk = CONFIG_SYS_CLK_FREQ;
365 #else
366         chip->sclk = clk_get_rate("SDC");
367 #endif
368
369         mmc->voltages  = MMC_VDD_32_33 | MMC_VDD_33_34;
370         mmc->f_max     = chip->sclk / 2;
371         mmc->f_min     = chip->sclk / 0x100;
372         mmc->block_dev.part_type = PART_TYPE_DOS;
373
374         mmc_register(mmc);
375
376         return 0;
377 }