sunxi: mmc: set transfer timeout according to byte_cnt.
[oweals/u-boot.git] / drivers / mmc / sunxi_mmc.c
index 623498187ef0255e6fd5a647819a7bdf4477f8e3..25f18adb67257359160803e92733a7ebaa938ac2 100644 (file)
@@ -9,6 +9,7 @@
  */
 
 #include <common.h>
+#include <errno.h>
 #include <malloc.h>
 #include <mmc.h>
 #include <asm/io.h>
@@ -37,7 +38,7 @@ static int sunxi_mmc_getcd_gpio(int sdc_no)
        case 2: return sunxi_name_to_gpio(CONFIG_MMC2_CD_PIN);
        case 3: return sunxi_name_to_gpio(CONFIG_MMC3_CD_PIN);
        }
-       return -1;
+       return -EINVAL;
 }
 
 static int mmc_resource_init(int sdc_no)
@@ -72,10 +73,12 @@ static int mmc_resource_init(int sdc_no)
        mmchost->mmc_no = sdc_no;
 
        cd_pin = sunxi_mmc_getcd_gpio(sdc_no);
-       if (cd_pin != -1) {
+       if (cd_pin >= 0) {
                ret = gpio_request(cd_pin, "mmc_cd");
-               if (!ret)
+               if (!ret) {
+                       sunxi_gpio_set_pull(cd_pin, SUNXI_GPIO_PULL_UP);
                        ret = gpio_direction_input(cd_pin);
+               }
        }
 
        return ret;
@@ -89,8 +92,13 @@ static int mmc_set_mod_clk(struct sunxi_mmc_host *mmchost, unsigned int hz)
                pll = CCM_MMC_CTRL_OSCM24;
                pll_hz = 24000000;
        } else {
+#ifdef CONFIG_MACH_SUN9I
+               pll = CCM_MMC_CTRL_PLL_PERIPH0;
+               pll_hz = clock_get_pll4_periph0();
+#else
                pll = CCM_MMC_CTRL_PLL6;
                pll_hz = clock_get_pll6();
+#endif
        }
 
        div = pll_hz / hz;
@@ -146,10 +154,15 @@ static int mmc_clk_io_on(int sdc_no)
        /* config ahb clock */
        setbits_le32(&ccm->ahb_gate0, 1 << AHB_GATE_OFFSET_MMC(sdc_no));
 
-#if defined(CONFIG_MACH_SUN6I) || defined(CONFIG_MACH_SUN8I)
+#ifdef CONFIG_SUNXI_GEN_SUN6I
        /* unassert reset */
        setbits_le32(&ccm->ahb_reset0_cfg, 1 << AHB_RESET_OFFSET_MMC(sdc_no));
 #endif
+#if defined(CONFIG_MACH_SUN9I)
+       /* sun9i has a mmc-common module, also set the gate and reset there */
+       writel(SUNXI_MMC_COMMON_CLK_GATE | SUNXI_MMC_COMMON_RESET,
+              SUNXI_MMC_COMMON_BASE + 4 * sdc_no);
+#endif
 
        return mmc_set_mod_clk(mmchost, 24000000);
 }
@@ -204,7 +217,7 @@ static int mmc_config_clock(struct mmc *mmc)
        return 0;
 }
 
-static void mmc_set_ios(struct mmc *mmc)
+static void sunxi_mmc_set_ios(struct mmc *mmc)
 {
        struct sunxi_mmc_host *mmchost = mmc->priv;
 
@@ -226,7 +239,7 @@ static void mmc_set_ios(struct mmc *mmc)
                writel(0x0, &mmchost->reg->width);
 }
 
-static int mmc_core_init(struct mmc *mmc)
+static int sunxi_mmc_core_init(struct mmc *mmc)
 {
        struct sunxi_mmc_host *mmchost = mmc->priv;
 
@@ -244,9 +257,11 @@ static int mmc_trans_data_by_cpu(struct mmc *mmc, struct mmc_data *data)
        const uint32_t status_bit = reading ? SUNXI_MMC_STATUS_FIFO_EMPTY :
                                              SUNXI_MMC_STATUS_FIFO_FULL;
        unsigned i;
-       unsigned byte_cnt = data->blocksize * data->blocks;
-       unsigned timeout_msecs = 2000;
        unsigned *buff = (unsigned int *)(reading ? data->dest : data->src);
+       unsigned byte_cnt = data->blocksize * data->blocks;
+       unsigned timeout_msecs = byte_cnt >> 8;
+       if (timeout_msecs < 2000)
+               timeout_msecs = 2000;
 
        /* Always read / write data through the CPU */
        setbits_le32(&mmchost->reg->gctrl, SUNXI_MMC_GCTRL_ACCESS_BY_AHB);
@@ -287,8 +302,8 @@ static int mmc_rint_wait(struct mmc *mmc, unsigned int timeout_msecs,
        return 0;
 }
 
-static int mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd,
-                       struct mmc_data *data)
+static int sunxi_mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd,
+                             struct mmc_data *data)
 {
        struct sunxi_mmc_host *mmchost = mmc->priv;
        unsigned int cmdval = SUNXI_MMC_CMD_START;
@@ -355,7 +370,7 @@ static int mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd,
                }
        }
 
-       error = mmc_rint_wait(mmc, 0xfffff, SUNXI_MMC_RINT_COMMAND_DONE, "cmd");
+       error = mmc_rint_wait(mmc, 1000, SUNXI_MMC_RINT_COMMAND_DONE, "cmd");
        if (error)
                goto out;
 
@@ -414,16 +429,33 @@ static int sunxi_mmc_getcd(struct mmc *mmc)
        int cd_pin;
 
        cd_pin = sunxi_mmc_getcd_gpio(mmchost->mmc_no);
-       if (cd_pin == -1)
+       if (cd_pin < 0)
                return 1;
 
        return !gpio_get_value(cd_pin);
 }
 
+int sunxi_mmc_has_egon_boot_signature(struct mmc *mmc)
+{
+       char *buf = malloc(512);
+       int valid_signature = 0;
+
+       if (buf == NULL)
+               panic("Failed to allocate memory\n");
+
+       if (mmc_getcd(mmc) && mmc_init(mmc) == 0 &&
+           mmc->block_dev.block_read(mmc->block_dev.dev, 16, 1, buf) == 1 &&
+           strncmp(&buf[4], "eGON.BT0", 8) == 0)
+               valid_signature = 1;
+
+       free(buf);
+       return valid_signature;
+}
+
 static const struct mmc_ops sunxi_mmc_ops = {
-       .send_cmd       = mmc_send_cmd,
-       .set_ios        = mmc_set_ios,
-       .init           = mmc_core_init,
+       .send_cmd       = sunxi_mmc_send_cmd,
+       .set_ios        = sunxi_mmc_set_ios,
+       .init           = sunxi_mmc_core_init,
        .getcd          = sunxi_mmc_getcd,
 };
 
@@ -439,9 +471,6 @@ struct mmc *sunxi_mmc_init(int sdc_no)
        cfg->voltages = MMC_VDD_32_33 | MMC_VDD_33_34;
        cfg->host_caps = MMC_MODE_4BIT;
        cfg->host_caps |= MMC_MODE_HS_52MHz | MMC_MODE_HS;
-#if defined(CONFIG_MACH_SUN6I) || defined(CONFIG_MACH_SUN7I) || defined(CONFIG_MACH_SUN8I)
-       cfg->host_caps |= MMC_MODE_HC;
-#endif
        cfg->b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT;
 
        cfg->f_min = 400000;