mmc: host: rk_sdmmc:
authorlintao <lintao@rock-chips.com>
Wed, 11 Jun 2014 06:02:19 +0000 (14:02 +0800)
committerlintao <lintao@rock-chips.com>
Wed, 11 Jun 2014 06:14:55 +0000 (14:14 +0800)
     [IMPORTANT COMMIT | NEED_EXPERIMENTAL | CAN_REVERT]

     <1> Support SDIO 3.0, workaround for non-standard behaviour(AP6335) Temporarily.
     <2> Support SD3.0, and SDXC card  should use  exfat filesystem.
     <3> Non-emmc devices that turning fail would not bug kernel.
         Hotplug and poweroff-able (wifi,SD,MMC) devices support re-insert and try it again.
     <4> note:
         (a) card & io aware devices, f_max = 2 * clock, e.g USH_SDR104 means
             support max 208MHz clock in standard.
         (b) setup_bus doesn't need update clk in svi flow
         (c) card_busy: bascially should check CMD,DATA[0:3], however we use
             toggle tags to match svi flow now.
         (d) shorter wait busy and remove  dump_stack in vsi flow.
             Card should be busy until clk re-enable and svi complete.

      All behaviour follow the protocol, enjoy it!

drivers/mmc/core/sdio.c [changed mode: 0644->0755]
drivers/mmc/host/dw_mmc-rockchip.c
drivers/mmc/host/rk_sdmmc.c
include/linux/mmc/rk_mmc.h

old mode 100644 (file)
new mode 100755 (executable)
index dc2178c..fbba1b2
 #include <linux/mmc/sdio_ids.h>
 #endif
 
+/*
+  Fixme: AP6335 doesn't follow standard sdio3.0 flow, 
+         temp workaround, Broadcom Inc. SHOULD fix it!!
+ */
+
+#define CONFIG_SDIO30_FOR_AP6335
+
 static int sdio_read_fbr(struct sdio_func *func)
 {
        int ret;
@@ -673,6 +680,9 @@ try_again:
         * systems that claim 1.8v signalling in fact do not support
         * it.
         */
+       #ifdef CONFIG_SDIO30_FOR_AP6335   
+       rocr &= ~R4_18V_PRESENT ;  
+       #endif
        if (!powered_resume && (rocr & ocr & R4_18V_PRESENT)) {
                err = mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180,
                                        ocr);
@@ -688,7 +698,11 @@ try_again:
                }
                err = 0;
        } else {
+               #ifdef CONFIG_SDIO30_FOR_AP6335
+               /*nothing to do*/
+               #else   
                ocr &= ~R4_18V_PRESENT;
+               #endif
        }
 
        /*
index 709d41ed2090175ba2f8504f49deec398fee98db..42566954eaf97b35ca17eaf3ab82821ea39a82b2 100755 (executable)
@@ -478,10 +478,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();
+               if(host->mmc->restrict_caps & RESTRICT_CARD_TYPE_EMMC)
+                       BUG();
+               return -EAGAIN;
         }
 
 delayline:
index 06cdc5e8e35f89c8bd93de894efed83d6598c346..54a3cd97f05506a9710dba52204bd71572400d18 100755 (executable)
@@ -67,7 +67,7 @@
 #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.*/
+#define SDMMC_DATA_TIMEOUT_SD  500 /*max is 250ms showed in Spec; Maybe adapt the value for the sick card.*/
 #define SDMMC_DATA_TIMEOUT_SDIO        250
 #define SDMMC_DATA_TIMEOUT_EMMC        2500
 
