From: lhh Date: Sat, 10 Jul 2010 10:09:10 +0000 (+0800) Subject: update sdmmc sdio X-Git-Tag: firefly_0821_release~11370 X-Git-Url: http://demsky.eecs.uci.edu/git/?a=commitdiff_plain;h=777ea0fbe3c42367a3caa971b8a06f7b696ffd98;p=firefly-linux-kernel-4.4.55.git update sdmmc sdio --- diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c index 8d2bd242ac63..a73fe94bb0d4 100644 --- a/drivers/mmc/card/block.c +++ b/drivers/mmc/card/block.c @@ -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; } diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c index bdb165f93046..602b150163ee 100644 --- a/drivers/mmc/core/bus.c +++ b/drivers/mmc/core/bus.c @@ -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); } diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index fb25fd001f4a..231439a961e2 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -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) { diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index 32af45c419f4..33747f583df8 100644 --- a/drivers/mmc/core/mmc.c +++ b/drivers/mmc/core/mmc.c @@ -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; diff --git a/drivers/mmc/host/rk2818-sdmmc.c b/drivers/mmc/host/rk2818-sdmmc.c index ae7c9307a1bf..e0086a42b3e3 100644 --- a/drivers/mmc/host/rk2818-sdmmc.c +++ b/drivers/mmc/host/rk2818-sdmmc.c @@ -29,6 +29,7 @@ #include #include #include +#include #include #include @@ -40,6 +41,11 @@ 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: diff --git a/drivers/mmc/host/rk2818-sdmmc.h b/drivers/mmc/host/rk2818-sdmmc.h index a6a3694214ab..15a12f4a5d55 100755 --- a/drivers/mmc/host/rk2818-sdmmc.h +++ b/drivers/mmc/host/rk2818-sdmmc.h @@ -106,9 +106,27 @@ #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