mod sdmmc
author柯飞雄 <kfx@rock-chips.com>
Thu, 27 May 2010 09:52:42 +0000 (09:52 +0000)
committer黄涛 <huangtao@rock-chips.com>
Mon, 21 Jun 2010 05:35:17 +0000 (13:35 +0800)
drivers/mmc/host/rk2818-sdmmc.c
drivers/mmc/host/rk2818-sdmmc.h

index f2ab2340e3c278e6ce69c1f8346e6b90456664b2..c2c6f5f135a4dd0fa611253705331af12660b689 100644 (file)
@@ -32,7 +32,7 @@
 
 #include <mach/board.h>
 #include <mach/rk2818_iomap.h>
-
+#include <mach/gpio.h>
 #include <asm/dma.h>
 #include <asm/scatterlist.h>
 
@@ -77,7 +77,10 @@ struct rk2818_sdmmc_host {
        struct mmc_data         *data;
 
        int                             dma_chn;
-       unsigned int            use_dma:1;
+       unsigned int    use_dma:1;
+       unsigned int    no_detect:1;
+       char                    dma_name[8];
+
        u32                     cmd_status;
        u32                     data_status;
        u32                     stop_cmdr;
@@ -91,7 +94,6 @@ struct rk2818_sdmmc_host {
        u32                     bus_hz;
        u32                     current_speed;
        struct platform_device  *pdev;
-       struct rk2818_sdmmc_platform_data *pdata;
 
        struct mmc_host         *mmc;
        u32                     ctype;
@@ -116,6 +118,7 @@ struct rk2818_sdmmc_host {
 #define rk2818_sdmmc_set_pending(host, event)                          \
        set_bit(event, &host->pending_events)
 
+static void rk2818_sdmmc_read_data_pio(struct rk2818_sdmmc_host *host);
 #if defined (CONFIG_DEBUG_FS)
 
 static int rk2818_sdmmc_req_show(struct seq_file *s, void *v)
@@ -368,11 +371,9 @@ static int rk2818_sdmmc_submit_data_dma(struct rk2818_sdmmc_host *host, struct m
        struct scatterlist              *sg;
        unsigned int                    i;
 
+       host->dma_chn = -1;
        if(host->use_dma == 0)
-       {
-               host->dma_chn = -1;
                return -ENOSYS;
-       }
        if (data->blocks * data->blksz < RK2818_MCI_DMA_THRESHOLD)
                return -EINVAL;
        if (data->blksz & 3)
@@ -382,25 +383,23 @@ static int rk2818_sdmmc_submit_data_dma(struct rk2818_sdmmc_host *host, struct m
                        return -EINVAL;
        }
        for(i = 0; i < MAX_SG_CHN; i++) {
-               if(request_dma(i, "sd_mmc") == 0) {
+               if(request_dma(i, host->dma_name) == 0) {
                        host->dma_chn = i;
                        break;
                }
        }
-       if(i == MAX_SG_CHN) {
-               host->dma_chn = -1;
+       if(i == MAX_SG_CHN) 
                return -EINVAL;
-       }
        dma_map_sg(host->dev, data->sg, data->sg_len, 
                        (data->flags & MMC_DATA_READ)? DMA_FROM_DEVICE : DMA_TO_DEVICE);
+       for_each_sg(data->sg, sg, data->sg_len, i) {
+               dev_dbg(host->dev, "sg[%d]  addr: 0x%08x, len: %d", i, sg->dma_address, sg->length);
+       }
 
        set_dma_sg(host->dma_chn, data->sg, data->sg_len);
-
        set_dma_mode(host->dma_chn,
-                       (data->flags & MMC_DATA_READ)? DMA_MODE_READ : DMA_MODE_WRITE);
-
+                               (data->flags & MMC_DATA_READ)? DMA_MODE_READ : DMA_MODE_WRITE);
        set_dma_handler(host->dma_chn, rk2818_sdmmc_dma_complete, (void *)host);
-
        writel(readl(host->regs + SDMMC_CTRL) | SDMMC_CTRL_DMA_ENABLE,
                                host->regs +SDMMC_CTRL);
        enable_dma(host->dma_chn);
@@ -412,7 +411,7 @@ static void rk2818_sdmmc_submit_data(struct rk2818_sdmmc_host *host, struct mmc_
 {
        data->error = -EINPROGRESS;
 
-       //WARN_ON(host->data);
+       WARN_ON(host->data);
        host->sg = NULL;
        host->data = data;
 
@@ -555,7 +554,10 @@ static void rk2818_sdmmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
                host->ctype = SDMMC_CTYPE_4BIT;
                break;
        }
-
+       if(ios->bus_mode == MMC_BUSMODE_OPENDRAIN)
+               writel(readl(host->regs + SDMMC_CTRL) | SDMMC_CTRL_OD_PULLUP, host->regs + SDMMC_CTRL);
+       else
+               writel(readl(host->regs + SDMMC_CTRL) & ~SDMMC_CTRL_OD_PULLUP, host->regs + SDMMC_CTRL);
 
        if (ios->clock) {
                spin_lock(&host->lock);
@@ -615,12 +617,18 @@ static void rk2818_sdmmc_enable_sdio_irq(struct mmc_host *mmc, int enable)
        spin_unlock_irqrestore(&host->lock, flags);
 }
 
-static const struct mmc_host_ops rk2818_sdmmc_ops = {
-       .request        = rk2818_sdmmc_request,
-       .set_ios        = rk2818_sdmmc_set_ios,
-       .get_ro         = rk2818_sdmmc_get_ro,
-       .get_cd         = rk2818_sdmmc_get_cd,
-       .enable_sdio_irq = rk2818_sdmmc_enable_sdio_irq,
+static const struct mmc_host_ops rk2818_sdmmc_ops[] = {
+       {
+               .request        = rk2818_sdmmc_request,
+               .set_ios        = rk2818_sdmmc_set_ios,
+               .get_ro         = rk2818_sdmmc_get_ro,
+               .get_cd         = rk2818_sdmmc_get_cd,
+       },
+       {
+               .request        = rk2818_sdmmc_request,
+               .set_ios        = rk2818_sdmmc_set_ios,
+               .enable_sdio_irq = rk2818_sdmmc_enable_sdio_irq,
+       },
 };
 
 static void rk2818_sdmmc_request_end(struct rk2818_sdmmc_host *host, struct mmc_request *mrq)
@@ -630,9 +638,8 @@ static void rk2818_sdmmc_request_end(struct rk2818_sdmmc_host *host, struct mmc_
        struct mmc_host         *prev_mmc = host->mmc;
 
        WARN_ON(host->cmd || host->data);
-
-       host->mrq = NULL;
        host->mrq = NULL;
+
        if (!list_empty(&host->queue)) {
                host = list_entry(host->queue.next,
                                struct rk2818_sdmmc_host, queue_node);
@@ -746,8 +753,13 @@ static void rk2818_sdmmc_tasklet_func(unsigned long priv)
 
                        if (!rk2818_sdmmc_test_and_clear_pending(host,
                                                EVENT_XFER_COMPLETE))
+                       {
+                               if(host-> no_detect == 1 && 
+                                       host->dir_status == RK2818_MCI_RECV_STATUS && 
+                                       host->dma_chn == -1)
+                                       rk2818_sdmmc_read_data_pio(host);
                                break;
-
+                       }
                        rk2818_sdmmc_set_completed(host, EVENT_XFER_COMPLETE);
                        prev_state = state = STATE_DATA_BUSY;
                        /* fall through */
@@ -763,15 +775,15 @@ static void rk2818_sdmmc_tasklet_func(unsigned long priv)
 
                        if (unlikely(status & RK2818_MCI_DATA_ERROR_FLAGS)) {
                                if (status & SDMMC_INT_DRTO) {
-                                       dev_err(&host->pdev->dev,
+                                       dev_err(host->dev,
                                                        "data timeout error\n");
                                        data->error = -ETIMEDOUT;
                                } else if (status & SDMMC_INT_DCRC) {
-                                       dev_err(&host->pdev->dev,
+                                       dev_err(host->dev,
                                                        "data CRC error\n");
                                        data->error = -EILSEQ;
                                } else {
-                                       dev_err(&host->pdev->dev,
+                                       dev_err(host->dev,
                                                "data FIFO error (status=%08x)\n",
                                                status);
                                        data->error = -EIO;
@@ -985,7 +997,7 @@ static void rk2818_sdmmc_cmd_interrupt(struct rk2818_sdmmc_host *host, u32 statu
 {
        if(!host->cmd_status) 
                host->cmd_status = status;
-
+       smp_wmb();
        rk2818_sdmmc_set_pending(host, EVENT_CMD_COMPLETE);
        tasklet_schedule(&host->tasklet);
 }
@@ -1010,7 +1022,7 @@ static irqreturn_t rk2818_sdmmc_interrupt(int irq, void *data)
                if(pending & RK2818_MCI_CMD_ERROR_FLAGS) {
                    writel(RK2818_MCI_CMD_ERROR_FLAGS, host->regs + SDMMC_RINTSTS);  //  clear interrupt
                    host->cmd_status = status;
-
+                       smp_wmb();
                    rk2818_sdmmc_set_pending(host, EVENT_CMD_COMPLETE);
                    tasklet_schedule(&host->tasklet);
                }
@@ -1018,7 +1030,7 @@ static irqreturn_t rk2818_sdmmc_interrupt(int irq, void *data)
                if (pending & RK2818_MCI_DATA_ERROR_FLAGS) { // if there is an error, let report DATA_ERROR
                        writel(RK2818_MCI_DATA_ERROR_FLAGS, host->regs + SDMMC_RINTSTS);  // clear interrupt
                        host->data_status = status;
-
+                       smp_wmb();
                        rk2818_sdmmc_set_pending(host, EVENT_DATA_ERROR);
                        tasklet_schedule(&host->tasklet);
                }
@@ -1027,10 +1039,11 @@ static irqreturn_t rk2818_sdmmc_interrupt(int irq, void *data)
                if(pending & SDMMC_INT_DTO) {
                    writel(SDMMC_INT_DTO, host->regs + SDMMC_RINTSTS);  // clear interrupt
                    if (!host->data_status)
-                       host->data_status = status;
+                               host->data_status = status;
+                       smp_wmb();
                    if(host->dir_status == RK2818_MCI_RECV_STATUS) {
-                       if(host->sg != NULL
-                               rk2818_sdmmc_read_data_pio(host);
+                               if(host->sg
+                                       rk2818_sdmmc_read_data_pio(host);
                    }
                    rk2818_sdmmc_set_pending(host, EVENT_DATA_COMPLETE);
                    tasklet_schedule(&host->tasklet);
@@ -1045,7 +1058,7 @@ static irqreturn_t rk2818_sdmmc_interrupt(int irq, void *data)
                if (pending & SDMMC_INT_TXDR) {
                    writel(SDMMC_INT_TXDR, host->regs + SDMMC_RINTSTS);  //  clear interrupt
                    if(host->sg) {
-                       rk2818_sdmmc_write_data_pio(host);
+                               rk2818_sdmmc_write_data_pio(host);
                    }
                }
 
@@ -1053,12 +1066,16 @@ static irqreturn_t rk2818_sdmmc_interrupt(int irq, void *data)
                        writel(SDMMC_INT_CMD_DONE, host->regs + SDMMC_RINTSTS);  //  clear interrupt
                    rk2818_sdmmc_cmd_interrupt(host, status);
                }
+               if(pending & SDMMC_INT_SDIO) {
+                       writel(SDMMC_INT_SDIO, host->regs + SDMMC_RINTSTS);
+                       mmc_signal_sdio_irq(host->mmc);
+               }
        } while (pass_count++ < 5);
        
        spin_unlock(&host->lock);
 
-       return IRQ_HANDLED;
-       //return pass_count ? IRQ_HANDLED : IRQ_NONE;
+       //return IRQ_HANDLED;
+       return pass_count ? IRQ_HANDLED : IRQ_NONE;
 }
 
 static void rk2818_sdmmc_detect_change(unsigned long host_data)
@@ -1076,7 +1093,7 @@ static void rk2818_sdmmc_detect_change(unsigned long host_data)
 
        if (present != present_old) {
 
-               dev_info(host->dev, "card %s\n", present ? "inserted" : "removed");
+               dev_dbg(host->dev, "card %s\n", present ? "inserted" : "removed");
 
                spin_lock(&host->lock);
 
@@ -1173,11 +1190,12 @@ static int rk2818_sdmmc_probe(struct platform_device *pdev)
        host = mmc_priv(mmc);
 
        host->mmc = mmc;
-       host->pdata = pdata;
        host->pdev = pdev;
        host->dev = &pdev->dev;
 
        host->use_dma = pdata->use_dma;
+       host->no_detect = pdata->no_detect;
+       memcpy(host->dma_name, pdata->dma_name, 8);
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        if (!res)
@@ -1208,6 +1226,7 @@ static int rk2818_sdmmc_probe(struct platform_device *pdev)
                goto err_free_map;
        }
 
+
        spin_lock_init(&host->lock);
        INIT_LIST_HEAD(&host->queue);
 
@@ -1252,26 +1271,25 @@ static int rk2818_sdmmc_probe(struct platform_device *pdev)
 
 
        platform_set_drvdata(pdev, host);
-
-
-       mmc->ops = &rk2818_sdmmc_ops;
+       dev_dbg(host->dev, "pdev->id = %d\n", pdev->id);
+       mmc->ops = &(rk2818_sdmmc_ops[pdev->id]);
 
        mmc->f_min = host->bus_hz/510;
        mmc->f_max = host->bus_hz/2; 
        dev_dbg(&pdev->dev, "bus_hz = %u\n", host->bus_hz);
-       mmc->ocr_avail = host->pdata->host_ocr_avail;
-       mmc->caps = host->pdata->host_caps;
+       mmc->ocr_avail = pdata->host_ocr_avail;
+       mmc->caps = pdata->host_caps;
        
-       mmc->max_phys_segs = 4095;
-       mmc->max_hw_segs = 4095;
-       mmc->max_blk_size = 4095 * 512; /* BLKSIZ is 16 bits*/
-       mmc->max_blk_count = 4095;
+       mmc->max_phys_segs = 64;
+       mmc->max_hw_segs = 64;
+       mmc->max_blk_size = 4095;
+       mmc->max_blk_count = 512;
        mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count;
        mmc->max_seg_size = mmc->max_req_size;
 
        rk2818_sdmmc_set_power(host, 0);
        /* Assume card is present initially */
-       if(rk2818_sdmmc_get_cd(host->mmc) != 0)
+       if(host->no_detect == 1 || rk2818_sdmmc_get_cd(host->mmc) != 0)
                set_bit(RK2818_MMC_CARD_PRESENT, &host->flags);
        else
                clear_bit(RK2818_MMC_CARD_PRESENT, &host->flags);
@@ -1294,8 +1312,8 @@ static int rk2818_sdmmc_probe(struct platform_device *pdev)
                        host->regs + SDMMC_INTMASK);
        writel(SDMMC_CTRL_INT_ENABLE, host->regs + SDMMC_CTRL); // enable mci interrupt
 
-       dev_info(&pdev->dev, "RK2818 MMC controller at irq %d, %s\n", 
-                               host->irq, (host->use_dma == 1)?"use dma":"do not use dma");
+       dev_info(&pdev->dev, "RK2818 MMC controller used as %s, at irq %d\n", 
+                               host->dma_name, host->irq);
 
        return 0;
 
index 8b06357b90f8c7fb12e676269f7db869c8846fc8..a6a3694214abee76fb4ef65c410918b54c7b0902 100755 (executable)
@@ -50,6 +50,7 @@
 #define RK2818_BIT(n)                          (1<<(n))
 
 /* Control register defines */
+#define SDMMC_CTRL_OD_PULLUP     RK2818_BIT(24)
 #define SDMMC_CTRL_ABRT_READ_DATA RK2818_BIT(8)
 #define SDMMC_CTRL_SEND_IRQ_RESP  RK2818_BIT(7)
 #define SDMMC_CTRL_READ_WAIT      RK2818_BIT(6)