update sdmmc sdio
authorlhh <lhh@rock-chips.com>
Sat, 10 Jul 2010 10:09:10 +0000 (18:09 +0800)
committerlhh <lhh@rock-chips.com>
Sat, 10 Jul 2010 10:09:10 +0000 (18:09 +0800)
drivers/mmc/card/block.c
drivers/mmc/core/bus.c
drivers/mmc/core/core.c
drivers/mmc/core/mmc.c
drivers/mmc/host/rk2818-sdmmc.c
drivers/mmc/host/rk2818-sdmmc.h

index 8d2bd242ac63eec01b938286f1b9b37da4a213e2..a73fe94bb0d48fb3b43841d1dd26ad06b62f9938 100644 (file)
@@ -235,9 +235,11 @@ static u32 get_card_status(struct mmc_card *card, struct request *req)
                cmd.arg = card->rca << 16;
        cmd.flags = MMC_RSP_SPI_R2 | MMC_RSP_R1 | MMC_CMD_AC;
        err = mmc_wait_for_cmd(card->host, &cmd, 0);
+       #if 0 //[xjh] not printk,save time
        if (err)
                printk(KERN_ERR "%s: error %d sending status comand",
                       req->rq_disk->disk_name, err);
+       #endif
        return cmd.resp[0];
 }
 
@@ -376,7 +378,9 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
                 * until later as we need to wait for the card to leave
                 * programming mode even when things go wrong.
                 */
