From c580ac7debd1907d9abaeb0b986f0b399126bbc4 Mon Sep 17 00:00:00 2001 From: lin tao Date: Mon, 16 Jun 2014 10:40:18 +0800 Subject: [PATCH] mmc: host: rk_sdmmc: Support physical level three transfer. --- drivers/mmc/core/sdio.c | 18 +- drivers/mmc/host/Kconfig | 9 + drivers/mmc/host/dw_mmc-rockchip.c | 8 +- drivers/mmc/host/rk_sdmmc.c | 496 ++++++++++++++++------------- include/linux/mmc/rk_mmc.h | 2 +- 5 files changed, 300 insertions(+), 233 deletions(-) mode change 100644 => 100755 drivers/mmc/core/sdio.c diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c old mode 100644 new mode 100755 index dc2178c6615b..9a9995f2c85e --- a/drivers/mmc/core/sdio.c +++ b/drivers/mmc/core/sdio.c @@ -673,6 +673,17 @@ try_again: * systems that claim 1.8v signalling in fact do not support * it. */ + + /* + * Fixme: ap6335 should not set S18A=1 if mmc I/F voltage + * has been 1.8v yet. + */ + #ifdef CONFIG_MMC_DW_ROCKCHIP_SWITCH_VOLTAGE + #ifdef CONFIG_AP6335 + rocr &= ~R4_18V_PRESENT; + #endif + #endif + if (!powered_resume && (rocr & ocr & R4_18V_PRESENT)) { err = mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180, ocr); @@ -688,7 +699,12 @@ try_again: } err = 0; } else { - ocr &= ~R4_18V_PRESENT; + #ifdef CONFIG_MMC_DW_ROCKCHIP_SWITCH_VOLTAGE + #ifdef CONFIG_AP6335 + #else + ocr &= ~R4_18V_PRESENT; + #endif + #endif } /* diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig index cae551376801..761e0808dcf0 100755 --- a/drivers/mmc/host/Kconfig +++ b/drivers/mmc/host/Kconfig @@ -556,6 +556,15 @@ config MMC_DW_ROCKCHIP Synopsys DesignWare Memory Card Interface driver. Select this option for platforms based on RK32XX SoC's. +config MMC_DW_ROCKCHIP_SWITCH_VOLTAGE + tristate "Supoort voltage switch for higher level standard" + depends on MMC_DW_ROCKCHIP + default n + help + This selects support for Rockchip RK32XX Soc specific extensions to voltage + switch squence + + config MMC_DW_EXYNOS tristate "Exynos specific extensions for Synopsys DW Memory Card Interface" depends on MMC_DW diff --git a/drivers/mmc/host/dw_mmc-rockchip.c b/drivers/mmc/host/dw_mmc-rockchip.c index 215936af1724..9982c2807d09 100755 --- a/drivers/mmc/host/dw_mmc-rockchip.c +++ b/drivers/mmc/host/dw_mmc-rockchip.c @@ -464,10 +464,12 @@ static int dw_mci_rockchip_execute_tuning(struct dw_mci_slot *slot, u32 opcode, goto done; #endif }else{ - MMC_DBG_ERR_FUNC(host->mmc, + MMC_DBG_ERR_FUNC(host->mmc, "execute tuning: candidates_degree beyong limited case! [%s]", - mmc_hostname(host->mmc)); - BUG(); + mmc_hostname(host->mmc)); + if(host->mmc->restrict_caps & RESTRICT_CARD_TYPE_EMMC) + BUG(); + return -EAGAIN; } delayline: diff --git a/drivers/mmc/host/rk_sdmmc.c b/drivers/mmc/host/rk_sdmmc.c index fedd50d61a2a..a377af381310 100755 --- a/drivers/mmc/host/rk_sdmmc.c +++ b/drivers/mmc/host/rk_sdmmc.c @@ -67,11 +67,12 @@ #define DW_MCI_FREQ_MAX 50000000//200000000 /* unit: HZ */ #define DW_MCI_FREQ_MIN 300000//400000 /* unit: HZ */ -#define SDMMC_DATA_TIMEOUT_SD 500; /*max is 250ms showed in Spec; Maybe adapt the value for the sick card.*/ +/*max is 250ms showed in Spec; Maybe adapt the value for the sick card.*/ +#define SDMMC_DATA_TIMEOUT_SD 500 #define SDMMC_DATA_TIMEOUT_SDIO 250 #define SDMMC_DATA_TIMEOUT_EMMC 2500 -#define SDMMC_CMD_RTO_MAX_HOLD 200 +#define SDMMC_CMD_RTO_MAX_HOLD 200 #define SDMMC_WAIT_FOR_UNBUSY 2500 #ifdef CONFIG_MMC_DW_IDMAC @@ -867,15 +868,18 @@ static void dw_mci_setup_bus(struct dw_mci_slot *slot, bool force_clkinit) u32 div; u32 clk_en_a; u32 sdio_int; - + MMC_DBG_INFO_FUNC(host->mmc,"%d..%s: clock=%d, current_speed=%d, bus_hz=%d,forc=%d[%s]\n", __LINE__, __FUNCTION__, clock, host->current_speed,host->bus_hz,force_clkinit,mmc_hostname(host->mmc)); if (!clock) { mci_writel(host, CLKENA, 0); - mci_send_cmd(slot, - SDMMC_CMD_UPD_CLK | SDMMC_CMD_PRV_DAT_WAIT, 0); - + #ifdef CONFIG_MMC_DW_ROCKCHIP_SWITCH_VOLTAGE + if(host->svi_flags == 0) + mci_send_cmd(slot, SDMMC_CMD_UPD_CLK | SDMMC_CMD_PRV_DAT_WAIT, 0); + #else + mci_send_cmd(slot, SDMMC_CMD_UPD_CLK | SDMMC_CMD_PRV_DAT_WAIT, 0); + #endif } else if (clock != host->current_speed || force_clkinit) { div = host->bus_hz / clock; if (host->bus_hz % clock && host->bus_hz > clock) @@ -1016,12 +1020,13 @@ static void dw_mci_wait_unbusy(struct dw_mci *host) time_loop = jiffies + msecs_to_jiffies(timeout); do { status = mci_readl(host, STATUS); - if (!(status & (SDMMC_STAUTS_DATA_BUSY|SDMMC_STAUTS_MC_BUSY))) + if (!(status & (SDMMC_STAUTS_DATA_BUSY | SDMMC_STAUTS_MC_BUSY))) break; - //MMC_DBG_INFO_FUNC("dw_mci_wait_unbusy, waiting for......"); } while (time_before(jiffies, time_loop)); } + +#ifdef CONFIG_MMC_DW_ROCKCHIP_SWITCH_VOLTAGE /* * result: * 0--status is busy. @@ -1031,34 +1036,24 @@ int dw_mci_card_busy(struct mmc_host *mmc) { struct dw_mci_slot *slot = mmc_priv(mmc); struct dw_mci *host = slot->host; - unsigned int timeout= SDMMC_DATA_TIMEOUT_SDIO; - unsigned long time_loop; - unsigned int status; - int ret= 0; + + MMC_DBG_INFO_FUNC(host->mmc, "dw_mci_card_busy: svi_flags = %d [%s]", \ + host->svi_flags, mmc_hostname(host->mmc)); - if(host->mmc->restrict_caps & RESTRICT_CARD_TYPE_EMMC) - timeout = SDMMC_DATA_TIMEOUT_EMMC; - else if(host->mmc->restrict_caps & RESTRICT_CARD_TYPE_SD) - timeout = SDMMC_DATA_TIMEOUT_SD; - timeout = 250*1000;//test - time_loop = jiffies + msecs_to_jiffies(timeout); + /* svi toggle*/ + if(host->svi_flags == 0){ + /*first svi*/ + host->svi_flags = 1; + return host->svi_flags; - MMC_DBG_INFO_FUNC(host->mmc, "line%d: dw_mci_wait_unbusy,timeloop=%lu, status=0x%x ", - __LINE__, time_loop, mci_readl(host, STATUS)); - do { - status = mci_readl(host, STATUS); - if (!(status & (SDMMC_STAUTS_DATA_BUSY|SDMMC_STAUTS_MC_BUSY))){ - ret = 1;//card is unbusy. - break; + }else{ + host->svi_flags = 0; + return host->svi_flags; } - //MMC_DBG_INFO_FUNC("dw_mci_wait_unbusy, waiting for......"); - } while (time_before(jiffies, time_loop)); - MMC_DBG_INFO_FUNC(host->mmc, "line%d: dw_mci_wait_unbusy,ret=%d, status=0x%x ", - __LINE__,ret,mci_readl(host, STATUS)); + - return ret; } - +#endif static void __dw_mci_start_request(struct dw_mci *host, struct dw_mci_slot *slot, struct mmc_command *cmd) @@ -1073,15 +1068,8 @@ static void __dw_mci_start_request(struct dw_mci *host, host->cur_slot = slot; host->mrq = mrq; -#if 0 //add by xbw,at 2014-03-12 - /*clean FIFO if it is a new request*/ - if(!(mrq->cmd->opcode & SDMMC_CMD_STOP)) { - MMC_DBG_INFO_FUNC("%d..%s: reset the ctrl.", __LINE__, __FUNCTION__); - mci_writel(host, CTRL, (SDMMC_CTRL_RESET | SDMMC_CTRL_FIFO_RESET | - SDMMC_CTRL_DMA_RESET)); - } - #endif - dw_mci_wait_unbusy(host); + + dw_mci_wait_unbusy(host); host->pending_events = 0; host->completed_events = 0; @@ -1116,9 +1104,9 @@ static void dw_mci_start_request(struct dw_mci *host, { struct mmc_request *mrq = slot->mrq; struct mmc_command *cmd; - - MMC_DBG_INFO_FUNC(host->mmc, " Begin to start the new request. cmd=%d(arg=0x%x)[%s]", \ - mrq->cmd->opcode, mrq->cmd->arg, mmc_hostname(host->mmc)); + + MMC_DBG_INFO_FUNC(host->mmc, " Begin to start the new request. cmd=%d(arg=0x%x)[%s]", \ + mrq->cmd->opcode, mrq->cmd->arg, mmc_hostname(host->mmc)); cmd = mrq->sbc ? mrq->sbc : mrq->cmd; __dw_mci_start_request(host, slot, cmd); @@ -1164,8 +1152,9 @@ static void dw_mci_request(struct mmc_host *mmc, struct mmc_request *mrq) mmc_request_done(mmc, mrq); return; } - MMC_DBG_CMD_FUNC(host->mmc, "======>\n pull a new request from MMC-frame to dw_mci_queue. cmd=%d(arg=0x%x)[%s]", \ - mrq->cmd->opcode, mrq->cmd->arg, mmc_hostname(host->mmc)); + + MMC_DBG_CMD_FUNC(host->mmc, "======>\n pull a new request from MMC-frame to dw_mci_queue. cmd=%d(arg=0x%x)[%s]", \ + mrq->cmd->opcode, mrq->cmd->arg, mmc_hostname(host->mmc)); dw_mci_queue_request(host, slot, mrq); @@ -1175,12 +1164,25 @@ static void dw_mci_request(struct mmc_host *mmc, struct mmc_request *mrq) static void dw_mci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) { struct dw_mci_slot *slot = mmc_priv(mmc); + #ifdef CONFIG_MMC_DW_ROCKCHIP_SWITCH_VOLTAGE + struct dw_mci *host = slot->host; + #endif const struct dw_mci_drv_data *drv_data = slot->host->drv_data; u32 regs; -#ifdef SDMMC_WAIT_FOR_UNBUSY - unsigned long time_loop = jiffies + msecs_to_jiffies(SDMMC_WAIT_FOR_UNBUSY); + + #ifdef SDMMC_WAIT_FOR_UNBUSY + unsigned long time_loop; bool ret = true; + #ifdef CONFIG_MMC_DW_ROCKCHIP_SWITCH_VOLTAGE + if(host->svi_flags == 1) + time_loop = jiffies + msecs_to_jiffies(SDMMC_DATA_TIMEOUT_SD); + else + time_loop = jiffies + msecs_to_jiffies(SDMMC_WAIT_FOR_UNBUSY); + #else + time_loop = jiffies + msecs_to_jiffies(SDMMC_WAIT_FOR_UNBUSY); + #endif + if(!test_bit(DW_MMC_CARD_PRESENT, &slot->flags)){ printk("%d..%s: no card. [%s]\n", \ __LINE__, __FUNCTION__, mmc_hostname(mmc)); @@ -1197,11 +1199,15 @@ static void dw_mci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) if(false == ret) { printk("slot->flags = %lu ", slot->flags); - dump_stack(); + #ifdef CONFIG_MMC_DW_ROCKCHIP_SWITCH_VOLTAGE + if(host->svi_flags != 1) + #endif + dump_stack(); printk("%d..%s: wait for unbusy timeout....... STATUS = 0x%x [%s]\n", \ __LINE__, __FUNCTION__, regs, mmc_hostname(mmc)); } -#endif + #endif + switch (ios->bus_width) { case MMC_BUS_WIDTH_4: slot->ctype = SDMMC_CTYPE_4BIT; @@ -1241,25 +1247,25 @@ static void dw_mci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) EXIT_POWER: switch (ios->power_mode) { - case MMC_POWER_UP: - set_bit(DW_MMC_CARD_NEED_INIT, &slot->flags); - /* Power up slot */ - if (slot->host->pdata->setpower) - slot->host->pdata->setpower(slot->id, mmc->ocr_avail); - regs = mci_readl(slot->host, PWREN); - regs |= (1 << slot->id); - mci_writel(slot->host, PWREN, regs); - break; - case MMC_POWER_OFF: - /* Power down slot */ - if (slot->host->pdata->setpower) - slot->host->pdata->setpower(slot->id, 0); - regs = mci_readl(slot->host, PWREN); - regs &= ~(1 << slot->id); - mci_writel(slot->host, PWREN, regs); - break; - default: - break; + case MMC_POWER_UP: + set_bit(DW_MMC_CARD_NEED_INIT, &slot->flags); + /* Power up slot */ + if (slot->host->pdata->setpower) + slot->host->pdata->setpower(slot->id, mmc->ocr_avail); + regs = mci_readl(slot->host, PWREN); + regs |= (1 << slot->id); + mci_writel(slot->host, PWREN, regs); + break; + case MMC_POWER_OFF: + /* Power down slot */ + if(slot->host->pdata->setpower) + slot->host->pdata->setpower(slot->id, 0); + regs = mci_readl(slot->host, PWREN); + regs &= ~(1 << slot->id); + mci_writel(slot->host, PWREN, regs); + break; + default: + break; } } @@ -1270,11 +1276,11 @@ static int dw_mci_get_ro(struct mmc_host *mmc) struct dw_mci_board *brd = slot->host->pdata; /* Use platform get_ro function, else try on board write protect */ - if (slot->quirks & DW_MCI_SLOT_QUIRK_NO_WRITE_PROTECT) + if(slot->quirks & DW_MCI_SLOT_QUIRK_NO_WRITE_PROTECT) read_only = 0; - else if (brd->get_ro) + else if(brd->get_ro) read_only = brd->get_ro(slot->id); - else if (gpio_is_valid(slot->wp_gpio)) + else if(gpio_is_valid(slot->wp_gpio)) read_only = gpio_get_value(slot->wp_gpio); else read_only = @@ -1324,8 +1330,8 @@ static int dw_mci_get_cd(struct mmc_host *mmc) struct dw_mci *host = slot->host; int gpio_cd = mmc_gpio_get_cd(mmc); - if (mmc->restrict_caps & RESTRICT_CARD_TYPE_SDIO) - return test_bit(DW_MMC_CARD_PRESENT, &slot->flags); + if (mmc->restrict_caps & RESTRICT_CARD_TYPE_SDIO) + return test_bit(DW_MMC_CARD_PRESENT, &slot->flags); /* Use platform get_cd function, else try onboard card detect */ if (brd->quirks & DW_MCI_QUIRK_BROKEN_CARD_DETECTION) @@ -1477,7 +1483,7 @@ static void dw_mci_enable_sdio_irq(struct mmc_host *mmc, int enb) /* Enable/disable Slot Specific SDIO interrupt */ int_mask = mci_readl(host, INTMASK); - if (host->verid < DW_MMC_240A) + if (host->verid < DW_MMC_240A) sdio_int = SDMMC_INT_SDIO(slot->id); else sdio_int = SDMMC_INT_SDIO((slot->id) + 8); @@ -1499,7 +1505,32 @@ static void dw_mci_enable_sdio_irq(struct mmc_host *mmc, int enb) } } -#if 0 +#ifdef CONFIG_MMC_DW_ROCKCHIP_SWITCH_VOLTAGE +enum{ + IO_DOMAIN_12 = 1200, + IO_DOMAIN_18 = 1800, + IO_DOMAIN_33 = 3300, +}; +static void dw_mci_do_grf_io_domain_switch(struct dw_mci *host, u32 voltage) +{ + if(cpu_is_rk3288()){ + if(voltage == IO_DOMAIN_33) + voltage = 0; + else if(voltage == IO_DOMAIN_18) + voltage = 1; + else + MMC_DBG_ERR_FUNC(host->mmc,"%s : err io domain voltage [%s]\n", + __FUNCTION__, mmc_hostname(host->mmc)); + if(host->mmc->restrict_caps & RESTRICT_CARD_TYPE_SD) + grf_writel((voltage << 7) | (1 << 23), RK3288_GRF_IO_VSEL); + else + return ; + }else{ + MMC_DBG_ERR_FUNC(host->mmc,"%s : unknown chip [%s]\n", + __FUNCTION__, mmc_hostname(host->mmc)); + } +} + static int dw_mci_do_start_signal_voltage_switch(struct dw_mci *host, struct mmc_ios *ios) { @@ -1514,76 +1545,80 @@ static int dw_mci_do_start_signal_voltage_switch(struct dw_mci *host, return 0; uhs_reg = mci_readl(host, UHS_REG); - MMC_DBG_SW_VOL_FUNC(host->mmc,"%d..%s: vol=%d.[%s]\n", - __LINE__, __FUNCTION__,ios->signal_voltage, mmc_hostname(host->mmc)); + MMC_DBG_SW_VOL_FUNC(host->mmc,"%d..%s: vol=%d.[%s]\n", + __LINE__, __FUNCTION__,ios->signal_voltage, mmc_hostname(host->mmc)); switch (ios->signal_voltage) { case MMC_SIGNAL_VOLTAGE_330: /* Set 1.8V Signal Enable in the Host Control2 register to 0 */ if (host->vmmc) { ret = io_domain_regulator_set_voltage(host->vmmc, 3300000, 3300000); - //regulator_put(host->vmmc); //to be done in remove function. + /* regulator_put(host->vmmc); //to be done in remove function. */ MMC_DBG_SW_VOL_FUNC(host->mmc,"%s =%dmV set 3.3end, ret=%d \n", __func__, regulator_get_voltage(host->vmmc), ret); if (ret) { - pr_warning("%s: Switching to 3.3V signalling voltage " + MMC_DBG_SW_VOL_FUNC(host->mmc, "%s: Switching to 3.3V signalling voltage " " failed\n", mmc_hostname(host->mmc)); return -EIO; } + dw_mci_do_grf_io_domain_switch(host, IO_DOMAIN_33); } - MMC_DBG_SW_VOL_FUNC(host->mmc,"%d..%s: [%s]\n",__LINE__, __FUNCTION__, mmc_hostname(host->mmc)); + MMC_DBG_SW_VOL_FUNC(host->mmc,"%d..%s: [%s]\n",__LINE__, + __FUNCTION__, mmc_hostname(host->mmc)); - //set High-power mode + /* set High-power mode */ value = mci_readl(host, CLKENA); - mci_writel(host,CLKENA , value& ~SDMMC_CLKEN_LOW_PWR); - //SDMMC_UHS_REG - mci_writel(host,UHS_REG , uhs_reg & ~SDMMC_UHS_VOLT_REG_18); + value &= ~SDMMC_CLKEN_LOW_PWR; + mci_writel(host,CLKENA , value); + /* SDMMC_UHS_REG */ + uhs_reg &= ~SDMMC_UHS_VOLT_REG_18; + mci_writel(host,UHS_REG , uhs_reg); /* Wait for 5ms */ usleep_range(5000, 5500); /* 3.3V regulator output should be stable within 5 ms */ uhs_reg = mci_readl(host, UHS_REG); - if( !(uhs_reg & SDMMC_UHS_VOLT_REG_18)) - return 0; + if( !(uhs_reg & SDMMC_UHS_VOLT_REG_18)) + return 0; - pr_warning("%s: 3.3V regulator output did not became stable\n", + MMC_DBG_SW_VOL_FUNC(host->mmc, "%s: 3.3V regulator output did not became stable\n", mmc_hostname(host->mmc)); return -EAGAIN; case MMC_SIGNAL_VOLTAGE_180: if (host->vmmc) { ret = io_domain_regulator_set_voltage(host->vmmc,1800000, 1800000); -// regulator_put(host->vmmc);//to be done in remove function. + /* regulator_put(host->vmmc);//to be done in remove function. */ MMC_DBG_SW_VOL_FUNC(host->mmc,"%d..%s =%dmV set 1.8end, ret=%d . \n", __LINE__, __func__, regulator_get_voltage(host->vmmc), ret); if (ret) { - pr_warning("%s: Switching to 1.8V signalling voltage " + MMC_DBG_SW_VOL_FUNC(host->mmc, "%s: Switching to 1.8V signalling voltage " " failed\n", mmc_hostname(host->mmc)); return -EIO; } + dw_mci_do_grf_io_domain_switch(host, IO_DOMAIN_18); } /* * Enable 1.8V Signal Enable in the Host Control2 * register */ - mci_writel(host,UHS_REG , uhs_reg | SDMMC_UHS_VOLT_REG_18); + mci_writel(host,UHS_REG , uhs_reg | SDMMC_UHS_VOLT_REG_18); /* Wait for 5ms */ usleep_range(5000, 5500); - MMC_DBG_SW_VOL_FUNC(host->mmc,"%d..%s: .[%s]\n",__LINE__, __FUNCTION__,mmc_hostname(host->mmc)); + MMC_DBG_SW_VOL_FUNC(host->mmc,"%d..%s: .[%s]\n",__LINE__, + __FUNCTION__,mmc_hostname(host->mmc)); /* 1.8V regulator output should be stable within 5 ms */ uhs_reg = mci_readl(host, UHS_REG); - if( uhs_reg & SDMMC_UHS_VOLT_REG_18){ - - return 0; - } - - pr_warning("%s: 1.8V regulator output did not became stable\n", + if(uhs_reg & SDMMC_UHS_VOLT_REG_18) + return 0; + + MMC_DBG_SW_VOL_FUNC(host->mmc, "%s: 1.8V regulator output did not became stable\n", mmc_hostname(host->mmc)); return -EAGAIN; @@ -1591,7 +1626,7 @@ static int dw_mci_do_start_signal_voltage_switch(struct dw_mci *host, if (host->vmmc) { ret = io_domain_regulator_set_voltage(host->vmmc, 1200000, 1200000); if (ret) { - pr_warning("%s: Switching to 1.2V signalling voltage " + MMC_DBG_SW_VOL_FUNC(host->mmc, "%s: Switching to 1.2V signalling voltage " " failed\n", mmc_hostname(host->mmc)); return -EIO; } @@ -1613,12 +1648,13 @@ static int dw_mci_start_signal_voltage_switch(struct mmc_host *mmc, if (host->verid < DW_MMC_240A) return 0; - //sdhci_runtime_pm_get(host); + err = dw_mci_do_start_signal_voltage_switch(host, ios); - //sdhci_runtime_pm_put(host); return err; } + #endif + static int dw_mci_execute_tuning(struct mmc_host *mmc, u32 opcode) { struct dw_mci_slot *slot = mmc_priv(mmc); @@ -1680,9 +1716,12 @@ static const struct mmc_host_ops dw_mci_ops = { .hw_reset = dw_mci_hw_reset, .enable_sdio_irq = dw_mci_enable_sdio_irq, .execute_tuning = dw_mci_execute_tuning, - //.start_signal_voltage_switch = dw_mci_start_signal_voltage_switch, - //.card_busy = dw_mci_card_busy, + #ifdef CONFIG_MMC_DW_ROCKCHIP_SWITCH_VOLTAGE + .start_signal_voltage_switch = dw_mci_start_signal_voltage_switch, + .card_busy = dw_mci_card_busy, + #endif }; + #if 0 static void dw_mci_enable_irq(struct dw_mci *host, bool irqflag) { @@ -1707,11 +1746,12 @@ static void dw_mci_enable_irq(struct dw_mci *host, bool irqflag) local_irq_restore(flags); } #endif + static void dw_mci_deal_data_end(struct dw_mci *host, struct mmc_request *mrq) __releases(&host->lock) __acquires(&host->lock) { - if(DW_MCI_SEND_STATUS == host->dir_status){ + if(DW_MCI_SEND_STATUS == host->dir_status){ #if 0 if( MMC_BUS_TEST_W != host->cmd->opcode){ if(host->data_status & SDMMC_INT_DCRC) @@ -1724,8 +1764,7 @@ static void dw_mci_deal_data_end(struct dw_mci *host, struct mmc_request *mrq) #else dw_mci_wait_unbusy(host); #endif - - } + } } static void dw_mci_request_end(struct dw_mci *host, struct mmc_request *mrq) @@ -1737,14 +1776,14 @@ static void dw_mci_request_end(struct dw_mci *host, struct mmc_request *mrq) WARN_ON(host->cmd || host->data); - dw_mci_deal_data_end(host, mrq); + dw_mci_deal_data_end(host, mrq); - if(mrq->cmd) - MMC_DBG_CMD_FUNC(host->mmc, " reqeust end--reqeuest done, cmd=%d, cmderr=%d, host->state=%d [%s]",\ - mrq->cmd->opcode,mrq->cmd->error, host->state,mmc_hostname(host->mmc)); - if(mrq->data) - MMC_DBG_CMD_FUNC(host->mmc, " reqeust end--reqeuest done, cmd=%d, dataerr=%d, host->state=%d [%s]",\ - mrq->cmd->opcode,mrq->data->error, host->state, mmc_hostname(host->mmc)); + if(mrq->cmd) + MMC_DBG_CMD_FUNC(host->mmc, " reqeust end--reqeuest done, cmd=%d, cmderr=%d, host->state=%d [%s]",\ + mrq->cmd->opcode,mrq->cmd->error, host->state,mmc_hostname(host->mmc)); + if(mrq->data) + MMC_DBG_CMD_FUNC(host->mmc, " reqeust end--reqeuest done, cmd=%d, dataerr=%d, host->state=%d [%s]",\ + mrq->cmd->opcode,mrq->data->error, host->state, mmc_hostname(host->mmc)); host->cur_slot->mrq = NULL; host->mrq = NULL; @@ -1762,7 +1801,7 @@ static void dw_mci_request_end(struct dw_mci *host, struct mmc_request *mrq) host->state = STATE_IDLE; } - spin_unlock(&host->lock); + spin_unlock(&host->lock); mmc_request_done(prev_mmc, mrq); spin_lock(&host->lock); } @@ -1806,15 +1845,16 @@ static void dw_mci_command_complete(struct dw_mci *host, struct mmc_command *cmd cmd->error = -EIO; else cmd->error = 0; - MMC_DBG_CMD_FUNC(host->mmc, " command complete, cmd=%d,cmdError=%d [%s]",cmd->opcode, cmd->error,mmc_hostname(host->mmc)); + MMC_DBG_CMD_FUNC(host->mmc, " command complete, cmd=%d,cmdError=%d [%s]", + cmd->opcode, cmd->error,mmc_hostname(host->mmc)); if (cmd->error) { if(MMC_SEND_STATUS != cmd->opcode) if(host->cmd_rto >= SDMMC_CMD_RTO_MAX_HOLD){ - MMC_DBG_ERR_FUNC(host->mmc, " command complete, cmd=%d,cmdError=%d [%s]",\ - cmd->opcode, cmd->error,mmc_hostname(host->mmc)); - host->cmd_rto = 0; - } + MMC_DBG_ERR_FUNC(host->mmc, " command complete, cmd=%d,cmdError=%d [%s]",\ + cmd->opcode, cmd->error,mmc_hostname(host->mmc)); + host->cmd_rto = 0; + } /* newer ip versions need a delay between retries */ if (host->quirks & DW_MCI_QUIRK_RETRY_DELAY) @@ -1826,7 +1866,7 @@ static void dw_mci_command_complete(struct dw_mci *host, struct mmc_command *cmd static void dw_mci_tasklet_func(unsigned long priv) { struct dw_mci *host = (struct dw_mci *)priv; - struct dw_mci_slot *slot = mmc_priv(host->mmc); + struct dw_mci_slot *slot = mmc_priv(host->mmc); struct mmc_data *data; struct mmc_command *cmd; enum dw_mci_state state; @@ -1880,7 +1920,6 @@ static void dw_mci_tasklet_func(unsigned long priv) #endif } - if (!host->mrq->data || cmd->error) { dw_mci_request_end(host, host->mrq); goto unlock; @@ -1896,32 +1935,32 @@ static void dw_mci_tasklet_func(unsigned long priv) if (data->stop){ send_stop_cmd(host, data); }else{ - /*single block read/write, send stop cmd manually to prevent host controller halt*/ - MMC_DBG_INFO_FUNC(host->mmc, "%s status 1 0x%08x [%s]\n", - __func__, mci_readl(host, STATUS), mmc_hostname(host->mmc)); + /*single block read/write, send stop cmd manually to prevent host controller halt*/ + MMC_DBG_INFO_FUNC(host->mmc, "%s status 1 0x%08x [%s]\n", + __func__, mci_readl(host, STATUS), mmc_hostname(host->mmc)); - mci_writel(host, CMDARG, 0); - wmb(); - cmd_flags = SDMMC_CMD_STOP |SDMMC_CMD_RESP_CRC|SDMMC_CMD_RESP_EXP|MMC_STOP_TRANSMISSION; - - if(host->mmc->hold_reg_flag) - cmd_flags |= SDMMC_CMD_USE_HOLD_REG; + mci_writel(host, CMDARG, 0); + wmb(); + cmd_flags = SDMMC_CMD_STOP | SDMMC_CMD_RESP_CRC + | SDMMC_CMD_RESP_EXP | MMC_STOP_TRANSMISSION; + + if(host->mmc->hold_reg_flag) + cmd_flags |= SDMMC_CMD_USE_HOLD_REG; - mci_writel(host, CMD, cmd_flags | SDMMC_CMD_START); - wmb(); - timeout = jiffies + msecs_to_jiffies(500); + mci_writel(host, CMD, cmd_flags | SDMMC_CMD_START); + wmb(); + timeout = jiffies + msecs_to_jiffies(500); - while(ret){ - ret = time_before(jiffies, timeout); - if(!(mci_readl(host, CMD) & SDMMC_CMD_START)) - break; - } - - if(false == ret) - MMC_DBG_ERR_FUNC(host->mmc, - "%s EVENT_DATA_ERROR recovery failed!!! [%s]\n", - __func__, mmc_hostname(host->mmc)); - } + while(ret){ + ret = time_before(jiffies, timeout); + if(!(mci_readl(host, CMD) & SDMMC_CMD_START)) + break; + } + if(false == ret) + MMC_DBG_ERR_FUNC(host->mmc, + "%s EVENT_DATA_ERROR recovery failed!!! [%s]\n", + __func__, mmc_hostname(host->mmc)); + } #else send_stop_abort(host, data); #endif @@ -2002,14 +2041,14 @@ static void dw_mci_tasklet_func(unsigned long priv) dw_mci_request_end(host, host->mrq); goto unlock; } - MMC_DBG_CMD_FUNC(host->mmc, "Pre-state[%d]-->NowState[%d]: begin to stop . [%s]", \ - prev_state,state,mmc_hostname(host->mmc)); + MMC_DBG_CMD_FUNC(host->mmc, "Pre-state[%d]-->NowState[%d]: begin to stop . [%s]", \ + prev_state,state,mmc_hostname(host->mmc)); if (host->mrq->sbc && !data->error) { data->stop->error = 0; - MMC_DBG_CMD_FUNC(host->mmc, "Pre-state[%d]-->NowState[%d]: have stop and sbc, exit. [%s]", \ - prev_state,state,mmc_hostname(host->mmc)); + MMC_DBG_CMD_FUNC(host->mmc, "Pre-state[%d]-->NowState[%d]: have stop and sbc, exit. [%s]", \ + prev_state,state,mmc_hostname(host->mmc)); dw_mci_request_end(host, host->mrq); goto unlock; @@ -2026,31 +2065,31 @@ static void dw_mci_tasklet_func(unsigned long priv) } #endif /* fall through */ - MMC_DBG_CMD_FUNC(host->mmc, "Pre-state[%d]-->NowState[%d]: begin to STATE_SENDING_STOP . [%s]", \ - prev_state,state,mmc_hostname(host->mmc)); + MMC_DBG_CMD_FUNC(host->mmc, "Pre-state[%d]-->NowState[%d]: begin to STATE_SENDING_STOP . [%s]", \ + prev_state,state,mmc_hostname(host->mmc)); case STATE_SENDING_STOP: - if (!test_and_clear_bit(EVENT_CMD_COMPLETE, - &host->pending_events)) + if (!test_and_clear_bit(EVENT_CMD_COMPLETE, &host->pending_events)) break; - MMC_DBG_CMD_FUNC(host->mmc, "Pre-state[%d]-->NowState[%d]: begin to send cmd12 . [%s]", \ - prev_state,state,mmc_hostname(host->mmc)); + + MMC_DBG_CMD_FUNC(host->mmc, "Pre-state[%d]-->NowState[%d]: begin to send cmd12 . [%s]", \ + prev_state, state, mmc_hostname(host->mmc)); - /* CMD error in data command */ + /* CMD error in data command */ if (host->mrq->cmd->error && host->mrq->data) { dw_mci_fifo_reset(host); } host->cmd = NULL; host->data = NULL; - #if 1 - dw_mci_command_complete(host, host->mrq->stop); - #else + #if 1 + dw_mci_command_complete(host, host->mrq->stop); + #else if (host->mrq->stop) dw_mci_command_complete(host, host->mrq->stop); else host->cmd_status = 0; - #endif + #endif dw_mci_request_end(host, host->mrq); goto unlock; @@ -2955,8 +2994,9 @@ static int dw_mci_init_slot(struct dw_mci *host, unsigned int id) if (drv_data && drv_data->hold_reg_flag) mmc->hold_reg_flag |= drv_data->hold_reg_flag[ctrl_id]; - //set the compatibility of driver. - mmc->caps |= MMC_CAP_UHS_SDR12|MMC_CAP_UHS_SDR25|MMC_CAP_UHS_SDR50|MMC_CAP_UHS_SDR104|MMC_CAP_ERASE ; + /* set the compatibility of driver. */ + mmc->caps |= MMC_CAP_UHS_SDR12 | MMC_CAP_UHS_SDR25 | MMC_CAP_UHS_SDR50 + | MMC_CAP_UHS_SDR104 | MMC_CAP_ERASE ; if (host->pdata->caps2) mmc->caps2 = host->pdata->caps2; @@ -2969,13 +3009,14 @@ static int dw_mci_init_slot(struct dw_mci *host, unsigned int id) bus_width = 1; switch (bus_width) { - case 8: - mmc->caps |= MMC_CAP_8_BIT_DATA; - case 4: - mmc->caps |= MMC_CAP_4_BIT_DATA; + case 8: + mmc->caps |= MMC_CAP_8_BIT_DATA; + case 4: + mmc->caps |= MMC_CAP_4_BIT_DATA; } + if (of_find_property(host->dev->of_node, "cap-power-off-card", NULL)) - mmc->caps |= MMC_CAP_POWER_OFF_CARD; + mmc->caps |= MMC_CAP_POWER_OFF_CARD; if (of_find_property(host->dev->of_node, "cap-sdio-irq", NULL)) mmc->caps |= MMC_CAP_SDIO_IRQ; if (of_find_property(host->dev->of_node, "poll-hw-reset", NULL)) @@ -2984,12 +3025,12 @@ static int dw_mci_init_slot(struct dw_mci *host, unsigned int id) mmc->caps2 |= MMC_CAP2_FULL_PWR_CYCLE; if (of_find_property(host->dev->of_node, "keep-power-in-suspend", NULL)) mmc->pm_caps |= MMC_PM_KEEP_POWER; - if (of_find_property(host->dev->of_node, "ignore-pm-notify", NULL)) - mmc->pm_caps |= MMC_PM_IGNORE_PM_NOTIFY; + if (of_find_property(host->dev->of_node, "ignore-pm-notify", NULL)) + mmc->pm_caps |= MMC_PM_IGNORE_PM_NOTIFY; if (of_find_property(host->dev->of_node, "enable-sdio-wakeup", NULL)) mmc->pm_caps |= MMC_PM_WAKE_SDIO_IRQ; - /*Assign pm_caps pass to pm_flags*/ + /*Assign pm_caps pass to pm_flags*/ mmc->pm_flags = mmc->pm_caps; if (host->pdata->blk_settings) { @@ -3014,74 +3055,72 @@ static int dw_mci_init_slot(struct dw_mci *host, unsigned int id) mmc->max_seg_size = mmc->max_req_size; #endif /* CONFIG_MMC_DW_IDMAC */ } - //pwr_en - slot->pwr_en_gpio = dw_mci_of_get_pwr_en_gpio(host->dev, slot->id); - - if (!(mmc->restrict_caps & RESTRICT_CARD_TYPE_SD))//(gpio_is_valid(slot->pwr_en_gpio)) - { - host->vmmc = NULL; - }else{ + /* pwr_en */ + slot->pwr_en_gpio = dw_mci_of_get_pwr_en_gpio(host->dev, slot->id); - if(mmc->restrict_caps & RESTRICT_CARD_TYPE_SD) + if (!(mmc->restrict_caps & RESTRICT_CARD_TYPE_SD)) { - host->vmmc = devm_regulator_get(mmc_dev(mmc), "vmmc"); - } - else - { - host->vmmc = NULL; - } + host->vmmc = NULL; + }else{ + + if(mmc->restrict_caps & RESTRICT_CARD_TYPE_SD) + host->vmmc = devm_regulator_get(mmc_dev(mmc), "vmmc"); + else + host->vmmc = NULL; - if (IS_ERR(host->vmmc)) { - pr_info("%s: no vmmc regulator found\n", mmc_hostname(mmc)); - host->vmmc = NULL; - } else { - ret = regulator_enable(host->vmmc); - if (ret) { - dev_err(host->dev, - "failed to enable regulator: %d\n", ret); - goto err_setup_bus; - } - } - } + if (IS_ERR(host->vmmc)) { + pr_info("%s: no vmmc regulator found\n", mmc_hostname(mmc)); + host->vmmc = NULL; + }else{ + ret = regulator_enable(host->vmmc); + if (ret) { + dev_err(host->dev, + "failed to enable regulator: %d\n", ret); + host->vmmc = NULL; + goto err_setup_bus; + } + } + } - slot->wp_gpio = dw_mci_of_get_wp_gpio(host->dev, slot->id); + slot->wp_gpio = dw_mci_of_get_wp_gpio(host->dev, slot->id); - if (mmc->restrict_caps & RESTRICT_CARD_TYPE_SDIO) - clear_bit(DW_MMC_CARD_PRESENT, &slot->flags); + if (mmc->restrict_caps & RESTRICT_CARD_TYPE_SDIO) + clear_bit(DW_MMC_CARD_PRESENT, &slot->flags); - ret = mmc_add_host(mmc); - if (ret) - goto err_setup_bus; - - /* Pinctrl set default iomux state to fucntion port. - * Fixme: DON'T TOUCH EMMC SETTING! - */ - if(!(host->mmc->restrict_caps & RESTRICT_CARD_TYPE_EMMC)) - { - host->pinctrl = devm_pinctrl_get(host->dev); - if(IS_ERR(host->pinctrl)) - printk("%s: Warning : No pinctrl used!\n",mmc_hostname(host->mmc)); - else + ret = mmc_add_host(mmc); + if (ret) + goto err_setup_bus; + + /* Pinctrl set default iomux state to fucntion port. + * Fixme: DON'T TOUCH EMMC SETTING! + */ + if(!(host->mmc->restrict_caps & RESTRICT_CARD_TYPE_EMMC)) { - host->pins_idle= pinctrl_lookup_state(host->pinctrl,PINCTRL_STATE_IDLE); - if(IS_ERR(host->pins_default)) - printk("%s: Warning : No IDLE pinctrl matched!\n", mmc_hostname(host->mmc)); - else - { - if(pinctrl_select_state(host->pinctrl, host->pins_idle) < 0) - printk("%s: Warning : Idle pinctrl setting failed!\n", mmc_hostname(host->mmc)); - } + host->pinctrl = devm_pinctrl_get(host->dev); + if(IS_ERR(host->pinctrl)){ + printk("%s: Warning : No pinctrl used!\n",mmc_hostname(host->mmc)); + }else{ + host->pins_idle= pinctrl_lookup_state(host->pinctrl,PINCTRL_STATE_IDLE); + if(IS_ERR(host->pins_default)){ + printk("%s: Warning : No IDLE pinctrl matched!\n", mmc_hostname(host->mmc)); + } + else + { + if(pinctrl_select_state(host->pinctrl, host->pins_idle) < 0) + printk("%s: Warning : Idle pinctrl setting failed!\n", mmc_hostname(host->mmc)); + } - host->pins_default = pinctrl_lookup_state(host->pinctrl,PINCTRL_STATE_DEFAULT); - if(IS_ERR(host->pins_default)) - printk("%s: Warning : No default pinctrl matched!\n", mmc_hostname(host->mmc)); - else - { - if(pinctrl_select_state(host->pinctrl, host->pins_default) < 0) - printk("%s: Warning : Default pinctrl setting failed!\n", mmc_hostname(host->mmc)); - } - } - } + host->pins_default = pinctrl_lookup_state(host->pinctrl,PINCTRL_STATE_DEFAULT); + if(IS_ERR(host->pins_default)){ + printk("%s: Warning : No default pinctrl matched!\n", mmc_hostname(host->mmc)); + } + else + { + if(pinctrl_select_state(host->pinctrl, host->pins_default) < 0) + printk("%s: Warning : Default pinctrl setting failed!\n", mmc_hostname(host->mmc)); + } + } + } #if defined(CONFIG_DEBUG_FS) @@ -3375,6 +3414,7 @@ int dw_mci_probe(struct dw_mci *host) host->irq_state = true; host->set_speed = 0; host->set_div = 0; + host->svi_flags = 0; spin_lock_init(&host->lock); INIT_LIST_HEAD(&host->queue); diff --git a/include/linux/mmc/rk_mmc.h b/include/linux/mmc/rk_mmc.h index b51aec791803..c0b0e344a554 100755 --- a/include/linux/mmc/rk_mmc.h +++ b/include/linux/mmc/rk_mmc.h @@ -193,7 +193,7 @@ struct dw_mci { /* Workaround flags */ u32 quirks; bool irq_state; - + u32 svi_flags; /*switch voltage interrupt flags*/ struct regulator *vmmc; /* Power regulator */ unsigned long irq_flags; /* IRQ flags */ int irq; -- 2.34.1