xref: /openbmc/linux/drivers/mmc/host/sdhci-st.c (revision 8bef7178)
1f52d9c4fSPeter Griffin /*
2f52d9c4fSPeter Griffin  * Support for SDHCI on STMicroelectronics SoCs
3f52d9c4fSPeter Griffin  *
4f52d9c4fSPeter Griffin  * Copyright (C) 2014 STMicroelectronics Ltd
5f52d9c4fSPeter Griffin  * Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
6f52d9c4fSPeter Griffin  * Contributors: Peter Griffin <peter.griffin@linaro.org>
7f52d9c4fSPeter Griffin  *
8f52d9c4fSPeter Griffin  * Based on sdhci-cns3xxx.c
9f52d9c4fSPeter Griffin  *
10f52d9c4fSPeter Griffin  * This program is free software; you can redistribute it and/or modify
11f52d9c4fSPeter Griffin  * it under the terms of the GNU General Public License version 2 as
12f52d9c4fSPeter Griffin  * published by the Free Software Foundation.
13f52d9c4fSPeter Griffin  *
14f52d9c4fSPeter Griffin  * This program is distributed in the hope that it will be useful,
15f52d9c4fSPeter Griffin  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16f52d9c4fSPeter Griffin  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17f52d9c4fSPeter Griffin  * GNU General Public License for more details.
18f52d9c4fSPeter Griffin  *
19f52d9c4fSPeter Griffin  */
20f52d9c4fSPeter Griffin 
21f52d9c4fSPeter Griffin #include <linux/io.h>
22f52d9c4fSPeter Griffin #include <linux/of.h>
23f52d9c4fSPeter Griffin #include <linux/module.h>
24f52d9c4fSPeter Griffin #include <linux/err.h>
25f52d9c4fSPeter Griffin #include <linux/mmc/host.h>
26f52d9c4fSPeter Griffin 
27f52d9c4fSPeter Griffin #include "sdhci-pltfm.h"
28f52d9c4fSPeter Griffin 
298bef7178SPeter Griffin /* MMCSS glue logic to setup the HC on some ST SoCs (e.g. STiH407 family) */
308bef7178SPeter Griffin 
318bef7178SPeter Griffin #define ST_MMC_CCONFIG_REG_1		0x400
328bef7178SPeter Griffin #define ST_MMC_CCONFIG_TIMEOUT_CLK_UNIT	BIT(24)
338bef7178SPeter Griffin #define ST_MMC_CCONFIG_TIMEOUT_CLK_FREQ	BIT(12)
348bef7178SPeter Griffin #define ST_MMC_CCONFIG_TUNING_COUNT_DEFAULT	BIT(8)
358bef7178SPeter Griffin #define ST_MMC_CCONFIG_ASYNC_WAKEUP	BIT(0)
368bef7178SPeter Griffin #define ST_MMC_CCONFIG_1_DEFAULT	\
378bef7178SPeter Griffin 				((ST_MMC_CCONFIG_TIMEOUT_CLK_UNIT) | \
388bef7178SPeter Griffin 				 (ST_MMC_CCONFIG_TIMEOUT_CLK_FREQ) | \
398bef7178SPeter Griffin 				 (ST_MMC_CCONFIG_TUNING_COUNT_DEFAULT))
408bef7178SPeter Griffin 
418bef7178SPeter Griffin #define ST_MMC_CCONFIG_REG_2		0x404
428bef7178SPeter Griffin #define ST_MMC_CCONFIG_HIGH_SPEED	BIT(28)
438bef7178SPeter Griffin #define ST_MMC_CCONFIG_ADMA2		BIT(24)
448bef7178SPeter Griffin #define ST_MMC_CCONFIG_8BIT		BIT(20)
458bef7178SPeter Griffin #define ST_MMC_CCONFIG_MAX_BLK_LEN	16
468bef7178SPeter Griffin #define  MAX_BLK_LEN_1024		1
478bef7178SPeter Griffin #define  MAX_BLK_LEN_2048		2
488bef7178SPeter Griffin #define BASE_CLK_FREQ_200		0xc8
498bef7178SPeter Griffin #define BASE_CLK_FREQ_100		0x64
508bef7178SPeter Griffin #define BASE_CLK_FREQ_50		0x32
518bef7178SPeter Griffin #define ST_MMC_CCONFIG_2_DEFAULT \
528bef7178SPeter Griffin 	(ST_MMC_CCONFIG_HIGH_SPEED | ST_MMC_CCONFIG_ADMA2 | \
538bef7178SPeter Griffin 	 ST_MMC_CCONFIG_8BIT | \
548bef7178SPeter Griffin 	 (MAX_BLK_LEN_1024 << ST_MMC_CCONFIG_MAX_BLK_LEN))
558bef7178SPeter Griffin 
568bef7178SPeter Griffin #define ST_MMC_CCONFIG_REG_3			0x408
578bef7178SPeter Griffin #define ST_MMC_CCONFIG_EMMC_SLOT_TYPE		BIT(28)
588bef7178SPeter Griffin #define ST_MMC_CCONFIG_64BIT			BIT(24)
598bef7178SPeter Griffin #define ST_MMC_CCONFIG_ASYNCH_INTR_SUPPORT	BIT(20)
608bef7178SPeter Griffin #define ST_MMC_CCONFIG_1P8_VOLT			BIT(16)
618bef7178SPeter Griffin #define ST_MMC_CCONFIG_3P0_VOLT			BIT(12)
628bef7178SPeter Griffin #define ST_MMC_CCONFIG_3P3_VOLT			BIT(8)
638bef7178SPeter Griffin #define ST_MMC_CCONFIG_SUSP_RES_SUPPORT		BIT(4)
648bef7178SPeter Griffin #define ST_MMC_CCONFIG_SDMA			BIT(0)
658bef7178SPeter Griffin #define ST_MMC_CCONFIG_3_DEFAULT	\
668bef7178SPeter Griffin 			 (ST_MMC_CCONFIG_ASYNCH_INTR_SUPPORT	| \
678bef7178SPeter Griffin 			  ST_MMC_CCONFIG_3P3_VOLT		| \
688bef7178SPeter Griffin 			  ST_MMC_CCONFIG_SUSP_RES_SUPPORT	| \
698bef7178SPeter Griffin 			  ST_MMC_CCONFIG_SDMA)
708bef7178SPeter Griffin 
718bef7178SPeter Griffin #define ST_MMC_CCONFIG_REG_4	0x40c
728bef7178SPeter Griffin #define ST_MMC_CCONFIG_D_DRIVER	BIT(20)
738bef7178SPeter Griffin #define ST_MMC_CCONFIG_C_DRIVER	BIT(16)
748bef7178SPeter Griffin #define ST_MMC_CCONFIG_A_DRIVER	BIT(12)
758bef7178SPeter Griffin #define ST_MMC_CCONFIG_DDR50	BIT(8)
768bef7178SPeter Griffin #define ST_MMC_CCONFIG_SDR104	BIT(4)
778bef7178SPeter Griffin #define ST_MMC_CCONFIG_SDR50	BIT(0)
788bef7178SPeter Griffin #define ST_MMC_CCONFIG_4_DEFAULT	0
798bef7178SPeter Griffin 
808bef7178SPeter Griffin #define ST_MMC_CCONFIG_REG_5		0x410
818bef7178SPeter Griffin #define ST_MMC_CCONFIG_TUNING_FOR_SDR50	BIT(8)
828bef7178SPeter Griffin #define RETUNING_TIMER_CNT_MAX		0xf
838bef7178SPeter Griffin #define ST_MMC_CCONFIG_5_DEFAULT	0
848bef7178SPeter Griffin 
858bef7178SPeter Griffin /* I/O configuration for Arasan IP */
868bef7178SPeter Griffin #define ST_MMC_GP_OUTPUT	0x450
878bef7178SPeter Griffin #define ST_MMC_GP_OUTPUT_CD	BIT(12)
888bef7178SPeter Griffin 
898bef7178SPeter Griffin #define ST_MMC_STATUS_R		0x460
908bef7178SPeter Griffin 
918bef7178SPeter Griffin #define ST_TOP_MMC_DLY_FIX_OFF(x)	(x - 0x8)
928bef7178SPeter Griffin 
938bef7178SPeter Griffin /* TOP config registers to manage static and dynamic delay */
948bef7178SPeter Griffin #define ST_TOP_MMC_TX_CLK_DLY			ST_TOP_MMC_DLY_FIX_OFF(0x8)
958bef7178SPeter Griffin #define ST_TOP_MMC_RX_CLK_DLY			ST_TOP_MMC_DLY_FIX_OFF(0xc)
968bef7178SPeter Griffin /* MMC delay control register */
978bef7178SPeter Griffin #define ST_TOP_MMC_DLY_CTRL			ST_TOP_MMC_DLY_FIX_OFF(0x18)
988bef7178SPeter Griffin #define ST_TOP_MMC_DLY_CTRL_DLL_BYPASS_CMD	BIT(0)
998bef7178SPeter Griffin #define ST_TOP_MMC_DLY_CTRL_DLL_BYPASS_PH_SEL	BIT(1)
1008bef7178SPeter Griffin #define ST_TOP_MMC_DLY_CTRL_TX_DLL_ENABLE	BIT(8)
1018bef7178SPeter Griffin #define ST_TOP_MMC_DLY_CTRL_RX_DLL_ENABLE	BIT(9)
1028bef7178SPeter Griffin #define ST_TOP_MMC_DLY_CTRL_ATUNE_NOT_CFG_DLY	BIT(10)
1038bef7178SPeter Griffin #define ST_TOP_MMC_START_DLL_LOCK		BIT(11)
1048bef7178SPeter Griffin 
1058bef7178SPeter Griffin /* register to provide the phase-shift value for DLL */
1068bef7178SPeter Griffin #define ST_TOP_MMC_TX_DLL_STEP_DLY		ST_TOP_MMC_DLY_FIX_OFF(0x1c)
1078bef7178SPeter Griffin #define ST_TOP_MMC_RX_DLL_STEP_DLY		ST_TOP_MMC_DLY_FIX_OFF(0x20)
1088bef7178SPeter Griffin #define ST_TOP_MMC_RX_CMD_STEP_DLY		ST_TOP_MMC_DLY_FIX_OFF(0x24)
1098bef7178SPeter Griffin 
1108bef7178SPeter Griffin /* phase shift delay on the tx clk 2.188ns */
1118bef7178SPeter Griffin #define ST_TOP_MMC_TX_DLL_STEP_DLY_VALID	0x6
1128bef7178SPeter Griffin 
1138bef7178SPeter Griffin #define ST_TOP_MMC_DLY_MAX			0xf
1148bef7178SPeter Griffin 
1158bef7178SPeter Griffin #define ST_TOP_MMC_DYN_DLY_CONF	\
1168bef7178SPeter Griffin 		(ST_TOP_MMC_DLY_CTRL_TX_DLL_ENABLE | \
1178bef7178SPeter Griffin 		 ST_TOP_MMC_DLY_CTRL_ATUNE_NOT_CFG_DLY | \
1188bef7178SPeter Griffin 		 ST_TOP_MMC_START_DLL_LOCK)
1198bef7178SPeter Griffin 
120f52d9c4fSPeter Griffin static u32 sdhci_st_readl(struct sdhci_host *host, int reg)
121f52d9c4fSPeter Griffin {
122f52d9c4fSPeter Griffin 	u32 ret;
123f52d9c4fSPeter Griffin 
124f52d9c4fSPeter Griffin 	switch (reg) {
125f52d9c4fSPeter Griffin 	case SDHCI_CAPABILITIES:
126f52d9c4fSPeter Griffin 		ret = readl_relaxed(host->ioaddr + reg);
127f52d9c4fSPeter Griffin 		/* Support 3.3V and 1.8V */
128f52d9c4fSPeter Griffin 		ret &= ~SDHCI_CAN_VDD_300;
129f52d9c4fSPeter Griffin 		break;
130f52d9c4fSPeter Griffin 	default:
131f52d9c4fSPeter Griffin 		ret = readl_relaxed(host->ioaddr + reg);
132f52d9c4fSPeter Griffin 	}
133f52d9c4fSPeter Griffin 	return ret;
134f52d9c4fSPeter Griffin }
135f52d9c4fSPeter Griffin 
136f52d9c4fSPeter Griffin static const struct sdhci_ops sdhci_st_ops = {
137f52d9c4fSPeter Griffin 	.get_max_clock = sdhci_pltfm_clk_get_max_clock,
138f52d9c4fSPeter Griffin 	.set_clock = sdhci_set_clock,
139f52d9c4fSPeter Griffin 	.set_bus_width = sdhci_set_bus_width,
140f52d9c4fSPeter Griffin 	.read_l = sdhci_st_readl,
141f52d9c4fSPeter Griffin 	.reset = sdhci_reset,
142f52d9c4fSPeter Griffin };
143f52d9c4fSPeter Griffin 
144f52d9c4fSPeter Griffin static const struct sdhci_pltfm_data sdhci_st_pdata = {
145f52d9c4fSPeter Griffin 	.ops = &sdhci_st_ops,
146f52d9c4fSPeter Griffin 	.quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC |
147f52d9c4fSPeter Griffin 	    SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN,
148f52d9c4fSPeter Griffin };
149f52d9c4fSPeter Griffin 
150f52d9c4fSPeter Griffin 
151f52d9c4fSPeter Griffin static int sdhci_st_probe(struct platform_device *pdev)
152f52d9c4fSPeter Griffin {
153f52d9c4fSPeter Griffin 	struct sdhci_host *host;
154f52d9c4fSPeter Griffin 	struct sdhci_pltfm_host *pltfm_host;
155f52d9c4fSPeter Griffin 	struct clk *clk;
156f52d9c4fSPeter Griffin 	int ret = 0;
157f52d9c4fSPeter Griffin 	u16 host_version;
158f52d9c4fSPeter Griffin 
159f52d9c4fSPeter Griffin 	clk =  devm_clk_get(&pdev->dev, "mmc");
160f52d9c4fSPeter Griffin 	if (IS_ERR(clk)) {
161f52d9c4fSPeter Griffin 		dev_err(&pdev->dev, "Peripheral clk not found\n");
162f52d9c4fSPeter Griffin 		return PTR_ERR(clk);
163f52d9c4fSPeter Griffin 	}
164f52d9c4fSPeter Griffin 
165f52d9c4fSPeter Griffin 	host = sdhci_pltfm_init(pdev, &sdhci_st_pdata, 0);
166f52d9c4fSPeter Griffin 	if (IS_ERR(host)) {
167f52d9c4fSPeter Griffin 		dev_err(&pdev->dev, "Failed sdhci_pltfm_init\n");
168f52d9c4fSPeter Griffin 		return PTR_ERR(host);
169f52d9c4fSPeter Griffin 	}
170f52d9c4fSPeter Griffin 
171f52d9c4fSPeter Griffin 	ret = mmc_of_parse(host->mmc);
172f52d9c4fSPeter Griffin 	if (ret) {
173f52d9c4fSPeter Griffin 		dev_err(&pdev->dev, "Failed mmc_of_parse\n");
174fc702cb3SUlf Hansson 		goto err_of;
175f52d9c4fSPeter Griffin 	}
176f52d9c4fSPeter Griffin 
177f52d9c4fSPeter Griffin 	clk_prepare_enable(clk);
178f52d9c4fSPeter Griffin 
179f52d9c4fSPeter Griffin 	pltfm_host = sdhci_priv(host);
180f52d9c4fSPeter Griffin 	pltfm_host->clk = clk;
181f52d9c4fSPeter Griffin 
182f52d9c4fSPeter Griffin 	ret = sdhci_add_host(host);
183f52d9c4fSPeter Griffin 	if (ret) {
184f52d9c4fSPeter Griffin 		dev_err(&pdev->dev, "Failed sdhci_add_host\n");
185f52d9c4fSPeter Griffin 		goto err_out;
186f52d9c4fSPeter Griffin 	}
187f52d9c4fSPeter Griffin 
188f52d9c4fSPeter Griffin 	platform_set_drvdata(pdev, host);
189f52d9c4fSPeter Griffin 
190f52d9c4fSPeter Griffin 	host_version = readw_relaxed((host->ioaddr + SDHCI_HOST_VERSION));
191f52d9c4fSPeter Griffin 
192f52d9c4fSPeter Griffin 	dev_info(&pdev->dev, "SDHCI ST Initialised: Host Version: 0x%x Vendor Version 0x%x\n",
193f52d9c4fSPeter Griffin 		((host_version & SDHCI_SPEC_VER_MASK) >> SDHCI_SPEC_VER_SHIFT),
194f52d9c4fSPeter Griffin 		((host_version & SDHCI_VENDOR_VER_MASK) >>
195f52d9c4fSPeter Griffin 		SDHCI_VENDOR_VER_SHIFT));
196f52d9c4fSPeter Griffin 
197f52d9c4fSPeter Griffin 	return 0;
198f52d9c4fSPeter Griffin 
199f52d9c4fSPeter Griffin err_out:
200f52d9c4fSPeter Griffin 	clk_disable_unprepare(clk);
201fc702cb3SUlf Hansson err_of:
202f52d9c4fSPeter Griffin 	sdhci_pltfm_free(pdev);
203f52d9c4fSPeter Griffin 
204f52d9c4fSPeter Griffin 	return ret;
205f52d9c4fSPeter Griffin }
206f52d9c4fSPeter Griffin 
207f52d9c4fSPeter Griffin #ifdef CONFIG_PM_SLEEP
208f52d9c4fSPeter Griffin static int sdhci_st_suspend(struct device *dev)
209f52d9c4fSPeter Griffin {
210f52d9c4fSPeter Griffin 	struct sdhci_host *host = dev_get_drvdata(dev);
211f52d9c4fSPeter Griffin 	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
212f52d9c4fSPeter Griffin 	int ret = sdhci_suspend_host(host);
213f52d9c4fSPeter Griffin 
214f52d9c4fSPeter Griffin 	if (ret)
215f52d9c4fSPeter Griffin 		goto out;
216f52d9c4fSPeter Griffin 
217f52d9c4fSPeter Griffin 	clk_disable_unprepare(pltfm_host->clk);
218f52d9c4fSPeter Griffin out:
219f52d9c4fSPeter Griffin 	return ret;
220f52d9c4fSPeter Griffin }
221f52d9c4fSPeter Griffin 
222f52d9c4fSPeter Griffin static int sdhci_st_resume(struct device *dev)
223f52d9c4fSPeter Griffin {
224f52d9c4fSPeter Griffin 	struct sdhci_host *host = dev_get_drvdata(dev);
225f52d9c4fSPeter Griffin 	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
226f52d9c4fSPeter Griffin 
227f52d9c4fSPeter Griffin 	clk_prepare_enable(pltfm_host->clk);
228f52d9c4fSPeter Griffin 
229f52d9c4fSPeter Griffin 	return sdhci_resume_host(host);
230f52d9c4fSPeter Griffin }
231f52d9c4fSPeter Griffin #endif
232f52d9c4fSPeter Griffin 
233f52d9c4fSPeter Griffin static SIMPLE_DEV_PM_OPS(sdhci_st_pmops, sdhci_st_suspend, sdhci_st_resume);
234f52d9c4fSPeter Griffin 
235f52d9c4fSPeter Griffin static const struct of_device_id st_sdhci_match[] = {
236f52d9c4fSPeter Griffin 	{ .compatible = "st,sdhci" },
237f52d9c4fSPeter Griffin 	{},
238f52d9c4fSPeter Griffin };
239f52d9c4fSPeter Griffin 
240f52d9c4fSPeter Griffin MODULE_DEVICE_TABLE(of, st_sdhci_match);
241f52d9c4fSPeter Griffin 
242f52d9c4fSPeter Griffin static struct platform_driver sdhci_st_driver = {
243f52d9c4fSPeter Griffin 	.probe = sdhci_st_probe,
244caebcae9SKevin Hao 	.remove = sdhci_pltfm_unregister,
245f52d9c4fSPeter Griffin 	.driver = {
246f52d9c4fSPeter Griffin 		   .name = "sdhci-st",
247f52d9c4fSPeter Griffin 		   .pm = &sdhci_st_pmops,
248f52d9c4fSPeter Griffin 		   .of_match_table = of_match_ptr(st_sdhci_match),
249f52d9c4fSPeter Griffin 		  },
250f52d9c4fSPeter Griffin };
251f52d9c4fSPeter Griffin 
252f52d9c4fSPeter Griffin module_platform_driver(sdhci_st_driver);
253f52d9c4fSPeter Griffin 
254f52d9c4fSPeter Griffin MODULE_DESCRIPTION("SDHCI driver for STMicroelectronics SoCs");
255f52d9c4fSPeter Griffin MODULE_AUTHOR("Giuseppe Cavallaro <peppe.cavallaro@st.com>");
256f52d9c4fSPeter Griffin MODULE_LICENSE("GPL v2");
257f52d9c4fSPeter Griffin MODULE_ALIAS("platform:st-sdhci");
258