2 * linux/drivers/mmc/moxasd.c - Moxa CPU SD/MMC driver
4 * Copyright (C) 2005 Moxa Tech., All Rights Reserved.
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
11 #include <linux/config.h>
12 #include <asm/arch/cpe/cpe.h>
13 #include <asm/arch/cpe_int.h>
14 #include <linux/module.h>
15 #include <linux/init.h>
16 #include <linux/ioport.h>
17 #include <linux/device.h>
18 #include <linux/delay.h>
19 #include <linux/interrupt.h>
20 #include <linux/blkdev.h>
21 #include <linux/dma-mapping.h>
22 #include <linux/mmc/host.h>
23 #include <linux/sched.h>
24 #include <linux/delay.h>
25 #include <linux/mmc/protocol.h>
30 #include <asm/sizes.h>
31 #include <asm/arch/gpio.h>
35 //#define MSD_SUPPORT_GET_CLOCK 1
37 #define MSD_RETRY_COUNT 1000
38 #define DMA_BUFFER_SIZE 65536
40 //#define CONFIG_MMC_DEBUG
41 #ifdef CONFIG_MMC_DEBUG
42 #define DBG(x...) printk(x)
52 #ifdef MSD_SUPPORT_GET_CLOCK
55 struct mmc_request
*mrq
;
56 struct mmc_data
*data
;
58 struct scatterlist
*cur_sg
; /* Current SG entry */
59 unsigned int num_sg
; /* Number of entries left */
60 void *mapped_sg
; /* vaddr of mapped sg */
61 unsigned int remain
; /* Data left in curren entry */
62 int size
; /* Total size of transfer */
64 struct tasklet_struct card_change_tasklet
;
65 struct tasklet_struct fifo_run_tasklet
;
68 static inline void moxasd_init_sg(struct moxasd_host
* host
, struct mmc_data
* data
)
70 // Get info. about SG list from data structure.
71 host
->cur_sg
= data
->sg
;
72 host
->num_sg
= data
->sg_len
;
74 host
->remain
= host
->cur_sg
->length
;
75 #if 1 // add by Victor Yu. 07-04-2007
76 if ( host
->remain
> host
->size
)
77 host
->remain
= host
->size
;
78 host
->mapped_sg
= NULL
;
80 data
->error
= MMC_ERR_NONE
;
83 static inline void moxasd_next_sg(struct moxasd_host
* host
)
85 #if 1 // add by Victor Yu. 07-04-2007
86 struct mmc_data
*data
=host
->data
;
89 // Skip to next SG entry.
94 if (host
->num_sg
> 0) {
95 host
->remain
= host
->cur_sg
->length
;
96 #if 1 // add by Victor Yu. 07-04-2007
99 remain
= host
->size
- data
->bytes_xfered
;
100 if ( remain
> 0 && remain
< host
->remain
) {
101 host
->remain
= remain
;
108 static inline char *moxasd_kmap_sg(struct moxasd_host
* host
)
110 host
->mapped_sg
= kmap_atomic(host
->cur_sg
->page
, KM_BIO_SRC_IRQ
);
111 return host
->mapped_sg
+ host
->cur_sg
->offset
;
114 static void moxasd_do_fifo(struct moxasd_host
*host
, struct mmc_data
*data
)
119 #if 1 // add by Victor Yu. 07-06-2007
120 if ( host
->mapped_sg
) {
121 kunmap_atomic(host
->mapped_sg
, KM_BIO_SRC_IRQ
);
122 moxasd_next_sg(host
);
125 if ( host
->size
<= data
->bytes_xfered
) {
128 buffer
= moxasd_kmap_sg(host
);
129 if ( host
->size
> MSD_FIFO_LENB
&& host
->dma
) {
130 apb_dma_conf_param param
;
131 param
.size
= host
->remain
;
132 param
.burst_mode
= APB_DMAB_BURST_MODE
;
133 param
.data_width
= APB_DMAB_DATA_WIDTH_4
;
134 if ( data
->flags
& MMC_DATA_WRITE
) {
135 param
.source_addr
= (unsigned int)buffer
;
136 param
.dest_addr
= (unsigned int)&host
->reg
->data_window
;
137 param
.dest_inc
= APB_DMAB_DEST_INC_0
;
138 param
.source_inc
= APB_DMAB_DEST_INC_4_16
;
139 param
.dest_sel
= APB_DMAB_DEST_APB
;
140 param
.source_sel
= APB_DMAB_SOURCE_AHB
;
142 param
.dest_addr
= (unsigned int)buffer
;
143 param
.source_addr
= (unsigned int)&host
->reg
->data_window
;
144 param
.source_inc
= APB_DMAB_DEST_INC_0
;
145 param
.dest_inc
= APB_DMAB_DEST_INC_4_16
;
146 param
.source_sel
= APB_DMAB_DEST_APB
;
147 param
.dest_sel
= APB_DMAB_SOURCE_AHB
;
149 data
->bytes_xfered
+= host
->remain
;
150 apb_dma_conf(host
->dma
, ¶m
);
151 apb_dma_enable(host
->dma
);
153 wcnt
= host
->remain
>> 2;
154 if ( data
->flags
& MMC_DATA_WRITE
) {
155 for ( i
=0; i
<wcnt
; i
++, buffer
+=4 )
156 writel(*(unsigned int *)buffer
, &host
->reg
->data_window
);
158 for ( i
=0; i
<wcnt
; i
++, buffer
+=4 )
159 *(unsigned int *)buffer
= readl(&host
->reg
->data_window
);
162 host
->remain
-= wcnt
;
163 data
->bytes_xfered
+= wcnt
;
165 #if 0 // mask by Victor Yu. 07-06-2007
166 kunmap_atomic(host
->mapped_sg
, KM_BIO_SRC_IRQ
);
167 moxasd_next_sg(host
);
171 static void moxasd_request_done(struct moxasd_host
*host
)
173 struct mmc_request
*mrq
=host
->mrq
;
180 mmc_request_done(host
->mmc
, mrq
);
183 static void moxasd_prepare_data(struct moxasd_host
*host
, struct mmc_data
*data
)
185 unsigned int timeout
, datactrl
;
186 //unsigned long flags;
190 // initialize the data size
191 host
->size
= data
->blocks
<< data
->blksz_bits
;
192 moxasd_init_sg(host
, data
);
194 // initialize the timeout value
195 timeout
= (host
->mmc
->f_max
/1000) * (data
->timeout_ns
/1000);
198 // initialize the data control
199 datactrl
= (data
->blksz_bits
& MSD_BLK_SIZE_MASK
) | MSD_DATA_EN
;
200 if ( data
->flags
& MMC_DATA_WRITE
) {
201 datactrl
|= MSD_DATA_WRITE
;
203 if ( host
->size
> MSD_FIFO_LENB
&& host
->dma
) {
204 datactrl
|= MSD_DMA_EN
;
206 writel(timeout
, &host
->reg
->data_timer
);
207 writel(host
->size
, &host
->reg
->data_length
);
208 writel(datactrl
, &host
->reg
->data_control
);
209 //printk("DCR:%x data_length:%x data->blocks:%x host->remain:%x\n",host->reg->data_control,host->reg->data_length,data->blocks, host->remain);//johnson
210 if ( host
->size
> MSD_FIFO_LENB
&& host
->dma
) {
211 writel(MSD_INT_CARD_CHANGE
, &host
->reg
->interrupt_mask
);
212 moxasd_do_fifo(host
, data
);
213 //tasklet_schedule(&host->fifo_run_tasklet);
215 writel(MSD_INT_FIFO_URUN
|MSD_INT_FIFO_ORUN
|MSD_INT_CARD_CHANGE
, &host
->reg
->interrupt_mask
);
219 static void moxasd_send_command(struct moxasd_host
*host
, struct mmc_command
*cmd
)
221 unsigned int status
, cmdctrl
;
224 // first clear status
225 writel(MSD_CLR_RSP_TIMEOUT
|MSD_CLR_RSP_CRC_OK
|MSD_CLR_RSP_CRC_FAIL
|MSD_CLR_CMD_SENT
, &host
->reg
->clear
);
228 writel(cmd
->arg
, &host
->reg
->argument
);
231 cmdctrl
= cmd
->opcode
& MSD_CMD_IDX_MASK
;
232 if ( cmdctrl
== SD_APP_SET_BUS_WIDTH
||
233 cmdctrl
== SD_APP_OP_COND
||
234 cmdctrl
== SD_APP_SEND_SCR
) // this is SD application specific command
235 cmdctrl
|= MSD_APP_CMD
;
236 if ( cmd
->flags
& MMC_RSP_LONG
)
237 cmdctrl
|= (MSD_LONG_RSP
|MSD_NEED_RSP
);
238 if ( cmd
->flags
& MMC_RSP_SHORT
)
239 cmdctrl
|= MSD_NEED_RSP
;
240 writel(cmdctrl
|MSD_CMD_EN
, &host
->reg
->command
);
243 while ( retry
++ < MSD_RETRY_COUNT
) {
244 status
= readl(&host
->reg
->status
);
245 if ( status
& MSD_CARD_DETECT
) { // card is removed
246 cmd
->error
= MMC_ERR_TIMEOUT
;
249 if ( cmdctrl
& MSD_NEED_RSP
) {
250 if ( status
& MSD_RSP_TIMEOUT
) {
251 writel(MSD_CLR_RSP_TIMEOUT
, &host
->reg
->clear
);
252 cmd
->error
= MMC_ERR_TIMEOUT
;
256 if ( status
& MSD_RSP_CRC_FAIL
) {
258 if ( (cmd
->flags
&MMC_RSP_CRC
) && (status
&MSD_RSP_CRC_FAIL
) ) {
260 writel(MSD_CLR_RSP_CRC_FAIL
, &host
->reg
->clear
);
261 cmd
->error
= MMC_ERR_BADCRC
;
264 if ( status
& MSD_RSP_CRC_OK
) {
265 writel(MSD_CLR_RSP_CRC_OK
, &host
->reg
->clear
);
267 cmd
->resp
[0] = readl(&host
->reg
->response0
);
268 cmd
->resp
[1] = readl(&host
->reg
->response1
);
269 cmd
->resp
[2] = readl(&host
->reg
->response2
);
270 cmd
->resp
[3] = readl(&host
->reg
->response3
);
271 cmd
->error
= MMC_ERR_NONE
;
275 if ( status
& MSD_CMD_SENT
) {
276 writel(MSD_CLR_CMD_SENT
, &host
->reg
->clear
);
277 cmd
->error
= MMC_ERR_NONE
;
283 cmd
->error
= MMC_ERR_TIMEOUT
;
284 // cmd->error = MMC_ERR_NONE;
288 static irqreturn_t
moxasd_irq(int irq
, void *devid
, struct pt_regs
*regs
)
290 struct moxasd_host
*host
=devid
;
293 // get the interrupt status
294 status
= readl(&host
->reg
->status
);
296 // acknowledge the interurpt
297 if ( status
& MSD_CARD_CHANGE
) { // has card inserted or removed
298 tasklet_schedule(&host
->card_change_tasklet
);
301 if ( status
& (MSD_FIFO_ORUN
|MSD_FIFO_URUN
) ) {
302 #if 1 // add by Victor Yu. 07-09-2007
303 writel(status
& (MSD_FIFO_ORUN
|MSD_FIFO_URUN
), &host
->reg
->clear
);
305 tasklet_schedule(&host
->fifo_run_tasklet
);
311 static void moxasd_fifo_run(unsigned long param
)
313 struct moxasd_host
*host
;
314 struct mmc_data
*data
;
317 spin_lock_irqsave(&host
->lock
, flags
);
318 host
= (struct moxasd_host
*)param
;
320 if ( host
->mrq
== NULL
|| data
== NULL
) {
321 spin_unlock_irqrestore(&host
->lock
, flags
);
324 moxasd_do_fifo(host
, data
);
325 if ( host
->size
<= data
->bytes_xfered
) {
326 #if 1 // mask by Victor Yu. 07-04-2007
329 status
= readl(&host
->reg
->status
);
330 if ( status
& (MSD_DATA_CRC_OK
|MSD_DATA_CRC_FAIL
|MSD_DATA_END
) )
332 current
->state
= TASK_INTERRUPTIBLE
;
335 if ( status
& MSD_DATA_CRC_OK
) {
336 writel(MSD_CLR_DATA_CRC_OK
, &host
->reg
->clear
);
338 if ( status
& MSD_DATA_CRC_FAIL
) {
339 writel(MSD_CLR_DATA_CRC_FAIL
, &host
->reg
->clear
);
340 data
->error
= MMC_ERR_TIMEOUT
;
342 if ( status
& MSD_DATA_END
) {
343 writel(MSD_CLR_DATA_END
, &host
->reg
->clear
);
346 //moxasd_do_fifo(host, data);
348 moxasd_send_command(host
, data
->stop
);
351 #if 0 // mask by Victor Yu. 07-10-2007
352 moxasd_do_fifo(host
, data
);
353 if ( host
->size
<= MSD_FIFO_LENB
) {
354 //tasklet_schedule(&host->fifo_run_tasklet);
355 moxasd_request_done(host
);
358 spin_unlock_irqrestore(&host
->lock
, flags
);
362 moxasd_request_done(host
);
363 spin_unlock_irqrestore(&host
->lock
, flags
);
366 static void moxasd_card_change(unsigned long param
)
368 struct moxasd_host
*host
=(struct moxasd_host
*)param
;
373 spin_lock_irqsave(&host
->lock
, flags
);
374 udelay(3000); // to wait the hardware stably for card inserted or removed
375 status
= readl(&host
->reg
->status
);
376 if ( status
& MSD_CARD_DETECT
) { // card removed
377 printk("Moxa CPU SD/MMC card is removed.\n");
380 if ( host
->dma
&& host
->size
> MSD_FIFO_LENB
)
381 apb_dma_disable(host
->dma
);
382 host
->size
= host
->data
->bytes_xfered
;
383 moxasd_do_fifo(host
, host
->data
);
384 host
->data
->error
= MMC_ERR_TIMEOUT
;
385 moxasd_request_done(host
);
386 //spin_unlock_irqrestore(&host->lock, flags);
387 //moxasd_fifo_run(*(unsigned long *)host);
388 //spin_lock_irqsave(&host->lock, flags);
390 } else { // card inserted
391 printk("Moxa CPU SD/MMC card is inserted.\n");
392 if ( readl(&host
->reg
->clock_control
) & MSD_CLK_SD
) { // SD
393 host
->mmc
->f_max
= 25000000;
395 host
->mmc
->mode
= MMC_MODE_SD
;
397 host
->mmc
->f_max
= 20000000;
398 host
->mmc
->mode
= MMC_MODE_MMC
;
402 writel(MSD_CLR_CARD_CHANGE
, &host
->reg
->clear
);
403 spin_unlock_irqrestore(&host
->lock
, flags
);
404 mmc_detect_change(host
->mmc
, msecs_to_jiffies(delay
));
407 static void moxasd_dma_irq(void *param
)
409 struct moxasd_host
*host
=(struct moxasd_host
*)param
;
412 tasklet_schedule(&host
->fifo_run_tasklet
);
415 static void moxasd_request(struct mmc_host
*mmc
, struct mmc_request
*mrq
)
417 struct moxasd_host
*host
=mmc_priv(mmc
);
418 struct mmc_command
*cmd
;
421 spin_lock_irqsave(&host
->lock
, flags
);
425 // if no card inserted, return timeout error
426 if ( readl(&host
->reg
->status
) & MSD_CARD_DETECT
) { // card is removed
427 cmd
->error
= MMC_ERR_TIMEOUT
;
431 // request include data or not
433 moxasd_prepare_data(host
, cmd
->data
);
436 // do request command
437 moxasd_send_command(host
, cmd
);
439 if ( cmd
->data
&& cmd
->error
== MMC_ERR_NONE
) {
440 spin_unlock_irqrestore(&host
->lock
, flags
);
446 moxasd_request_done(host
);
447 spin_unlock_irqrestore(&host
->lock
, flags
);
450 #define MIN_POWER (MMC_VDD_360 - MSD_SD_POWER_MASK)
451 static void moxasd_set_ios(struct mmc_host
*mmc
, struct mmc_ios
*ios
)
453 struct moxasd_host
*host
=mmc_priv(mmc
);
456 spin_lock_irqsave(&host
->lock
, flags
);
459 #ifdef MSD_SUPPORT_GET_CLOCK
460 div
= (host
->sysclk
/ (host
->mmc
->f_max
* 2)) - 1;
462 div
= (APB_CLK
/ (host
->mmc
->f_max
* 2)) - 1;
464 if ( div
> MSD_CLK_DIV_MASK
)
465 div
= MSD_CLK_DIV_MASK
;
468 if ( host
->mmc
->mode
== MMC_MODE_SD
)
470 writel(div
, &host
->reg
->clock_control
);
471 } else if ( !(readl(&host
->reg
->clock_control
) & MSD_CLK_DIS
) ) {
473 * Ensure that the clock is off.
475 writel(readl(&host
->reg
->clock_control
)|MSD_CLK_DIS
, &host
->reg
->clock_control
);
478 if ( ios
->power_mode
== MMC_POWER_OFF
) {
479 writel(readl(&host
->reg
->power_control
)&~MSD_SD_POWER_ON
, &host
->reg
->power_control
);
481 unsigned short power
;
483 if ( ios
->vdd
< MIN_POWER
)
486 power
= ios
->vdd
- MIN_POWER
;
487 writel(MSD_SD_POWER_ON
|(unsigned int)power
, &host
->reg
->power_control
);
491 if ( ios
->bus_width
== MMC_BUS_WIDTH_1
) {
492 writel(MSD_SINGLE_BUS
, &host
->reg
->bus_width
);
494 writel(MSD_WIDE_BUS
, &host
->reg
->bus_width
);
497 spin_unlock_irqrestore(&host
->lock
, flags
);
501 * To check write protect or not. Return 0 for none, 1 for write protect.
503 static int moxasd_get_ro(struct mmc_host
*mmc
)
505 struct moxasd_host
*host
=mmc_priv(mmc
);
507 if ( readl(&host
->reg
->status
) & MSD_WRITE_PROT
)
513 static struct mmc_host_ops moxasd_ops
= {
514 .request
= moxasd_request
,
515 .set_ios
= moxasd_set_ios
,
516 .get_ro
= moxasd_get_ro
,
519 static int moxasd_probe(struct device
*dev
)
521 struct mmc_host
*mmc
;
522 struct moxasd_host
*host
=NULL
;
525 mmc
= mmc_alloc_host(sizeof(struct moxasd_host
), dev
);
531 mmc
->ops
= &moxasd_ops
;
533 mmc
->f_max
= 25000000;
535 mmc
->mode
= MMC_MODE_SD
;
537 mmc
->ocr_avail
= 0xffff00; // support 2.0v - 3.6v power
539 mmc
->ocr_avail
= MMC_VDD_32_33
| MMC_VDD_33_34
;
540 mmc
->caps
= MMC_CAP_4_BIT_DATA
;
541 mmc
->max_hw_segs
= 128;
542 mmc
->max_phys_segs
= 128;
543 mmc
->max_sectors
= 128;
544 mmc
->max_seg_size
= mmc
->max_sectors
* 512;
547 host
= mmc_priv(mmc
);
549 spin_lock_init(&host
->lock
);
550 tasklet_init(&host
->card_change_tasklet
, moxasd_card_change
, (unsigned long)host
);
551 tasklet_init(&host
->fifo_run_tasklet
, moxasd_fifo_run
, (unsigned long)host
);
552 host
->reg
= (moxasd_reg
*)CPE_SD_VA_BASE
;
553 host
->dma
= apb_dma_alloc(APB_DMA_SD_REQ_NO
);
555 apb_dma_set_irq(host
->dma
, moxasd_dma_irq
, host
);
558 #ifdef MSD_SUPPORT_GET_CLOCK
561 unsigned int mul
, val
, div
;
562 mul
= (*(volatile unsigned int *)(CPE_PMU_VA_BASE
+0x30) >> 3) & 0x1ff;
563 val
= (*(volatile unsigned int *)(CPE_PMU_VA_BASE
+0x0c) >> 4) & 0x7;
565 case 0 : div
= 2; break;
566 case 1 : div
= 3; break;
567 case 2 : div
= 4; break;
568 case 3 : div
= 6; break;
569 case 4 : div
= 8; break;
570 default : div
= 2; break;
572 host
->sysclk
= (38684*mul
+ 10000) / (div
* 10000);
573 host
->sysclk
= (host
->sysclk
* 1000000) / 2;
577 // change I/O multiplexing to SD, so the GPIO 17-10 will be fail
578 mcpu_gpio_mp_clear(0xff<<10);
581 * Ensure that the host controller is shut down, and setup
584 writel(0, &host
->reg
->interrupt_mask
); // disable all interrupt
585 writel(MSD_SDC_RST
, &host
->reg
->command
); // reset chip
586 while ( readl(&host
->reg
->command
) & MSD_SDC_RST
); // wait for reset finished
587 writel(0, &host
->reg
->interrupt_mask
); // disable all interrupt
589 // to check any card inserted or not
590 if ( !(readl(&host
->reg
->status
) & MSD_CARD_DETECT
) ) { // is inserted
591 if ( readl(&host
->reg
->clock_control
) & MSD_CLK_SD
) { // is SD card
592 mmc
->f_max
= 25000000;
593 mmc
->mode
= MMC_MODE_SD
;
594 } else { // is MMC card
595 mmc
->f_max
= 20000000;
596 mmc
->mode
= MMC_MODE_MMC
;
600 mmc
->caps
= MMC_CAP_4_BIT_DATA
;
601 writel(MSD_WIDE_BUS
, &host
->reg
->bus_width
);
603 cpe_int_set_irq(IRQ_SD
, EDGE
, H_ACTIVE
);
604 ret
= request_irq(IRQ_SD
, moxasd_irq
, SA_INTERRUPT
, "MOXASD", host
);
608 writel(MSD_INT_CARD_CHANGE
, &host
->reg
->interrupt_mask
);
609 dev_set_drvdata(dev
, mmc
);
621 static int moxasd_remove(struct device
*dev
)
623 struct mmc_host
*mmc
=dev_get_drvdata(dev
);
625 dev_set_drvdata(dev
, NULL
);
628 struct moxasd_host
*host
=mmc_priv(mmc
);
630 mmc_remove_host(mmc
);
634 apb_dma_disable(host
->dma
);
635 apb_dma_release_irq(host
->dma
);
636 apb_dma_release(host
->dma
);
638 writel(0, &host
->reg
->interrupt_mask
);
639 writel(0, &host
->reg
->power_control
);
640 writel(readl(&host
->reg
->clock_control
)|MSD_CLK_DIS
, &host
->reg
->clock_control
);
642 free_irq(IRQ_SD
, host
);
643 tasklet_kill(&host
->card_change_tasklet
);
644 tasklet_kill(&host
->fifo_run_tasklet
);
651 static struct platform_device moxasd_device
= {
656 static struct device_driver moxasd_driver
= {
658 .bus
= &platform_bus_type
,
659 .probe
= moxasd_probe
,
660 .remove
= moxasd_remove
,
663 static int __init
moxasd_init(void)
667 printk("Moxa CPU SD/MMC Device Driver V1.0 initialize ");
668 platform_device_register(&moxasd_device
);
669 ret
= driver_register(&moxasd_driver
);
672 platform_device_unregister(&moxasd_device
);
679 static void __exit
moxasd_exit(void)
681 platform_device_unregister(&moxasd_device
);
682 driver_unregister(&moxasd_driver
);
685 module_init(moxasd_init
);
686 module_exit(moxasd_exit
);
688 MODULE_DESCRIPTION("Moxa CPU SD/Multimedia Card Interface Driver");
689 MODULE_LICENSE("GPL");