emmc: add emmc HS400 function
authorLong Yu <long.yu@amlogic.com>
Fri, 19 May 2017 01:54:22 +0000 (09:54 +0800)
committerVictor Wan <victor.wan@amlogic.com>
Thu, 1 Jun 2017 11:10:30 +0000 (04:10 -0700)
PD#142470: emmc: support hs400 busmode

1. refix source clock 400MHZ
2. add hs400 timming function

Change-Id: I9cc767262379ba2be5ab5d3e68aae87c1f18c242
Signed-off-by: Long Yu <long.yu@amlogic.com>
arch/arm64/boot/dts/amlogic/axg_s400.dts
arch/arm64/boot/dts/amlogic/axg_s420.dts
drivers/amlogic/mmc/aml_sd_emmc.c
drivers/amlogic/mmc/aml_sd_emmc_v3.c
drivers/mmc/core/mmc.c
include/linux/amlogic/aml_sd_emmc_internal.h
include/linux/amlogic/aml_sd_emmc_v3.h
include/linux/amlogic/amlsd.h
include/linux/amlogic/sd.h
include/linux/mmc/host.h

index 8dae8f8..f9e8fd9 100644 (file)
                pinctrl-1 = <&emmc_conf_pull_up &emmc_conf_pull_done>;
                clocks = <&clkc CLKID_SD_EMMC_C>,
                           <&clkc CLKID_SD_EMMC_C_P0_COMP>,
-                          <&clkc CLKID_FCLK_DIV2>;
-               clock-names = "core", "clkin0", "clkin1";
+                          <&clkc CLKID_FCLK_DIV2>,
+                          <&clkc CLKID_FCLK_DIV5>;
+               clock-names = "core", "clkin0", "clkin1", "clkin2";
 
                bus-width = <8>;
                cap-sd-highspeed;
                                 "MMC_CAP_HW_RESET",
                                 "MMC_CAP_ERASE",
                                 "MMC_CAP_CMD23";
-                       /*caps2 = "MMC_CAP2_HS200", "MMC_CAP2_HS400";*/
+                       caps2 = "MMC_CAP2_HS200", "MMC_CAP2_HS400";
                        f_min = <300000>;
-                       f_max = <100000000>;
+                       f_max = <200000000>;
                        max_req_size = <0x20000>; /**128KB*/
                        gpio_dat3 = <&gpio BOOT_3 GPIO_ACTIVE_HIGH>;
                        hw_reset = <&gpio BOOT_9 GPIO_ACTIVE_HIGH>;
                pinctrl-1 = <&sdio_all_pins>;
                clocks = <&clkc CLKID_SD_EMMC_B>,
                           <&clkc CLKID_SD_EMMC_B_P0_COMP>,
-                          <&clkc CLKID_FCLK_DIV2>;
-               clock-names = "core", "clkin0", "clkin1";
+                          <&clkc CLKID_FCLK_DIV2>,
+                          <&clkc CLKID_FCLK_DIV5>;
+               clock-names = "core", "clkin0", "clkin1", "clkin2";
 
                bus-width = <4>;
                cap-sd-highspeed;
index d1d47ab..c1b6e73 100644 (file)
                pinctrl-1 = <&emmc_conf_pull_up &emmc_conf_pull_done>;
                clocks = <&clkc CLKID_SD_EMMC_C>,
                           <&clkc CLKID_SD_EMMC_C_P0_COMP>,
-                          <&clkc CLKID_FCLK_DIV2>;
-               clock-names = "core", "clkin0", "clkin1";
+                          <&clkc CLKID_FCLK_DIV2>,
+                          <&clkc CLKID_FCLK_DIV5>;
+               clock-names = "core", "clkin0", "clkin1", "clkin2";
 
                bus-width = <8>;
                cap-sd-highspeed;
index 6599bc5..96aff57 100644 (file)
@@ -1240,6 +1240,8 @@ int aml_emmc_clktree_init(struct amlsd_host *host)
                ret = PTR_ERR(host->core_clk);
                return ret;
        }
+       pr_info("core->rate: %lu\n", clk_get_rate(host->core_clk));
+       pr_info("core->name: %s\n", __clk_get_name(host->core_clk));
        ret = clk_prepare_enable(host->core_clk);
        if (ret)
                return ret;
@@ -1257,6 +1259,8 @@ int aml_emmc_clktree_init(struct amlsd_host *host)
                }
                host->mux_parent_rate[i] = clk_get_rate(host->mux_parent[i]);
                mux_parent_names[i] = __clk_get_name(host->mux_parent[i]);
+               pr_info("rate: %lu, name: %s\n",
+                       host->mux_parent_rate[i], mux_parent_names[i]);
                mux_parent_count++;
                if (host->mux_parent_rate[i] < f_min)
                        f_min = host->mux_parent_rate[i];
@@ -1272,6 +1276,7 @@ int aml_emmc_clktree_init(struct amlsd_host *host)
 
        /* create the mux */
        snprintf(clk_name, sizeof(clk_name), "%s#mux", dev_name(host->dev));
+       pr_info("clk_name: %s\n", clk_name);
        init.name = clk_name;
        init.ops = &clk_mux_ops;
        init.flags = 0;
@@ -1306,7 +1311,8 @@ int aml_emmc_clktree_init(struct amlsd_host *host)
                return PTR_ERR(host->cfg_div_clk);
 
        ret = clk_prepare_enable(host->cfg_div_clk);
-
+       pr_info("[%s] clock: 0x%x\n",
+               __func__, readl(host->base + SD_EMMC_CLOCK_V3));
        return ret;
 }
 
@@ -1324,6 +1330,7 @@ static int meson_mmc_clk_init(struct amlsd_host *host)
        struct sd_emmc_config *pconf = (struct sd_emmc_config *)&vconf;
        struct amlsd_platform *pdata = host->pdata;
 
