On Fri, Jun 12, 2026 at 04:18:55PM -0400, Raymond Mao wrote:
>From: Guodong Xu <[email protected]>
>
>Add SDHCI platform driver support for SpacemiT K1 SoC. This driver
>implements the necessary platform-specific operations for the SDHCI
>controller, enabling MMC/SD card functionality on K1-based platforms.
>
>Signed-off-by: Guodong Xu <[email protected]>
>Signed-off-by: Raymond Mao <[email protected]>
>---
>+
>+#define LOG_CATEGORY UCLASS_MMC
>+
>+#include <clk.h>
>+#include <dm.h>
>+#include <dm/pinctrl.h>
>+#include <fdtdec.h>
>+#include <linux/libfdt.h>
>+#include <linux/delay.h>
>+#include <log.h>
>+#include <malloc.h>
>+#include <sdhci.h>
>+#include <reset-uclass.h>
>+#include <power/regulator.h>
>+#include <mapmem.h>

See doc/develop/codingstyle.rst regarding "Include files"

>+
>+/* SDH register definitions */
>+#define SDHC_OP_EXT_REG                       0x108
>+#define OVRRD_CLK_OEN                 0x0800
>+#define FORCE_CLK_ON                  0x1000
>+
>+#define SDHC_LEGACY_CTRL_REG          0x10C

Not used.

>+#define GEN_PAD_CLK_ON                        0x0040
>+
>+#define SDHC_MMC_CTRL_REG             0x114
>+#define MISC_INT_EN                   0x0002
>+#define MISC_INT                      0x0004
>+#define ENHANCE_STROBE_EN             0x0100
>+#define MMC_HS400                     0x0200
>+#define MMC_HS200                     0x0400
>+#define MMC_CARD_MODE                 0x1000

Use BIT(x) and GENMASK for register bits, and other places.

>+
>+#define SDHC_RX_CFG_REG                       0x118
>+#define RX_SDCLK_SEL0_MASK            0x03
>+#define RX_SDCLK_SEL0_SHIFT           0x00
>+#define RX_SDCLK_SEL0                 0x02
>+#define RX_SDCLK_SEL1_MASK            0x03
>+#define RX_SDCLK_SEL1_SHIFT           0x02
>+#define RX_SDCLK_SEL1                 0x01
>+
>+#define SDHC_TX_CFG_REG                       0x11C
>+#define TX_INT_CLK_SEL                        0x40000000
>+#define TX_MUX_SEL                    0x80000000
>+
>+#define SDHC_DLINE_CTRL_REG           0x130
>+#define DLINE_PU                      0x01
>+#define RX_DLINE_CODE_MASK            0xFF
>+#define RX_DLINE_CODE_SHIFT           0x10
>+#define TX_DLINE_CODE_MASK            0xFF
>+#define TX_DLINE_CODE_SHIFT           0x18
>+
>+#define SDHC_DLINE_CFG_REG            0x134
>+#define RX_DLINE_REG_MASK             0xFF
>+#define RX_DLINE_REG_SHIFT            0x00
>+#define RX_DLINE_GAIN_MASK            0x1
>+#define RX_DLINE_GAIN_SHIFT           0x8
>+#define RX_DLINE_GAIN                 0x1
>+#define TX_DLINE_REG_MASK             0xFF
>+#define TX_DLINE_REG_SHIFT            0x10
>+
>+#define SDHC_PHY_CTRL_REG             0x160
>+#define PHY_FUNC_EN                   0x0001
>+#define PHY_PLL_LOCK                  0x0002
>+#define HOST_LEGACY_MODE              0x80000000
>+
>+#define SDHC_PHY_FUNC_REG             0x164
>+#define PHY_TEST_EN                   0x0080
>+#define HS200_USE_RFIFO                       0x8000
>+
>+#define SDHC_PHY_DLLCFG                       0x168
>+#define DLL_PREDLY_NUM                        0x04
>+#define DLL_FULLDLY_RANGE             0x10
>+#define DLL_VREG_CTRL                 0x40
>+#define DLL_ENABLE                    0x80000000
>+#define DLL_REFRESH_SWEN_SHIFT                0x1C
>+#define DLL_REFRESH_SW_SHIFT          0x1D
>+
>+#define SDHC_PHY_DLLCFG1              0x16C
>+#define DLL_REG2_CTRL                 0x0C
>+#define DLL_REG3_CTRL_MASK            0xFF
>+#define DLL_REG3_CTRL_SHIFT           0x10
>+#define DLL_REG2_CTRL_MASK            0xFF
>+#define DLL_REG2_CTRL_SHIFT           0x08
>+#define DLL_REG1_CTRL                 0x92
>+#define DLL_REG1_CTRL_MASK            0xFF
>+#define DLL_REG1_CTRL_SHIFT           0x00
>+
>+#define SDHC_PHY_DLLSTS                       0x170
>+#define DLL_LOCK_STATE                        0x01
>+
>+#define SDHC_PHY_DLLSTS1              0x174
>+#define DLL_MASTER_DELAY_MASK         0xFF
>+#define DLL_MASTER_DELAY_SHIFT                0x10
>+
>+#define SDHC_PHY_PADCFG_REG           0x178
>+#define RX_BIAS_CTRL_SHIFT            0x5
>+#define PHY_DRIVE_SEL_SHIFT           0x0
>+#define PHY_DRIVE_SEL_MASK            0x7
>+#define PHY_DRIVE_SEL_DEFAULT         0x4
>+
>+#define MMC1_IO_V18EN                 0x04
>+#define AKEY_ASFAR                    0xBABA
>+#define AKEY_ASSAR                    0xEB10
>+
>+#define SDHC_RX_TUNE_DELAY_MIN                0x0
>+#define SDHC_RX_TUNE_DELAY_MAX                0xFF
>+#define SDHC_RX_TUNE_DELAY_STEP               0x1
>+
>+#define CANDIDATE_WIN_NUM             3
>+#define SELECT_DELAY_NUM              9
>+#define WINDOW_1ST                    0
>+#define WINDOW_2ND                    1
>+#define WINDOW_3RD                    2
>+
>+#define RX_TUNING_WINDOW_THRESHOLD    80
>+#define RX_TUNING_DLINE_REG           0x09
>+#define TX_TUNING_DLINE_REG           0x00
>+#define TX_TUNING_DELAYCODE           127
...
>+
>+static int spacemit_sdhci_send_tuning_cmd(struct sdhci_host *host, u32 opcode)
>+{
>+      int err = 0;
>+
>+      err = spacemit_sdhci_send_tuning(host, opcode, NULL);
>+      if (err) {
>+              log_warning("%s: send tuning err:%d\n", host->name, err);
>+              return err;
>+      }
>+
>+      err = spacemit_sdhci_tuning_pattern_check(host);
>+      return err;

return spacemit_sdhci_tuning_pattern_check(host);

>+}
>+
>+static void spacemit_sdhci_clear_tuned_clk(struct sdhci_host *host)
>+{
>+      u16 ctrl;
>+
>+      ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2);
>+      ctrl &= ~(SDHCI_CTRL_TUNED_CLK | SDHCI_CTRL_EXEC_TUNING);
>+      sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2);
>+}
>+
...
>+
>+
>+      /* Enable DLL */
>+      reg = sdhci_readl(host, SDHC_PHY_DLLCFG);
>+      reg |= DLL_ENABLE;
>+      sdhci_writel(host, reg, SDHC_PHY_DLLCFG);
>+
>+      /* Wait for DLL lock */
>+      i = 0;
>+      while (i++ < 100) {
>+              if (sdhci_readl(host, SDHC_PHY_DLLSTS) & DLL_LOCK_STATE)
>+                      break;
>+              udelay(10);
>+      }

