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>
21308f3f8dSSuman Tripathi #include <linux/of_device.h>
2291aa3661SShawn Lin #include <linux/phy/phy.h>
233ea4666eSDouglas Anderson #include <linux/regmap.h>
243794c542SZach Brown #include <linux/of.h>
25a5c8b2aeSManish Narani #include <linux/firmware/xlnx-zynqmp.h>
26e3ec3a3dSSoren Brinkmann 
2784362d79SShawn Lin #include "cqhci.h"
2884362d79SShawn Lin #include "sdhci-pltfm.h"
29e3ec3a3dSSoren Brinkmann 
3084362d79SShawn Lin #define SDHCI_ARASAN_VENDOR_REGISTER	0x78
311a470721SManish Narani 
321a470721SManish Narani #define SDHCI_ARASAN_ITAPDLY_REGISTER	0xF0F8
33d338c6d0SManish Narani #define SDHCI_ARASAN_ITAPDLY_SEL_MASK	0xFF
34d338c6d0SManish Narani 
351a470721SManish Narani #define SDHCI_ARASAN_OTAPDLY_REGISTER	0xF0FC
36d338c6d0SManish Narani #define SDHCI_ARASAN_OTAPDLY_SEL_MASK	0x3F
371a470721SManish Narani 
3884362d79SShawn Lin #define SDHCI_ARASAN_CQE_BASE_ADDR	0x200
39a05c8465SShawn Lin #define VENDOR_ENHANCED_STROBE		BIT(0)
40e3ec3a3dSSoren Brinkmann 
41b2db9c67SDouglas Anderson #define PHY_CLK_TOO_SLOW_HZ		400000
42b2db9c67SDouglas Anderson 
431a470721SManish Narani #define SDHCI_ITAPDLY_CHGWIN		0x200
441a470721SManish Narani #define SDHCI_ITAPDLY_ENABLE		0x100
451a470721SManish Narani #define SDHCI_OTAPDLY_ENABLE		0x40
461a470721SManish Narani 
47a5c8b2aeSManish Narani /* Default settings for ZynqMP Clock Phases */
48a5c8b2aeSManish Narani #define ZYNQMP_ICLK_PHASE {0, 63, 63, 0, 63,  0,   0, 183, 54,  0, 0}
49a5c8b2aeSManish Narani #define ZYNQMP_OCLK_PHASE {0, 72, 60, 0, 60, 72, 135, 48, 72, 135, 0}
50a5c8b2aeSManish Narani 
511a470721SManish Narani #define VERSAL_ICLK_PHASE {0, 132, 132, 0, 132, 0, 0, 162, 90, 0, 0}
521a470721SManish Narani #define VERSAL_OCLK_PHASE {0,  60, 48, 0, 48, 72, 90, 36, 60, 90, 0}
531a470721SManish Narani 
543ea4666eSDouglas Anderson /*
553ea4666eSDouglas Anderson  * On some SoCs the syscon area has a feature where the upper 16-bits of
563ea4666eSDouglas Anderson  * each 32-bit register act as a write mask for the lower 16-bits.  This allows
573ea4666eSDouglas Anderson  * atomic updates of the register without locking.  This macro is used on SoCs
583ea4666eSDouglas Anderson  * that have that feature.
593ea4666eSDouglas Anderson  */
603ea4666eSDouglas Anderson #define HIWORD_UPDATE(val, mask, shift) \
613ea4666eSDouglas Anderson 		((val) << (shift) | (mask) << ((shift) + 16))
623ea4666eSDouglas Anderson 
633ea4666eSDouglas Anderson /**
643ea4666eSDouglas Anderson  * struct sdhci_arasan_soc_ctl_field - Field used in sdhci_arasan_soc_ctl_map
653ea4666eSDouglas Anderson  *
663ea4666eSDouglas Anderson  * @reg:	Offset within the syscon of the register containing this field
673ea4666eSDouglas Anderson  * @width:	Number of bits for this field
683ea4666eSDouglas Anderson  * @shift:	Bit offset within @reg of this field (or -1 if not avail)
693ea4666eSDouglas Anderson  */
703ea4666eSDouglas Anderson struct sdhci_arasan_soc_ctl_field {
713ea4666eSDouglas Anderson 	u32 reg;
723ea4666eSDouglas Anderson 	u16 width;
733ea4666eSDouglas Anderson 	s16 shift;
743ea4666eSDouglas Anderson };
753ea4666eSDouglas Anderson 
763ea4666eSDouglas Anderson /**
773ea4666eSDouglas Anderson  * struct sdhci_arasan_soc_ctl_map - Map in syscon to corecfg registers
783ea4666eSDouglas Anderson  *
793ea4666eSDouglas Anderson  * @baseclkfreq:	Where to find corecfg_baseclkfreq
80b2ca77c9SShawn Lin  * @clockmultiplier:	Where to find corecfg_clockmultiplier
8136c6aadaSWan Ahmad Zainie  * @support64b:		Where to find SUPPORT64B bit
823ea4666eSDouglas Anderson  * @hiword_update:	If true, use HIWORD_UPDATE to access the syscon
834908460eSManish Narani  *
844908460eSManish Narani  * It's up to the licensee of the Arsan IP block to make these available
854908460eSManish Narani  * somewhere if needed.  Presumably these will be scattered somewhere that's
864908460eSManish Narani  * accessible via the syscon API.
873ea4666eSDouglas Anderson  */
883ea4666eSDouglas Anderson struct sdhci_arasan_soc_ctl_map {
893ea4666eSDouglas Anderson 	struct sdhci_arasan_soc_ctl_field	baseclkfreq;
90b2ca77c9SShawn Lin 	struct sdhci_arasan_soc_ctl_field	clockmultiplier;
9136c6aadaSWan Ahmad Zainie 	struct sdhci_arasan_soc_ctl_field	support64b;
923ea4666eSDouglas Anderson 	bool					hiword_update;
933ea4666eSDouglas Anderson };
943ea4666eSDouglas Anderson 
95e3ec3a3dSSoren Brinkmann /**
9616ada730SManish Narani  * struct sdhci_arasan_clk_ops - Clock Operations for Arasan SD controller
9716ada730SManish Narani  *
9816ada730SManish Narani  * @sdcardclk_ops:	The output clock related operations
9916ada730SManish Narani  * @sampleclk_ops:	The sample clock related operations
10016ada730SManish Narani  */
10116ada730SManish Narani struct sdhci_arasan_clk_ops {
10216ada730SManish Narani 	const struct clk_ops *sdcardclk_ops;
10316ada730SManish Narani 	const struct clk_ops *sampleclk_ops;
10416ada730SManish Narani };
10516ada730SManish Narani 
10616ada730SManish Narani /**
1074908460eSManish Narani  * struct sdhci_arasan_clk_data - Arasan Controller Clock Data.
1084908460eSManish Narani  *
109e1463618SManish Narani  * @sdcardclk_hw:	Struct for the clock we might provide to a PHY.
110e1463618SManish Narani  * @sdcardclk:		Pointer to normal 'struct clock' for sdcardclk_hw.
11107a14d1dSManish Narani  * @sampleclk_hw:	Struct for the clock we might provide to a PHY.
11207a14d1dSManish Narani  * @sampleclk:		Pointer to normal 'struct clock' for sampleclk_hw.
113f3dafc37SManish Narani  * @clk_phase_in:	Array of Input Clock Phase Delays for all speed modes
114f3dafc37SManish Narani  * @clk_phase_out:	Array of Output Clock Phase Delays for all speed modes
115f3dafc37SManish Narani  * @set_clk_delays:	Function pointer for setting Clock Delays
116a5c8b2aeSManish Narani  * @clk_of_data:	Platform specific runtime clock data storage pointer
117e1463618SManish Narani  */
118e1463618SManish Narani struct sdhci_arasan_clk_data {
119e1463618SManish Narani 	struct clk_hw	sdcardclk_hw;
120e1463618SManish Narani 	struct clk      *sdcardclk;
12107a14d1dSManish Narani 	struct clk_hw	sampleclk_hw;
12207a14d1dSManish Narani 	struct clk      *sampleclk;
123f3dafc37SManish Narani 	int		clk_phase_in[MMC_TIMING_MMC_HS400 + 1];
124f3dafc37SManish Narani 	int		clk_phase_out[MMC_TIMING_MMC_HS400 + 1];
125f3dafc37SManish Narani 	void		(*set_clk_delays)(struct sdhci_host *host);
126a5c8b2aeSManish Narani 	void		*clk_of_data;
127a5c8b2aeSManish Narani };
128a5c8b2aeSManish Narani 
129e1463618SManish Narani /**
1304908460eSManish Narani  * struct sdhci_arasan_data - Arasan Controller Data
1314908460eSManish Narani  *
132c390f211SDouglas Anderson  * @host:		Pointer to the main SDHCI host structure.
133e3ec3a3dSSoren Brinkmann  * @clk_ahb:		Pointer to the AHB clock
13491aa3661SShawn Lin  * @phy:		Pointer to the generic phy
135b2db9c67SDouglas Anderson  * @is_phy_on:		True if the PHY is on; false if not.
1364908460eSManish Narani  * @has_cqe:		True if controller has command queuing engine.
137e1463618SManish Narani  * @clk_data:		Struct for the Arasan Controller Clock Data.
13816ada730SManish Narani  * @clk_ops:		Struct for the Arasan Controller Clock Operations.
1393ea4666eSDouglas Anderson  * @soc_ctl_base:	Pointer to regmap for syscon for soc_ctl registers.
1403ea4666eSDouglas Anderson  * @soc_ctl_map:	Map to get offsets into soc_ctl registers.
1414908460eSManish Narani  * @quirks:		Arasan deviations from spec.
142e3ec3a3dSSoren Brinkmann  */
143e3ec3a3dSSoren Brinkmann struct sdhci_arasan_data {
144c390f211SDouglas Anderson 	struct sdhci_host *host;
145e3ec3a3dSSoren Brinkmann 	struct clk	*clk_ahb;
14691aa3661SShawn Lin 	struct phy	*phy;
147b2db9c67SDouglas Anderson 	bool		is_phy_on;
1483ea4666eSDouglas Anderson 
14984362d79SShawn Lin 	bool		has_cqe;
150e1463618SManish Narani 	struct sdhci_arasan_clk_data clk_data;
15116ada730SManish Narani 	const struct sdhci_arasan_clk_ops *clk_ops;
152c390f211SDouglas Anderson 
1533ea4666eSDouglas Anderson 	struct regmap	*soc_ctl_base;
1543ea4666eSDouglas Anderson 	const struct sdhci_arasan_soc_ctl_map *soc_ctl_map;
1554908460eSManish Narani 	unsigned int	quirks;
1563794c542SZach Brown 
1573794c542SZach Brown /* Controller does not have CD wired and will not function normally without */
1583794c542SZach Brown #define SDHCI_ARASAN_QUIRK_FORCE_CDTEST	BIT(0)
1593f2c7d5dSHelmut Grohne /* Controller immediately reports SDHCI_CLOCK_INT_STABLE after enabling the
1603f2c7d5dSHelmut Grohne  * internal clock even when the clock isn't stable */
1613f2c7d5dSHelmut Grohne #define SDHCI_ARASAN_QUIRK_CLOCK_UNSTABLE BIT(1)
162c0b4e411SManish Narani /*
163c0b4e411SManish Narani  * Some of the Arasan variations might not have timing requirements
164c0b4e411SManish Narani  * met at 25MHz for Default Speed mode, those controllers work at
165c0b4e411SManish Narani  * 19MHz instead
166c0b4e411SManish Narani  */
167c0b4e411SManish Narani #define SDHCI_ARASAN_QUIRK_CLOCK_25_BROKEN BIT(2)
168e3ec3a3dSSoren Brinkmann };
169e3ec3a3dSSoren Brinkmann 
17006b23ca0SFaiz Abbas struct sdhci_arasan_of_data {
17106b23ca0SFaiz Abbas 	const struct sdhci_arasan_soc_ctl_map *soc_ctl_map;
17206b23ca0SFaiz Abbas 	const struct sdhci_pltfm_data *pdata;
17316ada730SManish Narani 	const struct sdhci_arasan_clk_ops *clk_ops;
17406b23ca0SFaiz Abbas };
17506b23ca0SFaiz Abbas 
1763ea4666eSDouglas Anderson static const struct sdhci_arasan_soc_ctl_map rk3399_soc_ctl_map = {
1773ea4666eSDouglas Anderson 	.baseclkfreq = { .reg = 0xf000, .width = 8, .shift = 8 },
178b2ca77c9SShawn Lin 	.clockmultiplier = { .reg = 0xf02c, .width = 8, .shift = 0},
1793ea4666eSDouglas Anderson 	.hiword_update = true,
1803ea4666eSDouglas Anderson };
1813ea4666eSDouglas Anderson 
1825c1a4f40SRamuthevar Vadivel Muruganx static const struct sdhci_arasan_soc_ctl_map intel_lgm_emmc_soc_ctl_map = {
1835c1a4f40SRamuthevar Vadivel Muruganx 	.baseclkfreq = { .reg = 0xa0, .width = 8, .shift = 2 },
1845c1a4f40SRamuthevar Vadivel Muruganx 	.clockmultiplier = { .reg = 0, .width = -1, .shift = -1 },
1855c1a4f40SRamuthevar Vadivel Muruganx 	.hiword_update = false,
1865c1a4f40SRamuthevar Vadivel Muruganx };
1875c1a4f40SRamuthevar Vadivel Muruganx 
188d1807ad6SRamuthevar Vadivel Murugan static const struct sdhci_arasan_soc_ctl_map intel_lgm_sdxc_soc_ctl_map = {
189d1807ad6SRamuthevar Vadivel Murugan 	.baseclkfreq = { .reg = 0x80, .width = 8, .shift = 2 },
190d1807ad6SRamuthevar Vadivel Murugan 	.clockmultiplier = { .reg = 0, .width = -1, .shift = -1 },
191d1807ad6SRamuthevar Vadivel Murugan 	.hiword_update = false,
192d1807ad6SRamuthevar Vadivel Murugan };
193d1807ad6SRamuthevar Vadivel Murugan 
19436c6aadaSWan Ahmad Zainie static const struct sdhci_arasan_soc_ctl_map intel_keembay_soc_ctl_map = {
19536c6aadaSWan Ahmad Zainie 	.baseclkfreq = { .reg = 0x0, .width = 8, .shift = 14 },
19636c6aadaSWan Ahmad Zainie 	.clockmultiplier = { .reg = 0x4, .width = 8, .shift = 14 },
19736c6aadaSWan Ahmad Zainie 	.support64b = { .reg = 0x4, .width = 1, .shift = 24 },
19836c6aadaSWan Ahmad Zainie 	.hiword_update = false,
19936c6aadaSWan Ahmad Zainie };
20036c6aadaSWan Ahmad Zainie 
2013ea4666eSDouglas Anderson /**
2023ea4666eSDouglas Anderson  * sdhci_arasan_syscon_write - Write to a field in soc_ctl registers
2033ea4666eSDouglas Anderson  *
2044908460eSManish Narani  * @host:	The sdhci_host
2054908460eSManish Narani  * @fld:	The field to write to
2064908460eSManish Narani  * @val:	The value to write
2074908460eSManish Narani  *
2083ea4666eSDouglas Anderson  * This function allows writing to fields in sdhci_arasan_soc_ctl_map.
2093ea4666eSDouglas Anderson  * Note that if a field is specified as not available (shift < 0) then
2103ea4666eSDouglas Anderson  * this function will silently return an error code.  It will be noisy
2113ea4666eSDouglas Anderson  * and print errors for any other (unexpected) errors.
2123ea4666eSDouglas Anderson  *
2134908460eSManish Narani  * Return: 0 on success and error value on error
2143ea4666eSDouglas Anderson  */
2153ea4666eSDouglas Anderson static int sdhci_arasan_syscon_write(struct sdhci_host *host,
2163ea4666eSDouglas Anderson 				   const struct sdhci_arasan_soc_ctl_field *fld,
2173ea4666eSDouglas Anderson 				   u32 val)
2183ea4666eSDouglas Anderson {
2193ea4666eSDouglas Anderson 	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
2203ea4666eSDouglas Anderson 	struct sdhci_arasan_data *sdhci_arasan = sdhci_pltfm_priv(pltfm_host);
2213ea4666eSDouglas Anderson 	struct regmap *soc_ctl_base = sdhci_arasan->soc_ctl_base;
2223ea4666eSDouglas Anderson 	u32 reg = fld->reg;
2233ea4666eSDouglas Anderson 	u16 width = fld->width;
2243ea4666eSDouglas Anderson 	s16 shift = fld->shift;
2253ea4666eSDouglas Anderson 	int ret;
2263ea4666eSDouglas Anderson 
2273ea4666eSDouglas Anderson 	/*
2283ea4666eSDouglas Anderson 	 * Silently return errors for shift < 0 so caller doesn't have
2293ea4666eSDouglas Anderson 	 * to check for fields which are optional.  For fields that
2303ea4666eSDouglas Anderson 	 * are required then caller needs to do something special
2313ea4666eSDouglas Anderson 	 * anyway.
2323ea4666eSDouglas Anderson 	 */
2333ea4666eSDouglas Anderson 	if (shift < 0)
2343ea4666eSDouglas Anderson 		return -EINVAL;
2353ea4666eSDouglas Anderson 
2363ea4666eSDouglas Anderson 	if (sdhci_arasan->soc_ctl_map->hiword_update)
2373ea4666eSDouglas Anderson 		ret = regmap_write(soc_ctl_base, reg,
2383ea4666eSDouglas Anderson 				   HIWORD_UPDATE(val, GENMASK(width, 0),
2393ea4666eSDouglas Anderson 						 shift));
2403ea4666eSDouglas Anderson 	else
2413ea4666eSDouglas Anderson 		ret = regmap_update_bits(soc_ctl_base, reg,
2423ea4666eSDouglas Anderson 					 GENMASK(shift + width, shift),
2433ea4666eSDouglas Anderson 					 val << shift);
2443ea4666eSDouglas Anderson 
2453ea4666eSDouglas Anderson 	/* Yell about (unexpected) regmap errors */
2463ea4666eSDouglas Anderson 	if (ret)
2473ea4666eSDouglas Anderson 		pr_warn("%s: Regmap write fail: %d\n",
2483ea4666eSDouglas Anderson 			 mmc_hostname(host->mmc), ret);
2493ea4666eSDouglas Anderson 
2503ea4666eSDouglas Anderson 	return ret;
2513ea4666eSDouglas Anderson }
2523ea4666eSDouglas Anderson 
253802ac39aSShawn Lin static void sdhci_arasan_set_clock(struct sdhci_host *host, unsigned int clock)
254802ac39aSShawn Lin {
255802ac39aSShawn Lin 	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
256802ac39aSShawn Lin 	struct sdhci_arasan_data *sdhci_arasan = sdhci_pltfm_priv(pltfm_host);
257f3dafc37SManish Narani 	struct sdhci_arasan_clk_data *clk_data = &sdhci_arasan->clk_data;
2586fc09244SDouglas Anderson 	bool ctrl_phy = false;
259802ac39aSShawn Lin 
260b2db9c67SDouglas Anderson 	if (!IS_ERR(sdhci_arasan->phy)) {
261b2db9c67SDouglas Anderson 		if (!sdhci_arasan->is_phy_on && clock <= PHY_CLK_TOO_SLOW_HZ) {
262b2db9c67SDouglas Anderson 			/*
263b2db9c67SDouglas Anderson 			 * If PHY off, set clock to max speed and power PHY on.
264b2db9c67SDouglas Anderson 			 *
265b2db9c67SDouglas Anderson 			 * Although PHY docs apparently suggest power cycling
266b2db9c67SDouglas Anderson 			 * when changing the clock the PHY doesn't like to be
267b2db9c67SDouglas Anderson 			 * powered on while at low speeds like those used in ID
268b2db9c67SDouglas Anderson 			 * mode.  Even worse is powering the PHY on while the
269b2db9c67SDouglas Anderson 			 * clock is off.
270b2db9c67SDouglas Anderson 			 *
271b2db9c67SDouglas Anderson 			 * To workaround the PHY limitations, the best we can
272b2db9c67SDouglas Anderson 			 * do is to power it on at a faster speed and then slam
273b2db9c67SDouglas Anderson 			 * through low speeds without power cycling.
274b2db9c67SDouglas Anderson 			 */
275b2db9c67SDouglas Anderson 			sdhci_set_clock(host, host->max_clk);
276*66bad6edSManish Narani 			if (phy_power_on(sdhci_arasan->phy)) {
277*66bad6edSManish Narani 				pr_err("%s: Cannot power on phy.\n",
278*66bad6edSManish Narani 				       mmc_hostname(host->mmc));
279*66bad6edSManish Narani 				return;
280*66bad6edSManish Narani 			}
281*66bad6edSManish Narani 
282b2db9c67SDouglas Anderson 			sdhci_arasan->is_phy_on = true;
283802ac39aSShawn Lin 
284b2db9c67SDouglas Anderson 			/*
285b2db9c67SDouglas Anderson 			 * We'll now fall through to the below case with
286b2db9c67SDouglas Anderson 			 * ctrl_phy = false (so we won't turn off/on).  The
287b2db9c67SDouglas Anderson 			 * sdhci_set_clock() will set the real clock.
288b2db9c67SDouglas Anderson 			 */
289b2db9c67SDouglas Anderson 		} else if (clock > PHY_CLK_TOO_SLOW_HZ) {
290b2db9c67SDouglas Anderson 			/*
291b2db9c67SDouglas Anderson 			 * At higher clock speeds the PHY is fine being power
292b2db9c67SDouglas Anderson 			 * cycled and docs say you _should_ power cycle when
293b2db9c67SDouglas Anderson 			 * changing clock speeds.
294b2db9c67SDouglas Anderson 			 */
295b2db9c67SDouglas Anderson 			ctrl_phy = true;
296b2db9c67SDouglas Anderson 		}
297b2db9c67SDouglas Anderson 	}
298b2db9c67SDouglas Anderson 
299b2db9c67SDouglas Anderson 	if (ctrl_phy && sdhci_arasan->is_phy_on) {
300802ac39aSShawn Lin 		phy_power_off(sdhci_arasan->phy);
301b2db9c67SDouglas Anderson 		sdhci_arasan->is_phy_on = false;
302802ac39aSShawn Lin 	}
303802ac39aSShawn Lin 
304c0b4e411SManish Narani 	if (sdhci_arasan->quirks & SDHCI_ARASAN_QUIRK_CLOCK_25_BROKEN) {
305c0b4e411SManish Narani 		/*
306c0b4e411SManish Narani 		 * Some of the Arasan variations might not have timing
307c0b4e411SManish Narani 		 * requirements met at 25MHz for Default Speed mode,
308c0b4e411SManish Narani 		 * those controllers work at 19MHz instead.
309c0b4e411SManish Narani 		 */
310c0b4e411SManish Narani 		if (clock == DEFAULT_SPEED_MAX_DTR)
311c0b4e411SManish Narani 			clock = (DEFAULT_SPEED_MAX_DTR * 19) / 25;
312c0b4e411SManish Narani 	}
313c0b4e411SManish Narani 
314f3dafc37SManish Narani 	/* Set the Input and Output Clock Phase Delays */
315f3dafc37SManish Narani 	if (clk_data->set_clk_delays)
316f3dafc37SManish Narani 		clk_data->set_clk_delays(host);
317f3dafc37SManish Narani 
318802ac39aSShawn Lin 	sdhci_set_clock(host, clock);
319802ac39aSShawn Lin 
3203f2c7d5dSHelmut Grohne 	if (sdhci_arasan->quirks & SDHCI_ARASAN_QUIRK_CLOCK_UNSTABLE)
3213f2c7d5dSHelmut Grohne 		/*
3223f2c7d5dSHelmut Grohne 		 * Some controllers immediately report SDHCI_CLOCK_INT_STABLE
3233f2c7d5dSHelmut Grohne 		 * after enabling the clock even though the clock is not
3243f2c7d5dSHelmut Grohne 		 * stable. Trying to use a clock without waiting here results
3253f2c7d5dSHelmut Grohne 		 * in EILSEQ while detecting some older/slower cards. The
3263f2c7d5dSHelmut Grohne 		 * chosen delay is the maximum delay from sdhci_set_clock.
3273f2c7d5dSHelmut Grohne 		 */
3283f2c7d5dSHelmut Grohne 		msleep(20);
3293f2c7d5dSHelmut Grohne 
3306fc09244SDouglas Anderson 	if (ctrl_phy) {
331*66bad6edSManish Narani 		if (phy_power_on(sdhci_arasan->phy)) {
332*66bad6edSManish Narani 			pr_err("%s: Cannot power on phy.\n",
333*66bad6edSManish Narani 			       mmc_hostname(host->mmc));
334*66bad6edSManish Narani 			return;
335*66bad6edSManish Narani 		}
336*66bad6edSManish Narani 
337b2db9c67SDouglas Anderson 		sdhci_arasan->is_phy_on = true;
338802ac39aSShawn Lin 	}
339802ac39aSShawn Lin }
340802ac39aSShawn Lin 
341a05c8465SShawn Lin static void sdhci_arasan_hs400_enhanced_strobe(struct mmc_host *mmc,
342a05c8465SShawn Lin 					struct mmc_ios *ios)
343a05c8465SShawn Lin {
344a05c8465SShawn Lin 	u32 vendor;
345a05c8465SShawn Lin 	struct sdhci_host *host = mmc_priv(mmc);
346a05c8465SShawn Lin 
3470daf72feSJean-Francois Dagenais 	vendor = sdhci_readl(host, SDHCI_ARASAN_VENDOR_REGISTER);
348a05c8465SShawn Lin 	if (ios->enhanced_strobe)
349a05c8465SShawn Lin 		vendor |= VENDOR_ENHANCED_STROBE;
350a05c8465SShawn Lin 	else
351a05c8465SShawn Lin 		vendor &= ~VENDOR_ENHANCED_STROBE;
352a05c8465SShawn Lin 
3530daf72feSJean-Francois Dagenais 	sdhci_writel(host, vendor, SDHCI_ARASAN_VENDOR_REGISTER);
354a05c8465SShawn Lin }
355a05c8465SShawn Lin 
35613d62fd2SWei Yongjun static void sdhci_arasan_reset(struct sdhci_host *host, u8 mask)
3573794c542SZach Brown {
3583794c542SZach Brown 	u8 ctrl;
3593794c542SZach Brown 	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
3603794c542SZach Brown 	struct sdhci_arasan_data *sdhci_arasan = sdhci_pltfm_priv(pltfm_host);
3613794c542SZach Brown 
3623794c542SZach Brown 	sdhci_reset(host, mask);
3633794c542SZach Brown 
3643794c542SZach Brown 	if (sdhci_arasan->quirks & SDHCI_ARASAN_QUIRK_FORCE_CDTEST) {
3653794c542SZach Brown 		ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL);
3663794c542SZach Brown 		ctrl |= SDHCI_CTRL_CDTEST_INS | SDHCI_CTRL_CDTEST_EN;
3673794c542SZach Brown 		sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
3683794c542SZach Brown 	}
3693794c542SZach Brown }
3703794c542SZach Brown 
3718a3bee9bSShawn Lin static int sdhci_arasan_voltage_switch(struct mmc_host *mmc,
3728a3bee9bSShawn Lin 				       struct mmc_ios *ios)
3738a3bee9bSShawn Lin {
3748a3bee9bSShawn Lin 	switch (ios->signal_voltage) {
3758a3bee9bSShawn Lin 	case MMC_SIGNAL_VOLTAGE_180:
3768a3bee9bSShawn Lin 		/*
3778a3bee9bSShawn Lin 		 * Plese don't switch to 1V8 as arasan,5.1 doesn't
3788a3bee9bSShawn Lin 		 * actually refer to this setting to indicate the
3798a3bee9bSShawn Lin 		 * signal voltage and the state machine will be broken
3808a3bee9bSShawn Lin 		 * actually if we force to enable 1V8. That's something
3818a3bee9bSShawn Lin 		 * like broken quirk but we could work around here.
3828a3bee9bSShawn Lin 		 */
3838a3bee9bSShawn Lin 		return 0;
3848a3bee9bSShawn Lin 	case MMC_SIGNAL_VOLTAGE_330:
3858a3bee9bSShawn Lin 	case MMC_SIGNAL_VOLTAGE_120:
3868a3bee9bSShawn Lin 		/* We don't support 3V3 and 1V2 */
3878a3bee9bSShawn Lin 		break;
3888a3bee9bSShawn Lin 	}
3898a3bee9bSShawn Lin 
3908a3bee9bSShawn Lin 	return -EINVAL;
3918a3bee9bSShawn Lin }
3928a3bee9bSShawn Lin 
393a81dae3aSJulia Lawall static const struct sdhci_ops sdhci_arasan_ops = {
394802ac39aSShawn Lin 	.set_clock = sdhci_arasan_set_clock,
395e3ec3a3dSSoren Brinkmann 	.get_max_clock = sdhci_pltfm_clk_get_max_clock,
3968cc35289SShawn Lin 	.get_timeout_clock = sdhci_pltfm_clk_get_max_clock,
3972317f56cSRussell King 	.set_bus_width = sdhci_set_bus_width,
3983794c542SZach Brown 	.reset = sdhci_arasan_reset,
39996d7b78cSRussell King 	.set_uhs_signaling = sdhci_set_uhs_signaling,
400c2c5252cSNicolas Saenz Julienne 	.set_power = sdhci_set_power_and_bus_voltage,
401e3ec3a3dSSoren Brinkmann };
402e3ec3a3dSSoren Brinkmann 
40384362d79SShawn Lin static u32 sdhci_arasan_cqhci_irq(struct sdhci_host *host, u32 intmask)
40484362d79SShawn Lin {
40584362d79SShawn Lin 	int cmd_error = 0;
40684362d79SShawn Lin 	int data_error = 0;
40784362d79SShawn Lin 
40884362d79SShawn Lin 	if (!sdhci_cqe_irq(host, intmask, &cmd_error, &data_error))
40984362d79SShawn Lin 		return intmask;
41084362d79SShawn Lin 
41184362d79SShawn Lin 	cqhci_irq(host->mmc, intmask, cmd_error, data_error);
41284362d79SShawn Lin 
41384362d79SShawn Lin 	return 0;
41484362d79SShawn Lin }
41584362d79SShawn Lin 
41684362d79SShawn Lin static void sdhci_arasan_dumpregs(struct mmc_host *mmc)
41784362d79SShawn Lin {
41884362d79SShawn Lin 	sdhci_dumpregs(mmc_priv(mmc));
41984362d79SShawn Lin }
42084362d79SShawn Lin 
42184362d79SShawn Lin static void sdhci_arasan_cqe_enable(struct mmc_host *mmc)
42284362d79SShawn Lin {
42384362d79SShawn Lin 	struct sdhci_host *host = mmc_priv(mmc);
42484362d79SShawn Lin 	u32 reg;
42584362d79SShawn Lin 
42684362d79SShawn Lin 	reg = sdhci_readl(host, SDHCI_PRESENT_STATE);
42784362d79SShawn Lin 	while (reg & SDHCI_DATA_AVAILABLE) {
42884362d79SShawn Lin 		sdhci_readl(host, SDHCI_BUFFER);
42984362d79SShawn Lin 		reg = sdhci_readl(host, SDHCI_PRESENT_STATE);
43084362d79SShawn Lin 	}
43184362d79SShawn Lin 
43284362d79SShawn Lin 	sdhci_cqe_enable(mmc);
43384362d79SShawn Lin }
43484362d79SShawn Lin 
43584362d79SShawn Lin static const struct cqhci_host_ops sdhci_arasan_cqhci_ops = {
43684362d79SShawn Lin 	.enable         = sdhci_arasan_cqe_enable,
43784362d79SShawn Lin 	.disable        = sdhci_cqe_disable,
43884362d79SShawn Lin 	.dumpregs       = sdhci_arasan_dumpregs,
43984362d79SShawn Lin };
44084362d79SShawn Lin 
44184362d79SShawn Lin static const struct sdhci_ops sdhci_arasan_cqe_ops = {
44284362d79SShawn Lin 	.set_clock = sdhci_arasan_set_clock,
44384362d79SShawn Lin 	.get_max_clock = sdhci_pltfm_clk_get_max_clock,
44484362d79SShawn Lin 	.get_timeout_clock = sdhci_pltfm_clk_get_max_clock,
44584362d79SShawn Lin 	.set_bus_width = sdhci_set_bus_width,
44684362d79SShawn Lin 	.reset = sdhci_arasan_reset,
44784362d79SShawn Lin 	.set_uhs_signaling = sdhci_set_uhs_signaling,
448c2c5252cSNicolas Saenz Julienne 	.set_power = sdhci_set_power_and_bus_voltage,
44984362d79SShawn Lin 	.irq = sdhci_arasan_cqhci_irq,
45084362d79SShawn Lin };
45184362d79SShawn Lin 
45284362d79SShawn Lin static const struct sdhci_pltfm_data sdhci_arasan_cqe_pdata = {
45384362d79SShawn Lin 	.ops = &sdhci_arasan_cqe_ops,
45484362d79SShawn Lin 	.quirks = SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN,
45584362d79SShawn Lin 	.quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN |
45684362d79SShawn Lin 			SDHCI_QUIRK2_CLOCK_DIV_ZERO_BROKEN,
45784362d79SShawn Lin };
45884362d79SShawn Lin 
459e3ec3a3dSSoren Brinkmann #ifdef CONFIG_PM_SLEEP
460e3ec3a3dSSoren Brinkmann /**
461e3ec3a3dSSoren Brinkmann  * sdhci_arasan_suspend - Suspend method for the driver
462e3ec3a3dSSoren Brinkmann  * @dev:	Address of the device structure
463e3ec3a3dSSoren Brinkmann  *
464e3ec3a3dSSoren Brinkmann  * Put the device in a low power state.
4654908460eSManish Narani  *
4664908460eSManish Narani  * Return: 0 on success and error value on error
467e3ec3a3dSSoren Brinkmann  */
468e3ec3a3dSSoren Brinkmann static int sdhci_arasan_suspend(struct device *dev)
469e3ec3a3dSSoren Brinkmann {
470970f2d90SWolfram Sang 	struct sdhci_host *host = dev_get_drvdata(dev);
471e3ec3a3dSSoren Brinkmann 	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
47289211418SJisheng Zhang 	struct sdhci_arasan_data *sdhci_arasan = sdhci_pltfm_priv(pltfm_host);
473e3ec3a3dSSoren Brinkmann 	int ret;
474e3ec3a3dSSoren Brinkmann 
475d38dcad4SAdrian Hunter 	if (host->tuning_mode != SDHCI_TUNING_MODE_3)
476d38dcad4SAdrian Hunter 		mmc_retune_needed(host->mmc);
477d38dcad4SAdrian Hunter 
47884362d79SShawn Lin 	if (sdhci_arasan->has_cqe) {
47984362d79SShawn Lin 		ret = cqhci_suspend(host->mmc);
48084362d79SShawn Lin 		if (ret)
48184362d79SShawn Lin 			return ret;
48284362d79SShawn Lin 	}
48384362d79SShawn Lin 
484e3ec3a3dSSoren Brinkmann 	ret = sdhci_suspend_host(host);
485e3ec3a3dSSoren Brinkmann 	if (ret)
486e3ec3a3dSSoren Brinkmann 		return ret;
487e3ec3a3dSSoren Brinkmann 
488b2db9c67SDouglas Anderson 	if (!IS_ERR(sdhci_arasan->phy) && sdhci_arasan->is_phy_on) {
48991aa3661SShawn Lin 		ret = phy_power_off(sdhci_arasan->phy);
49091aa3661SShawn Lin 		if (ret) {
49191aa3661SShawn Lin 			dev_err(dev, "Cannot power off phy.\n");
492*66bad6edSManish Narani 			if (sdhci_resume_host(host))
493*66bad6edSManish Narani 				dev_err(dev, "Cannot resume host.\n");
494*66bad6edSManish Narani 
49591aa3661SShawn Lin 			return ret;
49691aa3661SShawn Lin 		}
497b2db9c67SDouglas Anderson 		sdhci_arasan->is_phy_on = false;
49891aa3661SShawn Lin 	}
49991aa3661SShawn Lin 
500e3ec3a3dSSoren Brinkmann 	clk_disable(pltfm_host->clk);
501e3ec3a3dSSoren Brinkmann 	clk_disable(sdhci_arasan->clk_ahb);
502e3ec3a3dSSoren Brinkmann 
503e3ec3a3dSSoren Brinkmann 	return 0;
504e3ec3a3dSSoren Brinkmann }
505e3ec3a3dSSoren Brinkmann 
506e3ec3a3dSSoren Brinkmann /**
507e3ec3a3dSSoren Brinkmann  * sdhci_arasan_resume - Resume method for the driver
508e3ec3a3dSSoren Brinkmann  * @dev:	Address of the device structure
509e3ec3a3dSSoren Brinkmann  *
510e3ec3a3dSSoren Brinkmann  * Resume operation after suspend
5114908460eSManish Narani  *
5124908460eSManish Narani  * Return: 0 on success and error value on error
513e3ec3a3dSSoren Brinkmann  */
514e3ec3a3dSSoren Brinkmann static int sdhci_arasan_resume(struct device *dev)
515e3ec3a3dSSoren Brinkmann {
516970f2d90SWolfram Sang 	struct sdhci_host *host = dev_get_drvdata(dev);
517e3ec3a3dSSoren Brinkmann 	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
51889211418SJisheng Zhang 	struct sdhci_arasan_data *sdhci_arasan = sdhci_pltfm_priv(pltfm_host);
519e3ec3a3dSSoren Brinkmann 	int ret;
520e3ec3a3dSSoren Brinkmann 
521e3ec3a3dSSoren Brinkmann 	ret = clk_enable(sdhci_arasan->clk_ahb);
522e3ec3a3dSSoren Brinkmann 	if (ret) {
523e3ec3a3dSSoren Brinkmann 		dev_err(dev, "Cannot enable AHB clock.\n");
524e3ec3a3dSSoren Brinkmann 		return ret;
525e3ec3a3dSSoren Brinkmann 	}
526e3ec3a3dSSoren Brinkmann 
527e3ec3a3dSSoren Brinkmann 	ret = clk_enable(pltfm_host->clk);
528e3ec3a3dSSoren Brinkmann 	if (ret) {
529e3ec3a3dSSoren Brinkmann 		dev_err(dev, "Cannot enable SD clock.\n");
530e3ec3a3dSSoren Brinkmann 		return ret;
531e3ec3a3dSSoren Brinkmann 	}
532e3ec3a3dSSoren Brinkmann 
533b2db9c67SDouglas Anderson 	if (!IS_ERR(sdhci_arasan->phy) && host->mmc->actual_clock) {
53491aa3661SShawn Lin 		ret = phy_power_on(sdhci_arasan->phy);
53591aa3661SShawn Lin 		if (ret) {
53691aa3661SShawn Lin 			dev_err(dev, "Cannot power on phy.\n");
53791aa3661SShawn Lin 			return ret;
53891aa3661SShawn Lin 		}
539b2db9c67SDouglas Anderson 		sdhci_arasan->is_phy_on = true;
54091aa3661SShawn Lin 	}
54191aa3661SShawn Lin 
54284362d79SShawn Lin 	ret = sdhci_resume_host(host);
54384362d79SShawn Lin 	if (ret) {
54484362d79SShawn Lin 		dev_err(dev, "Cannot resume host.\n");
54584362d79SShawn Lin 		return ret;
54684362d79SShawn Lin 	}
54784362d79SShawn Lin 
54884362d79SShawn Lin 	if (sdhci_arasan->has_cqe)
54984362d79SShawn Lin 		return cqhci_resume(host->mmc);
55084362d79SShawn Lin 
55184362d79SShawn Lin 	return 0;
552e3ec3a3dSSoren Brinkmann }
553e3ec3a3dSSoren Brinkmann #endif /* ! CONFIG_PM_SLEEP */
554e3ec3a3dSSoren Brinkmann 
555e3ec3a3dSSoren Brinkmann static SIMPLE_DEV_PM_OPS(sdhci_arasan_dev_pm_ops, sdhci_arasan_suspend,
556e3ec3a3dSSoren Brinkmann 			 sdhci_arasan_resume);
557e3ec3a3dSSoren Brinkmann 
5583ea4666eSDouglas Anderson /**
559c390f211SDouglas Anderson  * sdhci_arasan_sdcardclk_recalc_rate - Return the card clock rate
560c390f211SDouglas Anderson  *
5614908460eSManish Narani  * @hw:			Pointer to the hardware clock structure.
5624908460eSManish Narani  * @parent_rate:		The parent rate (should be rate of clk_xin).
5634908460eSManish Narani  *
564c390f211SDouglas Anderson  * Return the current actual rate of the SD card clock.  This can be used
565c390f211SDouglas Anderson  * to communicate with out PHY.
566c390f211SDouglas Anderson  *
5674908460eSManish Narani  * Return: The card clock rate.
568c390f211SDouglas Anderson  */
569c390f211SDouglas Anderson static unsigned long sdhci_arasan_sdcardclk_recalc_rate(struct clk_hw *hw,
570c390f211SDouglas Anderson 						      unsigned long parent_rate)
571c390f211SDouglas Anderson {
572e1463618SManish Narani 	struct sdhci_arasan_clk_data *clk_data =
573e1463618SManish Narani 		container_of(hw, struct sdhci_arasan_clk_data, sdcardclk_hw);
574c390f211SDouglas Anderson 	struct sdhci_arasan_data *sdhci_arasan =
575e1463618SManish Narani 		container_of(clk_data, struct sdhci_arasan_data, clk_data);
576c390f211SDouglas Anderson 	struct sdhci_host *host = sdhci_arasan->host;
577c390f211SDouglas Anderson 
578c390f211SDouglas Anderson 	return host->mmc->actual_clock;
579c390f211SDouglas Anderson }
580c390f211SDouglas Anderson 
581c390f211SDouglas Anderson static const struct clk_ops arasan_sdcardclk_ops = {
582c390f211SDouglas Anderson 	.recalc_rate = sdhci_arasan_sdcardclk_recalc_rate,
583c390f211SDouglas Anderson };
584c390f211SDouglas Anderson 
585c390f211SDouglas Anderson /**
58607a14d1dSManish Narani  * sdhci_arasan_sampleclk_recalc_rate - Return the sampling clock rate
58707a14d1dSManish Narani  *
5884908460eSManish Narani  * @hw:			Pointer to the hardware clock structure.
5894908460eSManish Narani  * @parent_rate:		The parent rate (should be rate of clk_xin).
5904908460eSManish Narani  *
59107a14d1dSManish Narani  * Return the current actual rate of the sampling clock.  This can be used
59207a14d1dSManish Narani  * to communicate with out PHY.
59307a14d1dSManish Narani  *
5944908460eSManish Narani  * Return: The sample clock rate.
59507a14d1dSManish Narani  */
59607a14d1dSManish Narani static unsigned long sdhci_arasan_sampleclk_recalc_rate(struct clk_hw *hw,
59707a14d1dSManish Narani 						      unsigned long parent_rate)
59807a14d1dSManish Narani {
59907a14d1dSManish Narani 	struct sdhci_arasan_clk_data *clk_data =
60007a14d1dSManish Narani 		container_of(hw, struct sdhci_arasan_clk_data, sampleclk_hw);
60107a14d1dSManish Narani 	struct sdhci_arasan_data *sdhci_arasan =
60207a14d1dSManish Narani 		container_of(clk_data, struct sdhci_arasan_data, clk_data);
60307a14d1dSManish Narani 	struct sdhci_host *host = sdhci_arasan->host;
60407a14d1dSManish Narani 
60507a14d1dSManish Narani 	return host->mmc->actual_clock;
60607a14d1dSManish Narani }
60707a14d1dSManish Narani 
60807a14d1dSManish Narani static const struct clk_ops arasan_sampleclk_ops = {
60907a14d1dSManish Narani 	.recalc_rate = sdhci_arasan_sampleclk_recalc_rate,
61007a14d1dSManish Narani };
61107a14d1dSManish Narani 
61207a14d1dSManish Narani /**
613a5c8b2aeSManish Narani  * sdhci_zynqmp_sdcardclk_set_phase - Set the SD Output Clock Tap Delays
614a5c8b2aeSManish Narani  *
6154908460eSManish Narani  * @hw:			Pointer to the hardware clock structure.
6164908460eSManish Narani  * @degrees:		The clock phase shift between 0 - 359.
6174908460eSManish Narani  *
618a5c8b2aeSManish Narani  * Set the SD Output Clock Tap Delays for Output path
619a5c8b2aeSManish Narani  *
620a5c8b2aeSManish Narani  * Return: 0 on success and error value on error
621a5c8b2aeSManish Narani  */
622a5c8b2aeSManish Narani static int sdhci_zynqmp_sdcardclk_set_phase(struct clk_hw *hw, int degrees)
623a5c8b2aeSManish Narani {
624a5c8b2aeSManish Narani 	struct sdhci_arasan_clk_data *clk_data =
625a5c8b2aeSManish Narani 		container_of(hw, struct sdhci_arasan_clk_data, sdcardclk_hw);
626a5c8b2aeSManish Narani 	struct sdhci_arasan_data *sdhci_arasan =
627a5c8b2aeSManish Narani 		container_of(clk_data, struct sdhci_arasan_data, clk_data);
628a5c8b2aeSManish Narani 	struct sdhci_host *host = sdhci_arasan->host;
629a5c8b2aeSManish Narani 	const char *clk_name = clk_hw_get_name(hw);
630a5c8b2aeSManish Narani 	u32 node_id = !strcmp(clk_name, "clk_out_sd0") ? NODE_SD_0 : NODE_SD_1;
631a5c8b2aeSManish Narani 	u8 tap_delay, tap_max = 0;
632a5c8b2aeSManish Narani 	int ret;
633a5c8b2aeSManish Narani 
6349e953432SManish Narani 	/* This is applicable for SDHCI_SPEC_300 and above */
6359e953432SManish Narani 	if (host->version < SDHCI_SPEC_300)
636a5c8b2aeSManish Narani 		return 0;
637a5c8b2aeSManish Narani 
638a5c8b2aeSManish Narani 	switch (host->timing) {
639a5c8b2aeSManish Narani 	case MMC_TIMING_MMC_HS:
640a5c8b2aeSManish Narani 	case MMC_TIMING_SD_HS:
641a5c8b2aeSManish Narani 	case MMC_TIMING_UHS_SDR25:
642a5c8b2aeSManish Narani 	case MMC_TIMING_UHS_DDR50:
643a5c8b2aeSManish Narani 	case MMC_TIMING_MMC_DDR52:
644a5c8b2aeSManish Narani 		/* For 50MHz clock, 30 Taps are available */
645a5c8b2aeSManish Narani 		tap_max = 30;
646a5c8b2aeSManish Narani 		break;
647a5c8b2aeSManish Narani 	case MMC_TIMING_UHS_SDR50:
648a5c8b2aeSManish Narani 		/* For 100MHz clock, 15 Taps are available */
649a5c8b2aeSManish Narani 		tap_max = 15;
650a5c8b2aeSManish Narani 		break;
651a5c8b2aeSManish Narani 	case MMC_TIMING_UHS_SDR104:
652a5c8b2aeSManish Narani 	case MMC_TIMING_MMC_HS200:
653a5c8b2aeSManish Narani 		/* For 200MHz clock, 8 Taps are available */
654a5c8b2aeSManish Narani 		tap_max = 8;
655a3096ec6SGustavo A. R. Silva 		break;
656a5c8b2aeSManish Narani 	default:
657a5c8b2aeSManish Narani 		break;
658a5c8b2aeSManish Narani 	}
659a5c8b2aeSManish Narani 
660a5c8b2aeSManish Narani 	tap_delay = (degrees * tap_max) / 360;
661a5c8b2aeSManish Narani 
662a5c8b2aeSManish Narani 	/* Set the Clock Phase */
663426c8d85SRajan Vaja 	ret = zynqmp_pm_set_sd_tapdelay(node_id, PM_TAPDELAY_OUTPUT, tap_delay);
664a5c8b2aeSManish Narani 	if (ret)
665a5c8b2aeSManish Narani 		pr_err("Error setting Output Tap Delay\n");
666a5c8b2aeSManish Narani 
667d06d60d5SManish Narani 	/* Release DLL Reset */
668d06d60d5SManish Narani 	zynqmp_pm_sd_dll_reset(node_id, PM_DLL_RESET_RELEASE);
669d06d60d5SManish Narani 
670a5c8b2aeSManish Narani 	return ret;
671a5c8b2aeSManish Narani }
672a5c8b2aeSManish Narani 
673a5c8b2aeSManish Narani static const struct clk_ops zynqmp_sdcardclk_ops = {
674a5c8b2aeSManish Narani 	.recalc_rate = sdhci_arasan_sdcardclk_recalc_rate,
675a5c8b2aeSManish Narani 	.set_phase = sdhci_zynqmp_sdcardclk_set_phase,
676a5c8b2aeSManish Narani };
677a5c8b2aeSManish Narani 
678a5c8b2aeSManish Narani /**
679a5c8b2aeSManish Narani  * sdhci_zynqmp_sampleclk_set_phase - Set the SD Input Clock Tap Delays
680a5c8b2aeSManish Narani  *
6814908460eSManish Narani  * @hw:			Pointer to the hardware clock structure.
6824908460eSManish Narani  * @degrees:		The clock phase shift between 0 - 359.
6834908460eSManish Narani  *
684a5c8b2aeSManish Narani  * Set the SD Input Clock Tap Delays for Input path
685a5c8b2aeSManish Narani  *
686a5c8b2aeSManish Narani  * Return: 0 on success and error value on error
687a5c8b2aeSManish Narani  */
688a5c8b2aeSManish Narani static int sdhci_zynqmp_sampleclk_set_phase(struct clk_hw *hw, int degrees)
689a5c8b2aeSManish Narani {
690a5c8b2aeSManish Narani 	struct sdhci_arasan_clk_data *clk_data =
691a5c8b2aeSManish Narani 		container_of(hw, struct sdhci_arasan_clk_data, sampleclk_hw);
692a5c8b2aeSManish Narani 	struct sdhci_arasan_data *sdhci_arasan =
693a5c8b2aeSManish Narani 		container_of(clk_data, struct sdhci_arasan_data, clk_data);
694a5c8b2aeSManish Narani 	struct sdhci_host *host = sdhci_arasan->host;
695a5c8b2aeSManish Narani 	const char *clk_name = clk_hw_get_name(hw);
696a5c8b2aeSManish Narani 	u32 node_id = !strcmp(clk_name, "clk_in_sd0") ? NODE_SD_0 : NODE_SD_1;
697a5c8b2aeSManish Narani 	u8 tap_delay, tap_max = 0;
698a5c8b2aeSManish Narani 	int ret;
699a5c8b2aeSManish Narani 
7009e953432SManish Narani 	/* This is applicable for SDHCI_SPEC_300 and above */
7019e953432SManish Narani 	if (host->version < SDHCI_SPEC_300)
702a5c8b2aeSManish Narani 		return 0;
703a5c8b2aeSManish Narani 
704d06d60d5SManish Narani 	/* Assert DLL Reset */
705d06d60d5SManish Narani 	zynqmp_pm_sd_dll_reset(node_id, PM_DLL_RESET_ASSERT);
706d06d60d5SManish Narani 
707a5c8b2aeSManish Narani 	switch (host->timing) {
708a5c8b2aeSManish Narani 	case MMC_TIMING_MMC_HS:
709a5c8b2aeSManish Narani 	case MMC_TIMING_SD_HS:
710a5c8b2aeSManish Narani 	case MMC_TIMING_UHS_SDR25:
711a5c8b2aeSManish Narani 	case MMC_TIMING_UHS_DDR50:
712a5c8b2aeSManish Narani 	case MMC_TIMING_MMC_DDR52:
713a5c8b2aeSManish Narani 		/* For 50MHz clock, 120 Taps are available */
714a5c8b2aeSManish Narani 		tap_max = 120;
715a5c8b2aeSManish Narani 		break;
716a5c8b2aeSManish Narani 	case MMC_TIMING_UHS_SDR50:
717a5c8b2aeSManish Narani 		/* For 100MHz clock, 60 Taps are available */
718a5c8b2aeSManish Narani 		tap_max = 60;
719a5c8b2aeSManish Narani 		break;
720a5c8b2aeSManish Narani 	case MMC_TIMING_UHS_SDR104:
721a5c8b2aeSManish Narani 	case MMC_TIMING_MMC_HS200:
722a5c8b2aeSManish Narani 		/* For 200MHz clock, 30 Taps are available */
723a5c8b2aeSManish Narani 		tap_max = 30;
724a3096ec6SGustavo A. R. Silva 		break;
725a5c8b2aeSManish Narani 	default:
726a5c8b2aeSManish Narani 		break;
727a5c8b2aeSManish Narani 	}
728a5c8b2aeSManish Narani 
729a5c8b2aeSManish Narani 	tap_delay = (degrees * tap_max) / 360;
730a5c8b2aeSManish Narani 
731a5c8b2aeSManish Narani 	/* Set the Clock Phase */
732426c8d85SRajan Vaja 	ret = zynqmp_pm_set_sd_tapdelay(node_id, PM_TAPDELAY_INPUT, tap_delay);
733a5c8b2aeSManish Narani 	if (ret)
734a5c8b2aeSManish Narani 		pr_err("Error setting Input Tap Delay\n");
735a5c8b2aeSManish Narani 
736a5c8b2aeSManish Narani 	return ret;
737a5c8b2aeSManish Narani }
738a5c8b2aeSManish Narani 
739a5c8b2aeSManish Narani static const struct clk_ops zynqmp_sampleclk_ops = {
740a5c8b2aeSManish Narani 	.recalc_rate = sdhci_arasan_sampleclk_recalc_rate,
741a5c8b2aeSManish Narani 	.set_phase = sdhci_zynqmp_sampleclk_set_phase,
742a5c8b2aeSManish Narani };
743a5c8b2aeSManish Narani 
7441a470721SManish Narani /**
7451a470721SManish Narani  * sdhci_versal_sdcardclk_set_phase - Set the SD Output Clock Tap Delays
7461a470721SManish Narani  *
7474908460eSManish Narani  * @hw:			Pointer to the hardware clock structure.
7484908460eSManish Narani  * @degrees:		The clock phase shift between 0 - 359.
7494908460eSManish Narani  *
7501a470721SManish Narani  * Set the SD Output Clock Tap Delays for Output path
7511a470721SManish Narani  *
7521a470721SManish Narani  * Return: 0 on success and error value on error
7531a470721SManish Narani  */
7541a470721SManish Narani static int sdhci_versal_sdcardclk_set_phase(struct clk_hw *hw, int degrees)
7551a470721SManish Narani {
7561a470721SManish Narani 	struct sdhci_arasan_clk_data *clk_data =
7571a470721SManish Narani 		container_of(hw, struct sdhci_arasan_clk_data, sdcardclk_hw);
7581a470721SManish Narani 	struct sdhci_arasan_data *sdhci_arasan =
7591a470721SManish Narani 		container_of(clk_data, struct sdhci_arasan_data, clk_data);
7601a470721SManish Narani 	struct sdhci_host *host = sdhci_arasan->host;
7611a470721SManish Narani 	u8 tap_delay, tap_max = 0;
7621a470721SManish Narani 
7639e953432SManish Narani 	/* This is applicable for SDHCI_SPEC_300 and above */
7649e953432SManish Narani 	if (host->version < SDHCI_SPEC_300)
7651a470721SManish Narani 		return 0;
7661a470721SManish Narani 
7671a470721SManish Narani 	switch (host->timing) {
7681a470721SManish Narani 	case MMC_TIMING_MMC_HS:
7691a470721SManish Narani 	case MMC_TIMING_SD_HS:
7701a470721SManish Narani 	case MMC_TIMING_UHS_SDR25:
7711a470721SManish Narani 	case MMC_TIMING_UHS_DDR50:
7721a470721SManish Narani 	case MMC_TIMING_MMC_DDR52:
7731a470721SManish Narani 		/* For 50MHz clock, 30 Taps are available */
7741a470721SManish Narani 		tap_max = 30;
7751a470721SManish Narani 		break;
7761a470721SManish Narani 	case MMC_TIMING_UHS_SDR50:
7771a470721SManish Narani 		/* For 100MHz clock, 15 Taps are available */
7781a470721SManish Narani 		tap_max = 15;
7791a470721SManish Narani 		break;
7801a470721SManish Narani 	case MMC_TIMING_UHS_SDR104:
7811a470721SManish Narani 	case MMC_TIMING_MMC_HS200:
7821a470721SManish Narani 		/* For 200MHz clock, 8 Taps are available */
7831a470721SManish Narani 		tap_max = 8;
784a3096ec6SGustavo A. R. Silva 		break;
7851a470721SManish Narani 	default:
7861a470721SManish Narani 		break;
7871a470721SManish Narani 	}
7881a470721SManish Narani 
7891a470721SManish Narani 	tap_delay = (degrees * tap_max) / 360;
7901a470721SManish Narani 
7911a470721SManish Narani 	/* Set the Clock Phase */
7921a470721SManish Narani 	if (tap_delay) {
7931a470721SManish Narani 		u32 regval;
7941a470721SManish Narani 
7951a470721SManish Narani 		regval = sdhci_readl(host, SDHCI_ARASAN_OTAPDLY_REGISTER);
7961a470721SManish Narani 		regval |= SDHCI_OTAPDLY_ENABLE;
7971a470721SManish Narani 		sdhci_writel(host, regval, SDHCI_ARASAN_OTAPDLY_REGISTER);
798d338c6d0SManish Narani 		regval &= ~SDHCI_ARASAN_OTAPDLY_SEL_MASK;
7991a470721SManish Narani 		regval |= tap_delay;
8001a470721SManish Narani 		sdhci_writel(host, regval, SDHCI_ARASAN_OTAPDLY_REGISTER);
8011a470721SManish Narani 	}
8021a470721SManish Narani 
803098c408bSNathan Chancellor 	return 0;
8041a470721SManish Narani }
8051a470721SManish Narani 
8061a470721SManish Narani static const struct clk_ops versal_sdcardclk_ops = {
8071a470721SManish Narani 	.recalc_rate = sdhci_arasan_sdcardclk_recalc_rate,
8081a470721SManish Narani 	.set_phase = sdhci_versal_sdcardclk_set_phase,
8091a470721SManish Narani };
8101a470721SManish Narani 
8111a470721SManish Narani /**
8121a470721SManish Narani  * sdhci_versal_sampleclk_set_phase - Set the SD Input Clock Tap Delays
8131a470721SManish Narani  *
8144908460eSManish Narani  * @hw:			Pointer to the hardware clock structure.
8154908460eSManish Narani  * @degrees:		The clock phase shift between 0 - 359.
8164908460eSManish Narani  *
8171a470721SManish Narani  * Set the SD Input Clock Tap Delays for Input path
8181a470721SManish Narani  *
8191a470721SManish Narani  * Return: 0 on success and error value on error
8201a470721SManish Narani  */
8211a470721SManish Narani static int sdhci_versal_sampleclk_set_phase(struct clk_hw *hw, int degrees)
8221a470721SManish Narani {
8231a470721SManish Narani 	struct sdhci_arasan_clk_data *clk_data =
8241a470721SManish Narani 		container_of(hw, struct sdhci_arasan_clk_data, sampleclk_hw);
8251a470721SManish Narani 	struct sdhci_arasan_data *sdhci_arasan =
8261a470721SManish Narani 		container_of(clk_data, struct sdhci_arasan_data, clk_data);
8271a470721SManish Narani 	struct sdhci_host *host = sdhci_arasan->host;
8281a470721SManish Narani 	u8 tap_delay, tap_max = 0;
8291a470721SManish Narani 
8309e953432SManish Narani 	/* This is applicable for SDHCI_SPEC_300 and above */
8319e953432SManish Narani 	if (host->version < SDHCI_SPEC_300)
8321a470721SManish Narani 		return 0;
8331a470721SManish Narani 
8341a470721SManish Narani 	switch (host->timing) {
8351a470721SManish Narani 	case MMC_TIMING_MMC_HS:
8361a470721SManish Narani 	case MMC_TIMING_SD_HS:
8371a470721SManish Narani 	case MMC_TIMING_UHS_SDR25:
8381a470721SManish Narani 	case MMC_TIMING_UHS_DDR50:
8391a470721SManish Narani 	case MMC_TIMING_MMC_DDR52:
8401a470721SManish Narani 		/* For 50MHz clock, 120 Taps are available */
8411a470721SManish Narani 		tap_max = 120;
8421a470721SManish Narani 		break;
8431a470721SManish Narani 	case MMC_TIMING_UHS_SDR50:
8441a470721SManish Narani 		/* For 100MHz clock, 60 Taps are available */
8451a470721SManish Narani 		tap_max = 60;
8461a470721SManish Narani 		break;
8471a470721SManish Narani 	case MMC_TIMING_UHS_SDR104:
8481a470721SManish Narani 	case MMC_TIMING_MMC_HS200:
8491a470721SManish Narani 		/* For 200MHz clock, 30 Taps are available */
8501a470721SManish Narani 		tap_max = 30;
851a3096ec6SGustavo A. R. Silva 		break;
8521a470721SManish Narani 	default:
8531a470721SManish Narani 		break;
8541a470721SManish Narani 	}
8551a470721SManish Narani 
8561a470721SManish Narani 	tap_delay = (degrees * tap_max) / 360;
8571a470721SManish Narani 
8581a470721SManish Narani 	/* Set the Clock Phase */
8591a470721SManish Narani 	if (tap_delay) {
8601a470721SManish Narani 		u32 regval;
8611a470721SManish Narani 
8621a470721SManish Narani 		regval = sdhci_readl(host, SDHCI_ARASAN_ITAPDLY_REGISTER);
8631a470721SManish Narani 		regval |= SDHCI_ITAPDLY_CHGWIN;
8641a470721SManish Narani 		sdhci_writel(host, regval, SDHCI_ARASAN_ITAPDLY_REGISTER);
8651a470721SManish Narani 		regval |= SDHCI_ITAPDLY_ENABLE;
8661a470721SManish Narani 		sdhci_writel(host, regval, SDHCI_ARASAN_ITAPDLY_REGISTER);
867d338c6d0SManish Narani 		regval &= ~SDHCI_ARASAN_ITAPDLY_SEL_MASK;
8681a470721SManish Narani 		regval |= tap_delay;
8691a470721SManish Narani 		sdhci_writel(host, regval, SDHCI_ARASAN_ITAPDLY_REGISTER);
8701a470721SManish Narani 		regval &= ~SDHCI_ITAPDLY_CHGWIN;
8711a470721SManish Narani 		sdhci_writel(host, regval, SDHCI_ARASAN_ITAPDLY_REGISTER);
8721a470721SManish Narani 	}
8731a470721SManish Narani 
874098c408bSNathan Chancellor 	return 0;
8751a470721SManish Narani }
8761a470721SManish Narani 
8771a470721SManish Narani static const struct clk_ops versal_sampleclk_ops = {
8781a470721SManish Narani 	.recalc_rate = sdhci_arasan_sampleclk_recalc_rate,
8791a470721SManish Narani 	.set_phase = sdhci_versal_sampleclk_set_phase,
8801a470721SManish Narani };
8811a470721SManish Narani 
8828d2e3343SManish Narani static void arasan_zynqmp_dll_reset(struct sdhci_host *host, u32 deviceid)
8838d2e3343SManish Narani {
8848d2e3343SManish Narani 	u16 clk;
8858d2e3343SManish Narani 
8868d2e3343SManish Narani 	clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL);
8878d2e3343SManish Narani 	clk &= ~(SDHCI_CLOCK_CARD_EN | SDHCI_CLOCK_INT_EN);
8888d2e3343SManish Narani 	sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
8898d2e3343SManish Narani 
8908d2e3343SManish Narani 	/* Issue DLL Reset */
891426c8d85SRajan Vaja 	zynqmp_pm_sd_dll_reset(deviceid, PM_DLL_RESET_PULSE);
8928d2e3343SManish Narani 
8938d2e3343SManish Narani 	clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL);
8948d2e3343SManish Narani 
8958d2e3343SManish Narani 	sdhci_enable_clk(host, clk);
8968d2e3343SManish Narani }
8978d2e3343SManish Narani 
8988d2e3343SManish Narani static int arasan_zynqmp_execute_tuning(struct mmc_host *mmc, u32 opcode)
8998d2e3343SManish Narani {
9008d2e3343SManish Narani 	struct sdhci_host *host = mmc_priv(mmc);
9018d2e3343SManish Narani 	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
9028d2e3343SManish Narani 	struct sdhci_arasan_data *sdhci_arasan = sdhci_pltfm_priv(pltfm_host);
9038d2e3343SManish Narani 	struct clk_hw *hw = &sdhci_arasan->clk_data.sdcardclk_hw;
9048d2e3343SManish Narani 	const char *clk_name = clk_hw_get_name(hw);
9058d2e3343SManish Narani 	u32 device_id = !strcmp(clk_name, "clk_out_sd0") ? NODE_SD_0 :
9068d2e3343SManish Narani 							   NODE_SD_1;
9078d2e3343SManish Narani 	int err;
9088d2e3343SManish Narani 
909256e4e4eSManish Narani 	/* ZynqMP SD controller does not perform auto tuning in DDR50 mode */
910256e4e4eSManish Narani 	if (mmc->ios.timing == MMC_TIMING_UHS_DDR50)
911256e4e4eSManish Narani 		return 0;
912256e4e4eSManish Narani 
9138d2e3343SManish Narani 	arasan_zynqmp_dll_reset(host, device_id);
9148d2e3343SManish Narani 
9158d2e3343SManish Narani 	err = sdhci_execute_tuning(mmc, opcode);
9168d2e3343SManish Narani 	if (err)
9178d2e3343SManish Narani 		return err;
9188d2e3343SManish Narani 
9198d2e3343SManish Narani 	arasan_zynqmp_dll_reset(host, device_id);
9208d2e3343SManish Narani 
9218d2e3343SManish Narani 	return 0;
9228d2e3343SManish Narani }
9238d2e3343SManish Narani 
924a5c8b2aeSManish Narani /**
925b2ca77c9SShawn Lin  * sdhci_arasan_update_clockmultiplier - Set corecfg_clockmultiplier
926b2ca77c9SShawn Lin  *
9274908460eSManish Narani  * @host:		The sdhci_host
9284908460eSManish Narani  * @value:		The value to write
9294908460eSManish Narani  *
930b2ca77c9SShawn Lin  * The corecfg_clockmultiplier is supposed to contain clock multiplier
931b2ca77c9SShawn Lin  * value of programmable clock generator.
932b2ca77c9SShawn Lin  *
933b2ca77c9SShawn Lin  * NOTES:
934b2ca77c9SShawn Lin  * - Many existing devices don't seem to do this and work fine.  To keep
935b2ca77c9SShawn Lin  *   compatibility for old hardware where the device tree doesn't provide a
936b2ca77c9SShawn Lin  *   register map, this function is a noop if a soc_ctl_map hasn't been provided
937b2ca77c9SShawn Lin  *   for this platform.
938b2ca77c9SShawn Lin  * - The value of corecfg_clockmultiplier should sync with that of corresponding
939b2ca77c9SShawn Lin  *   value reading from sdhci_capability_register. So this function is called
940b2ca77c9SShawn Lin  *   once at probe time and never called again.
941b2ca77c9SShawn Lin  */
942b2ca77c9SShawn Lin static void sdhci_arasan_update_clockmultiplier(struct sdhci_host *host,
943b2ca77c9SShawn Lin 						u32 value)
944b2ca77c9SShawn Lin {
945b2ca77c9SShawn Lin 	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
946b2ca77c9SShawn Lin 	struct sdhci_arasan_data *sdhci_arasan = sdhci_pltfm_priv(pltfm_host);
947b2ca77c9SShawn Lin 	const struct sdhci_arasan_soc_ctl_map *soc_ctl_map =
948b2ca77c9SShawn Lin 		sdhci_arasan->soc_ctl_map;
949b2ca77c9SShawn Lin 
950b2ca77c9SShawn Lin 	/* Having a map is optional */
951b2ca77c9SShawn Lin 	if (!soc_ctl_map)
952b2ca77c9SShawn Lin 		return;
953b2ca77c9SShawn Lin 
954b2ca77c9SShawn Lin 	/* If we have a map, we expect to have a syscon */
955b2ca77c9SShawn Lin 	if (!sdhci_arasan->soc_ctl_base) {
956b2ca77c9SShawn Lin 		pr_warn("%s: Have regmap, but no soc-ctl-syscon\n",
957b2ca77c9SShawn Lin 			mmc_hostname(host->mmc));
958b2ca77c9SShawn Lin 		return;
959b2ca77c9SShawn Lin 	}
960b2ca77c9SShawn Lin 
961b2ca77c9SShawn Lin 	sdhci_arasan_syscon_write(host, &soc_ctl_map->clockmultiplier, value);
962b2ca77c9SShawn Lin }
963b2ca77c9SShawn Lin 
964b2ca77c9SShawn Lin /**
9653ea4666eSDouglas Anderson  * sdhci_arasan_update_baseclkfreq - Set corecfg_baseclkfreq
9663ea4666eSDouglas Anderson  *
9674908460eSManish Narani  * @host:		The sdhci_host
9684908460eSManish Narani  *
9693ea4666eSDouglas Anderson  * The corecfg_baseclkfreq is supposed to contain the MHz of clk_xin.  This
9703ea4666eSDouglas Anderson  * function can be used to make that happen.
9713ea4666eSDouglas Anderson  *
9723ea4666eSDouglas Anderson  * NOTES:
9733ea4666eSDouglas Anderson  * - Many existing devices don't seem to do this and work fine.  To keep
9743ea4666eSDouglas Anderson  *   compatibility for old hardware where the device tree doesn't provide a
9753ea4666eSDouglas Anderson  *   register map, this function is a noop if a soc_ctl_map hasn't been provided
9763ea4666eSDouglas Anderson  *   for this platform.
9773ea4666eSDouglas Anderson  * - It's assumed that clk_xin is not dynamic and that we use the SDHCI divider
9783ea4666eSDouglas Anderson  *   to achieve lower clock rates.  That means that this function is called once
9793ea4666eSDouglas Anderson  *   at probe time and never called again.
9803ea4666eSDouglas Anderson  */
9813ea4666eSDouglas Anderson static void sdhci_arasan_update_baseclkfreq(struct sdhci_host *host)
9823ea4666eSDouglas Anderson {
9833ea4666eSDouglas Anderson 	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
9843ea4666eSDouglas Anderson 	struct sdhci_arasan_data *sdhci_arasan = sdhci_pltfm_priv(pltfm_host);
9853ea4666eSDouglas Anderson 	const struct sdhci_arasan_soc_ctl_map *soc_ctl_map =
9863ea4666eSDouglas Anderson 		sdhci_arasan->soc_ctl_map;
9873ea4666eSDouglas Anderson 	u32 mhz = DIV_ROUND_CLOSEST(clk_get_rate(pltfm_host->clk), 1000000);
9883ea4666eSDouglas Anderson 
9893ea4666eSDouglas Anderson 	/* Having a map is optional */
9903ea4666eSDouglas Anderson 	if (!soc_ctl_map)
9913ea4666eSDouglas Anderson 		return;
9923ea4666eSDouglas Anderson 
9933ea4666eSDouglas Anderson 	/* If we have a map, we expect to have a syscon */
9943ea4666eSDouglas Anderson 	if (!sdhci_arasan->soc_ctl_base) {
9953ea4666eSDouglas Anderson 		pr_warn("%s: Have regmap, but no soc-ctl-syscon\n",
9963ea4666eSDouglas Anderson 			mmc_hostname(host->mmc));
9973ea4666eSDouglas Anderson 		return;
9983ea4666eSDouglas Anderson 	}
9993ea4666eSDouglas Anderson 
10003ea4666eSDouglas Anderson 	sdhci_arasan_syscon_write(host, &soc_ctl_map->baseclkfreq, mhz);
10013ea4666eSDouglas Anderson }
10023ea4666eSDouglas Anderson 
1003f3dafc37SManish Narani static void sdhci_arasan_set_clk_delays(struct sdhci_host *host)
1004f3dafc37SManish Narani {
1005f3dafc37SManish Narani 	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
1006f3dafc37SManish Narani 	struct sdhci_arasan_data *sdhci_arasan = sdhci_pltfm_priv(pltfm_host);
1007f3dafc37SManish Narani 	struct sdhci_arasan_clk_data *clk_data = &sdhci_arasan->clk_data;
1008f3dafc37SManish Narani 
1009f3dafc37SManish Narani 	clk_set_phase(clk_data->sampleclk,
1010f3dafc37SManish Narani 		      clk_data->clk_phase_in[host->timing]);
1011f3dafc37SManish Narani 	clk_set_phase(clk_data->sdcardclk,
1012f3dafc37SManish Narani 		      clk_data->clk_phase_out[host->timing]);
1013f3dafc37SManish Narani }
1014f3dafc37SManish Narani 
1015f3dafc37SManish Narani static void arasan_dt_read_clk_phase(struct device *dev,
1016f3dafc37SManish Narani 				     struct sdhci_arasan_clk_data *clk_data,
1017f3dafc37SManish Narani 				     unsigned int timing, const char *prop)
1018f3dafc37SManish Narani {
1019f3dafc37SManish Narani 	struct device_node *np = dev->of_node;
1020f3dafc37SManish Narani 
1021f3dafc37SManish Narani 	int clk_phase[2] = {0};
1022f3dafc37SManish Narani 
1023f3dafc37SManish Narani 	/*
1024f3dafc37SManish Narani 	 * Read Tap Delay values from DT, if the DT does not contain the
1025f3dafc37SManish Narani 	 * Tap Values then use the pre-defined values.
1026f3dafc37SManish Narani 	 */
1027f3dafc37SManish Narani 	if (of_property_read_variable_u32_array(np, prop, &clk_phase[0],
1028f3dafc37SManish Narani 						2, 0)) {
1029f3dafc37SManish Narani 		dev_dbg(dev, "Using predefined clock phase for %s = %d %d\n",
1030f3dafc37SManish Narani 			prop, clk_data->clk_phase_in[timing],
1031f3dafc37SManish Narani 			clk_data->clk_phase_out[timing]);
1032f3dafc37SManish Narani 		return;
1033f3dafc37SManish Narani 	}
1034f3dafc37SManish Narani 
1035f3dafc37SManish Narani 	/* The values read are Input and Output Clock Delays in order */
1036f3dafc37SManish Narani 	clk_data->clk_phase_in[timing] = clk_phase[0];
1037f3dafc37SManish Narani 	clk_data->clk_phase_out[timing] = clk_phase[1];
1038f3dafc37SManish Narani }
1039f3dafc37SManish Narani 
1040f3dafc37SManish Narani /**
1041f3dafc37SManish Narani  * arasan_dt_parse_clk_phases - Read Clock Delay values from DT
1042f3dafc37SManish Narani  *
1043f3dafc37SManish Narani  * @dev:		Pointer to our struct device.
1044f3dafc37SManish Narani  * @clk_data:		Pointer to the Clock Data structure
10454908460eSManish Narani  *
10464908460eSManish Narani  * Called at initialization to parse the values of Clock Delays.
1047f3dafc37SManish Narani  */
1048f3dafc37SManish Narani static void arasan_dt_parse_clk_phases(struct device *dev,
1049f3dafc37SManish Narani 				       struct sdhci_arasan_clk_data *clk_data)
1050f3dafc37SManish Narani {
1051a5c8b2aeSManish Narani 	u32 mio_bank = 0;
1052a5c8b2aeSManish Narani 	int i;
1053a5c8b2aeSManish Narani 
1054f3dafc37SManish Narani 	/*
1055f3dafc37SManish Narani 	 * This has been kept as a pointer and is assigned a function here.
1056f3dafc37SManish Narani 	 * So that different controller variants can assign their own handling
1057f3dafc37SManish Narani 	 * function.
1058f3dafc37SManish Narani 	 */
1059f3dafc37SManish Narani 	clk_data->set_clk_delays = sdhci_arasan_set_clk_delays;
1060f3dafc37SManish Narani 
1061a5c8b2aeSManish Narani 	if (of_device_is_compatible(dev->of_node, "xlnx,zynqmp-8.9a")) {
106288e1d0b1SManish Narani 		u32 zynqmp_iclk_phase[MMC_TIMING_MMC_HS400 + 1] =
106388e1d0b1SManish Narani 			ZYNQMP_ICLK_PHASE;
106488e1d0b1SManish Narani 		u32 zynqmp_oclk_phase[MMC_TIMING_MMC_HS400 + 1] =
106588e1d0b1SManish Narani 			ZYNQMP_OCLK_PHASE;
1066a5c8b2aeSManish Narani 
1067a5c8b2aeSManish Narani 		of_property_read_u32(dev->of_node, "xlnx,mio-bank", &mio_bank);
1068a5c8b2aeSManish Narani 		if (mio_bank == 2) {
106988e1d0b1SManish Narani 			zynqmp_oclk_phase[MMC_TIMING_UHS_SDR104] = 90;
107088e1d0b1SManish Narani 			zynqmp_oclk_phase[MMC_TIMING_MMC_HS200] = 90;
1071a5c8b2aeSManish Narani 		}
1072a5c8b2aeSManish Narani 
1073a5c8b2aeSManish Narani 		for (i = 0; i <= MMC_TIMING_MMC_HS400; i++) {
107488e1d0b1SManish Narani 			clk_data->clk_phase_in[i] = zynqmp_iclk_phase[i];
107588e1d0b1SManish Narani 			clk_data->clk_phase_out[i] = zynqmp_oclk_phase[i];
1076a5c8b2aeSManish Narani 		}
1077a5c8b2aeSManish Narani 	}
1078a5c8b2aeSManish Narani 
10791a470721SManish Narani 	if (of_device_is_compatible(dev->of_node, "xlnx,versal-8.9a")) {
108088e1d0b1SManish Narani 		u32 versal_iclk_phase[MMC_TIMING_MMC_HS400 + 1] =
108188e1d0b1SManish Narani 			VERSAL_ICLK_PHASE;
108288e1d0b1SManish Narani 		u32 versal_oclk_phase[MMC_TIMING_MMC_HS400 + 1] =
108388e1d0b1SManish Narani 			VERSAL_OCLK_PHASE;
10841a470721SManish Narani 
10851a470721SManish Narani 		for (i = 0; i <= MMC_TIMING_MMC_HS400; i++) {
108688e1d0b1SManish Narani 			clk_data->clk_phase_in[i] = versal_iclk_phase[i];
108788e1d0b1SManish Narani 			clk_data->clk_phase_out[i] = versal_oclk_phase[i];
10881a470721SManish Narani 		}
10891a470721SManish Narani 	}
10901a470721SManish Narani 
1091f3dafc37SManish Narani 	arasan_dt_read_clk_phase(dev, clk_data, MMC_TIMING_LEGACY,
1092f3dafc37SManish Narani 				 "clk-phase-legacy");
1093f3dafc37SManish Narani 	arasan_dt_read_clk_phase(dev, clk_data, MMC_TIMING_MMC_HS,
1094f3dafc37SManish Narani 				 "clk-phase-mmc-hs");
1095f3dafc37SManish Narani 	arasan_dt_read_clk_phase(dev, clk_data, MMC_TIMING_SD_HS,
1096f3dafc37SManish Narani 				 "clk-phase-sd-hs");
1097f3dafc37SManish Narani 	arasan_dt_read_clk_phase(dev, clk_data, MMC_TIMING_UHS_SDR12,
1098f3dafc37SManish Narani 				 "clk-phase-uhs-sdr12");
1099f3dafc37SManish Narani 	arasan_dt_read_clk_phase(dev, clk_data, MMC_TIMING_UHS_SDR25,
1100f3dafc37SManish Narani 				 "clk-phase-uhs-sdr25");
1101f3dafc37SManish Narani 	arasan_dt_read_clk_phase(dev, clk_data, MMC_TIMING_UHS_SDR50,
1102f3dafc37SManish Narani 				 "clk-phase-uhs-sdr50");
1103f3dafc37SManish Narani 	arasan_dt_read_clk_phase(dev, clk_data, MMC_TIMING_UHS_SDR104,
1104f3dafc37SManish Narani 				 "clk-phase-uhs-sdr104");
1105f3dafc37SManish Narani 	arasan_dt_read_clk_phase(dev, clk_data, MMC_TIMING_UHS_DDR50,
1106f3dafc37SManish Narani 				 "clk-phase-uhs-ddr50");
1107f3dafc37SManish Narani 	arasan_dt_read_clk_phase(dev, clk_data, MMC_TIMING_MMC_DDR52,
1108f3dafc37SManish Narani 				 "clk-phase-mmc-ddr52");
1109f3dafc37SManish Narani 	arasan_dt_read_clk_phase(dev, clk_data, MMC_TIMING_MMC_HS200,
1110f3dafc37SManish Narani 				 "clk-phase-mmc-hs200");
1111f3dafc37SManish Narani 	arasan_dt_read_clk_phase(dev, clk_data, MMC_TIMING_MMC_HS400,
1112f3dafc37SManish Narani 				 "clk-phase-mmc-hs400");
1113f3dafc37SManish Narani }
1114f3dafc37SManish Narani 
111537d3ee7cSManish Narani static const struct sdhci_pltfm_data sdhci_arasan_pdata = {
111637d3ee7cSManish Narani 	.ops = &sdhci_arasan_ops,
111737d3ee7cSManish Narani 	.quirks = SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN,
111837d3ee7cSManish Narani 	.quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN |
111937d3ee7cSManish Narani 			SDHCI_QUIRK2_CLOCK_DIV_ZERO_BROKEN |
112037d3ee7cSManish Narani 			SDHCI_QUIRK2_STOP_WITH_TC,
112137d3ee7cSManish Narani };
112237d3ee7cSManish Narani 
112316ada730SManish Narani static const struct sdhci_arasan_clk_ops arasan_clk_ops = {
112416ada730SManish Narani 	.sdcardclk_ops = &arasan_sdcardclk_ops,
112516ada730SManish Narani 	.sampleclk_ops = &arasan_sampleclk_ops,
112616ada730SManish Narani };
112716ada730SManish Narani 
112837d3ee7cSManish Narani static struct sdhci_arasan_of_data sdhci_arasan_generic_data = {
112937d3ee7cSManish Narani 	.pdata = &sdhci_arasan_pdata,
113016ada730SManish Narani 	.clk_ops = &arasan_clk_ops,
113137d3ee7cSManish Narani };
113237d3ee7cSManish Narani 
113336c6aadaSWan Ahmad Zainie static const struct sdhci_pltfm_data sdhci_keembay_emmc_pdata = {
113436c6aadaSWan Ahmad Zainie 	.ops = &sdhci_arasan_cqe_ops,
113536c6aadaSWan Ahmad Zainie 	.quirks = SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN |
113636c6aadaSWan Ahmad Zainie 		SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC |
113736c6aadaSWan Ahmad Zainie 		SDHCI_QUIRK_NO_LED |
113836c6aadaSWan Ahmad Zainie 		SDHCI_QUIRK_32BIT_DMA_ADDR |
113936c6aadaSWan Ahmad Zainie 		SDHCI_QUIRK_32BIT_DMA_SIZE |
114036c6aadaSWan Ahmad Zainie 		SDHCI_QUIRK_32BIT_ADMA_SIZE,
114136c6aadaSWan Ahmad Zainie 	.quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN |
114236c6aadaSWan Ahmad Zainie 		SDHCI_QUIRK2_CLOCK_DIV_ZERO_BROKEN |
114336c6aadaSWan Ahmad Zainie 		SDHCI_QUIRK2_CAPS_BIT63_FOR_HS400 |
114436c6aadaSWan Ahmad Zainie 		SDHCI_QUIRK2_STOP_WITH_TC |
114536c6aadaSWan Ahmad Zainie 		SDHCI_QUIRK2_BROKEN_64_BIT_DMA,
114636c6aadaSWan Ahmad Zainie };
114736c6aadaSWan Ahmad Zainie 
114836c6aadaSWan Ahmad Zainie static const struct sdhci_pltfm_data sdhci_keembay_sd_pdata = {
114936c6aadaSWan Ahmad Zainie 	.ops = &sdhci_arasan_ops,
115036c6aadaSWan Ahmad Zainie 	.quirks = SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN |
115136c6aadaSWan Ahmad Zainie 		SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC |
115236c6aadaSWan Ahmad Zainie 		SDHCI_QUIRK_NO_LED |
115336c6aadaSWan Ahmad Zainie 		SDHCI_QUIRK_32BIT_DMA_ADDR |
115436c6aadaSWan Ahmad Zainie 		SDHCI_QUIRK_32BIT_DMA_SIZE |
115536c6aadaSWan Ahmad Zainie 		SDHCI_QUIRK_32BIT_ADMA_SIZE,
115636c6aadaSWan Ahmad Zainie 	.quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN |
115736c6aadaSWan Ahmad Zainie 		SDHCI_QUIRK2_CLOCK_DIV_ZERO_BROKEN |
115836c6aadaSWan Ahmad Zainie 		SDHCI_QUIRK2_CARD_ON_NEEDS_BUS_ON |
115936c6aadaSWan Ahmad Zainie 		SDHCI_QUIRK2_STOP_WITH_TC |
116036c6aadaSWan Ahmad Zainie 		SDHCI_QUIRK2_BROKEN_64_BIT_DMA,
116136c6aadaSWan Ahmad Zainie };
116236c6aadaSWan Ahmad Zainie 
116336c6aadaSWan Ahmad Zainie static const struct sdhci_pltfm_data sdhci_keembay_sdio_pdata = {
116436c6aadaSWan Ahmad Zainie 	.ops = &sdhci_arasan_ops,
116536c6aadaSWan Ahmad Zainie 	.quirks = SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN |
116636c6aadaSWan Ahmad Zainie 		SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC |
116736c6aadaSWan Ahmad Zainie 		SDHCI_QUIRK_NO_LED |
116836c6aadaSWan Ahmad Zainie 		SDHCI_QUIRK_32BIT_DMA_ADDR |
116936c6aadaSWan Ahmad Zainie 		SDHCI_QUIRK_32BIT_DMA_SIZE |
117036c6aadaSWan Ahmad Zainie 		SDHCI_QUIRK_32BIT_ADMA_SIZE,
117136c6aadaSWan Ahmad Zainie 	.quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN |
117236c6aadaSWan Ahmad Zainie 		SDHCI_QUIRK2_CLOCK_DIV_ZERO_BROKEN |
117336c6aadaSWan Ahmad Zainie 		SDHCI_QUIRK2_HOST_OFF_CARD_ON |
117436c6aadaSWan Ahmad Zainie 		SDHCI_QUIRK2_BROKEN_64_BIT_DMA,
117536c6aadaSWan Ahmad Zainie };
117636c6aadaSWan Ahmad Zainie 
117737d3ee7cSManish Narani static struct sdhci_arasan_of_data sdhci_arasan_rk3399_data = {
117837d3ee7cSManish Narani 	.soc_ctl_map = &rk3399_soc_ctl_map,
117937d3ee7cSManish Narani 	.pdata = &sdhci_arasan_cqe_pdata,
118016ada730SManish Narani 	.clk_ops = &arasan_clk_ops,
118137d3ee7cSManish Narani };
118237d3ee7cSManish Narani 
118337d3ee7cSManish Narani static struct sdhci_arasan_of_data intel_lgm_emmc_data = {
118437d3ee7cSManish Narani 	.soc_ctl_map = &intel_lgm_emmc_soc_ctl_map,
118537d3ee7cSManish Narani 	.pdata = &sdhci_arasan_cqe_pdata,
118616ada730SManish Narani 	.clk_ops = &arasan_clk_ops,
118737d3ee7cSManish Narani };
118837d3ee7cSManish Narani 
118937d3ee7cSManish Narani static struct sdhci_arasan_of_data intel_lgm_sdxc_data = {
119037d3ee7cSManish Narani 	.soc_ctl_map = &intel_lgm_sdxc_soc_ctl_map,
119137d3ee7cSManish Narani 	.pdata = &sdhci_arasan_cqe_pdata,
119216ada730SManish Narani 	.clk_ops = &arasan_clk_ops,
119337d3ee7cSManish Narani };
119437d3ee7cSManish Narani 
119537d3ee7cSManish Narani static const struct sdhci_pltfm_data sdhci_arasan_zynqmp_pdata = {
119637d3ee7cSManish Narani 	.ops = &sdhci_arasan_ops,
119737d3ee7cSManish Narani 	.quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN |
119837d3ee7cSManish Narani 			SDHCI_QUIRK2_CLOCK_DIV_ZERO_BROKEN |
119937d3ee7cSManish Narani 			SDHCI_QUIRK2_STOP_WITH_TC,
120037d3ee7cSManish Narani };
120137d3ee7cSManish Narani 
120216ada730SManish Narani static const struct sdhci_arasan_clk_ops zynqmp_clk_ops = {
120316ada730SManish Narani 	.sdcardclk_ops = &zynqmp_sdcardclk_ops,
120416ada730SManish Narani 	.sampleclk_ops = &zynqmp_sampleclk_ops,
120516ada730SManish Narani };
120616ada730SManish Narani 
120737d3ee7cSManish Narani static struct sdhci_arasan_of_data sdhci_arasan_zynqmp_data = {
120837d3ee7cSManish Narani 	.pdata = &sdhci_arasan_zynqmp_pdata,
120916ada730SManish Narani 	.clk_ops = &zynqmp_clk_ops,
121016ada730SManish Narani };
121116ada730SManish Narani 
121216ada730SManish Narani static const struct sdhci_arasan_clk_ops versal_clk_ops = {
121316ada730SManish Narani 	.sdcardclk_ops = &versal_sdcardclk_ops,
121416ada730SManish Narani 	.sampleclk_ops = &versal_sampleclk_ops,
121537d3ee7cSManish Narani };
121637d3ee7cSManish Narani 
121737d3ee7cSManish Narani static struct sdhci_arasan_of_data sdhci_arasan_versal_data = {
121837d3ee7cSManish Narani 	.pdata = &sdhci_arasan_zynqmp_pdata,
121916ada730SManish Narani 	.clk_ops = &versal_clk_ops,
122037d3ee7cSManish Narani };
122137d3ee7cSManish Narani 
122236c6aadaSWan Ahmad Zainie static struct sdhci_arasan_of_data intel_keembay_emmc_data = {
122336c6aadaSWan Ahmad Zainie 	.soc_ctl_map = &intel_keembay_soc_ctl_map,
122436c6aadaSWan Ahmad Zainie 	.pdata = &sdhci_keembay_emmc_pdata,
1225a42a7ec9SMuhammad Husaini Zulkifli 	.clk_ops = &arasan_clk_ops,
122636c6aadaSWan Ahmad Zainie };
122736c6aadaSWan Ahmad Zainie 
122836c6aadaSWan Ahmad Zainie static struct sdhci_arasan_of_data intel_keembay_sd_data = {
122936c6aadaSWan Ahmad Zainie 	.soc_ctl_map = &intel_keembay_soc_ctl_map,
123036c6aadaSWan Ahmad Zainie 	.pdata = &sdhci_keembay_sd_pdata,
1231a42a7ec9SMuhammad Husaini Zulkifli 	.clk_ops = &arasan_clk_ops,
123236c6aadaSWan Ahmad Zainie };
123336c6aadaSWan Ahmad Zainie 
123436c6aadaSWan Ahmad Zainie static struct sdhci_arasan_of_data intel_keembay_sdio_data = {
123536c6aadaSWan Ahmad Zainie 	.soc_ctl_map = &intel_keembay_soc_ctl_map,
123636c6aadaSWan Ahmad Zainie 	.pdata = &sdhci_keembay_sdio_pdata,
1237a42a7ec9SMuhammad Husaini Zulkifli 	.clk_ops = &arasan_clk_ops,
123836c6aadaSWan Ahmad Zainie };
123936c6aadaSWan Ahmad Zainie 
124037d3ee7cSManish Narani static const struct of_device_id sdhci_arasan_of_match[] = {
124137d3ee7cSManish Narani 	/* SoC-specific compatible strings w/ soc_ctl_map */
124237d3ee7cSManish Narani 	{
124337d3ee7cSManish Narani 		.compatible = "rockchip,rk3399-sdhci-5.1",
124437d3ee7cSManish Narani 		.data = &sdhci_arasan_rk3399_data,
124537d3ee7cSManish Narani 	},
124637d3ee7cSManish Narani 	{
124737d3ee7cSManish Narani 		.compatible = "intel,lgm-sdhci-5.1-emmc",
124837d3ee7cSManish Narani 		.data = &intel_lgm_emmc_data,
124937d3ee7cSManish Narani 	},
125037d3ee7cSManish Narani 	{
125137d3ee7cSManish Narani 		.compatible = "intel,lgm-sdhci-5.1-sdxc",
125237d3ee7cSManish Narani 		.data = &intel_lgm_sdxc_data,
125337d3ee7cSManish Narani 	},
125436c6aadaSWan Ahmad Zainie 	{
125536c6aadaSWan Ahmad Zainie 		.compatible = "intel,keembay-sdhci-5.1-emmc",
125636c6aadaSWan Ahmad Zainie 		.data = &intel_keembay_emmc_data,
125736c6aadaSWan Ahmad Zainie 	},
125836c6aadaSWan Ahmad Zainie 	{
125936c6aadaSWan Ahmad Zainie 		.compatible = "intel,keembay-sdhci-5.1-sd",
126036c6aadaSWan Ahmad Zainie 		.data = &intel_keembay_sd_data,
126136c6aadaSWan Ahmad Zainie 	},
126236c6aadaSWan Ahmad Zainie 	{
126336c6aadaSWan Ahmad Zainie 		.compatible = "intel,keembay-sdhci-5.1-sdio",
126436c6aadaSWan Ahmad Zainie 		.data = &intel_keembay_sdio_data,
126536c6aadaSWan Ahmad Zainie 	},
126637d3ee7cSManish Narani 	/* Generic compatible below here */
126737d3ee7cSManish Narani 	{
126837d3ee7cSManish Narani 		.compatible = "arasan,sdhci-8.9a",
126937d3ee7cSManish Narani 		.data = &sdhci_arasan_generic_data,
127037d3ee7cSManish Narani 	},
127137d3ee7cSManish Narani 	{
127237d3ee7cSManish Narani 		.compatible = "arasan,sdhci-5.1",
127337d3ee7cSManish Narani 		.data = &sdhci_arasan_generic_data,
127437d3ee7cSManish Narani 	},
127537d3ee7cSManish Narani 	{
127637d3ee7cSManish Narani 		.compatible = "arasan,sdhci-4.9a",
127737d3ee7cSManish Narani 		.data = &sdhci_arasan_generic_data,
127837d3ee7cSManish Narani 	},
127937d3ee7cSManish Narani 	{
128037d3ee7cSManish Narani 		.compatible = "xlnx,zynqmp-8.9a",
128137d3ee7cSManish Narani 		.data = &sdhci_arasan_zynqmp_data,
128237d3ee7cSManish Narani 	},
128337d3ee7cSManish Narani 	{
128437d3ee7cSManish Narani 		.compatible = "xlnx,versal-8.9a",
128537d3ee7cSManish Narani 		.data = &sdhci_arasan_versal_data,
128637d3ee7cSManish Narani 	},
128737d3ee7cSManish Narani 	{ /* sentinel */ }
128837d3ee7cSManish Narani };
128937d3ee7cSManish Narani MODULE_DEVICE_TABLE(of, sdhci_arasan_of_match);
129037d3ee7cSManish Narani 
1291c390f211SDouglas Anderson /**
129207a14d1dSManish Narani  * sdhci_arasan_register_sdcardclk - Register the sdcardclk for a PHY to use
1293c390f211SDouglas Anderson  *
12944908460eSManish Narani  * @sdhci_arasan:	Our private data structure.
12954908460eSManish Narani  * @clk_xin:		Pointer to the functional clock
12964908460eSManish Narani  * @dev:		Pointer to our struct device.
12974908460eSManish Narani  *
1298c390f211SDouglas Anderson  * Some PHY devices need to know what the actual card clock is.  In order for
1299c390f211SDouglas Anderson  * them to find out, we'll provide a clock through the common clock framework
1300c390f211SDouglas Anderson  * for them to query.
1301c390f211SDouglas Anderson  *
13024908460eSManish Narani  * Return: 0 on success and error value on error
1303c390f211SDouglas Anderson  */
130407a14d1dSManish Narani static int
130507a14d1dSManish Narani sdhci_arasan_register_sdcardclk(struct sdhci_arasan_data *sdhci_arasan,
1306c390f211SDouglas Anderson 				struct clk *clk_xin,
1307c390f211SDouglas Anderson 				struct device *dev)
1308c390f211SDouglas Anderson {
1309e1463618SManish Narani 	struct sdhci_arasan_clk_data *clk_data = &sdhci_arasan->clk_data;
1310c390f211SDouglas Anderson 	struct device_node *np = dev->of_node;
1311c390f211SDouglas Anderson 	struct clk_init_data sdcardclk_init;
1312c390f211SDouglas Anderson 	const char *parent_clk_name;
1313c390f211SDouglas Anderson 	int ret;
1314c390f211SDouglas Anderson 
1315c390f211SDouglas Anderson 	ret = of_property_read_string_index(np, "clock-output-names", 0,
1316c390f211SDouglas Anderson 					    &sdcardclk_init.name);
1317c390f211SDouglas Anderson 	if (ret) {
1318c390f211SDouglas Anderson 		dev_err(dev, "DT has #clock-cells but no clock-output-names\n");
1319c390f211SDouglas Anderson 		return ret;
1320c390f211SDouglas Anderson 	}
1321c390f211SDouglas Anderson 
1322c390f211SDouglas Anderson 	parent_clk_name = __clk_get_name(clk_xin);
1323c390f211SDouglas Anderson 	sdcardclk_init.parent_names = &parent_clk_name;
1324c390f211SDouglas Anderson 	sdcardclk_init.num_parents = 1;
1325c390f211SDouglas Anderson 	sdcardclk_init.flags = CLK_GET_RATE_NOCACHE;
132616ada730SManish Narani 	sdcardclk_init.ops = sdhci_arasan->clk_ops->sdcardclk_ops;
1327c390f211SDouglas Anderson 
1328e1463618SManish Narani 	clk_data->sdcardclk_hw.init = &sdcardclk_init;
1329e1463618SManish Narani 	clk_data->sdcardclk =
1330e1463618SManish Narani 		devm_clk_register(dev, &clk_data->sdcardclk_hw);
1331c99e1d0cSChuhong Yuan 	if (IS_ERR(clk_data->sdcardclk))
1332c99e1d0cSChuhong Yuan 		return PTR_ERR(clk_data->sdcardclk);
1333e1463618SManish Narani 	clk_data->sdcardclk_hw.init = NULL;
1334c390f211SDouglas Anderson 
1335c390f211SDouglas Anderson 	ret = of_clk_add_provider(np, of_clk_src_simple_get,
1336e1463618SManish Narani 				  clk_data->sdcardclk);
1337c390f211SDouglas Anderson 	if (ret)
133807a14d1dSManish Narani 		dev_err(dev, "Failed to add sdcard clock provider\n");
133907a14d1dSManish Narani 
134007a14d1dSManish Narani 	return ret;
134107a14d1dSManish Narani }
134207a14d1dSManish Narani 
134307a14d1dSManish Narani /**
134407a14d1dSManish Narani  * sdhci_arasan_register_sampleclk - Register the sampleclk for a PHY to use
134507a14d1dSManish Narani  *
13464908460eSManish Narani  * @sdhci_arasan:	Our private data structure.
13474908460eSManish Narani  * @clk_xin:		Pointer to the functional clock
13484908460eSManish Narani  * @dev:		Pointer to our struct device.
13494908460eSManish Narani  *
135007a14d1dSManish Narani  * Some PHY devices need to know what the actual card clock is.  In order for
135107a14d1dSManish Narani  * them to find out, we'll provide a clock through the common clock framework
135207a14d1dSManish Narani  * for them to query.
135307a14d1dSManish Narani  *
13544908460eSManish Narani  * Return: 0 on success and error value on error
135507a14d1dSManish Narani  */
135607a14d1dSManish Narani static int
135707a14d1dSManish Narani sdhci_arasan_register_sampleclk(struct sdhci_arasan_data *sdhci_arasan,
135807a14d1dSManish Narani 				struct clk *clk_xin,
135907a14d1dSManish Narani 				struct device *dev)
136007a14d1dSManish Narani {
136107a14d1dSManish Narani 	struct sdhci_arasan_clk_data *clk_data = &sdhci_arasan->clk_data;
136207a14d1dSManish Narani 	struct device_node *np = dev->of_node;
136307a14d1dSManish Narani 	struct clk_init_data sampleclk_init;
136407a14d1dSManish Narani 	const char *parent_clk_name;
136507a14d1dSManish Narani 	int ret;
136607a14d1dSManish Narani 
136707a14d1dSManish Narani 	ret = of_property_read_string_index(np, "clock-output-names", 1,
136807a14d1dSManish Narani 					    &sampleclk_init.name);
136907a14d1dSManish Narani 	if (ret) {
137007a14d1dSManish Narani 		dev_err(dev, "DT has #clock-cells but no clock-output-names\n");
137107a14d1dSManish Narani 		return ret;
137207a14d1dSManish Narani 	}
137307a14d1dSManish Narani 
137407a14d1dSManish Narani 	parent_clk_name = __clk_get_name(clk_xin);
137507a14d1dSManish Narani 	sampleclk_init.parent_names = &parent_clk_name;
137607a14d1dSManish Narani 	sampleclk_init.num_parents = 1;
137707a14d1dSManish Narani 	sampleclk_init.flags = CLK_GET_RATE_NOCACHE;
137816ada730SManish Narani 	sampleclk_init.ops = sdhci_arasan->clk_ops->sampleclk_ops;
137907a14d1dSManish Narani 
138007a14d1dSManish Narani 	clk_data->sampleclk_hw.init = &sampleclk_init;
138107a14d1dSManish Narani 	clk_data->sampleclk =
138207a14d1dSManish Narani 		devm_clk_register(dev, &clk_data->sampleclk_hw);
1383c99e1d0cSChuhong Yuan 	if (IS_ERR(clk_data->sampleclk))
1384c99e1d0cSChuhong Yuan 		return PTR_ERR(clk_data->sampleclk);
138507a14d1dSManish Narani 	clk_data->sampleclk_hw.init = NULL;
138607a14d1dSManish Narani 
138707a14d1dSManish Narani 	ret = of_clk_add_provider(np, of_clk_src_simple_get,
138807a14d1dSManish Narani 				  clk_data->sampleclk);
138907a14d1dSManish Narani 	if (ret)
139007a14d1dSManish Narani 		dev_err(dev, "Failed to add sample clock provider\n");
1391c390f211SDouglas Anderson 
1392c390f211SDouglas Anderson 	return ret;
1393c390f211SDouglas Anderson }
1394c390f211SDouglas Anderson 
1395c390f211SDouglas Anderson /**
1396c390f211SDouglas Anderson  * sdhci_arasan_unregister_sdclk - Undoes sdhci_arasan_register_sdclk()
1397c390f211SDouglas Anderson  *
13984908460eSManish Narani  * @dev:		Pointer to our struct device.
13994908460eSManish Narani  *
1400c390f211SDouglas Anderson  * Should be called any time we're exiting and sdhci_arasan_register_sdclk()
1401c390f211SDouglas Anderson  * returned success.
1402c390f211SDouglas Anderson  */
1403c390f211SDouglas Anderson static void sdhci_arasan_unregister_sdclk(struct device *dev)
1404c390f211SDouglas Anderson {
1405c390f211SDouglas Anderson 	struct device_node *np = dev->of_node;
1406c390f211SDouglas Anderson 
1407c390f211SDouglas Anderson 	if (!of_find_property(np, "#clock-cells", NULL))
1408c390f211SDouglas Anderson 		return;
1409c390f211SDouglas Anderson 
1410c390f211SDouglas Anderson 	of_clk_del_provider(dev->of_node);
1411c390f211SDouglas Anderson }
1412c390f211SDouglas Anderson 
141307a14d1dSManish Narani /**
141436c6aadaSWan Ahmad Zainie  * sdhci_arasan_update_support64b - Set SUPPORT_64B (64-bit System Bus Support)
1415973c7c99SMuhammad Husaini Zulkifli  * @host:		The sdhci_host
1416973c7c99SMuhammad Husaini Zulkifli  * @value:		The value to write
141736c6aadaSWan Ahmad Zainie  *
141836c6aadaSWan Ahmad Zainie  * This should be set based on the System Address Bus.
141936c6aadaSWan Ahmad Zainie  * 0: the Core supports only 32-bit System Address Bus.
142036c6aadaSWan Ahmad Zainie  * 1: the Core supports 64-bit System Address Bus.
142136c6aadaSWan Ahmad Zainie  *
1422973c7c99SMuhammad Husaini Zulkifli  * NOTE:
1423973c7c99SMuhammad Husaini Zulkifli  * For Keem Bay, it is required to clear this bit. Its default value is 1'b1.
142436c6aadaSWan Ahmad Zainie  * Keem Bay does not support 64-bit access.
142536c6aadaSWan Ahmad Zainie  */
142636c6aadaSWan Ahmad Zainie static void sdhci_arasan_update_support64b(struct sdhci_host *host, u32 value)
142736c6aadaSWan Ahmad Zainie {
142836c6aadaSWan Ahmad Zainie 	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
142936c6aadaSWan Ahmad Zainie 	struct sdhci_arasan_data *sdhci_arasan = sdhci_pltfm_priv(pltfm_host);
1430db845093SMuhammad Husaini Zulkifli 	const struct sdhci_arasan_soc_ctl_map *soc_ctl_map;
143136c6aadaSWan Ahmad Zainie 
143236c6aadaSWan Ahmad Zainie 	/* Having a map is optional */
1433db845093SMuhammad Husaini Zulkifli 	soc_ctl_map = sdhci_arasan->soc_ctl_map;
143436c6aadaSWan Ahmad Zainie 	if (!soc_ctl_map)
143536c6aadaSWan Ahmad Zainie 		return;
143636c6aadaSWan Ahmad Zainie 
143736c6aadaSWan Ahmad Zainie 	/* If we have a map, we expect to have a syscon */
143836c6aadaSWan Ahmad Zainie 	if (!sdhci_arasan->soc_ctl_base) {
143936c6aadaSWan Ahmad Zainie 		pr_warn("%s: Have regmap, but no soc-ctl-syscon\n",
144036c6aadaSWan Ahmad Zainie 			mmc_hostname(host->mmc));
144136c6aadaSWan Ahmad Zainie 		return;
144236c6aadaSWan Ahmad Zainie 	}
144336c6aadaSWan Ahmad Zainie 
144436c6aadaSWan Ahmad Zainie 	sdhci_arasan_syscon_write(host, &soc_ctl_map->support64b, value);
144536c6aadaSWan Ahmad Zainie }
144636c6aadaSWan Ahmad Zainie 
144736c6aadaSWan Ahmad Zainie /**
144807a14d1dSManish Narani  * sdhci_arasan_register_sdclk - Register the sdcardclk for a PHY to use
144907a14d1dSManish Narani  *
14504908460eSManish Narani  * @sdhci_arasan:	Our private data structure.
14514908460eSManish Narani  * @clk_xin:		Pointer to the functional clock
14524908460eSManish Narani  * @dev:		Pointer to our struct device.
14534908460eSManish Narani  *
145407a14d1dSManish Narani  * Some PHY devices need to know what the actual card clock is.  In order for
145507a14d1dSManish Narani  * them to find out, we'll provide a clock through the common clock framework
145607a14d1dSManish Narani  * for them to query.
145707a14d1dSManish Narani  *
145807a14d1dSManish Narani  * Note: without seriously re-architecting SDHCI's clock code and testing on
145907a14d1dSManish Narani  * all platforms, there's no way to create a totally beautiful clock here
146007a14d1dSManish Narani  * with all clock ops implemented.  Instead, we'll just create a clock that can
146107a14d1dSManish Narani  * be queried and set the CLK_GET_RATE_NOCACHE attribute to tell common clock
146207a14d1dSManish Narani  * framework that we're doing things behind its back.  This should be sufficient
146307a14d1dSManish Narani  * to create nice clean device tree bindings and later (if needed) we can try
146407a14d1dSManish Narani  * re-architecting SDHCI if we see some benefit to it.
146507a14d1dSManish Narani  *
14664908460eSManish Narani  * Return: 0 on success and error value on error
146707a14d1dSManish Narani  */
146807a14d1dSManish Narani static int sdhci_arasan_register_sdclk(struct sdhci_arasan_data *sdhci_arasan,
146907a14d1dSManish Narani 				       struct clk *clk_xin,
147007a14d1dSManish Narani 				       struct device *dev)
147107a14d1dSManish Narani {
147207a14d1dSManish Narani 	struct device_node *np = dev->of_node;
147307a14d1dSManish Narani 	u32 num_clks = 0;
147407a14d1dSManish Narani 	int ret;
147507a14d1dSManish Narani 
147607a14d1dSManish Narani 	/* Providing a clock to the PHY is optional; no error if missing */
147707a14d1dSManish Narani 	if (of_property_read_u32(np, "#clock-cells", &num_clks) < 0)
147807a14d1dSManish Narani 		return 0;
147907a14d1dSManish Narani 
148007a14d1dSManish Narani 	ret = sdhci_arasan_register_sdcardclk(sdhci_arasan, clk_xin, dev);
148107a14d1dSManish Narani 	if (ret)
148207a14d1dSManish Narani 		return ret;
148307a14d1dSManish Narani 
148407a14d1dSManish Narani 	if (num_clks) {
148507a14d1dSManish Narani 		ret = sdhci_arasan_register_sampleclk(sdhci_arasan, clk_xin,
148607a14d1dSManish Narani 						      dev);
148707a14d1dSManish Narani 		if (ret) {
148807a14d1dSManish Narani 			sdhci_arasan_unregister_sdclk(dev);
148907a14d1dSManish Narani 			return ret;
149007a14d1dSManish Narani 		}
149107a14d1dSManish Narani 	}
149207a14d1dSManish Narani 
149307a14d1dSManish Narani 	return 0;
149407a14d1dSManish Narani }
149507a14d1dSManish Narani 
149684362d79SShawn Lin static int sdhci_arasan_add_host(struct sdhci_arasan_data *sdhci_arasan)
149784362d79SShawn Lin {
149884362d79SShawn Lin 	struct sdhci_host *host = sdhci_arasan->host;
149984362d79SShawn Lin 	struct cqhci_host *cq_host;
150084362d79SShawn Lin 	bool dma64;
150184362d79SShawn Lin 	int ret;
150284362d79SShawn Lin 
150384362d79SShawn Lin 	if (!sdhci_arasan->has_cqe)
150484362d79SShawn Lin 		return sdhci_add_host(host);
150584362d79SShawn Lin 
150684362d79SShawn Lin 	ret = sdhci_setup_host(host);
150784362d79SShawn Lin 	if (ret)
150884362d79SShawn Lin 		return ret;
150984362d79SShawn Lin 
151084362d79SShawn Lin 	cq_host = devm_kzalloc(host->mmc->parent,
151184362d79SShawn Lin 			       sizeof(*cq_host), GFP_KERNEL);
151284362d79SShawn Lin 	if (!cq_host) {
151384362d79SShawn Lin 		ret = -ENOMEM;
151484362d79SShawn Lin 		goto cleanup;
151584362d79SShawn Lin 	}
151684362d79SShawn Lin 
151784362d79SShawn Lin 	cq_host->mmio = host->ioaddr + SDHCI_ARASAN_CQE_BASE_ADDR;
151884362d79SShawn Lin 	cq_host->ops = &sdhci_arasan_cqhci_ops;
151984362d79SShawn Lin 
152084362d79SShawn Lin 	dma64 = host->flags & SDHCI_USE_64_BIT_DMA;
152184362d79SShawn Lin 	if (dma64)
152284362d79SShawn Lin 		cq_host->caps |= CQHCI_TASK_DESC_SZ_128;
152384362d79SShawn Lin 
152484362d79SShawn Lin 	ret = cqhci_init(cq_host, host->mmc, dma64);
152584362d79SShawn Lin 	if (ret)
152684362d79SShawn Lin 		goto cleanup;
152784362d79SShawn Lin 
152884362d79SShawn Lin 	ret = __sdhci_add_host(host);
152984362d79SShawn Lin 	if (ret)
153084362d79SShawn Lin 		goto cleanup;
153184362d79SShawn Lin 
153284362d79SShawn Lin 	return 0;
153384362d79SShawn Lin 
153484362d79SShawn Lin cleanup:
153584362d79SShawn Lin 	sdhci_cleanup_host(host);
153684362d79SShawn Lin 	return ret;
153784362d79SShawn Lin }
153884362d79SShawn Lin 
1539e3ec3a3dSSoren Brinkmann static int sdhci_arasan_probe(struct platform_device *pdev)
1540e3ec3a3dSSoren Brinkmann {
1541e3ec3a3dSSoren Brinkmann 	int ret;
15423ea4666eSDouglas Anderson 	struct device_node *node;
1543e3ec3a3dSSoren Brinkmann 	struct clk *clk_xin;
1544e3ec3a3dSSoren Brinkmann 	struct sdhci_host *host;
1545e3ec3a3dSSoren Brinkmann 	struct sdhci_pltfm_host *pltfm_host;
15462ff0b85dSMuhammad Husaini Zulkifli 	struct device *dev = &pdev->dev;
15472ff0b85dSMuhammad Husaini Zulkifli 	struct device_node *np = dev->of_node;
1548e3ec3a3dSSoren Brinkmann 	struct sdhci_arasan_data *sdhci_arasan;
154906b23ca0SFaiz Abbas 	const struct sdhci_arasan_of_data *data;
1550e3ec3a3dSSoren Brinkmann 
15512ff0b85dSMuhammad Husaini Zulkifli 	data = of_device_get_match_data(dev);
155206b23ca0SFaiz Abbas 	host = sdhci_pltfm_init(pdev, data->pdata, sizeof(*sdhci_arasan));
155384362d79SShawn Lin 
155489211418SJisheng Zhang 	if (IS_ERR(host))
155589211418SJisheng Zhang 		return PTR_ERR(host);
155689211418SJisheng Zhang 
155789211418SJisheng Zhang 	pltfm_host = sdhci_priv(host);
155889211418SJisheng Zhang 	sdhci_arasan = sdhci_pltfm_priv(pltfm_host);
1559c390f211SDouglas Anderson 	sdhci_arasan->host = host;
1560e3ec3a3dSSoren Brinkmann 
156106b23ca0SFaiz Abbas 	sdhci_arasan->soc_ctl_map = data->soc_ctl_map;
156216ada730SManish Narani 	sdhci_arasan->clk_ops = data->clk_ops;
15633ea4666eSDouglas Anderson 
156480d41efeSMuhammad Husaini Zulkifli 	node = of_parse_phandle(np, "arasan,soc-ctl-syscon", 0);
15653ea4666eSDouglas Anderson 	if (node) {
15663ea4666eSDouglas Anderson 		sdhci_arasan->soc_ctl_base = syscon_node_to_regmap(node);
15673ea4666eSDouglas Anderson 		of_node_put(node);
15683ea4666eSDouglas Anderson 
15693ea4666eSDouglas Anderson 		if (IS_ERR(sdhci_arasan->soc_ctl_base)) {
15702ff0b85dSMuhammad Husaini Zulkifli 			ret = dev_err_probe(dev,
157172ea817dSKrzysztof Kozlowski 					    PTR_ERR(sdhci_arasan->soc_ctl_base),
157272ea817dSKrzysztof Kozlowski 					    "Can't get syscon\n");
15733ea4666eSDouglas Anderson 			goto err_pltfm_free;
15743ea4666eSDouglas Anderson 		}
15753ea4666eSDouglas Anderson 	}
15763ea4666eSDouglas Anderson 
1577b2af3227SRashmi A 	sdhci_get_of_property(pdev);
1578b2af3227SRashmi A 
15792ff0b85dSMuhammad Husaini Zulkifli 	sdhci_arasan->clk_ahb = devm_clk_get(dev, "clk_ahb");
1580e3ec3a3dSSoren Brinkmann 	if (IS_ERR(sdhci_arasan->clk_ahb)) {
1581ffd68f35SMuhammad Husaini Zulkifli 		ret = dev_err_probe(dev, PTR_ERR(sdhci_arasan->clk_ahb),
1582ffd68f35SMuhammad Husaini Zulkifli 				    "clk_ahb clock not found.\n");
1583278d0962SShawn Lin 		goto err_pltfm_free;
1584e3ec3a3dSSoren Brinkmann 	}
1585e3ec3a3dSSoren Brinkmann 
15862ff0b85dSMuhammad Husaini Zulkifli 	clk_xin = devm_clk_get(dev, "clk_xin");
1587e3ec3a3dSSoren Brinkmann 	if (IS_ERR(clk_xin)) {
1588ffd68f35SMuhammad Husaini Zulkifli 		ret = dev_err_probe(dev, PTR_ERR(clk_xin), "clk_xin clock not found.\n");
1589278d0962SShawn Lin 		goto err_pltfm_free;
1590e3ec3a3dSSoren Brinkmann 	}
1591e3ec3a3dSSoren Brinkmann 
1592e3ec3a3dSSoren Brinkmann 	ret = clk_prepare_enable(sdhci_arasan->clk_ahb);
1593e3ec3a3dSSoren Brinkmann 	if (ret) {
15942ff0b85dSMuhammad Husaini Zulkifli 		dev_err(dev, "Unable to enable AHB clock.\n");
1595278d0962SShawn Lin 		goto err_pltfm_free;
1596e3ec3a3dSSoren Brinkmann 	}
1597e3ec3a3dSSoren Brinkmann 
1598b2af3227SRashmi A 	/* If clock-frequency property is set, use the provided value */
1599b2af3227SRashmi A 	if (pltfm_host->clock &&
1600b2af3227SRashmi A 	    pltfm_host->clock != clk_get_rate(clk_xin)) {
1601b2af3227SRashmi A 		ret = clk_set_rate(clk_xin, pltfm_host->clock);
1602b2af3227SRashmi A 		if (ret) {
1603b2af3227SRashmi A 			dev_err(&pdev->dev, "Failed to set SD clock rate\n");
1604b2af3227SRashmi A 			goto clk_dis_ahb;
1605b2af3227SRashmi A 		}
1606b2af3227SRashmi A 	}
1607b2af3227SRashmi A 
1608e3ec3a3dSSoren Brinkmann 	ret = clk_prepare_enable(clk_xin);
1609e3ec3a3dSSoren Brinkmann 	if (ret) {
16102ff0b85dSMuhammad Husaini Zulkifli 		dev_err(dev, "Unable to enable SD clock.\n");
1611e3ec3a3dSSoren Brinkmann 		goto clk_dis_ahb;
1612e3ec3a3dSSoren Brinkmann 	}
1613e3ec3a3dSSoren Brinkmann 
16143794c542SZach Brown 	if (of_property_read_bool(np, "xlnx,fails-without-test-cd"))
16153794c542SZach Brown 		sdhci_arasan->quirks |= SDHCI_ARASAN_QUIRK_FORCE_CDTEST;
16163794c542SZach Brown 
16173f2c7d5dSHelmut Grohne 	if (of_property_read_bool(np, "xlnx,int-clock-stable-broken"))
16183f2c7d5dSHelmut Grohne 		sdhci_arasan->quirks |= SDHCI_ARASAN_QUIRK_CLOCK_UNSTABLE;
16193f2c7d5dSHelmut Grohne 
1620e3ec3a3dSSoren Brinkmann 	pltfm_host->clk = clk_xin;
1621e3ec3a3dSSoren Brinkmann 
162280d41efeSMuhammad Husaini Zulkifli 	if (of_device_is_compatible(np, "rockchip,rk3399-sdhci-5.1"))
1623b2ca77c9SShawn Lin 		sdhci_arasan_update_clockmultiplier(host, 0x0);
1624b2ca77c9SShawn Lin 
162536c6aadaSWan Ahmad Zainie 	if (of_device_is_compatible(np, "intel,keembay-sdhci-5.1-emmc") ||
162636c6aadaSWan Ahmad Zainie 	    of_device_is_compatible(np, "intel,keembay-sdhci-5.1-sd") ||
162736c6aadaSWan Ahmad Zainie 	    of_device_is_compatible(np, "intel,keembay-sdhci-5.1-sdio")) {
162836c6aadaSWan Ahmad Zainie 		sdhci_arasan_update_clockmultiplier(host, 0x0);
162936c6aadaSWan Ahmad Zainie 		sdhci_arasan_update_support64b(host, 0x0);
163036c6aadaSWan Ahmad Zainie 
163136c6aadaSWan Ahmad Zainie 		host->mmc->caps |= MMC_CAP_WAIT_WHILE_BUSY;
163236c6aadaSWan Ahmad Zainie 	}
163336c6aadaSWan Ahmad Zainie 
16343ea4666eSDouglas Anderson 	sdhci_arasan_update_baseclkfreq(host);
16353ea4666eSDouglas Anderson 
16362ff0b85dSMuhammad Husaini Zulkifli 	ret = sdhci_arasan_register_sdclk(sdhci_arasan, clk_xin, dev);
1637c390f211SDouglas Anderson 	if (ret)
1638c390f211SDouglas Anderson 		goto clk_disable_all;
1639c390f211SDouglas Anderson 
1640a5c8b2aeSManish Narani 	if (of_device_is_compatible(np, "xlnx,zynqmp-8.9a")) {
16418d2e3343SManish Narani 		host->mmc_host_ops.execute_tuning =
16428d2e3343SManish Narani 			arasan_zynqmp_execute_tuning;
1643c0b4e411SManish Narani 
1644c0b4e411SManish Narani 		sdhci_arasan->quirks |= SDHCI_ARASAN_QUIRK_CLOCK_25_BROKEN;
164525a91664SManish Narani 		host->quirks |= SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12;
1646a5c8b2aeSManish Narani 	}
1647a5c8b2aeSManish Narani 
16482ff0b85dSMuhammad Husaini Zulkifli 	arasan_dt_parse_clk_phases(dev, &sdhci_arasan->clk_data);
1649f3dafc37SManish Narani 
165016b23787SMichal Simek 	ret = mmc_of_parse(host->mmc);
165116b23787SMichal Simek 	if (ret) {
1652ffd68f35SMuhammad Husaini Zulkifli 		ret = dev_err_probe(dev, ret, "parsing dt failed.\n");
1653c390f211SDouglas Anderson 		goto unreg_clk;
165416b23787SMichal Simek 	}
165516b23787SMichal Simek 
165691aa3661SShawn Lin 	sdhci_arasan->phy = ERR_PTR(-ENODEV);
165780d41efeSMuhammad Husaini Zulkifli 	if (of_device_is_compatible(np, "arasan,sdhci-5.1")) {
16582ff0b85dSMuhammad Husaini Zulkifli 		sdhci_arasan->phy = devm_phy_get(dev, "phy_arasan");
165991aa3661SShawn Lin 		if (IS_ERR(sdhci_arasan->phy)) {
1660ffd68f35SMuhammad Husaini Zulkifli 			ret = dev_err_probe(dev, PTR_ERR(sdhci_arasan->phy),
1661ffd68f35SMuhammad Husaini Zulkifli 					    "No phy for arasan,sdhci-5.1.\n");
1662c390f211SDouglas Anderson 			goto unreg_clk;
166391aa3661SShawn Lin 		}
166491aa3661SShawn Lin 
166591aa3661SShawn Lin 		ret = phy_init(sdhci_arasan->phy);
166691aa3661SShawn Lin 		if (ret < 0) {
16672ff0b85dSMuhammad Husaini Zulkifli 			dev_err(dev, "phy_init err.\n");
1668c390f211SDouglas Anderson 			goto unreg_clk;
166991aa3661SShawn Lin 		}
167091aa3661SShawn Lin 
1671a05c8465SShawn Lin 		host->mmc_host_ops.hs400_enhanced_strobe =
1672a05c8465SShawn Lin 					sdhci_arasan_hs400_enhanced_strobe;
16738a3bee9bSShawn Lin 		host->mmc_host_ops.start_signal_voltage_switch =
16748a3bee9bSShawn Lin 					sdhci_arasan_voltage_switch;
167584362d79SShawn Lin 		sdhci_arasan->has_cqe = true;
16767bda9482SChristoph Muellner 		host->mmc->caps2 |= MMC_CAP2_CQE;
16777bda9482SChristoph Muellner 
16787bda9482SChristoph Muellner 		if (!of_property_read_bool(np, "disable-cqe-dcmd"))
16797bda9482SChristoph Muellner 			host->mmc->caps2 |= MMC_CAP2_CQE_DCMD;
168091aa3661SShawn Lin 	}
168191aa3661SShawn Lin 
168284362d79SShawn Lin 	ret = sdhci_arasan_add_host(sdhci_arasan);
1683b1df9de7SMike Looijmans 	if (ret)
168491aa3661SShawn Lin 		goto err_add_host;
1685e3ec3a3dSSoren Brinkmann 
1686e3ec3a3dSSoren Brinkmann 	return 0;
1687e3ec3a3dSSoren Brinkmann 
168891aa3661SShawn Lin err_add_host:
168991aa3661SShawn Lin 	if (!IS_ERR(sdhci_arasan->phy))
169091aa3661SShawn Lin 		phy_exit(sdhci_arasan->phy);
1691c390f211SDouglas Anderson unreg_clk:
16922ff0b85dSMuhammad Husaini Zulkifli 	sdhci_arasan_unregister_sdclk(dev);
1693e3ec3a3dSSoren Brinkmann clk_disable_all:
1694e3ec3a3dSSoren Brinkmann 	clk_disable_unprepare(clk_xin);
1695e3ec3a3dSSoren Brinkmann clk_dis_ahb:
1696e3ec3a3dSSoren Brinkmann 	clk_disable_unprepare(sdhci_arasan->clk_ahb);
1697278d0962SShawn Lin err_pltfm_free:
1698278d0962SShawn Lin 	sdhci_pltfm_free(pdev);
1699e3ec3a3dSSoren Brinkmann 	return ret;
1700e3ec3a3dSSoren Brinkmann }
1701e3ec3a3dSSoren Brinkmann 
1702e3ec3a3dSSoren Brinkmann static int sdhci_arasan_remove(struct platform_device *pdev)
1703e3ec3a3dSSoren Brinkmann {
17040c7fe32eSJisheng Zhang 	int ret;
1705e3ec3a3dSSoren Brinkmann 	struct sdhci_host *host = platform_get_drvdata(pdev);
1706e3ec3a3dSSoren Brinkmann 	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
170789211418SJisheng Zhang 	struct sdhci_arasan_data *sdhci_arasan = sdhci_pltfm_priv(pltfm_host);
170889211418SJisheng Zhang 	struct clk *clk_ahb = sdhci_arasan->clk_ahb;
1709e3ec3a3dSSoren Brinkmann 
171091aa3661SShawn Lin 	if (!IS_ERR(sdhci_arasan->phy)) {
1711b2db9c67SDouglas Anderson 		if (sdhci_arasan->is_phy_on)
171291aa3661SShawn Lin 			phy_power_off(sdhci_arasan->phy);
171391aa3661SShawn Lin 		phy_exit(sdhci_arasan->phy);
171491aa3661SShawn Lin 	}
171591aa3661SShawn Lin 
1716c390f211SDouglas Anderson 	sdhci_arasan_unregister_sdclk(&pdev->dev);
1717c390f211SDouglas Anderson 
17180c7fe32eSJisheng Zhang 	ret = sdhci_pltfm_unregister(pdev);
17190c7fe32eSJisheng Zhang 
172089211418SJisheng Zhang 	clk_disable_unprepare(clk_ahb);
1721e3ec3a3dSSoren Brinkmann 
17220c7fe32eSJisheng Zhang 	return ret;
1723e3ec3a3dSSoren Brinkmann }
1724e3ec3a3dSSoren Brinkmann 
1725e3ec3a3dSSoren Brinkmann static struct platform_driver sdhci_arasan_driver = {
1726e3ec3a3dSSoren Brinkmann 	.driver = {
1727e3ec3a3dSSoren Brinkmann 		.name = "sdhci-arasan",
172821b2cec6SDouglas Anderson 		.probe_type = PROBE_PREFER_ASYNCHRONOUS,
1729e3ec3a3dSSoren Brinkmann 		.of_match_table = sdhci_arasan_of_match,
1730e3ec3a3dSSoren Brinkmann 		.pm = &sdhci_arasan_dev_pm_ops,
1731e3ec3a3dSSoren Brinkmann 	},
1732e3ec3a3dSSoren Brinkmann 	.probe = sdhci_arasan_probe,
1733e3ec3a3dSSoren Brinkmann 	.remove = sdhci_arasan_remove,
1734e3ec3a3dSSoren Brinkmann };
1735e3ec3a3dSSoren Brinkmann 
1736e3ec3a3dSSoren Brinkmann module_platform_driver(sdhci_arasan_driver);
1737e3ec3a3dSSoren Brinkmann 
1738e3ec3a3dSSoren Brinkmann MODULE_DESCRIPTION("Driver for the Arasan SDHCI Controller");
1739e3ec3a3dSSoren Brinkmann MODULE_AUTHOR("Soeren Brinkmann <soren.brinkmann@xilinx.com>");
1740e3ec3a3dSSoren Brinkmann MODULE_LICENSE("GPL");
1741