@@ -884,8 +884,11 @@ static int dw_mci_setup_bus(struct dw_mci_slot *slot, bool force_clkinit)
 
        if (!clock) {
                mci_writel(host, CLKENA, 0);
-               ret = mci_send_cmd(slot,
-                            SDMMC_CMD_UPD_CLK | SDMMC_CMD_PRV_DAT_WAIT, 0);
+
+               if(host->svi_flags == 0)
+                       ret = mci_send_cmd(slot, SDMMC_CMD_UPD_CLK | SDMMC_CMD_PRV_DAT_WAIT, 0);
+                else
+                       ret = 0;
                if(ret < 0)
                        return -EAGAIN;
        } else if (clock != host->current_speed || force_clkinit) {
@@ -1050,32 +1053,19 @@ 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;
     
-    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;
 }
 
 static void __dw_mci_start_request(struct dw_mci *host,
@@ -1194,12 +1184,17 @@ static void dw_mci_request(struct mmc_host *mmc, struct mmc_request *mrq)
 static int dw_mci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
 {
        struct dw_mci_slot *slot = mmc_priv(mmc);
+       struct dw_mci *host = slot->host;
        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);
+        unsigned long   time_loop; 
     bool ret=0;
 
+        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);
     if(!test_bit(DW_MMC_CARD_PRESENT, &slot->flags)){
         printk("%d..%s:  no card. [%s]\n", \
             __LINE__, __FUNCTION__, mmc_hostname(mmc));
@@ -1213,7 +1208,8 @@ static int dw_mci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
     } ;
     if(!ret)
     {
-        printk("slot->flags=%d ", slot->flags);
+                printk("slot->flags=%d \n", slot->flags);
+                if(host->svi_flags != 1)
         dump_stack();
         printk("%d..%s:  wait for unbusy timeout....... STATUS = 0x%x[%s]\n", \
             __LINE__, __FUNCTION__, regs, mmc_hostname(mmc));
@@ -1446,6 +1442,30 @@ static void dw_mci_enable_sdio_irq(struct mmc_host *mmc, int enb)
        }
 }
 
+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 0;
+        }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)
@@ -1474,18 +1494,21 @@ static int dw_mci_do_start_signal_voltage_switch(struct dw_mci *host,
                        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));
 
                //set High-power mode
                value = mci_readl(host, CLKENA);
-               mci_writel(host,CLKENA , value& ~SDMMC_CLKEN_LOW_PWR);
+               value &= ~SDMMC_CLKEN_LOW_PWR;
+               mci_writel(host,CLKENA , value);
                //SDMMC_UHS_REG
-               mci_writel(host,UHS_REG , uhs_reg & ~SDMMC_UHS_VOLT_REG_18);
+               uhs_reg &= ~SDMMC_UHS_VOLT_REG_18; 
+               mci_writel(host,UHS_REG , uhs_reg);
                
                /* Wait for 5ms */
                usleep_range(5000, 5500);
@@ -1495,7 +1518,7 @@ static int dw_mci_do_start_signal_voltage_switch(struct dw_mci *host,
             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;
@@ -1507,10 +1530,11 @@ static int dw_mci_do_start_signal_voltage_switch(struct dw_mci *host,
                        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);
                }
 
                /*
@@ -1530,7 +1554,7 @@ static int dw_mci_do_start_signal_voltage_switch(struct dw_mci *host,
                 return 0;
             }
 
-               pr_warning("%s: 1.8V regulator output did not became stable\n",
+               MMC_DBG_SW_VOL_FUNC(host->mmc, "%s: 1.8V regulator output did not became stable\n",
                                mmc_hostname(host->mmc));
 
                return -EAGAIN;
@@ -1538,7 +1562,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;
                        }
@@ -1627,8 +1651,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_card_busy,
+       .start_signal_voltage_switch    = dw_mci_start_signal_voltage_switch,
+       .card_busy  = dw_mci_card_busy,
 };
 
 static void dw_mci_enable_irq(struct dw_mci *host, bool irqflag)
@@ -2982,6 +3006,7 @@ static int dw_mci_init_slot(struct dw_mci *host, unsigned int id)
                if (ret) {
                        dev_err(host->dev,
                                "failed to enable regulator: %d\n", ret);
+                       host->vmmc = NULL;
                        goto err_setup_bus;
                }
        }
@@ -3317,6 +3342,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);
index b51aec791803164fe2d78f00e2085a976f941759..c0b0e344a5548659c59967b5364d0d133cbb4c40 100755 (executable)
@@ -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;