rk_sdmmc: speed up MMC for 3368
authorlintao <lintao@rock-chips.com>
Fri, 27 Feb 2015 03:19:15 +0000 (11:19 +0800)
committerlintao <lintao@rock-chips.com>
Fri, 27 Feb 2015 03:21:39 +0000 (11:21 +0800)
   Test with p9-818 board, without DM for ext4 mount option.

Signed-off-by: lintao <lintao@rock-chips.com>
arch/arm64/boot/dts/rk3368-p9_818.dts
arch/arm64/boot/dts/rk3368.dtsi
drivers/mmc/host/dw_mmc-rockchip.c
drivers/mmc/host/rk_sdmmc.c
drivers/mmc/host/rk_sdmmc.h
include/linux/mmc/rk_mmc.h

index c31c4b1701bd27ce781d7a33311475bac06180a8..5a22ae61f651d358759b6a1fc1b97367e07c8732 100755 (executable)
 };
 
 &emmc {
-       clock-frequency = <100000000>;
-       clock-freq-min-max = <400000 100000000>;
+       clock-frequency = <150000000>;
+       clock-freq-min-max = <400000 150000000>;
 
        supports-highspeed;
        supports-emmc;
        bootpart-no-access;
 
        //supports-tSD;
-       //supports-DDR_MODE; //you should set the two value in your project. only close in RK3288-SDK board.
-       //caps2-mmc-hs200;
+       supports-DDR_MODE; //you should set the two value in your project. only close in RK3288-SDK board.
+       caps2-mmc-hs200;
 
        ignore-pm-notify;
        keep-power-in-suspend;
index 7ddb088545df96e824878430573e5c42d3ba8a88..9783d301ce6b6175e6d2ddad9062d25c96ab467a 100755 (executable)
        };
 
        emmc: rksdmmc@ff0f0000 {
-               compatible = "rockchip,rk_mmc", "rockchip,rk32xx-sdmmc";
+               compatible = "rockchip,rk_mmc", "rockchip,rk3368-sdmmc";
                reg = <0x0 0xff0f0000 0x0 0x4000>;
                interrupts = <GIC_SPI 35 IRQ_TYPE_LEVEL_HIGH>;
                #address-cells = <1>;
                #size-cells = <0>;
                clocks = <&clk_emmc>, <&clk_gates21 2>;
                clock-names = "clk_mmc", "hclk_mmc";
+               rockchip,grf = <&grf>;
                num-slots = <1>;
                fifo-depth = <0x100>;
                bus-width = <8>;
        };
 
        sdmmc: rksdmmc@ff0c0000 {
-               compatible = "rockchip,rk_mmc", "rockchip,rk32xx-sdmmc";
+               compatible = "rockchip,rk_mmc", "rockchip,rk3368-sdmmc";
                reg = <0x0 0xff0c0000 0x0 0x4000>;
                interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_HIGH>;
                #address-cells = <1>;
                cd-gpios = <&gpio2 GPIO_B3 GPIO_ACTIVE_HIGH>;/*CD GPIO*/
                clocks = <&clk_sdmmc0>, <&clk_gates21 0>;
                clock-names = "clk_mmc", "hclk_mmc";
+               rockchip,grf = <&grf>;
                num-slots = <1>;
                fifo-depth = <0x100>;
                bus-width = <4>;
        };
 
        sdio: rksdmmc@ff0d0000 {
-               compatible = "rockchip,rk_mmc", "rockchip,rk32xx-sdmmc";
+               compatible = "rockchip,rk_mmc", "rockchip,rk3368-sdmmc";
                reg = <0x0 0xff0d0000 0x0 0x4000>;
                interrupts = <GIC_SPI 33 IRQ_TYPE_LEVEL_HIGH>;
                #address-cells = <1>;
                pinctrl-1 = <&sdio0_gpio>;
                clocks = <&clk_sdio0>, <&clk_gates21 1>;
                clock-names = "clk_mmc", "hclk_mmc";
+               rockchip,grf = <&grf>;
                num-slots = <1>;
                fifo-depth = <0x100>;
                bus-width = <4>;
index bacca5ea0a9c814c015e5b3e21940285055e23d4..f71d34db5fd358d26f2c710db09bad050b171dff 100755 (executable)
@@ -21,6 +21,8 @@
 #include <linux/rockchip/cpu.h>
 #include <linux/rockchip/cru.h>
 #include <linux/delay.h>
+#include <linux/mfd/syscon.h>
+#include <linux/regmap.h>
 #include "rk_sdmmc.h"
 #include "dw_mmc-pltfm.h"
 #include "../../clk/rockchip/clk-ops.h"
@@ -79,13 +81,6 @@ enum{
         SLEW_RATE_FAST = 1,
 };
 
-/* Variations in Rockchip specific dw-mshc controller */
-enum dw_mci_rockchip_type {
-       DW_MCI_TYPE_RK3188,
-       DW_MCI_TYPE_RK3288,
-       DW_MCI_TYPE_RK3036,
-       DW_MCI_TYPE_RK312X,
-};
 
 /* Rockchip implementation specific driver private data */
 struct dw_mci_rockchip_priv_data {
@@ -112,6 +107,9 @@ static struct dw_mci_rockchip_compatible {
        },{
                .compatible     = "rockchip,rk312x-sdmmc",
                .ctrl_type      = DW_MCI_TYPE_RK312X,
+       },{
+               .compatible     = "rockchip,rk3368-sdmmc",
+               .ctrl_type      = DW_MCI_TYPE_RK3368,
        },
 };
 
@@ -128,8 +126,12 @@ static int dw_mci_rockchip_priv_init(struct dw_mci *host)
 
        for(idx = 0; idx < ARRAY_SIZE(rockchip_compat); idx++){
                 if(of_device_is_compatible(host->dev->of_node,
-                                rockchip_compat[idx].compatible))
+                                rockchip_compat[idx].compatible)) {
                        priv->ctrl_type = rockchip_compat[idx].ctrl_type;
+                       host->cid = priv->ctrl_type;
+                       host->grf = syscon_regmap_lookup_by_phandle(host->dev->of_node,
+                                                               "rockchip,grf");
+               }
        }
 
        host->priv = priv;
