brintos

brintos / linux-shallow public Read only

0
0
Text · 14.1 KiB · d12532b Raw
525 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Support for SDHCI on STMicroelectronics SoCs4 *5 * Copyright (C) 2014 STMicroelectronics Ltd6 * Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>7 * Contributors: Peter Griffin <peter.griffin@linaro.org>8 *9 * Based on sdhci-cns3xxx.c10 */11 12#include <linux/io.h>13#include <linux/of.h>14#include <linux/module.h>15#include <linux/err.h>16#include <linux/mmc/host.h>17#include <linux/reset.h>18#include "sdhci-pltfm.h"19 20struct st_mmc_platform_data {21	struct  reset_control *rstc;22	struct  clk *icnclk;23	void __iomem *top_ioaddr;24};25 26/* MMCSS glue logic to setup the HC on some ST SoCs (e.g. STiH407 family) */27 28#define ST_MMC_CCONFIG_REG_1		0x40029#define ST_MMC_CCONFIG_TIMEOUT_CLK_UNIT	BIT(24)30#define ST_MMC_CCONFIG_TIMEOUT_CLK_FREQ	BIT(12)31#define ST_MMC_CCONFIG_TUNING_COUNT_DEFAULT	BIT(8)32#define ST_MMC_CCONFIG_ASYNC_WAKEUP	BIT(0)33#define ST_MMC_CCONFIG_1_DEFAULT	\34				((ST_MMC_CCONFIG_TIMEOUT_CLK_UNIT) | \35				 (ST_MMC_CCONFIG_TIMEOUT_CLK_FREQ) | \36				 (ST_MMC_CCONFIG_TUNING_COUNT_DEFAULT))37 38#define ST_MMC_CCONFIG_REG_2		0x40439#define ST_MMC_CCONFIG_HIGH_SPEED	BIT(28)40#define ST_MMC_CCONFIG_ADMA2		BIT(24)41#define ST_MMC_CCONFIG_8BIT		BIT(20)42#define ST_MMC_CCONFIG_MAX_BLK_LEN	1643#define  MAX_BLK_LEN_1024		144#define  MAX_BLK_LEN_2048		245#define BASE_CLK_FREQ_200		0xc846#define BASE_CLK_FREQ_100		0x6447#define BASE_CLK_FREQ_50		0x3248#define ST_MMC_CCONFIG_2_DEFAULT \49	(ST_MMC_CCONFIG_HIGH_SPEED | ST_MMC_CCONFIG_ADMA2 | \50	 ST_MMC_CCONFIG_8BIT | \51	 (MAX_BLK_LEN_1024 << ST_MMC_CCONFIG_MAX_BLK_LEN))52 53#define ST_MMC_CCONFIG_REG_3			0x40854#define ST_MMC_CCONFIG_EMMC_SLOT_TYPE		BIT(28)55#define ST_MMC_CCONFIG_64BIT			BIT(24)56#define ST_MMC_CCONFIG_ASYNCH_INTR_SUPPORT	BIT(20)57#define ST_MMC_CCONFIG_1P8_VOLT			BIT(16)58#define ST_MMC_CCONFIG_3P0_VOLT			BIT(12)59#define ST_MMC_CCONFIG_3P3_VOLT			BIT(8)60#define ST_MMC_CCONFIG_SUSP_RES_SUPPORT		BIT(4)61#define ST_MMC_CCONFIG_SDMA			BIT(0)62#define ST_MMC_CCONFIG_3_DEFAULT	\63			 (ST_MMC_CCONFIG_ASYNCH_INTR_SUPPORT	| \64			  ST_MMC_CCONFIG_3P3_VOLT		| \65			  ST_MMC_CCONFIG_SUSP_RES_SUPPORT	| \66			  ST_MMC_CCONFIG_SDMA)67 68#define ST_MMC_CCONFIG_REG_4	0x40c69#define ST_MMC_CCONFIG_D_DRIVER	BIT(20)70#define ST_MMC_CCONFIG_C_DRIVER	BIT(16)71#define ST_MMC_CCONFIG_A_DRIVER	BIT(12)72#define ST_MMC_CCONFIG_DDR50	BIT(8)73#define ST_MMC_CCONFIG_SDR104	BIT(4)74#define ST_MMC_CCONFIG_SDR50	BIT(0)75#define ST_MMC_CCONFIG_4_DEFAULT	076 77#define ST_MMC_CCONFIG_REG_5		0x41078#define ST_MMC_CCONFIG_TUNING_FOR_SDR50	BIT(8)79#define RETUNING_TIMER_CNT_MAX		0xf80#define ST_MMC_CCONFIG_5_DEFAULT	081 82/* I/O configuration for Arasan IP */83#define ST_MMC_GP_OUTPUT	0x45084#define ST_MMC_GP_OUTPUT_CD	BIT(12)85 86#define ST_MMC_STATUS_R		0x46087 88#define ST_TOP_MMC_DLY_FIX_OFF(x)	(x - 0x8)89 90/* TOP config registers to manage static and dynamic delay */91#define ST_TOP_MMC_TX_CLK_DLY			ST_TOP_MMC_DLY_FIX_OFF(0x8)92#define ST_TOP_MMC_RX_CLK_DLY			ST_TOP_MMC_DLY_FIX_OFF(0xc)93/* MMC delay control register */94#define ST_TOP_MMC_DLY_CTRL			ST_TOP_MMC_DLY_FIX_OFF(0x18)95#define ST_TOP_MMC_DLY_CTRL_DLL_BYPASS_CMD	BIT(0)96#define ST_TOP_MMC_DLY_CTRL_DLL_BYPASS_PH_SEL	BIT(1)97#define ST_TOP_MMC_DLY_CTRL_TX_DLL_ENABLE	BIT(8)98#define ST_TOP_MMC_DLY_CTRL_RX_DLL_ENABLE	BIT(9)99#define ST_TOP_MMC_DLY_CTRL_ATUNE_NOT_CFG_DLY	BIT(10)100#define ST_TOP_MMC_START_DLL_LOCK		BIT(11)101 102/* register to provide the phase-shift value for DLL */103#define ST_TOP_MMC_TX_DLL_STEP_DLY		ST_TOP_MMC_DLY_FIX_OFF(0x1c)104#define ST_TOP_MMC_RX_DLL_STEP_DLY		ST_TOP_MMC_DLY_FIX_OFF(0x20)105#define ST_TOP_MMC_RX_CMD_STEP_DLY		ST_TOP_MMC_DLY_FIX_OFF(0x24)106 107/* phase shift delay on the tx clk 2.188ns */108#define ST_TOP_MMC_TX_DLL_STEP_DLY_VALID	0x6109 110#define ST_TOP_MMC_DLY_MAX			0xf111 112#define ST_TOP_MMC_DYN_DLY_CONF	\113		(ST_TOP_MMC_DLY_CTRL_TX_DLL_ENABLE | \114		 ST_TOP_MMC_DLY_CTRL_ATUNE_NOT_CFG_DLY | \115		 ST_TOP_MMC_START_DLL_LOCK)116 117/*118 * For clock speeds greater than 90MHz, we need to check that the119 * DLL procedure has finished before switching to ultra-speed modes.120 */121#define	CLK_TO_CHECK_DLL_LOCK	90000000122 123static inline void st_mmcss_set_static_delay(void __iomem *ioaddr)124{125	if (!ioaddr)126		return;127 128	writel_relaxed(0x0, ioaddr + ST_TOP_MMC_DLY_CTRL);129	writel_relaxed(ST_TOP_MMC_DLY_MAX,130			ioaddr + ST_TOP_MMC_TX_CLK_DLY);131}132 133/**134 * st_mmcss_cconfig: configure the Arasan HC inside the flashSS.135 * @np: dt device node.136 * @host: sdhci host137 * Description: this function is to configure the Arasan host controller.138 * On some ST SoCs, i.e. STiH407 family, the MMC devices inside a dedicated139 * flashSS sub-system which needs to be configured to be compliant to eMMC 4.5140 * or eMMC4.3.  This has to be done before registering the sdhci host.141 */142static void st_mmcss_cconfig(struct device_node *np, struct sdhci_host *host)143{144	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);145	struct mmc_host *mhost = host->mmc;146	u32 cconf2, cconf3, cconf4, cconf5;147 148	if (!of_device_is_compatible(np, "st,sdhci-stih407"))149		return;150 151	cconf2 = ST_MMC_CCONFIG_2_DEFAULT;152	cconf3 = ST_MMC_CCONFIG_3_DEFAULT;153	cconf4 = ST_MMC_CCONFIG_4_DEFAULT;154	cconf5 = ST_MMC_CCONFIG_5_DEFAULT;155 156	writel_relaxed(ST_MMC_CCONFIG_1_DEFAULT,157			host->ioaddr + ST_MMC_CCONFIG_REG_1);158 159	/* Set clock frequency, default to 50MHz if max-frequency is not160	 * provided */161 162	switch (mhost->f_max) {163	case 200000000:164		clk_set_rate(pltfm_host->clk, mhost->f_max);165		cconf2 |= BASE_CLK_FREQ_200;166		break;167	case 100000000:168		clk_set_rate(pltfm_host->clk, mhost->f_max);169		cconf2 |= BASE_CLK_FREQ_100;170		break;171	default:172		clk_set_rate(pltfm_host->clk, 50000000);173		cconf2 |= BASE_CLK_FREQ_50;174	}175 176	writel_relaxed(cconf2, host->ioaddr + ST_MMC_CCONFIG_REG_2);177 178	if (!mmc_card_is_removable(mhost))179		cconf3 |= ST_MMC_CCONFIG_EMMC_SLOT_TYPE;180	else181		/* CARD _D ET_CTRL */182		writel_relaxed(ST_MMC_GP_OUTPUT_CD,183				host->ioaddr + ST_MMC_GP_OUTPUT);184 185	if (mhost->caps & MMC_CAP_UHS_SDR50) {186		/* use 1.8V */187		cconf3 |= ST_MMC_CCONFIG_1P8_VOLT;188		cconf4 |= ST_MMC_CCONFIG_SDR50;189		/* Use tuning */190		cconf5 |= ST_MMC_CCONFIG_TUNING_FOR_SDR50;191		/* Max timeout for retuning */192		cconf5 |= RETUNING_TIMER_CNT_MAX;193	}194 195	if (mhost->caps & MMC_CAP_UHS_SDR104) {196		/*197		 * SDR104 implies the HC can support HS200 mode, so198		 * it's mandatory to use 1.8V199		 */200		cconf3 |= ST_MMC_CCONFIG_1P8_VOLT;201		cconf4 |= ST_MMC_CCONFIG_SDR104;202		/* Max timeout for retuning */203		cconf5 |= RETUNING_TIMER_CNT_MAX;204	}205 206	if (mhost->caps & MMC_CAP_UHS_DDR50)207		cconf4 |= ST_MMC_CCONFIG_DDR50;208 209	writel_relaxed(cconf3, host->ioaddr + ST_MMC_CCONFIG_REG_3);210	writel_relaxed(cconf4, host->ioaddr + ST_MMC_CCONFIG_REG_4);211	writel_relaxed(cconf5, host->ioaddr + ST_MMC_CCONFIG_REG_5);212}213 214static inline void st_mmcss_set_dll(void __iomem *ioaddr)215{216	if (!ioaddr)217		return;218 219	writel_relaxed(ST_TOP_MMC_DYN_DLY_CONF,	ioaddr + ST_TOP_MMC_DLY_CTRL);220	writel_relaxed(ST_TOP_MMC_TX_DLL_STEP_DLY_VALID,221			ioaddr + ST_TOP_MMC_TX_DLL_STEP_DLY);222}223 224static int st_mmcss_lock_dll(void __iomem *ioaddr)225{226	unsigned long curr, value;227	unsigned long finish = jiffies + HZ;228 229	/* Checks if the DLL procedure is finished */230	do {231		curr = jiffies;232		value = readl(ioaddr + ST_MMC_STATUS_R);233		if (value & 0x1)234			return 0;235 236		cpu_relax();237	} while (!time_after_eq(curr, finish));238 239	return -EBUSY;240}241 242static int sdhci_st_set_dll_for_clock(struct sdhci_host *host)243{244	int ret = 0;245	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);246	struct st_mmc_platform_data *pdata = sdhci_pltfm_priv(pltfm_host);247 248	if (host->clock > CLK_TO_CHECK_DLL_LOCK) {249		st_mmcss_set_dll(pdata->top_ioaddr);250		ret = st_mmcss_lock_dll(host->ioaddr);251	}252 253	return ret;254}255 256static void sdhci_st_set_uhs_signaling(struct sdhci_host *host,257					unsigned int uhs)258{259	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);260	struct st_mmc_platform_data *pdata = sdhci_pltfm_priv(pltfm_host);261	u16 ctrl_2 = sdhci_readw(host, SDHCI_HOST_CONTROL2);262	int ret = 0;263 264	/* Select Bus Speed Mode for host */265	ctrl_2 &= ~SDHCI_CTRL_UHS_MASK;266	switch (uhs) {267	/*268	 * Set V18_EN -- UHS modes do not work without this.269	 * does not change signaling voltage270	 */271 272	case MMC_TIMING_UHS_SDR12:273		st_mmcss_set_static_delay(pdata->top_ioaddr);274		ctrl_2 |= SDHCI_CTRL_UHS_SDR12 | SDHCI_CTRL_VDD_180;275		break;276	case MMC_TIMING_UHS_SDR25:277		st_mmcss_set_static_delay(pdata->top_ioaddr);278		ctrl_2 |= SDHCI_CTRL_UHS_SDR25 | SDHCI_CTRL_VDD_180;279		break;280	case MMC_TIMING_UHS_SDR50:281		st_mmcss_set_static_delay(pdata->top_ioaddr);282		ctrl_2 |= SDHCI_CTRL_UHS_SDR50 | SDHCI_CTRL_VDD_180;283		ret = sdhci_st_set_dll_for_clock(host);284		break;285	case MMC_TIMING_UHS_SDR104:286	case MMC_TIMING_MMC_HS200:287		st_mmcss_set_static_delay(pdata->top_ioaddr);288		ctrl_2 |= SDHCI_CTRL_UHS_SDR104 | SDHCI_CTRL_VDD_180;289		ret =  sdhci_st_set_dll_for_clock(host);290		break;291	case MMC_TIMING_UHS_DDR50:292	case MMC_TIMING_MMC_DDR52:293		st_mmcss_set_static_delay(pdata->top_ioaddr);294		ctrl_2 |= SDHCI_CTRL_UHS_DDR50 | SDHCI_CTRL_VDD_180;295		break;296	}297 298	if (ret)299		dev_warn(mmc_dev(host->mmc), "Error setting dll for clock "300						"(uhs %d)\n", uhs);301 302	dev_dbg(mmc_dev(host->mmc), "uhs %d, ctrl_2 %04X\n", uhs, ctrl_2);303 304	sdhci_writew(host, ctrl_2, SDHCI_HOST_CONTROL2);305}306 307static u32 sdhci_st_readl(struct sdhci_host *host, int reg)308{309	u32 ret;310 311	switch (reg) {312	case SDHCI_CAPABILITIES:313		ret = readl_relaxed(host->ioaddr + reg);314		/* Support 3.3V and 1.8V */315		ret &= ~SDHCI_CAN_VDD_300;316		break;317	default:318		ret = readl_relaxed(host->ioaddr + reg);319	}320	return ret;321}322 323static const struct sdhci_ops sdhci_st_ops = {324	.get_max_clock = sdhci_pltfm_clk_get_max_clock,325	.set_clock = sdhci_set_clock,326	.set_bus_width = sdhci_set_bus_width,327	.read_l = sdhci_st_readl,328	.reset = sdhci_reset,329	.set_uhs_signaling = sdhci_st_set_uhs_signaling,330};331 332static const struct sdhci_pltfm_data sdhci_st_pdata = {333	.ops = &sdhci_st_ops,334	.quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC |335		SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN |336		SDHCI_QUIRK_NO_HISPD_BIT,337	.quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN |338		SDHCI_QUIRK2_STOP_WITH_TC,339};340 341 342static int sdhci_st_probe(struct platform_device *pdev)343{344	struct device_node *np = pdev->dev.of_node;345	struct sdhci_host *host;346	struct st_mmc_platform_data *pdata;347	struct sdhci_pltfm_host *pltfm_host;348	struct clk *clk, *icnclk;349	int ret = 0;350	u16 host_version;351	struct reset_control *rstc;352 353	clk =  devm_clk_get(&pdev->dev, "mmc");354	if (IS_ERR(clk)) {355		dev_err(&pdev->dev, "Peripheral clk not found\n");356		return PTR_ERR(clk);357	}358 359	/* ICN clock isn't compulsory, but use it if it's provided. */360	icnclk = devm_clk_get(&pdev->dev, "icn");361	if (IS_ERR(icnclk))362		icnclk = NULL;363 364	rstc = devm_reset_control_get_optional_exclusive(&pdev->dev, NULL);365	if (IS_ERR(rstc))366		return PTR_ERR(rstc);367	reset_control_deassert(rstc);368 369	host = sdhci_pltfm_init(pdev, &sdhci_st_pdata, sizeof(*pdata));370	if (IS_ERR(host)) {371		dev_err(&pdev->dev, "Failed sdhci_pltfm_init\n");372		ret = PTR_ERR(host);373		goto err_pltfm_init;374	}375 376	pltfm_host = sdhci_priv(host);377	pdata = sdhci_pltfm_priv(pltfm_host);378	pdata->rstc = rstc;379 380	ret = mmc_of_parse(host->mmc);381	if (ret) {382		dev_err(&pdev->dev, "Failed mmc_of_parse\n");383		goto err_of;384	}385 386	ret = clk_prepare_enable(clk);387	if (ret) {388		dev_err(&pdev->dev, "Failed to prepare clock\n");389		goto err_of;390	}391 392	ret = clk_prepare_enable(icnclk);393	if (ret) {394		dev_err(&pdev->dev, "Failed to prepare icn clock\n");395		goto err_icnclk;396	}397 398	/* Configure the FlashSS Top registers for setting eMMC TX/RX delay */399	pdata->top_ioaddr = devm_platform_ioremap_resource_byname(pdev, "top-mmc-delay");400	if (IS_ERR(pdata->top_ioaddr))401		pdata->top_ioaddr = NULL;402 403	pltfm_host->clk = clk;404	pdata->icnclk = icnclk;405 406	/* Configure the Arasan HC inside the flashSS */407	st_mmcss_cconfig(np, host);408 409	ret = sdhci_add_host(host);410	if (ret)411		goto err_out;412 413	host_version = readw_relaxed((host->ioaddr + SDHCI_HOST_VERSION));414 415	dev_info(&pdev->dev, "SDHCI ST Initialised: Host Version: 0x%x Vendor Version 0x%x\n",416		((host_version & SDHCI_SPEC_VER_MASK) >> SDHCI_SPEC_VER_SHIFT),417		((host_version & SDHCI_VENDOR_VER_MASK) >>418		SDHCI_VENDOR_VER_SHIFT));419 420	return 0;421 422err_out:423	clk_disable_unprepare(icnclk);424err_icnclk:425	clk_disable_unprepare(clk);426err_of:427	sdhci_pltfm_free(pdev);428err_pltfm_init:429	reset_control_assert(rstc);430 431	return ret;432}433 434static void sdhci_st_remove(struct platform_device *pdev)435{436	struct sdhci_host *host = platform_get_drvdata(pdev);437	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);438	struct st_mmc_platform_data *pdata = sdhci_pltfm_priv(pltfm_host);439	struct reset_control *rstc = pdata->rstc;440	struct clk *clk = pltfm_host->clk;441 442	sdhci_pltfm_remove(pdev);443 444	clk_disable_unprepare(pdata->icnclk);445	clk_disable_unprepare(clk);446 447	reset_control_assert(rstc);448}449 450#ifdef CONFIG_PM_SLEEP451static int sdhci_st_suspend(struct device *dev)452{453	struct sdhci_host *host = dev_get_drvdata(dev);454	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);455	struct st_mmc_platform_data *pdata = sdhci_pltfm_priv(pltfm_host);456	int ret;457 458	if (host->tuning_mode != SDHCI_TUNING_MODE_3)459		mmc_retune_needed(host->mmc);460 461	ret = sdhci_suspend_host(host);462	if (ret)463		goto out;464 465	reset_control_assert(pdata->rstc);466 467	clk_disable_unprepare(pdata->icnclk);468	clk_disable_unprepare(pltfm_host->clk);469out:470	return ret;471}472 473static int sdhci_st_resume(struct device *dev)474{475	struct sdhci_host *host = dev_get_drvdata(dev);476	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);477	struct st_mmc_platform_data *pdata = sdhci_pltfm_priv(pltfm_host);478	struct device_node *np = dev->of_node;479	int ret;480 481	ret = clk_prepare_enable(pltfm_host->clk);482	if (ret)483		return ret;484 485	ret = clk_prepare_enable(pdata->icnclk);486	if (ret) {487		clk_disable_unprepare(pltfm_host->clk);488		return ret;489	}490 491	reset_control_deassert(pdata->rstc);492 493	st_mmcss_cconfig(np, host);494 495	return sdhci_resume_host(host);496}497#endif498 499static SIMPLE_DEV_PM_OPS(sdhci_st_pmops, sdhci_st_suspend, sdhci_st_resume);500 501static const struct of_device_id st_sdhci_match[] = {502	{ .compatible = "st,sdhci" },503	{},504};505 506MODULE_DEVICE_TABLE(of, st_sdhci_match);507 508static struct platform_driver sdhci_st_driver = {509	.probe = sdhci_st_probe,510	.remove_new = sdhci_st_remove,511	.driver = {512		   .name = "sdhci-st",513		   .probe_type = PROBE_PREFER_ASYNCHRONOUS,514		   .pm = &sdhci_st_pmops,515		   .of_match_table = st_sdhci_match,516		  },517};518 519module_platform_driver(sdhci_st_driver);520 521MODULE_DESCRIPTION("SDHCI driver for STMicroelectronics SoCs");522MODULE_AUTHOR("Giuseppe Cavallaro <peppe.cavallaro@st.com>");523MODULE_LICENSE("GPL v2");524MODULE_ALIAS("platform:sdhci-st");525