SDMMC:
authorxbw <xbw@rock-chips.com>
Mon, 5 May 2014 02:10:32 +0000 (10:10 +0800)
committerxbw <xbw@rock-chips.com>
Mon, 5 May 2014 02:10:32 +0000 (10:10 +0800)
1、set the emmc-clock to 150Mhz which compatible with new PLL.
2. Optimization timing Training.
3. SD3.0/SDIO3.0 implementation process.

arch/arm/boot/dts/rk3288.dtsi
drivers/mmc/host/dw_mmc-rockchip.c
drivers/mmc/host/rk_sdmmc.c
drivers/mmc/host/rk_sdmmc.h
drivers/mmc/host/rk_sdmmc_of.c
drivers/mmc/host/rk_sdmmc_of.h
include/linux/mmc/rk_mmc.h

index 32f0c94afb3a7c7d2a4721c5f275dc8683c9da2f..5e9cdd8cf78c9054e85a9b9917a524239747f9de 100755 (executable)
        };
 
        emmc: rksdmmc@ff0f0000 {
-               compatible = "rockchip,rk_mmc";
+               compatible = "rockchip,rk_mmc","rockchip,rk32xx-sdmmc";
                reg = <0xff0f0000 0x4000>;
                interrupts = <GIC_SPI 35 IRQ_TYPE_LEVEL_HIGH>;/*irq=67*/
                #address-cells = <1>;
        };
 
        sdmmc: rksdmmc@ff0c0000 {
-         compatible = "rockchip,rk_mmc";
+               compatible = "rockchip,rk_mmc","rockchip,rk32xx-sdmmc";
                reg = <0xff0c0000 0x4000>;
                interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_HIGH>; /*irq=64*/
          #address-cells = <1>;
        };
 
        sdio: rksdmmc@ff0d0000 {
-               compatible = "rockchip,rk_mmc";
+               compatible = "rockchip,rk_mmc","rockchip,rk32xx-sdmmc";
          reg = <0xff0d0000 0x4000>;
          interrupts = <GIC_SPI 33 IRQ_TYPE_LEVEL_HIGH>;
          #address-cells = <1>;
        };
 
         sdio1: rksdmmc@ff0e0000 {
-                compatible = "rockchip,rk_mmc";
+               compatible = "rockchip,rk_mmc","rockchip,rk32xx-sdmmc";
                 reg = <0xff0e0000 0x4000>;
                 interrupts = <GIC_SPI 34 IRQ_TYPE_LEVEL_HIGH>;
                 #address-cells = <1>;
index b1e90014b0d9842538df57326f8cc8229bb73a83..ea737f4f214a8b56aacfcdf20f5fb0c398252af3 100755 (executable)
 #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;
index 939467eae6fc5dc68bda376fe6619f8a7883db63..992e792b5b69e6a1fb90d6bb281d4297ba02c421 100755 (executable)
@@ -31,6 +31,7 @@
 #include <linux/irq.h>
 #include <linux/mmc/host.h>
 #include <linux/mmc/mmc.h>
+#include <linux/mmc/sd.h>
 #include <linux/mmc/sdio.h>
 #include <linux/mmc/rk_mmc.h>
 #include <linux/bitops.h>
 
 #include "rk_sdmmc.h"
 #include "rk_sdmmc_of.h"
+#include <linux/regulator/rockchip_io_vol_domain.h>
+
+#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;          
index fbedf413245a518f37a6a122e167ec54648ba92a..262db2025c3e239bf9f1846766094c7a2265f52a 100755 (executable)
@@ -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 | \
index 5fc8e662ed54a27ba869d14e3434c0973c4e0b3e..01a84d454a2ec513c8e8124255e11018b8af223d 100755 (executable)
@@ -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
index 168ca56eaa0e91d5237f7161fae809b193d4ae32..c18609b0e806950403ea1a0eefb723cf354ad3f7 100755 (executable)
@@ -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)
index f9dd8c7124d807b715e2c7734917d2c868129db5..b51aec791803164fe2d78f00e2085a976f941759 100755 (executable)
@@ -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;