@@ -142,7 +144,8 @@ static int dw_mci_rockchip_setup_clock(struct dw_mci *host)
 
        if ((priv->ctrl_type == DW_MCI_TYPE_RK3288) ||
                 (priv->ctrl_type == DW_MCI_TYPE_RK3036) ||
-                (priv->ctrl_type == DW_MCI_TYPE_RK312X))
+                (priv->ctrl_type == DW_MCI_TYPE_RK312X) ||
+               (priv->ctrl_type == DW_MCI_TYPE_RK3368))
                host->bus_hz /= (priv->ciu_div + 1);
 
        return 0;
@@ -185,6 +188,9 @@ static inline void dw_mci_rockchip_set_delaynum(struct dw_mci *host, u8 con_id,
                 con_id, tuning_type, regs, mmc_hostname(host->mmc));
 
         cru_writel(regs, CRU_SDMMC_CON(con_id, tuning_type));
+
+       MMC_DBG_INFO_FUNC(host->mmc,"CRU_SDMMC_CON(con_id, tuning_type) = 0x%x, regs = 0x%x [%s]",
+                       CRU_SDMMC_CON(con_id, tuning_type), cru_readl(CRU_SDMMC_CON(con_id, tuning_type)), mmc_hostname(host->mmc));
 }
 
 static inline void dw_mci_rockchip_set_degree(struct dw_mci *host, u8 con_id, u8 tuning_type, u8 phase)
@@ -200,6 +206,8 @@ static inline void dw_mci_rockchip_set_degree(struct dw_mci *host, u8 con_id, u8
                 con_id, tuning_type, regs, mmc_hostname(host->mmc));
        
        cru_writel(regs, CRU_SDMMC_CON(con_id, tuning_type));
+       MMC_DBG_INFO_FUNC(host->mmc,"CRU_SDMMC_CON(con_id, tuning_type) = 0x%x, regs = 0x%x [%s]",
+               CRU_SDMMC_CON(con_id, tuning_type), cru_readl(CRU_SDMMC_CON(con_id, tuning_type)), mmc_hostname(host->mmc));
 }
 
 static inline void dw_mci_rockchip_turning_sel(struct dw_mci *host, u8 con_id, u8 tuning_type, u8 mode)
@@ -267,14 +275,34 @@ static void dw_mci_rockchip_load_signal_integrity(struct dw_mci *host, u32 sr, u
                         grf_writel(0x000c0006, 0x01e4); /* GPIO3B1 */
                         grf_writel(0x003f0015, 0x01e8); /* GPIO3C2-C0 */
                 }
