sunxi: mmc: Improve reset procedure
authorJernej Skrabec <jernej.skrabec@gmail.com>
Sun, 9 Mar 2025 06:12:41 +0000 (07:12 +0100)
committerAndre Przywara <andre.przywara@arm.com>
Thu, 27 Mar 2025 00:26:35 +0000 (00:26 +0000)
Cards should always be reset and threshold set. This fixes eMMC on H616.

Signed-off-by: Jernej Skrabec <jernej.skrabec@gmail.com>
[Andre: use macro-defined offsets to fix build on older SoCs]
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
drivers/mmc/sunxi_mmc.c
drivers/mmc/sunxi_mmc.h

index 8f72d75..951e6ac 100644 (file)
@@ -449,6 +449,26 @@ out:
        return error;
 }
 
+static void sunxi_mmc_reset(void *regs)
+{
+       /* Reset controller */
+       writel(SUNXI_MMC_GCTRL_RESET, regs + SUNXI_MMC_GCTRL);
+       udelay(1000);
+
+       if (IS_ENABLED(CONFIG_SUN50I_GEN_H6) || IS_ENABLED(CONFIG_SUNXI_GEN_NCAT2)) {
+               /* Reset card */
+               writel(SUNXI_MMC_HWRST_ASSERT, regs + SUNXI_MMC_HWRST);
+               udelay(10);
+               writel(SUNXI_MMC_HWRST_DEASSERT, regs + SUNXI_MMC_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, regs + SUNXI_MMC_THLDC);
+       }
+}
+
 /* non-DM code here is used by the (ARM) SPL only */
 
 #if !CONFIG_IS_ENABLED(DM_MMC)
@@ -496,9 +516,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;
 }
@@ -691,9 +709,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;
 }
index f4ae5a7..7186516 100644 (file)
@@ -37,7 +37,9 @@ struct sunxi_mmc {
        u32 res0;               /* 0x54 reserved */
        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
@@ -57,6 +60,7 @@ struct sunxi_mmc {
 #define SUNXI_MMC_CLK_ENABLE           (0x1 << 16)
 #define SUNXI_MMC_CLK_DIVIDER_MASK     (0xff)
 
+#define SUNXI_MMC_GCTRL                0x000
 #define SUNXI_MMC_GCTRL_SOFT_RESET     (0x1 << 0)
 #define SUNXI_MMC_GCTRL_FIFO_RESET     (0x1 << 1)
 #define SUNXI_MMC_GCTRL_DMA_RESET      (0x1 << 2)
@@ -123,6 +127,10 @@ struct sunxi_mmc {
 
 #define SUNXI_MMC_NTSR_MODE_SEL_NEW            (0x1 << 31)
 
+#define SUNXI_MMC_HWRST                0x078
+#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 +141,12 @@ struct sunxi_mmc {
 #define SUNXI_MMC_COMMON_CLK_GATE              (1 << 16)
 #define SUNXI_MMC_COMMON_RESET                 (1 << 18)
 
+#define SUNXI_MMC_THLDC                0x100
+#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 */