+       writel(0, host->base + SD_EMMC_CLOCK);
        ret = aml_emmc_clktree_init(host);
        if (ret)
                return ret;
@@ -1662,7 +1669,7 @@ err_exit:
  *a linear buffer and an SG list  for amlogic,
  * We don't disable irq in this function
  **/
-static int aml_sd_emmc_post_dma(struct amlsd_host *host,
+int aml_sd_emmc_post_dma(struct amlsd_host *host,
                struct mmc_request *mrq)
 {
        struct mmc_data *data = NULL;
@@ -1718,7 +1725,7 @@ static void aml_sd_emmc_check_sdio_irq(struct amlsd_host *host)
                }
        }
 }
-static int meson_mmc_request_done(struct mmc_host *mmc, struct mmc_request *mrq)
+int meson_mmc_request_done(struct mmc_host *mmc, struct mmc_request *mrq)
 {
        struct amlsd_host *host = mmc_priv(mmc);
        struct amlsd_platform *pdata = host->pdata;
@@ -2023,7 +2030,7 @@ static void meson_mmc_request(struct mmc_host *mmc, struct mmc_request *mrq)
        spin_unlock_irqrestore(&host->mrq_lock, flags);
 }
 
-static int meson_mmc_read_resp(struct mmc_host *mmc, struct mmc_command *cmd)
+int meson_mmc_read_resp(struct mmc_host *mmc, struct mmc_command *cmd)
 {
        struct amlsd_host *host = mmc_priv(mmc);
        struct sd_emmc_desc_info *desc_info =
@@ -2694,6 +2701,7 @@ static const struct mmc_host_ops meson_mmc_ops_v3 = {
        .card_busy = aml_sd_emmc_card_busy,
        .execute_tuning = aml_mmc_execute_tuning_v3,
        .hw_reset = aml_emmc_hw_reset,
+       .post_hs400_timming = aml_post_hs400_timming,
 };
 
 static void aml_reg_print(struct amlsd_host *host)
@@ -2746,8 +2754,12 @@ static int meson_mmc_probe(struct platform_device *pdev)
                ret = -EINVAL;
                goto free_host;
        }