+               #if 1/*[xjh] do not retry with cmd17*/
                if (brq.cmd.error || brq.data.error || brq.stop.error) {
+                       
                        if (brq.data.blocks > 1 && rq_data_dir(req) == READ) {
                                /* Redo read one sector at a time */
                                printk(KERN_WARNING "%s: retrying using single "
@@ -384,11 +388,14 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
                                disable_multi = 1;
                                continue;
                        }
+                       
                        status = get_card_status(card, req);
                } else if (disable_multi == 1) {
                        disable_multi = 0;
                }
+               #endif
 
+               #if 0 //[xjh] not printk,save time
                if (brq.cmd.error) {
                        printk(KERN_ERR "%s: error %d sending read/write "
                               "command, response %#x, card status %#x\n",
@@ -413,6 +420,7 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
                               req->rq_disk->disk_name, brq.stop.error,
                               brq.stop.resp[0], status);
                }
+               #endif 
 
                if (!mmc_host_is_spi(card->host) && rq_data_dir(req) != READ) {
                        do {
@@ -445,6 +453,7 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
                }
 
                if (brq.cmd.error || brq.stop.error || brq.data.error) {
+                       #if 1/*[xjh] do not retry with cmd17*/
                        if (rq_data_dir(req) == READ) {
                                /*
                                 * After an error, we redo I/O one sector at a
@@ -456,6 +465,7 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
                                spin_unlock_irq(&md->lock);
                                continue;
                        }
+                       #endif
                        goto cmd_err;
                }
 
index bdb165f93046f9cdce780a614ddafcc41f3cab91..602b150163eebcbe87fd93ccdf0d1e4565d70a92 100644 (file)
@@ -268,6 +268,7 @@ int mmc_add_card(struct mmc_card *card)
        return 0;
 }
 
+extern int sdmmc0_disable_Irq_ForRemoval;
 /*
  * Unregister a new MMC card with the driver model, and
  * (eventually) free it.
@@ -277,6 +278,7 @@ void mmc_remove_card(struct mmc_card *card)
 #ifdef CONFIG_DEBUG_FS
        mmc_remove_card_debugfs(card);
 #endif
+       unsigned long flags;
 
        if (mmc_card_present(card)) {
                if (mmc_host_is_spi(card->host)) {
@@ -286,6 +288,13 @@ void mmc_remove_card(struct mmc_card *card)
                        printk(KERN_INFO "%s: card %04x removed\n",
                                mmc_hostname(card->host), card->rca);
                }
+
+        if( !strncmp( mmc_hostname(card->host) ,"mmc0" , strlen("mmc0")) )
+        {
+                       local_irq_save(flags);
+            sdmmc0_disable_Irq_ForRemoval = 1; //close the IRQ for insertion or removal  
+            local_irq_restore(flags);
+        }
                device_del(&card->dev);
        }
 
index fb25fd001f4a33672885789d0dbc7cd068af7391..231439a961e26cdc7e4b849ba4fee91d6919e2fe 100644 (file)
@@ -1059,7 +1059,7 @@ void mmc_detect_change(struct mmc_host *host, unsigned long delay)
 
 EXPORT_SYMBOL(mmc_detect_change);
 
-
+#if 0
 void mmc_rescan(struct work_struct *work)
 {
        struct mmc_host *host =
@@ -1154,6 +1154,102 @@ out:
        if (host->caps & MMC_CAP_NEEDS_POLL)
                mmc_schedule_delayed_work(&host->detect, HZ);
 }
+#else
+void mmc_rescan(struct work_struct *work)
+{
+       struct mmc_host *host =
+               container_of(work, struct mmc_host, detect.work);
+       u32 ocr;
+       int err;
+       int extend_wakelock = 0;
+
+       mmc_bus_get(host);
+       if(host->bus_ops == NULL)
+       {
+               /* detect a newly inserted card */
+
+               /*
+                * Only we can add a new handler, so it's safe to
+                * release the lock here.
+                */
+               mmc_bus_put(host);
+
+               if (host->ops->get_cd && host->ops->get_cd(host) == 0)
+                       goto out;
+
+               mmc_claim_host(host);
+
+               mmc_power_up(host);
+               mmc_go_idle(host);
+
+               mmc_send_if_cond(host, host->ocr_avail);
+
+               /*
+                * First we search for SDIO...
+                */
+               err = mmc_send_io_op_cond(host, 0, &ocr);
+               if (!err) {
+                       if (mmc_attach_sdio(host, ocr))
+                               mmc_power_off(host);
+                       extend_wakelock = 1;
+                       goto out;
+               }
+
+               /*
+                * ...then normal SD...
+                */
+               err = mmc_send_app_op_cond(host, 0, &ocr);
+               if (!err) {
+                       if (mmc_attach_sd(host, ocr))
+                               mmc_power_off(host);
+                       extend_wakelock = 1;
+                       goto out;
+               }
+
+               /*
+                * ...and finally MMC.
+                */
+               err = mmc_send_op_cond(host, 0, &ocr);
+               if (!err) {
+                       if (mmc_attach_mmc(host, ocr))
+                               mmc_power_off(host);
+                       extend_wakelock = 1;
+                       goto out;
+               }
+
+               mmc_release_host(host);
+               mmc_power_off(host);
+               
+       }
+       else
+       {
+               /* if there is a card registered, check whether it is still present */
+               if ((host->bus_ops != NULL) && host->bus_ops->detect && !host->bus_dead)
+                       host->bus_ops->detect(host);
+
+               /* If the card was removed the bus will be marked
+                * as dead - extend the wakelock so userspace
+                * can respond */
+               if (host->bus_dead)
+                       extend_wakelock = 1;
+
+               mmc_bus_put(host);
+               
+       }
+       
+
+
+out:
+       if (extend_wakelock)
+               wake_lock_timeout(&mmc_delayed_work_wake_lock, HZ / 2);
+       else
+               wake_unlock(&mmc_delayed_work_wake_lock);
+
+       if (host->caps & MMC_CAP_NEEDS_POLL)
+               mmc_schedule_delayed_work(&host->detect, HZ);
+}
+
+#endif
 
 void mmc_start_host(struct mmc_host *host)
 {
index 32af45c419f449d2f1cc9f07d058d667306a61a8..33747f583df89f8abf88b41eef123630b4aed22d 100644 (file)
@@ -660,6 +660,9 @@ static void mmc_attach_bus_ops(struct mmc_host *host)
 int mmc_attach_mmc(struct mmc_host *host, u32 ocr)
 {
        int err;
+       
+       unsigned long flags;
+       extern int sdmmc0_disable_Irq_ForRemoval;
 
        BUG_ON(!host);
        WARN_ON(!host->claimed);
@@ -708,6 +711,10 @@ int mmc_attach_mmc(struct mmc_host *host, u32 ocr)
        err = mmc_add_card(host->card);
        if (err)
                goto remove_card;
+       
+       local_irq_save(flags);
+       sdmmc0_disable_Irq_ForRemoval = 0; //close the IRQ for insertion or removal  
+       local_irq_restore(flags);
 
        return 0;
 
index ae7c9307a1bf81312fe354e88c61d00ce7640032..e0086a42b3e3702f09fd87a23596ab62d728a7fa 100644 (file)
@@ -29,6 +29,7 @@
 #include <linux/delay.h>
 #include <linux/irq.h>
 #include <linux/mmc/host.h>
+#include <linux/mmc/mmc.h>
 
 #include <mach/board.h>
 #include <mach/rk2818_iomap.h>
 
 struct mmc_host *wifi_mmc_host = NULL;
 
+int  sdmmc0_disable_Irq_ForRemoval;
+int hotplug_global_ctl;
+struct rk2818_sdmmc_host *mmc0_host;
+
+
 #define RK2818_MCI_DATA_ERROR_FLAGS    (SDMMC_INT_DRTO | SDMMC_INT_DCRC | SDMMC_INT_HTO | SDMMC_INT_SBE | SDMMC_INT_EBE)
 #define RK2818_MCI_CMD_ERROR_FLAGS     (SDMMC_INT_RTO | SDMMC_INT_RCRC | SDMMC_INT_RE | SDMMC_INT_HLE)
 #define RK2818_MCI_ERROR_FLAGS         (RK2818_MCI_DATA_ERROR_FLAGS | RK2818_MCI_CMD_ERROR_FLAGS | SDMMC_INT_HLE)
@@ -108,10 +114,19 @@ struct rk2818_sdmmc_host {
 #define RK2818_MMC_CARD_NEED_INIT      1
 #define RK2818_MMC_SHUTDOWN            2
        int                     irq;
+       unsigned int cmd_tmo;
+       struct mmc_command stop_mannual;
 
        struct timer_list       detect_timer;
 };
 
+#define MMC_DEBUG 0
+#if MMC_DEBUG
+#define xjhprintk(msg...) xjhprintk(msg)
+#else
+#define xjhprintk(msg...)
+#endif
+
 #define rk2818_sdmmc_test_and_clear_pending(host, event)               \
        test_and_clear_bit(event, &host->pending_events)
 #define rk2818_sdmmc_set_completed(host, event)                        \
@@ -243,6 +258,61 @@ err:
        dev_err(&mmc->class_dev, "failed to initialize debugfs for host\n");
 }
 #endif
+static void rk2818_show_regs(struct rk2818_sdmmc_host *host)
+{
+       unsigned long cpsr_tmp;
+
+       xjhprintk("--------[xjh] SD/MMC/SDIO Registers-----------------\n");
+       xjhprintk("SDMMC_CTRL:\t0x%x\n",readl(host->regs + SDMMC_CTRL));
+       xjhprintk("SDMMC_PWREN:\t0x%x\n",readl(host->regs + SDMMC_PWREN));
+       xjhprintk("SDMMC_CLKDIV:\t0x%x\n",readl(host->regs + SDMMC_CLKDIV));
+       xjhprintk("SDMMC_CLKSRC:\t0x%x\n",readl(host->regs + SDMMC_CLKSRC));
+       xjhprintk("SDMMC_CLKENA:\t0x%x\n",readl(host->regs + SDMMC_CLKENA));
+       xjhprintk("SDMMC_TMOUT:\t0x%x\n",readl(host->regs + SDMMC_TMOUT));
+       xjhprintk("SDMMC_CTYPE:\t0x%x\n",readl(host->regs + SDMMC_CTYPE));
+       xjhprintk("SDMMC_BLKSIZ:\t0x%x\n",readl(host->regs + SDMMC_BLKSIZ));
+       xjhprintk("SDMMC_BYTCNT:\t0x%x\n",readl(host->regs + SDMMC_BYTCNT));
+       xjhprintk("SDMMC_INTMASK:\t0x%x\n",readl(host->regs + SDMMC_INTMASK));
+       xjhprintk("SDMMC_CMDARG:\t0x%x\n",readl(host->regs + SDMMC_CMDARG));
+       xjhprintk("SDMMC_CMD:\t0x%x\n",readl(host->regs + SDMMC_CMD));
+       xjhprintk("SDMMC_RESP0:\t0x%x\n",readl(host->regs + SDMMC_RESP0));
+       xjhprintk("SDMMC_RESP1:\t0x%x\n",readl(host->regs + SDMMC_RESP1));
+       xjhprintk("SDMMC_RESP2:\t0x%x\n",readl(host->regs + SDMMC_RESP2));
+       xjhprintk("SDMMC_RESP3:\t0x%x\n",readl(host->regs + SDMMC_RESP3));
+       xjhprintk("SDMMC_MINTSTS:\t0x%x\n",readl(host->regs + SDMMC_MINTSTS));
+       xjhprintk("SDMMC_RINTSTS:\t0x%x\n",readl(host->regs + SDMMC_RINTSTS));
+       xjhprintk("SDMMC_STATUS:\t0x%x\n",readl(host->regs + SDMMC_STATUS));
+       xjhprintk("SDMMC_FIFOTH:\t0x%x\n",readl(host->regs + SDMMC_FIFOTH));
+       xjhprintk("SDMMC_CDETECT:\t0x%x\n",readl(host->regs + SDMMC_CDETECT));
+       xjhprintk("SDMMC_WRTPRT:\t0x%x\n",readl(host->regs + SDMMC_WRTPRT));
+       xjhprintk("SDMMC_TCBCNT:\t0x%x\n",readl(host->regs + SDMMC_TCBCNT));
+       xjhprintk("SDMMC_TBBCNT:\t0x%x\n",readl(host->regs + SDMMC_TBBCNT));
+       xjhprintk("SDMMC_DEBNCE:\t0x%x\n",readl(host->regs + SDMMC_DEBNCE));
+       xjhprintk("-------- Host states-----------------\n");
+       xjhprintk("host->state:\t0x%x\n",host->state);
+       xjhprintk("host->pending_events:\t0x%x\n",host->pending_events);
+       xjhprintk("host->cmd_status:\t0x%x\n",host->cmd_status);
+       xjhprintk("host->data_status:\t0x%x\n",host->data_status);
+       xjhprintk("host->stop_cmdr:\t0x%x\n",host->stop_cmdr);
+       xjhprintk("host->dir_status:\t0x%x\n",host->dir_status);
+       xjhprintk("host->completed_events:\t0x%x\n",host->completed_events);
+       xjhprintk("host->dma_chn:\t0x%x\n",host->dma_chn);
+       xjhprintk("host->use_dma:\t0x%x\n",host->use_dma);
+       xjhprintk("host->no_detect:\t0x%x\n",host->no_detect);
+       xjhprintk("host->bus_hz:\t0x%x\n",host->bus_hz);
+       xjhprintk("host->current_speed:\t0x%x\n",host->current_speed);
+       xjhprintk("host->ctype:\t0x%x\n",host->ctype);
+       xjhprintk("host->clock:\t0x%x\n",host->clock);
+       xjhprintk("host->flags:\t0x%x\n",host->flags);
+       xjhprintk("host->irq:\t0x%x\n",host->irq);
+       xjhprintk("-------- rk2818 CPU register-----------------\n");
+       __asm__ volatile ("mrs  %0, cpsr                @ local_irq_save\n":"=r" (cpsr_tmp)::"memory", "cc" );
+       xjhprintk("cpsr:\t0x%x\n",cpsr_tmp);
+                       
+
+
+}
+
 static void rk2818_sdmmc_set_power(struct rk2818_sdmmc_host *host, u32 ocr_avail)
 {
        if(ocr_avail == 0)
@@ -283,6 +353,8 @@ static u32 rk2818_sdmmc_prepare_command(struct mmc_host *mmc,
 
        if(cmdr == 12) 
                cmdr |= SDMMC_CMD_STOP;
+       else if(cmdr == 13) 
+               cmdr &= ~SDMMC_CMD_PRV_DAT_WAIT;
        else 
                cmdr |= SDMMC_CMD_PRV_DAT_WAIT;
 
@@ -311,24 +383,111 @@ static u32 rk2818_sdmmc_prepare_command(struct mmc_host *mmc,
 static void rk2818_sdmmc_start_command(struct rk2818_sdmmc_host *host,
                struct mmc_command *cmd, u32 cmd_flags)
 {
-       int tmo = 50;
+       int tmo = 5000;
+       unsigned long flags;
+       int retry = 4;
        host->cmd = cmd;
        dev_dbg(host->dev, "start cmd:%d ARGR=0x%08x CMDR=0x%08x\n",
                                        cmd->opcode, cmd->arg, cmd_flags);
+       local_irq_save(flags);
        writel(cmd->arg, host->regs + SDMMC_CMDARG); // write to CMDARG register
        writel(cmd_flags | SDMMC_CMD_START, host->regs + SDMMC_CMD); // write to CMD register
+       local_irq_restore(flags);
 
        /* wait until CIU accepts the command */
        while (--tmo && (readl(host->regs + SDMMC_CMD) & SDMMC_CMD_START)) 
                cpu_relax();
+       if(!tmo) {
+               tmo = 5000;
+               xjhprintk("%s start cmd %d error. retry again!!!\n",__FUNCTION__ ,cmd->opcode);
+               rk2818_show_regs(host);
+               rk2818_sdmmc_set_completed(host, EVENT_CMD_COMPLETE);
+               host->cmd_status |= SDMMC_INT_RE;
+               tasklet_schedule(&host->tasklet);
+               retry --;
+       //      if(retry)
+       //              goto START_CMD;
+       }
+       #if 0
+       tmo = 60;
+       host->cmd_tmo = 0;
+       while(--tmo && !host->cmd_tmo)
+       {
+               mdelay(5);
+               //cpu_relax();
+
+       }
+       if(!tmo)
+       {
+               xjhprintk("cmd %d response time out(not receive INT)\n",cmd->opcode);
+               rk2818_sdmmc_set_completed(host, EVENT_CMD_COMPLETE);
+               host->cmd_status |= SDMMC_INT_RE;
+               tasklet_schedule(&host->tasklet);
+       }
+       #endif
 }
 
 static void send_stop_cmd(struct rk2818_sdmmc_host *host, struct mmc_data *data)
 {
+       unsigned long flags;
+       unsigned long fifo_left;
+       /*µÈ´ýÇ°Ãæ´«Êä´¦ÀíÍê³É*/
+       int time_out =60;
+       while(readl(host->regs + SDMMC_STATUS) & (SDMMC_STAUTS_DATA_BUSY)) {
+               mdelay(5);
+               time_out --;
+               
+               if(!time_out){
+                       time_out =60;
+                       xjhprintk("card busy now,can not issuse req! \nreset DMA and FIFO\n");
+                        local_irq_save(flags);
+                       
+               //      writel(readl(host->regs + SDMMC_CTRL) | ( SDMMC_CTRL_DMA_RESET )  & ~SDMMC_CTRL_DMA_ENABLE, host->regs + SDMMC_CTRL);
+                       /* wait till resets clear */
+               //      while (readl(host->regs + SDMMC_CTRL) & ( SDMMC_CTRL_DMA_RESET));
+                       
+                       writel(readl(host->regs + SDMMC_CTRL) | ( SDMMC_CTRL_FIFO_RESET ), host->regs + SDMMC_CTRL);
+                        /* wait till resets clear */
+                       while (readl(host->regs + SDMMC_CTRL) & ( SDMMC_CTRL_FIFO_RESET));
+                        local_irq_restore(flags);
+               }
+               //cpu_relax();
+       }
+       
+       #if 1
+
+       fifo_left = readl(host->regs + SDMMC_STATUS);
+
+       if((fifo_left & SDMMC_STAUTS_FIFO_FULL) && (fifo_left & SDMMC_STAUTS_FIFO_RX_WATERMARK))
+       {
+               xjhprintk("%s read operation reach water mark\n",__FUNCTION__);
+               rk2818_show_regs(host);
+               while(SDMMC_GET_FCNT(readl(host->regs + SDMMC_STATUS))>>2)
+                       readl(host->regs + SDMMC_DATA);         //discard the no use data
+
+               rk2818_show_regs(host);
+               
+       }
+       #endif
+       /*¼ì²éFIFO,Èç¹û²»Îª¿Õ£¬Çå¿Õ*/
+       if(!(readl(host->regs + SDMMC_STATUS) & SDMMC_STAUTS_FIFO_EMPTY)) {
+               xjhprintk("%s: FIFO not empty, clear it\n",__FUNCTION__);
+               rk2818_show_regs(host);
+                local_irq_save(flags);
+       //      writel(readl(host->regs + SDMMC_CTRL) | ( SDMMC_CTRL_DMA_RESET ), host->regs + SDMMC_CTRL);
+               /* wait till resets clear */
+       //      while (readl(host->regs + SDMMC_CTRL) & ( SDMMC_CTRL_DMA_RESET));
+                         
+               writel(readl(host->regs + SDMMC_CTRL) | ( SDMMC_CTRL_FIFO_RESET ), host->regs + SDMMC_CTRL);
+                /* wait till resets clear */
+               while (readl(host->regs + SDMMC_CTRL) & ( SDMMC_CTRL_FIFO_RESET));
+                local_irq_restore(flags);
+               //cpu_relax();
+       }
+
        rk2818_sdmmc_start_command(host, data->stop, host->stop_cmdr);
 }
 
-
 static void rk2818_sdmmc_dma_cleanup(struct rk2818_sdmmc_host *host)
 {
        struct mmc_data                 *data = host->data;
@@ -340,12 +499,15 @@ static void rk2818_sdmmc_dma_cleanup(struct rk2818_sdmmc_host *host)
 static void rk2818_sdmmc_stop_dma(struct rk2818_sdmmc_host *host)
 {
        if (host->dma_chn >= 0) {
+               xjhprintk("[xjh] %s enter host->state %d\n", __FUNCTION__, host->state);
                writel(readl(host->regs + SDMMC_CTRL) & ~SDMMC_CTRL_DMA_ENABLE,
                                host->regs +SDMMC_CTRL);
                //disable_dma(host->dma_chn);
                free_dma(host->dma_chn);
                host->dma_chn = -1;
                rk2818_sdmmc_dma_cleanup(host);
+               rk2818_sdmmc_set_pending(host, EVENT_XFER_COMPLETE);//[xjh]  Èç¹ûÊý¾Ý¶Áд¹ý³Ì±»°Îµô£¬ÐèÒªÉèÖÃÕâ¸ö״̬
+               xjhprintk("[xjh] %s exit\n", __FUNCTION__);
        } else {
                /* Data transfer was stopped by the interrupt handler */
                rk2818_sdmmc_set_pending(host, EVENT_XFER_COMPLETE);
@@ -361,11 +523,15 @@ static void rk2818_sdmmc_dma_complete(int chn, void *arg)
        dev_dbg(host->dev, "DMA complete\n");
 
        spin_lock(&host->lock);
+       //disable dma
+       writel(readl(host->regs + SDMMC_CTRL) & ~SDMMC_CTRL_DMA_ENABLE,
+                               host->regs +SDMMC_CTRL);
        rk2818_sdmmc_dma_cleanup(host);
        //disable_dma(host->dma_chn);
        free_dma(host->dma_chn);
        host->dma_chn = -1;
        if (data) {
+               
                rk2818_sdmmc_set_pending(host, EVENT_XFER_COMPLETE);
                tasklet_schedule(&host->tasklet);
        }
@@ -431,13 +597,38 @@ static void rk2818_sdmmc_submit_data(struct rk2818_sdmmc_host *host, struct mmc_
                                host->regs +SDMMC_CTRL);
        }
 }
-
+#if 0
 #define mci_send_cmd(host,cmd,arg) {   \
     writel(arg, host->regs + SDMMC_CMDARG);            \
     writel(SDMMC_CMD_START | cmd, host->regs + SDMMC_CMD);             \
     while (readl(host->regs + SDMMC_CMD) & SDMMC_CMD_START); \
 }
+#else
+static void mci_send_cmd(struct rk2818_sdmmc_host *host,unsigned int cmd,int arg) 
+{
+       int tmo = 5000;
+       int retry = 4;
+
+    writel(arg, host->regs + SDMMC_CMDARG);            
+    writel(SDMMC_CMD_START | cmd, host->regs + SDMMC_CMD);             
+       while (--tmo && readl(host->regs + SDMMC_CMD) & SDMMC_CMD_START); 
+       if(!tmo) {
+               tmo = 5000;
+               xjhprintk("%s set register error. retry again!!!\n",__FUNCTION__);
+               retry --;
+       //      if(retry)
+       //              goto START_CMD;
+       }
+}
+
+#endif
 
+#if 1
+void inline rk2818_sdmmc_setup_bus(struct rk2818_sdmmc_host *host)
+{
+       ;
+}
+#else
 void rk2818_sdmmc_setup_bus(struct rk2818_sdmmc_host *host)
 {
        u32 div;
@@ -447,6 +638,8 @@ void rk2818_sdmmc_setup_bus(struct rk2818_sdmmc_host *host)
 
                dev_dbg(host->dev, "Bus speed = %dHz div:%d (actual %dHz)\n",
                        host->clock, div, (host->bus_hz / div) >> 1);
+               xjhprintk("Bus speed = %dHz div:%d (actual %dHz)\n",
+                       host->clock, div, (host->bus_hz / div) >> 1);
                
                /* store the actual clock for calculations */
                host->clock = (host->bus_hz / div) >> 1;
@@ -470,6 +663,8 @@ void rk2818_sdmmc_setup_bus(struct rk2818_sdmmc_host *host)
        /* Set the current host bus width */
        writel(host->ctype, host->regs + SDMMC_CTYPE);
 }
+#endif
+
 
 static void rk2818_sdmmc_start_request(struct rk2818_sdmmc_host *host)
 {
@@ -477,10 +672,50 @@ static void rk2818_sdmmc_start_request(struct rk2818_sdmmc_host *host)
        struct mmc_command      *cmd;
        struct mmc_data         *data;
        u32                     cmdflags;
+       unsigned long flags;
+
+       int time_out =60;
 
        mrq = host->mrq;
 
-       rk2818_sdmmc_setup_bus(host);
+       //rk2818_sdmmc_setup_bus(host);
+
+       /*µÈ´ýÇ°Ãæ´«Êä´¦ÀíÍê³É*/
+       while(readl(host->regs + SDMMC_STATUS) & (SDMMC_STAUTS_DATA_BUSY)) {
+               mdelay(5);
+               time_out --;
+               
+               if(!time_out){
+                       time_out =60;
+                       xjhprintk("card busy now,can not issuse req! \nreset DMA and FIFO\n");
+                        local_irq_save(flags);
+                       
+               //      writel(readl(host->regs + SDMMC_CTRL) | ( SDMMC_CTRL_DMA_RESET )  & ~SDMMC_CTRL_DMA_ENABLE, host->regs + SDMMC_CTRL);
+                       /* wait till resets clear */
+               //      while (readl(host->regs + SDMMC_CTRL) & ( SDMMC_CTRL_DMA_RESET));
+                                 
+                       writel(readl(host->regs + SDMMC_CTRL) | ( SDMMC_CTRL_FIFO_RESET ), host->regs + SDMMC_CTRL);
+                        /* wait till resets clear */
+                       while (readl(host->regs + SDMMC_CTRL) & ( SDMMC_CTRL_FIFO_RESET));
+                        local_irq_restore(flags);
+               }
+               //cpu_relax();
+       }
+       /*¼ì²éFIFO,Èç¹û²»Îª¿Õ£¬Çå¿Õ*/
+       if(!(readl(host->regs + SDMMC_STATUS) & SDMMC_STAUTS_FIFO_EMPTY)) {
+               xjhprintk("%s: FIFO not empty, clear it\n",__FUNCTION__);
+               rk2818_show_regs(host);
+                local_irq_save(flags);
+       //      writel(readl(host->regs + SDMMC_CTRL) | ( SDMMC_CTRL_DMA_RESET ), host->regs + SDMMC_CTRL);
+               /* wait till resets clear */
+       //      while (readl(host->regs + SDMMC_CTRL) & ( SDMMC_CTRL_DMA_RESET));
+                         
+               writel(readl(host->regs + SDMMC_CTRL) | ( SDMMC_CTRL_FIFO_RESET ), host->regs + SDMMC_CTRL);
+                /* wait till resets clear */
+               while (readl(host->regs + SDMMC_CTRL) & ( SDMMC_CTRL_FIFO_RESET));
+                local_irq_restore(flags);
+               //cpu_relax();
+       }
 
        host->mrq = mrq;
 
@@ -510,6 +745,7 @@ static void rk2818_sdmmc_start_request(struct rk2818_sdmmc_host *host)
                host->stop_cmdr = rk2818_sdmmc_prepare_command(host->mmc, mrq->stop);
                dev_dbg(host->dev, "mrq stop: stop_cmdr = %d", host->stop_cmdr);
        }
+
 }
 
 
@@ -536,12 +772,13 @@ static void rk2818_sdmmc_request(struct mmc_host *mmc, struct mmc_request *mrq)
        struct rk2818_sdmmc_host        *host = mmc_priv(mmc);
 
        WARN_ON(host->mrq);
-
+       #if 0
        if (!test_bit(RK2818_MMC_CARD_PRESENT, &host->flags)) {
                mrq->cmd->error = -ENOMEDIUM;
                mmc_request_done(mmc, mrq);
                return;
        }
+       #endif
 
        rk2818_sdmmc_queue_request(host, mrq);
 }
@@ -549,6 +786,11 @@ static void rk2818_sdmmc_request(struct mmc_host *mmc, struct mmc_request *mrq)
 static void rk2818_sdmmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
 {
        struct rk2818_sdmmc_host        *host = mmc_priv(mmc);
+       u32 div;
+       unsigned long flags;
+       
+       xjhprintk("%s bus_width %x ios->clock %x host->clock %x ocr %x\n",
+                       __FUNCTION__,ios->bus_width, ios->clock, host->clock, host->mmc->ocr_avail);
 
        host->ctype = 0; // set default 1 bit mode
        switch (ios->bus_width) {
@@ -559,33 +801,77 @@ static void rk2818_sdmmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
                host->ctype = SDMMC_CTYPE_4BIT;
                break;
        }
+
+       spin_lock_irqsave(host->lock,flags);
+       /* Set the current host bus width */
+       writel(host->ctype, host->regs + SDMMC_CTYPE);
+
        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);
+       spin_unlock_irqrestore(host->lock,flags);
 
-       if (ios->clock) {
-               spin_lock(&host->lock);
+       if (ios->clock && (host->current_speed != ios->clock)) {
                /*
                 * Use mirror of ios->clock to prevent race with mmc
                 * core ios update when finding the minimum.
                 */
-               host->clock = ios->clock;
+               div  = (((host->bus_hz + (host->bus_hz / 5)) / ios->clock)) >> 1;
+               xjhprintk("Bus speed = %dHz div:%d (actual %dHz)\n",
+                       host->clock, div, (host->bus_hz / div) >> 1);
+               
+               /* store the actual clock for calculations */
+               host->clock = (host->bus_hz / div) >> 1;
+               /*µÈ´ý¿¨Æ¬´«ÊäÍê³É*/
+               while(readl(host->regs + SDMMC_STATUS) & (SDMMC_STAUTS_MC_BUSY | SDMMC_STAUTS_DATA_BUSY)){
+                       udelay(10);
+                       xjhprintk("SD/MMC busy now(status 0x%x),can not change clock\n",readl(host->regs + SDMMC_STATUS));
+                       //cpu_relax();
+               }
+               spin_lock_irqsave(host->lock,flags);
+               /* disable clock */
+               writel(0, host->regs + SDMMC_CLKENA);
+               writel(0, host->regs + SDMMC_CLKSRC);
+               /* inform CIU */
+               mci_send_cmd(host, SDMMC_CMD_UPD_CLK | SDMMC_CMD_PRV_DAT_WAIT, 0);
+               /* set clock to desired speed */
+               writel(div, host->regs + SDMMC_CLKDIV);
+               /* inform CIU */
+               mci_send_cmd(host, SDMMC_CMD_UPD_CLK | SDMMC_CMD_PRV_DAT_WAIT, 0);
+               /* enable clock */
+               if(host->pdev->id == 0) //sdmmc0 endable low power mode
+                       writel(SDMMC_CLKEN_LOW_PWR | SDMMC_CLKEN_ENABLE, host->regs + SDMMC_CLKENA);
+               else
+                       writel(SDMMC_CLKEN_ENABLE, host->regs + SDMMC_CLKENA);
+               /* inform CIU */
+                mci_send_cmd(host, SDMMC_CMD_UPD_CLK | SDMMC_CMD_PRV_DAT_WAIT, 0);
 
-               spin_unlock(&host->lock);
-       } else {
+               host->current_speed= ios->clock; 
+               
+               spin_unlock_irqrestore(host->lock,flags);
+
+       } 
+       #if 0
+       else {
                spin_lock(&host->lock);
                host->clock = 0;
                spin_unlock(&host->lock);
        }
+       #endif
+       spin_lock_irqsave(host->lock,flags);
 
        switch (ios->power_mode) {
        case MMC_POWER_UP:
                set_bit(RK2818_MMC_CARD_NEED_INIT, &host->flags);
+               rk2818_sdmmc_set_power(host, host->mmc->ocr_avail);
                break;
        default:
+               //rk2818_sdmmc_set_power(host, 0);
                break;
        }
+       spin_unlock_irqrestore(host->lock,flags);
+       
 }
 
 
@@ -641,10 +927,65 @@ static void rk2818_sdmmc_request_end(struct rk2818_sdmmc_host *host, struct mmc_
        __acquires(&host->lock)
 {
        struct mmc_host         *prev_mmc = host->mmc;
-
+       unsigned long flags;
+       int time_out =60;
+       unsigned long fifo_left;
+       
        WARN_ON(host->cmd || host->data);
        host->mrq = NULL;
 
+       
+       /*µÈ´ýÇ°Ãæ´«Êä´¦ÀíÍê³É*/
+       while(readl(host->regs + SDMMC_STATUS) & (SDMMC_STAUTS_DATA_BUSY)) {
+               mdelay(5);
+               time_out --;
+               
+               if(!time_out){
+                       time_out =60;
+                       xjhprintk("req done:card busy for a long time!!!reset DMA and FIFO\n");
+                        local_irq_save(flags);
+                       
+       //              writel(readl(host->regs + SDMMC_CTRL) | ( SDMMC_CTRL_DMA_RESET )  & ~SDMMC_CTRL_DMA_ENABLE, host->regs + SDMMC_CTRL);
+                       /* wait till resets clear */
+       //              while (readl(host->regs + SDMMC_CTRL) & ( SDMMC_CTRL_DMA_RESET));
+                       writel(readl(host->regs + SDMMC_CTRL) | ( SDMMC_CTRL_FIFO_RESET ), host->regs + SDMMC_CTRL);
+                        /* wait till resets clear */
+                       while (readl(host->regs + SDMMC_CTRL) & ( SDMMC_CTRL_FIFO_RESET));
+                        local_irq_restore(flags);
+               }
+               //cpu_relax();
+       }
+
+       #if 1
+       fifo_left = readl(host->regs + SDMMC_STATUS);
+
+       if((fifo_left & SDMMC_STAUTS_FIFO_FULL) && (fifo_left & SDMMC_STAUTS_FIFO_RX_WATERMARK))
+       {
+               xjhprintk("%s read operation reach water mark\n",__FUNCTION__);
+               rk2818_show_regs(host);
+               while(SDMMC_GET_FCNT(readl(host->regs + SDMMC_STATUS))>>2)
+                       readl(host->regs + SDMMC_DATA);         //discard the no use data
+               rk2818_show_regs(host);
+               
+       }
+       #endif
+       /*¼ì²éFIFO,Èç¹û²»Îª¿Õ£¬Çå¿Õ*/
+       if(!(readl(host->regs + SDMMC_STATUS) & SDMMC_STAUTS_FIFO_EMPTY)) {
+               xjhprintk("%s: FIFO not empty, clear it\n",__FUNCTION__);
+               rk2818_show_regs(host);
+                local_irq_save(flags);
+       //      writel(readl(host->regs + SDMMC_CTRL) | ( SDMMC_CTRL_DMA_RESET ), host->regs + SDMMC_CTRL);
+               /* wait till resets clear */
+       //      while (readl(host->regs + SDMMC_CTRL) & ( SDMMC_CTRL_DMA_RESET));
+                 
+               writel(readl(host->regs + SDMMC_CTRL) | ( SDMMC_CTRL_FIFO_RESET ), host->regs + SDMMC_CTRL);
+                /* wait till resets clear */
+               while (readl(host->regs + SDMMC_CTRL) & ( SDMMC_CTRL_FIFO_RESET));
+                local_irq_restore(flags);
+               //cpu_relax();
+       }
+
        if (!list_empty(&host->queue)) {
                host = list_entry(host->queue.next,
                                struct rk2818_sdmmc_host, queue_node);
@@ -693,6 +1034,8 @@ static void rk2818_sdmmc_command_complete(struct rk2818_sdmmc_host *host,
                cmd->error = -EILSEQ;
        else if (status & SDMMC_INT_RE)
                cmd->error = -EIO;
+       else if(status & SDMMC_INT_HLE)
+               cmd->error = -EIO;
        else
                cmd->error = 0;
 
@@ -702,6 +1045,7 @@ static void rk2818_sdmmc_command_complete(struct rk2818_sdmmc_host *host,
                        "cmd=0x%08x arg=0x%08x flg=0x%08x err=%d\n", 
                        status, cmd->resp[0], 
                        cmd->opcode, cmd->arg, cmd->flags, cmd->error);
+               
 
                if (cmd->data) {
                        host->data = NULL;
@@ -715,16 +1059,22 @@ static void rk2818_sdmmc_tasklet_func(unsigned long priv)
        struct rk2818_sdmmc_host        *host = (struct rk2818_sdmmc_host *)priv;
        struct mmc_request      *mrq = host->mrq;
        struct mmc_data         *data = host->data;
-       struct mmc_command      *cmd = host->cmd;
        enum rk2818_sdmmc_state state = host->state;
        enum rk2818_sdmmc_state prev_state;
        u32                     status;
+       int timeout=5000;
 
        spin_lock(&host->lock);
 
        state = host->state;
        do {
                prev_state = state;
+               timeout --;
+               if(!timeout)
+               {
+                       timeout = 5000;
+                       xjhprintk("%s\n",__FUNCTION__);
+               }
 
                switch (state) {
                case STATE_IDLE:
@@ -738,7 +1088,8 @@ static void rk2818_sdmmc_tasklet_func(unsigned long priv)
                        host->cmd = NULL;
                        rk2818_sdmmc_set_completed(host, EVENT_CMD_COMPLETE);
                        rk2818_sdmmc_command_complete(host, mrq->cmd);
-                       if (!mrq->data || cmd->error) {
+                       //if (!mrq->data || cmd->error) {
+                       if (!mrq->data || mrq->cmd->error) {
                                rk2818_sdmmc_request_end(host, host->mrq);
                                goto unlock;
                        }
@@ -749,10 +1100,29 @@ static void rk2818_sdmmc_tasklet_func(unsigned long priv)
                case STATE_SENDING_DATA:
                        if (rk2818_sdmmc_test_and_clear_pending(host,
                                                EVENT_DATA_ERROR)) {
+                               xjhprintk("[xjh] %s data->stop %p\n", __FUNCTION__,data->stop);
                                rk2818_sdmmc_stop_dma(host);
+                               #if 0
                                if (data->stop)
                                        send_stop_cmd(host, data);
+                               #else
+                               if (data->stop)
+                                       send_stop_cmd(host, data);
+                               else //cmd17 or cmd24
+                               {
+                                       xjhprintk("%s>> send stop command mannualy\n",__FUNCTION__);
+                                       host->stop_mannual.opcode = MMC_STOP_TRANSMISSION;
+                                       host->stop_mannual.arg = 0;
+                                       host->stop_mannual.flags = MMC_RSP_SPI_R1B | MMC_RSP_R1B | MMC_CMD_AC;
+                                       host->stop_cmdr = 0x414c;
+
+                                       host->mrq->stop = &host->stop_mannual;
+                                       data->stop = &host->stop_mannual;
+                                       send_stop_cmd(host, data);
+                               }
+                               #endif
                                state = STATE_DATA_ERROR;
+                               xjhprintk("[xjh] %s sendging data error\n", __FUNCTION__);
                                break;
                        }
 
@@ -773,6 +1143,7 @@ static void rk2818_sdmmc_tasklet_func(unsigned long priv)
                        status = host->data_status;
 
                        if (unlikely(status & RK2818_MCI_DATA_ERROR_FLAGS)) {
+                               xjhprintk("[xjh] %s data error\n", __FUNCTION__);
                                if (status & SDMMC_INT_DRTO) {
                                        dev_err(host->dev,
                                                        "data timeout error\n");
@@ -807,7 +1178,8 @@ static void rk2818_sdmmc_tasklet_func(unsigned long priv)
                        if (!rk2818_sdmmc_test_and_clear_pending(host,
                                                EVENT_CMD_COMPLETE))
                                break;
-
+                       
+                       //xjhprintk("[xjh] %s sending stop cmd end\n", __FUNCTION__);
                        host->cmd = NULL;
                        rk2818_sdmmc_command_complete(host, mrq->stop);
                        rk2818_sdmmc_request_end(host, host->mrq);
@@ -816,7 +1188,16 @@ static void rk2818_sdmmc_tasklet_func(unsigned long priv)
                        if (!rk2818_sdmmc_test_and_clear_pending(host,
                                                EVENT_XFER_COMPLETE))
                                break;
-
+                       #if 0
+                       //[xjh]  cmd17ûÓвúÉúDTOÖжϣ¬EVENT_DATA_COMPLETEûÓб»ÉèÖã¬ÐèÒªÊÖ¹¤ÉèÖÃ
+                       //ΪºÎcmd17³ö´íºó²»ÄܲúÉúDTOÖжϣ¬ÐèÒª½øÒ»²½²éÃ÷???????
+                       if((host->mrq->cmd->opcode == 17)) {
+                               xjhprintk("%s cmd%d was interrupt(host->pending_events %x)\n",
+                                               __FUNCTION__,host->mrq->cmd->opcode,host->pending_events);
+                       //      rk2818_sdmmc_set_pending(host, EVENT_DATA_COMPLETE);
+                       }
+                       #endif
+                       
                        state = STATE_DATA_BUSY;
                        break;
                }
@@ -872,6 +1253,7 @@ static void rk2818_sdmmc_read_data_pio(struct rk2818_sdmmc_host *host)
        struct mmc_data         *data = host->data;
        u32                     status;
        unsigned int            nbytes = 0,len,old_len,count =0;
+       xjhprintk("[xjh] %s enter,sg->length 0x%x\n", __FUNCTION__, sg->length);
 
        do {
                len = SDMMC_GET_FCNT(readl(host->regs + SDMMC_STATUS)) << 2;
@@ -921,12 +1303,14 @@ static void rk2818_sdmmc_read_data_pio(struct rk2818_sdmmc_host *host)
        len = SDMMC_GET_FCNT(readl(host->regs + SDMMC_STATUS));
        host->pio_offset = offset;
        data->bytes_xfered += nbytes;
+       xjhprintk("[xjh] %s exit-1\n", __FUNCTION__);
        return;
 
 done:
        data->bytes_xfered += nbytes;
        smp_wmb();
        rk2818_sdmmc_set_pending(host, EVENT_XFER_COMPLETE);
+       xjhprintk("[xjh] %s exit-2\n", __FUNCTION__);
 }
 
 static void rk2818_sdmmc_write_data_pio(struct rk2818_sdmmc_host *host)
@@ -1008,6 +1392,8 @@ static irqreturn_t rk2818_sdmmc_interrupt(int irq, void *data)
        struct rk2818_sdmmc_host        *host = data;
        u32                     status,  pending;
        unsigned int            pass_count = 0;
+       bool present;
+       bool present_old;
        
        spin_lock(&host->lock);
        do {
@@ -1016,16 +1402,49 @@ static irqreturn_t rk2818_sdmmc_interrupt(int irq, void *data)
                if (!pending)
                        break;
                if(pending & SDMMC_INT_CD) {
-                       disable_irq_nosync(irq);
                    writel(SDMMC_INT_CD, host->regs + SDMMC_RINTSTS);  // clear interrupt
-                       mod_timer(&host->detect_timer, jiffies + msecs_to_jiffies(20));
+       
+                       present = rk2818_sdmmc_get_cd(host->mmc);
+                       present_old = test_bit(RK2818_MMC_CARD_PRESENT, &host->flags);
+                       if(present != present_old) {
+                               
+                               if (present != 0) {
+                                       set_bit(RK2818_MMC_CARD_PRESENT, &host->flags);
+                               } else {
+                                       clear_bit(RK2818_MMC_CARD_PRESENT, &host->flags);
+                               }                       
+
+                               if(host->pdev->id ==0) {        //sdmmc0        
+                                       xjhprintk("[xjh] %s >> %s >> %d sd/mmc insert/remove occur: Removal %d present %d present_old %d\n",
+                                                       __FILE__, __FUNCTION__,__LINE__,sdmmc0_disable_Irq_ForRemoval,present,present_old);
+                                       if(0 == sdmmc0_disable_Irq_ForRemoval) {
+                                               mod_timer(&host->detect_timer, jiffies + msecs_to_jiffies(20));
+                                               if(!test_bit(RK2818_MMC_CARD_PRESENT, &host->flags))
+                                                       sdmmc0_disable_Irq_ForRemoval = 1;
+                                       }
+                                       else
+                                               mod_timer(&host->detect_timer, jiffies + msecs_to_jiffies(RK28_SDMMC0_SWITCH_POLL_DELAY));
+                               } else {        //sdio
+                                               mod_timer(&host->detect_timer, jiffies + msecs_to_jiffies(20));
+                               }
+                       }
                }
+               
                if(pending & RK2818_MCI_CMD_ERROR_FLAGS) {
                    writel(RK2818_MCI_CMD_ERROR_FLAGS, host->regs + SDMMC_RINTSTS);  //  clear interrupt
+                   if(status & SDMMC_INT_HLE)
+                   {
+                           xjhprintk("[xjh] %s :cmd transfer error(int status 0x%x cmd %d host->state %d pending_events %d)\n", 
+                                       __FUNCTION__,status,host->cmd->opcode,host->state,host->pending_events);
+                       
+                   }
                    host->cmd_status = status;
                        smp_wmb();
                    rk2818_sdmmc_set_pending(host, EVENT_CMD_COMPLETE);
                    tasklet_schedule(&host->tasklet);
+                       host->cmd_tmo = 1;
+                       xjhprintk("[xjh] %s :cmd transfer error(int status 0x%x cmd %d host->state %d pending_events %d)\n", 
+                                       __FUNCTION__,status,host->cmd->opcode,host->state,host->pending_events);
                }
 
                if (pending & RK2818_MCI_DATA_ERROR_FLAGS) { // if there is an error, let report DATA_ERROR
@@ -1034,6 +1453,8 @@ static irqreturn_t rk2818_sdmmc_interrupt(int irq, void *data)
                        smp_wmb();
                        rk2818_sdmmc_set_pending(host, EVENT_DATA_ERROR);
                        tasklet_schedule(&host->tasklet);
+                       xjhprintk("[xjh] %s :data transfer error(int status 0x%x host->state %d pending_events %d)\n", 
+                                       __FUNCTION__,status,host->state,host->pending_events);
                }
 
 
@@ -1066,6 +1487,8 @@ static irqreturn_t rk2818_sdmmc_interrupt(int irq, void *data)
                if (pending & SDMMC_INT_CMD_DONE) {
                        writel(SDMMC_INT_CMD_DONE, host->regs + SDMMC_RINTSTS);  //  clear interrupt
                    rk2818_sdmmc_cmd_interrupt(host, status);
+                       host->cmd_tmo = 1;
+                       
                }
                if(pending & SDMMC_INT_SDIO) {
                        writel(SDMMC_INT_SDIO, host->regs + SDMMC_RINTSTS);
@@ -1074,6 +1497,7 @@ static irqreturn_t rk2818_sdmmc_interrupt(int irq, void *data)
        } while (pass_count++ < 5);
        
        spin_unlock(&host->lock);
+       
 
        //return IRQ_HANDLED;
        return pass_count ? IRQ_HANDLED : IRQ_NONE;
@@ -1082,74 +1506,201 @@ static irqreturn_t rk2818_sdmmc_interrupt(int irq, void *data)
 static void rk2818_sdmmc_detect_change(unsigned long host_data)
 {
        struct rk2818_sdmmc_host *host = (struct rk2818_sdmmc_host *) host_data;
-       struct mmc_request *mrq;
-       bool present;
-       bool present_old;
+       //bool present;
+       //bool present_old;
+       //unsigned long flags;
+       #if 0
+       mrq = host->mrq;
+       if (mrq) {
 
-       enable_irq(host->irq);
-       present = rk2818_sdmmc_get_cd(host->mmc);
-       present_old = test_bit(RK2818_MMC_CARD_PRESENT, &host->flags);
-       dev_dbg(host->dev, "detect change: %d (was %d)\n",
-                       present, present_old);
+               host->data = NULL;
+               host->cmd = NULL;
+               xjhprintk("[xjh] %s >> %s >> %d stage 2\n", __FILE__, __FUNCTION__,__LINE__);
 
-       if (present != present_old) {
+               switch (host->state) {
+               case STATE_IDLE:
+                       break;
+               case STATE_SENDING_CMD:
+                       mrq->cmd->error = -ENOMEDIUM;
+                       if (!mrq->data)
+                               break;
+                       /* fall through */
+               case STATE_SENDING_DATA:
+                       mrq->data->error = -ENOMEDIUM;
+                       xjhprintk("[xjh] %s host %p\n", __FUNCTION__,host);
+                       rk2818_sdmmc_stop_dma(host);
+                       break;
+               case STATE_DATA_BUSY:
+               case STATE_DATA_ERROR:
+                       if (mrq->data->error == -EINPROGRESS)
+                               mrq->data->error = -ENOMEDIUM;
+                       if (!mrq->stop)
+                               break;
+               case STATE_SENDING_STOP:
+                       mrq->stop->error = -ENOMEDIUM;
+                       break;
+               }
 
-               dev_dbg(host->dev, "card %s\n", present ? "inserted" : "removed");
+               rk2818_sdmmc_request_end(host, mrq);
+       }
+       #endif
+
+ // spin_lock( &sdmmc0_spinlock);
+//     xjhprintk("%s....%s....%d        **** timer open, then enable IRQ_OF_removal/insertion*****xbw****\n",__FUNCTION__,__FILE__,__LINE__);
+//     sdmmc0_disable_Irq_ForRemoval = 0; //´ò¿ªÖжϠ     
+//     spin_unlock( &sdmmc0_spinlock);            
+       
+       mmc_detect_change(host->mmc, 0);
+       
+}
 
-               spin_lock(&host->lock);
 
-               /* Power up host */
-               if (present != 0) {
-                       rk2818_sdmmc_set_power(host, host->mmc->ocr_avail);
+/*--------------------add communication interface with applications ---------------------------------*/
+int resetTimes = 0;//ͳ¼ÆÁ¬ÐøresetµÄ´ÎÊý¡£
+ssize_t sdmmc_reset_store(struct kobject *kobj, struct kobj_attribute *attr,
+                        const char *buf, size_t count)
+{
+       //»òÕß´Ókobj×·Ëݵ½rk2818_sdmmc_host£¬½ÓÏÂÀ´³¢ÊÔ
+    struct rk2818_sdmmc_host *host =  mmc0_host;  
+    struct mmc_host *mmc = host->mmc;
+    int currentTimes=0;
+       unsigned long flags;
+    
+    if( !strncmp(buf,"RemoveDone" , strlen("RemoveDone")) )
+    {
+        xjhprintk("%s------mmc receive the message of %s -----\n", __func__ , buf);
+       
+        local_irq_save(flags);
+        del_timer(&host->detect_timer);
+        sdmmc0_disable_Irq_ForRemoval = 0; //´ò¿ªÖжϠ     
+        local_irq_restore(flags);
+          
+       //Ö÷¶¯Ö´ÐÐÒ»´Î¼ì²â, ÈôÓп¨´æÔÚ
+       if(rk2818_sdmmc_get_cd(host->mmc)) {
+               //      mod_timer(&host->detect_timer, jiffies + msecs_to_jiffies(20));
                        set_bit(RK2818_MMC_CARD_PRESENT, &host->flags);
-               } else {
-                       rk2818_sdmmc_set_power(host, 0);
-                       clear_bit(RK2818_MMC_CARD_PRESENT, &host->flags);
-               }                       
+                   mmc_detect_change(mmc, 0);
+        }
+    }
+    else if( !strncmp(buf,"Removing" , strlen("Removing")) )
+    {        
+        xjhprintk("%s------mmc receive the message of %s -----\n", __func__ , buf);
 
+        //vold is removing, so modify the timer.
+        mod_timer(&host->detect_timer, jiffies +msecs_to_jiffies(RK28_SDMMC0_SWITCH_POLL_DELAY));        
+    }
+    else if( !strncmp(buf,"to_reset!" , strlen("to_reset!")) ) 
+    {       
+        xjhprintk("%s------mmc receive the message of %s -----\n", __func__ , buf);
+
+        //ÉèÖÃresetµÄÔÊÐí´ÎÊý
+        ++resetTimes;
+        currentTimes = resetTimes;
+        
+        //Á¬Ðøµ÷ÓÃreset³¬¹ý´ÎÊý£¬²»Ö´ÐС£        
+        if(currentTimes <= 3)
+        {          
+            xjhprintk("%s....%s....%d   **** Begin to call rk28_sdmmc_reset() Times=%d *****xbw****\n",__FUNCTION__,__FILE__,__LINE__, resetTimes);
+           // rk28_sdmmc_reset();
+        }
+    }
+    else if(!strncmp(buf,"mounted!" , strlen("mounted!")))
+    {        
+        xjhprintk("%s------mmc receive the message of %s -----\n", __func__ , buf);
+        resetTimes = 0;        
+    }
+       else if(!strncmp(buf,"dump_reg" , strlen("dump_reg")))
+       {
+               unsigned long cpsr_tmp;
+               xjhprintk("-------- SD/MMC/SDIO dump Registers-----------------\n");
+               xjhprintk("SDMMC_CTRL:\t0x%x\n",readl(host->regs + SDMMC_CTRL));
+               xjhprintk("SDMMC_PWREN:\t0x%x\n",readl(host->regs + SDMMC_PWREN));
+               xjhprintk("SDMMC_CLKDIV:\t0x%x\n",readl(host->regs + SDMMC_CLKDIV));
+               xjhprintk("SDMMC_CLKSRC:\t0x%x\n",readl(host->regs + SDMMC_CLKSRC));
+               xjhprintk("SDMMC_CLKENA:\t0x%x\n",readl(host->regs + SDMMC_CLKENA));
+               xjhprintk("SDMMC_TMOUT:\t0x%x\n",readl(host->regs + SDMMC_TMOUT));
+               xjhprintk("SDMMC_CTYPE:\t0x%x\n",readl(host->regs + SDMMC_CTYPE));
+               xjhprintk("SDMMC_BLKSIZ:\t0x%x\n",readl(host->regs + SDMMC_BLKSIZ));
+               xjhprintk("SDMMC_BYTCNT:\t0x%x\n",readl(host->regs + SDMMC_BYTCNT));
+               xjhprintk("SDMMC_INTMASK:\t0x%x\n",readl(host->regs + SDMMC_INTMASK));
+               xjhprintk("SDMMC_CMDARG:\t0x%x\n",readl(host->regs + SDMMC_CMDARG));
+               xjhprintk("SDMMC_CMD:\t0x%x\n",readl(host->regs + SDMMC_CMD));
+               xjhprintk("SDMMC_RESP0:\t0x%x\n",readl(host->regs + SDMMC_RESP0));
+               xjhprintk("SDMMC_RESP1:\t0x%x\n",readl(host->regs + SDMMC_RESP1));
+               xjhprintk("SDMMC_RESP2:\t0x%x\n",readl(host->regs + SDMMC_RESP2));
+               xjhprintk("SDMMC_RESP3:\t0x%x\n",readl(host->regs + SDMMC_RESP3));
+               xjhprintk("SDMMC_MINTSTS:\t0x%x\n",readl(host->regs + SDMMC_MINTSTS));
+               xjhprintk("SDMMC_RINTSTS:\t0x%x\n",readl(host->regs + SDMMC_RINTSTS));
+               xjhprintk("SDMMC_STATUS:\t0x%x\n",readl(host->regs + SDMMC_STATUS));
+               xjhprintk("SDMMC_FIFOTH:\t0x%x\n",readl(host->regs + SDMMC_FIFOTH));
+               xjhprintk("SDMMC_CDETECT:\t0x%x\n",readl(host->regs + SDMMC_CDETECT));
+               xjhprintk("SDMMC_WRTPRT:\t0x%x\n",readl(host->regs + SDMMC_WRTPRT));
+               xjhprintk("SDMMC_TCBCNT:\t0x%x\n",readl(host->regs + SDMMC_TCBCNT));
+               xjhprintk("SDMMC_TBBCNT:\t0x%x\n",readl(host->regs + SDMMC_TBBCNT));
+               xjhprintk("SDMMC_DEBNCE:\t0x%x\n",readl(host->regs + SDMMC_DEBNCE));
+               xjhprintk("-------- Host states-----------------\n");
+               xjhprintk("host->state:\t0x%x\n",host->state);
+               xjhprintk("host->pending_events:\t0x%x\n",host->pending_events);
+               xjhprintk("host->cmd_status:\t0x%x\n",host->cmd_status);
+               xjhprintk("host->data_status:\t0x%x\n",host->data_status);
+               xjhprintk("host->stop_cmdr:\t0x%x\n",host->stop_cmdr);
+               xjhprintk("host->dir_status:\t0x%x\n",host->dir_status);
+               xjhprintk("host->completed_events:\t0x%x\n",host->completed_events);
+               xjhprintk("host->dma_chn:\t0x%x\n",host->dma_chn);
+               xjhprintk("host->use_dma:\t0x%x\n",host->use_dma);
+               xjhprintk("host->no_detect:\t0x%x\n",host->no_detect);
+               xjhprintk("host->bus_hz:\t0x%x\n",host->bus_hz);
+               xjhprintk("host->current_speed:\t0x%x\n",host->current_speed);
+               xjhprintk("host->ctype:\t0x%x\n",host->ctype);
+               xjhprintk("host->clock:\t0x%x\n",host->clock);
+               xjhprintk("host->flags:\t0x%x\n",host->flags);
+               xjhprintk("host->irq:\t0x%x\n",host->irq);
+               xjhprintk("-------- rk2818 CPU register-----------------\n");
+               __asm__ volatile ("mrs  %0, cpsr                @ local_irq_save\n":"=r" (cpsr_tmp)::"memory", "cc"     );
+               xjhprintk("cpsr:\t0x%x\n",cpsr_tmp);
+               
 
-               mrq = host->mrq;
-               if (mrq) {
-                         writel((SDMMC_CTRL_RESET | SDMMC_CTRL_FIFO_RESET | SDMMC_CTRL_DMA_RESET| 
-                                               SDMMC_CTRL_INT_ENABLE), host->regs + SDMMC_CTRL);
-                        /* wait till resets clear */
-                         while (readl(host->regs + SDMMC_CTRL) & 
-                                       (SDMMC_CTRL_RESET | SDMMC_CTRL_FIFO_RESET | SDMMC_CTRL_DMA_RESET));
+       }
 
-                       host->data = NULL;
-                       host->cmd = NULL;
+    return count;
+}
 
-                       switch (host->state) {
-                       case STATE_IDLE:
-                               break;
-                       case STATE_SENDING_CMD:
-                               mrq->cmd->error = -ENOMEDIUM;
-                               if (!mrq->data)
-                                       break;
-                               /* fall through */
-                       case STATE_SENDING_DATA:
-                               mrq->data->error = -ENOMEDIUM;
-                               rk2818_sdmmc_stop_dma(host);
-                               break;
-                       case STATE_DATA_BUSY:
-                       case STATE_DATA_ERROR:
-                               if (mrq->data->error == -EINPROGRESS)
-                                       mrq->data->error = -ENOMEDIUM;
-                               if (!mrq->stop)
-                                       break;
-                       case STATE_SENDING_STOP:
-                               mrq->stop->error = -ENOMEDIUM;
-                               break;
-                       }
 
-                       rk2818_sdmmc_request_end(host, mrq);
-               }
 
-               spin_unlock(&host->lock);
-               mmc_detect_change(host->mmc, 0);
-       }
+struct kobj_attribute mmc_reset_attrs = 
+{
+        .attr = {
+                .name = "rescan",
+                .mode = 0777},
+        .show = NULL,
+        .store = sdmmc_reset_store,
+};
+struct attribute *mmc_attrs[] = 
+{
+        &mmc_reset_attrs.attr,
+        NULL
+};
+
+static struct kobj_type mmc_kset_ktype = {
+       .sysfs_ops      = &kobj_sysfs_ops,
+       .default_attrs = &mmc_attrs[0],
+};
+static int rk28_sdmmc0_add_attr( struct platform_device *pdev )
+{
+        int result;
+                struct kobject *parentkobject; 
+        struct kobject * me = kmalloc(sizeof(struct kobject) , GFP_KERNEL );
+        if( !me )
+                return -ENOMEM;
+        memset(me ,0,sizeof(struct kobject));
+        kobject_init( me , &mmc_kset_ktype );
+        //result = kobject_add( me , &pdev->dev.kobj , "%s", "RESET" );
+        parentkobject = &pdev->dev.kobj ;
+                result = kobject_add( me , parentkobject->parent->parent, "%s", "resetSdCard" );       
+        return result;
 }
 
+/*-------------------end of add communication interface with applications ---------------------------------*/
 
 static int rk2818_sdmmc_probe(struct platform_device *pdev)
 {
@@ -1276,37 +1827,49 @@ static int rk2818_sdmmc_probe(struct platform_device *pdev)
        mmc->max_seg_size = 4095 * 4;
 
        rk2818_sdmmc_set_power(host, 0);
+
+       /* Create card detect handler thread for the host */
+       setup_timer(&host->detect_timer, rk2818_sdmmc_detect_change,
+                       (unsigned long)host);
+
+       writel(0xFFFFFFFF, host->regs + SDMMC_RINTSTS);
+       writel(SDMMC_INT_CMD_DONE | SDMMC_INT_DTO | RK2818_MCI_ERROR_FLAGS | SDMMC_INT_CD,
+                       host->regs + SDMMC_INTMASK);
+       
        /* Assume card is present initially */
-       if(host->no_detect == 1 || rk2818_sdmmc_get_cd(host->mmc) != 0)
+       if(rk2818_sdmmc_get_cd(host->mmc) == 0 &&strncmp(host->dma_name, "sdio", strlen("sdio")) == 0)
+       {
+               dev_err(&pdev->dev, "failed to detect sdio.\n");
+               return 0;
+       }
+       else if(rk2818_sdmmc_get_cd(host->mmc) != 0)
                set_bit(RK2818_MMC_CARD_PRESENT, &host->flags);
        else
                clear_bit(RK2818_MMC_CARD_PRESENT, &host->flags);
+       
        ret = mmc_add_host(mmc);
        if(ret) 
        {
                dev_err(&pdev->dev, "failed to add mmc host.\n");
                goto err_free_irq;
        }
+       if (strncmp(host->dma_name, "sd_mmc", strlen("sd_mmc")) == 0) {
+               xjhprintk("[xjh] sdmmc0 add interface with application\n");
+               sdmmc0_disable_Irq_ForRemoval = 0; //´ò¿ªÖжÏ
+               mmc0_host = host;
+               rk28_sdmmc0_add_attr(pdev);
+       }
+       
 #if defined (CONFIG_DEBUG_FS)
        rk2818_sdmmc_init_debugfs(host);
 #endif
-       /* Create card detect handler thread for the host */
-       setup_timer(&host->detect_timer, rk2818_sdmmc_detect_change,
-                       (unsigned long)host);
-
-       writel(0xFFFFFFFF, host->regs + SDMMC_RINTSTS);
-       writel(SDMMC_INT_CMD_DONE | SDMMC_INT_DTO | SDMMC_INT_TXDR | 
-                       SDMMC_INT_RXDR | RK2818_MCI_ERROR_FLAGS | SDMMC_INT_CD,
-                       host->regs + SDMMC_INTMASK);
        writel(SDMMC_CTRL_INT_ENABLE, host->regs + SDMMC_CTRL); // enable mci interrupt
-
        dev_info(&pdev->dev, "RK2818 MMC controller used as %s, at irq %d\n", 
                                host->dma_name, host->irq);
-       if (strncmp(host->dma_name, "sdio", 4) == 0)
+       if (strncmp(host->dma_name, "sdio", strlen("sdio")) == 0)
                wifi_mmc_host = mmc;
 
        return 0;
-
 err_free_irq:
        free_irq(host->irq, host);
 err_free_clk:
index a6a3694214abee76fb4ef65c410918b54c7b0902..15a12f4a5d55a5bf78813d45058a5ea1575eeccc 100755 (executable)
 #define SDMMC_CMD_RESP_EXP      RK2818_BIT(6)
 #define SDMMC_CMD_INDX(n)       ((n) & 0x1F)
 /* Status register defines */
+#define SDMMC_STAUTS_RESP_INDEX        RK2818_BIT(11)
+#define SDMMC_STAUTS_MC_BUSY   RK2818_BIT(10)
+#define SDMMC_STAUTS_DATA_BUSY RK2818_BIT(9)
+#define SDMMC_STAUTS_CARD_PRESENT      RK2818_BIT(8)
+#define SDMMC_STAUTS_FIFO_FULL RK2818_BIT(3)
+#define SDMMC_STAUTS_FIFO_EMPTY        RK2818_BIT(2)
+#define SDMMC_STAUTS_FIFO_TX_WATERMARK RK2818_BIT(1)
+#define SDMMC_STAUTS_FIFO_RX_WATERMARK RK2818_BIT(0)
+
+
+
+
 #define SDMMC_GET_FCNT(x)       (((x)>>17) & 0x1FF)
 #define SDMMC_FIFO_SZ           32
 
 #define SDMMC_WRITE_PROTECT            RK2818_BIT(0)
 #define SDMMC_CARD_DETECT_N            RK2818_BIT(0)
+
+/* Specifies how often in millisecs to poll for card removal-insertion changes
+ * when the timer switch is open */
+#define RK28_SDMMC0_SWITCH_POLL_DELAY 3500
+
+
 #endif