fix IMQ on linux 2.6.27 and 2.6.28
[openwrt.git] / target / linux / s3c24xx / patches-2.6.24 / 1023-s3c_mci.patch.patch
1 From fbe3b2447eb15d4d34d906c8112bb33454163612 Mon Sep 17 00:00:00 2001
2 From: mokopatches <mokopatches@openmoko.org>
3 Date: Fri, 4 Apr 2008 11:33:15 +0100
4 Subject: [PATCH] s3c_mci.patch
5 This is a MMC/SD driver for the Samsung S3C24xx SD/MMC controller, originally
6 developed years ago by Thomas Kleffel <tk@maintech.de>.
7
8 Due to time restraints, he had no time to further maintain the driver and
9 follow the mainline Linux changes in the SD/MMC stack.
10
11 With his authorization, I have taken over the task of making it compliant to
12 the current mainline SD/MMC API and take care of the mainline kernel merge.
13
14 After a potential kernel inclusion, we would co-maintain the driver.
15
16 Acked-by: Thomas Kleffel <tk@maintech.de>
17 Signed-off-by: Harald Welte <laforge@gnumonks.org>
18 ---
19 arch/arm/mach-s3c2412/s3c2412.c | 3 +
20 arch/arm/mach-s3c2440/s3c2440.c | 3 +
21 arch/arm/mach-s3c2442/s3c2442.c | 4 +
22 drivers/mmc/host/Kconfig | 11 +
23 drivers/mmc/host/Makefile | 2 +-
24 drivers/mmc/host/s3cmci.c | 1419 +++++++++++++++++++++++++++++++
25 drivers/mmc/host/s3cmci.h | 69 ++
26 include/asm-arm/arch-s3c2410/mci.h | 13 +
27 include/asm-arm/arch-s3c2410/regs-sdi.h | 22 +-
28 9 files changed, 1542 insertions(+), 4 deletions(-)
29 create mode 100644 drivers/mmc/host/s3cmci.c
30 create mode 100644 drivers/mmc/host/s3cmci.h
31 create mode 100644 include/asm-arm/arch-s3c2410/mci.h
32
33 diff --git a/arch/arm/mach-s3c2412/s3c2412.c b/arch/arm/mach-s3c2412/s3c2412.c
34 index 4f92a15..6b45fd9 100644
35 --- a/arch/arm/mach-s3c2412/s3c2412.c
36 +++ b/arch/arm/mach-s3c2412/s3c2412.c
37 @@ -214,5 +214,8 @@ int __init s3c2412_init(void)
38 {
39 printk("S3C2412: Initialising architecture\n");
40
41 + /* make sure SD/MMC driver can distinguish 2412 from 2410 */
42 + s3c_device_sdi.name = "s3c2412-sdi";
43 +
44 return sysdev_register(&s3c2412_sysdev);
45 }
46 diff --git a/arch/arm/mach-s3c2440/s3c2440.c b/arch/arm/mach-s3c2440/s3c2440.c
47 index 90e1da6..6c18cbd 100644
48 --- a/arch/arm/mach-s3c2440/s3c2440.c
49 +++ b/arch/arm/mach-s3c2440/s3c2440.c
50 @@ -46,6 +46,9 @@ int __init s3c2440_init(void)
51 s3c_device_wdt.resource[1].start = IRQ_S3C2440_WDT;
52 s3c_device_wdt.resource[1].end = IRQ_S3C2440_WDT;
53
54 + /* make sure SD/MMC driver can distinguish 2440 from 2410 */
55 + s3c_device_sdi.name = "s3c2440-sdi";
56 +
57 /* register our system device for everything else */
58
59 return sysdev_register(&s3c2440_sysdev);
60 diff --git a/arch/arm/mach-s3c2442/s3c2442.c b/arch/arm/mach-s3c2442/s3c2442.c
61 index fbf8264..fbfb330 100644
62 --- a/arch/arm/mach-s3c2442/s3c2442.c
63 +++ b/arch/arm/mach-s3c2442/s3c2442.c
64 @@ -21,6 +21,7 @@
65
66 #include <asm/plat-s3c24xx/s3c2442.h>
67 #include <asm/plat-s3c24xx/cpu.h>
68 +#include <asm/plat-s3c24xx/devs.h>
69
70 static struct sys_device s3c2442_sysdev = {
71 .cls = &s3c2442_sysclass,
72 @@ -30,5 +31,8 @@ int __init s3c2442_init(void)
73 {
74 printk("S3C2442: Initialising architecture\n");
75
76 + /* make sure SD/MMC driver can distinguish 2440 from 2410 */
77 + s3c_device_sdi.name = "s3c2440-sdi";
78 +
79 return sysdev_register(&s3c2442_sysdev);
80 }
81 diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig
82 index 5fef678..6936802 100644
83 --- a/drivers/mmc/host/Kconfig
84 +++ b/drivers/mmc/host/Kconfig
85 @@ -130,3 +130,14 @@ config MMC_SPI
86
87 If unsure, or if your system has no SPI master driver, say N.
88
89 +config MMC_S3C
90 + tristate "Samsung S3C24xx SD/MMC Card Interface support"
91 + depends on ARCH_S3C2410 && MMC
92 + help
93 + This selects a driver for the MCI interface found in
94 + Samsung's S3C2410, S3C2412, S3C2440, S3C2442 CPUs.
95 + If you have a board based on one of those and a MMC/SD
96 + slot, say Y or M here.
97 +
98 + If unsure, say N.
99 +
100 diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile
101 index 3877c87..071d256 100644
102 --- a/drivers/mmc/host/Makefile
103 +++ b/drivers/mmc/host/Makefile
104 @@ -17,4 +17,4 @@ obj-$(CONFIG_MMC_OMAP) += omap.o
105 obj-$(CONFIG_MMC_AT91) += at91_mci.o
106 obj-$(CONFIG_MMC_TIFM_SD) += tifm_sd.o
107 obj-$(CONFIG_MMC_SPI) += mmc_spi.o
108 -
109 +obj-$(CONFIG_MMC_S3C) += s3cmci.o
110 diff --git a/drivers/mmc/host/s3cmci.c b/drivers/mmc/host/s3cmci.c
111 new file mode 100644
112 index 0000000..edba055
113 --- /dev/null
114 +++ b/drivers/mmc/host/s3cmci.c
115 @@ -0,0 +1,1419 @@
116 +/*
117 + * linux/drivers/mmc/s3cmci.h - Samsung S3C MCI driver
118 + *
119 + * Copyright (C) 2004-2006 maintech GmbH, Thomas Kleffel <tk@maintech.de>
120 + * Copyright (C) 2007 Harald Welte <laforge@gnumonks.org>
121 + *
122 + * This program is free software; you can redistribute it and/or modify
123 + * it under the terms of the GNU General Public License version 2 as
124 + * published by the Free Software Foundation.
125 + */
126 +
127 +#include <linux/module.h>
128 +#include <linux/dma-mapping.h>
129 +#include <linux/clk.h>
130 +#include <linux/mmc/host.h>
131 +#include <linux/platform_device.h>
132 +#include <linux/irq.h>
133 +
134 +#include <asm/dma.h>
135 +#include <asm/dma-mapping.h>
136 +
137 +#include <asm/io.h>
138 +#include <asm/arch/regs-sdi.h>
139 +#include <asm/arch/regs-gpio.h>
140 +#include <asm/arch/mci.h>
141 +#include <asm/arch/dma.h>
142 +
143 +#include "s3cmci.h"
144 +
145 +#define DRIVER_NAME "s3c-mci"
146 +
147 +enum dbg_channels {
148 + dbg_err = (1 << 0),
149 + dbg_debug = (1 << 1),
150 + dbg_info = (1 << 2),
151 + dbg_irq = (1 << 3),
152 + dbg_sg = (1 << 4),
153 + dbg_dma = (1 << 5),
154 + dbg_pio = (1 << 6),
155 + dbg_fail = (1 << 7),
156 + dbg_conf = (1 << 8),
157 +};
158 +
159 +static const int dbgmap_err = dbg_err | dbg_fail;
160 +static const int dbgmap_info = dbg_info | dbg_conf;
161 +static const int dbgmap_debug = dbg_debug;
162 +
163 +#define dbg(host, channels, args...) \
164 + do { \
165 + if (dbgmap_err & channels) \
166 + dev_err(&host->pdev->dev, args); \
167 + else if (dbgmap_info & channels) \
168 + dev_info(&host->pdev->dev, args);\
169 + else if (dbgmap_debug & channels) \
170 + dev_dbg(&host->pdev->dev, args); \
171 + } while (0)
172 +
173 +#define RESSIZE(ressource) (((ressource)->end - (ressource)->start)+1)
174 +
175 +static struct s3c2410_dma_client s3cmci_dma_client = {
176 + .name = "s3c-mci",
177 +};
178 +
179 +static void finalize_request(struct s3cmci_host *host);
180 +static void s3cmci_send_request(struct mmc_host *mmc);
181 +static void s3cmci_reset(struct s3cmci_host *host);
182 +
183 +#ifdef CONFIG_MMC_DEBUG
184 +static inline void dbg_dumpregs(struct s3cmci_host *host, char *prefix)
185 +{
186 + u32 con, pre, cmdarg, cmdcon, cmdsta, r0, r1, r2, r3, timer, bsize;
187 + u32 datcon, datcnt, datsta, fsta, imask;
188 +
189 + con = readl(host->base + S3C2410_SDICON);
190 + pre = readl(host->base + S3C2410_SDIPRE);
191 + cmdarg = readl(host->base + S3C2410_SDICMDARG);
192 + cmdcon = readl(host->base + S3C2410_SDICMDCON);
193 + cmdsta = readl(host->base + S3C2410_SDICMDSTAT);
194 + r0 = readl(host->base + S3C2410_SDIRSP0);
195 + r1 = readl(host->base + S3C2410_SDIRSP1);
196 + r2 = readl(host->base + S3C2410_SDIRSP2);
197 + r3 = readl(host->base + S3C2410_SDIRSP3);
198 + timer = readl(host->base + S3C2410_SDITIMER);
199 + bsize = readl(host->base + S3C2410_SDIBSIZE);
200 + datcon = readl(host->base + S3C2410_SDIDCON);
201 + datcnt = readl(host->base + S3C2410_SDIDCNT);
202 + datsta = readl(host->base + S3C2410_SDIDSTA);
203 + fsta = readl(host->base + S3C2410_SDIFSTA);
204 + imask = readl(host->base + host->sdiimsk);
205 +
206 + dbg(host, dbg_debug, "%s CON:[%08x] PRE:[%08x] TMR:[%08x]\n",
207 + prefix, con, pre, timer);
208 +
209 + dbg(host, dbg_debug, "%s CCON:[%08x] CARG:[%08x] CSTA:[%08x]\n",
210 + prefix, cmdcon, cmdarg, cmdsta);
211 +
212 + dbg(host, dbg_debug, "%s DCON:[%08x] FSTA:[%08x]"
213 + " DSTA:[%08x] DCNT:[%08x]\n",
214 + prefix, datcon, fsta, datsta, datcnt);
215 +
216 + dbg(host, dbg_debug, "%s R0:[%08x] R1:[%08x]"
217 + " R2:[%08x] R3:[%08x]\n",
218 + prefix, r0, r1, r2, r3);
219 +}
220 +
221 +static void prepare_dbgmsg(struct s3cmci_host *host, struct mmc_command *cmd,
222 + int stop)
223 +{
224 + snprintf(host->dbgmsg_cmd, 300,
225 + "#%u%s op:CMD%d arg:0x%08x flags:0x08%x retries:%u",
226 + host->ccnt, (stop?" (STOP)":""), cmd->opcode,
227 + cmd->arg, cmd->flags, cmd->retries);
228 +
229 + if (cmd->data) {
230 + snprintf(host->dbgmsg_dat, 300,
231 + "#%u bsize:%u blocks:%u bytes:%u",
232 + host->dcnt, cmd->data->blksz,
233 + cmd->data->blocks,
234 + cmd->data->blocks * cmd->data->blksz);
235 + } else {
236 + host->dbgmsg_dat[0] = '\0';
237 + }
238 +}
239 +
240 +static void dbg_dumpcmd(struct s3cmci_host *host, struct mmc_command *cmd,
241 + int fail)
242 +{
243 + unsigned int dbglvl = fail?dbg_fail:dbg_debug;
244 +
245 + if (!cmd)
246 + return;
247 +
248 + if (cmd->error == 0)
249 + dbg(host, dbglvl, "CMD[OK] %s R0:0x%08x\n",
250 + host->dbgmsg_cmd, cmd->resp[0]);
251 + else
252 + dbg(host, dbglvl, "CMD[FAIL(%d)] %s Status:%s\n",
253 + cmd->error, host->dbgmsg_cmd, host->status);
254 +
255 + if (!cmd->data)
256 + return;
257 +
258 + if (cmd->data->error == 0)
259 + dbg(host, dbglvl, "DAT[OK] %s\n", host->dbgmsg_dat);
260 + else
261 + dbg(host, dbglvl, "DAT[FAIL(%d)] %s DCNT:0x%08x\n",
262 + cmd->data->error, host->dbgmsg_dat,
263 + readl(host->base + S3C2410_SDIDCNT));
264 +}
265 +#endif /* CONFIG_MMC_DEBUG */
266 +
267 +static inline u32 enable_imask(struct s3cmci_host *host, u32 imask)
268 +{
269 + u32 newmask;
270 +
271 + newmask = readl(host->base + host->sdiimsk);
272 + newmask |= imask;
273 +
274 + writel(newmask, host->base + host->sdiimsk);
275 +
276 + return newmask;
277 +}
278 +
279 +static inline u32 disable_imask(struct s3cmci_host *host, u32 imask)
280 +{
281 + u32 newmask;
282 +
283 + newmask = readl(host->base + host->sdiimsk);
284 + newmask &= ~imask;
285 +
286 + writel(newmask, host->base + host->sdiimsk);
287 +
288 + return newmask;
289 +}
290 +
291 +static inline void clear_imask(struct s3cmci_host *host)
292 +{
293 + writel(0, host->base + host->sdiimsk);
294 +}
295 +
296 +static inline int get_data_buffer(struct s3cmci_host *host,
297 + u32 *bytes, u8 **pointer)
298 +{
299 + struct scatterlist *sg;
300 +
301 + if (host->pio_active == XFER_NONE)
302 + return -EINVAL;
303 +
304 + if ((!host->mrq) || (!host->mrq->data))
305 + return -EINVAL;
306 +
307 + if (host->pio_sgptr >= host->mrq->data->sg_len) {
308 + dbg(host, dbg_debug, "no more buffers (%i/%i)\n",
309 + host->pio_sgptr, host->mrq->data->sg_len);
310 + return -EBUSY;
311 + }
312 + sg = &host->mrq->data->sg[host->pio_sgptr];
313 +
314 + *bytes = sg->length;
315 + *pointer = page_address(sg_page(sg)) + sg->offset;
316 +
317 + host->pio_sgptr++;
318 +
319 + dbg(host, dbg_sg, "new buffer (%i/%i)\n",
320 + host->pio_sgptr, host->mrq->data->sg_len);
321 +
322 + return 0;
323 +}
324 +
325 +#define FIFO_FILL(host) (readl(host->base + S3C2410_SDIFSTA) & \
326 + S3C2410_SDIFSTA_COUNTMASK)
327 +#define FIFO_FREE(host) (63 - (readl(host->base + S3C2410_SDIFSTA) \
328 + & S3C2410_SDIFSTA_COUNTMASK))
329 +
330 +static inline void do_pio_read(struct s3cmci_host *host)
331 +{
332 + int res;
333 + int fifo;
334 + void __iomem *from_ptr;
335 +
336 + /* write real prescaler to host, it might be set slow to fix */
337 + writel(host->prescaler, host->base + S3C2410_SDIPRE);
338 +
339 + from_ptr = host->base + host->sdidata;
340 +
341 + while ((fifo = FIFO_FILL(host))) {
342 + if (!host->pio_bytes) {
343 + res = get_data_buffer(host, &host->pio_bytes,
344 + &host->pio_ptr);
345 + if (res) {
346 + host->pio_active = XFER_NONE;
347 + host->complete_what = COMPLETION_FINALIZE;
348 +
349 + dbg(host, dbg_pio, "pio_read(): "
350 + "complete (no more data).\n");
351 + return;
352 + }
353 +
354 + dbg(host, dbg_pio, "pio_read(): new target: "
355 + "[%i]@[%p]\n", host->pio_bytes, host->pio_ptr);
356 + }
357 +
358 + dbg(host, dbg_pio, "pio_read(): fifo:[%02i] "
359 + "buffer:[%03i] dcnt:[%08X]\n", fifo, host->pio_bytes,
360 + readl(host->base + S3C2410_SDIDCNT));
361 +
362 + if (fifo > host->pio_bytes)
363 + fifo = host->pio_bytes;
364 +
365 + host->pio_bytes -= fifo;
366 + host->pio_count += fifo;
367 +
368 + /* we might have an unaligned start of data */
369 + while (((unsigned long)host->pio_ptr & 0x03) && fifo) {
370 + *(host->pio_ptr++) = readb(host->base + host->sdidata_b);
371 + fifo--;
372 + }
373 +
374 + /* and a major chunk of data in the middle */
375 + for (; fifo >= 4; fifo -=4) {
376 + *(u32 *) host->pio_ptr = readl(from_ptr);
377 + host->pio_ptr+= 4;
378 + }
379 +
380 + /* as well as some non-modulo-four trailer */
381 + while (fifo) {
382 + *(host->pio_ptr++) = readb(host->base + host->sdidata_b);
383 + fifo--;
384 + }
385 + }
386 +
387 + if (!host->pio_bytes) {
388 + res = get_data_buffer(host, &host->pio_bytes, &host->pio_ptr);
389 + if (res) {
390 + dbg(host, dbg_pio, "pio_read(): "
391 + "complete (no more buffers).\n");
392 + host->pio_active = XFER_NONE;
393 + host->complete_what = COMPLETION_FINALIZE;
394 +
395 + return;
396 + }
397 + }
398 +
399 + enable_imask(host, S3C2410_SDIIMSK_RXFIFOHALF
400 + | S3C2410_SDIIMSK_RXFIFOLAST);
401 +}
402 +
403 +static inline void do_pio_write(struct s3cmci_host *host)
404 +{
405 + int res;
406 + int fifo;
407 +
408 + void __iomem *to_ptr;
409 +
410 + to_ptr = host->base + host->sdidata;
411 +
412 + while ((fifo = FIFO_FREE(host))) {
413 + if (!host->pio_bytes) {
414 + res = get_data_buffer(host, &host->pio_bytes,
415 + &host->pio_ptr);
416 + if (res) {
417 + dbg(host, dbg_pio, "pio_write(): "
418 + "complete (no more data).\n");
419 + host->pio_active = XFER_NONE;
420 +
421 + return;
422 + }
423 +
424 + dbg(host, dbg_pio, "pio_write(): "
425 + "new source: [%i]@[%p]\n",
426 + host->pio_bytes, host->pio_ptr);
427 +
428 + }
429 +
430 + if (fifo > host->pio_bytes)
431 + fifo = host->pio_bytes;
432 +
433 + host->pio_bytes -= fifo;
434 + host->pio_count += fifo;
435 +
436 + /* we might have an unaligned start of data */
437 + while (((unsigned long)host->pio_ptr & 0x03) && fifo) {
438 + writeb(*(host->pio_ptr++), host->base + host->sdidata_b);
439 + fifo--;
440 + }
441 +
442 + /* and a major chunk of data in the middle */
443 + for (; fifo >= 4; fifo -=4) {
444 + writel(*(u32 *) host->pio_ptr, to_ptr);
445 + host->pio_ptr += 4;
446 + }
447 +
448 + /* as well as some non-modulo-four trailer */
449 + while (fifo) {
450 + writeb(*(host->pio_ptr++), host->base + host->sdidata_b);
451 + fifo--;
452 + }
453 + }
454 +
455 + enable_imask(host, S3C2410_SDIIMSK_TXFIFOHALF);
456 +}
457 +
458 +static void pio_tasklet(unsigned long data)
459 +{
460 + struct s3cmci_host *host = (struct s3cmci_host *) data;
461 +
462 + disable_irq(host->irq);
463 +
464 + if (host->pio_active == XFER_WRITE)
465 + do_pio_write(host);
466 +
467 + if (host->pio_active == XFER_READ)
468 + do_pio_read(host);
469 +
470 + if (host->complete_what == COMPLETION_FINALIZE) {
471 + clear_imask(host);
472 + if (host->pio_active != XFER_NONE) {
473 + dbg(host, dbg_err, "unfinished %s "
474 + "- pio_count:[%u] pio_bytes:[%u]\n",
475 + (host->pio_active == XFER_READ)?"read":"write",
476 + host->pio_count, host->pio_bytes);
477 +
478 + host->mrq->data->error = -EIO;
479 + }
480 +
481 + finalize_request(host);
482 + } else
483 + enable_irq(host->irq);
484 +}
485 +
486 +/*
487 + * ISR for SDI Interface IRQ
488 + * Communication between driver and ISR works as follows:
489 + * host->mrq points to current request
490 + * host->complete_what tells ISR when the request is considered done
491 + * COMPLETION_CMDSENT when the command was sent
492 + * COMPLETION_RSPFIN when a response was received
493 + * COMPLETION_XFERFINISH when the data transfer is finished
494 + * COMPLETION_XFERFINISH_RSPFIN both of the above.
495 + * host->complete_request is the completion-object the driver waits for
496 + *
497 + * 1) Driver sets up host->mrq and host->complete_what
498 + * 2) Driver prepares the transfer
499 + * 3) Driver enables interrupts
500 + * 4) Driver starts transfer
501 + * 5) Driver waits for host->complete_rquest
502 + * 6) ISR checks for request status (errors and success)
503 + * 6) ISR sets host->mrq->cmd->error and host->mrq->data->error
504 + * 7) ISR completes host->complete_request
505 + * 8) ISR disables interrupts
506 + * 9) Driver wakes up and takes care of the request
507 + *
508 + * Note: "->error"-fields are expected to be set to 0 before the request
509 + * was issued by mmc.c - therefore they are only set, when an error
510 + * contition comes up
511 + */
512 +
513 +static irqreturn_t s3cmci_irq(int irq, void *dev_id)
514 +{
515 + struct s3cmci_host *host;
516 + struct mmc_command *cmd;
517 + u32 mci_csta, mci_dsta, mci_fsta, mci_dcnt, mci_imsk;
518 + u32 mci_cclear, mci_dclear;
519 + unsigned long iflags;
520 + int cardint = 0;
521 +
522 + host = (struct s3cmci_host *)dev_id;
523 +
524 + spin_lock_irqsave(&host->complete_lock, iflags);
525 +
526 + mci_csta = readl(host->base + S3C2410_SDICMDSTAT);
527 + mci_dsta = readl(host->base + S3C2410_SDIDSTA);
528 + mci_dcnt = readl(host->base + S3C2410_SDIDCNT);
529 + mci_fsta = readl(host->base + S3C2410_SDIFSTA);
530 + mci_imsk = readl(host->base + host->sdiimsk);
531 + mci_cclear = 0;
532 + mci_dclear = 0;
533 +
534 + if ((host->complete_what == COMPLETION_NONE) ||
535 + (host->complete_what == COMPLETION_FINALIZE)) {
536 + host->status = "nothing to complete";
537 + clear_imask(host);
538 + goto irq_out;
539 + }
540 +
541 + if (!host->mrq) {
542 + host->status = "no active mrq";
543 + clear_imask(host);
544 + goto irq_out;
545 + }
546 +
547 + cmd = host->cmd_is_stop?host->mrq->stop:host->mrq->cmd;
548 +
549 + if (!cmd) {
550 + host->status = "no active cmd";
551 + clear_imask(host);
552 + goto irq_out;
553 + }
554 +
555 + if (!host->dodma) {
556 + if ((host->pio_active == XFER_WRITE) &&
557 + (mci_fsta & S3C2410_SDIFSTA_TFDET)) {
558 +
559 + disable_imask(host, S3C2410_SDIIMSK_TXFIFOHALF);
560 + tasklet_schedule(&host->pio_tasklet);
561 + host->status = "pio tx";
562 + }
563 +
564 + if ((host->pio_active == XFER_READ) &&
565 + (mci_fsta & S3C2410_SDIFSTA_RFDET)) {
566 +
567 + disable_imask(host, S3C2410_SDIIMSK_RXFIFOHALF |
568 + S3C2410_SDIIMSK_RXFIFOLAST);
569 +
570 + tasklet_schedule(&host->pio_tasklet);
571 + host->status = "pio rx";
572 + }
573 + }
574 +
575 + if (mci_csta & S3C2410_SDICMDSTAT_CMDTIMEOUT) {
576 + cmd->error = -ETIMEDOUT;
577 + host->status = "error: command timeout";
578 + goto fail_transfer;
579 + }
580 +
581 + if (mci_csta & S3C2410_SDICMDSTAT_CMDSENT) {
582 + if (host->complete_what == COMPLETION_CMDSENT) {
583 + host->status = "ok: command sent";
584 + goto close_transfer;
585 + }
586 +
587 + mci_cclear |= S3C2410_SDICMDSTAT_CMDSENT;
588 + }
589 +
590 + if (mci_csta & S3C2410_SDICMDSTAT_CRCFAIL) {
591 + if (cmd->flags & MMC_RSP_CRC) {
592 + if (host->mrq->cmd->flags & MMC_RSP_136) {
593 + dbg(host, dbg_irq, "fixup for chip bug: "
594 + "ignore CRC fail with long rsp\n");
595 + } else {
596 + cmd->error = -EILSEQ;
597 + host->status = "error: bad command crc";
598 + goto fail_transfer;
599 + }
600 + }
601 +
602 + mci_cclear |= S3C2410_SDICMDSTAT_CRCFAIL;
603 + }
604 +
605 + if (mci_csta & S3C2410_SDICMDSTAT_RSPFIN) {
606 + if (host->complete_what == COMPLETION_RSPFIN) {
607 + host->status = "ok: command response received";
608 + goto close_transfer;
609 + }
610 +
611 + if (host->complete_what == COMPLETION_XFERFINISH_RSPFIN)
612 + host->complete_what = COMPLETION_XFERFINISH;
613 +
614 + mci_cclear |= S3C2410_SDICMDSTAT_RSPFIN;
615 + }
616 +
617 + /* errors handled after this point are only relevant
618 + when a data transfer is in progress */
619 +
620 + if (!cmd->data)
621 + goto clear_status_bits;
622 +
623 + /* Check for FIFO failure */
624 + if (host->is2440) {
625 + if (mci_fsta & S3C2440_SDIFSTA_FIFOFAIL) {
626 + host->mrq->data->error = -EIO;
627 + host->status = "error: 2440 fifo failure";
628 + goto fail_transfer;
629 + }
630 + } else {
631 + if (mci_dsta & S3C2410_SDIDSTA_FIFOFAIL) {
632 + cmd->data->error = -EIO;
633 + host->status = "error: fifo failure";
634 + goto fail_transfer;
635 + }
636 + }
637 +
638 + if (mci_dsta & S3C2410_SDIDSTA_RXCRCFAIL) {
639 + cmd->data->error = -EILSEQ;
640 + host->status = "error: bad data crc (outgoing)";
641 + goto fail_transfer;
642 + }
643 +
644 + if (mci_dsta & S3C2410_SDIDSTA_CRCFAIL) {
645 + cmd->data->error = -EIO;
646 + host->status = "error: bad data crc (incoming)";
647 + goto fail_transfer;
648 + }
649 +
650 + if (mci_dsta & S3C2410_SDIDSTA_DATATIMEOUT) {
651 + cmd->data->error = -ETIMEDOUT;
652 + host->status = "error: data timeout";
653 + goto fail_transfer;
654 + }
655 +
656 + if (mci_dsta & S3C2410_SDIDSTA_XFERFINISH) {
657 + if (host->complete_what == COMPLETION_XFERFINISH) {
658 + host->status = "ok: data transfer completed";
659 + goto close_transfer;
660 + }
661 +
662 + if (host->complete_what == COMPLETION_XFERFINISH_RSPFIN)
663 + host->complete_what = COMPLETION_RSPFIN;
664 +
665 + mci_dclear |= S3C2410_SDIDSTA_XFERFINISH;
666 + }
667 +
668 + if (mci_dsta & S3C2410_SDIDSTA_SDIOIRQDETECT) {
669 + cardint = 1;
670 + mci_dclear |= S3C2410_SDIDSTA_SDIOIRQDETECT;
671 + }
672 +
673 +clear_status_bits:
674 + writel(mci_cclear, host->base + S3C2410_SDICMDSTAT);
675 + writel(mci_dclear, host->base + S3C2410_SDIDSTA);
676 +
677 + goto irq_out;
678 +
679 +fail_transfer:
680 + host->pio_active = XFER_NONE;
681 +
682 +close_transfer:
683 + host->complete_what = COMPLETION_FINALIZE;
684 +
685 + clear_imask(host);
686 + tasklet_schedule(&host->pio_tasklet);
687 +
688 + goto irq_out;
689 +
690 +irq_out:
691 + dbg(host, dbg_irq, "csta:0x%08x dsta:0x%08x "
692 + "fsta:0x%08x dcnt:0x%08x status:%s.\n",
693 + mci_csta, mci_dsta, mci_fsta,
694 + mci_dcnt, host->status);
695 +
696 + spin_unlock_irqrestore(&host->complete_lock, iflags);
697 +
698 + /* We have to delay this as it calls back into the driver */
699 + if (cardint)
700 + mmc_signal_sdio_irq(host->mmc);
701 +
702 + return IRQ_HANDLED;
703 +
704 +}
705 +
706 +/*
707 + * ISR for the CardDetect Pin
708 +*/
709 +
710 +static irqreturn_t s3cmci_irq_cd(int irq, void *dev_id)
711 +{
712 + struct s3cmci_host *host = (struct s3cmci_host *)dev_id;
713 +
714 + dbg(host, dbg_irq, "card detect\n");
715 +
716 + mmc_detect_change(host->mmc, 500);
717 +
718 + return IRQ_HANDLED;
719 +}
720 +
721 +void s3cmci_dma_done_callback(struct s3c2410_dma_chan *dma_ch, void *buf_id,
722 + int size, enum s3c2410_dma_buffresult result)
723 +{
724 + unsigned long iflags;
725 + u32 mci_csta, mci_dsta, mci_fsta, mci_dcnt;
726 + struct s3cmci_host *host = (struct s3cmci_host *)buf_id;
727 +
728 + mci_csta = readl(host->base + S3C2410_SDICMDSTAT);
729 + mci_dsta = readl(host->base + S3C2410_SDIDSTA);
730 + mci_fsta = readl(host->base + S3C2410_SDIFSTA);
731 + mci_dcnt = readl(host->base + S3C2410_SDIDCNT);
732 +
733 + if ((!host->mrq) || (!host->mrq) || (!host->mrq->data))
734 + return;
735 +
736 + if (!host->dmatogo)
737 + return;
738 +
739 + spin_lock_irqsave(&host->complete_lock, iflags);
740 +
741 + if (result != S3C2410_RES_OK) {
742 + dbg(host, dbg_fail, "DMA FAILED: csta=0x%08x dsta=0x%08x "
743 + "fsta=0x%08x dcnt:0x%08x result:0x%08x toGo:%u\n",
744 + mci_csta, mci_dsta, mci_fsta,
745 + mci_dcnt, result, host->dmatogo);
746 +
747 + goto fail_request;
748 + }
749 +
750 + host->dmatogo--;
751 + if (host->dmatogo) {
752 + dbg(host, dbg_dma, "DMA DONE Size:%i DSTA:[%08x] "
753 + "DCNT:[%08x] toGo:%u\n",
754 + size, mci_dsta, mci_dcnt, host->dmatogo);
755 +
756 + goto out;
757 + }
758 +
759 + dbg(host, dbg_dma, "DMA FINISHED Size:%i DSTA:%08x DCNT:%08x\n",
760 + size, mci_dsta, mci_dcnt);
761 +
762 + host->complete_what = COMPLETION_FINALIZE;
763 +
764 +out:
765 + tasklet_schedule(&host->pio_tasklet);
766 + spin_unlock_irqrestore(&host->complete_lock, iflags);
767 + return;
768 +
769 +
770 +fail_request:
771 + host->mrq->data->error = -EIO;
772 + host->complete_what = COMPLETION_FINALIZE;
773 + writel(0, host->base + host->sdiimsk);
774 + goto out;
775 +
776 +}
777 +
778 +static void finalize_request(struct s3cmci_host *host)
779 +{
780 + struct mmc_request *mrq = host->mrq;
781 + struct mmc_command *cmd = host->cmd_is_stop?mrq->stop:mrq->cmd;
782 + int debug_as_failure = 0;
783 +
784 + if (host->complete_what != COMPLETION_FINALIZE)
785 + return;
786 +
787 + if (!mrq)
788 + return;
789 +
790 + if (cmd->data && (cmd->error == 0) &&
791 + (cmd->data->error == 0)) {
792 +
793 + if (host->dodma && (!host->dma_complete)) {
794 + dbg(host, dbg_dma, "DMA Missing!\n");
795 + return;
796 + }
797 + }
798 +
799 + /* Read response */
800 + cmd->resp[0] = readl(host->base + S3C2410_SDIRSP0);
801 + cmd->resp[1] = readl(host->base + S3C2410_SDIRSP1);
802 + cmd->resp[2] = readl(host->base + S3C2410_SDIRSP2);
803 + cmd->resp[3] = readl(host->base + S3C2410_SDIRSP3);
804 +
805 + /* reset clock speed, as it could still be set low for */
806 + writel(host->prescaler, host->base + S3C2410_SDIPRE);
807 +
808 + if (cmd->error)
809 + debug_as_failure = 1;
810 +
811 + if (cmd->data && cmd->data->error)
812 + debug_as_failure = 1;
813 +
814 +#ifdef CONFIG_MMC_DEBUG
815 + dbg_dumpcmd(host, cmd, debug_as_failure);
816 +#endif
817 + /* Cleanup controller */
818 + writel(0, host->base + S3C2410_SDICMDARG);
819 + writel(S3C2410_SDIDCON_STOP, host->base + S3C2410_SDIDCON);
820 + writel(0, host->base + S3C2410_SDICMDCON);
821 + writel(0, host->base + host->sdiimsk);
822 +
823 + if (cmd->data && cmd->error)
824 + cmd->data->error = cmd->error;
825 +
826 + if (cmd->data && cmd->data->stop && (!host->cmd_is_stop)) {
827 + host->cmd_is_stop = 1;
828 + s3cmci_send_request(host->mmc);
829 + return;
830 + }
831 +
832 + /* If we have no data transfer we are finished here */
833 + if (!mrq->data)
834 + goto request_done;
835 +
836 + /* Calulate the amout of bytes transfer, but only if there was
837 + * no error */
838 + if (mrq->data->error == 0)
839 + mrq->data->bytes_xfered =
840 + (mrq->data->blocks * mrq->data->blksz);
841 + else
842 + mrq->data->bytes_xfered = 0;
843 +
844 + /* If we had an error while transfering data we flush the
845 + * DMA channel and the fifo to clear out any garbage */
846 + if (mrq->data->error) {
847 + if (host->dodma)
848 + s3c2410_dma_ctrl(host->dma, S3C2410_DMAOP_FLUSH);
849 +
850 + if (host->is2440) {
851 + /* Clear failure register and reset fifo */
852 + writel(S3C2440_SDIFSTA_FIFORESET |
853 + S3C2440_SDIFSTA_FIFOFAIL,
854 + host->base + S3C2410_SDIFSTA);
855 + } else {
856 + u32 mci_con;
857 +
858 + /* reset fifo */
859 + mci_con = readl(host->base + S3C2410_SDICON);
860 + mci_con |= S3C2410_SDICON_FIFORESET;
861 +
862 + writel(mci_con, host->base + S3C2410_SDICON);
863 + }
864 + }
865 +
866 +request_done:
867 + host->complete_what = COMPLETION_NONE;
868 + host->mrq = NULL;
869 + mmc_request_done(host->mmc, mrq);
870 +}
871 +
872 +
873 +void s3cmci_dma_setup(struct s3cmci_host *host, enum s3c2410_dmasrc source)
874 +{
875 + static int setup_ok;
876 + static enum s3c2410_dmasrc last_source = -1;
877 +
878 + if (last_source == source)
879 + return;
880 +
881 + last_source = source;
882 +
883 + s3c2410_dma_devconfig(host->dma, source, 3,
884 + host->mem->start + host->sdidata);
885 +
886 + if (!setup_ok) {
887 + s3c2410_dma_config(host->dma, 4,
888 + (S3C2410_DCON_HWTRIG | S3C2410_DCON_CH0_SDI));
889 + s3c2410_dma_set_buffdone_fn(host->dma,
890 + s3cmci_dma_done_callback);
891 + s3c2410_dma_setflags(host->dma, S3C2410_DMAF_AUTOSTART);
892 + setup_ok = 1;
893 + }
894 +}
895 +
896 +static void s3cmci_send_command(struct s3cmci_host *host,
897 + struct mmc_command *cmd)
898 +{
899 + u32 ccon, imsk;
900 +
901 + imsk = S3C2410_SDIIMSK_CRCSTATUS | S3C2410_SDIIMSK_CMDTIMEOUT |
902 + S3C2410_SDIIMSK_RESPONSEND | S3C2410_SDIIMSK_CMDSENT |
903 + S3C2410_SDIIMSK_RESPONSECRC;
904 +
905 + enable_imask(host, imsk);
906 +
907 + if (cmd->data)
908 + host->complete_what = COMPLETION_XFERFINISH_RSPFIN;
909 + else if (cmd->flags & MMC_RSP_PRESENT)
910 + host->complete_what = COMPLETION_RSPFIN;
911 + else
912 + host->complete_what = COMPLETION_CMDSENT;
913 +
914 + writel(cmd->arg, host->base + S3C2410_SDICMDARG);
915 +
916 + ccon = cmd->opcode & S3C2410_SDICMDCON_INDEX;
917 + ccon |= S3C2410_SDICMDCON_SENDERHOST | S3C2410_SDICMDCON_CMDSTART;
918 +
919 + if (cmd->flags & MMC_RSP_PRESENT)
920 + ccon |= S3C2410_SDICMDCON_WAITRSP;
921 +
922 + if (cmd->flags & MMC_RSP_136)
923 + ccon |= S3C2410_SDICMDCON_LONGRSP;
924 +
925 + writel(ccon, host->base + S3C2410_SDICMDCON);
926 +}
927 +
928 +static int s3cmci_setup_data(struct s3cmci_host *host, struct mmc_data *data)
929 +{
930 + u32 dcon, imsk, stoptries = 3;
931 +
932 + /* write DCON register */
933 +
934 + if (!data) {
935 + writel(0, host->base + S3C2410_SDIDCON);
936 + return 0;
937 + }
938 +
939 + while (readl(host->base + S3C2410_SDIDSTA) &
940 + (S3C2410_SDIDSTA_TXDATAON | S3C2410_SDIDSTA_RXDATAON)) {
941 +
942 + dbg(host, dbg_err,
943 + "mci_setup_data() transfer stillin progress.\n");
944 +
945 + writel(S3C2410_SDIDCON_STOP, host->base + S3C2410_SDIDCON);
946 + s3cmci_reset(host);
947 +
948 + if (0 == (stoptries--)) {
949 +#ifdef CONFIG_MMC_DEBUG
950 + dbg_dumpregs(host, "DRF");
951 +#endif
952 +
953 + return -EINVAL;
954 + }
955 + }
956 +
957 + dcon = data->blocks & S3C2410_SDIDCON_BLKNUM_MASK;
958 +
959 + if (host->dodma)
960 + dcon |= S3C2410_SDIDCON_DMAEN;
961 +
962 + if (host->bus_width == MMC_BUS_WIDTH_4)
963 + dcon |= S3C2410_SDIDCON_WIDEBUS;
964 +
965 + if (!(data->flags & MMC_DATA_STREAM))
966 + dcon |= S3C2410_SDIDCON_BLOCKMODE;
967 +
968 + if (data->flags & MMC_DATA_WRITE) {
969 + dcon |= S3C2410_SDIDCON_TXAFTERRESP;
970 + dcon |= S3C2410_SDIDCON_XFER_TXSTART;
971 + }
972 +
973 + if (data->flags & MMC_DATA_READ) {
974 + dcon |= S3C2410_SDIDCON_RXAFTERCMD;
975 + dcon |= S3C2410_SDIDCON_XFER_RXSTART;
976 + }
977 +
978 + if (host->is2440) {
979 + dcon |= S3C2440_SDIDCON_DS_WORD;
980 + dcon |= S3C2440_SDIDCON_DATSTART;
981 + }
982 +
983 + writel(dcon, host->base + S3C2410_SDIDCON);
984 +
985 + /* write BSIZE register */
986 +
987 + writel(data->blksz, host->base + S3C2410_SDIBSIZE);
988 +
989 + /* add to IMASK register */
990 + imsk = S3C2410_SDIIMSK_FIFOFAIL | S3C2410_SDIIMSK_DATACRC |
991 + S3C2410_SDIIMSK_DATATIMEOUT | S3C2410_SDIIMSK_DATAFINISH;
992 +
993 + enable_imask(host, imsk);
994 +
995 + /* write TIMER register */
996 +
997 + if (host->is2440) {
998 + writel(0x007FFFFF, host->base + S3C2410_SDITIMER);
999 + } else {
1000 + writel(0x0000FFFF, host->base + S3C2410_SDITIMER);
1001 +
1002 + /* FIX: set slow clock to prevent timeouts on read */
1003 + if (data->flags & MMC_DATA_READ)
1004 + writel(0xFF, host->base + S3C2410_SDIPRE);
1005 + }
1006 +
1007 + return 0;
1008 +}
1009 +
1010 +static int s3cmci_prepare_pio(struct s3cmci_host *host, struct mmc_data *data)
1011 +{
1012 + int rw = (data->flags & MMC_DATA_WRITE)?1:0;
1013 +
1014 + if (rw != ((data->flags & MMC_DATA_READ)?0:1))
1015 + return -EINVAL;
1016 +
1017 + host->pio_sgptr = 0;
1018 + host->pio_bytes = 0;
1019 + host->pio_count = 0;
1020 + host->pio_active = rw?XFER_WRITE:XFER_READ;
1021 +
1022 + if (rw) {
1023 + do_pio_write(host);
1024 + enable_imask(host, S3C2410_SDIIMSK_TXFIFOHALF);
1025 + } else {
1026 + enable_imask(host, S3C2410_SDIIMSK_RXFIFOHALF
1027 + | S3C2410_SDIIMSK_RXFIFOLAST);
1028 + }
1029 +
1030 + return 0;
1031 +}
1032 +
1033 +static int s3cmci_prepare_dma(struct s3cmci_host *host, struct mmc_data *data)
1034 +{
1035 + int dma_len, i;
1036 +
1037 + int rw = (data->flags & MMC_DATA_WRITE)?1:0;
1038 +
1039 + if (rw != ((data->flags & MMC_DATA_READ)?0:1))
1040 + return -EINVAL;
1041 +
1042 + s3cmci_dma_setup(host, rw?S3C2410_DMASRC_MEM:S3C2410_DMASRC_HW);
1043 + s3c2410_dma_ctrl(host->dma, S3C2410_DMAOP_FLUSH);
1044 +
1045 + dma_len = dma_map_sg(mmc_dev(host->mmc), data->sg, data->sg_len,
1046 + (rw)?DMA_TO_DEVICE:DMA_FROM_DEVICE);
1047 +
1048 +
1049 + if (dma_len == 0)
1050 + return -ENOMEM;
1051 +
1052 + host->dma_complete = 0;
1053 + host->dmatogo = dma_len;
1054 +
1055 + for (i = 0; i < dma_len; i++) {
1056 + int res;
1057 +
1058 + dbg(host, dbg_dma, "enqueue %i:%u@%u\n", i,
1059 + sg_dma_address(&data->sg[i]),
1060 + sg_dma_len(&data->sg[i]));
1061 +
1062 + res = s3c2410_dma_enqueue(host->dma, (void *) host,
1063 + sg_dma_address(&data->sg[i]),
1064 + sg_dma_len(&data->sg[i]));
1065 +
1066 + if (res) {
1067 + s3c2410_dma_ctrl(host->dma, S3C2410_DMAOP_FLUSH);
1068 + return -EBUSY;
1069 + }
1070 + }
1071 +
1072 + s3c2410_dma_ctrl(host->dma, S3C2410_DMAOP_START);
1073 +
1074 + return 0;
1075 +}
1076 +
1077 +static void s3cmci_send_request(struct mmc_host *mmc)
1078 +{
1079 + struct s3cmci_host *host = mmc_priv(mmc);
1080 + struct mmc_request *mrq = host->mrq;
1081 + struct mmc_command *cmd = host->cmd_is_stop?mrq->stop:mrq->cmd;
1082 +
1083 + host->ccnt++;
1084 +#ifdef CONFIG_MMC_DEBUG
1085 + prepare_dbgmsg(host, cmd, host->cmd_is_stop);
1086 +#endif
1087 + /* clear command, data and fifo status registers;
1088 + * Fifo clear only necessary on 2440, but doesn't hurt on 2410 */
1089 + writel(0xFFFFFFFF, host->base + S3C2410_SDICMDSTAT);
1090 + writel(0xFFFFFFFF, host->base + S3C2410_SDIDSTA);
1091 + writel(0xFFFFFFFF, host->base + S3C2410_SDIFSTA);
1092 +
1093 + if (cmd->data) {
1094 + int res;
1095 + res = s3cmci_setup_data(host, cmd->data);
1096 +
1097 + host->dcnt++;
1098 +
1099 + if (res) {
1100 + cmd->error = -EIO;
1101 + cmd->data->error = -EIO;
1102 +
1103 + mmc_request_done(mmc, mrq);
1104 + return;
1105 + }
1106 +
1107 +
1108 + if (host->dodma)
1109 + res = s3cmci_prepare_dma(host, cmd->data);
1110 + else
1111 + res = s3cmci_prepare_pio(host, cmd->data);
1112 +
1113 + if (res) {
1114 + cmd->error = -EIO;
1115 + cmd->data->error = -EIO;
1116 +
1117 + mmc_request_done(mmc, mrq);
1118 + return;
1119 + }
1120 +
1121 + }
1122 +
1123 + s3cmci_send_command(host, cmd);
1124 + enable_irq(host->irq);
1125 +}
1126 +
1127 +static void s3cmci_request(struct mmc_host *mmc, struct mmc_request *mrq)
1128 +{
1129 + struct s3cmci_host *host = mmc_priv(mmc);
1130 +
1131 + host->cmd_is_stop = 0;
1132 + host->mrq = mrq;
1133 +
1134 + s3cmci_send_request(mmc);
1135 +}
1136 +
1137 +static void s3cmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
1138 +{
1139 + struct s3cmci_host *host = mmc_priv(mmc);
1140 + u32 mci_psc, mci_con;
1141 +
1142 + /* Set power */
1143 + mci_con = readl(host->base + S3C2410_SDICON);
1144 + switch (ios->power_mode) {
1145 + case MMC_POWER_ON:
1146 + case MMC_POWER_UP:
1147 + s3c2410_gpio_cfgpin(S3C2410_GPE5, S3C2410_GPE5_SDCLK);
1148 + s3c2410_gpio_cfgpin(S3C2410_GPE6, S3C2410_GPE6_SDCMD);
1149 + s3c2410_gpio_cfgpin(S3C2410_GPE7, S3C2410_GPE7_SDDAT0);
1150 + s3c2410_gpio_cfgpin(S3C2410_GPE8, S3C2410_GPE8_SDDAT1);
1151 + s3c2410_gpio_cfgpin(S3C2410_GPE9, S3C2410_GPE9_SDDAT2);
1152 + s3c2410_gpio_cfgpin(S3C2410_GPE10, S3C2410_GPE10_SDDAT3);
1153 +
1154 + if (host->pdata->set_power)
1155 + host->pdata->set_power(ios->power_mode, ios->vdd);
1156 +
1157 + if (!host->is2440)
1158 + mci_con |= S3C2410_SDICON_FIFORESET;
1159 +
1160 + break;
1161 +
1162 + case MMC_POWER_OFF:
1163 + default:
1164 + s3c2410_gpio_setpin(S3C2410_GPE5, 0);
1165 + s3c2410_gpio_cfgpin(S3C2410_GPE5, S3C2410_GPE5_OUTP);
1166 +
1167 + if (host->pdata->set_power)
1168 + host->pdata->set_power(ios->power_mode, ios->vdd);
1169 +
1170 + if (host->is2440)
1171 + mci_con |= S3C2440_SDICON_SDRESET;
1172 +
1173 + break;
1174 + }
1175 +
1176 + /* Set clock */
1177 + for (mci_psc = 0; mci_psc < 255; mci_psc++) {
1178 + host->real_rate = host->clk_rate / (host->clk_div*(mci_psc+1));
1179 +
1180 + if (host->real_rate <= ios->clock)
1181 + break;
1182 + }
1183 +
1184 + if (mci_psc > 255)
1185 + mci_psc = 255;
1186 + host->prescaler = mci_psc;
1187 +
1188 + writel(host->prescaler, host->base + S3C2410_SDIPRE);
1189 +
1190 + /* If requested clock is 0, real_rate will be 0, too */
1191 + if (ios->clock == 0)
1192 + host->real_rate = 0;
1193 +
1194 + /* Set CLOCK_ENABLE */
1195 + if (ios->clock)
1196 + mci_con |= S3C2410_SDICON_CLOCKTYPE;
1197 + else
1198 + mci_con &= ~S3C2410_SDICON_CLOCKTYPE;
1199 +
1200 + writel(mci_con, host->base + S3C2410_SDICON);
1201 +
1202 + if ((ios->power_mode == MMC_POWER_ON)
1203 + || (ios->power_mode == MMC_POWER_UP)) {
1204 +
1205 + dbg(host, dbg_conf, "running at %lukHz (requested: %ukHz).\n",
1206 + host->real_rate/1000, ios->clock/1000);
1207 + } else {
1208 + dbg(host, dbg_conf, "powered down.\n");
1209 + }
1210 +
1211 + host->bus_width = ios->bus_width;
1212 +
1213 +}
1214 +
1215 +static void s3cmci_reset(struct s3cmci_host *host)
1216 +{
1217 + u32 con = readl(host->base + S3C2410_SDICON);
1218 +
1219 + con |= S3C2440_SDICON_SDRESET;
1220 +
1221 + writel(con, host->base + S3C2410_SDICON);
1222 +}
1223 +
1224 +static int s3cmci_get_ro(struct mmc_host *mmc)
1225 +{
1226 + struct s3cmci_host *host = mmc_priv(mmc);
1227 +
1228 + if (host->pdata->gpio_wprotect == 0)
1229 + return 0;
1230 +
1231 + return s3c2410_gpio_getpin(host->pdata->gpio_wprotect);
1232 +}
1233 +
1234 +static void s3cmci_enable_sdio_irq(struct mmc_host *mmc, int enable)
1235 +{
1236 + struct s3cmci_host *host = mmc_priv(mmc);
1237 +
1238 + if (enable)
1239 + enable_imask(host, S3C2410_SDIIMSK_SDIOIRQ);
1240 + else
1241 + disable_imask(host, S3C2410_SDIIMSK_SDIOIRQ);
1242 +}
1243 +
1244 +static struct mmc_host_ops s3cmci_ops = {
1245 + .request = s3cmci_request,
1246 + .set_ios = s3cmci_set_ios,
1247 + .get_ro = s3cmci_get_ro,
1248 + .enable_sdio_irq = s3cmci_enable_sdio_irq,
1249 +};
1250 +
1251 +static struct s3c24xx_mci_pdata s3cmci_def_pdata = {
1252 + .do_dma = 0,
1253 + .gpio_detect = 0,
1254 + .set_power = NULL,
1255 + .ocr_avail = MMC_VDD_32_33,
1256 +};
1257 +
1258 +static int s3cmci_probe(struct platform_device *pdev, int is2440)
1259 +{
1260 + struct mmc_host *mmc;
1261 + struct s3cmci_host *host;
1262 +
1263 + int ret;
1264 +
1265 + mmc = mmc_alloc_host(sizeof(struct s3cmci_host), &pdev->dev);
1266 + if (!mmc) {
1267 + ret = -ENOMEM;
1268 + goto probe_out;
1269 + }
1270 +
1271 + host = mmc_priv(mmc);
1272 + host->mmc = mmc;
1273 + host->pdev = pdev;
1274 +
1275 + host->pdata = pdev->dev.platform_data;
1276 + if (!host->pdata) {
1277 + pdev->dev.platform_data = &s3cmci_def_pdata;
1278 + host->pdata = &s3cmci_def_pdata;
1279 + }
1280 +
1281 + spin_lock_init(&host->complete_lock);
1282 + tasklet_init(&host->pio_tasklet, pio_tasklet, (unsigned long) host);
1283 + if (is2440) {
1284 + host->is2440 = 1;
1285 + host->sdiimsk = S3C2440_SDIIMSK;
1286 + host->sdidata = S3C2440_SDIDATA;
1287 + host->sdidata_b = S3C2440_SDIDATA_BYTE;
1288 + host->clk_div = 1;
1289 + } else {
1290 + host->is2440 = 0;
1291 + host->sdiimsk = S3C2410_SDIIMSK;
1292 + host->sdidata = S3C2410_SDIDATA;
1293 + host->sdidata_b = S3C2410_SDIDATA_BYTE;
1294 + host->clk_div = 2;
1295 + }
1296 + host->dodma = host->pdata->do_dma;
1297 + host->complete_what = COMPLETION_NONE;
1298 + host->pio_active = XFER_NONE;
1299 +
1300 + host->dma = DMACH_SDI;
1301 + host->irq_cd = s3c2410_gpio_getirq(host->pdata->gpio_detect);
1302 + s3c2410_gpio_cfgpin(host->pdata->gpio_detect, S3C2410_GPIO_IRQ);
1303 +
1304 + host->mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
1305 + if (!host->mem) {
1306 + dev_err(&pdev->dev,
1307 + "failed to get io memory region resouce.\n");
1308 +
1309 + ret = -ENOENT;
1310 + goto probe_free_host;
1311 + }
1312 +
1313 + host->mem = request_mem_region(host->mem->start,
1314 + RESSIZE(host->mem), pdev->name);
1315 +
1316 + if (!host->mem) {
1317 + dev_err(&pdev->dev, "failed to request io memory region.\n");
1318 + ret = -ENOENT;
1319 + goto probe_free_host;
1320 + }
1321 +
1322 + host->base = ioremap(host->mem->start, RESSIZE(host->mem));
1323 + if (host->base == 0) {
1324 + dev_err(&pdev->dev, "failed to ioremap() io memory region.\n");
1325 + ret = -EINVAL;
1326 + goto probe_free_mem_region;
1327 + }
1328 +
1329 + host->irq = platform_get_irq(pdev, 0);
1330 + if (host->irq == 0) {
1331 + dev_err(&pdev->dev, "failed to get interrupt resouce.\n");
1332 + ret = -EINVAL;
1333 + goto probe_iounmap;
1334 + }
1335 +
1336 + if (request_irq(host->irq, s3cmci_irq, 0, DRIVER_NAME, host)) {
1337 + dev_err(&pdev->dev, "failed to request mci interrupt.\n");
1338 + ret = -ENOENT;
1339 + goto probe_iounmap;
1340 + }
1341 +
1342 + disable_irq(host->irq);
1343 +
1344 + s3c2410_gpio_cfgpin(host->pdata->gpio_detect, S3C2410_GPIO_IRQ);
1345 + set_irq_type(host->irq_cd, IRQT_BOTHEDGE);
1346 +
1347 + if (request_irq(host->irq_cd, s3cmci_irq_cd, 0, DRIVER_NAME, host)) {
1348 + dev_err(&pdev->dev,
1349 + "failed to request card detect interrupt.\n");
1350 +
1351 + ret = -ENOENT;
1352 + goto probe_free_irq;
1353 + }
1354 +
1355 + if (host->pdata->gpio_wprotect)
1356 + s3c2410_gpio_cfgpin(host->pdata->gpio_wprotect,
1357 + S3C2410_GPIO_INPUT);
1358 +
1359 + if (s3c2410_dma_request(host->dma, &s3cmci_dma_client, NULL)) {
1360 + dev_err(&pdev->dev, "unable to get DMA channel.\n");
1361 + ret = -EBUSY;
1362 + goto probe_free_irq_cd;
1363 + }
1364 +
1365 + host->clk = clk_get(&pdev->dev, "sdi");
1366 + if (IS_ERR(host->clk)) {
1367 + dev_err(&pdev->dev, "failed to find clock source.\n");
1368 + ret = PTR_ERR(host->clk);
1369 + host->clk = NULL;
1370 + goto probe_free_host;
1371 + }
1372 +
1373 + ret = clk_enable(host->clk);
1374 + if (ret) {
1375 + dev_err(&pdev->dev, "failed to enable clock source.\n");
1376 + goto clk_free;
1377 + }
1378 +
1379 + host->clk_rate = clk_get_rate(host->clk);
1380 +
1381 + mmc->ops = &s3cmci_ops;
1382 + mmc->ocr_avail = host->pdata->ocr_avail;
1383 + mmc->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_SDIO_IRQ;
1384 + mmc->f_min = host->clk_rate / (host->clk_div * 256);
1385 + mmc->f_max = host->clk_rate / host->clk_div;
1386 +
1387 + mmc->max_blk_count = 4095;
1388 + mmc->max_blk_size = 4095;
1389 + mmc->max_req_size = 4095 * 512;
1390 + mmc->max_seg_size = mmc->max_req_size;
1391 +
1392 + mmc->max_phys_segs = 128;
1393 + mmc->max_hw_segs = 128;
1394 +
1395 + dbg(host, dbg_debug, "probe: mode:%s mapped mci_base:%p irq:%u "
1396 + "irq_cd:%u dma:%u.\n", (host->is2440?"2440":""),
1397 + host->base, host->irq, host->irq_cd, host->dma);
1398 +
1399 + ret = mmc_add_host(mmc);
1400 + if (ret) {
1401 + dev_err(&pdev->dev, "failed to add mmc host.\n");
1402 + goto free_dmabuf;
1403 + }
1404 +
1405 + platform_set_drvdata(pdev, mmc);
1406 +
1407 + dev_info(&pdev->dev, "initialisation done.\n");
1408 + return 0;
1409 +
1410 + free_dmabuf:
1411 + clk_disable(host->clk);
1412 +
1413 + clk_free:
1414 + clk_put(host->clk);
1415 +
1416 + probe_free_irq_cd:
1417 + free_irq(host->irq_cd, host);
1418 +
1419 + probe_free_irq:
1420 + free_irq(host->irq, host);
1421 +
1422 + probe_iounmap:
1423 + iounmap(host->base);
1424 +
1425 + probe_free_mem_region:
1426 + release_mem_region(host->mem->start, RESSIZE(host->mem));
1427 +
1428 + probe_free_host:
1429 + mmc_free_host(mmc);
1430 + probe_out:
1431 + return ret;
1432 +}
1433 +
1434 +static int s3cmci_remove(struct platform_device *pdev)
1435 +{
1436 + struct mmc_host *mmc = platform_get_drvdata(pdev);
1437 + struct s3cmci_host *host = mmc_priv(mmc);
1438 +
1439 + mmc_remove_host(mmc);
1440 + clk_disable(host->clk);
1441 + clk_put(host->clk);
1442 + s3c2410_dma_free(host->dma, &s3cmci_dma_client);
1443 + free_irq(host->irq_cd, host);
1444 + free_irq(host->irq, host);
1445 + iounmap(host->base);
1446 + release_mem_region(host->mem->start, RESSIZE(host->mem));
1447 + mmc_free_host(mmc);
1448 +
1449 + return 0;
1450 +}
1451 +
1452 +static int s3cmci_probe_2410(struct platform_device *dev)
1453 +{
1454 + return s3cmci_probe(dev, 0);
1455 +}
1456 +
1457 +static int s3cmci_probe_2412(struct platform_device *dev)
1458 +{
1459 + return s3cmci_probe(dev, 1);
1460 +}
1461 +
1462 +static int s3cmci_probe_2440(struct platform_device *dev)
1463 +{
1464 + return s3cmci_probe(dev, 1);
1465 +}
1466 +
1467 +#ifdef CONFIG_PM
1468 +
1469 +static int s3cmci_suspend(struct platform_device *dev, pm_message_t state)
1470 +{
1471 + struct mmc_host *mmc = platform_get_drvdata(dev);
1472 +
1473 + return mmc_suspend_host(mmc, state);
1474 +}
1475 +
1476 +static int s3cmci_resume(struct platform_device *dev)
1477 +{
1478 + struct mmc_host *mmc = platform_get_drvdata(dev);
1479 +
1480 + return mmc_resume_host(mmc);
1481 +}
1482 +
1483 +#else /* CONFIG_PM */
1484 +#define s3cmci_suspend NULL
1485 +#define s3cmci_resume NULL
1486 +#endif /* CONFIG_PM */
1487 +
1488 +
1489 +static struct platform_driver s3cmci_driver_2410 = {
1490 + .driver.name = "s3c2410-sdi",
1491 + .probe = s3cmci_probe_2410,
1492 + .remove = s3cmci_remove,
1493 + .suspend = s3cmci_suspend,
1494 + .resume = s3cmci_resume,
1495 +};
1496 +
1497 +static struct platform_driver s3cmci_driver_2412 = {
1498 + .driver.name = "s3c2412-sdi",
1499 + .probe = s3cmci_probe_2412,
1500 + .remove = s3cmci_remove,
1501 + .suspend = s3cmci_suspend,
1502 + .resume = s3cmci_resume,
1503 +};
1504 +
1505 +static struct platform_driver s3cmci_driver_2440 = {
1506 + .driver.name = "s3c2440-sdi",
1507 + .probe = s3cmci_probe_2440,
1508 + .remove = s3cmci_remove,
1509 + .suspend = s3cmci_suspend,
1510 + .resume = s3cmci_resume,
1511 +};
1512 +
1513 +
1514 +static int __init s3cmci_init(void)
1515 +{
1516 + platform_driver_register(&s3cmci_driver_2410);
1517 + platform_driver_register(&s3cmci_driver_2412);
1518 + platform_driver_register(&s3cmci_driver_2440);
1519 + return 0;
1520 +}
1521 +
1522 +static void __exit s3cmci_exit(void)
1523 +{
1524 + platform_driver_unregister(&s3cmci_driver_2410);
1525 + platform_driver_unregister(&s3cmci_driver_2412);
1526 + platform_driver_unregister(&s3cmci_driver_2440);
1527 +}
1528 +
1529 +module_init(s3cmci_init);
1530 +module_exit(s3cmci_exit);
1531 +
1532 +MODULE_DESCRIPTION("Samsung S3C MMC/SD Card Interface driver");
1533 +MODULE_LICENSE("GPL");
1534 +MODULE_AUTHOR("Thomas Kleffel <tk@maintech.de>");
1535 diff --git a/drivers/mmc/host/s3cmci.h b/drivers/mmc/host/s3cmci.h
1536 new file mode 100644
1537 index 0000000..9644b45
1538 --- /dev/null
1539 +++ b/drivers/mmc/host/s3cmci.h
1540 @@ -0,0 +1,69 @@
1541 +/*
1542 + * linux/drivers/mmc/s3cmci.h - Samsung S3C MCI driver
1543 + *
1544 + * Copyright (C) 2004-2006 Thomas Kleffel, All Rights Reserved.
1545 + *
1546 + * This program is free software; you can redistribute it and/or modify
1547 + * it under the terms of the GNU General Public License version 2 as
1548 + * published by the Free Software Foundation.
1549 + */
1550 +
1551 +enum s3cmci_waitfor {
1552 + COMPLETION_NONE,
1553 + COMPLETION_FINALIZE,
1554 + COMPLETION_CMDSENT,
1555 + COMPLETION_RSPFIN,
1556 + COMPLETION_XFERFINISH,
1557 + COMPLETION_XFERFINISH_RSPFIN,
1558 +};
1559 +
1560 +struct s3cmci_host {
1561 + struct platform_device *pdev;
1562 + struct s3c24xx_mci_pdata *pdata;
1563 + struct mmc_host *mmc;
1564 + struct resource *mem;
1565 + struct clk *clk;
1566 + void __iomem *base;
1567 + int irq;
1568 + int irq_cd;
1569 + int dma;
1570 +
1571 + unsigned long clk_rate;
1572 + unsigned long clk_div;
1573 + unsigned long real_rate;
1574 + u8 prescaler;
1575 +
1576 + int is2440;
1577 + unsigned sdiimsk;
1578 + unsigned sdidata;
1579 + unsigned sdidata_b;
1580 + int dodma;
1581 +
1582 + int dmatogo;
1583 +
1584 + struct mmc_request *mrq;
1585 + int cmd_is_stop;
1586 +
1587 + spinlock_t complete_lock;
1588 + enum s3cmci_waitfor complete_what;
1589 +
1590 + int dma_complete;
1591 +
1592 + u32 pio_sgptr;
1593 + u32 pio_bytes;
1594 + u32 pio_count;
1595 + u8 *pio_ptr;
1596 +#define XFER_NONE 0
1597 +#define XFER_READ 1
1598 +#define XFER_WRITE 2
1599 + u32 pio_active;
1600 +
1601 + int bus_width;
1602 +
1603 + char dbgmsg_cmd[301];
1604 + char dbgmsg_dat[301];
1605 + char *status;
1606 +
1607 + unsigned int ccnt, dcnt;
1608 + struct tasklet_struct pio_tasklet;
1609 +};
1610 diff --git a/include/asm-arm/arch-s3c2410/mci.h b/include/asm-arm/arch-s3c2410/mci.h
1611 new file mode 100644
1612 index 0000000..24e6cd1
1613 --- /dev/null
1614 +++ b/include/asm-arm/arch-s3c2410/mci.h
1615 @@ -0,0 +1,13 @@
1616 +#ifndef _ARCH_MCI_H
1617 +#define _ARCH_MCI_H
1618 +
1619 +struct s3c24xx_mci_pdata {
1620 + unsigned int gpio_detect;
1621 + unsigned int gpio_wprotect;
1622 + unsigned long ocr_avail;
1623 + unsigned int do_dma;
1624 + void (*set_power)(unsigned char power_mode,
1625 + unsigned short vdd);
1626 +};
1627 +
1628 +#endif /* _ARCH_NCI_H */
1629 diff --git a/include/asm-arm/arch-s3c2410/regs-sdi.h b/include/asm-arm/arch-s3c2410/regs-sdi.h
1630 index bb9d30b..4bb1ec5 100644
1631 --- a/include/asm-arm/arch-s3c2410/regs-sdi.h
1632 +++ b/include/asm-arm/arch-s3c2410/regs-sdi.h
1633 @@ -28,9 +28,17 @@
1634 #define S3C2410_SDIDCNT (0x30)
1635 #define S3C2410_SDIDSTA (0x34)
1636 #define S3C2410_SDIFSTA (0x38)
1637 +
1638 #define S3C2410_SDIDATA (0x3C)
1639 +#define S3C2410_SDIDATA_BYTE (0x3C)
1640 #define S3C2410_SDIIMSK (0x40)
1641
1642 +#define S3C2440_SDIDATA (0x40)
1643 +#define S3C2440_SDIDATA_BYTE (0x48)
1644 +#define S3C2440_SDIIMSK (0x3C)
1645 +
1646 +#define S3C2440_SDICON_SDRESET (1<<8)
1647 +#define S3C2440_SDICON_MMCCLOCK (1<<5)
1648 #define S3C2410_SDICON_BYTEORDER (1<<4)
1649 #define S3C2410_SDICON_SDIOIRQ (1<<3)
1650 #define S3C2410_SDICON_RWAITEN (1<<2)
1651 @@ -42,7 +50,8 @@
1652 #define S3C2410_SDICMDCON_LONGRSP (1<<10)
1653 #define S3C2410_SDICMDCON_WAITRSP (1<<9)
1654 #define S3C2410_SDICMDCON_CMDSTART (1<<8)
1655 -#define S3C2410_SDICMDCON_INDEX (0xff)
1656 +#define S3C2410_SDICMDCON_SENDERHOST (1<<6)
1657 +#define S3C2410_SDICMDCON_INDEX (0x3f)
1658
1659 #define S3C2410_SDICMDSTAT_CRCFAIL (1<<12)
1660 #define S3C2410_SDICMDSTAT_CMDSENT (1<<11)
1661 @@ -51,6 +60,9 @@
1662 #define S3C2410_SDICMDSTAT_XFERING (1<<8)
1663 #define S3C2410_SDICMDSTAT_INDEX (0xff)
1664
1665 +#define S3C2440_SDIDCON_DS_BYTE (0<<22)
1666 +#define S3C2440_SDIDCON_DS_HALFWORD (1<<22)
1667 +#define S3C2440_SDIDCON_DS_WORD (2<<22)
1668 #define S3C2410_SDIDCON_IRQPERIOD (1<<21)
1669 #define S3C2410_SDIDCON_TXAFTERRESP (1<<20)
1670 #define S3C2410_SDIDCON_RXAFTERCMD (1<<19)
1671 @@ -59,6 +71,7 @@
1672 #define S3C2410_SDIDCON_WIDEBUS (1<<16)
1673 #define S3C2410_SDIDCON_DMAEN (1<<15)
1674 #define S3C2410_SDIDCON_STOP (1<<14)
1675 +#define S3C2440_SDIDCON_DATSTART (1<<14)
1676 #define S3C2410_SDIDCON_DATMODE (3<<12)
1677 #define S3C2410_SDIDCON_BLKNUM (0x7ff)
1678
1679 @@ -68,6 +81,7 @@
1680 #define S3C2410_SDIDCON_XFER_RXSTART (2<<12)
1681 #define S3C2410_SDIDCON_XFER_TXSTART (3<<12)
1682
1683 +#define S3C2410_SDIDCON_BLKNUM_MASK (0xFFF)
1684 #define S3C2410_SDIDCNT_BLKNUM_SHIFT (12)
1685
1686 #define S3C2410_SDIDSTA_RDYWAITREQ (1<<10)
1687 @@ -82,10 +96,12 @@
1688 #define S3C2410_SDIDSTA_TXDATAON (1<<1)
1689 #define S3C2410_SDIDSTA_RXDATAON (1<<0)
1690
1691 +#define S3C2440_SDIFSTA_FIFORESET (1<<16)
1692 +#define S3C2440_SDIFSTA_FIFOFAIL (3<<14) /* 3 is correct (2 bits) */
1693 #define S3C2410_SDIFSTA_TFDET (1<<13)
1694 #define S3C2410_SDIFSTA_RFDET (1<<12)
1695 -#define S3C2410_SDIFSTA_TXHALF (1<<11)
1696 -#define S3C2410_SDIFSTA_TXEMPTY (1<<10)
1697 +#define S3C2410_SDIFSTA_TFHALF (1<<11)
1698 +#define S3C2410_SDIFSTA_TFEMPTY (1<<10)
1699 #define S3C2410_SDIFSTA_RFLAST (1<<9)
1700 #define S3C2410_SDIFSTA_RFFULL (1<<8)
1701 #define S3C2410_SDIFSTA_RFHALF (1<<7)
1702 --
1703 1.5.6.5
1704
This page took 0.109072 seconds and 5 git commands to generate.