Use readx_poll_sleep_timeout?

>+      if (i == 100) {
>+              log_err("%s: phy dll lock timeout\n", host->name);
>+              return -ETIMEDOUT;
>+      }
>+
>+      return 0;
>+}
>+
>+static int spacemit_sdhci_hs400_enhanced_strobe(struct sdhci_host *host)
>+{
>+      u32 reg;
>+
>+      reg = sdhci_readl(host, SDHC_MMC_CTRL_REG);
>+      reg |= ENHANCE_STROBE_EN;
>+      sdhci_writel(host, reg, SDHC_MMC_CTRL_REG);
>+
>+      return spacemit_sdhci_phy_dll_init(host);
>+}
>+#endif
>+
>+const struct sdhci_ops spacemit_sdhci_ops = {
>+      .set_control_reg                = spacemit_sdhci_set_control_reg,
>+      .platform_execute_tuning        = spacemit_sdhci_execute_tuning,
>+#if CONFIG_IS_ENABLED(MMC_HS400_ES_SUPPORT)
>+      .set_enhanced_strobe            = spacemit_sdhci_hs400_enhanced_strobe,
>+#endif
>+};
>+
>+static struct dm_mmc_ops spacemit_mmc_ops;
>+
>+static int spacemit_sdhci_probe(struct udevice *dev)
>+{
>+      struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev);
>+      struct spacemit_sdhci_priv *priv = dev_get_priv(dev);
>+      struct spacemit_sdhci_plat *plat = dev_get_plat(dev);
>+      struct sdhci_host *host = &priv->host;
>+      struct clk clk;
>+      int ret = 0;
>+
>+      host->mmc = &plat->mmc;
>+      host->mmc->priv = host;
>+      host->mmc->dev = dev;
>+      upriv->mmc = host->mmc;
>+
>+      spacemit_mmc_ops = sdhci_ops;
>+      spacemit_mmc_ops.wait_dat0 = spacemit_sdhci_wait_dat0;
>+
>+      ret = clk_get_bulk(dev, &plat->clks);
>+      if (ret) {
>+              log_err("Can't get clk: %d\n", ret);
>+              return ret;
>+      }
>+
>+      ret = clk_enable_bulk(&plat->clks);
>+      if (ret) {
>+              log_err("Failed to enable clk: %d\n", ret);
>+              return ret;
>+      }
>+
>+      ret = reset_get_bulk(dev, &plat->resets);
>+      if (ret) {
>+              log_err("Can't get reset: %d\n", ret);
>+              return ret;
>+      }
>+
>+      ret = reset_deassert_bulk(&plat->resets);
>+      if (ret) {
>+              log_err("Failed to reset: %d\n", ret);
>+              return ret;
>+      }
>+
>+      ret = clk_get_by_index(dev, 1, &clk);
>+      if (ret) {
>+              log_err("Can't get io clk: %d\n", ret);
>+              return ret;
>+      }
>+
>+      ret = clk_set_rate(&clk, plat->cfg.f_max);
>+      if (ret) {
>+              log_err("Failed to set io clk: %d\n", ret);
>+              return ret;
>+      }
>+
>+      /* Set quirks */
>+      if (IS_ENABLED(CONFIG_SPL_BUILD))

CONFIG_XPL_BUILD

>+              host->quirks = SDHCI_QUIRK_WAIT_SEND_CMD;
>+      else
>+              host->quirks = SDHCI_QUIRK_WAIT_SEND_CMD |
>+                              SDHCI_QUIRK_32BIT_DMA_ADDR;

Regards
Peng

Reply via email to