-        }
+        } else if (host->cid == DW_MCI_TYPE_RK3368) {
+                if (host->mmc->restrict_caps & RESTRICT_CARD_TYPE_SDIO) {
+                       regmap_write(host->grf, 0x21c, 0xff000000 | (drv << 14) | (drv << 12) |
+                                               (drv << 10) | (drv << 8)); /* GPIO2D4-D7 */
+                       regmap_write(host->grf, 0x220, 0x000f0000 | (drv << 0) | (drv << 2)); /* GPIO3A0-A1 */
+               }else if (host->mmc->restrict_caps & RESTRICT_CARD_TYPE_SD) {
+                       regmap_write(host->grf, 0x210, 0xfc000000 | (drv << 10) | (drv << 12) | (drv << 14)); /* GPIO2A5-A7 */
+                       regmap_write(host->grf, 0x214, 0x003f0000 | (drv << 0) | (drv << 2) | (drv << 4)); /* GPIO2B0-2 */
+               }else if (host->mmc->restrict_caps & RESTRICT_CARD_TYPE_EMMC) {
+                       regmap_write(host->grf, 0x208, 0xfff00000 | (drv << 4) | (drv << 6) | (drv << 8) | (drv << 10) 
+                                                               | (drv << 12) | (drv << 14)); /* GPIO1C2-C7 */
+                       regmap_write(host->grf, 0x20c, 0x003f0000 | (drv << 0) | (drv << 2) | (drv << 4)); /* GPIO1D0-D2 */
+                       regmap_write(host->grf, 0x210, 0x03000000 | (drv << 8)); /* GPIO2A4 */
+               }
+       }
 
 }
-static void dw_mci_rockchip_load_tuning_base(void)
+static void dw_mci_rockchip_load_tuning_base(struct dw_mci *host)
 {
         /* load tuning base */
-        if(cpu_is_rk3288())
+        if (cpu_is_rk3288()) {
                 cru_tuning_base =  RK3288_CRU_SDMMC_CON0;
+       } else if (host->cid == DW_MCI_TYPE_RK3368) {
+               if (IS_ERR(host->grf))
+                       pr_err("rk_sdmmc: dts couldn't find grf regmap\n");
+
+               cru_tuning_base =  0x400;
+       }
 }
 
 static int inline __dw_mci_rockchip_execute_tuning(struct dw_mci_slot *slot, u32 opcode,
@@ -339,7 +367,7 @@ static int dw_mci_rockchip_execute_tuning(struct dw_mci_slot *slot, u32 opcode,
 
        MMC_DBG_INFO_FUNC(host->mmc,"execute tuning:  [%s]", mmc_hostname(host->mmc));
 
-       dw_mci_rockchip_load_tuning_base();
+       dw_mci_rockchip_load_tuning_base(host);
 
        blk_test = kmalloc(blksz, GFP_KERNEL);
        if (!blk_test)
@@ -381,8 +409,8 @@ static int dw_mci_rockchip_execute_tuning(struct dw_mci_slot *slot, u32 opcode,
                                         "execute tuning: TOO LARGE STEP![%s]", mmc_hostname(host->mmc));
                 }
                 MMC_DBG_INFO_FUNC(host->mmc,
-                                "execute tuning: SOC is UNKNOWN, step = %d[%s]",
-                                step, mmc_hostname(host->mmc));
+                                "execute tuning: SOC id is %d, step = %d[%s]",
+                                host->cid, step, mmc_hostname(host->mmc));
         }
 
 re_phase:
@@ -394,7 +422,7 @@ re_phase:
 
         dw_mci_rockchip_load_signal_integrity(host, SLEW_RATE_SLOW, default_drv);
         /* Loop degree from 0 ~ 270 */
