11802d0beSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2f52d9c4fSPeter Griffin /*
3f52d9c4fSPeter Griffin * Support for SDHCI on STMicroelectronics SoCs
4f52d9c4fSPeter Griffin *
5f52d9c4fSPeter Griffin * Copyright (C) 2014 STMicroelectronics Ltd
6f52d9c4fSPeter Griffin * Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
7f52d9c4fSPeter Griffin * Contributors: Peter Griffin <peter.griffin@linaro.org>
8f52d9c4fSPeter Griffin *
9f52d9c4fSPeter Griffin * Based on sdhci-cns3xxx.c
10f52d9c4fSPeter Griffin */
11f52d9c4fSPeter Griffin
12f52d9c4fSPeter Griffin #include <linux/io.h>
13f52d9c4fSPeter Griffin #include <linux/of.h>
14f52d9c4fSPeter Griffin #include <linux/module.h>
15f52d9c4fSPeter Griffin #include <linux/err.h>
16f52d9c4fSPeter Griffin #include <linux/mmc/host.h>
17406c2431SPeter Griffin #include <linux/reset.h>
18f52d9c4fSPeter Griffin #include "sdhci-pltfm.h"
19f52d9c4fSPeter Griffin
20406c2431SPeter Griffin struct st_mmc_platform_data {
21406c2431SPeter Griffin struct reset_control *rstc;
223ae50f45SLee Jones struct clk *icnclk;
23406c2431SPeter Griffin void __iomem *top_ioaddr;
24406c2431SPeter Griffin };
25406c2431SPeter Griffin
268bef7178SPeter Griffin /* MMCSS glue logic to setup the HC on some ST SoCs (e.g. STiH407 family) */
278bef7178SPeter Griffin
288bef7178SPeter Griffin #define ST_MMC_CCONFIG_REG_1 0x400
298bef7178SPeter Griffin #define ST_MMC_CCONFIG_TIMEOUT_CLK_UNIT BIT(24)
308bef7178SPeter Griffin #define ST_MMC_CCONFIG_TIMEOUT_CLK_FREQ BIT(12)
318bef7178SPeter Griffin #define ST_MMC_CCONFIG_TUNING_COUNT_DEFAULT BIT(8)
328bef7178SPeter Griffin #define ST_MMC_CCONFIG_ASYNC_WAKEUP BIT(0)
338bef7178SPeter Griffin #define ST_MMC_CCONFIG_1_DEFAULT \
348bef7178SPeter Griffin ((ST_MMC_CCONFIG_TIMEOUT_CLK_UNIT) | \
358bef7178SPeter Griffin (ST_MMC_CCONFIG_TIMEOUT_CLK_FREQ) | \
368bef7178SPeter Griffin (ST_MMC_CCONFIG_TUNING_COUNT_DEFAULT))
378bef7178SPeter Griffin
388bef7178SPeter Griffin #define ST_MMC_CCONFIG_REG_2 0x404
398bef7178SPeter Griffin #define ST_MMC_CCONFIG_HIGH_SPEED BIT(28)
408bef7178SPeter Griffin #define ST_MMC_CCONFIG_ADMA2 BIT(24)
418bef7178SPeter Griffin #define ST_MMC_CCONFIG_8BIT BIT(20)
428bef7178SPeter Griffin #define ST_MMC_CCONFIG_MAX_BLK_LEN 16
438bef7178SPeter Griffin #define MAX_BLK_LEN_1024 1
448bef7178SPeter Griffin #define MAX_BLK_LEN_2048 2
458bef7178SPeter Griffin #define BASE_CLK_FREQ_200 0xc8
468bef7178SPeter Griffin #define BASE_CLK_FREQ_100 0x64
478bef7178SPeter Griffin #define BASE_CLK_FREQ_50 0x32
488bef7178SPeter Griffin #define ST_MMC_CCONFIG_2_DEFAULT \
498bef7178SPeter Griffin (ST_MMC_CCONFIG_HIGH_SPEED | ST_MMC_CCONFIG_ADMA2 | \
508bef7178SPeter Griffin ST_MMC_CCONFIG_8BIT | \
518bef7178SPeter Griffin (MAX_BLK_LEN_1024 << ST_MMC_CCONFIG_MAX_BLK_LEN))
528bef7178SPeter Griffin
538bef7178SPeter Griffin #define ST_MMC_CCONFIG_REG_3 0x408
548bef7178SPeter Griffin #define ST_MMC_CCONFIG_EMMC_SLOT_TYPE BIT(28)
558bef7178SPeter Griffin #define ST_MMC_CCONFIG_64BIT BIT(24)
568bef7178SPeter Griffin #define ST_MMC_CCONFIG_ASYNCH_INTR_SUPPORT BIT(20)
578bef7178SPeter Griffin #define ST_MMC_CCONFIG_1P8_VOLT BIT(16)
588bef7178SPeter Griffin #define ST_MMC_CCONFIG_3P0_VOLT BIT(12)
598bef7178SPeter Griffin #define ST_MMC_CCONFIG_3P3_VOLT BIT(8)
608bef7178SPeter Griffin #define ST_MMC_CCONFIG_SUSP_RES_SUPPORT BIT(4)
618bef7178SPeter Griffin #define ST_MMC_CCONFIG_SDMA BIT(0)
628bef7178SPeter Griffin #define ST_MMC_CCONFIG_3_DEFAULT \
638bef7178SPeter Griffin (ST_MMC_CCONFIG_ASYNCH_INTR_SUPPORT | \
648bef7178SPeter Griffin ST_MMC_CCONFIG_3P3_VOLT | \
658bef7178SPeter Griffin ST_MMC_CCONFIG_SUSP_RES_SUPPORT | \
668bef7178SPeter Griffin ST_MMC_CCONFIG_SDMA)
678bef7178SPeter Griffin
688bef7178SPeter Griffin #define ST_MMC_CCONFIG_REG_4 0x40c
698bef7178SPeter Griffin #define ST_MMC_CCONFIG_D_DRIVER BIT(20)
708bef7178SPeter Griffin #define ST_MMC_CCONFIG_C_DRIVER BIT(16)
718bef7178SPeter Griffin #define ST_MMC_CCONFIG_A_DRIVER BIT(12)
728bef7178SPeter Griffin #define ST_MMC_CCONFIG_DDR50 BIT(8)
738bef7178SPeter Griffin #define ST_MMC_CCONFIG_SDR104 BIT(4)
748bef7178SPeter Griffin #define ST_MMC_CCONFIG_SDR50 BIT(0)
758bef7178SPeter Griffin #define ST_MMC_CCONFIG_4_DEFAULT 0
768bef7178SPeter Griffin
778bef7178SPeter Griffin #define ST_MMC_CCONFIG_REG_5 0x410
788bef7178SPeter Griffin #define ST_MMC_CCONFIG_TUNING_FOR_SDR50 BIT(8)
798bef7178SPeter Griffin #define RETUNING_TIMER_CNT_MAX 0xf
808bef7178SPeter Griffin #define ST_MMC_CCONFIG_5_DEFAULT 0
818bef7178SPeter Griffin
828bef7178SPeter Griffin /* I/O configuration for Arasan IP */
838bef7178SPeter Griffin #define ST_MMC_GP_OUTPUT 0x450
848bef7178SPeter Griffin #define ST_MMC_GP_OUTPUT_CD BIT(12)
858bef7178SPeter Griffin
868bef7178SPeter Griffin #define ST_MMC_STATUS_R 0x460
878bef7178SPeter Griffin
888bef7178SPeter Griffin #define ST_TOP_MMC_DLY_FIX_OFF(x) (x - 0x8)
898bef7178SPeter Griffin
908bef7178SPeter Griffin /* TOP config registers to manage static and dynamic delay */
918bef7178SPeter Griffin #define ST_TOP_MMC_TX_CLK_DLY ST_TOP_MMC_DLY_FIX_OFF(0x8)
928bef7178SPeter Griffin #define ST_TOP_MMC_RX_CLK_DLY ST_TOP_MMC_DLY_FIX_OFF(0xc)
938bef7178SPeter Griffin /* MMC delay control register */
948bef7178SPeter Griffin #define ST_TOP_MMC_DLY_CTRL ST_TOP_MMC_DLY_FIX_OFF(0x18)
958bef7178SPeter Griffin #define ST_TOP_MMC_DLY_CTRL_DLL_BYPASS_CMD BIT(0)
968bef7178SPeter Griffin #define ST_TOP_MMC_DLY_CTRL_DLL_BYPASS_PH_SEL BIT(1)
978bef7178SPeter Griffin #define ST_TOP_MMC_DLY_CTRL_TX_DLL_ENABLE BIT(8)
988bef7178SPeter Griffin #define ST_TOP_MMC_DLY_CTRL_RX_DLL_ENABLE BIT(9)
998bef7178SPeter Griffin #define ST_TOP_MMC_DLY_CTRL_ATUNE_NOT_CFG_DLY BIT(10)
1008bef7178SPeter Griffin #define ST_TOP_MMC_START_DLL_LOCK BIT(11)
1018bef7178SPeter Griffin
1028bef7178SPeter Griffin /* register to provide the phase-shift value for DLL */
1038bef7178SPeter Griffin #define ST_TOP_MMC_TX_DLL_STEP_DLY ST_TOP_MMC_DLY_FIX_OFF(0x1c)
1048bef7178SPeter Griffin #define ST_TOP_MMC_RX_DLL_STEP_DLY ST_TOP_MMC_DLY_FIX_OFF(0x20)
1058bef7178SPeter Griffin #define ST_TOP_MMC_RX_CMD_STEP_DLY ST_TOP_MMC_DLY_FIX_OFF(0x24)
1068bef7178SPeter Griffin
1078bef7178SPeter Griffin /* phase shift delay on the tx clk 2.188ns */
1088bef7178SPeter Griffin #define ST_TOP_MMC_TX_DLL_STEP_DLY_VALID 0x6
1098bef7178SPeter Griffin
1108bef7178SPeter Griffin #define ST_TOP_MMC_DLY_MAX 0xf
1118bef7178SPeter Griffin
1128bef7178SPeter Griffin #define ST_TOP_MMC_DYN_DLY_CONF \
1138bef7178SPeter Griffin (ST_TOP_MMC_DLY_CTRL_TX_DLL_ENABLE | \
1148bef7178SPeter Griffin ST_TOP_MMC_DLY_CTRL_ATUNE_NOT_CFG_DLY | \
1158bef7178SPeter Griffin ST_TOP_MMC_START_DLL_LOCK)
1168bef7178SPeter Griffin
117bfa44804SPeter Griffin /*
118bfa44804SPeter Griffin * For clock speeds greater than 90MHz, we need to check that the
119bfa44804SPeter Griffin * DLL procedure has finished before switching to ultra-speed modes.
120bfa44804SPeter Griffin */
121bfa44804SPeter Griffin #define CLK_TO_CHECK_DLL_LOCK 90000000
122bfa44804SPeter Griffin
st_mmcss_set_static_delay(void __iomem * ioaddr)123bfa44804SPeter Griffin static inline void st_mmcss_set_static_delay(void __iomem *ioaddr)
124bfa44804SPeter Griffin {
125bfa44804SPeter Griffin if (!ioaddr)
126bfa44804SPeter Griffin return;
127bfa44804SPeter Griffin
128bfa44804SPeter Griffin writel_relaxed(0x0, ioaddr + ST_TOP_MMC_DLY_CTRL);
129bfa44804SPeter Griffin writel_relaxed(ST_TOP_MMC_DLY_MAX,
130bfa44804SPeter Griffin ioaddr + ST_TOP_MMC_TX_CLK_DLY);
131bfa44804SPeter Griffin }
132bfa44804SPeter Griffin
1332053812fSPeter Griffin /**
1342053812fSPeter Griffin * st_mmcss_cconfig: configure the Arasan HC inside the flashSS.
1352053812fSPeter Griffin * @np: dt device node.
1362053812fSPeter Griffin * @host: sdhci host
1372053812fSPeter Griffin * Description: this function is to configure the Arasan host controller.
1382053812fSPeter Griffin * On some ST SoCs, i.e. STiH407 family, the MMC devices inside a dedicated
1392053812fSPeter Griffin * flashSS sub-system which needs to be configured to be compliant to eMMC 4.5
1402053812fSPeter Griffin * or eMMC4.3. This has to be done before registering the sdhci host.
1412053812fSPeter Griffin */
st_mmcss_cconfig(struct device_node * np,struct sdhci_host * host)1422053812fSPeter Griffin static void st_mmcss_cconfig(struct device_node *np, struct sdhci_host *host)
1432053812fSPeter Griffin {
1442053812fSPeter Griffin struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
1452053812fSPeter Griffin struct mmc_host *mhost = host->mmc;
1462053812fSPeter Griffin u32 cconf2, cconf3, cconf4, cconf5;
1472053812fSPeter Griffin
1482053812fSPeter Griffin if (!of_device_is_compatible(np, "st,sdhci-stih407"))
1492053812fSPeter Griffin return;
1502053812fSPeter Griffin
1512053812fSPeter Griffin cconf2 = ST_MMC_CCONFIG_2_DEFAULT;
1522053812fSPeter Griffin cconf3 = ST_MMC_CCONFIG_3_DEFAULT;
1532053812fSPeter Griffin cconf4 = ST_MMC_CCONFIG_4_DEFAULT;
1542053812fSPeter Griffin cconf5 = ST_MMC_CCONFIG_5_DEFAULT;
1552053812fSPeter Griffin
1562053812fSPeter Griffin writel_relaxed(ST_MMC_CCONFIG_1_DEFAULT,
1572053812fSPeter Griffin host->ioaddr + ST_MMC_CCONFIG_REG_1);
1582053812fSPeter Griffin
1592053812fSPeter Griffin /* Set clock frequency, default to 50MHz if max-frequency is not
1602053812fSPeter Griffin * provided */
1612053812fSPeter Griffin
1622053812fSPeter Griffin switch (mhost->f_max) {
1632053812fSPeter Griffin case 200000000:
1642053812fSPeter Griffin clk_set_rate(pltfm_host->clk, mhost->f_max);
1652053812fSPeter Griffin cconf2 |= BASE_CLK_FREQ_200;
1662053812fSPeter Griffin break;
1672053812fSPeter Griffin case 100000000:
1682053812fSPeter Griffin clk_set_rate(pltfm_host->clk, mhost->f_max);
1692053812fSPeter Griffin cconf2 |= BASE_CLK_FREQ_100;
1702053812fSPeter Griffin break;
1712053812fSPeter Griffin default:
1722053812fSPeter Griffin clk_set_rate(pltfm_host->clk, 50000000);
1732053812fSPeter Griffin cconf2 |= BASE_CLK_FREQ_50;
1742053812fSPeter Griffin }
1752053812fSPeter Griffin
1762053812fSPeter Griffin writel_relaxed(cconf2, host->ioaddr + ST_MMC_CCONFIG_REG_2);
1772053812fSPeter Griffin
178860951c5SJaehoon Chung if (!mmc_card_is_removable(mhost))
1792053812fSPeter Griffin cconf3 |= ST_MMC_CCONFIG_EMMC_SLOT_TYPE;
1802053812fSPeter Griffin else
1812053812fSPeter Griffin /* CARD _D ET_CTRL */
1822053812fSPeter Griffin writel_relaxed(ST_MMC_GP_OUTPUT_CD,
1832053812fSPeter Griffin host->ioaddr + ST_MMC_GP_OUTPUT);
1842053812fSPeter Griffin
1852053812fSPeter Griffin if (mhost->caps & MMC_CAP_UHS_SDR50) {
1862053812fSPeter Griffin /* use 1.8V */
1872053812fSPeter Griffin cconf3 |= ST_MMC_CCONFIG_1P8_VOLT;
1882053812fSPeter Griffin cconf4 |= ST_MMC_CCONFIG_SDR50;
1892053812fSPeter Griffin /* Use tuning */
1902053812fSPeter Griffin cconf5 |= ST_MMC_CCONFIG_TUNING_FOR_SDR50;
1912053812fSPeter Griffin /* Max timeout for retuning */
1922053812fSPeter Griffin cconf5 |= RETUNING_TIMER_CNT_MAX;
1932053812fSPeter Griffin }
1942053812fSPeter Griffin
1952053812fSPeter Griffin if (mhost->caps & MMC_CAP_UHS_SDR104) {
1962053812fSPeter Griffin /*
1972053812fSPeter Griffin * SDR104 implies the HC can support HS200 mode, so
1982053812fSPeter Griffin * it's mandatory to use 1.8V
1992053812fSPeter Griffin */
2002053812fSPeter Griffin cconf3 |= ST_MMC_CCONFIG_1P8_VOLT;
2012053812fSPeter Griffin cconf4 |= ST_MMC_CCONFIG_SDR104;
2022053812fSPeter Griffin /* Max timeout for retuning */
2032053812fSPeter Griffin cconf5 |= RETUNING_TIMER_CNT_MAX;
2042053812fSPeter Griffin }
2052053812fSPeter Griffin
2062053812fSPeter Griffin if (mhost->caps & MMC_CAP_UHS_DDR50)
2072053812fSPeter Griffin cconf4 |= ST_MMC_CCONFIG_DDR50;
2082053812fSPeter Griffin
2092053812fSPeter Griffin writel_relaxed(cconf3, host->ioaddr + ST_MMC_CCONFIG_REG_3);
2102053812fSPeter Griffin writel_relaxed(cconf4, host->ioaddr + ST_MMC_CCONFIG_REG_4);
2112053812fSPeter Griffin writel_relaxed(cconf5, host->ioaddr + ST_MMC_CCONFIG_REG_5);
2122053812fSPeter Griffin }
2132053812fSPeter Griffin
st_mmcss_set_dll(void __iomem * ioaddr)214bfa44804SPeter Griffin static inline void st_mmcss_set_dll(void __iomem *ioaddr)
215bfa44804SPeter Griffin {
216bfa44804SPeter Griffin if (!ioaddr)
217bfa44804SPeter Griffin return;
218bfa44804SPeter Griffin
219bfa44804SPeter Griffin writel_relaxed(ST_TOP_MMC_DYN_DLY_CONF, ioaddr + ST_TOP_MMC_DLY_CTRL);
220bfa44804SPeter Griffin writel_relaxed(ST_TOP_MMC_TX_DLL_STEP_DLY_VALID,
221bfa44804SPeter Griffin ioaddr + ST_TOP_MMC_TX_DLL_STEP_DLY);
222bfa44804SPeter Griffin }
223bfa44804SPeter Griffin
st_mmcss_lock_dll(void __iomem * ioaddr)224bfa44804SPeter Griffin static int st_mmcss_lock_dll(void __iomem *ioaddr)
225bfa44804SPeter Griffin {
226bfa44804SPeter Griffin unsigned long curr, value;
227bfa44804SPeter Griffin unsigned long finish = jiffies + HZ;
228bfa44804SPeter Griffin
229bfa44804SPeter Griffin /* Checks if the DLL procedure is finished */
230bfa44804SPeter Griffin do {
231bfa44804SPeter Griffin curr = jiffies;
232bfa44804SPeter Griffin value = readl(ioaddr + ST_MMC_STATUS_R);
233bfa44804SPeter Griffin if (value & 0x1)
234bfa44804SPeter Griffin return 0;
235bfa44804SPeter Griffin
236bfa44804SPeter Griffin cpu_relax();
237bfa44804SPeter Griffin } while (!time_after_eq(curr, finish));
238bfa44804SPeter Griffin
239bfa44804SPeter Griffin return -EBUSY;
240bfa44804SPeter Griffin }
241bfa44804SPeter Griffin
sdhci_st_set_dll_for_clock(struct sdhci_host * host)242bfa44804SPeter Griffin static int sdhci_st_set_dll_for_clock(struct sdhci_host *host)
243bfa44804SPeter Griffin {
244bfa44804SPeter Griffin int ret = 0;
245bfa44804SPeter Griffin struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
24615316752SJisheng Zhang struct st_mmc_platform_data *pdata = sdhci_pltfm_priv(pltfm_host);
247bfa44804SPeter Griffin
248bfa44804SPeter Griffin if (host->clock > CLK_TO_CHECK_DLL_LOCK) {
249bfa44804SPeter Griffin st_mmcss_set_dll(pdata->top_ioaddr);
250bfa44804SPeter Griffin ret = st_mmcss_lock_dll(host->ioaddr);
251bfa44804SPeter Griffin }
252bfa44804SPeter Griffin
253bfa44804SPeter Griffin return ret;
254bfa44804SPeter Griffin }
255bfa44804SPeter Griffin
sdhci_st_set_uhs_signaling(struct sdhci_host * host,unsigned int uhs)256cf48d32eSPeter Griffin static void sdhci_st_set_uhs_signaling(struct sdhci_host *host,
257cf48d32eSPeter Griffin unsigned int uhs)
258cf48d32eSPeter Griffin {
259cf48d32eSPeter Griffin struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
26015316752SJisheng Zhang struct st_mmc_platform_data *pdata = sdhci_pltfm_priv(pltfm_host);
261cf48d32eSPeter Griffin u16 ctrl_2 = sdhci_readw(host, SDHCI_HOST_CONTROL2);
262cf48d32eSPeter Griffin int ret = 0;
263cf48d32eSPeter Griffin
264cf48d32eSPeter Griffin /* Select Bus Speed Mode for host */
265cf48d32eSPeter Griffin ctrl_2 &= ~SDHCI_CTRL_UHS_MASK;
266cf48d32eSPeter Griffin switch (uhs) {
267cf48d32eSPeter Griffin /*
268cf48d32eSPeter Griffin * Set V18_EN -- UHS modes do not work without this.
269cf48d32eSPeter Griffin * does not change signaling voltage
270cf48d32eSPeter Griffin */
271cf48d32eSPeter Griffin
272cf48d32eSPeter Griffin case MMC_TIMING_UHS_SDR12:
273cf48d32eSPeter Griffin st_mmcss_set_static_delay(pdata->top_ioaddr);
274cf48d32eSPeter Griffin ctrl_2 |= SDHCI_CTRL_UHS_SDR12 | SDHCI_CTRL_VDD_180;
275cf48d32eSPeter Griffin break;
276cf48d32eSPeter Griffin case MMC_TIMING_UHS_SDR25:
277cf48d32eSPeter Griffin st_mmcss_set_static_delay(pdata->top_ioaddr);
278cf48d32eSPeter Griffin ctrl_2 |= SDHCI_CTRL_UHS_SDR25 | SDHCI_CTRL_VDD_180;
279cf48d32eSPeter Griffin break;
280cf48d32eSPeter Griffin case MMC_TIMING_UHS_SDR50:
281cf48d32eSPeter Griffin st_mmcss_set_static_delay(pdata->top_ioaddr);
282cf48d32eSPeter Griffin ctrl_2 |= SDHCI_CTRL_UHS_SDR50 | SDHCI_CTRL_VDD_180;
283cf48d32eSPeter Griffin ret = sdhci_st_set_dll_for_clock(host);
284cf48d32eSPeter Griffin break;
285cf48d32eSPeter Griffin case MMC_TIMING_UHS_SDR104:
286cf48d32eSPeter Griffin case MMC_TIMING_MMC_HS200:
287cf48d32eSPeter Griffin st_mmcss_set_static_delay(pdata->top_ioaddr);
288cf48d32eSPeter Griffin ctrl_2 |= SDHCI_CTRL_UHS_SDR104 | SDHCI_CTRL_VDD_180;
289cf48d32eSPeter Griffin ret = sdhci_st_set_dll_for_clock(host);
290cf48d32eSPeter Griffin break;
291cf48d32eSPeter Griffin case MMC_TIMING_UHS_DDR50:
292cf48d32eSPeter Griffin case MMC_TIMING_MMC_DDR52:
293cf48d32eSPeter Griffin st_mmcss_set_static_delay(pdata->top_ioaddr);
294cf48d32eSPeter Griffin ctrl_2 |= SDHCI_CTRL_UHS_DDR50 | SDHCI_CTRL_VDD_180;
295cf48d32eSPeter Griffin break;
296cf48d32eSPeter Griffin }
297cf48d32eSPeter Griffin
298cf48d32eSPeter Griffin if (ret)
299cf48d32eSPeter Griffin dev_warn(mmc_dev(host->mmc), "Error setting dll for clock "
300cf48d32eSPeter Griffin "(uhs %d)\n", uhs);
301cf48d32eSPeter Griffin
302cf48d32eSPeter Griffin dev_dbg(mmc_dev(host->mmc), "uhs %d, ctrl_2 %04X\n", uhs, ctrl_2);
303cf48d32eSPeter Griffin
304cf48d32eSPeter Griffin sdhci_writew(host, ctrl_2, SDHCI_HOST_CONTROL2);
305cf48d32eSPeter Griffin }
306bfa44804SPeter Griffin
sdhci_st_readl(struct sdhci_host * host,int reg)307f52d9c4fSPeter Griffin static u32 sdhci_st_readl(struct sdhci_host *host, int reg)
308f52d9c4fSPeter Griffin {
309f52d9c4fSPeter Griffin u32 ret;
310f52d9c4fSPeter Griffin
311f52d9c4fSPeter Griffin switch (reg) {
312f52d9c4fSPeter Griffin case SDHCI_CAPABILITIES:
313f52d9c4fSPeter Griffin ret = readl_relaxed(host->ioaddr + reg);
314f52d9c4fSPeter Griffin /* Support 3.3V and 1.8V */
315f52d9c4fSPeter Griffin ret &= ~SDHCI_CAN_VDD_300;
316f52d9c4fSPeter Griffin break;
317f52d9c4fSPeter Griffin default:
318f52d9c4fSPeter Griffin ret = readl_relaxed(host->ioaddr + reg);
319f52d9c4fSPeter Griffin }
320f52d9c4fSPeter Griffin return ret;
321f52d9c4fSPeter Griffin }
322f52d9c4fSPeter Griffin
323f52d9c4fSPeter Griffin static const struct sdhci_ops sdhci_st_ops = {
324f52d9c4fSPeter Griffin .get_max_clock = sdhci_pltfm_clk_get_max_clock,
325f52d9c4fSPeter Griffin .set_clock = sdhci_set_clock,
326f52d9c4fSPeter Griffin .set_bus_width = sdhci_set_bus_width,
327f52d9c4fSPeter Griffin .read_l = sdhci_st_readl,
328f52d9c4fSPeter Griffin .reset = sdhci_reset,
329cf48d32eSPeter Griffin .set_uhs_signaling = sdhci_st_set_uhs_signaling,
330f52d9c4fSPeter Griffin };
331f52d9c4fSPeter Griffin
332f52d9c4fSPeter Griffin static const struct sdhci_pltfm_data sdhci_st_pdata = {
333f52d9c4fSPeter Griffin .ops = &sdhci_st_ops,
334f52d9c4fSPeter Griffin .quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC |
3354e187d31SPeter Griffin SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN |
3364e187d31SPeter Griffin SDHCI_QUIRK_NO_HISPD_BIT,
3374e187d31SPeter Griffin .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN |
3384e187d31SPeter Griffin SDHCI_QUIRK2_STOP_WITH_TC,
339f52d9c4fSPeter Griffin };
340f52d9c4fSPeter Griffin
341f52d9c4fSPeter Griffin
sdhci_st_probe(struct platform_device * pdev)342f52d9c4fSPeter Griffin static int sdhci_st_probe(struct platform_device *pdev)
343f52d9c4fSPeter Griffin {
3442053812fSPeter Griffin struct device_node *np = pdev->dev.of_node;
345f52d9c4fSPeter Griffin struct sdhci_host *host;
346406c2431SPeter Griffin struct st_mmc_platform_data *pdata;
347f52d9c4fSPeter Griffin struct sdhci_pltfm_host *pltfm_host;
3483ae50f45SLee Jones struct clk *clk, *icnclk;
349f52d9c4fSPeter Griffin int ret = 0;
350f52d9c4fSPeter Griffin u16 host_version;
35115316752SJisheng Zhang struct reset_control *rstc;
352f52d9c4fSPeter Griffin
353f52d9c4fSPeter Griffin clk = devm_clk_get(&pdev->dev, "mmc");
354f52d9c4fSPeter Griffin if (IS_ERR(clk)) {
355f52d9c4fSPeter Griffin dev_err(&pdev->dev, "Peripheral clk not found\n");
356f52d9c4fSPeter Griffin return PTR_ERR(clk);
357f52d9c4fSPeter Griffin }
358f52d9c4fSPeter Griffin
3593ae50f45SLee Jones /* ICN clock isn't compulsory, but use it if it's provided. */
3603ae50f45SLee Jones icnclk = devm_clk_get(&pdev->dev, "icn");
3613ae50f45SLee Jones if (IS_ERR(icnclk))
3623ae50f45SLee Jones icnclk = NULL;
3633ae50f45SLee Jones
36495211a98SPhilipp Zabel rstc = devm_reset_control_get_optional_exclusive(&pdev->dev, NULL);
36515316752SJisheng Zhang if (IS_ERR(rstc))
36695211a98SPhilipp Zabel return PTR_ERR(rstc);
36715316752SJisheng Zhang reset_control_deassert(rstc);
368406c2431SPeter Griffin
36915316752SJisheng Zhang host = sdhci_pltfm_init(pdev, &sdhci_st_pdata, sizeof(*pdata));
370f52d9c4fSPeter Griffin if (IS_ERR(host)) {
371f52d9c4fSPeter Griffin dev_err(&pdev->dev, "Failed sdhci_pltfm_init\n");
372406c2431SPeter Griffin ret = PTR_ERR(host);
373406c2431SPeter Griffin goto err_pltfm_init;
374f52d9c4fSPeter Griffin }
375f52d9c4fSPeter Griffin
37615316752SJisheng Zhang pltfm_host = sdhci_priv(host);
37715316752SJisheng Zhang pdata = sdhci_pltfm_priv(pltfm_host);
37815316752SJisheng Zhang pdata->rstc = rstc;
37915316752SJisheng Zhang
380f52d9c4fSPeter Griffin ret = mmc_of_parse(host->mmc);
381f52d9c4fSPeter Griffin if (ret) {
382f52d9c4fSPeter Griffin dev_err(&pdev->dev, "Failed mmc_of_parse\n");
383fc702cb3SUlf Hansson goto err_of;
384f52d9c4fSPeter Griffin }
385f52d9c4fSPeter Griffin
3867f55eb10SArvind Yadav ret = clk_prepare_enable(clk);
3877f55eb10SArvind Yadav if (ret) {
3887f55eb10SArvind Yadav dev_err(&pdev->dev, "Failed to prepare clock\n");
3897f55eb10SArvind Yadav goto err_of;
3907f55eb10SArvind Yadav }
3917f55eb10SArvind Yadav
3927f55eb10SArvind Yadav ret = clk_prepare_enable(icnclk);
3937f55eb10SArvind Yadav if (ret) {
3947f55eb10SArvind Yadav dev_err(&pdev->dev, "Failed to prepare icn clock\n");
3957f55eb10SArvind Yadav goto err_icnclk;
3967f55eb10SArvind Yadav }
397f52d9c4fSPeter Griffin
398406c2431SPeter Griffin /* Configure the FlashSS Top registers for setting eMMC TX/RX delay */
399aa857326SLi Zetao pdata->top_ioaddr = devm_platform_ioremap_resource_byname(pdev, "top-mmc-delay");
40050eae6baSLaibin Qiu if (IS_ERR(pdata->top_ioaddr))
401406c2431SPeter Griffin pdata->top_ioaddr = NULL;
402406c2431SPeter Griffin
403f52d9c4fSPeter Griffin pltfm_host->clk = clk;
4043ae50f45SLee Jones pdata->icnclk = icnclk;
405f52d9c4fSPeter Griffin
4062053812fSPeter Griffin /* Configure the Arasan HC inside the flashSS */
4072053812fSPeter Griffin st_mmcss_cconfig(np, host);
4082053812fSPeter Griffin
409f52d9c4fSPeter Griffin ret = sdhci_add_host(host);
410fb8617e1SJisheng Zhang if (ret)
411f52d9c4fSPeter Griffin goto err_out;
412f52d9c4fSPeter Griffin
413f52d9c4fSPeter Griffin host_version = readw_relaxed((host->ioaddr + SDHCI_HOST_VERSION));
414f52d9c4fSPeter Griffin
415f52d9c4fSPeter Griffin dev_info(&pdev->dev, "SDHCI ST Initialised: Host Version: 0x%x Vendor Version 0x%x\n",
416f52d9c4fSPeter Griffin ((host_version & SDHCI_SPEC_VER_MASK) >> SDHCI_SPEC_VER_SHIFT),
417f52d9c4fSPeter Griffin ((host_version & SDHCI_VENDOR_VER_MASK) >>
418f52d9c4fSPeter Griffin SDHCI_VENDOR_VER_SHIFT));
419f52d9c4fSPeter Griffin
420f52d9c4fSPeter Griffin return 0;
421f52d9c4fSPeter Griffin
422f52d9c4fSPeter Griffin err_out:
4233ae50f45SLee Jones clk_disable_unprepare(icnclk);
4247f55eb10SArvind Yadav err_icnclk:
425f52d9c4fSPeter Griffin clk_disable_unprepare(clk);
426fc702cb3SUlf Hansson err_of:
427f52d9c4fSPeter Griffin sdhci_pltfm_free(pdev);
428406c2431SPeter Griffin err_pltfm_init:
42915316752SJisheng Zhang reset_control_assert(rstc);
430406c2431SPeter Griffin
431406c2431SPeter Griffin return ret;
432406c2431SPeter Griffin }
433406c2431SPeter Griffin
sdhci_st_remove(struct platform_device * pdev)434887c1331SYangtao Li static void sdhci_st_remove(struct platform_device *pdev)
435406c2431SPeter Griffin {
436406c2431SPeter Griffin struct sdhci_host *host = platform_get_drvdata(pdev);
437406c2431SPeter Griffin struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
43815316752SJisheng Zhang struct st_mmc_platform_data *pdata = sdhci_pltfm_priv(pltfm_host);
43915316752SJisheng Zhang struct reset_control *rstc = pdata->rstc;
440*b1284d7cSAdrian Hunter struct clk *clk = pltfm_host->clk;
441406c2431SPeter Griffin
442*b1284d7cSAdrian Hunter sdhci_pltfm_remove(pdev);
443406c2431SPeter Griffin
4443ae50f45SLee Jones clk_disable_unprepare(pdata->icnclk);
445*b1284d7cSAdrian Hunter clk_disable_unprepare(clk);
4463ae50f45SLee Jones
44715316752SJisheng Zhang reset_control_assert(rstc);
448f52d9c4fSPeter Griffin }
449f52d9c4fSPeter Griffin
450f52d9c4fSPeter Griffin #ifdef CONFIG_PM_SLEEP
sdhci_st_suspend(struct device * dev)451f52d9c4fSPeter Griffin static int sdhci_st_suspend(struct device *dev)
452f52d9c4fSPeter Griffin {
453f52d9c4fSPeter Griffin struct sdhci_host *host = dev_get_drvdata(dev);
454f52d9c4fSPeter Griffin struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
45515316752SJisheng Zhang struct st_mmc_platform_data *pdata = sdhci_pltfm_priv(pltfm_host);
456d38dcad4SAdrian Hunter int ret;
457f52d9c4fSPeter Griffin
458d38dcad4SAdrian Hunter if (host->tuning_mode != SDHCI_TUNING_MODE_3)
459d38dcad4SAdrian Hunter mmc_retune_needed(host->mmc);
460d38dcad4SAdrian Hunter
461d38dcad4SAdrian Hunter ret = sdhci_suspend_host(host);
462f52d9c4fSPeter Griffin if (ret)
463f52d9c4fSPeter Griffin goto out;
464f52d9c4fSPeter Griffin
465406c2431SPeter Griffin reset_control_assert(pdata->rstc);
466406c2431SPeter Griffin
4673ae50f45SLee Jones clk_disable_unprepare(pdata->icnclk);
468f52d9c4fSPeter Griffin clk_disable_unprepare(pltfm_host->clk);
469f52d9c4fSPeter Griffin out:
470f52d9c4fSPeter Griffin return ret;
471f52d9c4fSPeter Griffin }
472f52d9c4fSPeter Griffin
sdhci_st_resume(struct device * dev)473f52d9c4fSPeter Griffin static int sdhci_st_resume(struct device *dev)
474f52d9c4fSPeter Griffin {
475f52d9c4fSPeter Griffin struct sdhci_host *host = dev_get_drvdata(dev);
476f52d9c4fSPeter Griffin struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
47715316752SJisheng Zhang struct st_mmc_platform_data *pdata = sdhci_pltfm_priv(pltfm_host);
4782053812fSPeter Griffin struct device_node *np = dev->of_node;
4797f55eb10SArvind Yadav int ret;
480f52d9c4fSPeter Griffin
4817f55eb10SArvind Yadav ret = clk_prepare_enable(pltfm_host->clk);
4827f55eb10SArvind Yadav if (ret)
4837f55eb10SArvind Yadav return ret;
4847f55eb10SArvind Yadav
4857f55eb10SArvind Yadav ret = clk_prepare_enable(pdata->icnclk);
4867f55eb10SArvind Yadav if (ret) {
4877f55eb10SArvind Yadav clk_disable_unprepare(pltfm_host->clk);
4887f55eb10SArvind Yadav return ret;
4897f55eb10SArvind Yadav }
490f52d9c4fSPeter Griffin
491406c2431SPeter Griffin reset_control_deassert(pdata->rstc);
492406c2431SPeter Griffin
4932053812fSPeter Griffin st_mmcss_cconfig(np, host);
4942053812fSPeter Griffin
495f52d9c4fSPeter Griffin return sdhci_resume_host(host);
496f52d9c4fSPeter Griffin }
497f52d9c4fSPeter Griffin #endif
498f52d9c4fSPeter Griffin
499f52d9c4fSPeter Griffin static SIMPLE_DEV_PM_OPS(sdhci_st_pmops, sdhci_st_suspend, sdhci_st_resume);
500f52d9c4fSPeter Griffin
501f52d9c4fSPeter Griffin static const struct of_device_id st_sdhci_match[] = {
502f52d9c4fSPeter Griffin { .compatible = "st,sdhci" },
503f52d9c4fSPeter Griffin {},
504f52d9c4fSPeter Griffin };
505f52d9c4fSPeter Griffin
506f52d9c4fSPeter Griffin MODULE_DEVICE_TABLE(of, st_sdhci_match);
507f52d9c4fSPeter Griffin
508f52d9c4fSPeter Griffin static struct platform_driver sdhci_st_driver = {
509f52d9c4fSPeter Griffin .probe = sdhci_st_probe,
510887c1331SYangtao Li .remove_new = sdhci_st_remove,
511f52d9c4fSPeter Griffin .driver = {
512f52d9c4fSPeter Griffin .name = "sdhci-st",
51321b2cec6SDouglas Anderson .probe_type = PROBE_PREFER_ASYNCHRONOUS,
514f52d9c4fSPeter Griffin .pm = &sdhci_st_pmops,
515bf3023e6SKrzysztof Kozlowski .of_match_table = st_sdhci_match,
516f52d9c4fSPeter Griffin },
517f52d9c4fSPeter Griffin };
518f52d9c4fSPeter Griffin
519f52d9c4fSPeter Griffin module_platform_driver(sdhci_st_driver);
520f52d9c4fSPeter Griffin
521f52d9c4fSPeter Griffin MODULE_DESCRIPTION("SDHCI driver for STMicroelectronics SoCs");
522f52d9c4fSPeter Griffin MODULE_AUTHOR("Giuseppe Cavallaro <peppe.cavallaro@st.com>");
523f52d9c4fSPeter Griffin MODULE_LICENSE("GPL v2");
524e6ac184bSZhangfei Gao MODULE_ALIAS("platform:sdhci-st");
525