Lines Matching +full:mmc +full:- +full:host

1 // SPDX-License-Identifier: GPL-2.0
3 * Copyright (C) 2023-2025 SpacemiT (Hangzhou) Technology Co. Ltd
12 #include <linux/mmc/card.h>
13 #include <linux/mmc/host.h>
14 #include <linux/mmc/mmc.h>
21 #include "sdhci-pltfm.h"
69 static inline void spacemit_sdhci_setbits(struct sdhci_host *host, u32 val, int reg) in spacemit_sdhci_setbits() argument
71 sdhci_writel(host, sdhci_readl(host, reg) | val, reg); in spacemit_sdhci_setbits()
74 static inline void spacemit_sdhci_clrbits(struct sdhci_host *host, u32 val, int reg) in spacemit_sdhci_clrbits() argument
76 sdhci_writel(host, sdhci_readl(host, reg) & ~val, reg); in spacemit_sdhci_clrbits()
79 static inline void spacemit_sdhci_clrsetbits(struct sdhci_host *host, u32 clr, u32 set, int reg) in spacemit_sdhci_clrsetbits() argument
81 u32 val = sdhci_readl(host, reg); in spacemit_sdhci_clrsetbits()
84 sdhci_writel(host, val, reg); in spacemit_sdhci_clrsetbits()
87 static void spacemit_sdhci_reset(struct sdhci_host *host, u8 mask) in spacemit_sdhci_reset() argument
89 sdhci_reset(host, mask); in spacemit_sdhci_reset()
94 spacemit_sdhci_setbits(host, PHY_FUNC_EN | PHY_PLL_LOCK, SDHC_PHY_CTRL_REG); in spacemit_sdhci_reset()
96 spacemit_sdhci_clrsetbits(host, PHY_DRIVE_SEL, in spacemit_sdhci_reset()
100 if (!(host->mmc->caps2 & MMC_CAP2_NO_MMC)) in spacemit_sdhci_reset()
101 spacemit_sdhci_setbits(host, MMC_CARD_MODE, SDHC_MMC_CTRL_REG); in spacemit_sdhci_reset()
104 static void spacemit_sdhci_set_uhs_signaling(struct sdhci_host *host, unsigned int timing) in spacemit_sdhci_set_uhs_signaling() argument
107 spacemit_sdhci_setbits(host, MMC_HS200, SDHC_MMC_CTRL_REG); in spacemit_sdhci_set_uhs_signaling()
110 spacemit_sdhci_setbits(host, MMC_HS400, SDHC_MMC_CTRL_REG); in spacemit_sdhci_set_uhs_signaling()
112 sdhci_set_uhs_signaling(host, timing); in spacemit_sdhci_set_uhs_signaling()
114 if (!(host->mmc->caps2 & MMC_CAP2_NO_SDIO)) in spacemit_sdhci_set_uhs_signaling()
115 spacemit_sdhci_setbits(host, SDHCI_CTRL_VDD_180, SDHCI_HOST_CONTROL2); in spacemit_sdhci_set_uhs_signaling()
118 static void spacemit_sdhci_set_clock(struct sdhci_host *host, unsigned int clock) in spacemit_sdhci_set_clock() argument
120 struct mmc_host *mmc = host->mmc; in spacemit_sdhci_set_clock() local
122 if (mmc->ios.timing <= MMC_TIMING_UHS_SDR50) in spacemit_sdhci_set_clock()
123 spacemit_sdhci_setbits(host, TX_INT_CLK_SEL, SDHC_TX_CFG_REG); in spacemit_sdhci_set_clock()
125 spacemit_sdhci_clrbits(host, TX_INT_CLK_SEL, SDHC_TX_CFG_REG); in spacemit_sdhci_set_clock()
127 sdhci_set_clock(host, clock); in spacemit_sdhci_set_clock()
130 static void spacemit_sdhci_phy_dll_init(struct sdhci_host *host) in spacemit_sdhci_phy_dll_init() argument
135 spacemit_sdhci_clrsetbits(host, DLL_PREDLY_NUM | DLL_FULLDLY_RANGE | DLL_VREG_CTRL, in spacemit_sdhci_phy_dll_init()
141 spacemit_sdhci_clrsetbits(host, DLL_REG1_CTRL, in spacemit_sdhci_phy_dll_init()
145 spacemit_sdhci_setbits(host, DLL_ENABLE, SDHC_PHY_DLLCFG); in spacemit_sdhci_phy_dll_init()
147 ret = readl_poll_timeout(host->ioaddr + SDHC_PHY_DLLSTS, state, in spacemit_sdhci_phy_dll_init()
149 if (ret == -ETIMEDOUT) in spacemit_sdhci_phy_dll_init()
150 dev_warn(mmc_dev(host->mmc), "fail to lock phy dll in 100us!\n"); in spacemit_sdhci_phy_dll_init()
153 static void spacemit_sdhci_hs400_enhanced_strobe(struct mmc_host *mmc, struct mmc_ios *ios) in spacemit_sdhci_hs400_enhanced_strobe() argument
155 struct sdhci_host *host = mmc_priv(mmc); in spacemit_sdhci_hs400_enhanced_strobe() local
157 if (!ios->enhanced_strobe) { in spacemit_sdhci_hs400_enhanced_strobe()
158 spacemit_sdhci_clrbits(host, ENHANCE_STROBE_EN, SDHC_MMC_CTRL_REG); in spacemit_sdhci_hs400_enhanced_strobe()
162 spacemit_sdhci_setbits(host, ENHANCE_STROBE_EN, SDHC_MMC_CTRL_REG); in spacemit_sdhci_hs400_enhanced_strobe()
163 spacemit_sdhci_phy_dll_init(host); in spacemit_sdhci_hs400_enhanced_strobe()
166 static unsigned int spacemit_sdhci_clk_get_max_clock(struct sdhci_host *host) in spacemit_sdhci_clk_get_max_clock() argument
168 struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); in spacemit_sdhci_clk_get_max_clock()
170 return clk_get_rate(pltfm_host->clk); in spacemit_sdhci_clk_get_max_clock()
173 static int spacemit_sdhci_pre_select_hs400(struct mmc_host *mmc) in spacemit_sdhci_pre_select_hs400() argument
175 struct sdhci_host *host = mmc_priv(mmc); in spacemit_sdhci_pre_select_hs400() local
177 spacemit_sdhci_setbits(host, MMC_HS400, SDHC_MMC_CTRL_REG); in spacemit_sdhci_pre_select_hs400()
178 host->mmc->caps |= MMC_CAP_WAIT_WHILE_BUSY; in spacemit_sdhci_pre_select_hs400()
183 static void spacemit_sdhci_post_select_hs400(struct mmc_host *mmc) in spacemit_sdhci_post_select_hs400() argument
185 struct sdhci_host *host = mmc_priv(mmc); in spacemit_sdhci_post_select_hs400() local
187 spacemit_sdhci_phy_dll_init(host); in spacemit_sdhci_post_select_hs400()
188 host->mmc->caps &= ~MMC_CAP_WAIT_WHILE_BUSY; in spacemit_sdhci_post_select_hs400()
191 static void spacemit_sdhci_pre_hs400_to_hs200(struct mmc_host *mmc) in spacemit_sdhci_pre_hs400_to_hs200() argument
193 struct sdhci_host *host = mmc_priv(mmc); in spacemit_sdhci_pre_hs400_to_hs200() local
195 spacemit_sdhci_clrbits(host, PHY_FUNC_EN | PHY_PLL_LOCK, SDHC_PHY_CTRL_REG); in spacemit_sdhci_pre_hs400_to_hs200()
196 spacemit_sdhci_clrbits(host, MMC_HS400 | MMC_HS200 | ENHANCE_STROBE_EN, SDHC_MMC_CTRL_REG); in spacemit_sdhci_pre_hs400_to_hs200()
197 spacemit_sdhci_clrbits(host, HS200_USE_RFIFO, SDHC_PHY_FUNC_REG); in spacemit_sdhci_pre_hs400_to_hs200()
201 spacemit_sdhci_setbits(host, PHY_FUNC_EN | PHY_PLL_LOCK, SDHC_PHY_CTRL_REG); in spacemit_sdhci_pre_hs400_to_hs200()
209 sdhst->clk_core = devm_clk_get_enabled(dev, "core"); in spacemit_sdhci_get_clocks()
210 if (IS_ERR(sdhst->clk_core)) in spacemit_sdhci_get_clocks()
211 return -EINVAL; in spacemit_sdhci_get_clocks()
213 sdhst->clk_io = devm_clk_get_enabled(dev, "io"); in spacemit_sdhci_get_clocks()
214 if (IS_ERR(sdhst->clk_io)) in spacemit_sdhci_get_clocks()
215 return -EINVAL; in spacemit_sdhci_get_clocks()
217 pltfm_host->clk = sdhst->clk_io; in spacemit_sdhci_get_clocks()
243 { .compatible = "spacemit,k1-sdhci" },
250 struct device *dev = &pdev->dev; in spacemit_sdhci_probe()
253 struct sdhci_host *host; in spacemit_sdhci_probe() local
257 host = sdhci_pltfm_init(pdev, &spacemit_sdhci_k1_pdata, sizeof(*sdhst)); in spacemit_sdhci_probe()
258 if (IS_ERR(host)) in spacemit_sdhci_probe()
259 return PTR_ERR(host); in spacemit_sdhci_probe()
261 pltfm_host = sdhci_priv(host); in spacemit_sdhci_probe()
263 ret = mmc_of_parse(host->mmc); in spacemit_sdhci_probe()
269 if (!(host->mmc->caps2 & MMC_CAP2_NO_MMC)) { in spacemit_sdhci_probe()
270 mops = &host->mmc_host_ops; in spacemit_sdhci_probe()
271 mops->hs400_prepare_ddr = spacemit_sdhci_pre_select_hs400; in spacemit_sdhci_probe()
272 mops->hs400_complete = spacemit_sdhci_post_select_hs400; in spacemit_sdhci_probe()
273 mops->hs400_downgrade = spacemit_sdhci_pre_hs400_to_hs200; in spacemit_sdhci_probe()
274 mops->hs400_enhanced_strobe = spacemit_sdhci_hs400_enhanced_strobe; in spacemit_sdhci_probe()
277 host->mmc->caps |= MMC_CAP_NEED_RSP_BUSY; in spacemit_sdhci_probe()
282 ret = sdhci_add_host(host); in spacemit_sdhci_probe()
295 .name = "sdhci-spacemit",