12874c5fdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
2e3ec3a3dSSoren Brinkmann /*
3e3ec3a3dSSoren Brinkmann  * Arasan Secure Digital Host Controller Interface.
4e3ec3a3dSSoren Brinkmann  * Copyright (C) 2011 - 2012 Michal Simek <monstr@monstr.eu>
5e3ec3a3dSSoren Brinkmann  * Copyright (c) 2012 Wind River Systems, Inc.
6e3ec3a3dSSoren Brinkmann  * Copyright (C) 2013 Pengutronix e.K.
7e3ec3a3dSSoren Brinkmann  * Copyright (C) 2013 Xilinx Inc.
8e3ec3a3dSSoren Brinkmann  *
9e3ec3a3dSSoren Brinkmann  * Based on sdhci-of-esdhc.c
10e3ec3a3dSSoren Brinkmann  *
11e3ec3a3dSSoren Brinkmann  * Copyright (c) 2007 Freescale Semiconductor, Inc.
12e3ec3a3dSSoren Brinkmann  * Copyright (c) 2009 MontaVista Software, Inc.
13e3ec3a3dSSoren Brinkmann  *
14e3ec3a3dSSoren Brinkmann  * Authors: Xiaobo Xie <X.Xie@freescale.com>
15e3ec3a3dSSoren Brinkmann  *	    Anton Vorontsov <avorontsov@ru.mvista.com>
16e3ec3a3dSSoren Brinkmann  */
17e3ec3a3dSSoren Brinkmann 
18c390f211SDouglas Anderson #include <linux/clk-provider.h>
193ea4666eSDouglas Anderson #include <linux/mfd/syscon.h>
20e3ec3a3dSSoren Brinkmann #include <linux/module.h>
21c62da8a8SRob Herring #include <linux/of.h>
22c62da8a8SRob Herring #include <linux/platform_device.h>
2391aa3661SShawn Lin #include <linux/phy/phy.h>
243ea4666eSDouglas Anderson #include <linux/regmap.h>
250614b0aeSSai Krishna Potthuri #include <linux/reset.h>
26a5c8b2aeSManish Narani #include <linux/firmware/xlnx-zynqmp.h>
27e3ec3a3dSSoren Brinkmann 
2884362d79SShawn Lin #include "cqhci.h"
295d249ac3SBrian Norris #include "sdhci-cqhci.h"
3084362d79SShawn Lin #include "sdhci-pltfm.h"
31e3ec3a3dSSoren Brinkmann 
3284362d79SShawn Lin #define SDHCI_ARASAN_VENDOR_REGISTER	0x78
331a470721SManish Narani 
341a470721SManish Narani #define SDHCI_ARASAN_ITAPDLY_REGISTER	0xF0F8
35d338c6d0SManish Narani #define SDHCI_ARASAN_ITAPDLY_SEL_MASK	0xFF
36d338c6d0SManish Narani 
371a470721SManish Narani #define SDHCI_ARASAN_OTAPDLY_REGISTER	0xF0FC
38d338c6d0SManish Narani #define SDHCI_ARASAN_OTAPDLY_SEL_MASK	0x3F
391a470721SManish Narani 
4084362d79SShawn Lin #define SDHCI_ARASAN_CQE_BASE_ADDR	0x200
41a05c8465SShawn Lin #define VENDOR_ENHANCED_STROBE		BIT(0)
42e3ec3a3dSSoren Brinkmann 
43b2db9c67SDouglas Anderson #define PHY_CLK_TOO_SLOW_HZ		400000
44b095f4f5SSwati Agarwal #define MIN_PHY_CLK_HZ			50000000
45b2db9c67SDouglas Anderson 
461a470721SManish Narani #define SDHCI_ITAPDLY_CHGWIN		0x200
471a470721SManish Narani #define SDHCI_ITAPDLY_ENABLE		0x100
481a470721SManish Narani #define SDHCI_OTAPDLY_ENABLE		0x40
491a470721SManish Narani 
50b095f4f5SSwati Agarwal #define PHY_CTRL_REG1			0x270
51b095f4f5SSwati Agarwal #define PHY_CTRL_ITAPDLY_ENA_MASK	BIT(0)
52b095f4f5SSwati Agarwal #define PHY_CTRL_ITAPDLY_SEL_MASK	GENMASK(5, 1)
53b095f4f5SSwati Agarwal #define PHY_CTRL_ITAPDLY_SEL_SHIFT	1
54b095f4f5SSwati Agarwal #define PHY_CTRL_ITAP_CHG_WIN_MASK	BIT(6)
55b095f4f5SSwati Agarwal #define PHY_CTRL_OTAPDLY_ENA_MASK	BIT(8)
56b095f4f5SSwati Agarwal #define PHY_CTRL_OTAPDLY_SEL_MASK	GENMASK(15, 12)
57b095f4f5SSwati Agarwal #define PHY_CTRL_OTAPDLY_SEL_SHIFT	12
58b095f4f5SSwati Agarwal #define PHY_CTRL_STRB_SEL_MASK		GENMASK(23, 16)
59b095f4f5SSwati Agarwal #define PHY_CTRL_STRB_SEL_SHIFT		16
60b095f4f5SSwati Agarwal #define PHY_CTRL_TEST_CTRL_MASK		GENMASK(31, 24)
61b095f4f5SSwati Agarwal 
62b095f4f5SSwati Agarwal #define PHY_CTRL_REG2			0x274
63b095f4f5SSwati Agarwal #define PHY_CTRL_EN_DLL_MASK		BIT(0)
64b095f4f5SSwati Agarwal #define PHY_CTRL_DLL_RDY_MASK		BIT(1)
65b095f4f5SSwati Agarwal #define PHY_CTRL_FREQ_SEL_MASK		GENMASK(6, 4)
66b095f4f5SSwati Agarwal #define PHY_CTRL_FREQ_SEL_SHIFT		4
67b095f4f5SSwati Agarwal #define PHY_CTRL_SEL_DLY_TX_MASK	BIT(16)
68b095f4f5SSwati Agarwal #define PHY_CTRL_SEL_DLY_RX_MASK	BIT(17)
69b095f4f5SSwati Agarwal #define FREQSEL_200M_170M		0x0
70b095f4f5SSwati Agarwal #define FREQSEL_170M_140M	        0x1
71b095f4f5SSwati Agarwal #define FREQSEL_140M_110M	        0x2
72b095f4f5SSwati Agarwal #define FREQSEL_110M_80M	        0x3
73b095f4f5SSwati Agarwal #define FREQSEL_80M_50M			0x4
74b095f4f5SSwati Agarwal #define FREQSEL_275M_250M		0x5
75b095f4f5SSwati Agarwal #define FREQSEL_250M_225M		0x6
76b095f4f5SSwati Agarwal #define FREQSEL_225M_200M		0x7
77b095f4f5SSwati Agarwal #define PHY_DLL_TIMEOUT_MS		100
78b095f4f5SSwati Agarwal 
79a5c8b2aeSManish Narani /* Default settings for ZynqMP Clock Phases */
80a5c8b2aeSManish Narani #define ZYNQMP_ICLK_PHASE {0, 63, 63, 0, 63,  0,   0, 183, 54,  0, 0}
81a5c8b2aeSManish Narani #define ZYNQMP_OCLK_PHASE {0, 72, 60, 0, 60, 72, 135, 48, 72, 135, 0}
82a5c8b2aeSManish Narani 
831a470721SManish Narani #define VERSAL_ICLK_PHASE {0, 132, 132, 0, 132, 0, 0, 162, 90, 0, 0}
841a470721SManish Narani #define VERSAL_OCLK_PHASE {0,  60, 48, 0, 48, 72, 90, 36, 60, 90, 0}
851a470721SManish Narani 
86b095f4f5SSwati Agarwal #define VERSAL_NET_EMMC_ICLK_PHASE {0, 0, 0, 0, 0, 0, 0, 0, 39, 0, 0}
87b095f4f5SSwati Agarwal #define VERSAL_NET_EMMC_OCLK_PHASE {0, 113, 0, 0, 0, 0, 0, 0, 113, 79, 45}
88b095f4f5SSwati Agarwal 
89b095f4f5SSwati Agarwal #define VERSAL_NET_PHY_CTRL_STRB90_STRB180_VAL		0X77
90b095f4f5SSwati Agarwal 
913ea4666eSDouglas Anderson /*
923ea4666eSDouglas Anderson  * On some SoCs the syscon area has a feature where the upper 16-bits of
933ea4666eSDouglas Anderson  * each 32-bit register act as a write mask for the lower 16-bits.  This allows
943ea4666eSDouglas Anderson  * atomic updates of the register without locking.  This macro is used on SoCs
953ea4666eSDouglas Anderson  * that have that feature.
963ea4666eSDouglas Anderson  */
973ea4666eSDouglas Anderson #define HIWORD_UPDATE(val, mask, shift) \
983ea4666eSDouglas Anderson 		((val) << (shift) | (mask) << ((shift) + 16))
993ea4666eSDouglas Anderson 
1003ea4666eSDouglas Anderson /**
1013ea4666eSDouglas Anderson  * struct sdhci_arasan_soc_ctl_field - Field used in sdhci_arasan_soc_ctl_map
1023ea4666eSDouglas Anderson  *
1033ea4666eSDouglas Anderson  * @reg:	Offset within the syscon of the register containing this field
1043ea4666eSDouglas Anderson  * @width:	Number of bits for this field
1053ea4666eSDouglas Anderson  * @shift:	Bit offset within @reg of this field (or -1 if not avail)
1063ea4666eSDouglas Anderson  */
1073ea4666eSDouglas Anderson struct sdhci_arasan_soc_ctl_field {
1083ea4666eSDouglas Anderson 	u32 reg;
1093ea4666eSDouglas Anderson 	u16 width;
1103ea4666eSDouglas Anderson 	s16 shift;
1113ea4666eSDouglas Anderson };
1123ea4666eSDouglas Anderson 
1133ea4666eSDouglas Anderson /**
1143ea4666eSDouglas Anderson  * struct sdhci_arasan_soc_ctl_map - Map in syscon to corecfg registers
1153ea4666eSDouglas Anderson  *
1163ea4666eSDouglas Anderson  * @baseclkfreq:	Where to find corecfg_baseclkfreq
117b2ca77c9SShawn Lin  * @clockmultiplier:	Where to find corecfg_clockmultiplier
11836c6aadaSWan Ahmad Zainie  * @support64b:		Where to find SUPPORT64B bit
1193ea4666eSDouglas Anderson  * @hiword_update:	If true, use HIWORD_UPDATE to access the syscon
1204908460eSManish Narani  *
1214908460eSManish Narani  * It's up to the licensee of the Arsan IP block to make these available
1224908460eSManish Narani  * somewhere if needed.  Presumably these will be scattered somewhere that's
1234908460eSManish Narani  * accessible via the syscon API.
1243ea4666eSDouglas Anderson  */
1253ea4666eSDouglas Anderson struct sdhci_arasan_soc_ctl_map {
1263ea4666eSDouglas Anderson 	struct sdhci_arasan_soc_ctl_field	baseclkfreq;
127b2ca77c9SShawn Lin 	struct sdhci_arasan_soc_ctl_field	clockmultiplier;
12836c6aadaSWan Ahmad Zainie 	struct sdhci_arasan_soc_ctl_field	support64b;
1293ea4666eSDouglas Anderson 	bool					hiword_update;
1303ea4666eSDouglas Anderson };
1313ea4666eSDouglas Anderson 
132e3ec3a3dSSoren Brinkmann /**
13316ada730SManish Narani  * struct sdhci_arasan_clk_ops - Clock Operations for Arasan SD controller
13416ada730SManish Narani  *
13516ada730SManish Narani  * @sdcardclk_ops:	The output clock related operations
13616ada730SManish Narani  * @sampleclk_ops:	The sample clock related operations
13716ada730SManish Narani  */
13816ada730SManish Narani struct sdhci_arasan_clk_ops {
13916ada730SManish Narani 	const struct clk_ops *sdcardclk_ops;
14016ada730SManish Narani 	const struct clk_ops *sampleclk_ops;
14116ada730SManish Narani };
14216ada730SManish Narani 
14316ada730SManish Narani /**
1444908460eSManish Narani  * struct sdhci_arasan_clk_data - Arasan Controller Clock Data.
1454908460eSManish Narani  *
146e1463618SManish Narani  * @sdcardclk_hw:	Struct for the clock we might provide to a PHY.
147e1463618SManish Narani  * @sdcardclk:		Pointer to normal 'struct clock' for sdcardclk_hw.
14807a14d1dSManish Narani  * @sampleclk_hw:	Struct for the clock we might provide to a PHY.
14907a14d1dSManish Narani  * @sampleclk:		Pointer to normal 'struct clock' for sampleclk_hw.
150f3dafc37SManish Narani  * @clk_phase_in:	Array of Input Clock Phase Delays for all speed modes
151f3dafc37SManish Narani  * @clk_phase_out:	Array of Output Clock Phase Delays for all speed modes
152f3dafc37SManish Narani  * @set_clk_delays:	Function pointer for setting Clock Delays
153a5c8b2aeSManish Narani  * @clk_of_data:	Platform specific runtime clock data storage pointer
154e1463618SManish Narani  */
155e1463618SManish Narani struct sdhci_arasan_clk_data {
156e1463618SManish Narani 	struct clk_hw	sdcardclk_hw;
157e1463618SManish Narani 	struct clk      *sdcardclk;
15807a14d1dSManish Narani 	struct clk_hw	sampleclk_hw;
15907a14d1dSManish Narani 	struct clk      *sampleclk;
160f3dafc37SManish Narani 	int		clk_phase_in[MMC_TIMING_MMC_HS400 + 1];
161f3dafc37SManish Narani 	int		clk_phase_out[MMC_TIMING_MMC_HS400 + 1];
162f3dafc37SManish Narani 	void		(*set_clk_delays)(struct sdhci_host *host);
163a5c8b2aeSManish Narani 	void		*clk_of_data;
164a5c8b2aeSManish Narani };
165a5c8b2aeSManish Narani 
166e1463618SManish Narani /**
1674908460eSManish Narani  * struct sdhci_arasan_data - Arasan Controller Data
1684908460eSManish Narani  *
169c390f211SDouglas Anderson  * @host:		Pointer to the main SDHCI host structure.
170e3ec3a3dSSoren Brinkmann  * @clk_ahb:		Pointer to the AHB clock
17191aa3661SShawn Lin  * @phy:		Pointer to the generic phy
172b2db9c67SDouglas Anderson  * @is_phy_on:		True if the PHY is on; false if not.
173b095f4f5SSwati Agarwal  * @internal_phy_reg:	True if the PHY is within the Host controller.
1744908460eSManish Narani  * @has_cqe:		True if controller has command queuing engine.
175e1463618SManish Narani  * @clk_data:		Struct for the Arasan Controller Clock Data.
17616ada730SManish Narani  * @clk_ops:		Struct for the Arasan Controller Clock Operations.
1773ea4666eSDouglas Anderson  * @soc_ctl_base:	Pointer to regmap for syscon for soc_ctl registers.
1783ea4666eSDouglas Anderson  * @soc_ctl_map:	Map to get offsets into soc_ctl registers.
1794908460eSManish Narani  * @quirks:		Arasan deviations from spec.
180e3ec3a3dSSoren Brinkmann  */
181e3ec3a3dSSoren Brinkmann struct sdhci_arasan_data {
182c390f211SDouglas Anderson 	struct sdhci_host *host;
183e3ec3a3dSSoren Brinkmann 	struct clk	*clk_ahb;
18491aa3661SShawn Lin 	struct phy	*phy;
185b2db9c67SDouglas Anderson 	bool		is_phy_on;
186b095f4f5SSwati Agarwal 	bool		internal_phy_reg;
1873ea4666eSDouglas Anderson 
18884362d79SShawn Lin 	bool		has_cqe;
189e1463618SManish Narani 	struct sdhci_arasan_clk_data clk_data;
19016ada730SManish Narani 	const struct sdhci_arasan_clk_ops *clk_ops;
191c390f211SDouglas Anderson 
1923ea4666eSDouglas Anderson 	struct regmap	*soc_ctl_base;
1933ea4666eSDouglas Anderson 	const struct sdhci_arasan_soc_ctl_map *soc_ctl_map;
1944908460eSManish Narani 	unsigned int	quirks;
1953794c542SZach Brown 
1963794c542SZach Brown /* Controller does not have CD wired and will not function normally without */
1973794c542SZach Brown #define SDHCI_ARASAN_QUIRK_FORCE_CDTEST	BIT(0)
1983f2c7d5dSHelmut Grohne /* Controller immediately reports SDHCI_CLOCK_INT_STABLE after enabling the
1993f2c7d5dSHelmut Grohne  * internal clock even when the clock isn't stable */
2003f2c7d5dSHelmut Grohne #define SDHCI_ARASAN_QUIRK_CLOCK_UNSTABLE BIT(1)
201c0b4e411SManish Narani /*
202c0b4e411SManish Narani  * Some of the Arasan variations might not have timing requirements
203c0b4e411SManish Narani  * met at 25MHz for Default Speed mode, those controllers work at
204c0b4e411SManish Narani  * 19MHz instead
205c0b4e411SManish Narani  */
206c0b4e411SManish Narani #define SDHCI_ARASAN_QUIRK_CLOCK_25_BROKEN BIT(2)
207e3ec3a3dSSoren Brinkmann };
208e3ec3a3dSSoren Brinkmann 
20906b23ca0SFaiz Abbas struct sdhci_arasan_of_data {
21006b23ca0SFaiz Abbas 	const struct sdhci_arasan_soc_ctl_map *soc_ctl_map;
21106b23ca0SFaiz Abbas 	const struct sdhci_pltfm_data *pdata;
21216ada730SManish Narani 	const struct sdhci_arasan_clk_ops *clk_ops;
21306b23ca0SFaiz Abbas };
21406b23ca0SFaiz Abbas 
2153ea4666eSDouglas Anderson static const struct sdhci_arasan_soc_ctl_map rk3399_soc_ctl_map = {
2163ea4666eSDouglas Anderson 	.baseclkfreq = { .reg = 0xf000, .width = 8, .shift = 8 },
217b2ca77c9SShawn Lin 	.clockmultiplier = { .reg = 0xf02c, .width = 8, .shift = 0},
2183ea4666eSDouglas Anderson 	.hiword_update = true,
2193ea4666eSDouglas Anderson };
2203ea4666eSDouglas Anderson 
2215c1a4f40SRamuthevar Vadivel Muruganx static const struct sdhci_arasan_soc_ctl_map intel_lgm_emmc_soc_ctl_map = {
2225c1a4f40SRamuthevar Vadivel Muruganx 	.baseclkfreq = { .reg = 0xa0, .width = 8, .shift = 2 },
2235c1a4f40SRamuthevar Vadivel Muruganx 	.clockmultiplier = { .reg = 0, .width = -1, .shift = -1 },
2245c1a4f40SRamuthevar Vadivel Muruganx 	.hiword_update = false,
2255c1a4f40SRamuthevar Vadivel Muruganx };
2265c1a4f40SRamuthevar Vadivel Muruganx 
227d1807ad6SRamuthevar Vadivel Murugan static const struct sdhci_arasan_soc_ctl_map intel_lgm_sdxc_soc_ctl_map = {
228d1807ad6SRamuthevar Vadivel Murugan 	.baseclkfreq = { .reg = 0x80, .width = 8, .shift = 2 },
229d1807ad6SRamuthevar Vadivel Murugan 	.clockmultiplier = { .reg = 0, .width = -1, .shift = -1 },
230d1807ad6SRamuthevar Vadivel Murugan 	.hiword_update = false,
231d1807ad6SRamuthevar Vadivel Murugan };
232d1807ad6SRamuthevar Vadivel Murugan 
23336c6aadaSWan Ahmad Zainie static const struct sdhci_arasan_soc_ctl_map intel_keembay_soc_ctl_map = {
23436c6aadaSWan Ahmad Zainie 	.baseclkfreq = { .reg = 0x0, .width = 8, .shift = 14 },
23536c6aadaSWan Ahmad Zainie 	.clockmultiplier = { .reg = 0x4, .width = 8, .shift = 14 },
23636c6aadaSWan Ahmad Zainie 	.support64b = { .reg = 0x4, .width = 1, .shift = 24 },
23736c6aadaSWan Ahmad Zainie 	.hiword_update = false,
23836c6aadaSWan Ahmad Zainie };
23936c6aadaSWan Ahmad Zainie 
sdhci_arasan_phy_set_delaychain(struct sdhci_host * host,bool enable)240b095f4f5SSwati Agarwal static void sdhci_arasan_phy_set_delaychain(struct sdhci_host *host, bool enable)
241b095f4f5SSwati Agarwal {
242b095f4f5SSwati Agarwal 	u32 reg;
243b095f4f5SSwati Agarwal 
244b095f4f5SSwati Agarwal 	reg = readl(host->ioaddr + PHY_CTRL_REG2);
245b095f4f5SSwati Agarwal 	if (enable)
246b095f4f5SSwati Agarwal 		reg |= (PHY_CTRL_SEL_DLY_TX_MASK | PHY_CTRL_SEL_DLY_RX_MASK);
247b095f4f5SSwati Agarwal 	else
248b095f4f5SSwati Agarwal 		reg &= ~(PHY_CTRL_SEL_DLY_TX_MASK | PHY_CTRL_SEL_DLY_RX_MASK);
249b095f4f5SSwati Agarwal 
250b095f4f5SSwati Agarwal 	writel(reg, host->ioaddr + PHY_CTRL_REG2);
251b095f4f5SSwati Agarwal }
252b095f4f5SSwati Agarwal 
sdhci_arasan_phy_set_dll(struct sdhci_host * host,bool enable)253b095f4f5SSwati Agarwal static int sdhci_arasan_phy_set_dll(struct sdhci_host *host, bool enable)
254b095f4f5SSwati Agarwal {
255b095f4f5SSwati Agarwal 	u32 reg;
256b095f4f5SSwati Agarwal 
257b095f4f5SSwati Agarwal 	reg = readl(host->ioaddr + PHY_CTRL_REG2);
258b095f4f5SSwati Agarwal 	if (enable)
259b095f4f5SSwati Agarwal 		reg |= PHY_CTRL_EN_DLL_MASK;
260b095f4f5SSwati Agarwal 	else
261b095f4f5SSwati Agarwal 		reg &= ~PHY_CTRL_EN_DLL_MASK;
262b095f4f5SSwati Agarwal 
263b095f4f5SSwati Agarwal 	writel(reg, host->ioaddr + PHY_CTRL_REG2);
264b095f4f5SSwati Agarwal 
265b095f4f5SSwati Agarwal 	if (!enable)
266b095f4f5SSwati Agarwal 		return 0;
267b095f4f5SSwati Agarwal 
268b095f4f5SSwati Agarwal 	return readl_relaxed_poll_timeout(host->ioaddr + PHY_CTRL_REG2, reg,
269b095f4f5SSwati Agarwal 					  (reg & PHY_CTRL_DLL_RDY_MASK), 10,
270b095f4f5SSwati Agarwal 					  1000 * PHY_DLL_TIMEOUT_MS);
271b095f4f5SSwati Agarwal }
272b095f4f5SSwati Agarwal 
sdhci_arasan_phy_dll_set_freq(struct sdhci_host * host,int clock)273b095f4f5SSwati Agarwal static void sdhci_arasan_phy_dll_set_freq(struct sdhci_host *host, int clock)
274b095f4f5SSwati Agarwal {
275b095f4f5SSwati Agarwal 	u32 reg, freq_sel, freq;
276b095f4f5SSwati Agarwal 
277b095f4f5SSwati Agarwal 	freq = DIV_ROUND_CLOSEST(clock, 1000000);
278b095f4f5SSwati Agarwal 	if (freq <= 200 && freq > 170)
279b095f4f5SSwati Agarwal 		freq_sel = FREQSEL_200M_170M;
280b095f4f5SSwati Agarwal 	else if (freq <= 170 && freq > 140)
281b095f4f5SSwati Agarwal 		freq_sel = FREQSEL_170M_140M;
282b095f4f5SSwati Agarwal 	else if (freq <= 140 && freq > 110)
283b095f4f5SSwati Agarwal 		freq_sel = FREQSEL_140M_110M;
284b095f4f5SSwati Agarwal 	else if (freq <= 110 && freq > 80)
285b095f4f5SSwati Agarwal 		freq_sel = FREQSEL_110M_80M;
286b095f4f5SSwati Agarwal 	else
287b095f4f5SSwati Agarwal 		freq_sel = FREQSEL_80M_50M;
288b095f4f5SSwati Agarwal 
289b095f4f5SSwati Agarwal 	reg = readl(host->ioaddr + PHY_CTRL_REG2);
290b095f4f5SSwati Agarwal 	reg &= ~PHY_CTRL_FREQ_SEL_MASK;
291b095f4f5SSwati Agarwal 	reg |= (freq_sel << PHY_CTRL_FREQ_SEL_SHIFT);
292b095f4f5SSwati Agarwal 	writel(reg, host->ioaddr + PHY_CTRL_REG2);
293b095f4f5SSwati Agarwal }
294b095f4f5SSwati Agarwal 
2953ea4666eSDouglas Anderson /**
2963ea4666eSDouglas Anderson  * sdhci_arasan_syscon_write - Write to a field in soc_ctl registers
2973ea4666eSDouglas Anderson  *
2984908460eSManish Narani  * @host:	The sdhci_host
2994908460eSManish Narani  * @fld:	The field to write to
3004908460eSManish Narani  * @val:	The value to write
3014908460eSManish Narani  *
3023ea4666eSDouglas Anderson  * This function allows writing to fields in sdhci_arasan_soc_ctl_map.
3033ea4666eSDouglas Anderson  * Note that if a field is specified as not available (shift < 0) then
3043ea4666eSDouglas Anderson  * this function will silently return an error code.  It will be noisy
3053ea4666eSDouglas Anderson  * and print errors for any other (unexpected) errors.
3063ea4666eSDouglas Anderson  *
3074908460eSManish Narani  * Return: 0 on success and error value on error
3083ea4666eSDouglas Anderson  */
sdhci_arasan_syscon_write(struct sdhci_host * host,const struct sdhci_arasan_soc_ctl_field * fld,u32 val)3093ea4666eSDouglas Anderson static int sdhci_arasan_syscon_write(struct sdhci_host *host,
3103ea4666eSDouglas Anderson 				   const struct sdhci_arasan_soc_ctl_field *fld,
3113ea4666eSDouglas Anderson 				   u32 val)
3123ea4666eSDouglas Anderson {
3133ea4666eSDouglas Anderson 	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
3143ea4666eSDouglas Anderson 	struct sdhci_arasan_data *sdhci_arasan = sdhci_pltfm_priv(pltfm_host);
3153ea4666eSDouglas Anderson 	struct regmap *soc_ctl_base = sdhci_arasan->soc_ctl_base;
3163ea4666eSDouglas Anderson 	u32 reg = fld->reg;
3173ea4666eSDouglas Anderson 	u16 width = fld->width;
3183ea4666eSDouglas Anderson 	s16 shift = fld->shift;
3193ea4666eSDouglas Anderson 	int ret;
3203ea4666eSDouglas Anderson 
3213ea4666eSDouglas Anderson 	/*
3223ea4666eSDouglas Anderson 	 * Silently return errors for shift < 0 so caller doesn't have
3233ea4666eSDouglas Anderson 	 * to check for fields which are optional.  For fields that
3243ea4666eSDouglas Anderson 	 * are required then caller needs to do something special
3253ea4666eSDouglas Anderson 	 * anyway.
3263ea4666eSDouglas Anderson 	 */
3273ea4666eSDouglas Anderson 	if (shift < 0)
3283ea4666eSDouglas Anderson 		return -EINVAL;
3293ea4666eSDouglas Anderson 
3303ea4666eSDouglas Anderson 	if (sdhci_arasan->soc_ctl_map->hiword_update)
3313ea4666eSDouglas Anderson 		ret = regmap_write(soc_ctl_base, reg,
3323ea4666eSDouglas Anderson 				   HIWORD_UPDATE(val, GENMASK(width, 0),
3333ea4666eSDouglas Anderson 						 shift));
3343ea4666eSDouglas Anderson 	else
3353ea4666eSDouglas Anderson 		ret = regmap_update_bits(soc_ctl_base, reg,
3363ea4666eSDouglas Anderson 					 GENMASK(shift + width, shift),
3373ea4666eSDouglas Anderson 					 val << shift);
3383ea4666eSDouglas Anderson 
3393ea4666eSDouglas Anderson 	/* Yell about (unexpected) regmap errors */
3403ea4666eSDouglas Anderson 	if (ret)
3413ea4666eSDouglas Anderson 		pr_warn("%s: Regmap write fail: %d\n",
3423ea4666eSDouglas Anderson 			 mmc_hostname(host->mmc), ret);
3433ea4666eSDouglas Anderson 
3443ea4666eSDouglas Anderson 	return ret;
3453ea4666eSDouglas Anderson }
3463ea4666eSDouglas Anderson 
sdhci_arasan_set_clock(struct sdhci_host * host,unsigned int clock)347802ac39aSShawn Lin static void sdhci_arasan_set_clock(struct sdhci_host *host, unsigned int clock)
348802ac39aSShawn Lin {
349802ac39aSShawn Lin 	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
350802ac39aSShawn Lin 	struct sdhci_arasan_data *sdhci_arasan = sdhci_pltfm_priv(pltfm_host);
351f3dafc37SManish Narani 	struct sdhci_arasan_clk_data *clk_data = &sdhci_arasan->clk_data;
3526fc09244SDouglas Anderson 	bool ctrl_phy = false;
353802ac39aSShawn Lin 
354b2db9c67SDouglas Anderson 	if (!IS_ERR(sdhci_arasan->phy)) {
355b2db9c67SDouglas Anderson 		if (!sdhci_arasan->is_phy_on && clock <= PHY_CLK_TOO_SLOW_HZ) {
356b2db9c67SDouglas Anderson 			/*
357b2db9c67SDouglas Anderson 			 * If PHY off, set clock to max speed and power PHY on.
358b2db9c67SDouglas Anderson 			 *
359b2db9c67SDouglas Anderson 			 * Although PHY docs apparently suggest power cycling
360b2db9c67SDouglas Anderson 			 * when changing the clock the PHY doesn't like to be
361b2db9c67SDouglas Anderson 			 * powered on while at low speeds like those used in ID
362b2db9c67SDouglas Anderson 			 * mode.  Even worse is powering the PHY on while the
363b2db9c67SDouglas Anderson 			 * clock is off.
364b2db9c67SDouglas Anderson 			 *
365b2db9c67SDouglas Anderson 			 * To workaround the PHY limitations, the best we can
366b2db9c67SDouglas Anderson 			 * do is to power it on at a faster speed and then slam
367b2db9c67SDouglas Anderson 			 * through low speeds without power cycling.
368b2db9c67SDouglas Anderson 			 */
369b2db9c67SDouglas Anderson 			sdhci_set_clock(host, host->max_clk);
37066bad6edSManish Narani 			if (phy_power_on(sdhci_arasan->phy)) {
37166bad6edSManish Narani 				pr_err("%s: Cannot power on phy.\n",
37266bad6edSManish Narani 				       mmc_hostname(host->mmc));
37366bad6edSManish Narani 				return;
37466bad6edSManish Narani 			}
37566bad6edSManish Narani 
376b2db9c67SDouglas Anderson 			sdhci_arasan->is_phy_on = true;
377802ac39aSShawn Lin 
378b2db9c67SDouglas Anderson 			/*
379b2db9c67SDouglas Anderson 			 * We'll now fall through to the below case with
380b2db9c67SDouglas Anderson 			 * ctrl_phy = false (so we won't turn off/on).  The
381b2db9c67SDouglas Anderson 			 * sdhci_set_clock() will set the real clock.
382b2db9c67SDouglas Anderson 			 */
383b2db9c67SDouglas Anderson 		} else if (clock > PHY_CLK_TOO_SLOW_HZ) {
384b2db9c67SDouglas Anderson 			/*
385b2db9c67SDouglas Anderson 			 * At higher clock speeds the PHY is fine being power
386b2db9c67SDouglas Anderson 			 * cycled and docs say you _should_ power cycle when
387b2db9c67SDouglas Anderson 			 * changing clock speeds.
388b2db9c67SDouglas Anderson 			 */
389b2db9c67SDouglas Anderson 			ctrl_phy = true;
390b2db9c67SDouglas Anderson 		}
391b2db9c67SDouglas Anderson 	}
392b2db9c67SDouglas Anderson 
393b2db9c67SDouglas Anderson 	if (ctrl_phy && sdhci_arasan->is_phy_on) {
394802ac39aSShawn Lin 		phy_power_off(sdhci_arasan->phy);
395b2db9c67SDouglas Anderson 		sdhci_arasan->is_phy_on = false;
396802ac39aSShawn Lin 	}
397802ac39aSShawn Lin 
398c0b4e411SManish Narani 	if (sdhci_arasan->quirks & SDHCI_ARASAN_QUIRK_CLOCK_25_BROKEN) {
399c0b4e411SManish Narani 		/*
400c0b4e411SManish Narani 		 * Some of the Arasan variations might not have timing
401c0b4e411SManish Narani 		 * requirements met at 25MHz for Default Speed mode,
402c0b4e411SManish Narani 		 * those controllers work at 19MHz instead.
403c0b4e411SManish Narani 		 */
404c0b4e411SManish Narani 		if (clock == DEFAULT_SPEED_MAX_DTR)
405c0b4e411SManish Narani 			clock = (DEFAULT_SPEED_MAX_DTR * 19) / 25;
406c0b4e411SManish Narani 	}
407c0b4e411SManish Narani 
408f3dafc37SManish Narani 	/* Set the Input and Output Clock Phase Delays */
4099fab9389SSai Krishna Potthuri 	if (clk_data->set_clk_delays && clock > PHY_CLK_TOO_SLOW_HZ)
410f3dafc37SManish Narani 		clk_data->set_clk_delays(host);
411f3dafc37SManish Narani 
412b095f4f5SSwati Agarwal 	if (sdhci_arasan->internal_phy_reg && clock >= MIN_PHY_CLK_HZ) {
413b095f4f5SSwati Agarwal 		sdhci_writew(host, 0, SDHCI_CLOCK_CONTROL);
414b095f4f5SSwati Agarwal 		sdhci_arasan_phy_set_dll(host, 0);
415b095f4f5SSwati Agarwal 		sdhci_arasan_phy_set_delaychain(host, 0);
416b095f4f5SSwati Agarwal 		sdhci_arasan_phy_dll_set_freq(host, clock);
417b095f4f5SSwati Agarwal 	} else if (sdhci_arasan->internal_phy_reg) {
418b095f4f5SSwati Agarwal 		sdhci_writew(host, 0, SDHCI_CLOCK_CONTROL);
419b095f4f5SSwati Agarwal 		sdhci_arasan_phy_set_delaychain(host, 1);
420b095f4f5SSwati Agarwal 	}
421b095f4f5SSwati Agarwal 
422802ac39aSShawn Lin 	sdhci_set_clock(host, clock);
423802ac39aSShawn Lin 
424b095f4f5SSwati Agarwal 	if (sdhci_arasan->internal_phy_reg && clock >= MIN_PHY_CLK_HZ)
425b095f4f5SSwati Agarwal 		sdhci_arasan_phy_set_dll(host, 1);
426b095f4f5SSwati Agarwal 
4273f2c7d5dSHelmut Grohne 	if (sdhci_arasan->quirks & SDHCI_ARASAN_QUIRK_CLOCK_UNSTABLE)
4283f2c7d5dSHelmut Grohne 		/*
4293f2c7d5dSHelmut Grohne 		 * Some controllers immediately report SDHCI_CLOCK_INT_STABLE
4303f2c7d5dSHelmut Grohne 		 * after enabling the clock even though the clock is not
4313f2c7d5dSHelmut Grohne 		 * stable. Trying to use a clock without waiting here results
4323f2c7d5dSHelmut Grohne 		 * in EILSEQ while detecting some older/slower cards. The
4333f2c7d5dSHelmut Grohne 		 * chosen delay is the maximum delay from sdhci_set_clock.
4343f2c7d5dSHelmut Grohne 		 */
4353f2c7d5dSHelmut Grohne 		msleep(20);
4363f2c7d5dSHelmut Grohne 
4376fc09244SDouglas Anderson 	if (ctrl_phy) {
43866bad6edSManish Narani 		if (phy_power_on(sdhci_arasan->phy)) {
43966bad6edSManish Narani 			pr_err("%s: Cannot power on phy.\n",
44066bad6edSManish Narani 			       mmc_hostname(host->mmc));
44166bad6edSManish Narani 			return;
44266bad6edSManish Narani 		}
44366bad6edSManish Narani 
444b2db9c67SDouglas Anderson 		sdhci_arasan->is_phy_on = true;
445802ac39aSShawn Lin 	}
446802ac39aSShawn Lin }
447802ac39aSShawn Lin 
sdhci_arasan_hs400_enhanced_strobe(struct mmc_host * mmc,struct mmc_ios * ios)448a05c8465SShawn Lin static void sdhci_arasan_hs400_enhanced_strobe(struct mmc_host *mmc,
449a05c8465SShawn Lin 					struct mmc_ios *ios)
450a05c8465SShawn Lin {
451a05c8465SShawn Lin 	u32 vendor;
452a05c8465SShawn Lin 	struct sdhci_host *host = mmc_priv(mmc);
453a05c8465SShawn Lin 
4540daf72feSJean-Francois Dagenais 	vendor = sdhci_readl(host, SDHCI_ARASAN_VENDOR_REGISTER);
455a05c8465SShawn Lin 	if (ios->enhanced_strobe)
456a05c8465SShawn Lin 		vendor |= VENDOR_ENHANCED_STROBE;
457a05c8465SShawn Lin 	else
458a05c8465SShawn Lin 		vendor &= ~VENDOR_ENHANCED_STROBE;
459a05c8465SShawn Lin 
4600daf72feSJean-Francois Dagenais 	sdhci_writel(host, vendor, SDHCI_ARASAN_VENDOR_REGISTER);
461a05c8465SShawn Lin }
462a05c8465SShawn Lin 
sdhci_arasan_reset(struct sdhci_host * host,u8 mask)46313d62fd2SWei Yongjun static void sdhci_arasan_reset(struct sdhci_host *host, u8 mask)
4643794c542SZach Brown {
4653794c542SZach Brown 	u8 ctrl;
4663794c542SZach Brown 	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
4673794c542SZach Brown 	struct sdhci_arasan_data *sdhci_arasan = sdhci_pltfm_priv(pltfm_host);
4683794c542SZach Brown 
4695d249ac3SBrian Norris 	sdhci_and_cqhci_reset(host, mask);
4703794c542SZach Brown 
4713794c542SZach Brown 	if (sdhci_arasan->quirks & SDHCI_ARASAN_QUIRK_FORCE_CDTEST) {
4723794c542SZach Brown 		ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL);
4733794c542SZach Brown 		ctrl |= SDHCI_CTRL_CDTEST_INS | SDHCI_CTRL_CDTEST_EN;
4743794c542SZach Brown 		sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
4753794c542SZach Brown 	}
4763794c542SZach Brown }
4773794c542SZach Brown 
sdhci_arasan_voltage_switch(struct mmc_host * mmc,struct mmc_ios * ios)4788a3bee9bSShawn Lin static int sdhci_arasan_voltage_switch(struct mmc_host *mmc,
4798a3bee9bSShawn Lin 				       struct mmc_ios *ios)
4808a3bee9bSShawn Lin {
4818a3bee9bSShawn Lin 	switch (ios->signal_voltage) {
4828a3bee9bSShawn Lin 	case MMC_SIGNAL_VOLTAGE_180:
4838a3bee9bSShawn Lin 		/*
4848a3bee9bSShawn Lin 		 * Plese don't switch to 1V8 as arasan,5.1 doesn't
4858a3bee9bSShawn Lin 		 * actually refer to this setting to indicate the
4868a3bee9bSShawn Lin 		 * signal voltage and the state machine will be broken
4878a3bee9bSShawn Lin 		 * actually if we force to enable 1V8. That's something
4888a3bee9bSShawn Lin 		 * like broken quirk but we could work around here.
4898a3bee9bSShawn Lin 		 */
4908a3bee9bSShawn Lin 		return 0;
4918a3bee9bSShawn Lin 	case MMC_SIGNAL_VOLTAGE_330:
4928a3bee9bSShawn Lin 	case MMC_SIGNAL_VOLTAGE_120:
4938a3bee9bSShawn Lin 		/* We don't support 3V3 and 1V2 */
4948a3bee9bSShawn Lin 		break;
4958a3bee9bSShawn Lin 	}
4968a3bee9bSShawn Lin 
4978a3bee9bSShawn Lin 	return -EINVAL;
4988a3bee9bSShawn Lin }
4998a3bee9bSShawn Lin 
500a81dae3aSJulia Lawall static const struct sdhci_ops sdhci_arasan_ops = {
501802ac39aSShawn Lin 	.set_clock = sdhci_arasan_set_clock,
502e3ec3a3dSSoren Brinkmann 	.get_max_clock = sdhci_pltfm_clk_get_max_clock,
5038cc35289SShawn Lin 	.get_timeout_clock = sdhci_pltfm_clk_get_max_clock,
5042317f56cSRussell King 	.set_bus_width = sdhci_set_bus_width,
5053794c542SZach Brown 	.reset = sdhci_arasan_reset,
50696d7b78cSRussell King 	.set_uhs_signaling = sdhci_set_uhs_signaling,
507c2c5252cSNicolas Saenz Julienne 	.set_power = sdhci_set_power_and_bus_voltage,
508e3ec3a3dSSoren Brinkmann };
509e3ec3a3dSSoren Brinkmann 
sdhci_arasan_cqhci_irq(struct sdhci_host * host,u32 intmask)51084362d79SShawn Lin static u32 sdhci_arasan_cqhci_irq(struct sdhci_host *host, u32 intmask)
51184362d79SShawn Lin {
51284362d79SShawn Lin 	int cmd_error = 0;
51384362d79SShawn Lin 	int data_error = 0;
51484362d79SShawn Lin 
51584362d79SShawn Lin 	if (!sdhci_cqe_irq(host, intmask, &cmd_error, &data_error))
51684362d79SShawn Lin 		return intmask;
51784362d79SShawn Lin 
51884362d79SShawn Lin 	cqhci_irq(host->mmc, intmask, cmd_error, data_error);
51984362d79SShawn Lin 
52084362d79SShawn Lin 	return 0;
52184362d79SShawn Lin }
52284362d79SShawn Lin 
sdhci_arasan_dumpregs(struct mmc_host * mmc)52384362d79SShawn Lin static void sdhci_arasan_dumpregs(struct mmc_host *mmc)
52484362d79SShawn Lin {
52584362d79SShawn Lin 	sdhci_dumpregs(mmc_priv(mmc));
52684362d79SShawn Lin }
52784362d79SShawn Lin 
sdhci_arasan_cqe_enable(struct mmc_host * mmc)52884362d79SShawn Lin static void sdhci_arasan_cqe_enable(struct mmc_host *mmc)
52984362d79SShawn Lin {
53084362d79SShawn Lin 	struct sdhci_host *host = mmc_priv(mmc);
53184362d79SShawn Lin 	u32 reg;
53284362d79SShawn Lin 
53384362d79SShawn Lin 	reg = sdhci_readl(host, SDHCI_PRESENT_STATE);
53484362d79SShawn Lin 	while (reg & SDHCI_DATA_AVAILABLE) {
53584362d79SShawn Lin 		sdhci_readl(host, SDHCI_BUFFER);
53684362d79SShawn Lin 		reg = sdhci_readl(host, SDHCI_PRESENT_STATE);
53784362d79SShawn Lin 	}
53884362d79SShawn Lin 
53984362d79SShawn Lin 	sdhci_cqe_enable(mmc);
54084362d79SShawn Lin }
54184362d79SShawn Lin 
54284362d79SShawn Lin static const struct cqhci_host_ops sdhci_arasan_cqhci_ops = {
54384362d79SShawn Lin 	.enable         = sdhci_arasan_cqe_enable,
54484362d79SShawn Lin 	.disable        = sdhci_cqe_disable,
54584362d79SShawn Lin 	.dumpregs       = sdhci_arasan_dumpregs,
54684362d79SShawn Lin };
54784362d79SShawn Lin 
54884362d79SShawn Lin static const struct sdhci_ops sdhci_arasan_cqe_ops = {
54984362d79SShawn Lin 	.set_clock = sdhci_arasan_set_clock,
55084362d79SShawn Lin 	.get_max_clock = sdhci_pltfm_clk_get_max_clock,
55184362d79SShawn Lin 	.get_timeout_clock = sdhci_pltfm_clk_get_max_clock,
55284362d79SShawn Lin 	.set_bus_width = sdhci_set_bus_width,
55384362d79SShawn Lin 	.reset = sdhci_arasan_reset,
55484362d79SShawn Lin 	.set_uhs_signaling = sdhci_set_uhs_signaling,
555c2c5252cSNicolas Saenz Julienne 	.set_power = sdhci_set_power_and_bus_voltage,
55684362d79SShawn Lin 	.irq = sdhci_arasan_cqhci_irq,
55784362d79SShawn Lin };
55884362d79SShawn Lin 
55984362d79SShawn Lin static const struct sdhci_pltfm_data sdhci_arasan_cqe_pdata = {
56084362d79SShawn Lin 	.ops = &sdhci_arasan_cqe_ops,
56184362d79SShawn Lin 	.quirks = SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN,
56284362d79SShawn Lin 	.quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN |
56384362d79SShawn Lin 			SDHCI_QUIRK2_CLOCK_DIV_ZERO_BROKEN,
56484362d79SShawn Lin };
56584362d79SShawn Lin 
566e3ec3a3dSSoren Brinkmann #ifdef CONFIG_PM_SLEEP
567e3ec3a3dSSoren Brinkmann /**
568e3ec3a3dSSoren Brinkmann  * sdhci_arasan_suspend - Suspend method for the driver
569e3ec3a3dSSoren Brinkmann  * @dev:	Address of the device structure
570e3ec3a3dSSoren Brinkmann  *
571e3ec3a3dSSoren Brinkmann  * Put the device in a low power state.
5724908460eSManish Narani  *
5734908460eSManish Narani  * Return: 0 on success and error value on error
574e3ec3a3dSSoren Brinkmann  */
sdhci_arasan_suspend(struct device * dev)575e3ec3a3dSSoren Brinkmann static int sdhci_arasan_suspend(struct device *dev)
576e3ec3a3dSSoren Brinkmann {
577970f2d90SWolfram Sang 	struct sdhci_host *host = dev_get_drvdata(dev);
578e3ec3a3dSSoren Brinkmann 	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
57989211418SJisheng Zhang 	struct sdhci_arasan_data *sdhci_arasan = sdhci_pltfm_priv(pltfm_host);
580e3ec3a3dSSoren Brinkmann 	int ret;
581e3ec3a3dSSoren Brinkmann 
582d38dcad4SAdrian Hunter 	if (host->tuning_mode != SDHCI_TUNING_MODE_3)
583d38dcad4SAdrian Hunter 		mmc_retune_needed(host->mmc);
584d38dcad4SAdrian Hunter 
58584362d79SShawn Lin 	if (sdhci_arasan->has_cqe) {
58684362d79SShawn Lin 		ret = cqhci_suspend(host->mmc);
58784362d79SShawn Lin 		if (ret)
58884362d79SShawn Lin 			return ret;
58984362d79SShawn Lin 	}
59084362d79SShawn Lin 
591e3ec3a3dSSoren Brinkmann 	ret = sdhci_suspend_host(host);
592e3ec3a3dSSoren Brinkmann 	if (ret)
593e3ec3a3dSSoren Brinkmann 		return ret;
594e3ec3a3dSSoren Brinkmann 
595b2db9c67SDouglas Anderson 	if (!IS_ERR(sdhci_arasan->phy) && sdhci_arasan->is_phy_on) {
59691aa3661SShawn Lin 		ret = phy_power_off(sdhci_arasan->phy);
59791aa3661SShawn Lin 		if (ret) {
59891aa3661SShawn Lin 			dev_err(dev, "Cannot power off phy.\n");
59966bad6edSManish Narani 			if (sdhci_resume_host(host))
60066bad6edSManish Narani 				dev_err(dev, "Cannot resume host.\n");
60166bad6edSManish Narani 
60291aa3661SShawn Lin 			return ret;
60391aa3661SShawn Lin 		}
604b2db9c67SDouglas Anderson 		sdhci_arasan->is_phy_on = false;
60591aa3661SShawn Lin 	}
60691aa3661SShawn Lin 
607e3ec3a3dSSoren Brinkmann 	clk_disable(pltfm_host->clk);
608e3ec3a3dSSoren Brinkmann 	clk_disable(sdhci_arasan->clk_ahb);
609e3ec3a3dSSoren Brinkmann 
610e3ec3a3dSSoren Brinkmann 	return 0;
611e3ec3a3dSSoren Brinkmann }
612e3ec3a3dSSoren Brinkmann 
613e3ec3a3dSSoren Brinkmann /**
614e3ec3a3dSSoren Brinkmann  * sdhci_arasan_resume - Resume method for the driver
615e3ec3a3dSSoren Brinkmann  * @dev:	Address of the device structure
616e3ec3a3dSSoren Brinkmann  *
617e3ec3a3dSSoren Brinkmann  * Resume operation after suspend
6184908460eSManish Narani  *
6194908460eSManish Narani  * Return: 0 on success and error value on error
620e3ec3a3dSSoren Brinkmann  */
sdhci_arasan_resume(struct device * dev)621e3ec3a3dSSoren Brinkmann static int sdhci_arasan_resume(struct device *dev)
622e3ec3a3dSSoren Brinkmann {
623970f2d90SWolfram Sang 	struct sdhci_host *host = dev_get_drvdata(dev);
624e3ec3a3dSSoren Brinkmann 	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
62589211418SJisheng Zhang 	struct sdhci_arasan_data *sdhci_arasan = sdhci_pltfm_priv(pltfm_host);
626e3ec3a3dSSoren Brinkmann 	int ret;
627e3ec3a3dSSoren Brinkmann 
628e3ec3a3dSSoren Brinkmann 	ret = clk_enable(sdhci_arasan->clk_ahb);
629e3ec3a3dSSoren Brinkmann 	if (ret) {
630e3ec3a3dSSoren Brinkmann 		dev_err(dev, "Cannot enable AHB clock.\n");
631e3ec3a3dSSoren Brinkmann 		return ret;
632e3ec3a3dSSoren Brinkmann 	}
633e3ec3a3dSSoren Brinkmann 
634e3ec3a3dSSoren Brinkmann 	ret = clk_enable(pltfm_host->clk);
635e3ec3a3dSSoren Brinkmann 	if (ret) {
636e3ec3a3dSSoren Brinkmann 		dev_err(dev, "Cannot enable SD clock.\n");
637e3ec3a3dSSoren Brinkmann 		return ret;
638e3ec3a3dSSoren Brinkmann 	}
639e3ec3a3dSSoren Brinkmann 
640b2db9c67SDouglas Anderson 	if (!IS_ERR(sdhci_arasan->phy) && host->mmc->actual_clock) {
64191aa3661SShawn Lin 		ret = phy_power_on(sdhci_arasan->phy);
64291aa3661SShawn Lin 		if (ret) {
64391aa3661SShawn Lin 			dev_err(dev, "Cannot power on phy.\n");
64491aa3661SShawn Lin 			return ret;
64591aa3661SShawn Lin 		}
646b2db9c67SDouglas Anderson 		sdhci_arasan->is_phy_on = true;
64791aa3661SShawn Lin 	}
64891aa3661SShawn Lin 
64984362d79SShawn Lin 	ret = sdhci_resume_host(host);
65084362d79SShawn Lin 	if (ret) {
65184362d79SShawn Lin 		dev_err(dev, "Cannot resume host.\n");
65284362d79SShawn Lin 		return ret;
65384362d79SShawn Lin 	}
65484362d79SShawn Lin 
65584362d79SShawn Lin 	if (sdhci_arasan->has_cqe)
65684362d79SShawn Lin 		return cqhci_resume(host->mmc);
65784362d79SShawn Lin 
65884362d79SShawn Lin 	return 0;
659e3ec3a3dSSoren Brinkmann }
660e3ec3a3dSSoren Brinkmann #endif /* ! CONFIG_PM_SLEEP */
661e3ec3a3dSSoren Brinkmann 
662e3ec3a3dSSoren Brinkmann static SIMPLE_DEV_PM_OPS(sdhci_arasan_dev_pm_ops, sdhci_arasan_suspend,
663e3ec3a3dSSoren Brinkmann 			 sdhci_arasan_resume);
664e3ec3a3dSSoren Brinkmann 
6653ea4666eSDouglas Anderson /**
666c390f211SDouglas Anderson  * sdhci_arasan_sdcardclk_recalc_rate - Return the card clock rate
667c390f211SDouglas Anderson  *
6684908460eSManish Narani  * @hw:			Pointer to the hardware clock structure.
6694908460eSManish Narani  * @parent_rate:		The parent rate (should be rate of clk_xin).
6704908460eSManish Narani  *
671c390f211SDouglas Anderson  * Return the current actual rate of the SD card clock.  This can be used
672c390f211SDouglas Anderson  * to communicate with out PHY.
673c390f211SDouglas Anderson  *
6744908460eSManish Narani  * Return: The card clock rate.
675c390f211SDouglas Anderson  */
sdhci_arasan_sdcardclk_recalc_rate(struct clk_hw * hw,unsigned long parent_rate)676c390f211SDouglas Anderson static unsigned long sdhci_arasan_sdcardclk_recalc_rate(struct clk_hw *hw,
677c390f211SDouglas Anderson 						      unsigned long parent_rate)
678c390f211SDouglas Anderson {
679e1463618SManish Narani 	struct sdhci_arasan_clk_data *clk_data =
680e1463618SManish Narani 		container_of(hw, struct sdhci_arasan_clk_data, sdcardclk_hw);
681c390f211SDouglas Anderson 	struct sdhci_arasan_data *sdhci_arasan =
682e1463618SManish Narani 		container_of(clk_data, struct sdhci_arasan_data, clk_data);
683c390f211SDouglas Anderson 	struct sdhci_host *host = sdhci_arasan->host;
684c390f211SDouglas Anderson 
685c390f211SDouglas Anderson 	return host->mmc->actual_clock;
686c390f211SDouglas Anderson }
687c390f211SDouglas Anderson 
688c390f211SDouglas Anderson static const struct clk_ops arasan_sdcardclk_ops = {
689c390f211SDouglas Anderson 	.recalc_rate = sdhci_arasan_sdcardclk_recalc_rate,
690c390f211SDouglas Anderson };
691c390f211SDouglas Anderson 
692c390f211SDouglas Anderson /**
69307a14d1dSManish Narani  * sdhci_arasan_sampleclk_recalc_rate - Return the sampling clock rate
69407a14d1dSManish Narani  *
6954908460eSManish Narani  * @hw:			Pointer to the hardware clock structure.
6964908460eSManish Narani  * @parent_rate:		The parent rate (should be rate of clk_xin).
6974908460eSManish Narani  *
69807a14d1dSManish Narani  * Return the current actual rate of the sampling clock.  This can be used
69907a14d1dSManish Narani  * to communicate with out PHY.
70007a14d1dSManish Narani  *
7014908460eSManish Narani  * Return: The sample clock rate.
70207a14d1dSManish Narani  */
sdhci_arasan_sampleclk_recalc_rate(struct clk_hw * hw,unsigned long parent_rate)70307a14d1dSManish Narani static unsigned long sdhci_arasan_sampleclk_recalc_rate(struct clk_hw *hw,
70407a14d1dSManish Narani 						      unsigned long parent_rate)
70507a14d1dSManish Narani {
70607a14d1dSManish Narani 	struct sdhci_arasan_clk_data *clk_data =
70707a14d1dSManish Narani 		container_of(hw, struct sdhci_arasan_clk_data, sampleclk_hw);
70807a14d1dSManish Narani 	struct sdhci_arasan_data *sdhci_arasan =
70907a14d1dSManish Narani 		container_of(clk_data, struct sdhci_arasan_data, clk_data);
71007a14d1dSManish Narani 	struct sdhci_host *host = sdhci_arasan->host;
71107a14d1dSManish Narani 
71207a14d1dSManish Narani 	return host->mmc->actual_clock;
71307a14d1dSManish Narani }
71407a14d1dSManish Narani 
71507a14d1dSManish Narani static const struct clk_ops arasan_sampleclk_ops = {
71607a14d1dSManish Narani 	.recalc_rate = sdhci_arasan_sampleclk_recalc_rate,
71707a14d1dSManish Narani };
71807a14d1dSManish Narani 
71907a14d1dSManish Narani /**
720a5c8b2aeSManish Narani  * sdhci_zynqmp_sdcardclk_set_phase - Set the SD Output Clock Tap Delays
721a5c8b2aeSManish Narani  *
7224908460eSManish Narani  * @hw:			Pointer to the hardware clock structure.
7234908460eSManish Narani  * @degrees:		The clock phase shift between 0 - 359.
7244908460eSManish Narani  *
725a5c8b2aeSManish Narani  * Set the SD Output Clock Tap Delays for Output path
726a5c8b2aeSManish Narani  *
727a5c8b2aeSManish Narani  * Return: 0 on success and error value on error
728a5c8b2aeSManish Narani  */
sdhci_zynqmp_sdcardclk_set_phase(struct clk_hw * hw,int degrees)729a5c8b2aeSManish Narani static int sdhci_zynqmp_sdcardclk_set_phase(struct clk_hw *hw, int degrees)
730a5c8b2aeSManish Narani {
731a5c8b2aeSManish Narani 	struct sdhci_arasan_clk_data *clk_data =
732a5c8b2aeSManish Narani 		container_of(hw, struct sdhci_arasan_clk_data, sdcardclk_hw);
733a5c8b2aeSManish Narani 	struct sdhci_arasan_data *sdhci_arasan =
734a5c8b2aeSManish Narani 		container_of(clk_data, struct sdhci_arasan_data, clk_data);
735a5c8b2aeSManish Narani 	struct sdhci_host *host = sdhci_arasan->host;
736a5c8b2aeSManish Narani 	const char *clk_name = clk_hw_get_name(hw);
737a5c8b2aeSManish Narani 	u32 node_id = !strcmp(clk_name, "clk_out_sd0") ? NODE_SD_0 : NODE_SD_1;
738a5c8b2aeSManish Narani 	u8 tap_delay, tap_max = 0;
739a5c8b2aeSManish Narani 	int ret;
740a5c8b2aeSManish Narani 
7419e953432SManish Narani 	/* This is applicable for SDHCI_SPEC_300 and above */
7429e953432SManish Narani 	if (host->version < SDHCI_SPEC_300)
743a5c8b2aeSManish Narani 		return 0;
744a5c8b2aeSManish Narani 
745a5c8b2aeSManish Narani 	switch (host->timing) {
746a5c8b2aeSManish Narani 	case MMC_TIMING_MMC_HS:
747a5c8b2aeSManish Narani 	case MMC_TIMING_SD_HS:
748a5c8b2aeSManish Narani 	case MMC_TIMING_UHS_SDR25:
749a5c8b2aeSManish Narani 	case MMC_TIMING_UHS_DDR50:
750a5c8b2aeSManish Narani 	case MMC_TIMING_MMC_DDR52:
751a5c8b2aeSManish Narani 		/* For 50MHz clock, 30 Taps are available */
752a5c8b2aeSManish Narani 		tap_max = 30;
753a5c8b2aeSManish Narani 		break;
754a5c8b2aeSManish Narani 	case MMC_TIMING_UHS_SDR50:
755a5c8b2aeSManish Narani 		/* For 100MHz clock, 15 Taps are available */
756a5c8b2aeSManish Narani 		tap_max = 15;
757a5c8b2aeSManish Narani 		break;
758a5c8b2aeSManish Narani 	case MMC_TIMING_UHS_SDR104:
759a5c8b2aeSManish Narani 	case MMC_TIMING_MMC_HS200:
760a5c8b2aeSManish Narani 		/* For 200MHz clock, 8 Taps are available */
761a5c8b2aeSManish Narani 		tap_max = 8;
762a3096ec6SGustavo A. R. Silva 		break;
763a5c8b2aeSManish Narani 	default:
764a5c8b2aeSManish Narani 		break;
765a5c8b2aeSManish Narani 	}
766a5c8b2aeSManish Narani 
767a5c8b2aeSManish Narani 	tap_delay = (degrees * tap_max) / 360;
768a5c8b2aeSManish Narani 
769a5c8b2aeSManish Narani 	/* Set the Clock Phase */
770426c8d85SRajan Vaja 	ret = zynqmp_pm_set_sd_tapdelay(node_id, PM_TAPDELAY_OUTPUT, tap_delay);
771a5c8b2aeSManish Narani 	if (ret)
772a5c8b2aeSManish Narani 		pr_err("Error setting Output Tap Delay\n");
773a5c8b2aeSManish Narani 
774d06d60d5SManish Narani 	/* Release DLL Reset */
775d06d60d5SManish Narani 	zynqmp_pm_sd_dll_reset(node_id, PM_DLL_RESET_RELEASE);
776d06d60d5SManish Narani 
777a5c8b2aeSManish Narani 	return ret;
778a5c8b2aeSManish Narani }
779a5c8b2aeSManish Narani 
780a5c8b2aeSManish Narani static const struct clk_ops zynqmp_sdcardclk_ops = {
781a5c8b2aeSManish Narani 	.recalc_rate = sdhci_arasan_sdcardclk_recalc_rate,
782a5c8b2aeSManish Narani 	.set_phase = sdhci_zynqmp_sdcardclk_set_phase,
783a5c8b2aeSManish Narani };
784a5c8b2aeSManish Narani 
785a5c8b2aeSManish Narani /**
786a5c8b2aeSManish Narani  * sdhci_zynqmp_sampleclk_set_phase - Set the SD Input Clock Tap Delays
787a5c8b2aeSManish Narani  *
7884908460eSManish Narani  * @hw:			Pointer to the hardware clock structure.
7894908460eSManish Narani  * @degrees:		The clock phase shift between 0 - 359.
7904908460eSManish Narani  *
791a5c8b2aeSManish Narani  * Set the SD Input Clock Tap Delays for Input path
792a5c8b2aeSManish Narani  *
793a5c8b2aeSManish Narani  * Return: 0 on success and error value on error
794a5c8b2aeSManish Narani  */
sdhci_zynqmp_sampleclk_set_phase(struct clk_hw * hw,int degrees)795a5c8b2aeSManish Narani static int sdhci_zynqmp_sampleclk_set_phase(struct clk_hw *hw, int degrees)
796a5c8b2aeSManish Narani {
797a5c8b2aeSManish Narani 	struct sdhci_arasan_clk_data *clk_data =
798a5c8b2aeSManish Narani 		container_of(hw, struct sdhci_arasan_clk_data, sampleclk_hw);
799a5c8b2aeSManish Narani 	struct sdhci_arasan_data *sdhci_arasan =
800a5c8b2aeSManish Narani 		container_of(clk_data, struct sdhci_arasan_data, clk_data);
801a5c8b2aeSManish Narani 	struct sdhci_host *host = sdhci_arasan->host;
802a5c8b2aeSManish Narani 	const char *clk_name = clk_hw_get_name(hw);
803a5c8b2aeSManish Narani 	u32 node_id = !strcmp(clk_name, "clk_in_sd0") ? NODE_SD_0 : NODE_SD_1;
804a5c8b2aeSManish Narani 	u8 tap_delay, tap_max = 0;
805a5c8b2aeSManish Narani 	int ret;
806a5c8b2aeSManish Narani 
8079e953432SManish Narani 	/* This is applicable for SDHCI_SPEC_300 and above */
8089e953432SManish Narani 	if (host->version < SDHCI_SPEC_300)
809a5c8b2aeSManish Narani 		return 0;
810a5c8b2aeSManish Narani 
811d06d60d5SManish Narani 	/* Assert DLL Reset */
812d06d60d5SManish Narani 	zynqmp_pm_sd_dll_reset(node_id, PM_DLL_RESET_ASSERT);
813d06d60d5SManish Narani 
814a5c8b2aeSManish Narani 	switch (host->timing) {
815a5c8b2aeSManish Narani 	case MMC_TIMING_MMC_HS:
816a5c8b2aeSManish Narani 	case MMC_TIMING_SD_HS:
817a5c8b2aeSManish Narani 	case MMC_TIMING_UHS_SDR25:
818a5c8b2aeSManish Narani 	case MMC_TIMING_UHS_DDR50:
819a5c8b2aeSManish Narani 	case MMC_TIMING_MMC_DDR52:
820a5c8b2aeSManish Narani 		/* For 50MHz clock, 120 Taps are available */
821a5c8b2aeSManish Narani 		tap_max = 120;
822a5c8b2aeSManish Narani 		break;
823a5c8b2aeSManish Narani 	case MMC_TIMING_UHS_SDR50:
824a5c8b2aeSManish Narani 		/* For 100MHz clock, 60 Taps are available */
825a5c8b2aeSManish Narani 		tap_max = 60;
826a5c8b2aeSManish Narani 		break;
827a5c8b2aeSManish Narani 	case MMC_TIMING_UHS_SDR104:
828a5c8b2aeSManish Narani 	case MMC_TIMING_MMC_HS200:
829a5c8b2aeSManish Narani 		/* For 200MHz clock, 30 Taps are available */
830a5c8b2aeSManish Narani 		tap_max = 30;
831a3096ec6SGustavo A. R. Silva 		break;
832a5c8b2aeSManish Narani 	default:
833a5c8b2aeSManish Narani 		break;
834a5c8b2aeSManish Narani 	}
835a5c8b2aeSManish Narani 
836a5c8b2aeSManish Narani 	tap_delay = (degrees * tap_max) / 360;
837a5c8b2aeSManish Narani 
838a5c8b2aeSManish Narani 	/* Set the Clock Phase */
839426c8d85SRajan Vaja 	ret = zynqmp_pm_set_sd_tapdelay(node_id, PM_TAPDELAY_INPUT, tap_delay);
840a5c8b2aeSManish Narani 	if (ret)
841a5c8b2aeSManish Narani 		pr_err("Error setting Input Tap Delay\n");
842a5c8b2aeSManish Narani 
843a5c8b2aeSManish Narani 	return ret;
844a5c8b2aeSManish Narani }
845a5c8b2aeSManish Narani 
846a5c8b2aeSManish Narani static const struct clk_ops zynqmp_sampleclk_ops = {
847a5c8b2aeSManish Narani 	.recalc_rate = sdhci_arasan_sampleclk_recalc_rate,
848a5c8b2aeSManish Narani 	.set_phase = sdhci_zynqmp_sampleclk_set_phase,
849a5c8b2aeSManish Narani };
850a5c8b2aeSManish Narani 
8511a470721SManish Narani /**
8521a470721SManish Narani  * sdhci_versal_sdcardclk_set_phase - Set the SD Output Clock Tap Delays
8531a470721SManish Narani  *
8544908460eSManish Narani  * @hw:			Pointer to the hardware clock structure.
8554908460eSManish Narani  * @degrees:		The clock phase shift between 0 - 359.
8564908460eSManish Narani  *
8571a470721SManish Narani  * Set the SD Output Clock Tap Delays for Output path
8581a470721SManish Narani  *
8591a470721SManish Narani  * Return: 0 on success and error value on error
8601a470721SManish Narani  */
sdhci_versal_sdcardclk_set_phase(struct clk_hw * hw,int degrees)8611a470721SManish Narani static int sdhci_versal_sdcardclk_set_phase(struct clk_hw *hw, int degrees)
8621a470721SManish Narani {
8631a470721SManish Narani 	struct sdhci_arasan_clk_data *clk_data =
8641a470721SManish Narani 		container_of(hw, struct sdhci_arasan_clk_data, sdcardclk_hw);
8651a470721SManish Narani 	struct sdhci_arasan_data *sdhci_arasan =
8661a470721SManish Narani 		container_of(clk_data, struct sdhci_arasan_data, clk_data);
8671a470721SManish Narani 	struct sdhci_host *host = sdhci_arasan->host;
8681a470721SManish Narani 	u8 tap_delay, tap_max = 0;
8691a470721SManish Narani 
8709e953432SManish Narani 	/* This is applicable for SDHCI_SPEC_300 and above */
8719e953432SManish Narani 	if (host->version < SDHCI_SPEC_300)
8721a470721SManish Narani 		return 0;
8731a470721SManish Narani 
8741a470721SManish Narani 	switch (host->timing) {
8751a470721SManish Narani 	case MMC_TIMING_MMC_HS:
8761a470721SManish Narani 	case MMC_TIMING_SD_HS:
8771a470721SManish Narani 	case MMC_TIMING_UHS_SDR25:
8781a470721SManish Narani 	case MMC_TIMING_UHS_DDR50:
8791a470721SManish Narani 	case MMC_TIMING_MMC_DDR52:
8801a470721SManish Narani 		/* For 50MHz clock, 30 Taps are available */
8811a470721SManish Narani 		tap_max = 30;
8821a470721SManish Narani 		break;
8831a470721SManish Narani 	case MMC_TIMING_UHS_SDR50:
8841a470721SManish Narani 		/* For 100MHz clock, 15 Taps are available */
8851a470721SManish Narani 		tap_max = 15;
8861a470721SManish Narani 		break;
8871a470721SManish Narani 	case MMC_TIMING_UHS_SDR104:
8881a470721SManish Narani 	case MMC_TIMING_MMC_HS200:
8891a470721SManish Narani 		/* For 200MHz clock, 8 Taps are available */
8901a470721SManish Narani 		tap_max = 8;
891a3096ec6SGustavo A. R. Silva 		break;
8921a470721SManish Narani 	default:
8931a470721SManish Narani 		break;
8941a470721SManish Narani 	}
8951a470721SManish Narani 
8961a470721SManish Narani 	tap_delay = (degrees * tap_max) / 360;
8971a470721SManish Narani 
8981a470721SManish Narani 	/* Set the Clock Phase */
8991a470721SManish Narani 	if (tap_delay) {
9001a470721SManish Narani 		u32 regval;
9011a470721SManish Narani 
9021a470721SManish Narani 		regval = sdhci_readl(host, SDHCI_ARASAN_OTAPDLY_REGISTER);
9031a470721SManish Narani 		regval |= SDHCI_OTAPDLY_ENABLE;
9041a470721SManish Narani 		sdhci_writel(host, regval, SDHCI_ARASAN_OTAPDLY_REGISTER);
905d338c6d0SManish Narani 		regval &= ~SDHCI_ARASAN_OTAPDLY_SEL_MASK;
9061a470721SManish Narani 		regval |= tap_delay;
9071a470721SManish Narani 		sdhci_writel(host, regval, SDHCI_ARASAN_OTAPDLY_REGISTER);
9081a470721SManish Narani 	}
9091a470721SManish Narani 
910098c408bSNathan Chancellor 	return 0;
9111a470721SManish Narani }
9121a470721SManish Narani 
9131a470721SManish Narani static const struct clk_ops versal_sdcardclk_ops = {
9141a470721SManish Narani 	.recalc_rate = sdhci_arasan_sdcardclk_recalc_rate,
9151a470721SManish Narani 	.set_phase = sdhci_versal_sdcardclk_set_phase,
9161a470721SManish Narani };
9171a470721SManish Narani 
9181a470721SManish Narani /**
9191a470721SManish Narani  * sdhci_versal_sampleclk_set_phase - Set the SD Input Clock Tap Delays
9201a470721SManish Narani  *
9214908460eSManish Narani  * @hw:			Pointer to the hardware clock structure.
9224908460eSManish Narani  * @degrees:		The clock phase shift between 0 - 359.
9234908460eSManish Narani  *
9241a470721SManish Narani  * Set the SD Input Clock Tap Delays for Input path
9251a470721SManish Narani  *
9261a470721SManish Narani  * Return: 0 on success and error value on error
9271a470721SManish Narani  */
sdhci_versal_sampleclk_set_phase(struct clk_hw * hw,int degrees)9281a470721SManish Narani static int sdhci_versal_sampleclk_set_phase(struct clk_hw *hw, int degrees)
9291a470721SManish Narani {
9301a470721SManish Narani 	struct sdhci_arasan_clk_data *clk_data =
9311a470721SManish Narani 		container_of(hw, struct sdhci_arasan_clk_data, sampleclk_hw);
9321a470721SManish Narani 	struct sdhci_arasan_data *sdhci_arasan =
9331a470721SManish Narani 		container_of(clk_data, struct sdhci_arasan_data, clk_data);
9341a470721SManish Narani 	struct sdhci_host *host = sdhci_arasan->host;
9351a470721SManish Narani 	u8 tap_delay, tap_max = 0;
9361a470721SManish Narani 
9379e953432SManish Narani 	/* This is applicable for SDHCI_SPEC_300 and above */
9389e953432SManish Narani 	if (host->version < SDHCI_SPEC_300)
9391a470721SManish Narani 		return 0;
9401a470721SManish Narani 
9411a470721SManish Narani 	switch (host->timing) {
9421a470721SManish Narani 	case MMC_TIMING_MMC_HS:
9431a470721SManish Narani 	case MMC_TIMING_SD_HS:
9441a470721SManish Narani 	case MMC_TIMING_UHS_SDR25:
9451a470721SManish Narani 	case MMC_TIMING_UHS_DDR50:
9461a470721SManish Narani 	case MMC_TIMING_MMC_DDR52:
9471a470721SManish Narani 		/* For 50MHz clock, 120 Taps are available */
9481a470721SManish Narani 		tap_max = 120;
9491a470721SManish Narani 		break;
9501a470721SManish Narani 	case MMC_TIMING_UHS_SDR50:
9511a470721SManish Narani 		/* For 100MHz clock, 60 Taps are available */
9521a470721SManish Narani 		tap_max = 60;
9531a470721SManish Narani 		break;
9541a470721SManish Narani 	case MMC_TIMING_UHS_SDR104:
9551a470721SManish Narani 	case MMC_TIMING_MMC_HS200:
9561a470721SManish Narani 		/* For 200MHz clock, 30 Taps are available */
9571a470721SManish Narani 		tap_max = 30;
958a3096ec6SGustavo A. R. Silva 		break;
9591a470721SManish Narani 	default:
9601a470721SManish Narani 		break;
9611a470721SManish Narani 	}
9621a470721SManish Narani 
9631a470721SManish Narani 	tap_delay = (degrees * tap_max) / 360;
9641a470721SManish Narani 
9651a470721SManish Narani 	/* Set the Clock Phase */
9661a470721SManish Narani 	if (tap_delay) {
9671a470721SManish Narani 		u32 regval;
9681a470721SManish Narani 
9691a470721SManish Narani 		regval = sdhci_readl(host, SDHCI_ARASAN_ITAPDLY_REGISTER);
9701a470721SManish Narani 		regval |= SDHCI_ITAPDLY_CHGWIN;
9711a470721SManish Narani 		sdhci_writel(host, regval, SDHCI_ARASAN_ITAPDLY_REGISTER);
9721a470721SManish Narani 		regval |= SDHCI_ITAPDLY_ENABLE;
9731a470721SManish Narani 		sdhci_writel(host, regval, SDHCI_ARASAN_ITAPDLY_REGISTER);
974d338c6d0SManish Narani 		regval &= ~SDHCI_ARASAN_ITAPDLY_SEL_MASK;
9751a470721SManish Narani 		regval |= tap_delay;
9761a470721SManish Narani 		sdhci_writel(host, regval, SDHCI_ARASAN_ITAPDLY_REGISTER);
9771a470721SManish Narani 		regval &= ~SDHCI_ITAPDLY_CHGWIN;
9781a470721SManish Narani 		sdhci_writel(host, regval, SDHCI_ARASAN_ITAPDLY_REGISTER);
9791a470721SManish Narani 	}
9801a470721SManish Narani 
981098c408bSNathan Chancellor 	return 0;
9821a470721SManish Narani }
9831a470721SManish Narani 
9841a470721SManish Narani static const struct clk_ops versal_sampleclk_ops = {
9851a470721SManish Narani 	.recalc_rate = sdhci_arasan_sampleclk_recalc_rate,
9861a470721SManish Narani 	.set_phase = sdhci_versal_sampleclk_set_phase,
9871a470721SManish Narani };
9881a470721SManish Narani 
sdhci_versal_net_emmc_sdcardclk_set_phase(struct clk_hw * hw,int degrees)989b095f4f5SSwati Agarwal static int sdhci_versal_net_emmc_sdcardclk_set_phase(struct clk_hw *hw, int degrees)
990b095f4f5SSwati Agarwal {
991b095f4f5SSwati Agarwal 	struct sdhci_arasan_clk_data *clk_data =
992b095f4f5SSwati Agarwal 		container_of(hw, struct sdhci_arasan_clk_data, sdcardclk_hw);
993b095f4f5SSwati Agarwal 	struct sdhci_arasan_data *sdhci_arasan =
994b095f4f5SSwati Agarwal 		container_of(clk_data, struct sdhci_arasan_data, clk_data);
995b095f4f5SSwati Agarwal 	struct sdhci_host *host = sdhci_arasan->host;
996b095f4f5SSwati Agarwal 	u8 tap_delay, tap_max = 0;
997b095f4f5SSwati Agarwal 
998b095f4f5SSwati Agarwal 	switch (host->timing) {
999b095f4f5SSwati Agarwal 	case MMC_TIMING_MMC_HS:
1000b095f4f5SSwati Agarwal 	case MMC_TIMING_MMC_DDR52:
1001b095f4f5SSwati Agarwal 		tap_max = 16;
1002b095f4f5SSwati Agarwal 		break;
1003b095f4f5SSwati Agarwal 	case MMC_TIMING_MMC_HS200:
1004b095f4f5SSwati Agarwal 	case MMC_TIMING_MMC_HS400:
1005b095f4f5SSwati Agarwal 		 /* For 200MHz clock, 32 Taps are available */
1006b095f4f5SSwati Agarwal 		tap_max = 32;
1007b095f4f5SSwati Agarwal 		break;
1008b095f4f5SSwati Agarwal 	default:
1009b095f4f5SSwati Agarwal 		break;
1010b095f4f5SSwati Agarwal 	}
1011b095f4f5SSwati Agarwal 
1012b095f4f5SSwati Agarwal 	tap_delay = (degrees * tap_max) / 360;
1013b095f4f5SSwati Agarwal 
1014b095f4f5SSwati Agarwal 	/* Set the Clock Phase */
1015b095f4f5SSwati Agarwal 	if (tap_delay) {
1016b095f4f5SSwati Agarwal 		u32 regval;
1017b095f4f5SSwati Agarwal 
1018b095f4f5SSwati Agarwal 		regval = sdhci_readl(host, PHY_CTRL_REG1);
1019b095f4f5SSwati Agarwal 		regval |= PHY_CTRL_OTAPDLY_ENA_MASK;
1020b095f4f5SSwati Agarwal 		sdhci_writel(host, regval, PHY_CTRL_REG1);
1021b095f4f5SSwati Agarwal 		regval &= ~PHY_CTRL_OTAPDLY_SEL_MASK;
1022b095f4f5SSwati Agarwal 		regval |= tap_delay << PHY_CTRL_OTAPDLY_SEL_SHIFT;
1023b095f4f5SSwati Agarwal 		sdhci_writel(host, regval, PHY_CTRL_REG1);
1024b095f4f5SSwati Agarwal 	}
1025b095f4f5SSwati Agarwal 
1026b095f4f5SSwati Agarwal 	return 0;
1027b095f4f5SSwati Agarwal }
1028b095f4f5SSwati Agarwal 
1029b095f4f5SSwati Agarwal static const struct clk_ops versal_net_sdcardclk_ops = {
1030b095f4f5SSwati Agarwal 	.recalc_rate = sdhci_arasan_sdcardclk_recalc_rate,
1031b095f4f5SSwati Agarwal 	.set_phase = sdhci_versal_net_emmc_sdcardclk_set_phase,
1032b095f4f5SSwati Agarwal };
1033b095f4f5SSwati Agarwal 
sdhci_versal_net_emmc_sampleclk_set_phase(struct clk_hw * hw,int degrees)1034b095f4f5SSwati Agarwal static int sdhci_versal_net_emmc_sampleclk_set_phase(struct clk_hw *hw, int degrees)
1035b095f4f5SSwati Agarwal {
1036b095f4f5SSwati Agarwal 	struct sdhci_arasan_clk_data *clk_data =
1037b095f4f5SSwati Agarwal 		container_of(hw, struct sdhci_arasan_clk_data, sampleclk_hw);
1038b095f4f5SSwati Agarwal 	struct sdhci_arasan_data *sdhci_arasan =
1039b095f4f5SSwati Agarwal 		container_of(clk_data, struct sdhci_arasan_data, clk_data);
1040b095f4f5SSwati Agarwal 	struct sdhci_host *host = sdhci_arasan->host;
1041b095f4f5SSwati Agarwal 	u8 tap_delay, tap_max = 0;
1042b095f4f5SSwati Agarwal 	u32 regval;
1043b095f4f5SSwati Agarwal 
1044b095f4f5SSwati Agarwal 	switch (host->timing) {
1045b095f4f5SSwati Agarwal 	case MMC_TIMING_MMC_HS:
1046b095f4f5SSwati Agarwal 	case MMC_TIMING_MMC_DDR52:
1047b095f4f5SSwati Agarwal 		tap_max = 32;
1048b095f4f5SSwati Agarwal 		break;
1049b095f4f5SSwati Agarwal 	case MMC_TIMING_MMC_HS400:
1050b095f4f5SSwati Agarwal 		/* Strobe select tap point for strb90 and strb180 */
1051b095f4f5SSwati Agarwal 		regval = sdhci_readl(host, PHY_CTRL_REG1);
1052b095f4f5SSwati Agarwal 		regval &= ~PHY_CTRL_STRB_SEL_MASK;
1053b095f4f5SSwati Agarwal 		regval |= VERSAL_NET_PHY_CTRL_STRB90_STRB180_VAL << PHY_CTRL_STRB_SEL_SHIFT;
1054b095f4f5SSwati Agarwal 		sdhci_writel(host, regval, PHY_CTRL_REG1);
1055b095f4f5SSwati Agarwal 		break;
1056b095f4f5SSwati Agarwal 	default:
1057b095f4f5SSwati Agarwal 		break;
1058b095f4f5SSwati Agarwal 	}
1059b095f4f5SSwati Agarwal 
1060b095f4f5SSwati Agarwal 	tap_delay = (degrees * tap_max) / 360;
1061b095f4f5SSwati Agarwal 
1062b095f4f5SSwati Agarwal 	/* Set the Clock Phase */
1063b095f4f5SSwati Agarwal 	if (tap_delay) {
1064b095f4f5SSwati Agarwal 		regval = sdhci_readl(host, PHY_CTRL_REG1);
1065b095f4f5SSwati Agarwal 		regval |= PHY_CTRL_ITAP_CHG_WIN_MASK;
1066b095f4f5SSwati Agarwal 		sdhci_writel(host, regval, PHY_CTRL_REG1);
1067b095f4f5SSwati Agarwal 		regval |= PHY_CTRL_ITAPDLY_ENA_MASK;
1068b095f4f5SSwati Agarwal 		sdhci_writel(host, regval, PHY_CTRL_REG1);
1069b095f4f5SSwati Agarwal 		regval &= ~PHY_CTRL_ITAPDLY_SEL_MASK;
1070b095f4f5SSwati Agarwal 		regval |= tap_delay << PHY_CTRL_ITAPDLY_SEL_SHIFT;
1071b095f4f5SSwati Agarwal 		sdhci_writel(host, regval, PHY_CTRL_REG1);
1072b095f4f5SSwati Agarwal 		regval &= ~PHY_CTRL_ITAP_CHG_WIN_MASK;
1073b095f4f5SSwati Agarwal 		sdhci_writel(host, regval, PHY_CTRL_REG1);
1074b095f4f5SSwati Agarwal 	}
1075b095f4f5SSwati Agarwal 
1076b095f4f5SSwati Agarwal 	return 0;
1077b095f4f5SSwati Agarwal }
1078b095f4f5SSwati Agarwal 
1079b095f4f5SSwati Agarwal static const struct clk_ops versal_net_sampleclk_ops = {
1080b095f4f5SSwati Agarwal 	.recalc_rate = sdhci_arasan_sampleclk_recalc_rate,
1081b095f4f5SSwati Agarwal 	.set_phase = sdhci_versal_net_emmc_sampleclk_set_phase,
1082b095f4f5SSwati Agarwal };
1083b095f4f5SSwati Agarwal 
arasan_zynqmp_dll_reset(struct sdhci_host * host,u32 deviceid)10848d2e3343SManish Narani static void arasan_zynqmp_dll_reset(struct sdhci_host *host, u32 deviceid)
10858d2e3343SManish Narani {
10868d2e3343SManish Narani 	u16 clk;
10878d2e3343SManish Narani 
10888d2e3343SManish Narani 	clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL);
10898d2e3343SManish Narani 	clk &= ~(SDHCI_CLOCK_CARD_EN | SDHCI_CLOCK_INT_EN);
10908d2e3343SManish Narani 	sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
10918d2e3343SManish Narani 
10928d2e3343SManish Narani 	/* Issue DLL Reset */
1093426c8d85SRajan Vaja 	zynqmp_pm_sd_dll_reset(deviceid, PM_DLL_RESET_PULSE);
10948d2e3343SManish Narani 
10958d2e3343SManish Narani 	clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL);
10968d2e3343SManish Narani 
10978d2e3343SManish Narani 	sdhci_enable_clk(host, clk);
10988d2e3343SManish Narani }
10998d2e3343SManish Narani 
arasan_zynqmp_execute_tuning(struct mmc_host * mmc,u32 opcode)11008d2e3343SManish Narani static int arasan_zynqmp_execute_tuning(struct mmc_host *mmc, u32 opcode)
11018d2e3343SManish Narani {
11028d2e3343SManish Narani 	struct sdhci_host *host = mmc_priv(mmc);
11038d2e3343SManish Narani 	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
11048d2e3343SManish Narani 	struct sdhci_arasan_data *sdhci_arasan = sdhci_pltfm_priv(pltfm_host);
11058d2e3343SManish Narani 	struct clk_hw *hw = &sdhci_arasan->clk_data.sdcardclk_hw;
11068d2e3343SManish Narani 	const char *clk_name = clk_hw_get_name(hw);
11078d2e3343SManish Narani 	u32 device_id = !strcmp(clk_name, "clk_out_sd0") ? NODE_SD_0 :
11088d2e3343SManish Narani 							   NODE_SD_1;
11098d2e3343SManish Narani 	int err;
11108d2e3343SManish Narani 
1111256e4e4eSManish Narani 	/* ZynqMP SD controller does not perform auto tuning in DDR50 mode */
1112256e4e4eSManish Narani 	if (mmc->ios.timing == MMC_TIMING_UHS_DDR50)
1113256e4e4eSManish Narani 		return 0;
1114256e4e4eSManish Narani 
11158d2e3343SManish Narani 	arasan_zynqmp_dll_reset(host, device_id);
11168d2e3343SManish Narani 
11178d2e3343SManish Narani 	err = sdhci_execute_tuning(mmc, opcode);
11188d2e3343SManish Narani 	if (err)
11198d2e3343SManish Narani 		return err;
11208d2e3343SManish Narani 
11218d2e3343SManish Narani 	arasan_zynqmp_dll_reset(host, device_id);
11228d2e3343SManish Narani 
11238d2e3343SManish Narani 	return 0;
11248d2e3343SManish Narani }
11258d2e3343SManish Narani 
1126a5c8b2aeSManish Narani /**
1127b2ca77c9SShawn Lin  * sdhci_arasan_update_clockmultiplier - Set corecfg_clockmultiplier
1128b2ca77c9SShawn Lin  *
11294908460eSManish Narani  * @host:		The sdhci_host
11304908460eSManish Narani  * @value:		The value to write
11314908460eSManish Narani  *
1132b2ca77c9SShawn Lin  * The corecfg_clockmultiplier is supposed to contain clock multiplier
1133b2ca77c9SShawn Lin  * value of programmable clock generator.
1134b2ca77c9SShawn Lin  *
1135b2ca77c9SShawn Lin  * NOTES:
1136b2ca77c9SShawn Lin  * - Many existing devices don't seem to do this and work fine.  To keep
1137b2ca77c9SShawn Lin  *   compatibility for old hardware where the device tree doesn't provide a
1138b2ca77c9SShawn Lin  *   register map, this function is a noop if a soc_ctl_map hasn't been provided
1139b2ca77c9SShawn Lin  *   for this platform.
1140b2ca77c9SShawn Lin  * - The value of corecfg_clockmultiplier should sync with that of corresponding
1141b2ca77c9SShawn Lin  *   value reading from sdhci_capability_register. So this function is called
1142b2ca77c9SShawn Lin  *   once at probe time and never called again.
1143b2ca77c9SShawn Lin  */
sdhci_arasan_update_clockmultiplier(struct sdhci_host * host,u32 value)1144b2ca77c9SShawn Lin static void sdhci_arasan_update_clockmultiplier(struct sdhci_host *host,
1145b2ca77c9SShawn Lin 						u32 value)
1146b2ca77c9SShawn Lin {
1147b2ca77c9SShawn Lin 	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
1148b2ca77c9SShawn Lin 	struct sdhci_arasan_data *sdhci_arasan = sdhci_pltfm_priv(pltfm_host);
1149b2ca77c9SShawn Lin 	const struct sdhci_arasan_soc_ctl_map *soc_ctl_map =
1150b2ca77c9SShawn Lin 		sdhci_arasan->soc_ctl_map;
1151b2ca77c9SShawn Lin 
1152b2ca77c9SShawn Lin 	/* Having a map is optional */
1153b2ca77c9SShawn Lin 	if (!soc_ctl_map)
1154b2ca77c9SShawn Lin 		return;
1155b2ca77c9SShawn Lin 
1156b2ca77c9SShawn Lin 	/* If we have a map, we expect to have a syscon */
1157b2ca77c9SShawn Lin 	if (!sdhci_arasan->soc_ctl_base) {
1158b2ca77c9SShawn Lin 		pr_warn("%s: Have regmap, but no soc-ctl-syscon\n",
1159b2ca77c9SShawn Lin 			mmc_hostname(host->mmc));
1160b2ca77c9SShawn Lin 		return;
1161b2ca77c9SShawn Lin 	}
1162b2ca77c9SShawn Lin 
1163b2ca77c9SShawn Lin 	sdhci_arasan_syscon_write(host, &soc_ctl_map->clockmultiplier, value);
1164b2ca77c9SShawn Lin }
1165b2ca77c9SShawn Lin 
1166b2ca77c9SShawn Lin /**
11673ea4666eSDouglas Anderson  * sdhci_arasan_update_baseclkfreq - Set corecfg_baseclkfreq
11683ea4666eSDouglas Anderson  *
11694908460eSManish Narani  * @host:		The sdhci_host
11704908460eSManish Narani  *
11713ea4666eSDouglas Anderson  * The corecfg_baseclkfreq is supposed to contain the MHz of clk_xin.  This
11723ea4666eSDouglas Anderson  * function can be used to make that happen.
11733ea4666eSDouglas Anderson  *
11743ea4666eSDouglas Anderson  * NOTES:
11753ea4666eSDouglas Anderson  * - Many existing devices don't seem to do this and work fine.  To keep
11763ea4666eSDouglas Anderson  *   compatibility for old hardware where the device tree doesn't provide a
11773ea4666eSDouglas Anderson  *   register map, this function is a noop if a soc_ctl_map hasn't been provided
11783ea4666eSDouglas Anderson  *   for this platform.
11793ea4666eSDouglas Anderson  * - It's assumed that clk_xin is not dynamic and that we use the SDHCI divider
11803ea4666eSDouglas Anderson  *   to achieve lower clock rates.  That means that this function is called once
11813ea4666eSDouglas Anderson  *   at probe time and never called again.
11823ea4666eSDouglas Anderson  */
sdhci_arasan_update_baseclkfreq(struct sdhci_host * host)11833ea4666eSDouglas Anderson static void sdhci_arasan_update_baseclkfreq(struct sdhci_host *host)
11843ea4666eSDouglas Anderson {
11853ea4666eSDouglas Anderson 	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
11863ea4666eSDouglas Anderson 	struct sdhci_arasan_data *sdhci_arasan = sdhci_pltfm_priv(pltfm_host);
11873ea4666eSDouglas Anderson 	const struct sdhci_arasan_soc_ctl_map *soc_ctl_map =
11883ea4666eSDouglas Anderson 		sdhci_arasan->soc_ctl_map;
1189462f58fdSManish Narani 	u32 mhz = DIV_ROUND_CLOSEST_ULL(clk_get_rate(pltfm_host->clk), 1000000);
11903ea4666eSDouglas Anderson 
11913ea4666eSDouglas Anderson 	/* Having a map is optional */
11923ea4666eSDouglas Anderson 	if (!soc_ctl_map)
11933ea4666eSDouglas Anderson 		return;
11943ea4666eSDouglas Anderson 
11953ea4666eSDouglas Anderson 	/* If we have a map, we expect to have a syscon */
11963ea4666eSDouglas Anderson 	if (!sdhci_arasan->soc_ctl_base) {
11973ea4666eSDouglas Anderson 		pr_warn("%s: Have regmap, but no soc-ctl-syscon\n",
11983ea4666eSDouglas Anderson 			mmc_hostname(host->mmc));
11993ea4666eSDouglas Anderson 		return;
12003ea4666eSDouglas Anderson 	}
12013ea4666eSDouglas Anderson 
12023ea4666eSDouglas Anderson 	sdhci_arasan_syscon_write(host, &soc_ctl_map->baseclkfreq, mhz);
12033ea4666eSDouglas Anderson }
12043ea4666eSDouglas Anderson 
sdhci_arasan_set_clk_delays(struct sdhci_host * host)1205f3dafc37SManish Narani static void sdhci_arasan_set_clk_delays(struct sdhci_host *host)
1206f3dafc37SManish Narani {
1207f3dafc37SManish Narani 	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
1208f3dafc37SManish Narani 	struct sdhci_arasan_data *sdhci_arasan = sdhci_pltfm_priv(pltfm_host);
1209f3dafc37SManish Narani 	struct sdhci_arasan_clk_data *clk_data = &sdhci_arasan->clk_data;
1210f3dafc37SManish Narani 
1211f3dafc37SManish Narani 	clk_set_phase(clk_data->sampleclk,
1212f3dafc37SManish Narani 		      clk_data->clk_phase_in[host->timing]);
1213f3dafc37SManish Narani 	clk_set_phase(clk_data->sdcardclk,
1214f3dafc37SManish Narani 		      clk_data->clk_phase_out[host->timing]);
1215f3dafc37SManish Narani }
1216f3dafc37SManish Narani 
arasan_dt_read_clk_phase(struct device * dev,struct sdhci_arasan_clk_data * clk_data,unsigned int timing,const char * prop)1217f3dafc37SManish Narani static void arasan_dt_read_clk_phase(struct device *dev,
1218f3dafc37SManish Narani 				     struct sdhci_arasan_clk_data *clk_data,
1219f3dafc37SManish Narani 				     unsigned int timing, const char *prop)
1220f3dafc37SManish Narani {
1221f3dafc37SManish Narani 	struct device_node *np = dev->of_node;
1222f3dafc37SManish Narani 
12234dd7080aSManish Narani 	u32 clk_phase[2] = {0};
12245c7e468aSSai Krishna Potthuri 	int ret;
1225f3dafc37SManish Narani 
1226f3dafc37SManish Narani 	/*
1227f3dafc37SManish Narani 	 * Read Tap Delay values from DT, if the DT does not contain the
1228f3dafc37SManish Narani 	 * Tap Values then use the pre-defined values.
1229f3dafc37SManish Narani 	 */
12305c7e468aSSai Krishna Potthuri 	ret = of_property_read_variable_u32_array(np, prop, &clk_phase[0],
12315c7e468aSSai Krishna Potthuri 						  2, 0);
12325c7e468aSSai Krishna Potthuri 	if (ret < 0) {
1233f3dafc37SManish Narani 		dev_dbg(dev, "Using predefined clock phase for %s = %d %d\n",
1234f3dafc37SManish Narani 			prop, clk_data->clk_phase_in[timing],
1235f3dafc37SManish Narani 			clk_data->clk_phase_out[timing]);
1236f3dafc37SManish Narani 		return;
1237f3dafc37SManish Narani 	}
1238f3dafc37SManish Narani 
1239f3dafc37SManish Narani 	/* The values read are Input and Output Clock Delays in order */
1240f3dafc37SManish Narani 	clk_data->clk_phase_in[timing] = clk_phase[0];
1241f3dafc37SManish Narani 	clk_data->clk_phase_out[timing] = clk_phase[1];
1242f3dafc37SManish Narani }
1243f3dafc37SManish Narani 
1244f3dafc37SManish Narani /**
1245f3dafc37SManish Narani  * arasan_dt_parse_clk_phases - Read Clock Delay values from DT
1246f3dafc37SManish Narani  *
1247f3dafc37SManish Narani  * @dev:		Pointer to our struct device.
1248f3dafc37SManish Narani  * @clk_data:		Pointer to the Clock Data structure
12494908460eSManish Narani  *
12504908460eSManish Narani  * Called at initialization to parse the values of Clock Delays.
1251f3dafc37SManish Narani  */
arasan_dt_parse_clk_phases(struct device * dev,struct sdhci_arasan_clk_data * clk_data)1252f3dafc37SManish Narani static void arasan_dt_parse_clk_phases(struct device *dev,
1253f3dafc37SManish Narani 				       struct sdhci_arasan_clk_data *clk_data)
1254f3dafc37SManish Narani {
1255a5c8b2aeSManish Narani 	u32 mio_bank = 0;
1256a5c8b2aeSManish Narani 	int i;
1257a5c8b2aeSManish Narani 
1258f3dafc37SManish Narani 	/*
1259f3dafc37SManish Narani 	 * This has been kept as a pointer and is assigned a function here.
1260f3dafc37SManish Narani 	 * So that different controller variants can assign their own handling
1261f3dafc37SManish Narani 	 * function.
1262f3dafc37SManish Narani 	 */
1263f3dafc37SManish Narani 	clk_data->set_clk_delays = sdhci_arasan_set_clk_delays;
1264f3dafc37SManish Narani 
1265a5c8b2aeSManish Narani 	if (of_device_is_compatible(dev->of_node, "xlnx,zynqmp-8.9a")) {
126688e1d0b1SManish Narani 		u32 zynqmp_iclk_phase[MMC_TIMING_MMC_HS400 + 1] =
126788e1d0b1SManish Narani 			ZYNQMP_ICLK_PHASE;
126888e1d0b1SManish Narani 		u32 zynqmp_oclk_phase[MMC_TIMING_MMC_HS400 + 1] =
126988e1d0b1SManish Narani 			ZYNQMP_OCLK_PHASE;
1270a5c8b2aeSManish Narani 
1271a5c8b2aeSManish Narani 		of_property_read_u32(dev->of_node, "xlnx,mio-bank", &mio_bank);
1272a5c8b2aeSManish Narani 		if (mio_bank == 2) {
127388e1d0b1SManish Narani 			zynqmp_oclk_phase[MMC_TIMING_UHS_SDR104] = 90;
127488e1d0b1SManish Narani 			zynqmp_oclk_phase[MMC_TIMING_MMC_HS200] = 90;
1275a5c8b2aeSManish Narani 		}
1276a5c8b2aeSManish Narani 
1277a5c8b2aeSManish Narani 		for (i = 0; i <= MMC_TIMING_MMC_HS400; i++) {
127888e1d0b1SManish Narani 			clk_data->clk_phase_in[i] = zynqmp_iclk_phase[i];
127988e1d0b1SManish Narani 			clk_data->clk_phase_out[i] = zynqmp_oclk_phase[i];
1280a5c8b2aeSManish Narani 		}
1281a5c8b2aeSManish Narani 	}
1282a5c8b2aeSManish Narani 
12831a470721SManish Narani 	if (of_device_is_compatible(dev->of_node, "xlnx,versal-8.9a")) {
128488e1d0b1SManish Narani 		u32 versal_iclk_phase[MMC_TIMING_MMC_HS400 + 1] =
128588e1d0b1SManish Narani 			VERSAL_ICLK_PHASE;
128688e1d0b1SManish Narani 		u32 versal_oclk_phase[MMC_TIMING_MMC_HS400 + 1] =
128788e1d0b1SManish Narani 			VERSAL_OCLK_PHASE;
12881a470721SManish Narani 
12891a470721SManish Narani 		for (i = 0; i <= MMC_TIMING_MMC_HS400; i++) {
129088e1d0b1SManish Narani 			clk_data->clk_phase_in[i] = versal_iclk_phase[i];
129188e1d0b1SManish Narani 			clk_data->clk_phase_out[i] = versal_oclk_phase[i];
12921a470721SManish Narani 		}
12931a470721SManish Narani 	}
1294b095f4f5SSwati Agarwal 	if (of_device_is_compatible(dev->of_node, "xlnx,versal-net-emmc")) {
1295b095f4f5SSwati Agarwal 		u32 versal_net_iclk_phase[MMC_TIMING_MMC_HS400 + 1] =
1296b095f4f5SSwati Agarwal 			VERSAL_NET_EMMC_ICLK_PHASE;
1297b095f4f5SSwati Agarwal 		u32 versal_net_oclk_phase[MMC_TIMING_MMC_HS400 + 1] =
1298b095f4f5SSwati Agarwal 			VERSAL_NET_EMMC_OCLK_PHASE;
12991a470721SManish Narani 
1300b095f4f5SSwati Agarwal 		for (i = 0; i <= MMC_TIMING_MMC_HS400; i++) {
1301b095f4f5SSwati Agarwal 			clk_data->clk_phase_in[i] = versal_net_iclk_phase[i];
1302b095f4f5SSwati Agarwal 			clk_data->clk_phase_out[i] = versal_net_oclk_phase[i];
1303b095f4f5SSwati Agarwal 		}
1304b095f4f5SSwati Agarwal 	}
1305f3dafc37SManish Narani 	arasan_dt_read_clk_phase(dev, clk_data, MMC_TIMING_LEGACY,
1306f3dafc37SManish Narani 				 "clk-phase-legacy");
1307f3dafc37SManish Narani 	arasan_dt_read_clk_phase(dev, clk_data, MMC_TIMING_MMC_HS,
1308f3dafc37SManish Narani 				 "clk-phase-mmc-hs");
1309f3dafc37SManish Narani 	arasan_dt_read_clk_phase(dev, clk_data, MMC_TIMING_SD_HS,
1310f3dafc37SManish Narani 				 "clk-phase-sd-hs");
1311f3dafc37SManish Narani 	arasan_dt_read_clk_phase(dev, clk_data, MMC_TIMING_UHS_SDR12,
1312f3dafc37SManish Narani 				 "clk-phase-uhs-sdr12");
1313f3dafc37SManish Narani 	arasan_dt_read_clk_phase(dev, clk_data, MMC_TIMING_UHS_SDR25,
1314f3dafc37SManish Narani 				 "clk-phase-uhs-sdr25");
1315f3dafc37SManish Narani 	arasan_dt_read_clk_phase(dev, clk_data, MMC_TIMING_UHS_SDR50,
1316f3dafc37SManish Narani 				 "clk-phase-uhs-sdr50");
1317f3dafc37SManish Narani 	arasan_dt_read_clk_phase(dev, clk_data, MMC_TIMING_UHS_SDR104,
1318f3dafc37SManish Narani 				 "clk-phase-uhs-sdr104");
1319f3dafc37SManish Narani 	arasan_dt_read_clk_phase(dev, clk_data, MMC_TIMING_UHS_DDR50,
1320f3dafc37SManish Narani 				 "clk-phase-uhs-ddr50");
1321f3dafc37SManish Narani 	arasan_dt_read_clk_phase(dev, clk_data, MMC_TIMING_MMC_DDR52,
1322f3dafc37SManish Narani 				 "clk-phase-mmc-ddr52");
1323f3dafc37SManish Narani 	arasan_dt_read_clk_phase(dev, clk_data, MMC_TIMING_MMC_HS200,
1324f3dafc37SManish Narani 				 "clk-phase-mmc-hs200");
1325f3dafc37SManish Narani 	arasan_dt_read_clk_phase(dev, clk_data, MMC_TIMING_MMC_HS400,
1326f3dafc37SManish Narani 				 "clk-phase-mmc-hs400");
1327f3dafc37SManish Narani }
1328f3dafc37SManish Narani 
132937d3ee7cSManish Narani static const struct sdhci_pltfm_data sdhci_arasan_pdata = {
133037d3ee7cSManish Narani 	.ops = &sdhci_arasan_ops,
133137d3ee7cSManish Narani 	.quirks = SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN,
133237d3ee7cSManish Narani 	.quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN |
133337d3ee7cSManish Narani 			SDHCI_QUIRK2_CLOCK_DIV_ZERO_BROKEN |
133437d3ee7cSManish Narani 			SDHCI_QUIRK2_STOP_WITH_TC,
133537d3ee7cSManish Narani };
133637d3ee7cSManish Narani 
133716ada730SManish Narani static const struct sdhci_arasan_clk_ops arasan_clk_ops = {
133816ada730SManish Narani 	.sdcardclk_ops = &arasan_sdcardclk_ops,
133916ada730SManish Narani 	.sampleclk_ops = &arasan_sampleclk_ops,
134016ada730SManish Narani };
134116ada730SManish Narani 
134237d3ee7cSManish Narani static struct sdhci_arasan_of_data sdhci_arasan_generic_data = {
134337d3ee7cSManish Narani 	.pdata = &sdhci_arasan_pdata,
134416ada730SManish Narani 	.clk_ops = &arasan_clk_ops,
134537d3ee7cSManish Narani };
134637d3ee7cSManish Narani 
134736c6aadaSWan Ahmad Zainie static const struct sdhci_pltfm_data sdhci_keembay_emmc_pdata = {
134836c6aadaSWan Ahmad Zainie 	.ops = &sdhci_arasan_cqe_ops,
134936c6aadaSWan Ahmad Zainie 	.quirks = SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN |
135036c6aadaSWan Ahmad Zainie 		SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC |
135136c6aadaSWan Ahmad Zainie 		SDHCI_QUIRK_NO_LED |
135236c6aadaSWan Ahmad Zainie 		SDHCI_QUIRK_32BIT_DMA_ADDR |
135336c6aadaSWan Ahmad Zainie 		SDHCI_QUIRK_32BIT_DMA_SIZE |
135436c6aadaSWan Ahmad Zainie 		SDHCI_QUIRK_32BIT_ADMA_SIZE,
135536c6aadaSWan Ahmad Zainie 	.quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN |
135636c6aadaSWan Ahmad Zainie 		SDHCI_QUIRK2_CLOCK_DIV_ZERO_BROKEN |
135736c6aadaSWan Ahmad Zainie 		SDHCI_QUIRK2_CAPS_BIT63_FOR_HS400 |
135836c6aadaSWan Ahmad Zainie 		SDHCI_QUIRK2_STOP_WITH_TC |
135936c6aadaSWan Ahmad Zainie 		SDHCI_QUIRK2_BROKEN_64_BIT_DMA,
136036c6aadaSWan Ahmad Zainie };
136136c6aadaSWan Ahmad Zainie 
136236c6aadaSWan Ahmad Zainie static const struct sdhci_pltfm_data sdhci_keembay_sd_pdata = {
136336c6aadaSWan Ahmad Zainie 	.ops = &sdhci_arasan_ops,
136436c6aadaSWan Ahmad Zainie 	.quirks = SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN |
136536c6aadaSWan Ahmad Zainie 		SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC |
136636c6aadaSWan Ahmad Zainie 		SDHCI_QUIRK_NO_LED |
136736c6aadaSWan Ahmad Zainie 		SDHCI_QUIRK_32BIT_DMA_ADDR |
136836c6aadaSWan Ahmad Zainie 		SDHCI_QUIRK_32BIT_DMA_SIZE |
136936c6aadaSWan Ahmad Zainie 		SDHCI_QUIRK_32BIT_ADMA_SIZE,
137036c6aadaSWan Ahmad Zainie 	.quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN |
137136c6aadaSWan Ahmad Zainie 		SDHCI_QUIRK2_CLOCK_DIV_ZERO_BROKEN |
137236c6aadaSWan Ahmad Zainie 		SDHCI_QUIRK2_CARD_ON_NEEDS_BUS_ON |
137336c6aadaSWan Ahmad Zainie 		SDHCI_QUIRK2_STOP_WITH_TC |
137436c6aadaSWan Ahmad Zainie 		SDHCI_QUIRK2_BROKEN_64_BIT_DMA,
137536c6aadaSWan Ahmad Zainie };
137636c6aadaSWan Ahmad Zainie 
137736c6aadaSWan Ahmad Zainie static const struct sdhci_pltfm_data sdhci_keembay_sdio_pdata = {
137836c6aadaSWan Ahmad Zainie 	.ops = &sdhci_arasan_ops,
137936c6aadaSWan Ahmad Zainie 	.quirks = SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN |
138036c6aadaSWan Ahmad Zainie 		SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC |
138136c6aadaSWan Ahmad Zainie 		SDHCI_QUIRK_NO_LED |
138236c6aadaSWan Ahmad Zainie 		SDHCI_QUIRK_32BIT_DMA_ADDR |
138336c6aadaSWan Ahmad Zainie 		SDHCI_QUIRK_32BIT_DMA_SIZE |
138436c6aadaSWan Ahmad Zainie 		SDHCI_QUIRK_32BIT_ADMA_SIZE,
138536c6aadaSWan Ahmad Zainie 	.quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN |
138636c6aadaSWan Ahmad Zainie 		SDHCI_QUIRK2_CLOCK_DIV_ZERO_BROKEN |
138736c6aadaSWan Ahmad Zainie 		SDHCI_QUIRK2_HOST_OFF_CARD_ON |
138836c6aadaSWan Ahmad Zainie 		SDHCI_QUIRK2_BROKEN_64_BIT_DMA,
138936c6aadaSWan Ahmad Zainie };
139036c6aadaSWan Ahmad Zainie 
139137d3ee7cSManish Narani static struct sdhci_arasan_of_data sdhci_arasan_rk3399_data = {
139237d3ee7cSManish Narani 	.soc_ctl_map = &rk3399_soc_ctl_map,
139337d3ee7cSManish Narani 	.pdata = &sdhci_arasan_cqe_pdata,
139416ada730SManish Narani 	.clk_ops = &arasan_clk_ops,
139537d3ee7cSManish Narani };
139637d3ee7cSManish Narani 
139737d3ee7cSManish Narani static struct sdhci_arasan_of_data intel_lgm_emmc_data = {
139837d3ee7cSManish Narani 	.soc_ctl_map = &intel_lgm_emmc_soc_ctl_map,
139937d3ee7cSManish Narani 	.pdata = &sdhci_arasan_cqe_pdata,
140016ada730SManish Narani 	.clk_ops = &arasan_clk_ops,
140137d3ee7cSManish Narani };
140237d3ee7cSManish Narani 
140337d3ee7cSManish Narani static struct sdhci_arasan_of_data intel_lgm_sdxc_data = {
140437d3ee7cSManish Narani 	.soc_ctl_map = &intel_lgm_sdxc_soc_ctl_map,
140537d3ee7cSManish Narani 	.pdata = &sdhci_arasan_cqe_pdata,
140616ada730SManish Narani 	.clk_ops = &arasan_clk_ops,
140737d3ee7cSManish Narani };
140837d3ee7cSManish Narani 
140937d3ee7cSManish Narani static const struct sdhci_pltfm_data sdhci_arasan_zynqmp_pdata = {
141037d3ee7cSManish Narani 	.ops = &sdhci_arasan_ops,
141137d3ee7cSManish Narani 	.quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN |
141237d3ee7cSManish Narani 			SDHCI_QUIRK2_CLOCK_DIV_ZERO_BROKEN |
141337d3ee7cSManish Narani 			SDHCI_QUIRK2_STOP_WITH_TC,
141437d3ee7cSManish Narani };
141537d3ee7cSManish Narani 
1416b095f4f5SSwati Agarwal static const struct sdhci_pltfm_data sdhci_arasan_versal_net_pdata = {
1417b095f4f5SSwati Agarwal 	.ops = &sdhci_arasan_ops,
1418b095f4f5SSwati Agarwal 	.quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN |
1419b095f4f5SSwati Agarwal 			SDHCI_QUIRK2_CLOCK_DIV_ZERO_BROKEN |
1420b095f4f5SSwati Agarwal 			SDHCI_QUIRK2_STOP_WITH_TC |
1421b095f4f5SSwati Agarwal 			SDHCI_QUIRK2_CAPS_BIT63_FOR_HS400,
1422b095f4f5SSwati Agarwal };
1423b095f4f5SSwati Agarwal 
142416ada730SManish Narani static const struct sdhci_arasan_clk_ops zynqmp_clk_ops = {
142516ada730SManish Narani 	.sdcardclk_ops = &zynqmp_sdcardclk_ops,
142616ada730SManish Narani 	.sampleclk_ops = &zynqmp_sampleclk_ops,
142716ada730SManish Narani };
142816ada730SManish Narani 
142937d3ee7cSManish Narani static struct sdhci_arasan_of_data sdhci_arasan_zynqmp_data = {
143037d3ee7cSManish Narani 	.pdata = &sdhci_arasan_zynqmp_pdata,
143116ada730SManish Narani 	.clk_ops = &zynqmp_clk_ops,
143216ada730SManish Narani };
143316ada730SManish Narani 
143416ada730SManish Narani static const struct sdhci_arasan_clk_ops versal_clk_ops = {
143516ada730SManish Narani 	.sdcardclk_ops = &versal_sdcardclk_ops,
143616ada730SManish Narani 	.sampleclk_ops = &versal_sampleclk_ops,
143737d3ee7cSManish Narani };
143837d3ee7cSManish Narani 
143937d3ee7cSManish Narani static struct sdhci_arasan_of_data sdhci_arasan_versal_data = {
144037d3ee7cSManish Narani 	.pdata = &sdhci_arasan_zynqmp_pdata,
144116ada730SManish Narani 	.clk_ops = &versal_clk_ops,
144237d3ee7cSManish Narani };
144337d3ee7cSManish Narani 
1444b095f4f5SSwati Agarwal static const struct sdhci_arasan_clk_ops versal_net_clk_ops = {
1445b095f4f5SSwati Agarwal 	.sdcardclk_ops = &versal_net_sdcardclk_ops,
1446b095f4f5SSwati Agarwal 	.sampleclk_ops = &versal_net_sampleclk_ops,
1447b095f4f5SSwati Agarwal };
1448b095f4f5SSwati Agarwal 
1449b095f4f5SSwati Agarwal static struct sdhci_arasan_of_data sdhci_arasan_versal_net_data = {
1450b095f4f5SSwati Agarwal 	.pdata = &sdhci_arasan_versal_net_pdata,
1451b095f4f5SSwati Agarwal 	.clk_ops = &versal_net_clk_ops,
1452b095f4f5SSwati Agarwal };
1453b095f4f5SSwati Agarwal 
145436c6aadaSWan Ahmad Zainie static struct sdhci_arasan_of_data intel_keembay_emmc_data = {
145536c6aadaSWan Ahmad Zainie 	.soc_ctl_map = &intel_keembay_soc_ctl_map,
145636c6aadaSWan Ahmad Zainie 	.pdata = &sdhci_keembay_emmc_pdata,
1457a42a7ec9SMuhammad Husaini Zulkifli 	.clk_ops = &arasan_clk_ops,
145836c6aadaSWan Ahmad Zainie };
145936c6aadaSWan Ahmad Zainie 
146036c6aadaSWan Ahmad Zainie static struct sdhci_arasan_of_data intel_keembay_sd_data = {
146136c6aadaSWan Ahmad Zainie 	.soc_ctl_map = &intel_keembay_soc_ctl_map,
146236c6aadaSWan Ahmad Zainie 	.pdata = &sdhci_keembay_sd_pdata,
1463a42a7ec9SMuhammad Husaini Zulkifli 	.clk_ops = &arasan_clk_ops,
146436c6aadaSWan Ahmad Zainie };
146536c6aadaSWan Ahmad Zainie 
146636c6aadaSWan Ahmad Zainie static struct sdhci_arasan_of_data intel_keembay_sdio_data = {
146736c6aadaSWan Ahmad Zainie 	.soc_ctl_map = &intel_keembay_soc_ctl_map,
146836c6aadaSWan Ahmad Zainie 	.pdata = &sdhci_keembay_sdio_pdata,
1469a42a7ec9SMuhammad Husaini Zulkifli 	.clk_ops = &arasan_clk_ops,
147036c6aadaSWan Ahmad Zainie };
147136c6aadaSWan Ahmad Zainie 
147237d3ee7cSManish Narani static const struct of_device_id sdhci_arasan_of_match[] = {
147337d3ee7cSManish Narani 	/* SoC-specific compatible strings w/ soc_ctl_map */
147437d3ee7cSManish Narani 	{
147537d3ee7cSManish Narani 		.compatible = "rockchip,rk3399-sdhci-5.1",
147637d3ee7cSManish Narani 		.data = &sdhci_arasan_rk3399_data,
147737d3ee7cSManish Narani 	},
147837d3ee7cSManish Narani 	{
147937d3ee7cSManish Narani 		.compatible = "intel,lgm-sdhci-5.1-emmc",
148037d3ee7cSManish Narani 		.data = &intel_lgm_emmc_data,
148137d3ee7cSManish Narani 	},
148237d3ee7cSManish Narani 	{
148337d3ee7cSManish Narani 		.compatible = "intel,lgm-sdhci-5.1-sdxc",
148437d3ee7cSManish Narani 		.data = &intel_lgm_sdxc_data,
148537d3ee7cSManish Narani 	},
148636c6aadaSWan Ahmad Zainie 	{
148736c6aadaSWan Ahmad Zainie 		.compatible = "intel,keembay-sdhci-5.1-emmc",
148836c6aadaSWan Ahmad Zainie 		.data = &intel_keembay_emmc_data,
148936c6aadaSWan Ahmad Zainie 	},
149036c6aadaSWan Ahmad Zainie 	{
149136c6aadaSWan Ahmad Zainie 		.compatible = "intel,keembay-sdhci-5.1-sd",
149236c6aadaSWan Ahmad Zainie 		.data = &intel_keembay_sd_data,
149336c6aadaSWan Ahmad Zainie 	},
149436c6aadaSWan Ahmad Zainie 	{
149536c6aadaSWan Ahmad Zainie 		.compatible = "intel,keembay-sdhci-5.1-sdio",
149636c6aadaSWan Ahmad Zainie 		.data = &intel_keembay_sdio_data,
149736c6aadaSWan Ahmad Zainie 	},
149837d3ee7cSManish Narani 	/* Generic compatible below here */
149937d3ee7cSManish Narani 	{
150037d3ee7cSManish Narani 		.compatible = "arasan,sdhci-8.9a",
150137d3ee7cSManish Narani 		.data = &sdhci_arasan_generic_data,
150237d3ee7cSManish Narani 	},
150337d3ee7cSManish Narani 	{
150437d3ee7cSManish Narani 		.compatible = "arasan,sdhci-5.1",
150537d3ee7cSManish Narani 		.data = &sdhci_arasan_generic_data,
150637d3ee7cSManish Narani 	},
150737d3ee7cSManish Narani 	{
150837d3ee7cSManish Narani 		.compatible = "arasan,sdhci-4.9a",
150937d3ee7cSManish Narani 		.data = &sdhci_arasan_generic_data,
151037d3ee7cSManish Narani 	},
151137d3ee7cSManish Narani 	{
151237d3ee7cSManish Narani 		.compatible = "xlnx,zynqmp-8.9a",
151337d3ee7cSManish Narani 		.data = &sdhci_arasan_zynqmp_data,
151437d3ee7cSManish Narani 	},
151537d3ee7cSManish Narani 	{
151637d3ee7cSManish Narani 		.compatible = "xlnx,versal-8.9a",
151737d3ee7cSManish Narani 		.data = &sdhci_arasan_versal_data,
151837d3ee7cSManish Narani 	},
1519b095f4f5SSwati Agarwal 	{
1520b095f4f5SSwati Agarwal 		.compatible = "xlnx,versal-net-emmc",
1521b095f4f5SSwati Agarwal 		.data = &sdhci_arasan_versal_net_data,
1522b095f4f5SSwati Agarwal 	},
152337d3ee7cSManish Narani 	{ /* sentinel */ }
152437d3ee7cSManish Narani };
152537d3ee7cSManish Narani MODULE_DEVICE_TABLE(of, sdhci_arasan_of_match);
152637d3ee7cSManish Narani 
1527c390f211SDouglas Anderson /**
152807a14d1dSManish Narani  * sdhci_arasan_register_sdcardclk - Register the sdcardclk for a PHY to use
1529c390f211SDouglas Anderson  *
15304908460eSManish Narani  * @sdhci_arasan:	Our private data structure.
15314908460eSManish Narani  * @clk_xin:		Pointer to the functional clock
15324908460eSManish Narani  * @dev:		Pointer to our struct device.
15334908460eSManish Narani  *
1534c390f211SDouglas Anderson  * Some PHY devices need to know what the actual card clock is.  In order for
1535c390f211SDouglas Anderson  * them to find out, we'll provide a clock through the common clock framework
1536c390f211SDouglas Anderson  * for them to query.
1537c390f211SDouglas Anderson  *
15384908460eSManish Narani  * Return: 0 on success and error value on error
1539c390f211SDouglas Anderson  */
154007a14d1dSManish Narani static int
sdhci_arasan_register_sdcardclk(struct sdhci_arasan_data * sdhci_arasan,struct clk * clk_xin,struct device * dev)154107a14d1dSManish Narani sdhci_arasan_register_sdcardclk(struct sdhci_arasan_data *sdhci_arasan,
1542c390f211SDouglas Anderson 				struct clk *clk_xin,
1543c390f211SDouglas Anderson 				struct device *dev)
1544c390f211SDouglas Anderson {
1545e1463618SManish Narani 	struct sdhci_arasan_clk_data *clk_data = &sdhci_arasan->clk_data;
1546c390f211SDouglas Anderson 	struct device_node *np = dev->of_node;
1547c390f211SDouglas Anderson 	struct clk_init_data sdcardclk_init;
1548c390f211SDouglas Anderson 	const char *parent_clk_name;
1549c390f211SDouglas Anderson 	int ret;
1550c390f211SDouglas Anderson 
1551c390f211SDouglas Anderson 	ret = of_property_read_string_index(np, "clock-output-names", 0,
1552c390f211SDouglas Anderson 					    &sdcardclk_init.name);
1553c390f211SDouglas Anderson 	if (ret) {
1554c390f211SDouglas Anderson 		dev_err(dev, "DT has #clock-cells but no clock-output-names\n");
1555c390f211SDouglas Anderson 		return ret;
1556c390f211SDouglas Anderson 	}
1557c390f211SDouglas Anderson 
1558c390f211SDouglas Anderson 	parent_clk_name = __clk_get_name(clk_xin);
1559c390f211SDouglas Anderson 	sdcardclk_init.parent_names = &parent_clk_name;
1560c390f211SDouglas Anderson 	sdcardclk_init.num_parents = 1;
1561c390f211SDouglas Anderson 	sdcardclk_init.flags = CLK_GET_RATE_NOCACHE;
156216ada730SManish Narani 	sdcardclk_init.ops = sdhci_arasan->clk_ops->sdcardclk_ops;
1563c390f211SDouglas Anderson 
1564e1463618SManish Narani 	clk_data->sdcardclk_hw.init = &sdcardclk_init;
1565e1463618SManish Narani 	clk_data->sdcardclk =
1566e1463618SManish Narani 		devm_clk_register(dev, &clk_data->sdcardclk_hw);
1567c99e1d0cSChuhong Yuan 	if (IS_ERR(clk_data->sdcardclk))
1568c99e1d0cSChuhong Yuan 		return PTR_ERR(clk_data->sdcardclk);
1569e1463618SManish Narani 	clk_data->sdcardclk_hw.init = NULL;
1570c390f211SDouglas Anderson 
1571c390f211SDouglas Anderson 	ret = of_clk_add_provider(np, of_clk_src_simple_get,
1572e1463618SManish Narani 				  clk_data->sdcardclk);
1573c390f211SDouglas Anderson 	if (ret)
157407a14d1dSManish Narani 		dev_err(dev, "Failed to add sdcard clock provider\n");
157507a14d1dSManish Narani 
157607a14d1dSManish Narani 	return ret;
157707a14d1dSManish Narani }
157807a14d1dSManish Narani 
157907a14d1dSManish Narani /**
158007a14d1dSManish Narani  * sdhci_arasan_register_sampleclk - Register the sampleclk for a PHY to use
158107a14d1dSManish Narani  *
15824908460eSManish Narani  * @sdhci_arasan:	Our private data structure.
15834908460eSManish Narani  * @clk_xin:		Pointer to the functional clock
15844908460eSManish Narani  * @dev:		Pointer to our struct device.
15854908460eSManish Narani  *
158607a14d1dSManish Narani  * Some PHY devices need to know what the actual card clock is.  In order for
158707a14d1dSManish Narani  * them to find out, we'll provide a clock through the common clock framework
158807a14d1dSManish Narani  * for them to query.
158907a14d1dSManish Narani  *
15904908460eSManish Narani  * Return: 0 on success and error value on error
159107a14d1dSManish Narani  */
159207a14d1dSManish Narani static int
sdhci_arasan_register_sampleclk(struct sdhci_arasan_data * sdhci_arasan,struct clk * clk_xin,struct device * dev)159307a14d1dSManish Narani sdhci_arasan_register_sampleclk(struct sdhci_arasan_data *sdhci_arasan,
159407a14d1dSManish Narani 				struct clk *clk_xin,
159507a14d1dSManish Narani 				struct device *dev)
159607a14d1dSManish Narani {
159707a14d1dSManish Narani 	struct sdhci_arasan_clk_data *clk_data = &sdhci_arasan->clk_data;
159807a14d1dSManish Narani 	struct device_node *np = dev->of_node;
159907a14d1dSManish Narani 	struct clk_init_data sampleclk_init;
160007a14d1dSManish Narani 	const char *parent_clk_name;
160107a14d1dSManish Narani 	int ret;
160207a14d1dSManish Narani 
160307a14d1dSManish Narani 	ret = of_property_read_string_index(np, "clock-output-names", 1,
160407a14d1dSManish Narani 					    &sampleclk_init.name);
160507a14d1dSManish Narani 	if (ret) {
160607a14d1dSManish Narani 		dev_err(dev, "DT has #clock-cells but no clock-output-names\n");
160707a14d1dSManish Narani 		return ret;
160807a14d1dSManish Narani 	}
160907a14d1dSManish Narani 
161007a14d1dSManish Narani 	parent_clk_name = __clk_get_name(clk_xin);
161107a14d1dSManish Narani 	sampleclk_init.parent_names = &parent_clk_name;
161207a14d1dSManish Narani 	sampleclk_init.num_parents = 1;
161307a14d1dSManish Narani 	sampleclk_init.flags = CLK_GET_RATE_NOCACHE;
161416ada730SManish Narani 	sampleclk_init.ops = sdhci_arasan->clk_ops->sampleclk_ops;
161507a14d1dSManish Narani 
161607a14d1dSManish Narani 	clk_data->sampleclk_hw.init = &sampleclk_init;
161707a14d1dSManish Narani 	clk_data->sampleclk =
161807a14d1dSManish Narani 		devm_clk_register(dev, &clk_data->sampleclk_hw);
1619c99e1d0cSChuhong Yuan 	if (IS_ERR(clk_data->sampleclk))
1620c99e1d0cSChuhong Yuan 		return PTR_ERR(clk_data->sampleclk);
162107a14d1dSManish Narani 	clk_data->sampleclk_hw.init = NULL;
162207a14d1dSManish Narani 
162307a14d1dSManish Narani 	ret = of_clk_add_provider(np, of_clk_src_simple_get,
162407a14d1dSManish Narani 				  clk_data->sampleclk);
162507a14d1dSManish Narani 	if (ret)
162607a14d1dSManish Narani 		dev_err(dev, "Failed to add sample clock provider\n");
1627c390f211SDouglas Anderson 
1628c390f211SDouglas Anderson 	return ret;
1629c390f211SDouglas Anderson }
1630c390f211SDouglas Anderson 
1631c390f211SDouglas Anderson /**
1632c390f211SDouglas Anderson  * sdhci_arasan_unregister_sdclk - Undoes sdhci_arasan_register_sdclk()
1633c390f211SDouglas Anderson  *
16344908460eSManish Narani  * @dev:		Pointer to our struct device.
16354908460eSManish Narani  *
1636c390f211SDouglas Anderson  * Should be called any time we're exiting and sdhci_arasan_register_sdclk()
1637c390f211SDouglas Anderson  * returned success.
1638c390f211SDouglas Anderson  */
sdhci_arasan_unregister_sdclk(struct device * dev)1639c390f211SDouglas Anderson static void sdhci_arasan_unregister_sdclk(struct device *dev)
1640c390f211SDouglas Anderson {
1641c390f211SDouglas Anderson 	struct device_node *np = dev->of_node;
1642c390f211SDouglas Anderson 
164366756ca3SRob Herring 	if (!of_property_present(np, "#clock-cells"))
1644c390f211SDouglas Anderson 		return;
1645c390f211SDouglas Anderson 
1646c390f211SDouglas Anderson 	of_clk_del_provider(dev->of_node);
1647c390f211SDouglas Anderson }
1648c390f211SDouglas Anderson 
164907a14d1dSManish Narani /**
165036c6aadaSWan Ahmad Zainie  * sdhci_arasan_update_support64b - Set SUPPORT_64B (64-bit System Bus Support)
1651973c7c99SMuhammad Husaini Zulkifli  * @host:		The sdhci_host
1652973c7c99SMuhammad Husaini Zulkifli  * @value:		The value to write
165336c6aadaSWan Ahmad Zainie  *
165436c6aadaSWan Ahmad Zainie  * This should be set based on the System Address Bus.
165536c6aadaSWan Ahmad Zainie  * 0: the Core supports only 32-bit System Address Bus.
165636c6aadaSWan Ahmad Zainie  * 1: the Core supports 64-bit System Address Bus.
165736c6aadaSWan Ahmad Zainie  *
1658973c7c99SMuhammad Husaini Zulkifli  * NOTE:
1659973c7c99SMuhammad Husaini Zulkifli  * For Keem Bay, it is required to clear this bit. Its default value is 1'b1.
166036c6aadaSWan Ahmad Zainie  * Keem Bay does not support 64-bit access.
166136c6aadaSWan Ahmad Zainie  */
sdhci_arasan_update_support64b(struct sdhci_host * host,u32 value)166236c6aadaSWan Ahmad Zainie static void sdhci_arasan_update_support64b(struct sdhci_host *host, u32 value)
166336c6aadaSWan Ahmad Zainie {
166436c6aadaSWan Ahmad Zainie 	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
166536c6aadaSWan Ahmad Zainie 	struct sdhci_arasan_data *sdhci_arasan = sdhci_pltfm_priv(pltfm_host);
1666db845093SMuhammad Husaini Zulkifli 	const struct sdhci_arasan_soc_ctl_map *soc_ctl_map;
166736c6aadaSWan Ahmad Zainie 
166836c6aadaSWan Ahmad Zainie 	/* Having a map is optional */
1669db845093SMuhammad Husaini Zulkifli 	soc_ctl_map = sdhci_arasan->soc_ctl_map;
167036c6aadaSWan Ahmad Zainie 	if (!soc_ctl_map)
167136c6aadaSWan Ahmad Zainie 		return;
167236c6aadaSWan Ahmad Zainie 
167336c6aadaSWan Ahmad Zainie 	/* If we have a map, we expect to have a syscon */
167436c6aadaSWan Ahmad Zainie 	if (!sdhci_arasan->soc_ctl_base) {
167536c6aadaSWan Ahmad Zainie 		pr_warn("%s: Have regmap, but no soc-ctl-syscon\n",
167636c6aadaSWan Ahmad Zainie 			mmc_hostname(host->mmc));
167736c6aadaSWan Ahmad Zainie 		return;
167836c6aadaSWan Ahmad Zainie 	}
167936c6aadaSWan Ahmad Zainie 
168036c6aadaSWan Ahmad Zainie 	sdhci_arasan_syscon_write(host, &soc_ctl_map->support64b, value);
168136c6aadaSWan Ahmad Zainie }
168236c6aadaSWan Ahmad Zainie 
168336c6aadaSWan Ahmad Zainie /**
168407a14d1dSManish Narani  * sdhci_arasan_register_sdclk - Register the sdcardclk for a PHY to use
168507a14d1dSManish Narani  *
16864908460eSManish Narani  * @sdhci_arasan:	Our private data structure.
16874908460eSManish Narani  * @clk_xin:		Pointer to the functional clock
16884908460eSManish Narani  * @dev:		Pointer to our struct device.
16894908460eSManish Narani  *
169007a14d1dSManish Narani  * Some PHY devices need to know what the actual card clock is.  In order for
169107a14d1dSManish Narani  * them to find out, we'll provide a clock through the common clock framework
169207a14d1dSManish Narani  * for them to query.
169307a14d1dSManish Narani  *
169407a14d1dSManish Narani  * Note: without seriously re-architecting SDHCI's clock code and testing on
169507a14d1dSManish Narani  * all platforms, there's no way to create a totally beautiful clock here
169607a14d1dSManish Narani  * with all clock ops implemented.  Instead, we'll just create a clock that can
169707a14d1dSManish Narani  * be queried and set the CLK_GET_RATE_NOCACHE attribute to tell common clock
169807a14d1dSManish Narani  * framework that we're doing things behind its back.  This should be sufficient
169907a14d1dSManish Narani  * to create nice clean device tree bindings and later (if needed) we can try
170007a14d1dSManish Narani  * re-architecting SDHCI if we see some benefit to it.
170107a14d1dSManish Narani  *
17024908460eSManish Narani  * Return: 0 on success and error value on error
170307a14d1dSManish Narani  */
sdhci_arasan_register_sdclk(struct sdhci_arasan_data * sdhci_arasan,struct clk * clk_xin,struct device * dev)170407a14d1dSManish Narani static int sdhci_arasan_register_sdclk(struct sdhci_arasan_data *sdhci_arasan,
170507a14d1dSManish Narani 				       struct clk *clk_xin,
170607a14d1dSManish Narani 				       struct device *dev)
170707a14d1dSManish Narani {
170807a14d1dSManish Narani 	struct device_node *np = dev->of_node;
170907a14d1dSManish Narani 	u32 num_clks = 0;
171007a14d1dSManish Narani 	int ret;
171107a14d1dSManish Narani 
171207a14d1dSManish Narani 	/* Providing a clock to the PHY is optional; no error if missing */
171307a14d1dSManish Narani 	if (of_property_read_u32(np, "#clock-cells", &num_clks) < 0)
171407a14d1dSManish Narani 		return 0;
171507a14d1dSManish Narani 
171607a14d1dSManish Narani 	ret = sdhci_arasan_register_sdcardclk(sdhci_arasan, clk_xin, dev);
171707a14d1dSManish Narani 	if (ret)
171807a14d1dSManish Narani 		return ret;
171907a14d1dSManish Narani 
172007a14d1dSManish Narani 	if (num_clks) {
172107a14d1dSManish Narani 		ret = sdhci_arasan_register_sampleclk(sdhci_arasan, clk_xin,
172207a14d1dSManish Narani 						      dev);
172307a14d1dSManish Narani 		if (ret) {
172407a14d1dSManish Narani 			sdhci_arasan_unregister_sdclk(dev);
172507a14d1dSManish Narani 			return ret;
172607a14d1dSManish Narani 		}
172707a14d1dSManish Narani 	}
172807a14d1dSManish Narani 
172907a14d1dSManish Narani 	return 0;
173007a14d1dSManish Narani }
173107a14d1dSManish Narani 
sdhci_zynqmp_set_dynamic_config(struct device * dev,struct sdhci_arasan_data * sdhci_arasan)17320614b0aeSSai Krishna Potthuri static int sdhci_zynqmp_set_dynamic_config(struct device *dev,
17330614b0aeSSai Krishna Potthuri 					   struct sdhci_arasan_data *sdhci_arasan)
17340614b0aeSSai Krishna Potthuri {
17350614b0aeSSai Krishna Potthuri 	struct sdhci_host *host = sdhci_arasan->host;
17360614b0aeSSai Krishna Potthuri 	struct clk_hw *hw = &sdhci_arasan->clk_data.sdcardclk_hw;
17370614b0aeSSai Krishna Potthuri 	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
17380614b0aeSSai Krishna Potthuri 	const char *clk_name = clk_hw_get_name(hw);
17390614b0aeSSai Krishna Potthuri 	u32 mhz, node_id = !strcmp(clk_name, "clk_out_sd0") ? NODE_SD_0 : NODE_SD_1;
17400614b0aeSSai Krishna Potthuri 	struct reset_control *rstc;
17410614b0aeSSai Krishna Potthuri 	int ret;
17420614b0aeSSai Krishna Potthuri 
17430614b0aeSSai Krishna Potthuri 	/* Obtain SDHC reset control */
17440614b0aeSSai Krishna Potthuri 	rstc = devm_reset_control_get_optional_exclusive(dev, NULL);
17450614b0aeSSai Krishna Potthuri 	if (IS_ERR(rstc)) {
17460614b0aeSSai Krishna Potthuri 		dev_err(dev, "Cannot get SDHC reset.\n");
17470614b0aeSSai Krishna Potthuri 		return PTR_ERR(rstc);
17480614b0aeSSai Krishna Potthuri 	}
17490614b0aeSSai Krishna Potthuri 
17500614b0aeSSai Krishna Potthuri 	ret = reset_control_assert(rstc);
17510614b0aeSSai Krishna Potthuri 	if (ret)
17520614b0aeSSai Krishna Potthuri 		return ret;
17530614b0aeSSai Krishna Potthuri 
17540614b0aeSSai Krishna Potthuri 	ret = zynqmp_pm_set_sd_config(node_id, SD_CONFIG_FIXED, 0);
17550614b0aeSSai Krishna Potthuri 	if (ret)
17560614b0aeSSai Krishna Potthuri 		return ret;
17570614b0aeSSai Krishna Potthuri 
17580614b0aeSSai Krishna Potthuri 	ret = zynqmp_pm_set_sd_config(node_id, SD_CONFIG_EMMC_SEL,
17590614b0aeSSai Krishna Potthuri 				      !!(host->mmc->caps & MMC_CAP_NONREMOVABLE));
17600614b0aeSSai Krishna Potthuri 	if (ret)
17610614b0aeSSai Krishna Potthuri 		return ret;
17620614b0aeSSai Krishna Potthuri 
17630614b0aeSSai Krishna Potthuri 	mhz = DIV_ROUND_CLOSEST_ULL(clk_get_rate(pltfm_host->clk), 1000000);
17640614b0aeSSai Krishna Potthuri 	if (mhz > 100 && mhz <= 200)
17650614b0aeSSai Krishna Potthuri 		mhz = 200;
17660614b0aeSSai Krishna Potthuri 	else if (mhz > 50 && mhz <= 100)
17670614b0aeSSai Krishna Potthuri 		mhz = 100;
17680614b0aeSSai Krishna Potthuri 	else if (mhz > 25 && mhz <= 50)
17690614b0aeSSai Krishna Potthuri 		mhz = 50;
17700614b0aeSSai Krishna Potthuri 	else
17710614b0aeSSai Krishna Potthuri 		mhz = 25;
17720614b0aeSSai Krishna Potthuri 
17730614b0aeSSai Krishna Potthuri 	ret = zynqmp_pm_set_sd_config(node_id, SD_CONFIG_BASECLK, mhz);
17740614b0aeSSai Krishna Potthuri 	if (ret)
17750614b0aeSSai Krishna Potthuri 		return ret;
17760614b0aeSSai Krishna Potthuri 
17770614b0aeSSai Krishna Potthuri 	ret = zynqmp_pm_set_sd_config(node_id, SD_CONFIG_8BIT,
17780614b0aeSSai Krishna Potthuri 				      !!(host->mmc->caps & MMC_CAP_8_BIT_DATA));
17790614b0aeSSai Krishna Potthuri 	if (ret)
17800614b0aeSSai Krishna Potthuri 		return ret;
17810614b0aeSSai Krishna Potthuri 
17820614b0aeSSai Krishna Potthuri 	ret = reset_control_deassert(rstc);
17830614b0aeSSai Krishna Potthuri 	if (ret)
17840614b0aeSSai Krishna Potthuri 		return ret;
17850614b0aeSSai Krishna Potthuri 
17860614b0aeSSai Krishna Potthuri 	usleep_range(1000, 1500);
17870614b0aeSSai Krishna Potthuri 
17880614b0aeSSai Krishna Potthuri 	return 0;
17890614b0aeSSai Krishna Potthuri }
17900614b0aeSSai Krishna Potthuri 
sdhci_arasan_add_host(struct sdhci_arasan_data * sdhci_arasan)179184362d79SShawn Lin static int sdhci_arasan_add_host(struct sdhci_arasan_data *sdhci_arasan)
179284362d79SShawn Lin {
179384362d79SShawn Lin 	struct sdhci_host *host = sdhci_arasan->host;
179484362d79SShawn Lin 	struct cqhci_host *cq_host;
179584362d79SShawn Lin 	bool dma64;
179684362d79SShawn Lin 	int ret;
179784362d79SShawn Lin 
179884362d79SShawn Lin 	if (!sdhci_arasan->has_cqe)
179984362d79SShawn Lin 		return sdhci_add_host(host);
180084362d79SShawn Lin 
180184362d79SShawn Lin 	ret = sdhci_setup_host(host);
180284362d79SShawn Lin 	if (ret)
180384362d79SShawn Lin 		return ret;
180484362d79SShawn Lin 
180584362d79SShawn Lin 	cq_host = devm_kzalloc(host->mmc->parent,
180684362d79SShawn Lin 			       sizeof(*cq_host), GFP_KERNEL);
180784362d79SShawn Lin 	if (!cq_host) {
180884362d79SShawn Lin 		ret = -ENOMEM;
180984362d79SShawn Lin 		goto cleanup;
181084362d79SShawn Lin 	}
181184362d79SShawn Lin 
181284362d79SShawn Lin 	cq_host->mmio = host->ioaddr + SDHCI_ARASAN_CQE_BASE_ADDR;
181384362d79SShawn Lin 	cq_host->ops = &sdhci_arasan_cqhci_ops;
181484362d79SShawn Lin 
181584362d79SShawn Lin 	dma64 = host->flags & SDHCI_USE_64_BIT_DMA;
181684362d79SShawn Lin 	if (dma64)
181784362d79SShawn Lin 		cq_host->caps |= CQHCI_TASK_DESC_SZ_128;
181884362d79SShawn Lin 
181984362d79SShawn Lin 	ret = cqhci_init(cq_host, host->mmc, dma64);
182084362d79SShawn Lin 	if (ret)
182184362d79SShawn Lin 		goto cleanup;
182284362d79SShawn Lin 
182384362d79SShawn Lin 	ret = __sdhci_add_host(host);
182484362d79SShawn Lin 	if (ret)
182584362d79SShawn Lin 		goto cleanup;
182684362d79SShawn Lin 
182784362d79SShawn Lin 	return 0;
182884362d79SShawn Lin 
182984362d79SShawn Lin cleanup:
183084362d79SShawn Lin 	sdhci_cleanup_host(host);
183184362d79SShawn Lin 	return ret;
183284362d79SShawn Lin }
183384362d79SShawn Lin 
sdhci_arasan_probe(struct platform_device * pdev)1834e3ec3a3dSSoren Brinkmann static int sdhci_arasan_probe(struct platform_device *pdev)
1835e3ec3a3dSSoren Brinkmann {
1836e3ec3a3dSSoren Brinkmann 	int ret;
18373ea4666eSDouglas Anderson 	struct device_node *node;
1838e3ec3a3dSSoren Brinkmann 	struct clk *clk_xin;
18394453d51eSSwati Agarwal 	struct clk *clk_dll;
1840e3ec3a3dSSoren Brinkmann 	struct sdhci_host *host;
1841e3ec3a3dSSoren Brinkmann 	struct sdhci_pltfm_host *pltfm_host;
18422ff0b85dSMuhammad Husaini Zulkifli 	struct device *dev = &pdev->dev;
18432ff0b85dSMuhammad Husaini Zulkifli 	struct device_node *np = dev->of_node;
1844e3ec3a3dSSoren Brinkmann 	struct sdhci_arasan_data *sdhci_arasan;
184506b23ca0SFaiz Abbas 	const struct sdhci_arasan_of_data *data;
1846e3ec3a3dSSoren Brinkmann 
18472ff0b85dSMuhammad Husaini Zulkifli 	data = of_device_get_match_data(dev);
1848ded2c4c3SSai Krishna Potthuri 	if (!data)
1849ded2c4c3SSai Krishna Potthuri 		return -EINVAL;
1850ded2c4c3SSai Krishna Potthuri 
185106b23ca0SFaiz Abbas 	host = sdhci_pltfm_init(pdev, data->pdata, sizeof(*sdhci_arasan));
185284362d79SShawn Lin 
185389211418SJisheng Zhang 	if (IS_ERR(host))
185489211418SJisheng Zhang 		return PTR_ERR(host);
185589211418SJisheng Zhang 
185689211418SJisheng Zhang 	pltfm_host = sdhci_priv(host);
185789211418SJisheng Zhang 	sdhci_arasan = sdhci_pltfm_priv(pltfm_host);
1858c390f211SDouglas Anderson 	sdhci_arasan->host = host;
1859e3ec3a3dSSoren Brinkmann 
186006b23ca0SFaiz Abbas 	sdhci_arasan->soc_ctl_map = data->soc_ctl_map;
186116ada730SManish Narani 	sdhci_arasan->clk_ops = data->clk_ops;
18623ea4666eSDouglas Anderson 
186380d41efeSMuhammad Husaini Zulkifli 	node = of_parse_phandle(np, "arasan,soc-ctl-syscon", 0);
18643ea4666eSDouglas Anderson 	if (node) {
18653ea4666eSDouglas Anderson 		sdhci_arasan->soc_ctl_base = syscon_node_to_regmap(node);
18663ea4666eSDouglas Anderson 		of_node_put(node);
18673ea4666eSDouglas Anderson 
18683ea4666eSDouglas Anderson 		if (IS_ERR(sdhci_arasan->soc_ctl_base)) {
18692ff0b85dSMuhammad Husaini Zulkifli 			ret = dev_err_probe(dev,
187072ea817dSKrzysztof Kozlowski 					    PTR_ERR(sdhci_arasan->soc_ctl_base),
187172ea817dSKrzysztof Kozlowski 					    "Can't get syscon\n");
18723ea4666eSDouglas Anderson 			goto err_pltfm_free;
18733ea4666eSDouglas Anderson 		}
18743ea4666eSDouglas Anderson 	}
18753ea4666eSDouglas Anderson 
1876b2af3227SRashmi A 	sdhci_get_of_property(pdev);
1877b2af3227SRashmi A 
18782ff0b85dSMuhammad Husaini Zulkifli 	sdhci_arasan->clk_ahb = devm_clk_get(dev, "clk_ahb");
1879e3ec3a3dSSoren Brinkmann 	if (IS_ERR(sdhci_arasan->clk_ahb)) {
1880ffd68f35SMuhammad Husaini Zulkifli 		ret = dev_err_probe(dev, PTR_ERR(sdhci_arasan->clk_ahb),
1881ffd68f35SMuhammad Husaini Zulkifli 				    "clk_ahb clock not found.\n");
1882278d0962SShawn Lin 		goto err_pltfm_free;
1883e3ec3a3dSSoren Brinkmann 	}
1884e3ec3a3dSSoren Brinkmann 
18852ff0b85dSMuhammad Husaini Zulkifli 	clk_xin = devm_clk_get(dev, "clk_xin");
1886e3ec3a3dSSoren Brinkmann 	if (IS_ERR(clk_xin)) {
1887ffd68f35SMuhammad Husaini Zulkifli 		ret = dev_err_probe(dev, PTR_ERR(clk_xin), "clk_xin clock not found.\n");
1888278d0962SShawn Lin 		goto err_pltfm_free;
1889e3ec3a3dSSoren Brinkmann 	}
1890e3ec3a3dSSoren Brinkmann 
1891e3ec3a3dSSoren Brinkmann 	ret = clk_prepare_enable(sdhci_arasan->clk_ahb);
1892e3ec3a3dSSoren Brinkmann 	if (ret) {
18932ff0b85dSMuhammad Husaini Zulkifli 		dev_err(dev, "Unable to enable AHB clock.\n");
1894278d0962SShawn Lin 		goto err_pltfm_free;
1895e3ec3a3dSSoren Brinkmann 	}
1896e3ec3a3dSSoren Brinkmann 
1897b2af3227SRashmi A 	/* If clock-frequency property is set, use the provided value */
1898b2af3227SRashmi A 	if (pltfm_host->clock &&
1899b2af3227SRashmi A 	    pltfm_host->clock != clk_get_rate(clk_xin)) {
1900b2af3227SRashmi A 		ret = clk_set_rate(clk_xin, pltfm_host->clock);
1901b2af3227SRashmi A 		if (ret) {
1902b2af3227SRashmi A 			dev_err(&pdev->dev, "Failed to set SD clock rate\n");
1903b2af3227SRashmi A 			goto clk_dis_ahb;
1904b2af3227SRashmi A 		}
1905b2af3227SRashmi A 	}
1906b2af3227SRashmi A 
1907e3ec3a3dSSoren Brinkmann 	ret = clk_prepare_enable(clk_xin);
1908e3ec3a3dSSoren Brinkmann 	if (ret) {
19092ff0b85dSMuhammad Husaini Zulkifli 		dev_err(dev, "Unable to enable SD clock.\n");
1910e3ec3a3dSSoren Brinkmann 		goto clk_dis_ahb;
1911e3ec3a3dSSoren Brinkmann 	}
1912e3ec3a3dSSoren Brinkmann 
19134453d51eSSwati Agarwal 	clk_dll = devm_clk_get_optional_enabled(dev, "gate");
19144453d51eSSwati Agarwal 	if (IS_ERR(clk_dll)) {
19154453d51eSSwati Agarwal 		ret = dev_err_probe(dev, PTR_ERR(clk_dll), "failed to get dll clk\n");
19164453d51eSSwati Agarwal 		goto clk_disable_all;
19174453d51eSSwati Agarwal 	}
19184453d51eSSwati Agarwal 
19193794c542SZach Brown 	if (of_property_read_bool(np, "xlnx,fails-without-test-cd"))
19203794c542SZach Brown 		sdhci_arasan->quirks |= SDHCI_ARASAN_QUIRK_FORCE_CDTEST;
19213794c542SZach Brown 
19223f2c7d5dSHelmut Grohne 	if (of_property_read_bool(np, "xlnx,int-clock-stable-broken"))
19233f2c7d5dSHelmut Grohne 		sdhci_arasan->quirks |= SDHCI_ARASAN_QUIRK_CLOCK_UNSTABLE;
19243f2c7d5dSHelmut Grohne 
1925e3ec3a3dSSoren Brinkmann 	pltfm_host->clk = clk_xin;
1926e3ec3a3dSSoren Brinkmann 
192780d41efeSMuhammad Husaini Zulkifli 	if (of_device_is_compatible(np, "rockchip,rk3399-sdhci-5.1"))
1928b2ca77c9SShawn Lin 		sdhci_arasan_update_clockmultiplier(host, 0x0);
1929b2ca77c9SShawn Lin 
193036c6aadaSWan Ahmad Zainie 	if (of_device_is_compatible(np, "intel,keembay-sdhci-5.1-emmc") ||
193136c6aadaSWan Ahmad Zainie 	    of_device_is_compatible(np, "intel,keembay-sdhci-5.1-sd") ||
1932189f7370SA, Rashmi 	    of_device_is_compatible(np, "intel,keembay-sdhci-5.1-sdio")) {
193336c6aadaSWan Ahmad Zainie 		sdhci_arasan_update_clockmultiplier(host, 0x0);
193436c6aadaSWan Ahmad Zainie 		sdhci_arasan_update_support64b(host, 0x0);
193536c6aadaSWan Ahmad Zainie 
193636c6aadaSWan Ahmad Zainie 		host->mmc->caps |= MMC_CAP_WAIT_WHILE_BUSY;
193736c6aadaSWan Ahmad Zainie 	}
193836c6aadaSWan Ahmad Zainie 
19393ea4666eSDouglas Anderson 	sdhci_arasan_update_baseclkfreq(host);
19403ea4666eSDouglas Anderson 
19412ff0b85dSMuhammad Husaini Zulkifli 	ret = sdhci_arasan_register_sdclk(sdhci_arasan, clk_xin, dev);
1942c390f211SDouglas Anderson 	if (ret)
1943c390f211SDouglas Anderson 		goto clk_disable_all;
1944c390f211SDouglas Anderson 
1945a5c8b2aeSManish Narani 	if (of_device_is_compatible(np, "xlnx,zynqmp-8.9a")) {
19468d2e3343SManish Narani 		host->mmc_host_ops.execute_tuning =
19478d2e3343SManish Narani 			arasan_zynqmp_execute_tuning;
1948c0b4e411SManish Narani 
1949c0b4e411SManish Narani 		sdhci_arasan->quirks |= SDHCI_ARASAN_QUIRK_CLOCK_25_BROKEN;
195025a91664SManish Narani 		host->quirks |= SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12;
1951a5c8b2aeSManish Narani 	}
1952a5c8b2aeSManish Narani 
19532ff0b85dSMuhammad Husaini Zulkifli 	arasan_dt_parse_clk_phases(dev, &sdhci_arasan->clk_data);
1954f3dafc37SManish Narani 
195516b23787SMichal Simek 	ret = mmc_of_parse(host->mmc);
195616b23787SMichal Simek 	if (ret) {
1957ffd68f35SMuhammad Husaini Zulkifli 		ret = dev_err_probe(dev, ret, "parsing dt failed.\n");
1958c390f211SDouglas Anderson 		goto unreg_clk;
195916b23787SMichal Simek 	}
196016b23787SMichal Simek 
19610614b0aeSSai Krishna Potthuri 	if (of_device_is_compatible(np, "xlnx,zynqmp-8.9a")) {
19620614b0aeSSai Krishna Potthuri 		ret = zynqmp_pm_is_function_supported(PM_IOCTL, IOCTL_SET_SD_CONFIG);
19630614b0aeSSai Krishna Potthuri 		if (!ret) {
19640614b0aeSSai Krishna Potthuri 			ret = sdhci_zynqmp_set_dynamic_config(dev, sdhci_arasan);
19650614b0aeSSai Krishna Potthuri 			if (ret)
19660614b0aeSSai Krishna Potthuri 				goto unreg_clk;
19670614b0aeSSai Krishna Potthuri 		}
19680614b0aeSSai Krishna Potthuri 	}
19690614b0aeSSai Krishna Potthuri 
197091aa3661SShawn Lin 	sdhci_arasan->phy = ERR_PTR(-ENODEV);
197180d41efeSMuhammad Husaini Zulkifli 	if (of_device_is_compatible(np, "arasan,sdhci-5.1")) {
19722ff0b85dSMuhammad Husaini Zulkifli 		sdhci_arasan->phy = devm_phy_get(dev, "phy_arasan");
197391aa3661SShawn Lin 		if (IS_ERR(sdhci_arasan->phy)) {
1974ffd68f35SMuhammad Husaini Zulkifli 			ret = dev_err_probe(dev, PTR_ERR(sdhci_arasan->phy),
1975ffd68f35SMuhammad Husaini Zulkifli 					    "No phy for arasan,sdhci-5.1.\n");
1976c390f211SDouglas Anderson 			goto unreg_clk;
197791aa3661SShawn Lin 		}
197891aa3661SShawn Lin 
197991aa3661SShawn Lin 		ret = phy_init(sdhci_arasan->phy);
198091aa3661SShawn Lin 		if (ret < 0) {
19812ff0b85dSMuhammad Husaini Zulkifli 			dev_err(dev, "phy_init err.\n");
1982c390f211SDouglas Anderson 			goto unreg_clk;
198391aa3661SShawn Lin 		}
198491aa3661SShawn Lin 
1985a05c8465SShawn Lin 		host->mmc_host_ops.hs400_enhanced_strobe =
1986a05c8465SShawn Lin 					sdhci_arasan_hs400_enhanced_strobe;
19878a3bee9bSShawn Lin 		host->mmc_host_ops.start_signal_voltage_switch =
19888a3bee9bSShawn Lin 					sdhci_arasan_voltage_switch;
198984362d79SShawn Lin 		sdhci_arasan->has_cqe = true;
19907bda9482SChristoph Muellner 		host->mmc->caps2 |= MMC_CAP2_CQE;
19917bda9482SChristoph Muellner 
19927bda9482SChristoph Muellner 		if (!of_property_read_bool(np, "disable-cqe-dcmd"))
19937bda9482SChristoph Muellner 			host->mmc->caps2 |= MMC_CAP2_CQE_DCMD;
199491aa3661SShawn Lin 	}
199591aa3661SShawn Lin 
1996b095f4f5SSwati Agarwal 	if (of_device_is_compatible(np, "xlnx,versal-net-emmc"))
1997b095f4f5SSwati Agarwal 		sdhci_arasan->internal_phy_reg = true;
1998b095f4f5SSwati Agarwal 
199984362d79SShawn Lin 	ret = sdhci_arasan_add_host(sdhci_arasan);
2000b1df9de7SMike Looijmans 	if (ret)
200191aa3661SShawn Lin 		goto err_add_host;
2002e3ec3a3dSSoren Brinkmann 
2003e3ec3a3dSSoren Brinkmann 	return 0;
2004e3ec3a3dSSoren Brinkmann 
200591aa3661SShawn Lin err_add_host:
200691aa3661SShawn Lin 	if (!IS_ERR(sdhci_arasan->phy))
200791aa3661SShawn Lin 		phy_exit(sdhci_arasan->phy);
2008c390f211SDouglas Anderson unreg_clk:
20092ff0b85dSMuhammad Husaini Zulkifli 	sdhci_arasan_unregister_sdclk(dev);
2010e3ec3a3dSSoren Brinkmann clk_disable_all:
2011e3ec3a3dSSoren Brinkmann 	clk_disable_unprepare(clk_xin);
2012e3ec3a3dSSoren Brinkmann clk_dis_ahb:
2013e3ec3a3dSSoren Brinkmann 	clk_disable_unprepare(sdhci_arasan->clk_ahb);
2014278d0962SShawn Lin err_pltfm_free:
2015278d0962SShawn Lin 	sdhci_pltfm_free(pdev);
2016e3ec3a3dSSoren Brinkmann 	return ret;
2017e3ec3a3dSSoren Brinkmann }
2018e3ec3a3dSSoren Brinkmann 
sdhci_arasan_remove(struct platform_device * pdev)20193de205a0SYangtao Li static void sdhci_arasan_remove(struct platform_device *pdev)
2020e3ec3a3dSSoren Brinkmann {
2021e3ec3a3dSSoren Brinkmann 	struct sdhci_host *host = platform_get_drvdata(pdev);
2022e3ec3a3dSSoren Brinkmann 	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
202389211418SJisheng Zhang 	struct sdhci_arasan_data *sdhci_arasan = sdhci_pltfm_priv(pltfm_host);
202489211418SJisheng Zhang 	struct clk *clk_ahb = sdhci_arasan->clk_ahb;
2025*ef1c3a7eSAdrian Hunter 	struct clk *clk_xin = pltfm_host->clk;
2026e3ec3a3dSSoren Brinkmann 
202791aa3661SShawn Lin 	if (!IS_ERR(sdhci_arasan->phy)) {
2028b2db9c67SDouglas Anderson 		if (sdhci_arasan->is_phy_on)
202991aa3661SShawn Lin 			phy_power_off(sdhci_arasan->phy);
203091aa3661SShawn Lin 		phy_exit(sdhci_arasan->phy);
203191aa3661SShawn Lin 	}
203291aa3661SShawn Lin 
2033c390f211SDouglas Anderson 	sdhci_arasan_unregister_sdclk(&pdev->dev);
2034c390f211SDouglas Anderson 
2035*ef1c3a7eSAdrian Hunter 	sdhci_pltfm_remove(pdev);
20360c7fe32eSJisheng Zhang 
2037*ef1c3a7eSAdrian Hunter 	clk_disable_unprepare(clk_xin);
203889211418SJisheng Zhang 	clk_disable_unprepare(clk_ahb);
2039e3ec3a3dSSoren Brinkmann }
2040e3ec3a3dSSoren Brinkmann 
2041e3ec3a3dSSoren Brinkmann static struct platform_driver sdhci_arasan_driver = {
2042e3ec3a3dSSoren Brinkmann 	.driver = {
2043e3ec3a3dSSoren Brinkmann 		.name = "sdhci-arasan",
204421b2cec6SDouglas Anderson 		.probe_type = PROBE_PREFER_ASYNCHRONOUS,
2045e3ec3a3dSSoren Brinkmann 		.of_match_table = sdhci_arasan_of_match,
2046e3ec3a3dSSoren Brinkmann 		.pm = &sdhci_arasan_dev_pm_ops,
2047e3ec3a3dSSoren Brinkmann 	},
2048e3ec3a3dSSoren Brinkmann 	.probe = sdhci_arasan_probe,
20493de205a0SYangtao Li 	.remove_new = sdhci_arasan_remove,
2050e3ec3a3dSSoren Brinkmann };
2051e3ec3a3dSSoren Brinkmann 
2052e3ec3a3dSSoren Brinkmann module_platform_driver(sdhci_arasan_driver);
2053e3ec3a3dSSoren Brinkmann 
2054e3ec3a3dSSoren Brinkmann MODULE_DESCRIPTION("Driver for the Arasan SDHCI Controller");
2055e3ec3a3dSSoren Brinkmann MODULE_AUTHOR("Soeren Brinkmann <soren.brinkmann@xilinx.com>");
2056e3ec3a3dSSoren Brinkmann MODULE_LICENSE("GPL");
2057