mmc: sunxi: Support new mode
authorMaxime Ripard <maxime.ripard@free-electrons.com>
Wed, 23 Aug 2017 10:03:41 +0000 (12:03 +0200)
committerJagan Teki <jagan@amarulasolutions.com>
Mon, 28 Aug 2017 17:06:44 +0000 (22:36 +0530)
Almost all of the newer Allwinner SoCs have a new operating mode for the
eMMC clocks that needs to be enabled in both the clock and the MMC
controller.

Details about that mode are sparse, and the name itself (new mode vs old
mode) doesn't give much details, but it seems that the it changes the
sampling of the MMC clock. One side effect is also that it divides the
parent clock rate by 2.

Add support for it through a Kconfig option.

Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
Reviewed-by: Jagan Teki <jagan@openedev.com>
arch/arm/include/asm/arch-sunxi/clock_sun8i_a83t.h
arch/arm/include/asm/arch-sunxi/mmc.h
drivers/mmc/Kconfig
drivers/mmc/sunxi_mmc.c

index 5e1346e5242ad78916b655239d8cddc771190064..5dfcbf3b017bec52a80f97eab0121302c27de46b 100644 (file)
@@ -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)
index cb52e648731ce9687b7c9cb472463fd54d8da38d..69f737f3bffc5eb8873c6d511b4e60dcf455c99a 100644 (file)
@@ -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)
index 56c352e72a0210ea417a8348581af971c9ba529b..6de927b8c6cb98ee71c60b8b6e22ec8ae3a7ffa7 100644 (file)
@@ -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
index 588574fab6a9a02ff2dae4b49d1a8f1729e209f6..bc638ae2e64a54116e4f2d8661349ae976f1bc2a 100644 (file)
@@ -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);