From 36ae021903cb306454c03d36f9298a1b1bb5c257 Mon Sep 17 00:00:00 2001 From: xbw Date: Mon, 5 May 2014 10:10:32 +0800 Subject: [PATCH] =?utf8?q?SDMMC:=201=E3=80=81set=20the=20emmc-clock=20to?= =?utf8?q?=20150Mhz=20which=20compatible=20with=20new=20PLL.=202.=20Optimi?= =?utf8?q?zation=20timing=20Training.=203.=20SD3.0/SDIO3.0=20implementatio?= =?utf8?q?n=20process.?= MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit --- arch/arm/boot/dts/rk3288.dtsi | 8 +- drivers/mmc/host/dw_mmc-rockchip.c | 13 +- drivers/mmc/host/rk_sdmmc.c | 310 +++++++++++++++++++++++------ drivers/mmc/host/rk_sdmmc.h | 14 +- drivers/mmc/host/rk_sdmmc_of.c | 2 +- drivers/mmc/host/rk_sdmmc_of.h | 20 +- include/linux/mmc/rk_mmc.h | 3 +- 7 files changed, 290 insertions(+), 80 deletions(-) diff --git a/arch/arm/boot/dts/rk3288.dtsi b/arch/arm/boot/dts/rk3288.dtsi index 32f0c94afb3a..5e9cdd8cf78c 100755 --- a/arch/arm/boot/dts/rk3288.dtsi +++ b/arch/arm/boot/dts/rk3288.dtsi @@ -259,7 +259,7 @@ }; emmc: rksdmmc@ff0f0000 { - compatible = "rockchip,rk_mmc"; + compatible = "rockchip,rk_mmc","rockchip,rk32xx-sdmmc"; reg = <0xff0f0000 0x4000>; interrupts = ;/*irq=67*/ #address-cells = <1>; @@ -275,7 +275,7 @@ }; sdmmc: rksdmmc@ff0c0000 { - compatible = "rockchip,rk_mmc"; + compatible = "rockchip,rk_mmc","rockchip,rk32xx-sdmmc"; reg = <0xff0c0000 0x4000>; interrupts = ; /*irq=64*/ #address-cells = <1>; @@ -294,7 +294,7 @@ }; sdio: rksdmmc@ff0d0000 { - compatible = "rockchip,rk_mmc"; + compatible = "rockchip,rk_mmc","rockchip,rk32xx-sdmmc"; reg = <0xff0d0000 0x4000>; interrupts = ; #address-cells = <1>; @@ -313,7 +313,7 @@ }; sdio1: rksdmmc@ff0e0000 { - compatible = "rockchip,rk_mmc"; + compatible = "rockchip,rk_mmc","rockchip,rk32xx-sdmmc"; reg = <0xff0e0000 0x4000>; interrupts = ; #address-cells = <1>; diff --git a/drivers/mmc/host/dw_mmc-rockchip.c b/drivers/mmc/host/dw_mmc-rockchip.c index b1e90014b0d9..ea737f4f214a 100755 --- a/drivers/mmc/host/dw_mmc-rockchip.c +++ b/drivers/mmc/host/dw_mmc-rockchip.c @@ -37,7 +37,11 @@ #define SDMMC_TUNING_DEGREE(tuning_type) ( tuning_type? 0:1 ) #define SDMMC_TUNING_INIT_STATE (0) -#define SDMMC_CMD_USE_HOLD_REG BIT(29) +#define SDMMC_SHIFT_DEGREE_0 (0) +#define SDMMC_SHIFT_DEGREE_90 (1) +#define SDMMC_SHIFT_DEGREE_180 (2) +#define SDMMC_SHIFT_DEGREE_270 (3) + /* Variations in Rockchip specific dw-mshc controller */ enum dw_mci_rockchip_type { @@ -59,10 +63,10 @@ static struct dw_mci_rockchip_compatible { enum dw_mci_rockchip_type ctrl_type; } rockchip_compat[] = { { - .compatible = "rockchip,rk3188-sdmmc", + .compatible = "rockchip,rk31xx-sdmmc", .ctrl_type = DW_MCI_TYPE_RK3188, },{ - .compatible = "rockchip,rk3288-sdmmc", + .compatible = "rockchip,rk32xx-sdmmc", .ctrl_type = DW_MCI_TYPE_RK3288, }, }; @@ -199,6 +203,9 @@ static int dw_mci_rockchip_execute_tuning(struct dw_mci_slot *slot, u32 opcode, blk_test = kmalloc(blksz, GFP_KERNEL); if (!blk_test) return -ENOMEM; + + //be fixed to 90 degrees + dw_mci_rockchip_set_degree(host, tuning_data->con_id, tuning_data->tuning_type, SDMMC_SHIFT_DEGREE_90); //start_smpl = dw_mci_rockchip_get_delaynum(host, tuning_data->con_id, tuning_data->tuning_type); start_smpl = 0; diff --git a/drivers/mmc/host/rk_sdmmc.c b/drivers/mmc/host/rk_sdmmc.c index 939467eae6fc..992e792b5b69 100755 --- a/drivers/mmc/host/rk_sdmmc.c +++ b/drivers/mmc/host/rk_sdmmc.c @@ -31,6 +31,7 @@ #include #include #include +#include #include #include #include @@ -42,10 +43,13 @@ #include "rk_sdmmc.h" #include "rk_sdmmc_of.h" +#include + +#define RK_SDMMC_DRIVER_VERSION "Ver 1.00. The last modify date is 2014-05-05" /* Common flag combinations */ #define DW_MCI_DATA_ERROR_FLAGS (SDMMC_INT_DRTO | SDMMC_INT_DCRC | \ - SDMMC_INT_HTO | SDMMC_INT_SBE | \ + /*SDMMC_INT_HTO | */SDMMC_INT_SBE | \ SDMMC_INT_EBE) #define DW_MCI_CMD_ERROR_FLAGS (SDMMC_INT_RTO | SDMMC_INT_RCRC | \ SDMMC_INT_RESP_ERR) @@ -58,8 +62,8 @@ #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 refer to Spec; Maybe adapt the value to the sick card.*/ #define SDMMC_DATA_TIMEOUT_SDIO 250 +#define SDMMC_DATA_TIMEOUT_SD 5000; /*max is 250ms refer to Spec; Maybe adapt the value to the sick card.*/ #define SDMMC_DATA_TIMEOUT_EMMC 2500 #define SDMMC_CMD_RTO_MAX_HOLD 200 @@ -124,6 +128,7 @@ static const u8 tuning_blk_pattern_8bit[] = { static inline bool dw_mci_fifo_reset(struct dw_mci *host); static inline bool dw_mci_ctrl_all_reset(struct dw_mci *host); static bool dw_mci_ctrl_reset(struct dw_mci *host, u32 reset); +static void dw_mci_disable_low_power(struct dw_mci_slot *slot); /*printk the all register of current host*/ static int dw_mci_regs_printk(struct dw_mci *host) @@ -343,36 +348,46 @@ static u32 dw_mci_prep_stop_abort(struct dw_mci *host, struct mmc_command *cmd) static void dw_mci_start_command(struct dw_mci *host, struct mmc_command *cmd, u32 cmd_flags) { -#ifdef SDMMC_WAIT_FOR_UNBUSY - unsigned long time_loop = jiffies + msecs_to_jiffies(SDMMC_WAIT_FOR_UNBUSY); + unsigned long time_loop = jiffies + msecs_to_jiffies(5000); unsigned int status; - bool ret=1; - - while ((ret=time_before(jiffies, time_loop))&&(test_bit(DW_MMC_CARD_PRESENT, &host->cur_slot->flags))){ - status = mci_readl(host, STATUS); - if (!(status & (SDMMC_STAUTS_DATA_BUSY|SDMMC_STAUTS_MC_BUSY))) - break; - } ; - if(!ret) - printk("%d..%s: cmd=%d,wait for unbusy timeout.......[%s]\n", - __LINE__, __FUNCTION__,cmd->opcode,mmc_hostname(host->mmc)); -#endif + bool ret=0; + host->pre_cmd = host->cmd; host->cmd = cmd; dev_vdbg(host->dev, "start command: ARGR=0x%08x CMDR=0x%08x\n", cmd->arg, cmd_flags); + + if(SD_SWITCH_VOLTAGE == cmd->opcode){ + /*confirm non-low-power mode*/ + struct dw_mci_slot *slot = host->slot[0];//temporality fix slot[0] due to host->num_slots equal to 1; + mci_writel(host, CMDARG, 0); + dw_mci_disable_low_power(slot); + MMC_DBG_INFO_FUNC(host->mmc,"Line%d..%s before start cmd=11,[%s]", + __LINE__, __FUNCTION__,mmc_hostname(host->mmc)); + + cmd_flags |= SDMMC_CMD_VOLT_SWITCH; + } mci_writel(host, CMDARG, cmd->arg); - wmb(); - MMC_DBG_INFO_FUNC(host->mmc,"Line%d..%s start cmd=%d, arg=0x%x[%s]",\ - __LINE__, __FUNCTION__,cmd->opcode, cmd->arg,mmc_hostname(host->mmc)); - //dw_mci_regs_printk(host); - if(host->mmc->hold_reg_flag) cmd_flags |= SDMMC_CMD_USE_HOLD_REG;//fix the value to 1 in some Soc,for example RK3188. mci_writel(host, CMD, cmd_flags | SDMMC_CMD_START); + wmb(); + + while ((time_before(jiffies, time_loop))&&(test_bit(DW_MMC_CARD_PRESENT, &host->cur_slot->flags))){ + status = mci_readl(host, STATUS); + if (!(status & (SDMMC_STAUTS_DATA_BUSY|SDMMC_STAUTS_MC_BUSY))){ + ret = 1 ;//card is unbusy + break; + } + } ; + if(!ret) + MMC_DBG_ERR_FUNC(host->mmc,"Line%d..%s start cmd=%d(arg=0x%x), cmd_reg=0x%x, unbusy=%d,card-present=%d. [%s]", + __LINE__, __FUNCTION__,cmd->opcode, cmd->arg,cmd_flags, + ret,test_bit(DW_MMC_CARD_PRESENT, &host->cur_slot->flags), mmc_hostname(host->mmc)); + } static void send_stop_cmd(struct dw_mci *host, struct mmc_data *data) @@ -814,7 +829,7 @@ static void dw_mci_submit_data(struct dw_mci *host, struct mmc_data *data) static void mci_send_cmd(struct dw_mci_slot *slot, u32 cmd, u32 arg) { struct dw_mci *host = slot->host; - unsigned long timeout = jiffies + msecs_to_jiffies(500); + unsigned long timeout = jiffies + msecs_to_jiffies(5000); unsigned int cmd_status = 0; #ifdef SDMMC_WAIT_FOR_UNBUSY timeout = jiffies + msecs_to_jiffies(SDMMC_WAIT_FOR_UNBUSY); @@ -847,10 +862,13 @@ static void mci_send_cmd(struct dw_mci_slot *slot, u32 cmd, u32 arg) static void dw_mci_setup_bus(struct dw_mci_slot *slot, bool force_clkinit) { struct dw_mci *host = slot->host; - unsigned int clock = slot->clock; + unsigned int tempck,clock = slot->clock; 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); @@ -867,12 +885,16 @@ static void dw_mci_setup_bus(struct dw_mci_slot *slot, bool force_clkinit) div = (host->bus_hz != clock) ? DIV_ROUND_UP(div, 2) : 0; - if ((clock << div) != slot->__clk_old || force_clkinit) + if ((clock << div) != slot->__clk_old || force_clkinit) { + tempck = div ? ((host->bus_hz / div) >> 1) :host->bus_hz; dev_info(&slot->mmc->class_dev, "Bus speed (slot %d) = %dHz (slot req %dHz, actual %dHZ div = %d)\n", slot->id, host->bus_hz, clock, - div ? ((host->bus_hz / div) >> 1) : - host->bus_hz, div); + tempck, div); + + host->set_speed = tempck; + host->set_div = div; + } /* disable clock */ mci_writel(host, CLKENA, 0); @@ -883,8 +905,8 @@ static void dw_mci_setup_bus(struct dw_mci_slot *slot, bool force_clkinit) SDMMC_CMD_UPD_CLK | SDMMC_CMD_PRV_DAT_WAIT, 0); /* set clock to desired speed */ - mci_writel(host, CLKDIV, div>>1); // *2 due to fix divider 2 in controller - host->current_div = div; + mci_writel(host, CLKDIV, div); + /* inform CIU */ mci_send_cmd(slot, SDMMC_CMD_UPD_CLK | SDMMC_CMD_PRV_DAT_WAIT, 0); @@ -912,9 +934,10 @@ static void dw_mci_setup_bus(struct dw_mci_slot *slot, bool force_clkinit) host->current_speed = clock; if(slot->ctype != slot->pre_ctype) - MMC_DBG_BOOT_FUNC(host->mmc, "Bus speed=%dHz,Bus width=%s.[%s]", \ - div ? ((host->bus_hz / div) >> 1):host->bus_hz, \ - (slot->ctype == SDMMC_CTYPE_4BIT)?"4bits":"8bits", mmc_hostname(host->mmc)); + MMC_DBG_BOOT_FUNC(host->mmc, "Bus speed=%dHz,Bus width=%s.[%s]", + host->set_speed, + (slot->ctype == SDMMC_CTYPE_4BIT)?"4bits":"8bits", + mmc_hostname(host->mmc)); slot->pre_ctype = slot->ctype; /* Set the current slot bus width */ @@ -922,27 +945,41 @@ static void dw_mci_setup_bus(struct dw_mci_slot *slot, bool force_clkinit) } -static void dw_mci_wait_unbusy(struct dw_mci *host) +/* +* result: +* 0--status is busy. +* 1--status is unbusy. +*/ +int dw_mci_wait_unbusy(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; - - MMC_DBG_INFO_FUNC(host->mmc, "dw_mci_wait_unbusy, status=0x%x ", mci_readl(host, STATUS)); + int ret= 0; 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 = SDMMC_DATA_TIMEOUT_SD; + timeout = 250*1000;//test time_loop = jiffies + msecs_to_jiffies(timeout); + + 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))) + if (!(status & (SDMMC_STAUTS_DATA_BUSY|SDMMC_STAUTS_MC_BUSY))){ + ret = 1;//card is unbusy. break; + } //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; } static void __dw_mci_start_request(struct dw_mci *host, @@ -967,7 +1004,7 @@ static void __dw_mci_start_request(struct dw_mci *host, SDMMC_CTRL_DMA_RESET)); } #endif - dw_mci_wait_unbusy(host); + dw_mci_wait_unbusy(host->mmc); host->pending_events = 0; host->completed_events = 0; @@ -1304,6 +1341,126 @@ static void dw_mci_enable_sdio_irq(struct mmc_host *mmc, int enb) } } + +static int dw_mci_do_start_signal_voltage_switch(struct dw_mci *host, + struct mmc_ios *ios) +{ + int ret; + unsigned int value,uhs_reg; + + /* + * Signal Voltage Switching is only applicable for Host Controllers + * v3.00 and above. + */ + if (host->verid < DW_MMC_240A) + 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)); + + 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. + + 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 " + " failed\n", mmc_hostname(host->mmc)); + return -EIO; + } + } + MMC_DBG_SW_VOL_FUNC(host->mmc,"%d..%s: [%s]\n",__LINE__, __FUNCTION__, mmc_hostname(host->mmc)); + + //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); + + /* 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; + + pr_warning("%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. + + 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 " + " failed\n", mmc_hostname(host->mmc)); + return -EIO; + } + } + + /* + * Enable 1.8V Signal Enable in the Host Control2 + * register + */ + 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)); + + /* 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", + mmc_hostname(host->mmc)); + + return -EAGAIN; + case MMC_SIGNAL_VOLTAGE_120: + if (host->vmmc) { + ret = io_domain_regulator_set_voltage(host->vmmc, 1200000, 1200000); + if (ret) { + pr_warning("%s: Switching to 1.2V signalling voltage " + " failed\n", mmc_hostname(host->mmc)); + return -EIO; + } + } + return 0; + default: + /* No signal voltage switch required */ + return 0; + } +} + + +static int dw_mci_start_signal_voltage_switch(struct mmc_host *mmc, + struct mmc_ios *ios) +{ + struct dw_mci_slot *slot = mmc_priv(mmc); + struct dw_mci *host = slot->host; + int err; + + 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; +} + static int dw_mci_execute_tuning(struct mmc_host *mmc, u32 opcode) { struct dw_mci_slot *slot = mmc_priv(mmc); @@ -1358,6 +1515,8 @@ 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_wait_unbusy, }; static void dw_mci_enable_irq(struct dw_mci *host, bool irqflag) @@ -1395,10 +1554,10 @@ static void dw_mci_deal_data_end(struct dw_mci *host, struct mmc_request *mrq) else if(host->data_status & SDMMC_INT_EBE) host->data->error = -ETIMEDOUT; } else { - dw_mci_wait_unbusy(host); + dw_mci_wait_unbusy(host->mmc); } #else - dw_mci_wait_unbusy(host); + dw_mci_wait_unbusy(host->mmc); #endif } @@ -1457,15 +1616,15 @@ static void dw_mci_command_complete(struct dw_mci *host, struct mmc_command *cmd cmd->resp[1] = mci_readl(host, RESP2); cmd->resp[0] = mci_readl(host, RESP3); - MMC_DBG_INFO_FUNC(host->mmc," command complete [%s], \ncmd=%d,resp[3]=0x%x, resp[2]=0x%x,resp[1]=0x%x,resp[0]=0x%x", \ - mmc_hostname(host->mmc), cmd->opcode,cmd->resp[3], cmd->resp[2], cmd->resp[1], cmd->resp[0]); + MMC_DBG_INFO_FUNC(host->mmc,"Line%d: command complete cmd=%d,resp[3]=0x%x, resp[2]=0x%x,resp[1]=0x%x,resp[0]=0x%x.[%s]", \ + __LINE__,cmd->opcode,cmd->resp[3], cmd->resp[2], cmd->resp[1], cmd->resp[0], mmc_hostname(host->mmc)); } else { cmd->resp[0] = mci_readl(host, RESP0); cmd->resp[1] = 0; cmd->resp[2] = 0; cmd->resp[3] = 0; - MMC_DBG_INFO_FUNC(host->mmc, " command complete [%s], cmd=%d,resp[0]=0x%x",\ - mmc_hostname(host->mmc),cmd->opcode, cmd->resp[0]); + MMC_DBG_INFO_FUNC(host->mmc, "Line%d: command complete cmd=%d,resp[0]=0x%x. [%s]",\ + __LINE__,cmd->opcode, cmd->resp[0], mmc_hostname(host->mmc)); } } @@ -2159,6 +2318,9 @@ static irqreturn_t dw_mci_interrupt(int irq, void *dev_id) mci_writel(host, RINTSTS, DW_MCI_CMD_ERROR_FLAGS); host->cmd_status = pending; smp_wmb(); + MMC_DBG_INFO_FUNC(host->mmc,"Line%d..%s cmd_status INT=0x%x,[%s]", + __LINE__, __FUNCTION__,host->cmd_status,mmc_hostname(host->mmc)); + set_bit(EVENT_CMD_COMPLETE, &host->pending_events); } @@ -2168,6 +2330,9 @@ static irqreturn_t dw_mci_interrupt(int irq, void *dev_id) host->data_status = pending; smp_wmb(); set_bit(EVENT_DATA_ERROR, &host->pending_events); + + MMC_DBG_INFO_FUNC(host->mmc,"Line%d..%s data_status INT=0x%x,[%s]", + __LINE__, __FUNCTION__,host->data_status,mmc_hostname(host->mmc)); tasklet_schedule(&host->tasklet); } @@ -2197,6 +2362,12 @@ static irqreturn_t dw_mci_interrupt(int irq, void *dev_id) dw_mci_write_data_pio(host); } + if (pending & SDMMC_INT_VSI) { + MMC_DBG_SW_VOL_FUNC(host->mmc, "SDMMC_INT_VSI, INT-pending=0x%x. [%s]",pending,mmc_hostname(host->mmc)); + mci_writel(host, RINTSTS, SDMMC_INT_VSI); + dw_mci_cmd_interrupt(host, pending); + } + if (pending & SDMMC_INT_CMD_DONE) { MMC_DBG_CMD_FUNC(host->mmc, "SDMMC_INT_CMD_DONE, INT-pending=0x%x. [%s]",pending,mmc_hostname(host->mmc)); mci_writel(host, RINTSTS, SDMMC_INT_CMD_DONE); @@ -2521,7 +2692,10 @@ static int dw_mci_init_slot(struct dw_mci *host, unsigned int id) printk("%d..%s: fmin=%d, fmax=%d [%s]\n", __LINE__,__FUNCTION__, mmc->f_min, mmc->f_max, mmc_hostname(mmc)); } - + + if(strstr("mmc0",mmc_hostname(mmc))) + printk("Line%d..%s: The rk_sdmmc %s",__LINE__, __FUNCTION__,RK_SDMMC_DRIVER_VERSION); + if (of_find_property(host->dev->of_node, "supports-sd", NULL)) mmc->restrict_caps |= RESTRICT_CARD_TYPE_SD; if (of_find_property(host->dev->of_node, "supports-sdio", NULL)) @@ -2911,6 +3085,18 @@ int dw_mci_probe(struct dw_mci *host) return -ENODEV; } + /* + * In 2.40a spec, Data offset is changed. + * Need to check the version-id and set data-offset for DATA register. + */ + host->verid = SDMMC_GET_VERID(mci_readl(host, VERID)); + dev_info(host->dev, "Version ID is %04x\n", host->verid); + + if (host->verid < DW_MMC_240A) + host->data_offset = DATA_OFFSET; + else + host->data_offset = DATA_240A_OFFSET; + //hclk enable host->hclk_mmc= devm_clk_get(host->dev, "hclk_mmc"); if (IS_ERR(host->hclk_mmc)) { @@ -2928,7 +3114,10 @@ int dw_mci_probe(struct dw_mci *host) goto err_clk_mmc; } - host->bus_hz = host->pdata->bus_hz; + if (host->verid < DW_MMC_240A) + host->bus_hz = host->pdata->bus_hz; + else + host->bus_hz = host->pdata->bus_hz*2;// *2 due to fix divider 2 in controller. if (!host->bus_hz) { dev_err(host->dev,"Platform data must supply bus speed\n"); ret = -ENODEV; @@ -2941,8 +3130,6 @@ int dw_mci_probe(struct dw_mci *host) goto err_clk_mmc; } clk_prepare_enable(host->clk_mmc); - // printk(" hclk=0x%x, hclk-rate=%lu, clk=0x%x, mmcclk-rate=%lu,host->bus_hz=%d",\ - // host->hclk_mmc,host->hclk_mmc->rate,host->clk_mmc,host->clk_mmc.rate,host->bus_hz); if (drv_data && drv_data->setup_clock) { ret = drv_data->setup_clock(host); @@ -2955,7 +3142,8 @@ int dw_mci_probe(struct dw_mci *host) host->quirks = host->pdata->quirks; host->irq_state = true; - host->current_div = 0; + host->set_speed = 0; + host->set_div = 0; spin_lock_init(&host->lock); INIT_LIST_HEAD(&host->queue); @@ -3025,18 +3213,6 @@ int dw_mci_probe(struct dw_mci *host) mci_writel(host, CLKENA, 0); mci_writel(host, CLKSRC, 0); - /* - * In 2.40a spec, Data offset is changed. - * Need to check the version-id and set data-offset for DATA register. - */ - host->verid = SDMMC_GET_VERID(mci_readl(host, VERID)); - dev_info(host->dev, "Version ID is %04x\n", host->verid); - - if (host->verid < DW_MMC_240A) - host->data_offset = DATA_OFFSET; - else - host->data_offset = DATA_240A_OFFSET; - tasklet_init(&host->tasklet, dw_mci_tasklet_func, (unsigned long)host); host->card_workqueue = alloc_workqueue("dw-mci-card", WQ_MEM_RECLAIM | WQ_NON_REENTRANT, 1); @@ -3069,7 +3245,7 @@ int dw_mci_probe(struct dw_mci *host) * receive ready and error such as transmit, receive timeout, crc error */ mci_writel(host, RINTSTS, 0xFFFFFFFF); - regs = SDMMC_INT_CMD_DONE | SDMMC_INT_DATA_OVER | SDMMC_INT_TXDR | + regs = SDMMC_INT_CMD_DONE | SDMMC_INT_DATA_OVER | SDMMC_INT_TXDR | SDMMC_INT_VSI | SDMMC_INT_RXDR | DW_MCI_ERROR_FLAGS; if(!(host->mmc->restrict_caps & RESTRICT_CARD_TYPE_SDIO) && !(host->mmc->restrict_caps & RESTRICT_CARD_TYPE_EMMC)) @@ -3105,8 +3281,10 @@ err_dmaunmap: if (host->use_dma && host->dma_ops->exit) host->dma_ops->exit(host); - if (host->vmmc) + if (host->vmmc){ regulator_disable(host->vmmc); + regulator_put(host->vmmc); + } err_clk_mmc: if (!IS_ERR(host->clk_mmc)) @@ -3141,8 +3319,10 @@ void dw_mci_remove(struct dw_mci *host) if (host->use_dma && host->dma_ops->exit) host->dma_ops->exit(host); - if (host->vmmc) + if (host->vmmc){ regulator_disable(host->vmmc); + regulator_put(host->vmmc); + } if (!IS_ERR(host->clk_mmc)) clk_disable_unprepare(host->clk_mmc); @@ -3200,7 +3380,7 @@ int dw_mci_resume(struct dw_mci *host) mci_writel(host, TMOUT, 0xFFFFFFFF); mci_writel(host, RINTSTS, 0xFFFFFFFF); - regs = SDMMC_INT_CMD_DONE | SDMMC_INT_DATA_OVER | SDMMC_INT_TXDR | SDMMC_INT_RXDR | + regs = SDMMC_INT_CMD_DONE | SDMMC_INT_DATA_OVER | SDMMC_INT_TXDR | SDMMC_INT_RXDR | SDMMC_INT_VSI | DW_MCI_ERROR_FLAGS; if(!(host->mmc->restrict_caps & RESTRICT_CARD_TYPE_SDIO)) regs |= SDMMC_INT_CD; diff --git a/drivers/mmc/host/rk_sdmmc.h b/drivers/mmc/host/rk_sdmmc.h index fbedf413245a..262db2025c3e 100755 --- a/drivers/mmc/host/rk_sdmmc.h +++ b/drivers/mmc/host/rk_sdmmc.h @@ -15,6 +15,7 @@ #ifndef _DW_MMC_H_ #define _DW_MMC_H_ +#include "rk_sdmmc_of.h" #define DW_MMC_240A 0x240a @@ -87,7 +88,7 @@ static struct sdmmc_reg dw_mci_regs[] = { 0x0018, " CTYPE" }, { 0x001C, " BLKSIZ" }, { 0x0020, " BYTCNT" }, - { 0x0024, " INTMSK" }, + { 0x0024, " INTMASK" }, { 0x0028, " CMDARG" }, { 0x002C, " CMD" }, { 0x0030, " RESP0" }, @@ -154,6 +155,7 @@ static struct sdmmc_reg dw_mci_regs[] = #define SDMMC_INT_HLE BIT(12) #define SDMMC_INT_FRUN BIT(11) #define SDMMC_INT_HTO BIT(10) +#define SDMMC_INT_VSI SDMMC_INT_HTO // VSI => Voltage Switch Interrupt,Volt_Switch_int #define SDMMC_INT_DRTO BIT(9) #define SDMMC_INT_RTO BIT(8) #define SDMMC_INT_DCRC BIT(7) @@ -168,6 +170,12 @@ static struct sdmmc_reg dw_mci_regs[] = /* Command register defines */ #define SDMMC_CMD_START BIT(31) #define SDMMC_CMD_USE_HOLD_REG BIT(29) +#define SDMMC_CMD_VOLT_SWITCH BIT(28) //Voltage switch bit +#define SDMMC_CMD_VOLT_SWITCH BIT(28) //Voltage switch bit +#define SDMMC_CMD_BOOT_MODE BIT(27) //set boot mode. +#define SDMMC_CMD_DISABLE_BOOT BIT(26) //disable boot. +#define SDMMC_CMD_EXPECT_BOOT_ACK BIT(25) //Expect Boot Acknowledge. +#define SDMMC_CMD_ENABLE_BOOT BIT(24) //be set only for mandatory boot mode. #define SDMMC_CMD_CCS_EXP BIT(23) #define SDMMC_CMD_CEATA_RD BIT(22) #define SDMMC_CMD_UPD_CLK BIT(21) @@ -191,6 +199,10 @@ static struct sdmmc_reg dw_mci_regs[] = #define SDMMC_STAUTS_FIFO_FULL BIT(3) //FIFO is full status #define SDMMC_STAUTS_FIFO_EMPTY BIT(2) //FIFO is empty status +/* Control SDMMC_UHS_REG defines (base+ 0x74)*/ +#define SDMMC_UHS_DDR_MODE BIT(16) // 0--Non DDR Mode; 1--DDR mode +#define SDMMC_UHS_VOLT_REG_18 BIT(0) // 0--3.3v; 1--1.8V + /* FIFOTH register defines */ #define SDMMC_SET_FIFOTH(m, r, t) (((m) & 0x7) << 28 | \ ((r) & 0xFFF) << 16 | \ diff --git a/drivers/mmc/host/rk_sdmmc_of.c b/drivers/mmc/host/rk_sdmmc_of.c index 5fc8e662ed54..01a84d454a2e 100755 --- a/drivers/mmc/host/rk_sdmmc_of.c +++ b/drivers/mmc/host/rk_sdmmc_of.c @@ -10,7 +10,7 @@ */ #include "rk_sdmmc_of.h" -u32 mmc_debug_level= MMC_DBG_ERROR;//MMC_DBG_CMD//set the value refer to file rk_sdmmc_of.h +u32 mmc_debug_level= MMC_DBG_BOOT|MMC_DBG_ERROR;//MMC_DBG_SW_VOL|MMC_DBG_CMD;//set the value refer to file rk_sdmmc_of.h char dbg_flag[]="mmc0mmc1mmc2"; #if DW_MMC_OF_PROBE diff --git a/drivers/mmc/host/rk_sdmmc_of.h b/drivers/mmc/host/rk_sdmmc_of.h index 168ca56eaa0e..c18609b0e806 100755 --- a/drivers/mmc/host/rk_sdmmc_of.h +++ b/drivers/mmc/host/rk_sdmmc_of.h @@ -31,6 +31,7 @@ enum MMC_DBG_MASK{ MMC_DBG_INFO = BIT(3), MMC_DBG_CMD = BIT(4), MMC_DBG_DBG = BIT(5), + MMC_DBG_SW_VOL = BIT(6), MMC_DBG_ALL = 0xFF, }; @@ -42,7 +43,7 @@ extern char dbg_flag[]; #if MMC_DBG_FUNC_CONFIG #define MMC_DBG_BOOT_FUNC(mmc_host,fmt, arg...) \ do { \ - if(mmc_debug_level >= MMC_DBG_BOOT) { \ + if(mmc_debug_level & MMC_DBG_BOOT) { \ if(NULL != strpbrk(dbg_flag,mmc_hostname(mmc_host))) { \ printk(DRIVER_PREFIX "BOOT " fmt "\n", ##arg);\ } \ @@ -50,7 +51,7 @@ extern char dbg_flag[]; }while(0) #define MMC_DBG_ERR_FUNC(mmc_host,fmt, arg...) \ do{ \ - if(mmc_debug_level >= MMC_DBG_ERROR) { \ + if(mmc_debug_level & MMC_DBG_ERROR) { \ if(strstr(dbg_flag,mmc_hostname(mmc_host))) { \ printk(DRIVER_PREFIX "ERROR " fmt "\n", ##arg);\ } \ @@ -58,7 +59,7 @@ extern char dbg_flag[]; }while(0) #define MMC_DBG_WARN_FUNC(mmc_host,fmt, arg...) \ do { \ - if(mmc_debug_level >= MMC_DBG_WARN) { \ + if(mmc_debug_level & MMC_DBG_WARN) { \ if(strstr(dbg_flag,mmc_hostname(mmc_host))) { \ printk(DRIVER_PREFIX "WARN " fmt "\n", ##arg);\ } \ @@ -66,7 +67,7 @@ extern char dbg_flag[]; }while(0) #define MMC_DBG_INFO_FUNC(mmc_host,fmt, arg...) \ do { \ - if(mmc_debug_level >= MMC_DBG_INFO) { \ + if(mmc_debug_level & MMC_DBG_INFO) { \ if(strstr(dbg_flag,mmc_hostname(mmc_host))) { \ printk(DRIVER_PREFIX "INFO " fmt "\n", ##arg);\ } \ @@ -74,18 +75,27 @@ extern char dbg_flag[]; }while(0) #define MMC_DBG_CMD_FUNC(mmc_host,fmt, arg...) \ do { \ - if(mmc_debug_level >= MMC_DBG_CMD) { \ + if(mmc_debug_level & MMC_DBG_CMD) { \ if(strstr(dbg_flag,mmc_hostname(mmc_host))) { \ printk(DRIVER_PREFIX "CMD " fmt "\n", ##arg);\ } \ } \ }while(0) +#define MMC_DBG_SW_VOL_FUNC(mmc_host,fmt, arg...) \ + do { \ + if(mmc_debug_level & MMC_DBG_SW_VOL) { \ + if(strstr(dbg_flag,mmc_hostname(mmc_host))) { \ + printk(DRIVER_PREFIX "SW-VOL " fmt "\n", ##arg);\ + } \ + } \ + }while(0) #else #define MMC_DBG_BOOT_FUNC(mmc_host,fmt, arg...) {printk(DRIVER_PREFIX "BOOT " fmt "\n", ##arg);} #define MMC_DBG_ERR_FUNC(mmc_host,fmt, arg...) #define MMC_DBG_WARN_FUNC(mmc_host,fmt, arg...) #define MMC_DBG_INFO_FUNC(mmc_host,fmt, arg...) #define MMC_DBG_CMD_FUNC(mmc_host,fmt, arg...) +#define MMC_DBG_SW_VOL_FUNC(mmc_host,fmt, arg...) #endif #if defined(CONFIG_DYNAMIC_DEBUG) diff --git a/include/linux/mmc/rk_mmc.h b/include/linux/mmc/rk_mmc.h index f9dd8c7124d8..b51aec791803 100755 --- a/include/linux/mmc/rk_mmc.h +++ b/include/linux/mmc/rk_mmc.h @@ -160,7 +160,8 @@ struct dw_mci { u32 bus_hz; u32 current_speed; - u32 current_div; + u32 set_speed; + u32 set_div; u32 num_slots; u32 fifoth_val; u16 verid; -- 2.34.1