-        for(start_degree = SDMMC_SHIFT_DEGREE_0; start_degree < SDMMC_SHIFT_DEGREE_270; start_degree++){
+        for(start_degree = SDMMC_SHIFT_DEGREE_0; start_degree <= SDMMC_SHIFT_DEGREE_270; start_degree++){
                 dw_mci_rockchip_set_degree(host, tuning_data->con_id, tuning_data->tuning_type, start_degree);
                 if(0 == __dw_mci_rockchip_execute_tuning(slot, opcode, blk_test, blksz)){
                         if(!memcmp(blk_pattern, blk_test, blksz)){
@@ -458,7 +486,17 @@ re_phase:
                 ret = 0;
                goto done;  
                 #endif       
-        }else if((candidates_degree[0]==SDMMC_SHIFT_DEGREE_0) 
+        }else if((candidates_degree[0]==SDMMC_SHIFT_DEGREE_0)
+               && (candidates_degree[1]==SDMMC_SHIFT_DEGREE_180)
+               && (candidates_degree[2]==SDMMC_SHIFT_DEGREE_270)){
+               MMC_DBG_INFO_FUNC(host->mmc,
+                       "execute tuning: candidates_degree = SDMMC_SHIFT_DEGREE_0 AND SDMMC_SHIFT_DEGREE_180 AND SDMMC_SHIFT_DEGREE_270[%s]",
+                       mmc_hostname(host->mmc));
+               dw_mci_rockchip_set_degree(host, tuning_data->con_id, tuning_data->tuning_type, SDMMC_SHIFT_DEGREE_180);
+               dw_mci_rockchip_set_delaynum(host, tuning_data->con_id, tuning_data->tuning_type, step);
+               ret = 0;
+               goto done;
+       }else if((candidates_degree[0]==SDMMC_SHIFT_DEGREE_0) 
                 && (candidates_degree[1]==SDMMC_SHIFT_DEGREE_180)){
 
                 MMC_DBG_INFO_FUNC(host->mmc,
index 15966783dbca7def5b536ab10935abce6d9724ce..1d9e5a3f507124740539e61e639be6ce9eb6a8d2 100755 (executable)
@@ -46,6 +46,8 @@
 #include <linux/clk-private.h>
 #include <linux/rockchip/cpu.h>
 #include <linux/rfkill-wlan.h>
+#include <linux/mfd/syscon.h>
+#include <linux/regmap.h>
 #include "rk_sdmmc.h"
 #include "rk_sdmmc_dbg.h"
 #include <linux/regulator/rockchip_io_vol_domain.h>
@@ -1804,12 +1806,17 @@ static void dw_mci_do_grf_io_domain_switch(struct dw_mci *host, u32 voltage)
                         break;
         }
 
-        if(cpu_is_rk3288()){
+        if (cpu_is_rk3288()) {
                 if(host->mmc->restrict_caps & RESTRICT_CARD_TYPE_SD)      
                         grf_writel((voltage << 7) | (1 << 23), RK3288_GRF_IO_VSEL);
                 else
                         return ;
-        }else{
+        } else if (host->cid == DW_MCI_TYPE_RK3368) {
+               if(host->mmc->restrict_caps & RESTRICT_CARD_TYPE_SD)
+                        regmap_write(host->grf, 0x900, (voltage << 6) | (1 << 22));    
+               else
+                       return;
+       } else {
                 MMC_DBG_ERR_FUNC(host->mmc,"%s : unknown chip [%s]\n",
                                         __FUNCTION__, mmc_hostname(host->mmc));
         }
@@ -4181,6 +4188,8 @@ int dw_mci_resume(struct dw_mci *host)
                 else if(cpu_is_rk312x())
                         /* RK3036_GRF_SOC_CON0 is compatible with rk312x, tmp setting */
                         grf_writel(((1 << 8) << 16) | (0 << 8), RK3036_GRF_SOC_CON0);
+               else if(host->cid == DW_MCI_TYPE_RK3368)
+                       regmap_write(host->grf, 0x43c, ((1 << 13) << 16) | (0 << 13));
        }
        if(host->vmmc){
                ret = regulator_enable(host->vmmc);
index d3ed86bb6a20f365f1d8c7bac365b7e1980ca514..f4ed8e440d1e867c74e473241fdf6dea15ffd744 100755 (executable)
@@ -344,4 +344,14 @@ struct dw_mci_drv_data {
        int             (*execute_tuning)(struct dw_mci_slot *slot, u32 opcode,
                                        struct dw_mci_tuning_data *tuning_data);
 };
+
+/* Variations in Rockchip specific dw-mshc controller */
+enum dw_mci_rockchip_type {
+         DW_MCI_TYPE_RK3188,
+         DW_MCI_TYPE_RK3288,
+         DW_MCI_TYPE_RK3036,
+         DW_MCI_TYPE_RK312X,
+         DW_MCI_TYPE_RK3368,
+};
+
 #endif /* _DW_MMC_H_ */
index 5c9118fd98777c74726fe2759c00d26cf9be5701..6f02751efca9fc6c56d610865b6964db37a197f7 100755 (executable)
@@ -214,6 +214,9 @@ struct dw_mci {
        struct pinctrl_state    *pins_default; /* Function port */
        struct pinctrl_state    *pins_idle;    /* Gpio port */
        struct pinctrl_state    *pins_udbg;    /* uart_dbg port */
+
+       u32     cid;
+       struct regmap   *grf;
 };
 
 /* DMA ops for Internal/External DMAC interface */