-
-       ret = devm_request_threaded_irq(&pdev->dev, host->irq,
+       if (host->ctrl_ver >= 3)
+               ret = devm_request_threaded_irq(&pdev->dev, host->irq,
+                       meson_mmc_irq, meson_mmc_irq_thread_v3,
+                       IRQF_SHARED, "meson-aml-mmc", host);
+       else
+               ret = devm_request_threaded_irq(&pdev->dev, host->irq,
                        meson_mmc_irq, meson_mmc_irq_thread,
                        IRQF_SHARED, "meson-aml-mmc", host);
        if (ret)
index fdb684b..ad21c5e 100644 (file)
@@ -51,6 +51,7 @@ int meson_mmc_clk_init_v3(struct amlsd_host *host)
        struct sd_emmc_config *pconf = (struct sd_emmc_config *)&vconf;
        struct amlsd_platform *pdata = host->pdata;
 
+       writel(0, host->base + SD_EMMC_CLOCK);
        ret = aml_emmc_clktree_init(host);
        if (ret)
                return ret;
@@ -89,7 +90,10 @@ static int meson_mmc_clk_set_rate_v3(struct amlsd_host *host,
                unsigned long clk_ios)
 {
        struct mmc_host *mmc = host->mmc;
+       struct amlsd_platform *pdata = host->pdata;
        int ret = 0;
+       struct clk *fdiv5_clk = NULL;
+       void __iomem *source_base = NULL;
 #ifdef SD_EMMC_CLK_CTRL
        u32 clk_rate, clk_div, clk_src_sel;
        struct amlsd_platform *pdata = host->pdata;
@@ -141,7 +145,8 @@ static int meson_mmc_clk_set_rate_v3(struct amlsd_host *host,
 #else
        if (clk_ios == mmc->actual_clock)
                return 0;
-
+       pr_info("[%s] before clock: 0x%x\n",
+               __func__, readl(host->base + SD_EMMC_CLOCK_V3));
        /* stop clock */
        vcfg = readl(host->base + SD_EMMC_CFG);
        if (!conf->stop_clk) {
@@ -149,6 +154,16 @@ static int meson_mmc_clk_set_rate_v3(struct amlsd_host *host,
                writel(vcfg, host->base + SD_EMMC_CFG);
        }
 
+       if ((clk_ios >= 200000000) && aml_card_type_mmc(pdata)) {
+               ret = clk_set_parent(host->cfg_div_clk, host->mux_clk);
+               if (ret)
+                       pr_warn("set mux_clk as parent error\n");
+               fdiv5_clk = devm_clk_get(host->dev, "clkin2");
+               ret = clk_set_parent(host->mux_parent[0], fdiv5_clk);
+               if (ret)
+                       pr_warn("set fdiv5_clk as parent error\n");
+       }
+
        dev_dbg(host->dev, "change clock rate %u -> %lu\n",
                mmc->actual_clock, clk_ios);
        ret = clk_set_rate(host->cfg_div_clk, clk_ios);
@@ -165,7 +180,16 @@ static int meson_mmc_clk_set_rate_v3(struct amlsd_host *host,
                writel(vcfg, host->base + SD_EMMC_CFG);
        }
 #endif
-
+       source_base =
+                               ioremap_nocache(P_HHI_NAND_CLK_CNTL,
+                                       sizeof(u32));
+       /* pr_info("actual_clock :%u, HHI_nand: 0x%x\n",
+        *      mmc->actual_clock, readl(source_base));
+        */
+       /* pr_info("[%s] after clock: 0x%x\n",
+        * __func__, readl(host->base + SD_EMMC_CLOCK_V3));
+        */
+       iounmap(source_base);
        return ret;
 }
 
@@ -192,6 +216,7 @@ static void aml_sd_emmc_set_timing_v3(struct amlsd_host *host,
                                adjust = readl(host->base + SD_EMMC_ADJUST_V3);
                                gadjust->ds_enable = 1;
                                writel(adjust, host->base + SD_EMMC_ADJUST_V3);
+                               clk_rate = 400000000;
                                /*host->tuning_mode = AUTO_TUNING_MODE;*/
                        }
                }
@@ -273,8 +298,7 @@ int aml_mmc_execute_tuning_v3(struct mmc_host *mmc, u32 opcode)
 {
        struct amlsd_host *host = mmc_priv(mmc);
        struct aml_tuning_data tuning_data;
-       int err;
-       u32 adj_win_start = 100;
+       int err = 0;
        u32 intf3;
 
        if (opcode == MMC_SEND_TUNING_BLOCK_HS200) {
@@ -298,8 +322,6 @@ int aml_mmc_execute_tuning_v3(struct mmc_host *mmc, u32 opcode)
        intf3 = readl(host->base + SD_EMMC_INTF3);
        intf3 |= (1 << 22);
        writel(intf3, host->base + SD_EMMC_INTF3);
-       err = aml_sd_emmc_execute_tuning_(mmc, opcode,
-                       &tuning_data, adj_win_start);
 
        pr_info("%s: gclock=0x%x, gdelay1=0x%x, gdelay2=0x%x,intf3=0x%x\n",
                mmc_hostname(mmc), readl(host->base + SD_EMMC_CLOCK_V3),
@@ -309,39 +331,553 @@ int aml_mmc_execute_tuning_v3(struct mmc_host *mmc, u32 opcode)
        return err;
 }
 
-/*static int aml_sd_emmc_cali_v3(struct mmc_host *mmc,
- *     u8 opcode, u8 *blk_test, u32 blksz, u32 blocks)
- *{
- *     struct amlsd_host *host = mmc_priv(mmc);
- *     struct mmc_request mrq = {NULL};
- *     struct mmc_command cmd = {0};
- *     struct mmc_command stop = {0};
- *     struct mmc_data data = {0};
- *     struct scatterlist sg;
- *
- *     cmd.opcode = opcode;
- *     cmd.arg = ((SZ_1M * (36 + 3)) / 512);
- *     cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
- *
- *     stop.opcode = MMC_STOP_TRANSMISSION;
- *     stop.arg = 0;
- *     stop.flags = MMC_RSP_R1B | MMC_CMD_AC;
- *
- *     data.blksz = blksz;
- *     data.blocks = blocks;
- *     data.flags = MMC_DATA_READ;
- *     data.sg = &sg;
- *     data.sg_len = 1;
- *
- *     memset(blk_test, 0, blksz * data.blocks);
- *     sg_init_one(&sg, blk_test, blksz * data.blocks);
- *
- *     mrq.cmd = &cmd;
- *     mrq.stop = &stop;
- *     mrq.data = &data;
- *     host->mrq = &mrq;
- *     mmc_wait_for_req(mmc, &mrq);
- *     return data.error | cmd.error;
- *}
+irqreturn_t meson_mmc_irq_thread_v3(int irq, void *dev_id)
+{
+       struct amlsd_host *host = dev_id;
+       struct amlsd_platform *pdata = host->pdata;
+       struct mmc_request *mrq;
+       unsigned long flags;
+       enum aml_mmc_waitfor xfer_step;
+       u32 status, xfer_bytes = 0;
+
+       spin_lock_irqsave(&host->mrq_lock, flags);
+       mrq = host->mrq;
+       xfer_step = host->xfer_step;
+       status = host->status;
+
+       if ((xfer_step == XFER_FINISHED) || (xfer_step == XFER_TIMER_TIMEOUT)) {
+               sd_emmc_err("Warning: %s xfer_step=%d, host->status=%d\n",
+                       mmc_hostname(host->mmc), xfer_step, status);
+               spin_unlock_irqrestore(&host->mrq_lock, flags);
+               return IRQ_HANDLED;
+       }
+
+       WARN_ON((host->xfer_step != XFER_IRQ_OCCUR)
+                && (host->xfer_step != XFER_IRQ_TASKLET_BUSY));
+
+       if (!mrq) {
+               sd_emmc_err("%s: !mrq xfer_step %d\n",
+                       mmc_hostname(host->mmc), xfer_step);
+               if (xfer_step == XFER_FINISHED ||
+                       xfer_step == XFER_TIMER_TIMEOUT){
+                       spin_unlock_irqrestore(&host->mrq_lock, flags);
+                       return IRQ_HANDLED;
+               }
+               /* aml_sd_emmc_print_err(host); */
+       }
+       /* process stop cmd we sent on porpos */
+       if (host->cmd_is_stop) {
+               /* --new irq enter, */
+               host->cmd_is_stop = 0;
+               mrq->cmd->error = host->error_bak;
+               spin_unlock_irqrestore(&host->mrq_lock, flags);
+               meson_mmc_request_done(host->mmc, host->mrq);
+
+               return IRQ_HANDLED;
+       }
+       spin_unlock_irqrestore(&host->mrq_lock, flags);
+
+       WARN_ON(!host->mrq->cmd);
+
+       switch (status) {
+       case HOST_TASKLET_DATA:
+       case HOST_TASKLET_CMD:
+               /* WARN_ON(aml_sd_emmc_desc_check(host)); */
+               sd_emmc_dbg(AMLSD_DBG_REQ, "%s %d cmd:%d\n",
+                       __func__, __LINE__, mrq->cmd->opcode);
+               host->error_flag = 0;
+               if (mrq->cmd->data &&  mrq->cmd->opcode) {
+                       xfer_bytes = mrq->data->blksz*mrq->data->blocks;
+                       /* copy buffer from dma to data->sg in read cmd*/
+#ifdef SD_EMMC_REQ_DMA_SGMAP
+                       WARN_ON(aml_sd_emmc_post_dma(host, mrq));
+#else
+                       if (host->mrq->data->flags & MMC_DATA_READ) {
+                               aml_sg_copy_buffer(mrq->data->sg,
+                               mrq->data->sg_len, host->bn_buf,
+                                xfer_bytes, 0);
+                       }
+#endif
+                       mrq->data->bytes_xfered = xfer_bytes;
+                       host->xfer_step = XFER_TASKLET_DATA;
+               } else {
+                       host->xfer_step = XFER_TASKLET_CMD;
+               }
+               spin_lock_irqsave(&host->mrq_lock, flags);
+               mrq->cmd->error = 0;
+               spin_unlock_irqrestore(&host->mrq_lock, flags);
+
+               meson_mmc_read_resp(host->mmc, mrq->cmd);
+               meson_mmc_request_done(host->mmc, mrq);
+
+               break;
+
+       case HOST_RSP_TIMEOUT_ERR:
+       case HOST_DAT_TIMEOUT_ERR:
+       case HOST_RSP_CRC_ERR:
+       case HOST_DAT_CRC_ERR:
+               if (host->is_tunning == 0)
+                       pr_info("%s %d %s: cmd:%d\n", __func__, __LINE__,
+                               mmc_hostname(host->mmc), mrq->cmd->opcode);
+               if (mrq->cmd->data) {
+                       dma_unmap_sg(mmc_dev(host->mmc), mrq->cmd->data->sg,
+                               mrq->cmd->data->sg_len,
+                               (mrq->cmd->data->flags & MMC_DATA_READ) ?
+                                       DMA_FROM_DEVICE : DMA_TO_DEVICE);
+               }
+               meson_mmc_read_resp(host->mmc, host->mrq->cmd);
+
+               /* set retry @ 1st error happens! */
+               if ((host->error_flag == 0)
+                       && (aml_card_type_mmc(pdata)
+                               || aml_card_type_non_sdio(pdata))
+                       && (host->is_tunning == 0)) {
+
+                       sd_emmc_err("%s() %d: set 1st retry!\n",
+                               __func__, __LINE__);
+                       host->error_flag |= (1<<0);
+                       spin_lock_irqsave(&host->mrq_lock, flags);
+                       mrq->cmd->retries = 3;
+                       spin_unlock_irqrestore(&host->mrq_lock, flags);
+               }
+
+               if (aml_card_type_mmc(pdata) &&
+                       (host->error_flag & (1<<0)) && mrq->cmd->retries) {
+                       sd_emmc_err("retry cmd %d the %d-th time(s)\n",
+                               mrq->cmd->opcode, mrq->cmd->retries);
+                       /* chage configs on current host */
+               }
+               /* last retry effort! */
+               if ((aml_card_type_mmc(pdata) || aml_card_type_non_sdio(pdata))
+                       && host->error_flag && (mrq->cmd->retries == 0)) {
+                       host->error_flag |= (1<<30);
+                       sd_emmc_err("Command retried failed line:%d, cmd:%d\n",
+                               __LINE__, mrq->cmd->opcode);
+               }
+               /* retry need send a stop 2 emmc... */
+               /* do not send stop for sdio wifi case */
+               if (host->mrq->stop
+                       && (aml_card_type_mmc(pdata)
+                               || aml_card_type_non_sdio(pdata))
+                       && pdata->is_in
+                       && (host->mrq->cmd->opcode != MMC_SEND_TUNING_BLOCK)
+                       && (host->mrq->cmd->opcode !=
+                                       MMC_SEND_TUNING_BLOCK_HS200))
+                       aml_sd_emmc_send_stop(host);
+               else
+                       meson_mmc_request_done(host->mmc, mrq);
+               break;
+
+       default:
+               sd_emmc_err("BUG %s: xfer_step=%d, host->status=%d\n",
+                       mmc_hostname(host->mmc),  xfer_step, status);
+               /* aml_sd_emmc_print_err(host); */
+       }
+
+       return IRQ_HANDLED;
+}
+
+static int aml_sd_emmc_cali_v3(struct mmc_host *mmc,
+       u8 opcode, u8 *blk_test, u32 blksz, u32 blocks)
+{
+       struct amlsd_host *host = mmc_priv(mmc);
+       struct mmc_request mrq = {NULL};
+       struct mmc_command cmd = {0};
+       struct mmc_command stop = {0};
+       struct mmc_data data = {0};
+       struct scatterlist sg;
+
+       cmd.opcode = opcode;
+       cmd.arg = ((SZ_1M * (36 + 3)) / 512);
+       cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
+
+       stop.opcode = MMC_STOP_TRANSMISSION;
+       stop.arg = 0;
+       stop.flags = MMC_RSP_R1B | MMC_CMD_AC;
+
+       data.blksz = blksz;
+       data.blocks = blocks;
+       data.flags = MMC_DATA_READ;
+       data.sg = &sg;
+       data.sg_len = 1;
+
+       memset(blk_test, 0, blksz * data.blocks);
+       sg_init_one(&sg, blk_test, blksz * data.blocks);
+
+       mrq.cmd = &cmd;
+       mrq.stop = &stop;
+       mrq.data = &data;
+       host->mrq = &mrq;
+       mmc_wait_for_req(mmc, &mrq);
+       return data.error | cmd.error;
+}
+
+#define EMMC_TIMMING_DBG 1
+
+static int emmc_eyetest_log(struct mmc_host *mmc, u32 line_x)
+{
+       struct amlsd_host *host = mmc_priv(mmc);
+       struct amlsd_platform *pdata = host->pdata;
+       u32 adjust = readl(host->base + SD_EMMC_ADJUST_V3);
+       struct sd_emmc_adjust_v3 *gadjust =
+               (struct sd_emmc_adjust_v3 *)&adjust;
+       /*u32 delay1 = sd_emmc_regs->reg.v3.gdelay1;
+        *struct sd_emmc_delay1 *gdelay1 = (struct sd_emmc_delay1 *)&delay1;
+        *u32 delay2 = sd_emmc_regs->reg.v3.gdelay2;
+        *struct sd_emmc_delay2 *gdelay2 = (struct sd_emmc_delay2 *)&delay2;
+        *u32 clktest_log = 0;
+        *struct clktest_log gclktest_log =
+        *      (struct clktest_log *)&(clktest_log);
+        *u32 clktest_out = 0;
+        */
+       u32 eyetest_log = 0;
+       struct eyetest_log *geyetest_log = (struct eyetest_log *)&(eyetest_log);
+       u32 eyetest_out0 = 0, eyetest_out1 = 0;
+       u32 intf3 = readl(host->base + SD_EMMC_INTF3);
+       struct intf3 *gintf3 = (struct intf3 *)&(intf3);
+       u32 vcfg = readl(host->base + SD_EMMC_CFG);
+       int j = 0;
+       u64 tmp = 0;
+       u32 blksz = 512;
+       u8 *blk_test;
+               blk_test = kmalloc(blksz * CALI_BLK_CNT, GFP_KERNEL);
+       if (!blk_test)
+               return -ENOMEM;
+       host->is_tunning = 1;
+       emmc_dbg(EMMC_TIMMING_DBG,
+               "line_x: %d\n", line_x);
+       /*sd_emmc_regs->reg.v3.gdelay1 = delay1;
+        *sd_emmc_regs->reg.v3.gdelay2 = delay2;
+        */
+       emmc_dbg(EMMC_TIMMING_DBG, "delay1: 0x%x , delay2: 0x%x\n",
+           readl(host->base + SD_EMMC_DELAY1_V3),
+               readl(host->base + SD_EMMC_DELAY2_V3));
+       gadjust->cali_enable = 1;
+       gadjust->cali_sel = line_x;
+       writel(adjust, host->base + SD_EMMC_ADJUST_V3);
+       if (line_x < 9)
+               gintf3->eyetest_exp = 7;
+       else
+               gintf3->eyetest_exp = 3;
+       gintf3->eyetest_on = 1;
+       writel(intf3, host->base + SD_EMMC_INTF3);
+       emmc_dbg(EMMC_TIMMING_DBG, "intf3: 0x%x,adjust: 0x%x\n",
+               readl(host->base + SD_EMMC_INTF3),
+               readl(host->base + SD_EMMC_ADJUST_V3));
+
+       /*****test start*************/
+       if (line_x < 9)
+               aml_sd_emmc_cali_v3(mmc,
+                       MMC_READ_MULTIPLE_BLOCK,
+                       blk_test, blksz, 40);
+       else
+               aml_sd_emmc_cali_v3(mmc,
+                       MMC_READ_MULTIPLE_BLOCK,
+                       blk_test, blksz, 80);
+
+       eyetest_log = readl(host->base + SD_EMMC_EYETEST_LOG);
+       eyetest_out0 = readl(host->base + SD_EMMC_EYETEST_OUT0);
+       eyetest_out1 = readl(host->base + SD_EMMC_EYETEST_OUT1);
+
+       while ((!(geyetest_log->eyetest_done & 0x1))) {
+               eyetest_out0 = readl(host->base + SD_EMMC_EYETEST_OUT0);
+               eyetest_out1 = readl(host->base + SD_EMMC_EYETEST_OUT1);
+               eyetest_log = readl(host->base + SD_EMMC_EYETEST_LOG);
+               emmc_dbg(EMMC_TIMMING_DBG, "testing eyetest times: 0x%x, out: 0x%x, 0x%x\n",
+                       readl(host->base + SD_EMMC_EYETEST_LOG),
+                       eyetest_out0, eyetest_out1);
+               if (j == 10)
+                       break;
+               j++;
+       }
+       emmc_dbg(EMMC_TIMMING_DBG, "test done! eyetest times: 0x%x, out: 0x%x, 0x%x\n",
+                       readl(host->base + SD_EMMC_EYETEST_LOG),
+                       eyetest_out0, eyetest_out1);
+       gintf3->eyetest_on = 0;
+       writel(intf3, host->base + SD_EMMC_INTF3);
+       emmc_dbg(EMMC_TIMMING_DBG, "intf3: 0x%x,adjust: 0x%x\n",
+               readl(host->base + SD_EMMC_INTF3),
+               readl(host->base + SD_EMMC_ADJUST_V3));
+       if (vcfg & 0x4) {
+               if (pdata->count > 32) {
+                       eyetest_out1 <<= (32 - (pdata->count - 32));
+                       eyetest_out1 >>= (32 - (pdata->count - 32));
+               } else
+                       eyetest_out1 = 0x0;
+       }
+       pdata->align[line_x] = ((tmp | eyetest_out1) << 32) | eyetest_out0;
+       emmc_dbg(EMMC_TIMMING_DBG, "u64 eyetestout 0x%llx\n",
+                       pdata->align[line_x]);
+       host->is_tunning = 0;
+       kfree(blk_test);
+       return 0;
+}
+
+static int fbinary(u64 x)
+{
+       int i;
+
+       for (i = 0; i < 64; i++) {
+               if ((x >> i) & 0x1)
+                       return i;
+       }
+       return -1;
+}
+
+static int emmc_detect_base_line(u64 *arr)
+{
+       u32 i = 0, first[10] = {0};
+       u32  max = 0, l_max = 0xff;
+
+       for (i = 0; i < 8; i++) {
+               first[i] = fbinary(arr[i]);
+               if (first[i] > max) {
+                       l_max = i;
+                       max = first[i];
+               }
+       }
+       pr_warn("%s [%d] detect line:%d, max: %u\n",
+                       __func__, __LINE__, l_max, max);
+       return max;
+}
+
+/**************** start all data align ********************/
+static int emmc_all_data_line_alignment(struct mmc_host *mmc)
+{
+       struct amlsd_host *host = mmc_priv(mmc);
+       struct amlsd_platform *pdata = host->pdata;
+       u32 delay1 = 0, delay2 = 0;
+       int result;
+       int temp = 0, base_line = 0, line_x = 0;
+
+       pdata->base_line = emmc_detect_base_line(pdata->align);
+       base_line = pdata->base_line;
+       for (line_x = 0; line_x < 9; line_x++) {
+               if (line_x == 8)
+                       continue;
+               temp = fbinary(pdata->align[line_x]);
+               if (temp <= 4)
+                       continue;
+               result = base_line - temp;
+               emmc_dbg(EMMC_TIMMING_DBG, "line_x: %d, result: %d\n",
+                               line_x, result);
+               if (line_x < 5)
+                       delay1 |= result << (6 * line_x);
+               else
+                       delay2 |= result << (6 * (line_x - 5));
+       }
+       delay1 |= readl(host->base + SD_EMMC_DELAY1_V3);
+       delay2 |= readl(host->base + SD_EMMC_DELAY2_V3);
+       writel(delay1, host->base + SD_EMMC_DELAY1_V3);
+       writel(delay2, host->base + SD_EMMC_DELAY2_V3);
+       emmc_dbg(EMMC_TIMMING_DBG, "delay1: 0x%x, delay2: 0x%x\n",
+                       delay1, delay2);
+       emmc_dbg(EMMC_TIMMING_DBG, "gdelay1: 0x%x, gdelay2: 0x%x\n",
+                       readl(host->base + SD_EMMC_DELAY1_V3),
+                       readl(host->base + SD_EMMC_DELAY2_V3));
+
+       return 0;
+}
+
+static int emmc_ds_data_alignment(struct mmc_host *mmc)
+{
+       struct amlsd_host *host = mmc_priv(mmc);
+       struct amlsd_platform *pdata = host->pdata;
+       u32 delay1 = readl(host->base + SD_EMMC_DELAY1_V3);
+       u32 delay2 = readl(host->base + SD_EMMC_DELAY2_V3);
+       int i;
+
+       for (i = 0; i < 64; i++) {
+               pr_info("i = %d, delay1: 0x%x, delay2: 0x%x\n",
+                               i, readl(host->base + SD_EMMC_DELAY1_V3),
+                               readl(host->base + SD_EMMC_DELAY2_V3));
+               delay1 += (1<<0)|(1<<6)|(1<<12)|(1<<18)|(1<<24);
+               delay2 += (1<<0)|(1<<6)|(1<<12)|(1<<24);
+               writel(delay1, host->base + SD_EMMC_DELAY1_V3);
+               writel(delay2, host->base + SD_EMMC_DELAY2_V3);
+               emmc_eyetest_log(mmc, 3);
+               emmc_eyetest_log(mmc, 8);
+               if (pdata->align[3] & 0xf)
+                       break;
+       }
+       if (i == 64) {
+               pr_warn("%s [%d] Don't find line delay which aligned with DS\n",
+                               __func__, __LINE__);
+               return 1;
+       }
+       return 0;
+}
+
+
+static void print_all_line_eyetest(struct mmc_host *mmc)
+{
+       int line_x;
+
+       for (line_x = 0; line_x < 10; line_x++)
+               emmc_eyetest_log(mmc, line_x);
+}
+/* first step*/
+static int emmc_ds_core_align(struct mmc_host *mmc)
+{
+       struct amlsd_host *host = mmc_priv(mmc);
+       struct amlsd_platform *pdata = host->pdata;
+       u32 delay1 = readl(host->base + SD_EMMC_DELAY1_V3);
+       u32 delay2 = readl(host->base + SD_EMMC_DELAY2_V3);
+       u32 delay2_bak = delay2;
+       u32 count = 0;
+       u32 ds_count = 0;
+
+       if (pdata->align[8] & 0xf)
+               return 0;
+       ds_count = fbinary(pdata->align[8]);
+       //BUG_ON(ds_count >= 4 && ds_count <= 8);
+       emmc_dbg(EMMC_TIMMING_DBG, "ds_count:%d,delay1:0x%x,delay2:0x%x\n",
+                       ds_count, readl(host->base + SD_EMMC_DELAY1_V3),
+                       readl(host->base + SD_EMMC_DELAY2_V3));
+       if (ds_count < 20) {
+               delay2 += ((20 - ds_count) << 18);
+               writel(delay2, host->base + SD_EMMC_DELAY2_V3);
+       } else {
+               delay2 += (1<<18);
+               writel(delay2, host->base + SD_EMMC_DELAY2_V3);
+       }
+       emmc_eyetest_log(mmc, 8);
+       while (!(pdata->align[8] & 0xf)) {
+               delay2 += (1<<18);
+               writel(delay2, host->base + SD_EMMC_DELAY2_V3);
+               emmc_eyetest_log(mmc, 8);
+       }
+       delay1 = readl(host->base + SD_EMMC_DELAY1_V3);
+       delay2 = readl(host->base + SD_EMMC_DELAY2_V3);
+       ds_count = fbinary(pdata->align[8]);
+       count = ((delay2>>18) & 0x3f) - ((delay2_bak>>18) & 0x3f);
+       pdata->ds_core = count;
+       delay1 += (count<<0)|(count<<6)|(count<<12)|(count<<18)|(count<<24);
+       delay2 += (count<<0)|(count<<6)|(count<<12)|(count<<24);
+       writel(delay1, host->base + SD_EMMC_DELAY1_V3);
+       writel(delay2, host->base + SD_EMMC_DELAY2_V3);
+       emmc_dbg(EMMC_TIMMING_DBG,
+               "ds_count:%d,delay1:0x%x,delay2:0x%x,count: %u\n",
+               ds_count, readl(host->base + SD_EMMC_DELAY1_V3),
+               readl(host->base + SD_EMMC_DELAY2_V3), count);
+       return 0;
+}
+
+#if 1
+static int emmc_ds_manual_sht(struct mmc_host *mmc)
+{
+       struct amlsd_host *host = mmc_priv(mmc);
+       /* struct amlsd_platform *pdata = host->pdata; */
+       u32 intf3 = readl(host->base + SD_EMMC_INTF3);
+       struct intf3 *gintf3 = (struct intf3 *)&(intf3);
+       u8 *blk_test = NULL;
+       u32 blksz = 512;
+       int i, err = 0;
+       u32 sta = 0, end = 0, flag = 0;
+
+       blk_test = kmalloc(blksz * CALI_BLK_CNT, GFP_KERNEL);
+       if (!blk_test)
+               return -ENOMEM;
+
+       print_all_line_eyetest(mmc);
+       emmc_ds_core_align(mmc);
+       print_all_line_eyetest(mmc);
+       emmc_all_data_line_alignment(mmc);
+       print_all_line_eyetest(mmc);
+       emmc_ds_data_alignment(mmc);
+       print_all_line_eyetest(mmc);
+       host->is_tunning = 1;
+       for (i = 0; i < 64; i++) {
+               gintf3->ds_sht_m += 1;
+               writel(intf3, host->base + SD_EMMC_INTF3);
+               err = aml_sd_emmc_cali_v3(mmc,
+                       MMC_READ_MULTIPLE_BLOCK,
+                       blk_test, blksz, 20);
+               emmc_dbg(EMMC_TIMMING_DBG, "intf3: 0x%x, err: %d\n",
+                       readl(host->base + SD_EMMC_INTF3), err);
+               if (!err && !flag) {
+                       sta = i;
+                       flag = 1;
+               } else if (err && flag) {
+                       end = i-1;
+                       break;
+               }
+       }
+       gintf3->ds_sht_m = (sta + end) / 2;
+       writel(intf3, host->base + SD_EMMC_INTF3);
+       emmc_dbg(EMMC_TIMMING_DBG, "sta:%u, end:%u,ds_sht:%u, intf3:0x%x",
+                       sta, end, gintf3->ds_sht_m,
+                       readl(host->base +  SD_EMMC_INTF3));
+       host->is_tunning = 0;
+       kfree(blk_test);
+       blk_test = NULL;
+       return 0;
+}
+#endif
+
+
+/* test clock, return delay cells for one cycle
  */
+static unsigned int emmc_clktest(struct mmc_host *mmc)
+{
+       struct amlsd_host *host = mmc_priv(mmc);
+       struct amlsd_platform *pdata = host->pdata;
+       u32 intf3 = readl(host->base + SD_EMMC_INTF3);
+       struct intf3 *gintf3 = (struct intf3 *)&(intf3);
+       u32 clktest = 0, delay_cell = 0, clktest_log = 0, count = 0;
+       u32 vcfg = readl(host->base + SD_EMMC_CFG);
+       int i = 0;
+
+       vcfg &= ~(1 << 23);
+       writel(vcfg, host->base + SD_EMMC_CFG);
+       writel(0, host->base + SD_EMMC_DELAY1_V3);
+       writel(0, host->base + SD_EMMC_DELAY2_V3);
+       gintf3->clktest_exp = 8;
+       gintf3->clktest_on_m = 1;
+       writel(intf3, host->base + SD_EMMC_INTF3);
+       emmc_dbg(EMMC_TIMMING_DBG, "CFG: 0x%x\n",
+               readl(host->base + SD_EMMC_CFG));
+
+       clktest_log = readl(host->base + SD_EMMC_CLKTEST_LOG);
+       clktest = readl(host->base + SD_EMMC_CLKTEST_OUT);
+       while (!(clktest_log & 0x80000000)) {
+               mdelay(1);
+               i++;
+               clktest_log = readl(host->base + SD_EMMC_CLKTEST_LOG);
+               clktest = readl(host->base + SD_EMMC_CLKTEST_OUT);
+               if (i > 4) {
+                       pr_warn("[%s] [%d] emmc clktest error\n",
+                               __func__, __LINE__);
+                       break;
+               }
+       }
+       if (clktest_log & 0x80000000) {
+               clktest = readl(host->base + SD_EMMC_CLKTEST_OUT);
+               count = clktest / (1 << 8);
+               if (vcfg & 0x4)
+                       delay_cell = (2500 / count);
+               else
+                       delay_cell = (5000 / count);
+       }
+       pr_info("%s [%d] clktest : %u, delay_cell: %d, count: %u\n",
+                       __func__, __LINE__, clktest, delay_cell, count);
+       gintf3->clktest_on_m = 0;
+       writel(intf3, host->base + SD_EMMC_INTF3);
+       vcfg |= (1 << 23);
+       writel(vcfg, host->base + SD_EMMC_CFG);
+
+       emmc_dbg(EMMC_TIMMING_DBG, "CFG: 0x%x\n",
+               readl(host->base + SD_EMMC_CFG));
+       pdata->count = count;
+       pdata->delay_cell = delay_cell;
+       return count;
+}
 
+int aml_post_hs400_timming(struct mmc_host *mmc)
+{
+       int ret = 0;
+
+       emmc_clktest(mmc);
+       ret = emmc_ds_manual_sht(mmc);
+       return 0;
+}
index 254e486..c856425 100644 (file)
@@ -27,6 +27,7 @@
 #include "sd_ops.h"
 
 #define DEFAULT_CMD6_TIMEOUT_MS        500
+#define AMLOGIC_HS400_TIMING 1
 
 static const unsigned int tran_exp[] = {
        10000,          100000,         1000000,        10000000,
@@ -1500,7 +1501,23 @@ static int mmc_hs200_tuning(struct mmc_card *card)
 
        return mmc_execute_tuning(card);
 }
+#ifdef AMLOGIC_HS400_TIMING
+static int mmc_hs400_timming(struct mmc_card *card)
+{
+       struct mmc_host *host = card->host;
+       int err = 0;
+
+       if ((card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS400)
+                       &&  (host->ops->post_hs400_timming)) {
+               err = host->ops->post_hs400_timming(host);
+               if (err)
+                       pr_warn("%s: refix HS400 timming failed\n",
+                               mmc_hostname(host));
+       }
 
+       return err;
+}
+#endif
 /*
  * Handle the detection and initialisation of a card.
  *
@@ -1742,6 +1759,11 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
                err = mmc_select_hs400(card);
                if (err)
                        goto free_card;
+#ifdef AMLOGIC_HS400_TIMING
+               err = mmc_hs400_timming(card);
+               if (err)
+                       goto err;
+#endif
        } else {
                /* Select the desired bus width optionally */
                err = mmc_select_bus_width(card);
index bf3bd82..2489035 100644 (file)
@@ -24,9 +24,21 @@ extern int meson_mmc_clk_init_v3(struct amlsd_host *host);
 
 extern void meson_mmc_set_ios_v3(struct mmc_host *mmc, struct mmc_ios *ios);
 
-extern int aml_sd_emmc_execute_tuning_(struct mmc_host *mmc, u32 opcode,
-               struct aml_tuning_data *tuning_data, u32 adj_win_start);
+/*extern int aml_sd_emmc_execute_tuning_(struct mmc_host *mmc, u32 opcode,
+ *             struct aml_tuning_data *tuning_data, u32 adj_win_start);
+ */
 
 extern void aml_sd_emmc_set_buswidth(struct amlsd_host *host, u32 busw_ios);
 
+extern int meson_mmc_request_done(struct mmc_host *mmc,
+               struct mmc_request *mrq);
+
+extern int meson_mmc_read_resp(struct mmc_host *mmc,
+               struct mmc_command *cmd);
+
+extern void aml_sd_emmc_send_stop(struct amlsd_host *host);
+
+extern int aml_sd_emmc_post_dma(struct amlsd_host *host,
+               struct mmc_request *mrq);
+
 #endif
index adbc302..8e9d96e 100644 (file)
@@ -25,10 +25,9 @@ void meson_mmc_set_ios_v3(struct mmc_host *mmc, struct mmc_ios *ios);
 
 int aml_mmc_execute_tuning_v3(struct mmc_host *mmc, u32 opcode);
 
-/* irqreturn_t meson_mmc_irq_v3(int irq, void *dev_id);*/
+irqreturn_t meson_mmc_irq_thread_v3(int irq, void *dev_id);
 
-/*irqreturn_t meson_mmc_irq_thread_v3(int irq, void *dev_id);*/
-/* int aml_post_hs400_timming(struct mmc_host *mmc); */
+int aml_post_hs400_timming(struct mmc_host *mmc);
 
 /* extern ssize_t emmc_eyetest_show(struct device *dev,
  *             struct device_attribute *attr, char *buf);
index bbafd0e..07827c3 100644 (file)
@@ -109,6 +109,11 @@ extern const u8 tuning_blk_pattern_8bit[128];
 #define sd_emmc_err(fmt, args...) \
        pr_warn("[%s] " fmt, __func__, ##args)
 
+#define emmc_dbg(emmc_timming_dbg, fmt, args...) do {\
+       if (emmc_timming_dbg)   \
+               pr_warn("[%s]" fmt, __func__, ##args);  \
+} while (0)
+
 #define SD_PARSE_U32_PROP_HEX(node, prop_name, prop, value) do { \
        if (!of_property_read_u32(node, prop_name, &prop)) {\
                value = prop;\
index 36d5c24..e475c36 100644 (file)
@@ -39,7 +39,7 @@
 #ifdef AML_CALIBRATION
 #define MAX_CALI_RETRY 3
 #define MAX_DELAY_CNT  16
-#define CALI_BLK_CNT   10
+#define CALI_BLK_CNT   80
 #endif
 
 #define SD_EMMC_CLOCK 0x0
@@ -58,7 +58,7 @@
 #define SD_EMMC_CLOCK_V3 0x0
 #define SD_EMMC_DELAY1_V3 0x4
 #define SD_EMMC_DELAY2_V3 0x8
-#define SD_EMMC_ADJUST_V3 0X10
+#define SD_EMMC_ADJUST_V3 0xc
 #define SD_EMMC_ADJ_IDX_LOG 0x20
 #define SD_EMMC_CLKTEST_LOG    0x24
 #define SD_EMMC_CLKTEST_OUT    0x28
@@ -224,6 +224,13 @@ struct amlsd_platform {
        unsigned char caling;
        unsigned char calout[20][20];
 #endif
+       u64 align[10];
+       int base_line;
+       unsigned int count;
+       unsigned int delay_cell;
+       unsigned int ds_core;
+       /* int order; */
+       unsigned int rx_err;
        /* 0:unknown, 1:mmc card(include eMMC), 2:sd card(include tSD),
         * 3:sdio device(ie:sdio-wifi), 4:SD combo (IO+mem) card,
         * 5:NON sdio device(means sd/mmc card), other:reserved
@@ -327,6 +334,7 @@ struct amlsd_host {
        dma_addr_t              dma_gping; /* 0x400 */
        dma_addr_t              dma_gpong; /* 0x800 */
        char is_tunning;
+       char is_timming;
        char tuning_mode;
        unsigned int irq;
        unsigned int irq_in;
index 4e2cecb..eddfaae 100644 (file)
@@ -155,6 +155,7 @@ struct mmc_host_ops {
                                         int card_drv, int *drv_type);
        void    (*hw_reset)(struct mmc_host *host);
        void    (*card_event)(struct mmc_host *host);
+       int (*post_hs400_timming)(struct mmc_host *host);
 
        /*
         * Optional callback to support controllers with HW issues for multiple