]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - drivers/mmc/ftsdc010_mci.c
JFFS2: Speed up and fix comparison functions
[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  * SPDX-License-Identifier:     GPL-2.0+
8  */
9
10 #include <common.h>
11 #include <malloc.h>
12 #include <part.h>
13 #include <mmc.h>
14
15 #include <asm/io.h>
16 #include <asm/errno.h>
17 #include <asm/byteorder.h>
18 #include <faraday/ftsdc010.h>
19
20 #define CFG_CMD_TIMEOUT (CONFIG_SYS_HZ >> 4) /* 250 ms */
21 #define CFG_RST_TIMEOUT CONFIG_SYS_HZ /* 1 sec reset timeout */
22
23 struct ftsdc010_chip {
24         void __iomem *regs;
25         uint32_t wprot;   /* write protected (locked) */
26         uint32_t rate;    /* actual SD clock in Hz */
27         uint32_t sclk;    /* FTSDC010 source clock in Hz */
28         uint32_t fifo;    /* fifo depth in bytes */
29         uint32_t acmd;
30         struct mmc_config cfg;  /* mmc configuration */
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 int ftsdc010_wait(struct ftsdc010_mmc __iomem *regs, uint32_t mask)
128 {
129         int ret = TIMEOUT;
130         uint32_t st, ts;
131
132         for (ts = get_timer(0); get_timer(ts) < CFG_CMD_TIMEOUT; ) {
133                 st = readl(&regs->status);
134                 if (!(st & mask))
135                         continue;
136                 writel(st & mask, &regs->clr);
137                 ret = 0;
138                 break;
139         }
140
141         if (ret)
142                 debug("ftsdc010: wait st(0x%x) timeout\n", mask);
143
144         return ret;
145 }
146
147 /*
148  * u-boot mmc api
149  */
150
151 static int ftsdc010_request(struct mmc *mmc, struct mmc_cmd *cmd,
152         struct mmc_data *data)
153 {
154         int ret = UNUSABLE_ERR;
155         uint32_t len = 0;
156         struct ftsdc010_chip *chip = mmc->priv;
157         struct ftsdc010_mmc __iomem *regs = chip->regs;
158
159         if (data && (data->flags & MMC_DATA_WRITE) && chip->wprot) {
160                 printf("ftsdc010: the card is write protected!\n");
161                 return ret;
162         }
163
164         if (data) {
165                 uint32_t dcr;
166
167                 len = data->blocksize * data->blocks;
168
169                 /* 1. data disable + fifo reset */
170                 dcr = 0;
171 #ifdef CONFIG_FTSDC010_SDIO
172                 dcr |= FTSDC010_DCR_FIFO_RST;
173 #endif
174                 writel(dcr, &regs->dcr);
175
176                 /* 2. clear status register */
177                 writel(FTSDC010_STATUS_DATA_MASK | FTSDC010_STATUS_FIFO_URUN
178                         | FTSDC010_STATUS_FIFO_ORUN, &regs->clr);
179
180                 /* 3. data timeout (1 sec) */
181                 writel(chip->rate, &regs->dtr);
182
183                 /* 4. data length (bytes) */
184                 writel(len, &regs->dlr);
185
186                 /* 5. data enable */
187                 dcr = (ffs(data->blocksize) - 1) | FTSDC010_DCR_DATA_EN;
188                 if (data->flags & MMC_DATA_WRITE)
189                         dcr |= FTSDC010_DCR_DATA_WRITE;
190                 writel(dcr, &regs->dcr);
191         }
192
193         ret = ftsdc010_send_cmd(mmc, cmd);
194         if (ret) {
195                 printf("ftsdc010: CMD%d failed\n", cmd->cmdidx);
196                 return ret;
197         }
198
199         if (!data)
200                 return ret;
201
202         if (data->flags & MMC_DATA_WRITE) {
203                 const uint8_t *buf = (const uint8_t *)data->src;
204
205                 while (len > 0) {
206                         int wlen;
207
208                         /* wait for tx ready */
209                         ret = ftsdc010_wait(regs, FTSDC010_STATUS_FIFO_URUN);
210                         if (ret)
211                                 break;
212
213                         /* write bytes to ftsdc010 */
214                         for (wlen = 0; wlen < len && wlen < chip->fifo; ) {
215                                 writel(*(uint32_t *)buf, &regs->dwr);
216                                 buf  += 4;
217                                 wlen += 4;
218                         }
219
220                         len -= wlen;
221                 }
222
223         } else {
224                 uint8_t *buf = (uint8_t *)data->dest;
225
226                 while (len > 0) {
227                         int rlen;
228
229                         /* wait for rx ready */
230                         ret = ftsdc010_wait(regs, FTSDC010_STATUS_FIFO_ORUN);
231                         if (ret)
232                                 break;
233
234                         /* fetch bytes from ftsdc010 */
235                         for (rlen = 0; rlen < len && rlen < chip->fifo; ) {
236                                 *(uint32_t *)buf = readl(&regs->dwr);
237                                 buf  += 4;
238                                 rlen += 4;
239                         }
240
241                         len -= rlen;
242                 }
243
244         }
245
246         if (!ret) {
247                 ret = ftsdc010_wait(regs,
248                         FTSDC010_STATUS_DATA_END | FTSDC010_STATUS_DATA_ERROR);
249         }
250
251         return ret;
252 }
253
254 static void ftsdc010_set_ios(struct mmc *mmc)
255 {
256         struct ftsdc010_chip *chip = mmc->priv;
257         struct ftsdc010_mmc __iomem *regs = chip->regs;
258
259         ftsdc010_clkset(mmc, mmc->clock);
260
261         clrbits_le32(&regs->bwr, FTSDC010_BWR_MODE_MASK);
262         switch (mmc->bus_width) {
263         case 4:
264                 setbits_le32(&regs->bwr, FTSDC010_BWR_MODE_4BIT);
265                 break;
266         case 8:
267                 setbits_le32(&regs->bwr, FTSDC010_BWR_MODE_8BIT);
268                 break;
269         default:
270                 setbits_le32(&regs->bwr, FTSDC010_BWR_MODE_1BIT);
271                 break;
272         }
273 }
274
275 static int ftsdc010_init(struct mmc *mmc)
276 {
277         struct ftsdc010_chip *chip = mmc->priv;
278         struct ftsdc010_mmc __iomem *regs = chip->regs;
279         uint32_t ts;
280
281         if (readl(&regs->status) & FTSDC010_STATUS_CARD_DETECT)
282                 return NO_CARD_ERR;
283
284         if (readl(&regs->status) & FTSDC010_STATUS_WRITE_PROT) {
285                 printf("ftsdc010: write protected\n");
286                 chip->wprot = 1;
287         }
288
289         chip->fifo = (readl(&regs->feature) & 0xff) << 2;
290
291         /* 1. chip reset */
292         writel(FTSDC010_CMD_SDC_RST, &regs->cmd);
293         for (ts = get_timer(0); get_timer(ts) < CFG_RST_TIMEOUT; ) {
294                 if (readl(&regs->cmd) & FTSDC010_CMD_SDC_RST)
295                         continue;
296                 break;
297         }
298         if (readl(&regs->cmd) & FTSDC010_CMD_SDC_RST) {
299                 printf("ftsdc010: reset failed\n");
300                 return UNUSABLE_ERR;
301         }
302
303         /* 2. enter low speed mode (400k card detection) */
304         ftsdc010_clkset(mmc, 400000);
305
306         /* 3. interrupt disabled */
307         writel(0, &regs->int_mask);
308
309         return 0;
310 }
311
312 static const struct mmc_ops ftsdc010_ops = {
313         .send_cmd       = ftsdc010_request,
314         .set_ios        = ftsdc010_set_ios,
315         .init           = ftsdc010_init,
316 };
317
318 int ftsdc010_mmc_init(int devid)
319 {
320         struct mmc *mmc;
321         struct ftsdc010_chip *chip;
322         struct ftsdc010_mmc __iomem *regs;
323 #ifdef CONFIG_FTSDC010_BASE_LIST
324         uint32_t base_list[] = CONFIG_FTSDC010_BASE_LIST;
325
326         if (devid < 0 || devid >= ARRAY_SIZE(base_list))
327                 return -1;
328         regs = (void __iomem *)base_list[devid];
329 #else
330         regs = (void __iomem *)(CONFIG_FTSDC010_BASE + (devid << 20));
331 #endif
332
333         chip = malloc(sizeof(struct ftsdc010_chip));
334         if (!chip)
335                 return -ENOMEM;
336         memset(chip, 0, sizeof(struct ftsdc010_chip));
337
338         chip->regs = regs;
339 #ifdef CONFIG_SYS_CLK_FREQ
340         chip->sclk = CONFIG_SYS_CLK_FREQ;
341 #else
342         chip->sclk = clk_get_rate("SDC");
343 #endif
344
345         chip->cfg.name = "ftsdc010";
346         chip->cfg.ops = &ftsdc010_ops;
347         chip->cfg.host_caps = MMC_MODE_HS | MMC_MODE_HS_52MHz;
348         switch (readl(&regs->bwr) & FTSDC010_BWR_CAPS_MASK) {
349         case FTSDC010_BWR_CAPS_4BIT:
350                 chip->cfg.host_caps |= MMC_MODE_4BIT;
351                 break;
352         case FTSDC010_BWR_CAPS_8BIT:
353                 chip->cfg.host_caps |= MMC_MODE_4BIT | MMC_MODE_8BIT;
354                 break;
355         default:
356                 break;
357         }
358
359         chip->cfg.voltages  = MMC_VDD_32_33 | MMC_VDD_33_34;
360         chip->cfg.f_max     = chip->sclk / 2;
361         chip->cfg.f_min     = chip->sclk / 0x100;
362
363         chip->cfg.part_type = PART_TYPE_DOS;
364         chip->cfg.b_max     = CONFIG_SYS_MMC_MAX_BLK_COUNT;
365
366         mmc = mmc_create(&chip->cfg, chip);
367         if (mmc == NULL) {
368                 free(chip);
369                 return -ENOMEM;
370         }
371
372         return 0;
373 }