diff --git a/arch/arm/include/asm/arch-sunxi/clock_sun8i_a83t.h b/arch/arm/include/asm/arch-sunxi/clock_sun8i_a83t.h index 5e1346e..5dfcbf3 100644 --- a/arch/arm/include/asm/arch-sunxi/clock_sun8i_a83t.h +++ b/arch/arm/include/asm/arch-sunxi/clock_sun8i_a83t.h @@ -220,6 +220,7 @@ struct sunxi_ccm_reg { #define CCM_MMC_CTRL_SCLK_DLY(x) ((x) << 20) #define CCM_MMC_CTRL_OSCM24 (0x0 << 24) #define CCM_MMC_CTRL_PLL6 (0x1 << 24) +#define CCM_MMC_CTRL_MODE_SEL_NEW (0x1 << 30) #define CCM_MMC_CTRL_ENABLE (0x1 << 31) #define CCM_USB_CTRL_PHY0_RST (0x1 << 0) diff --git a/arch/arm/include/asm/arch-sunxi/mmc.h b/arch/arm/include/asm/arch-sunxi/mmc.h index cb52e64..69f737f 100644 --- a/arch/arm/include/asm/arch-sunxi/mmc.h +++ b/arch/arm/include/asm/arch-sunxi/mmc.h @@ -35,16 +35,19 @@ struct sunxi_mmc { u32 cbcr; /* 0x48 CIU byte count */ u32 bbcr; /* 0x4c BIU byte count */ u32 dbgc; /* 0x50 debug enable */ - u32 res0[11]; + u32 res0; /* 0x54 reserved */ + u32 a12a; /* 0x58 Auto command 12 argument */ + u32 ntsr; /* 0x5c New timing set register */ + u32 res1[8]; u32 dmac; /* 0x80 internal DMA control */ u32 dlba; /* 0x84 internal DMA descr list base address */ u32 idst; /* 0x88 internal DMA status */ u32 idie; /* 0x8c internal DMA interrupt enable */ u32 chda; /* 0x90 */ u32 cbda; /* 0x94 */ - u32 res1[26]; + u32 res2[26]; #ifdef CONFIG_SUNXI_GEN_SUN6I - u32 res2[64]; + u32 res3[64]; #endif u32 fifo; /* 0x100 / 0x200 FIFO access address */ }; @@ -116,6 +119,8 @@ struct sunxi_mmc { #define SUNXI_MMC_STATUS_CARD_DATA_BUSY (0x1 << 9) #define SUNXI_MMC_STATUS_DATA_FSM_BUSY (0x1 << 10) +#define SUNXI_MMC_NTSR_MODE_SEL_NEW (0x1 << 31) + #define SUNXI_MMC_IDMAC_RESET (0x1 << 0) #define SUNXI_MMC_IDMAC_FIXBURST (0x1 << 1) #define SUNXI_MMC_IDMAC_ENABLE (0x1 << 7) diff --git a/drivers/mmc/Kconfig b/drivers/mmc/Kconfig index 56c352e..6de927b 100644 --- a/drivers/mmc/Kconfig +++ b/drivers/mmc/Kconfig @@ -369,6 +369,10 @@ config MMC_SUNXI This selects support for the SD/MMC Host Controller on Allwinner sunxi SoCs. +config MMC_SUNXI_HAS_NEW_MODE + bool + depends on MMC_SUNXI + config GENERIC_ATMEL_MCI bool "Atmel Multimedia Card Interface support" depends on DM_MMC && BLK && ARCH_AT91 diff --git a/drivers/mmc/sunxi_mmc.c b/drivers/mmc/sunxi_mmc.c index 588574f..bc638ae 100644 --- a/drivers/mmc/sunxi_mmc.c +++ b/drivers/mmc/sunxi_mmc.c @@ -96,6 +96,18 @@ static int mmc_resource_init(int sdc_no) 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; + bool new_mode = false; + u32 val = 0; + + if (IS_ENABLED(CONFIG_MMC_SUNXI_HAS_NEW_MODE) && (priv->mmc_no == 2)) + new_mode = true; + + /* + * The MMC clock has an extra /2 post-divider when operating in the new + * mode. + */ + if (new_mode) + hz = hz * 2; if (hz <= 24000000) { pll = CCM_MMC_CTRL_OSCM24; @@ -152,9 +164,18 @@ static int mmc_set_mod_clk(struct sunxi_mmc_priv *priv, unsigned int hz) #endif } - writel(CCM_MMC_CTRL_ENABLE | pll | CCM_MMC_CTRL_SCLK_DLY(sclk_dly) | - CCM_MMC_CTRL_N(n) | CCM_MMC_CTRL_OCLK_DLY(oclk_dly) | - CCM_MMC_CTRL_M(div), priv->mclkreg); + if (new_mode) { +#ifdef CONFIG_MMC_SUNXI_HAS_NEW_MODE + val = CCM_MMC_CTRL_MODE_SEL_NEW; + writel(SUNXI_MMC_NTSR_MODE_SEL_NEW, &priv->reg->ntsr); +#endif + } else { + val = CCM_MMC_CTRL_OCLK_DLY(oclk_dly) | + CCM_MMC_CTRL_SCLK_DLY(sclk_dly); + } + + writel(CCM_MMC_CTRL_ENABLE| pll | CCM_MMC_CTRL_N(n) | + CCM_MMC_CTRL_M(div) | val, priv->mclkreg); debug("mmc %u set mod-clk req %u parent %u n %u m %u rate %u\n", priv->mmc_no, hz, pll_hz, 1u << n, div, pll_hz / (1u << n) / div);