diff -drupN a/drivers/mmc/host/sunxi-mmc-v4p1x.c b/drivers/mmc/host/sunxi-mmc-v4p1x.c --- a/drivers/mmc/host/sunxi-mmc-v4p1x.c 1970-01-01 03:00:00.000000000 +0300 +++ b/drivers/mmc/host/sunxi-mmc-v4p1x.c 2022-06-12 05:28:14.000000000 +0300 @@ -0,0 +1,721 @@ +/* +* Sunxi SD/MMC host driver +* +* Copyright (C) 2015 AllWinnertech Ltd. +* Author: lixiang +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License version 2 as +* published by the Free Software Foundation. +* +* This program is distributed "as is" WITHOUT ANY WARRANTY of any +* kind, whether express or implied; without even the implied warranty +* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +*/ + + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "sunxi-mmc.h" +#include "sunxi-mmc-v4p1x.h" +#include "sunxi-mmc-export.h" + +#define SUNXI_RETRY_CNT_PER_PHA_V4P1X 3 + +/*dma triger level setting*/ +#define SUNXI_DMA_TL_SDMMC_V4P1X ((0x2<<28)|(7<<16)|248) +/*one dma des can transfer data size = 1<>2) + +/*size*/ +#define SDXC_CARD_RD_THLD_SIZE (0x00000FFF) + +/*shit*/ +#define SDXC_CARD_RD_THLD_SIZE_SHIFT (16) + +#define SDXC_STIMING_CMD_PH_SHIFT (4) +#define SDXC_STIMING_DAT_PH_SHIFT (8) + +enum sunxi_mmc_clk_mode { + mmc_clk_400k = 0, + mmc_clk_26M, + mmc_clk_52M, + mmc_clk_52M_DDR4, + mmc_clk_52M_DDR8, + mmc_clk_104M, + mmc_clk_208M, + mmc_clk_104M_DDR, + mmc_clk_208M_DDR, + mmc_clk_mod_num, +}; + +struct sunxi_mmc_clk_dly { + enum sunxi_mmc_clk_mode cmod; + char *mod_str; + u32 cmd_drv_ph; + u32 dat_drv_ph; + u32 sam_dly; + u32 ds_dly; + u32 sam_ph_dat; + u32 sam_ph_cmd; +}; + +struct sunxi_mmc_spec_regs { + u32 drv_dl; /*REG_DRV_DL */ + u32 samp_dl; /*REG_SAMP_DL */ + u32 ds_dl; /*REG_DS_DL */ + u32 sd_ntsr; /*REG_SD_NTSR */ +}; + +struct sunxi_mmc_ver_priv { + struct sunxi_mmc_spec_regs bak_spec_regs; + struct sunxi_mmc_clk_dly mmc_clk_dly[mmc_clk_mod_num]; +}; + + +static void sunxi_mmc_set_clk_dly(struct sunxi_mmc_host *host, int clk, + int bus_width, int timing) +{ + struct mmc_host *mhost = host->mmc; + u32 rval = 0; + enum sunxi_mmc_clk_mode cmod = mmc_clk_400k; + u32 in_clk_dly[6] = { 0 }; + int ret = 0; + struct device_node *np = NULL; + struct sunxi_mmc_clk_dly *mmc_clk_dly = + ((struct sunxi_mmc_ver_priv *)host->version_priv_dat)->mmc_clk_dly; + + if (!mhost->parent || !mhost->parent->of_node) { + dev_err(mmc_dev(host->mmc), + "no dts to parse clk dly,use default\n"); + return; + } + + np = mhost->parent->of_node; + + if (clk <= 400 * 1000) { + cmod = mmc_clk_400k; + } else if (clk <= 26 * 1000 * 1000) { + cmod = mmc_clk_26M; + } else if (clk <= 52 * 1000 * 1000) { + if ((bus_width == MMC_BUS_WIDTH_4) + && sunxi_mmc_ddr_timing(timing)) { + cmod = mmc_clk_52M_DDR4; + } else if ((bus_width == MMC_BUS_WIDTH_8) + && (timing == MMC_TIMING_MMC_DDR52)) { + cmod = mmc_clk_52M_DDR8; + } else { + cmod = mmc_clk_52M; + } + } else if (clk <= 104 * 1000 * 1000) { + if ((bus_width == MMC_BUS_WIDTH_8) + && (timing == MMC_TIMING_MMC_HS400)) { + cmod = mmc_clk_104M_DDR; + } else { + cmod = mmc_clk_104M; + } + } else if (clk <= 208 * 1000 * 1000) { + if ((bus_width == MMC_BUS_WIDTH_8) + && (timing == MMC_TIMING_MMC_HS400)) { + cmod = mmc_clk_208M_DDR; + } else { + cmod = mmc_clk_208M; + } + } else { + dev_err(mmc_dev(mhost), "clk %d is out of range\n", clk); + return; + } + + ret = of_property_read_u32_array(np, mmc_clk_dly[cmod].mod_str, + in_clk_dly, ARRAY_SIZE(in_clk_dly)); + if (ret) { + dev_dbg(mmc_dev(host->mmc), "failed to get %s used default\n", + mmc_clk_dly[cmod].mod_str); + } else { + mmc_clk_dly[cmod].cmd_drv_ph = in_clk_dly[0]; + mmc_clk_dly[cmod].dat_drv_ph = in_clk_dly[1]; + /*mmc_clk_dly[cmod].sam_dly = in_clk_dly[2]; */ + /*mmc_clk_dly[cmod].ds_dly = in_clk_dly[3]; */ + mmc_clk_dly[cmod].sam_ph_dat = in_clk_dly[4]; + mmc_clk_dly[cmod].sam_ph_cmd = in_clk_dly[5]; + dev_dbg(mmc_dev(host->mmc), "Get %s clk dly ok\n", + mmc_clk_dly[cmod].mod_str); + + } + + dev_dbg(mmc_dev(host->mmc), "Try set %s clk dly ok\n", + mmc_clk_dly[cmod].mod_str); + dev_dbg(mmc_dev(host->mmc), "cmd_drv_ph %d\n", + mmc_clk_dly[cmod].cmd_drv_ph); + dev_dbg(mmc_dev(host->mmc), "dat_drv_ph %d\n", + mmc_clk_dly[cmod].dat_drv_ph); + dev_dbg(mmc_dev(host->mmc), "sam_ph_dat %d\n", + mmc_clk_dly[cmod].sam_ph_dat); + dev_dbg(mmc_dev(host->mmc), "sam_ph_cmd %d\n", + mmc_clk_dly[cmod].sam_ph_cmd); + + rval = mmc_readl(host, REG_DRV_DL); + if (mmc_clk_dly[cmod].cmd_drv_ph) + rval |= SDXC_CMD_DRV_PH_SEL; /*180 phase */ + else + rval &= ~SDXC_CMD_DRV_PH_SEL; /*90 phase */ + + if (mmc_clk_dly[cmod].dat_drv_ph) + rval |= SDXC_DAT_DRV_PH_SEL; /*180 phase */ + else + rval &= ~SDXC_DAT_DRV_PH_SEL; /*90 phase */ + + mmc_writel(host, REG_DRV_DL, rval); + +/* +* rval = mmc_readl(host,REG_SAMP_DL); +* rval &= ~SDXC_SAMP_DL_SW_MASK; +* rval |= mmc_clk_dly[cmod].sam_dly & SDXC_SAMP_DL_SW_MASK; +* rval |= SDXC_SAMP_DL_SW_EN; +* mmc_writel(host,REG_SAMP_DL,rval); +* +* rval = mmc_readl(host,REG_DS_DL); +* rval &= ~SDXC_DS_DL_SW_MASK; +* rval |= mmc_clk_dly[cmod].ds_dly & SDXC_DS_DL_SW_MASK; +* rval |= SDXC_DS_DL_SW_EN; +* mmc_writel(host,REG_DS_DL,rval); +*/ + + rval = mmc_readl(host, REG_SD_NTSR); + rval &= ~SDXC_STIMING_DAT_PH_MASK; + rval |= + (mmc_clk_dly[cmod]. + sam_ph_dat << SDXC_STIMING_DAT_PH_SHIFT) & + SDXC_STIMING_DAT_PH_MASK; + mmc_writel(host, REG_SD_NTSR, rval); + + rval = mmc_readl(host, REG_SD_NTSR); + rval &= ~SDXC_STIMING_CMD_PH_MASK; + rval |= + (mmc_clk_dly[cmod]. + sam_ph_cmd << SDXC_STIMING_CMD_PH_SHIFT) & + SDXC_STIMING_CMD_PH_MASK; + mmc_writel(host, REG_SD_NTSR, rval); + + dev_dbg(mmc_dev(host->mmc), " REG_DRV_DL %08x\n", + mmc_readl(host, REG_DRV_DL)); + dev_dbg(mmc_dev(host->mmc), " REG_SAMP_DL %08x\n", + mmc_readl(host, REG_SAMP_DL)); + dev_dbg(mmc_dev(host->mmc), " REG_DS_DL %08x\n", + mmc_readl(host, REG_DS_DL)); + dev_dbg(mmc_dev(host->mmc), " REG_SD_NTSR %08x\n", + mmc_readl(host, REG_SD_NTSR)); + +} + +static int __sunxi_mmc_do_oclk_onoff(struct sunxi_mmc_host *host, u32 oclk_en, + u32 pwr_save, u32 ignore_dat0) +{ + unsigned long expire = jiffies + msecs_to_jiffies(250); + u32 rval; + + rval = mmc_readl(host, REG_CLKCR); + rval &= ~(SDXC_CARD_CLOCK_ON | SDXC_LOW_POWER_ON | SDXC_MASK_DATA0); + + if (oclk_en) + rval |= SDXC_CARD_CLOCK_ON; + if (pwr_save) + rval |= SDXC_LOW_POWER_ON; + if (ignore_dat0) + rval |= SDXC_MASK_DATA0; + + mmc_writel(host, REG_CLKCR, rval); + + dev_dbg(mmc_dev(host->mmc), "%s REG_CLKCR:%x\n", __func__, + mmc_readl(host, REG_CLKCR)); + + rval = SDXC_START | SDXC_UPCLK_ONLY | SDXC_WAIT_PRE_OVER; + mmc_writel(host, REG_CMDR, rval); + + do { + rval = mmc_readl(host, REG_CMDR); + } while (time_before(jiffies, expire) && (rval & SDXC_START)); + + /* clear irq status bits set by the command */ + mmc_writel(host, REG_RINTR, + mmc_readl(host, REG_RINTR) & ~SDXC_SDIO_INTERRUPT); + + if (rval & SDXC_START) { + dev_err(mmc_dev(host->mmc), "fatal err update clk timeout\n"); + return -EIO; + } + + /*only use mask data0 when update clk,clear it when not update clk */ + if (ignore_dat0) + mmc_writel(host, REG_CLKCR, + mmc_readl(host, REG_CLKCR) & ~SDXC_MASK_DATA0); + + return 0; +} + +static int sunxi_mmc_oclk_onoff(struct sunxi_mmc_host *host, u32 oclk_en) +{ + struct device_node *np = NULL; + struct mmc_host *mmc = host->mmc; + int pwr_save = 0; + int len = 0; + + if (!mmc->parent || !mmc->parent->of_node) { + dev_err(mmc_dev(host->mmc), + "no dts to parse power save mode\n"); + return -EIO; + } + + np = mmc->parent->of_node; + if (of_find_property(np, "sunxi-power-save-mode", &len)) + pwr_save = 1; + return __sunxi_mmc_do_oclk_onoff(host, oclk_en, pwr_save, 1); +} + +static void sunxi_mmc_2xmod_onoff(struct sunxi_mmc_host *host, u32 newmode_en) +{ + u32 rval = mmc_readl(host, REG_SD_NTSR); + + if (newmode_en) + rval |= SDXC_2X_TIMING_MODE; + else + rval &= ~SDXC_2X_TIMING_MODE; + + mmc_writel(host, REG_SD_NTSR, rval); + + dev_dbg(mmc_dev(host->mmc), "REG_SD_NTSR: 0x%08x ,val %x\n", + mmc_readl(host, REG_SD_NTSR), rval); +} + +static int sunxi_mmc_clk_set_rate_for_sdmmc_v4p1x(struct sunxi_mmc_host *host, + struct mmc_ios *ios) +{ + u32 mod_clk = 0; + u32 src_clk = 0; + u32 rval = 0; + s32 err = 0; + u32 rate = 0; + char *sclk_name = NULL; + struct clk *mclk = host->clk_mmc; + struct clk *sclk = NULL; + struct device *dev = mmc_dev(host->mmc); + int div = 0; + + if (ios->clock == 0) { + __sunxi_mmc_do_oclk_onoff(host, 0, 0, 1); + return 0; + } + + if (sunxi_mmc_ddr_timing(ios->timing)) { + mod_clk = ios->clock << 2; + div = 1; + } else { + mod_clk = ios->clock << 1; + div = 0; + } + + sclk = clk_get(dev, "osc24m"); + sclk_name = "osc24m"; + if (IS_ERR(sclk)) { + dev_err(mmc_dev(host->mmc), "Error to get source clock %s\n", + sclk_name); + return -1; + } + + src_clk = clk_get_rate(sclk); + if (mod_clk > src_clk) { + clk_put(sclk); + sclk = clk_get(dev, "pll_periph"); + sclk_name = "pll_periph"; + } + if (IS_ERR(sclk)) { + dev_err(mmc_dev(host->mmc), "Error to get source clock %s\n", + sclk_name); + return -1; + } + + sunxi_mmc_oclk_onoff(host, 0); + + err = clk_set_parent(mclk, sclk); + if (err) { + dev_err(mmc_dev(host->mmc), "set parent failed\n"); + clk_put(sclk); + return -1; + } + + rate = clk_round_rate(mclk, mod_clk); + + dev_dbg(mmc_dev(host->mmc), "get round rate %d\n", rate); + + /*clk_disable_unprepare(host->clk_mmc);*/ + + err = clk_set_rate(mclk, rate); + if (err) { + dev_err(mmc_dev(host->mmc), "set mclk rate error, rate %dHz\n", + rate); + clk_put(sclk); + return -1; + } +/* + rval = clk_prepare_enable(host->clk_mmc); + if (rval) { + dev_err(mmc_dev(host->mmc), "Enable mmc clk err %d\n", rval); + return -1; + } +*/ + src_clk = clk_get_rate(sclk); + clk_put(sclk); + + dev_dbg(mmc_dev(host->mmc), "set round clock %d, soure clk is %d\n", + rate, src_clk); + +#ifdef MMC_FPGA + if (sunxi_mmc_ddr_timing(ios->timing)) { + /* clear internal divider */ + rval = mmc_readl(host, REG_CLKCR); + rval &= ~0xff; + rval |= 1; + } else { + /* support internal divide clock under fpga environment */ + rval = mmc_readl(host, REG_CLKCR); + rval &= ~0xff; + rval |= 24000000 / mod_clk / 2; /* =24M/400K/2=0x1E */ + } + mmc_writel(host, REG_CLKCR, rval); + dev_info(mmc_dev(host->mmc), "FPGA REG_CLKCR: 0x%08x\n", + mmc_readl(host, REG_CLKCR)); +#else + /* clear internal divider */ + rval = mmc_readl(host, REG_CLKCR); + rval &= ~0xff; + rval |= div; + mmc_writel(host, REG_CLKCR, rval); +#endif + + /*sunxi_of_parse_clk_dly(host); */ + sunxi_mmc_2xmod_onoff(host, 1); + + if (sunxi_mmc_ddr_timing(ios->timing)) + ios->clock = rate >> 2; + else + ios->clock = rate >> 1; + + sunxi_mmc_set_clk_dly(host, ios->clock, ios->bus_width, ios->timing); + + return sunxi_mmc_oclk_onoff(host, 1); +} + +static void sunxi_mmc_thld_ctl_for_sdmmc_v4p1x(struct sunxi_mmc_host *host, + struct mmc_ios *ios, + struct mmc_data *data) +{ + u32 bsz = data->blksz; + /*unit:byte */ + /*u32 tdtl = (host->dma_tl & SDXC_TX_TL_MASK)<<2;*/ + /*unit:byte */ + u32 rdtl = ((host->dma_tl & SDXC_RX_TL_MASK) >> 16) << 2; + u32 rval = 0; + + if ((data->flags & MMC_DATA_READ) + && (bsz <= SDXC_CARD_RD_THLD_SIZE) + /*((SDXC_FIFO_DETH<<2)-bsz) >= (rdtl) */ + && ((SDXC_FIFO_DETH << 2) >= (rdtl + bsz)) + && ((ios->timing == MMC_TIMING_MMC_HS200) + || (ios->timing == MMC_TIMING_UHS_SDR50) + || (ios->timing == MMC_TIMING_UHS_SDR104))) { + rval = mmc_readl(host, REG_THLD); + rval &= ~SDXC_CARD_RD_THLD_MASK; + rval |= data->blksz << SDXC_CARD_RD_THLD_SIZE_SHIFT; + rval |= SDXC_CARD_RD_THLD_ENB; + mmc_writel(host, REG_THLD, rval); + } else { + rval = mmc_readl(host, REG_THLD); + rval &= ~SDXC_CARD_RD_THLD_ENB; + mmc_writel(host, REG_THLD, rval); + } + + dev_dbg(mmc_dev(host->mmc), "SDXC_REG_THLD: 0x%08x\n", + mmc_readl(host, REG_THLD)); + +} + +static void sunxi_mmc_save_spec_reg_v4p1x(struct sunxi_mmc_host *host) +{ + struct sunxi_mmc_spec_regs *spec_regs = + &((struct sunxi_mmc_ver_priv *)(host->version_priv_dat))-> + bak_spec_regs; + spec_regs->drv_dl = mmc_readl(host, REG_DRV_DL); + spec_regs->samp_dl = mmc_readl(host, REG_SAMP_DL); + spec_regs->ds_dl = mmc_readl(host, REG_DS_DL); + spec_regs->sd_ntsr = mmc_readl(host, REG_SD_NTSR); +} + +static void sunxi_mmc_restore_spec_reg_v4p1x(struct sunxi_mmc_host *host) +{ + struct sunxi_mmc_spec_regs *spec_regs = + &((struct sunxi_mmc_ver_priv *)(host->version_priv_dat))-> + bak_spec_regs; + mmc_writel(host, REG_DRV_DL, spec_regs->drv_dl); + mmc_writel(host, REG_SAMP_DL, spec_regs->samp_dl); + mmc_writel(host, REG_DS_DL, spec_regs->ds_dl); + mmc_writel(host, REG_SD_NTSR, spec_regs->sd_ntsr); +} + +static inline void sunxi_mmc_set_dly_raw(struct sunxi_mmc_host *host, + s32 opha_cmd, s32 ipha_cmd, + s32 opha_dat, s32 ipha_dat) +{ + u32 rval = mmc_readl(host, REG_DRV_DL); + + if (opha_cmd > 0) + rval |= SDXC_CMD_DRV_PH_SEL; /*180 phase */ + else if (opha_cmd == 0) + rval &= ~SDXC_CMD_DRV_PH_SEL; /*90 phase */ + + if (opha_dat > 0) + rval |= SDXC_DAT_DRV_PH_SEL; /*180 phase */ + else if (opha_dat == 0) + rval &= ~SDXC_DAT_DRV_PH_SEL; /*90 phase */ + + mmc_writel(host, REG_DRV_DL, rval); + + rval = mmc_readl(host, REG_SD_NTSR); + + if (ipha_cmd >= 0) { + rval &= ~SDXC_STIMING_CMD_PH_MASK; + rval |= + (ipha_cmd << SDXC_STIMING_CMD_PH_SHIFT) & + SDXC_STIMING_CMD_PH_MASK; + } + + if (ipha_dat >= 0) { + rval &= ~SDXC_STIMING_DAT_PH_MASK; + rval |= + (ipha_dat << SDXC_STIMING_DAT_PH_SHIFT) & + SDXC_STIMING_DAT_PH_MASK; + } + + rval &= ~SDXC_2X_TIMING_MODE; + mmc_writel(host, REG_SD_NTSR, rval); + rval |= SDXC_2X_TIMING_MODE; + mmc_writel(host, REG_SD_NTSR, rval); + + dev_info(mmc_dev(host->mmc), "REG_DRV_DL: 0x%08x\n", + mmc_readl(host, REG_DRV_DL)); + dev_info(mmc_dev(host->mmc), "REG_SD_NTSR: 0x%08x\n", + mmc_readl(host, REG_SD_NTSR)); +} + +static int sunxi_mmc_judge_retry_v4p1x(struct sunxi_mmc_host *host, + struct mmc_command *cmd, u32 rcnt, + u32 errno, void *other) +{ + /****-1 means use default value***/ + /* + *We use {-1,-1} as first member,because we want to + *retry current delay first. + *Only If current delay failed,we try new delay + */ + const s32 sunxi_phase[10][2] = { {-1, -1}, + {1, 1}, {0, 0}, {1, 0}, {0, 1}, {1, 2}, {0, 2} }; + + if (rcnt < (SUNXI_RETRY_CNT_PER_PHA_V4P1X * 10)) { + sunxi_mmc_set_dly_raw(host, + sunxi_phase[rcnt / + SUNXI_RETRY_CNT_PER_PHA_V4P1X] + [0], + sunxi_phase[rcnt / + SUNXI_RETRY_CNT_PER_PHA_V4P1X] + [1], + sunxi_phase[rcnt / + SUNXI_RETRY_CNT_PER_PHA_V4P1X] + [0], + sunxi_phase[rcnt / + SUNXI_RETRY_CNT_PER_PHA_V4P1X] + [1]); + return 0; + } + + sunxi_mmc_set_dly_raw(host, sunxi_phase[0][0], + sunxi_phase[0][1], + sunxi_phase[0][0], sunxi_phase[0][1]); + dev_info(mmc_dev(host->mmc), "sunxi v4p1x retry give up\n"); + return -1; +} + +void sunxi_mmc_init_priv_v4p1x(struct sunxi_mmc_host *host, + struct platform_device *pdev, int phy_index) +{ + struct sunxi_mmc_ver_priv *ver_priv = + devm_kzalloc(&pdev->dev, sizeof(struct sunxi_mmc_ver_priv), + GFP_KERNEL); + host->version_priv_dat = ver_priv; + ver_priv->mmc_clk_dly[mmc_clk_400k].cmod = mmc_clk_400k; + ver_priv->mmc_clk_dly[mmc_clk_400k].mod_str = "sunxi-dly-400k"; + ver_priv->mmc_clk_dly[mmc_clk_400k].cmd_drv_ph = 1; + ver_priv->mmc_clk_dly[mmc_clk_400k].dat_drv_ph = 0; + ver_priv->mmc_clk_dly[mmc_clk_400k].sam_dly = 0; + ver_priv->mmc_clk_dly[mmc_clk_400k].ds_dly = 0; + ver_priv->mmc_clk_dly[mmc_clk_400k].sam_ph_dat = 0; + ver_priv->mmc_clk_dly[mmc_clk_400k].sam_ph_cmd = 0; + + ver_priv->mmc_clk_dly[mmc_clk_26M].cmod = mmc_clk_26M; + ver_priv->mmc_clk_dly[mmc_clk_26M].mod_str = "sunxi-dly-26M"; + ver_priv->mmc_clk_dly[mmc_clk_26M].cmd_drv_ph = 1; + ver_priv->mmc_clk_dly[mmc_clk_26M].dat_drv_ph = 0; + ver_priv->mmc_clk_dly[mmc_clk_26M].sam_dly = 0; + ver_priv->mmc_clk_dly[mmc_clk_26M].ds_dly = 0; + ver_priv->mmc_clk_dly[mmc_clk_26M].sam_ph_dat = 0; + ver_priv->mmc_clk_dly[mmc_clk_26M].sam_ph_cmd = 0; + + ver_priv->mmc_clk_dly[mmc_clk_52M].cmod = mmc_clk_52M, + ver_priv->mmc_clk_dly[mmc_clk_52M].mod_str = "sunxi-dly-52M"; + ver_priv->mmc_clk_dly[mmc_clk_52M].cmd_drv_ph = 1; + ver_priv->mmc_clk_dly[mmc_clk_52M].dat_drv_ph = 1; + ver_priv->mmc_clk_dly[mmc_clk_52M].sam_dly = 0; + ver_priv->mmc_clk_dly[mmc_clk_52M].ds_dly = 0; + ver_priv->mmc_clk_dly[mmc_clk_52M].sam_ph_dat = 1; + ver_priv->mmc_clk_dly[mmc_clk_52M].sam_ph_cmd = 1; + + ver_priv->mmc_clk_dly[mmc_clk_52M_DDR4].cmod = mmc_clk_52M_DDR4; + ver_priv->mmc_clk_dly[mmc_clk_52M_DDR4].mod_str = "sunxi-dly-52M-ddr4"; + ver_priv->mmc_clk_dly[mmc_clk_52M_DDR4].cmd_drv_ph = 1; + ver_priv->mmc_clk_dly[mmc_clk_52M_DDR4].dat_drv_ph = 1; + ver_priv->mmc_clk_dly[mmc_clk_52M_DDR4].sam_dly = 0; + ver_priv->mmc_clk_dly[mmc_clk_52M_DDR4].ds_dly = 0; + ver_priv->mmc_clk_dly[mmc_clk_52M_DDR4].sam_ph_dat = 1; + ver_priv->mmc_clk_dly[mmc_clk_52M_DDR4].sam_ph_cmd = 1; + + ver_priv->mmc_clk_dly[mmc_clk_52M_DDR8].cmod = mmc_clk_52M_DDR8; + ver_priv->mmc_clk_dly[mmc_clk_52M_DDR8].mod_str = "sunxi-dly-52M-ddr8"; + ver_priv->mmc_clk_dly[mmc_clk_52M_DDR8].cmd_drv_ph = 1; + ver_priv->mmc_clk_dly[mmc_clk_52M_DDR8].dat_drv_ph = 1; + ver_priv->mmc_clk_dly[mmc_clk_52M_DDR8].sam_dly = 0; + ver_priv->mmc_clk_dly[mmc_clk_52M_DDR8].ds_dly = 0; + ver_priv->mmc_clk_dly[mmc_clk_52M_DDR8].sam_ph_dat = 1; + ver_priv->mmc_clk_dly[mmc_clk_52M_DDR8].sam_ph_cmd = 1; + + ver_priv->mmc_clk_dly[mmc_clk_104M].cmod = mmc_clk_104M; + ver_priv->mmc_clk_dly[mmc_clk_104M].mod_str = "sunxi-dly-104M"; + ver_priv->mmc_clk_dly[mmc_clk_104M].cmd_drv_ph = 1; + ver_priv->mmc_clk_dly[mmc_clk_104M].dat_drv_ph = 0; + ver_priv->mmc_clk_dly[mmc_clk_104M].sam_dly = 0; + ver_priv->mmc_clk_dly[mmc_clk_104M].ds_dly = 0; + ver_priv->mmc_clk_dly[mmc_clk_104M].sam_ph_dat = 0; + ver_priv->mmc_clk_dly[mmc_clk_104M].sam_ph_cmd = 0; + + ver_priv->mmc_clk_dly[mmc_clk_208M].cmod = mmc_clk_208M; + ver_priv->mmc_clk_dly[mmc_clk_208M].mod_str = "sunxi-dly-208M"; + ver_priv->mmc_clk_dly[mmc_clk_208M].cmd_drv_ph = 1; + ver_priv->mmc_clk_dly[mmc_clk_208M].dat_drv_ph = 0; + ver_priv->mmc_clk_dly[mmc_clk_208M].sam_dly = 0; + ver_priv->mmc_clk_dly[mmc_clk_208M].ds_dly = 0; + ver_priv->mmc_clk_dly[mmc_clk_208M].sam_ph_dat = 0; + ver_priv->mmc_clk_dly[mmc_clk_208M].sam_ph_cmd = 0; + + ver_priv->mmc_clk_dly[mmc_clk_104M_DDR].cmod = mmc_clk_104M_DDR; + ver_priv->mmc_clk_dly[mmc_clk_104M_DDR].mod_str = "sunxi-dly-104M-ddr"; + ver_priv->mmc_clk_dly[mmc_clk_104M_DDR].cmd_drv_ph = 1; + ver_priv->mmc_clk_dly[mmc_clk_104M_DDR].dat_drv_ph = 0; + ver_priv->mmc_clk_dly[mmc_clk_104M_DDR].sam_dly = 0; + ver_priv->mmc_clk_dly[mmc_clk_104M_DDR].ds_dly = 0; + ver_priv->mmc_clk_dly[mmc_clk_104M_DDR].sam_ph_dat = 0; + ver_priv->mmc_clk_dly[mmc_clk_104M_DDR].sam_ph_cmd = 0; + + ver_priv->mmc_clk_dly[mmc_clk_208M_DDR].cmod = mmc_clk_208M_DDR; + ver_priv->mmc_clk_dly[mmc_clk_208M_DDR].mod_str = "sunxi-dly-208M-ddr"; + ver_priv->mmc_clk_dly[mmc_clk_208M_DDR].cmd_drv_ph = 1; + ver_priv->mmc_clk_dly[mmc_clk_208M_DDR].dat_drv_ph = 0; + ver_priv->mmc_clk_dly[mmc_clk_208M_DDR].sam_dly = 0; + ver_priv->mmc_clk_dly[mmc_clk_208M_DDR].ds_dly = 0; + ver_priv->mmc_clk_dly[mmc_clk_208M_DDR].sam_ph_dat = 0; + ver_priv->mmc_clk_dly[mmc_clk_208M_DDR].sam_ph_cmd = 0; + + host->sunxi_mmc_clk_set_rate = sunxi_mmc_clk_set_rate_for_sdmmc_v4p1x; + host->dma_tl = SUNXI_DMA_TL_SDMMC_V4P1X; + host->idma_des_size_bits = SUNXI_DES_SIZE_SDMMC_V4P1X; + host->sunxi_mmc_thld_ctl = sunxi_mmc_thld_ctl_for_sdmmc_v4p1x; + host->sunxi_mmc_save_spec_reg = sunxi_mmc_save_spec_reg_v4p1x; + host->sunxi_mmc_restore_spec_reg = sunxi_mmc_restore_spec_reg_v4p1x; + sunxi_mmc_reg_ex_res_inter(host, phy_index); + host->sunxi_mmc_set_acmda = sunxi_mmc_set_a12a; + host->phy_index = phy_index; + host->sunxi_mmc_oclk_en = sunxi_mmc_oclk_onoff; + host->sunxi_mmc_judge_retry = sunxi_mmc_judge_retry_v4p1x; + /*sunxi_of_parse_clk_dly(host); */ +#if (defined(CONFIG_ARCH_SUN50IW9P1) || defined(CONFIG_ARCH_SUN50IW10)) + host->des_addr_shift = 2; +#endif +} +EXPORT_SYMBOL_GPL(sunxi_mmc_init_priv_v4p1x);