diff --git a/drivers/mmc/sunxi_mmc.c b/drivers/mmc/sunxi_mmc.c index 0b56d1405bee..1d313166371f 100644 --- a/drivers/mmc/sunxi_mmc.c +++ b/drivers/mmc/sunxi_mmc.c @@ -66,7 +66,7 @@ static bool sunxi_mmc_can_calibrate(void) static int mmc_set_mod_clk(struct sunxi_mmc_priv *priv, unsigned int hz) { - unsigned int pll, pll_hz, div, n, oclk_dly, sclk_dly; + unsigned int pll, pll_hz, div, n, oclk_dly, sclk_dly, clk; bool new_mode = IS_ENABLED(CONFIG_MMC_SUNXI_HAS_NEW_MODE); u32 val = 0; @@ -74,7 +74,11 @@ static int mmc_set_mod_clk(struct sunxi_mmc_priv *priv, unsigned int hz) if (IS_ENABLED(CONFIG_MACH_SUN8I_A83T) && priv->mmc_no != 2) new_mode = false; - if (hz <= 24000000) { + clk = hz; + if (new_mode && priv->mmc_no == 2) + clk *= 2; + + if (clk <= 24000000) { pll = CCM_MMC_CTRL_OSCM24; pll_hz = 24000000; } else { @@ -94,8 +98,8 @@ static int mmc_set_mod_clk(struct sunxi_mmc_priv *priv, unsigned int hz) #endif } - div = pll_hz / hz; - if (pll_hz % hz) + div = pll_hz / clk; + if (pll_hz % clk) div++; n = 0; @@ -377,6 +381,7 @@ static int sunxi_mmc_send_cmd_common(struct sunxi_mmc_priv *priv, bytecnt = data->blocksize * data->blocks; debug("trans data %d bytes\n", bytecnt); + setbits_le32(&priv->reg->gctrl, SUNXI_MMC_GCTRL_ACCESS_BY_AHB); writel(cmdval | cmd->cmdidx, &priv->reg->cmd); ret = mmc_trans_data_by_cpu(priv, mmc, data); if (ret) { @@ -442,6 +447,30 @@ out: return error; } +static void sunxi_mmc_reset(struct sunxi_mmc *regs) +{ + /* Reset controller */ + writel(SUNXI_MMC_GCTRL_RESET, ®s->gctrl); + udelay(1000); + + if (IS_ENABLED(CONFIG_SUN50I_GEN_H6) || IS_ENABLED(CONFIG_SUNXI_GEN_NCAT2)) { + /* Reset card */ + writel(SUNXI_MMC_HWRST_ASSERT, ®s->hwrst); + udelay(10); + writel(SUNXI_MMC_HWRST_DEASSERT, ®s->hwrst); + udelay(300); + + /* Setup FIFO R/W threshold. Needed on H616. */ + writel(SUNXI_MMC_THLDC_READ_THLD(512) | + SUNXI_MMC_THLDC_WRITE_EN | + SUNXI_MMC_THLDC_READ_EN, ®s->thldc); + + writel((0xffffffU << 8) | 0xff, &priv->reg->timeout); + writel(3, &priv->reg->csdc); + writel(0xdeb, &priv->reg->dbgc); + } +} + /* non-DM code here is used by the (ARM) SPL only */ #if !CONFIG_IS_ENABLED(DM_MMC) @@ -489,9 +518,7 @@ static int sunxi_mmc_core_init(struct mmc *mmc) { struct sunxi_mmc_priv *priv = mmc->priv; - /* Reset controller */ - writel(SUNXI_MMC_GCTRL_RESET, &priv->reg->gctrl); - udelay(1000); + sunxi_mmc_reset(priv->reg); return 0; } @@ -684,9 +711,7 @@ static int sunxi_mmc_probe(struct udevice *dev) upriv->mmc = &plat->mmc; - /* Reset controller */ - writel(SUNXI_MMC_GCTRL_RESET, &priv->reg->gctrl); - udelay(1000); + sunxi_mmc_reset(priv->reg); return 0; } diff --git a/drivers/mmc/sunxi_mmc.h b/drivers/mmc/sunxi_mmc.h index f4ae5a790c87..05fc34e5b869 100644 --- a/drivers/mmc/sunxi_mmc.h +++ b/drivers/mmc/sunxi_mmc.h @@ -34,10 +34,12 @@ struct sunxi_mmc { u32 cbcr; /* 0x48 CIU byte count */ u32 bbcr; /* 0x4c BIU byte count */ u32 dbgc; /* 0x50 debug enable */ - u32 res0; /* 0x54 reserved */ + u32 csdc; /* 0x54 crc status detect */ u32 a12a; /* 0x58 Auto command 12 argument */ u32 ntsr; /* 0x5c New timing set register */ - u32 res1[8]; + u32 res1[6]; + u32 hwrst; /* 0x78 Hardware Reset */ + u32 res5; u32 dmac; /* 0x80 internal DMA control */ u32 dlba; /* 0x84 internal DMA descr list base address */ u32 idst; /* 0x88 internal DMA status */ @@ -46,7 +48,8 @@ struct sunxi_mmc { u32 cbda; /* 0x94 */ u32 res2[26]; #if defined(CONFIG_SUNXI_GEN_SUN6I) || defined(CONFIG_SUN50I_GEN_H6) || defined(CONFIG_SUNXI_GEN_NCAT2) - u32 res3[17]; + u32 thldc; /* 0x100 Threshold control */ + u32 res3[16]; u32 samp_dl; u32 res4[46]; #endif @@ -123,6 +126,9 @@ struct sunxi_mmc { #define SUNXI_MMC_NTSR_MODE_SEL_NEW (0x1 << 31) +#define SUNXI_MMC_HWRST_ASSERT (0x0 << 0) +#define SUNXI_MMC_HWRST_DEASSERT (0x1 << 0) + #define SUNXI_MMC_IDMAC_RESET (0x1 << 0) #define SUNXI_MMC_IDMAC_FIXBURST (0x1 << 1) #define SUNXI_MMC_IDMAC_ENABLE (0x1 << 7) @@ -133,6 +139,11 @@ struct sunxi_mmc { #define SUNXI_MMC_COMMON_CLK_GATE (1 << 16) #define SUNXI_MMC_COMMON_RESET (1 << 18) +#define SUNXI_MMC_THLDC_READ_EN (0x1 << 0) +#define SUNXI_MMC_THLDC_BSY_CLR_INT_EN (0x1 << 1) +#define SUNXI_MMC_THLDC_WRITE_EN (0x1 << 2) +#define SUNXI_MMC_THLDC_READ_THLD(x) (((x) & 0xfff) << 16) + #define SUNXI_MMC_CAL_DL_SW_EN (0x1 << 7) #endif /* _SUNXI_MMC_H */