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