mmc: add support for rk3036
authorlintao <lintao@rock-chips.com>
Mon, 7 Jul 2014 09:39:37 +0000 (17:39 +0800)
committerlintao <lintao@rock-chips.com>
Mon, 7 Jul 2014 09:39:37 +0000 (17:39 +0800)
arch/arm/boot/dts/rk3036-pinctrl.dtsi
arch/arm/boot/dts/rk3036.dtsi
arch/arm/configs/rockchip_defconfig
drivers/mmc/host/Kconfig
drivers/mmc/host/dw_mmc-pltfm.c
drivers/mmc/host/dw_mmc-rockchip.c
drivers/mmc/host/rk_sdmmc.c
include/linux/mmc/rk_mmc.h

index d1d9d3b1c16d6257a5854d16afc06e89bc7b73e6..96cda83ef1498d492259efb7c6e4942950878c11 100755 (executable)
                        };
                };
                
+               gpio1_emmc0 {
+                        emmc0_clk: emmc0-clk {
+                                rockchip,pins = <EMMC_CLKOUT>;
+                                rockchip,pull = <VALUE_PULL_DISABLE>;
+                                rockchip,drive = <VALUE_DRV_DEFAULT>;
+                                //rockchip,tristate = <VALUE_TRI_DEFAULT>;
+                        };
+
+                        emmc0_cmd: emmc0-cmd {
+                                rockchip,pins = <EMMC_CMD>;
+                                rockchip,pull = <VALUE_PULL_UP>;
+                                rockchip,drive = <VALUE_DRV_DEFAULT>;
+                                //rockchip,tristate = <VALUE_TRI_DEFAULT>;
+                        };
+
+                    
+                        emmc0_bus1: emmc0-bus-width1 {
+                                rockchip,pins = <EMMC_D0>;
+                                rockchip,pull = <VALUE_PULL_UP>;
+                                rockchip,drive = <VALUE_DRV_DEFAULT>;
+                                //rockchip,tristate = <VALUE_TRI_DEFAULT>;
+                        };
+
+                        emmc0_bus4: emmc0-bus-width4 {
+                                rockchip,pins = <EMMC_D0>,
+                                                <EMMC_D1>,
+                                                <EMMC_D2 >,
+                                                <EMMC_D3>;
+                                rockchip,pull = <VALUE_PULL_UP>;
+                                rockchip,drive = <VALUE_DRV_DEFAULT>;
+                                //rockchip,tristate = <VALUE_TRI_DEFAULT>;
+                        };
+                };
+
+                gpio1_sdmmc0 {
+                        sdmmc0_clk: sdmmc0-clk {
+                                rockchip,pins = <MMC0_CLKOUT>;
+                                rockchip,pull = <VALUE_PULL_DISABLE>;
+                                rockchip,drive = <VALUE_DRV_DEFAULT>;
+                                //rockchip,tristate = <VALUE_TRI_DEFAULT>;
+                        };
+
+                        sdmmc0_cmd: sdmmc0-cmd {
+                                rockchip,pins = <MMC0_CMD>;
+                                rockchip,pull = <VALUE_PULL_UP>;
+                                rockchip,drive = <VALUE_DRV_DEFAULT>;
+                                //rockchip,tristate = <VALUE_TRI_DEFAULT>;
+                        };
+
+                        sdmmc0_dectn: sdmmc0-dectn{
+                                rockchip,pins = <MMC0_DETN>;
+                                rockchip,pull = <VALUE_PULL_UP>;
+                                rockchip,drive = <VALUE_DRV_DEFAULT>;
+                                //rockchip,tristate = <VALUE_TRI_DEFAULT>;
+                        };
+
+
+                        sdmmc0_bus1: sdmmc0-bus-width1 {
+                                rockchip,pins = <MMC0_D0>;
+                                rockchip,pull = <VALUE_PULL_UP>;
+                                rockchip,drive = <VALUE_DRV_DEFAULT>;
+                                //rockchip,tristate = <VALUE_TRI_DEFAULT>;
+                        };
+
+                        sdmmc0_bus4: sdmmc0-bus-width4 {
+                                rockchip,pins = <MMC0_D0>,
+                                                <MMC0_D1>,
+                                                <MMC0_D2>,
+                                                <MMC0_D3>;
+                                rockchip,pull = <VALUE_PULL_UP>;
+                                rockchip,drive = <VALUE_DRV_DEFAULT>;
+                                //rockchip,tristate = <VALUE_TRI_DEFAULT>;
+                        };
+
+                        sdmmc0_gpio: sdmmc0_gpio{
+                                rockchip,pins =
+                                        <GPIO1_B7>,  //CMD
+                                        <GPIO1_C0>,  //CLK
+                                        <GPIO1_C1>,  //DET
+                                        <GPIO1_C2>,  //D0
+                                        <GPIO1_C3>,  //D1
+                                       <GPIO1_C4>,  //D2
+                                        <GPIO1_C5>;  //D3
+                                rockchip,pull = <VALUE_PULL_UP>;
+                                rockchip,drive = <VALUE_DRV_DEFAULT>;
+                                //rockchip,tristate = <VALUE_TRI_DEFAULT>;
+                        };
+
+                };
+               gpio0_sdio0 {
+
+                sdio0_clk: sdio0_clk {
+                rockchip,pins = <MMC1_CLKOUT>;
+                rockchip,pull = <VALUE_PULL_DISABLE>;
+                rockchip,drive = <VALUE_DRV_DEFAULT>;
+                //rockchip,tristate = <VALUE_TRI_DEFAULT>;
+                };
+
+                sdio0_cmd: sdio0_cmd {
+                        rockchip,pins = <MMC1_CMD>;
+                        rockchip,pull = <VALUE_PULL_UP>;
+                        rockchip,drive = <VALUE_DRV_DEFAULT>;
+                        //rockchip,tristate = <VALUE_TRI_DEFAULT>;
+                };
+
+                sdio0_bus1: sdio0-bus-width1 {
+                        rockchip,pins = <MMC1_D0>;
+                        rockchip,pull = <VALUE_PULL_UP>;
+                        rockchip,drive = <VALUE_DRV_DEFAULT>;
+                        //rockchip,tristate = <VALUE_TRI_DEFAULT>;
+                };
+
+                sdio0_bus4: sdio0-bus-width4 {
+                        rockchip,pins = <MMC1_D0>,
+                        <MMC1_D1>,
+                        <MMC1_D2>,
+                        <MMC1_D3>;
+                        rockchip,pull = <VALUE_PULL_UP>;
+                        rockchip,drive = <VALUE_DRV_DEFAULT>;
+                        //rockchip,tristate = <VALUE_TRI_DEFAULT>;
+                };
+
+                sdio0_gpio: sdio0-all-gpio{
+                                        rockchip,pins =
+                                                <GPIO0_B1>,   //CLK
+                                                <GPIO0_B0>,   //CMD
+                                                <GPIO0_B3>,   //DO
+                                                <GPIO0_B4>,   //D1
+                                                <GPIO0_B5>,   //D2
+                                                <GPIO0_B6>;   //D3
+                                        rockchip,pull = <VALUE_PULL_UP>;
+                                        rockchip,drive = <VALUE_DRV_DEFAULT>;
+                                        //rockchip,tristate = <VALUE_TRI_DEFAULT>;
+                                };
+                };
 
                vol_domain {
                        ap0_vcc:ap0-vcc {
index d970a9fb382a7597f2c8c61160d112ef9dc07847..572a94762ed13534073f1d3f1f13f9f8834bf3a0 100755 (executable)
                //pinctrl-0 = <&sd0_clk &sd0_cmd &sd0_cd &sd0_wp &sd0_pwr &sd0_bus1 &sd0_bus4>;
                clocks = <&clk_emmc>, <&clk_gates7 0>;
                clock-names = "clk_mmc", "hclk_mmc";
+               dmas = <&pdma 12>;
+               dma-names = "dw_mci";
                num-slots = <1>;
                fifo-depth = <0x100>;
                bus-width = <8>;
                interrupts = <GIC_SPI 14 IRQ_TYPE_LEVEL_HIGH>;
                #address-cells = <1>;
                #size-cells = <0>;
-               //pinctrl-names = "default", "idle";
-               //pinctrl-0 = <&sdmmc0_clk &sdmmc0_cmd &sdmmc0_dectn &sdmmc0_bus4>;
-               //pinctrl-1 = <&sdmmc0_gpio>;
-               //cd-gpios = <&gpio1 GPIO_C1 GPIO_ACTIVE_HIGH>;/*CD GPIO*/
+               pinctrl-names = "default", "idle";
+               pinctrl-0 = <&sdmmc0_clk &sdmmc0_cmd &sdmmc0_dectn &sdmmc0_bus4>;
+               pinctrl-1 = <&sdmmc0_gpio>;
+               cd-gpios = <&gpio1 GPIO_C1 GPIO_ACTIVE_HIGH>;/*CD GPIO*/
                clocks = <&clk_sdmmc0>, <&clk_gates2 11>;
                clock-names = "clk_mmc", "hclk_mmc";
+               dmas = <&pdma 10>;
+               dma-names = "dw_mci";
                num-slots = <1>;
                fifo-depth = <0x100>;
                bus-width = <4>;
                interrupts = <GIC_SPI 15 IRQ_TYPE_LEVEL_HIGH>;
                #address-cells = <1>;
                #size-cells = <0>;
-               //pinctrl-names = "default","idle";
-               //pinctrl-0 = <&sdio_clk &sdio_cmd &sdio_wrprt &sdio_pwr &sdio_bkpwr &sdio_intn &sdio_bus4>;
-               //pinctrl-1 = <&sdio_gpio>;
+               pinctrl-names = "default","idle";
+               pinctrl-0 = <&sdio0_clk &sdio0_cmd  &sdio0_bus4>;
+               pinctrl-1 = <&sdio0_gpio>;
                clocks = <&clk_sdio>, <&clk_gates5 11>;
                clock-names = "clk_mmc", "hclk_mmc";
+               dmas = <&pdma 11>;
+               dma-names = "dw_mci";
                num-slots = <1>;
                fifo-depth = <0x100>;
                bus-width = <4>;
index 5087295107d5d4474468c5e04791fd214025604a..0145c131c55b74ab303f39791a825c3d6427fe22 100644 (file)
@@ -478,7 +478,8 @@ CONFIG_MMC_PARANOID_SD_INIT=y
 CONFIG_MMC_BLOCK_MINORS=32
 # CONFIG_MMC_BLOCK_BOUNCE is not set
 CONFIG_MMC_DW=y
-CONFIG_MMC_DW_IDMAC=y
+#CONFIG_MMC_DW_IDMAC is not set
+CONFIG_MMC_DW_EDMAC=y
 CONFIG_MMC_DW_ROCKCHIP=y
 CONFIG_LEDS_GPIO=y
 CONFIG_LEDS_TRIGGERS=y
index d34baf9a47d5f5f8879e42729ade4fa3d03816a3..41351e81a3bf7711cd14e631a2a9afbeaa0213be 100755 (executable)
@@ -541,7 +541,6 @@ config MMC_DW_EDMAC
           Designware Mobile Storage IP block. This disables the internal DMA
           interface.
 
-
 config MMC_DW_PLTFM
        tristate "Synopsys Designware MCI Support as platform device"
        depends on MMC_DW
index 93fc6a725dbae14e8a82964ea916097af0a6696b..527b2c8d86fdf259676880e2b0d04ab832406c6f 100755 (executable)
@@ -49,6 +49,9 @@ int dw_mci_pltfm_register(struct platform_device *pdev,
        host->irq_flags = 0;
        host->pdata = pdev->dev.platform_data;
        host->regs = devm_ioremap_resource(&pdev->dev, regs);
+        #ifdef CONFIG_MMC_DW_EDMAC
+        host->phy_regs = (void *)(regs->start);
+        #endif
        if (IS_ERR(host->regs))
                return PTR_ERR(host->regs);
 
index 69b1cf3d9e9efa716536e233830d233adf8bd925..8e17e6111eb4bfd883f5161c0f238f162372a61f 100755 (executable)
@@ -105,14 +105,14 @@ static int dw_mci_rockchip_priv_init(struct dw_mci *host)
        int idx;
 
        priv = devm_kzalloc(host->dev, sizeof(*priv), GFP_KERNEL);
-       if (!priv) {
+       if(!priv){
                dev_err(host->dev, "mem alloc failed for private data\n");
                return -ENOMEM;
        }
 
-       for (idx = 0; idx < ARRAY_SIZE(rockchip_compat); idx++) {
-               if (of_device_is_compatible(host->dev->of_node,
-                                       rockchip_compat[idx].compatible))
+       for(idx = 0; idx < ARRAY_SIZE(rockchip_compat); idx++){
+                if(of_device_is_compatible(host->dev->of_node,
+                                rockchip_compat[idx].compatible))
                        priv->ctrl_type = rockchip_compat[idx].ctrl_type;
        }
 
@@ -124,7 +124,7 @@ static int dw_mci_rockchip_setup_clock(struct dw_mci *host)
 {
        struct dw_mci_rockchip_priv_data *priv = host->priv;
 
-       if ((priv->ctrl_type == DW_MCI_TYPE_RK3288) || 
+       if ((priv->ctrl_type == DW_MCI_TYPE_RK3288) ||
                (priv->ctrl_type == DW_MCI_TYPE_RK3036))
                host->bus_hz /= (priv->ciu_div + 1);
 
@@ -133,8 +133,7 @@ static int dw_mci_rockchip_setup_clock(struct dw_mci *host)
 
 static void dw_mci_rockchip_prepare_command(struct dw_mci *host, u32 *cmdr)
 {
-//     if (SDMMC_CLKSEL_GET_DRV_WD3(mci_readl(host, CLKSEL)))
-//             *cmdr |= SDMMC_CMD_USE_HOLD_REG;
+
 }
 
 static void dw_mci_rockchip_set_ios(struct dw_mci *host, struct mmc_ios *ios)
@@ -310,10 +309,8 @@ static int dw_mci_rockchip_execute_tuning(struct dw_mci_slot *slot, u32 opcode,
            So we take average --- 60ps, (1.66ns/ 2) = 0.83(middle-value),TAKE 0.9
            0.9 / 60ps = 15 delayline
          */
-        if(cpu_is_rk3288()){ 
-                /*
-                        Fixme: 3036:  dose it compatitable?
-                */
+        if(cpu_is_rk3288()){
+                /* Fixme: 3036:  dose it compatitable? */
                  ref = ((FREQ_REF_150MHZ + host->bus_hz - 1) / host->bus_hz);
                  step = (15 * ref);
 
index 70af9f1b53456e696c450664ac116e686b164ce5..1bba0bfd8377adcc41343489d30a31abf7365a75 100755 (executable)
@@ -49,9 +49,6 @@
 #include <linux/regulator/rockchip_io_vol_domain.h>
 #include "../../clk/rockchip/clk-ops.h"
 
-/*
-        Fixme: 3036: RK_GRF_VIRT compatitable?
-*/
 #define grf_writel(v, offset)   do { writel_relaxed(v, RK_GRF_VIRT + offset); dsb(); } while (0)
 
 #define RK_SDMMC_DRIVER_VERSION "Ver 1.11 2014-06-05" 
@@ -457,25 +454,26 @@ static void dw_mci_idmac_stop_dma(struct dw_mci *host)
 static void dw_mci_idmac_complete_dma(void *arg)
 {
         struct dw_mci *host = arg;
-       struct mmc_data *data = host->data;
+        struct mmc_data *data = host->data;
+
+        dev_vdbg(host->dev, "DMA complete\n");
 
-       dev_vdbg(host->dev, "DMA complete\n");
+        /*
+        MMC_DBG_CMD_FUNC(host->mmc," DMA complete cmd=%d(arg=0x%x), blocks=%d,blksz=%d[%s]", \
+                host->mrq->cmd->opcode,host->mrq->cmd->arg,
+                data->blocks,data->blksz,mmc_hostname(host->mmc));
+        */
 
-    /*
-    MMC_DBG_CMD_FUNC(host->mmc," DMA complete cmd=%d(arg=0x%x), blocks=%d,blksz=%d[%s]", \
-        host->mrq->cmd->opcode,host->mrq->cmd->arg,data->blocks,data->blksz,mmc_hostname(host->mmc));
-    */
-    
-       host->dma_ops->cleanup(host);
+        host->dma_ops->cleanup(host);
 
        /*
         * If the card was removed, data will be NULL. No point in trying to
         * send the stop command or waiting for NBUSY in this case.
         */
-       if (data) {
-               set_bit(EVENT_XFER_COMPLETE, &host->pending_events);
-               tasklet_schedule(&host->tasklet);
-       }
+        if(data){
+                set_bit(EVENT_XFER_COMPLETE, &host->pending_events);
+                tasklet_schedule(&host->tasklet);
+        }
 }
 
 static void dw_mci_translate_sglist(struct dw_mci *host, struct mmc_data *data,
@@ -593,12 +591,11 @@ static void dw_mci_edmac_complete_dma(void *arg)
 
         dev_vdbg(host->dev, "DMA complete\n");
 
-        if(data->flags & MMC_DATA_READ)
-        {
-                /* Invalidate cache after read */
-                dma_sync_sg_for_cpu(host->dms->ch->device->dev, data->sg,
-                        data->sg_len, DMA_FROM_DEVICE);
-        }
+        if(data)
+                if(data->flags & MMC_DATA_READ)
+                        /* Invalidate cache after read */
+                        dma_sync_sg_for_cpu(mmc_dev(host->mmc), data->sg,
+                                data->sg_len, DMA_FROM_DEVICE);
 
         host->dma_ops->cleanup(host);
 
@@ -620,62 +617,59 @@ static void dw_mci_edmac_start_dma(struct dw_mci *host, unsigned int sg_len)
         u32 sg_elems = host->data->sg_len;
         int ret = 0;
 
-       /* set external dma config: burst size, burst width*/
-       if(host->data->flags & MMC_DATA_WRITE){
-                slave_config.direction = DMA_MEM_TO_DEV;
-                slave_config.dst_addr = (dma_addr_t)(host->regs + host->data_offset);
-                slave_config.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
-                //slave_config.dst_maxburst = 16;
-                slave_config.dst_maxburst = ((host->fifoth_val) >> 28) && 0x7;
+        /* Set external dma config: burst size, burst width*/
+        slave_config.dst_addr = (dma_addr_t)(host->phy_regs + host->data_offset);
+        slave_config.src_addr = slave_config.dst_addr;
+        slave_config.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+        slave_config.src_addr_width = slave_config.dst_addr_width;
+
+        /* Match FIFO dma burst MSIZE with external dma config*/
+        slave_config.dst_maxburst = ((host->fifoth_val) >> 28) && 0x7;
+        slave_config.src_maxburst = slave_config.dst_maxburst;
 
+        if(host->data->flags & MMC_DATA_WRITE){
+                slave_config.direction = DMA_MEM_TO_DEV;
                 ret = dmaengine_slave_config(host->dms->ch, &slave_config);
-                if (ret) {
+                if(ret){
                         dev_err(host->dev, "error in dw_mci edma configuration.\n");
                         return;
                 }
 
                 desc = dmaengine_prep_slave_sg(host->dms->ch, sgl, sg_len,
                                 DMA_MEM_TO_DEV, DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
-                if (!desc) {
-                       dev_err(host->dev, "We cannot prepare for the dw_mci slave edma!\n");
-                       return;
-               }
-                /* set dw_mci_edmac_complete_dma as callback */
-               desc->callback = dw_mci_edmac_complete_dma;
-               desc->callback_param = (void *)host;
-               dmaengine_submit(desc);
+                if(!desc){
+                        dev_err(host->dev, "We cannot prepare for the dw_mci slave edma!\n");
+                        return;
+                }
+                /* Set dw_mci_edmac_complete_dma as callback */
+                desc->callback = dw_mci_edmac_complete_dma;
+                desc->callback_param = (void *)host;
+                dmaengine_submit(desc);
 
-               /* Flush cache before write */
-                dma_sync_sg_for_device(host->dms->ch->device->dev, sgl,
+                /* Flush cache before write */
+                dma_sync_sg_for_device(mmc_dev(host->mmc), sgl,
                                         sg_elems, DMA_TO_DEVICE);
                 dma_async_issue_pending(host->dms->ch);
-       }else{
+        }else{
                 /* MMC_DATA_READ*/
                 slave_config.direction = DMA_DEV_TO_MEM;
-                slave_config.src_addr = (dma_addr_t)(host->regs + host->data_offset);
-                slave_config.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
-                //slave_config.src_maxburst = 16;
-                slave_config.dst_maxburst = ((host->fifoth_val) >> 28) && 0x7;
-
                 ret = dmaengine_slave_config(host->dms->ch, &slave_config);
-                if (ret) {
+                if(ret){
                         dev_err(host->dev, "error in dw_mci edma configuration.\n");
                         return;
                 }
                 desc = dmaengine_prep_slave_sg(host->dms->ch, sgl, sg_len,
-                       DMA_DEV_TO_MEM, DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
-                if (!desc) {
-                       dev_err(host->dev, "We cannot prepare for the dw_mci slave edma!\n");
-                       return;
-               }
-                /* set dw_mci_edmac_complete_dma as callback */
-               desc->callback = dw_mci_edmac_complete_dma;
-               desc->callback_param = (void *)host;
-               dmaengine_submit(desc);
-               dma_async_issue_pending(host->dms->ch);
-       }
-
-       return;
+                                DMA_DEV_TO_MEM, DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+                if(!desc){
+                        dev_err(host->dev, "We cannot prepare for the dw_mci slave edma!\n");
+                        return;
+                }
+                /* set dw_mci_edmac_complete_dma as callback */
+                desc->callback = dw_mci_edmac_complete_dma;
+                desc->callback_param = (void *)host;
+                dmaengine_submit(desc);
+                dma_async_issue_pending(host->dms->ch);
+        }
 }
 
 static int dw_mci_edmac_init(struct dw_mci *host)
@@ -684,17 +678,17 @@ static int dw_mci_edmac_init(struct dw_mci *host)
                                 (unsigned int)(rockchip_soc_id & ROCKCHIP_CPU_MASK), mmc_hostname(host->mmc));
 
         /* 1) request external dma channel, SHOULD decide chn in dts */
+        host->dms = (struct dw_mci_dma_slave *)kmalloc(sizeof(struct dw_mci_dma_slave),GFP_KERNEL);
         host->dms->ch = dma_request_slave_channel(host->dev, "dw_mci");
-        if (!host->dms->ch)
-       {
-               dev_err(host->dev, "Failed to get external DMA channel: channel id = %d\n",
-                               host->dms->ch->chan_id);
-               goto err_exit;
-       }
+        if (!host->dms->ch){
+                dev_err(host->dev, "Failed to get external DMA channel: channel id = %d\n",
+                                host->dms->ch->chan_id);
+                goto err_exit;
+        }
 
         /* anything? */
 
-       return 0;
+        return 0;
 
 err_exit:
         return -ENODEV;
@@ -715,7 +709,6 @@ static const struct dw_mci_dma_ops dw_mci_edmac_ops = {
         .cleanup = dw_mci_edma_cleanup,
 };
 #endif
-
 static int dw_mci_pre_dma_transfer(struct dw_mci *host,
                                   struct mmc_data *data,
                                   bool next)
@@ -1066,7 +1059,7 @@ static void dw_mci_setup_bus(struct dw_mci_slot *slot, bool force_clkinit)
                        MMC_DBG_BOOT_FUNC(host->mmc,
                                 "dw_mci_setup_bus: argue clk_mmc workaround out %dHz for init[%s]",
                                 clock * 2, mmc_hostname(host->mmc)); 
-                        /* RK3288 clk_mmc will change parents to 24MHz xtal*/
+                        /* clk_mmc will change parents to 24MHz xtal*/
                        clk_set_rate(host->clk_mmc, clock * 2);                
 
                        div = 0;
@@ -1501,7 +1494,6 @@ static int dw_mci_get_cd(struct mmc_host *mmc)
        else
                present = (mci_readl(slot->host, CDETECT) & (1 << slot->id))
                        == 0 ? 1 : 0;
-
        spin_lock_bh(&host->lock);
        if (present) {
                set_bit(DW_MMC_CARD_PRESENT, &slot->flags);
@@ -1679,26 +1671,32 @@ enum{
         IO_DOMAIN_33 = 3300,
 };
 static void dw_mci_do_grf_io_domain_switch(struct dw_mci *host, u32 voltage)
-{       
-        /*
-                Fixme: 3036:  RK3288_GRF_IO_VSEL compatitable?
-        */
-
-        if(cpu_is_rk3288()){
-               if(voltage == IO_DOMAIN_33)
+{
+        switch(voltage){
+                case IO_DOMAIN_33:
                         voltage = 0;
-                else if(voltage == IO_DOMAIN_18)
+                        break;
+                case IO_DOMAIN_18:
                         voltage = 1;
-                else
-                     MMC_DBG_ERR_FUNC(host->mmc,"%s : err io domain voltage [%s]\n", 
-                          __FUNCTION__, mmc_hostname(host->mmc));
+                        break;
+                case IO_DOMAIN_12:
+                        MMC_DBG_ERR_FUNC(host->mmc,"%s : Not support io domain voltage [%s]\n",
+                                                        __FUNCTION__, mmc_hostname(host->mmc));
+                        break;
+                default:
+                        MMC_DBG_ERR_FUNC(host->mmc,"%s : Err io domain voltage [%s]\n",
+                                                        __FUNCTION__, mmc_hostname(host->mmc));
+                        break;
+        }
+
+        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{
-                 MMC_DBG_ERR_FUNC(host->mmc,"%s : unknown chip [%s]\n", 
-                          __FUNCTION__, mmc_hostname(host->mmc));
+                MMC_DBG_ERR_FUNC(host->mmc,"%s : unknown chip [%s]\n",
+                                        __FUNCTION__, mmc_hostname(host->mmc));
         }
 }
 
@@ -1834,6 +1832,13 @@ static int dw_mci_execute_tuning(struct mmc_host *mmc, u32 opcode)
        struct dw_mci_tuning_data tuning_data;
        int err = -ENOSYS;
 
+        /* Fixme: 3036/3126 doesn't support 1.8 io domain, no sense exe tuning
+        if(cpu_is_3036() || cpu_is_3126())
+                return ENOSYS;
+        AND
+                what about audi-b?
+        */
+
        if (opcode == MMC_SEND_TUNING_BLOCK_HS200) {
                if (mmc->ios.bus_width == MMC_BUS_WIDTH_8) {
                        tuning_data.blk_pattern = tuning_blk_pattern_8bit;
@@ -1946,7 +1951,8 @@ static void dw_mci_request_end(struct dw_mci *host, struct mmc_request *mrq)
        struct mmc_host *prev_mmc = host->cur_slot->mmc;
 
        WARN_ON(host->cmd || host->data);
-       
+
+       del_timer_sync(&host->dto_timer);
         dw_mci_deal_data_end(host, mrq);
 
         if(mrq->cmd)
@@ -2007,19 +2013,23 @@ static void dw_mci_command_complete(struct dw_mci *host, struct mmc_command *cmd
        {
            if(host->mmc->restrict_caps & RESTRICT_CARD_TYPE_SDIO)
                host->cmd_rto += 1;
-               
-               cmd->error = -ETIMEDOUT;
-       }
-       else if ((cmd->flags & MMC_RSP_CRC) && (status & SDMMC_INT_RCRC))
+
+               cmd->error = -ETIMEDOUT;
+                del_timer_sync(&host->dto_timer);
+       }else if ((cmd->flags & MMC_RSP_CRC) && (status & SDMMC_INT_RCRC)){
+                del_timer_sync(&host->dto_timer);
                cmd->error = -EILSEQ;
-       else if (status & SDMMC_INT_RESP_ERR)
+        }else if (status & SDMMC_INT_RESP_ERR){
+                del_timer_sync(&host->dto_timer);
                cmd->error = -EIO;
-       else
+        }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));
 
        if (cmd->error) {
+                del_timer_sync(&host->dto_timer);
            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]",\
@@ -2074,21 +2084,23 @@ static void dw_mci_tasklet_func(unsigned long priv)
                                goto unlock;
                        }
                        
-            if (cmd->data && cmd->error) {
+                        if (cmd->data && cmd->error) {
+                                del_timer_sync(&host->dto_timer); /* delete the timer for INT_DTO */
                                dw_mci_stop_dma(host);
                                #if 1
-                if (data->stop) {
-                    send_stop_cmd(host, data);
-                    state = STATE_SENDING_STOP;
-                    break;
-                } else {
-                    host->data = NULL;
-                }
+                                if (data->stop) {
+                                        send_stop_cmd(host, data);
+                                        state = STATE_SENDING_STOP;
+                                        break;
+                                }else{
+                                        host->data = NULL;
+                                }
                                #else
                                send_stop_abort(host, data);
                                state = STATE_SENDING_STOP;
                                break;
                                #endif
+                                set_bit(EVENT_DATA_COMPLETE, &host->completed_events);
                        }
 
                        if (!host->mrq->data || cmd->error) {
@@ -2160,6 +2172,7 @@ static void dw_mci_tasklet_func(unsigned long priv)
                                break;
                                
                        dw_mci_deal_data_end(host, host->mrq);                  
+                       del_timer_sync(&host->dto_timer); //delete the timer for INT_DTO
                         MMC_DBG_INFO_FUNC(host->mmc, 
                                "Pre-state[%d]-->NowState[%d]: STATE_DATA_BUSY, after EVENT_DATA_COMPLETE. [%s]", \
                                           prev_state,state,mmc_hostname(host->mmc));
@@ -2704,12 +2717,27 @@ host_put:
 
 static void dw_mci_cmd_interrupt(struct dw_mci *host, u32 status)
 {
-       if (!host->cmd_status)
+        u32 multi, unit;
+
+        if (!host->cmd_status)
            host->cmd_status = status;
            
-       smp_wmb();
+       if(!host->cmd)
+               goto cmd_exit;
 
-       set_bit(EVENT_CMD_COMPLETE, &host->pending_events);
+       if((MMC_STOP_TRANSMISSION != host->cmd->opcode))
+        {
+                unit = 2*1024*1024;
+                multi = mci_readl(host, BYTCNT)/unit;
+                multi += ((mci_readl(host, BYTCNT) % unit) ? 1 :0 );
+                multi = (multi > 0) ? multi : 1;
+                multi += (host->cmd->retries > 2)? 2 : host->cmd->retries;
+                mod_timer(&host->dto_timer, jiffies + msecs_to_jiffies(4500 * multi));//max wait 8s larger
+        }
+
+cmd_exit:
+        smp_wmb();
+        set_bit(EVENT_CMD_COMPLETE, &host->pending_events);
        tasklet_schedule(&host->tasklet);
 }
 
@@ -2720,13 +2748,12 @@ static irqreturn_t dw_mci_interrupt(int irq, void *dev_id)
        int i;
 
        pending = mci_readl(host, MINTSTS); /* read-only mask reg */
-       //if(host->mmc->restrict_caps & RESTRICT_CARD_TYPE_SD)
-       //      printk("%s pending: 0x%08x\n",__func__,pending);        
+
        /*
-                * DTO fix - version 2.10a and below, and only if internal DMA
-                * is configured.
-                */
-               if (host->quirks & DW_MCI_QUIRK_IDMAC_DTO) {
+       * DTO fix - version 2.10a and below, and only if internal DMA
+       * is configured.
+        */
+        if (host->quirks & DW_MCI_QUIRK_IDMAC_DTO) {
                        if (!pending &&
                            ((mci_readl(host, STATUS) >> 17) & 0x1fff))
                                pending |= SDMMC_INT_DATA_OVER;
@@ -2757,6 +2784,7 @@ static irqreturn_t dw_mci_interrupt(int irq, void *dev_id)
 
                if (pending & SDMMC_INT_DATA_OVER) {
                        mci_writel(host, RINTSTS, SDMMC_INT_DATA_OVER);
+                       del_timer(&host->dto_timer); /* delete the timer for INT_DTO */
                        MMC_DBG_CMD_FUNC(host->mmc, "SDMMC_INT_DATA_OVER, INT-pending=0x%x. [%s]",pending,mmc_hostname(host->mmc));
                        if (!host->data_status)
                                host->data_status = pending;
@@ -2857,6 +2885,7 @@ static void dw_mci_work_routine_card(struct work_struct *work)
                        rk_send_wakeup_key();//wake up system
                        spin_lock_bh(&host->lock);
 
+                        del_timer(&host->dto_timer); /* delete the timer for INT_DTO */
                        /* Card change detected */
                        slot->last_detect_state = present;
 
@@ -2900,7 +2929,8 @@ static void dw_mci_work_routine_card(struct work_struct *work)
                                        if (mrq->stop)
                                                mrq->stop->error = -ENOMEDIUM;
                                                
-                    MMC_DBG_CMD_FUNC(host->mmc, "dw_mci_work--reqeuest done, cmd=%d [%s]",mrq->cmd->opcode, mmc_hostname(mmc));
+                                        MMC_DBG_CMD_FUNC(host->mmc, "dw_mci_work--reqeuest done, cmd=%d [%s]",
+                                                        mrq->cmd->opcode, mmc_hostname(mmc));
 
                                        spin_unlock(&host->lock);
                                        mmc_request_done(slot->mmc, mrq);
@@ -2924,7 +2954,7 @@ static void dw_mci_work_routine_card(struct work_struct *work)
                }
 
                mmc_detect_change(slot->mmc,
-                       msecs_to_jiffies(host->pdata->detect_delay_ms));
+                msecs_to_jiffies(host->pdata->detect_delay_ms));
        }
 }
 
@@ -3337,7 +3367,7 @@ static void dw_mci_init_dma(struct dw_mci *host)
        dev_info(host->dev, "Using internal DMA controller.\n");
 #elif defined(CONFIG_MMC_DW_EDMAC)
         host->dma_ops = &dw_mci_edmac_ops;
-        dev_info(host->dev, "Using external DMA controller.\n"); 
+        dev_info(host->dev, "Using external DMA controller.\n");
 #endif
 
        if (!host->dma_ops)
@@ -3504,6 +3534,72 @@ static struct dw_mci_board *dw_mci_parse_dt(struct dw_mci *host)
 }
 #endif /* CONFIG_OF */
 
+static void dw_mci_dealwith_timeout(struct dw_mci *host)
+{
+        u32 ret, i, regs;
+
+        switch(host->state){
+                case STATE_IDLE:
+                        break;
+                case STATE_SENDING_DATA:
+                case STATE_DATA_BUSY:
+                       host->data_status |= (SDMMC_INT_DCRC|SDMMC_INT_EBE);
+                       mci_writel(host, RINTSTS, SDMMC_INT_DRTO);  // clear interrupt
+                        set_bit(EVENT_DATA_COMPLETE, &host->pending_events);
+                        host->state = STATE_DATA_BUSY;
+                       if (!dw_mci_ctrl_all_reset(host)) {
+                                ret = -ENODEV;
+                                return ;
+                        }
+
+                        /* NO requirement to reclaim slave chn using external dmac */
+                        #ifdef CONFIG_MMC_DW_IDMAC
+                        if (host->use_dma && host->dma_ops->init)
+                               host->dma_ops->init(host);
+                        #endif
+
+                        /*
+                         * Restore the initial value at FIFOTH register
+                         * And Invalidate the prev_blksz with zero
+                         */
+                        mci_writel(host, FIFOTH, host->fifoth_val);
+                        host->prev_blksz = 0;
+                        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 | SDMMC_INT_VSI | DW_MCI_ERROR_FLAGS;
+                        if(!(host->mmc->restrict_caps & RESTRICT_CARD_TYPE_SDIO))
+                                regs |= SDMMC_INT_CD;
+                                mci_writel(host, INTMASK, regs);
+                        mci_writel(host, CTRL, SDMMC_CTRL_INT_ENABLE);
+                        for (i = 0; i < host->num_slots; i++) {
+                                struct dw_mci_slot *slot = host->slot[i];
+                                if (!slot)
+                                        continue;
+                                if (slot->mmc->pm_flags & MMC_PM_KEEP_POWER) {
+                                        dw_mci_set_ios(slot->mmc, &slot->mmc->ios);
+                                        dw_mci_setup_bus(slot, true);
+                                }
+                        }
+                        mci_writel(host, RINTSTS, 0xFFFFFFFF);
+                        tasklet_schedule(&host->tasklet);
+                        break;
+                default:
+                        break;
+    }
+}
+static void dw_mci_dto_timeout(unsigned long host_data)
+{
+       struct dw_mci *host = (struct dw_mci *) host_data;
+
+       disable_irq(host->irq);
+
+       host->data_status = SDMMC_INT_EBE;
+       mci_writel(host, RINTSTS, 0xFFFFFFFF);
+       dw_mci_dealwith_timeout(host);
+
+       enable_irq(host->irq);
+}
 int dw_mci_probe(struct dw_mci *host)
 {
        const struct dw_mci_drv_data *drv_data = host->drv_data;
@@ -3676,6 +3772,7 @@ int dw_mci_probe(struct dw_mci *host)
        else
                host->num_slots = ((mci_readl(host, HCON) >> 1) & 0x1F) + 1;
 
+        setup_timer(&host->dto_timer, dw_mci_dto_timeout, (unsigned long)host);
        /* We need at least one slot to succeed */
        for (i = 0; i < host->num_slots; i++) {
                ret = dw_mci_init_slot(host, i);
@@ -3745,38 +3842,35 @@ EXPORT_SYMBOL(dw_mci_probe);
 void dw_mci_remove(struct dw_mci *host)
 {
        int i;
+       del_timer_sync(&host->dto_timer);
 
-       if (host->use_dma && host->dma_ops->exit)
-               host->dma_ops->exit(host);
-
-       mci_writel(host, RINTSTS, 0xFFFFFFFF);
-       mci_writel(host, INTMASK, 0); /* disable all mmc interrupt first */
+        mci_writel(host, RINTSTS, 0xFFFFFFFF);
+        mci_writel(host, INTMASK, 0); /* disable all mmc interrupt first */
 
-       for (i = 0; i < host->num_slots; i++) {
-               dev_dbg(host->dev, "remove slot %d\n", i);
-               if (host->slot[i])
-                       dw_mci_cleanup_slot(host->slot[i], i);
-       }
+        for(i = 0; i < host->num_slots; i++){
+                dev_dbg(host->dev, "remove slot %d\n", i);
+                if(host->slot[i])
+                        dw_mci_cleanup_slot(host->slot[i], i);
+        }
 
-       /* disable clock to CIU */
-       mci_writel(host, CLKENA, 0);
-       mci_writel(host, CLKSRC, 0);
+        /* disable clock to CIU */
+        mci_writel(host, CLKENA, 0);
+        mci_writel(host, CLKSRC, 0);
 
-       destroy_workqueue(host->card_workqueue);
+        destroy_workqueue(host->card_workqueue);
 
-       if (host->use_dma && host->dma_ops->exit)
-               host->dma_ops->exit(host);
+        if(host->use_dma && host->dma_ops->exit)
+                host->dma_ops->exit(host);
 
-       if (host->vmmc){
-               regulator_disable(host->vmmc);
-               regulator_put(host->vmmc);
-       }
-               
-    if (!IS_ERR(host->clk_mmc))
-               clk_disable_unprepare(host->clk_mmc);
+        if(host->vmmc){
+                regulator_disable(host->vmmc);
+                regulator_put(host->vmmc);
+        }
+       if(!IS_ERR(host->clk_mmc))
+                clk_disable_unprepare(host->clk_mmc);
 
-    if (!IS_ERR(host->hclk_mmc))
-               clk_disable_unprepare(host->hclk_mmc);
+        if(!IS_ERR(host->hclk_mmc))
+                clk_disable_unprepare(host->hclk_mmc);
 }
 EXPORT_SYMBOL(dw_mci_remove);
 
@@ -3788,24 +3882,22 @@ EXPORT_SYMBOL(dw_mci_remove);
  */
 int dw_mci_suspend(struct dw_mci *host)
 {
-        if (host->vmmc)
+        if(host->vmmc)
                 regulator_disable(host->vmmc);
 
-        if (host->use_dma && host->dma_ops->exit)
+        if(host->use_dma && host->dma_ops->exit)
                 host->dma_ops->exit(host);
 
-        /* Only for sdmmc controller */
+        /*only for sdmmc controller*/
         if(host->mmc->restrict_caps & RESTRICT_CARD_TYPE_SD){
                 host->mmc->rescan_disable = 1;
+                if(cancel_delayed_work_sync(&host->mmc->detect))
+                       wake_unlock(&host->mmc->detect_wake_lock);
 
-                if (cancel_delayed_work_sync(&host->mmc->detect))
-                        wake_unlock(&host->mmc->detect_wake_lock);
-       
                 disable_irq(host->irq);
                 if(pinctrl_select_state(host->pinctrl, host->pins_idle) < 0)
-                       MMC_DBG_ERR_FUNC(host->mmc, "Idle pinctrl setting failed! [%s]",
-                               mmc_hostname(host->mmc));
-
+                        MMC_DBG_ERR_FUNC(host->mmc, "Idle pinctrl setting failed! [%s]",
+                                                mmc_hostname(host->mmc));
                 dw_mci_of_get_cd_gpio(host->dev,0,host->mmc);
                 mci_writel(host, RINTSTS, 0xFFFFFFFF);
                 mci_writel(host, INTMASK, 0x00);
@@ -3818,58 +3910,63 @@ EXPORT_SYMBOL(dw_mci_suspend);
 
 int dw_mci_resume(struct dw_mci *host)
 {
-        int i, ret, retry_cnt = 0;
-        u32 regs;
+       int i, ret, retry_cnt = 0;
+       u32 regs;
         struct dw_mci_slot *slot;
     
-        if(host->mmc->restrict_caps & RESTRICT_CARD_TYPE_SDIO){
+        if (host->mmc->restrict_caps & RESTRICT_CARD_TYPE_SDIO){
                 slot = mmc_priv(host->mmc);
+
                 if(!test_bit(DW_MMC_CARD_PRESENT, &slot->flags))
                         return 0;
         }
-
-        /*only for sdmmc controller*/
-       if(host->mmc->restrict_caps & RESTRICT_CARD_TYPE_SD){
+       /*only for sdmmc controller*/
+       if(host->mmc->restrict_caps & RESTRICT_CARD_TYPE_SD) {
                disable_irq_wake(host->mmc->slot.cd_irq);
-               mmc_gpio_free_cd(host->mmc);
+                mmc_gpio_free_cd(host->mmc);
                if(pinctrl_select_state(host->pinctrl, host->pins_default) < 0)
                         MMC_DBG_ERR_FUNC(host->mmc, "Default pinctrl setting failed! [%s]",
                                                 mmc_hostname(host->mmc));
-                host->mmc->rescan_disable = 0;
-                if(cpu_is_rk3288()) {
-                       /*
-                         Fixme: 3036:  RK3288_GRF_SOC_CON0 compatitable?
-                        */
-                        grf_writel(((1<<12)<<16)|(0<<12), RK3288_GRF_SOC_CON0);//disable jtag
-                }
-        }
-        if(host->vmmc){
-                ret = regulator_enable(host->vmmc);
-                if (ret){
-                        dev_err(host->dev,
-                                "failed to enable regulator: %d\n", ret);
-                        return ret;
-                }
-        }
+               host->mmc->rescan_disable = 0;
+               /* Disable jtag*/
+               if(cpu_is_rk3288())
+                        grf_writel(((1 << 12) << 16) | (0 << 12), RK3288_GRF_SOC_CON0);
+                /*
+                else if(cpu_is_rk3036())
+                        grf_writel(((1 << 11) << 16) | (0 << 11), RK3036_GRF_SOC_CON0);
+                else if(cpu_is_rk3126())
+                        TODO;
+                else if audi-b
+                        TODO;
+                */
+       }
+       if(host->vmmc){
+               ret = regulator_enable(host->vmmc);
+               if (ret){
+                       dev_err(host->dev,
+                               "failed to enable regulator: %d\n", ret);
+                       return ret;
+               }
+       }
        
-        if(!dw_mci_ctrl_all_reset(host)){
-                ret = -ENODEV;
-                return ret;
-        }
+       if(!dw_mci_ctrl_all_reset(host)){
+               ret = -ENODEV;
+               return ret;
+       }
 
-        if(host->use_dma && host->dma_ops->init)
-                host->dma_ops->init(host);
+       if(host->use_dma && host->dma_ops->init)
+               host->dma_ops->init(host);
 
        /*
         * Restore the initial value at FIFOTH register
         * And Invalidate the prev_blksz with zero
         */
-        mci_writel(host, FIFOTH, host->fifoth_val);
-        host->prev_blksz = 0;
+       mci_writel(host, FIFOTH, host->fifoth_val);
+       host->prev_blksz = 0;
        /* Put in max timeout */
-        mci_writel(host, TMOUT, 0xFFFFFFFF);
-        mci_writel(host, RINTSTS, 0xFFFFFFFF);
+       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 | SDMMC_INT_VSI |
                   DW_MCI_ERROR_FLAGS;
        if(!(host->mmc->restrict_caps & RESTRICT_CARD_TYPE_SDIO))
@@ -3882,8 +3979,8 @@ int dw_mci_resume(struct dw_mci *host)
        }   
 
        for(i = 0; i < host->num_slots; i++){
-               struct dw_mci_slot *slot = host->slot[i];
-               if (!slot)
+               struct dw_mci_slot *slot = host->slot[i];
+               if(!slot)
                        continue;
                if(slot->mmc->pm_flags & MMC_PM_KEEP_POWER){
                        dw_mci_set_ios(slot->mmc, &slot->mmc->ios);
index ffbabea05742a6c8fd79f0e069938efb1b74d98c..d808eb1e361d9dacfdf6d616a6caa6b97afb1b1b 100755 (executable)
@@ -17,6 +17,7 @@
 #include <linux/scatterlist.h>
 #include <linux/mmc/core.h>
 #include <linux/dmaengine.h>
+#include <linux/timer.h>
 
 #define MAX_MCI_SLOTS  2
 
@@ -36,14 +37,12 @@ enum {
        EVENT_DATA_ERROR,
        EVENT_XFER_ERROR
 };
-
 struct dw_mci_dma_slave {
        struct dma_chan *ch;
        enum dma_transfer_direction direction;
        unsigned int dmach;
 };
 
-
 struct mmc_data;
 
 /**
@@ -157,7 +156,8 @@ struct dw_mci {
 #endif
 
 #ifdef CONFIG_MMC_DW_EDMAC
-        struct dw_mci_dma_slave        *dms;
+        struct dw_mci_dma_slave *dms;
+        void                    *phy_regs;
 #endif
        u32                     cmd_status;
        u32                     data_status;
@@ -187,8 +187,10 @@ struct dw_mci {
        struct dw_mci_slot      *slot[MAX_MCI_SLOTS];
        struct mmc_host         *mmc;
        struct mmc_command      *pre_cmd;
-       unsigned int    hold_reg_flag;//to fix the hold_reg value
-
+        /* Fix the hold_reg value */
+        unsigned int    hold_reg_flag;
+        /* Timer for INT_DTO */
+        struct timer_list       dto_timer;
        /* FIFO push and pull */
        int                     fifo_depth;
        int                     data_shift;