1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * PHY support for Xenon SDHC |
4 | * |
5 | * Copyright (C) 2016 Marvell, All Rights Reserved. |
6 | * |
7 | * Author: Hu Ziji <huziji@marvell.com> |
8 | * Date: 2016-8-24 |
9 | */ |
10 | |
11 | #include <linux/slab.h> |
12 | #include <linux/delay.h> |
13 | #include <linux/ktime.h> |
14 | #include <linux/of_address.h> |
15 | |
16 | #include "sdhci-pltfm.h" |
17 | #include "sdhci-xenon.h" |
18 | |
19 | /* Register base for eMMC PHY 5.0 Version */ |
20 | #define XENON_EMMC_5_0_PHY_REG_BASE 0x0160 |
21 | /* Register base for eMMC PHY 5.1 Version */ |
22 | #define XENON_EMMC_PHY_REG_BASE 0x0170 |
23 | |
24 | #define XENON_EMMC_PHY_TIMING_ADJUST XENON_EMMC_PHY_REG_BASE |
25 | #define XENON_EMMC_5_0_PHY_TIMING_ADJUST XENON_EMMC_5_0_PHY_REG_BASE |
26 | #define XENON_TIMING_ADJUST_SLOW_MODE BIT(29) |
27 | #define XENON_TIMING_ADJUST_SDIO_MODE BIT(28) |
28 | #define XENON_SAMPL_INV_QSP_PHASE_SELECT BIT(18) |
29 | #define XENON_SAMPL_INV_QSP_PHASE_SELECT_SHIFT 18 |
30 | #define XENON_PHY_INITIALIZAION BIT(31) |
31 | #define XENON_WAIT_CYCLE_BEFORE_USING_MASK 0xF |
32 | #define XENON_WAIT_CYCLE_BEFORE_USING_SHIFT 12 |
33 | #define XENON_FC_SYNC_EN_DURATION_MASK 0xF |
34 | #define XENON_FC_SYNC_EN_DURATION_SHIFT 8 |
35 | #define XENON_FC_SYNC_RST_EN_DURATION_MASK 0xF |
36 | #define XENON_FC_SYNC_RST_EN_DURATION_SHIFT 4 |
37 | #define XENON_FC_SYNC_RST_DURATION_MASK 0xF |
38 | #define XENON_FC_SYNC_RST_DURATION_SHIFT 0 |
39 | |
40 | #define XENON_EMMC_PHY_FUNC_CONTROL (XENON_EMMC_PHY_REG_BASE + 0x4) |
41 | #define XENON_EMMC_5_0_PHY_FUNC_CONTROL \ |
42 | (XENON_EMMC_5_0_PHY_REG_BASE + 0x4) |
43 | #define XENON_ASYNC_DDRMODE_MASK BIT(23) |
44 | #define XENON_ASYNC_DDRMODE_SHIFT 23 |
45 | #define XENON_CMD_DDR_MODE BIT(16) |
46 | #define XENON_DQ_DDR_MODE_SHIFT 8 |
47 | #define XENON_DQ_DDR_MODE_MASK 0xFF |
48 | #define XENON_DQ_ASYNC_MODE BIT(4) |
49 | |
50 | #define XENON_EMMC_PHY_PAD_CONTROL (XENON_EMMC_PHY_REG_BASE + 0x8) |
51 | #define XENON_EMMC_5_0_PHY_PAD_CONTROL \ |
52 | (XENON_EMMC_5_0_PHY_REG_BASE + 0x8) |
53 | #define XENON_REC_EN_SHIFT 24 |
54 | #define XENON_REC_EN_MASK 0xF |
55 | #define XENON_FC_DQ_RECEN BIT(24) |
56 | #define XENON_FC_CMD_RECEN BIT(25) |
57 | #define XENON_FC_QSP_RECEN BIT(26) |
58 | #define XENON_FC_QSN_RECEN BIT(27) |
59 | #define XENON_OEN_QSN BIT(28) |
60 | #define XENON_AUTO_RECEN_CTRL BIT(30) |
61 | #define XENON_FC_ALL_CMOS_RECEIVER 0xF000 |
62 | |
63 | #define XENON_EMMC5_FC_QSP_PD BIT(18) |
64 | #define XENON_EMMC5_FC_QSP_PU BIT(22) |
65 | #define XENON_EMMC5_FC_CMD_PD BIT(17) |
66 | #define XENON_EMMC5_FC_CMD_PU BIT(21) |
67 | #define XENON_EMMC5_FC_DQ_PD BIT(16) |
68 | #define XENON_EMMC5_FC_DQ_PU BIT(20) |
69 | |
70 | #define XENON_EMMC_PHY_PAD_CONTROL1 (XENON_EMMC_PHY_REG_BASE + 0xC) |
71 | #define XENON_EMMC5_1_FC_QSP_PD BIT(9) |
72 | #define XENON_EMMC5_1_FC_QSP_PU BIT(25) |
73 | #define XENON_EMMC5_1_FC_CMD_PD BIT(8) |
74 | #define XENON_EMMC5_1_FC_CMD_PU BIT(24) |
75 | #define XENON_EMMC5_1_FC_DQ_PD 0xFF |
76 | #define XENON_EMMC5_1_FC_DQ_PU (0xFF << 16) |
77 | |
78 | #define XENON_EMMC_PHY_PAD_CONTROL2 (XENON_EMMC_PHY_REG_BASE + 0x10) |
79 | #define XENON_EMMC_5_0_PHY_PAD_CONTROL2 \ |
80 | (XENON_EMMC_5_0_PHY_REG_BASE + 0xC) |
81 | #define XENON_ZNR_MASK 0x1F |
82 | #define XENON_ZNR_SHIFT 8 |
83 | #define XENON_ZPR_MASK 0x1F |
84 | /* Preferred ZNR and ZPR value vary between different boards. |
85 | * The specific ZNR and ZPR value should be defined here |
86 | * according to board actual timing. |
87 | */ |
88 | #define XENON_ZNR_DEF_VALUE 0xF |
89 | #define XENON_ZPR_DEF_VALUE 0xF |
90 | |
91 | #define XENON_EMMC_PHY_DLL_CONTROL (XENON_EMMC_PHY_REG_BASE + 0x14) |
92 | #define XENON_EMMC_5_0_PHY_DLL_CONTROL \ |
93 | (XENON_EMMC_5_0_PHY_REG_BASE + 0x10) |
94 | #define XENON_DLL_ENABLE BIT(31) |
95 | #define XENON_DLL_UPDATE_STROBE_5_0 BIT(30) |
96 | #define XENON_DLL_REFCLK_SEL BIT(30) |
97 | #define XENON_DLL_UPDATE BIT(23) |
98 | #define XENON_DLL_PHSEL1_SHIFT 24 |
99 | #define XENON_DLL_PHSEL0_SHIFT 16 |
100 | #define XENON_DLL_PHASE_MASK 0x3F |
101 | #define XENON_DLL_PHASE_90_DEGREE 0x1F |
102 | #define XENON_DLL_FAST_LOCK BIT(5) |
103 | #define XENON_DLL_GAIN2X BIT(3) |
104 | #define XENON_DLL_BYPASS_EN BIT(0) |
105 | |
106 | #define XENON_EMMC_5_0_PHY_LOGIC_TIMING_ADJUST \ |
107 | (XENON_EMMC_5_0_PHY_REG_BASE + 0x14) |
108 | #define XENON_EMMC_5_0_PHY_LOGIC_TIMING_VALUE 0x5A54 |
109 | #define XENON_EMMC_PHY_LOGIC_TIMING_ADJUST (XENON_EMMC_PHY_REG_BASE + 0x18) |
110 | #define XENON_LOGIC_TIMING_VALUE 0x00AA8977 |
111 | |
112 | /* |
113 | * List offset of PHY registers and some special register values |
114 | * in eMMC PHY 5.0 or eMMC PHY 5.1 |
115 | */ |
116 | struct xenon_emmc_phy_regs { |
117 | /* Offset of Timing Adjust register */ |
118 | u16 timing_adj; |
119 | /* Offset of Func Control register */ |
120 | u16 func_ctrl; |
121 | /* Offset of Pad Control register */ |
122 | u16 pad_ctrl; |
123 | /* Offset of Pad Control register 2 */ |
124 | u16 pad_ctrl2; |
125 | /* Offset of DLL Control register */ |
126 | u16 dll_ctrl; |
127 | /* Offset of Logic Timing Adjust register */ |
128 | u16 logic_timing_adj; |
129 | /* DLL Update Enable bit */ |
130 | u32 dll_update; |
131 | /* value in Logic Timing Adjustment register */ |
132 | u32 logic_timing_val; |
133 | }; |
134 | |
135 | static const char * const phy_types[] = { |
136 | "emmc 5.0 phy" , |
137 | "emmc 5.1 phy" |
138 | }; |
139 | |
140 | enum xenon_phy_type_enum { |
141 | EMMC_5_0_PHY, |
142 | EMMC_5_1_PHY, |
143 | NR_PHY_TYPES |
144 | }; |
145 | |
146 | enum soc_pad_ctrl_type { |
147 | SOC_PAD_SD, |
148 | SOC_PAD_FIXED_1_8V, |
149 | }; |
150 | |
151 | struct soc_pad_ctrl { |
152 | /* Register address of SoC PHY PAD ctrl */ |
153 | void __iomem *reg; |
154 | /* SoC PHY PAD ctrl type */ |
155 | enum soc_pad_ctrl_type pad_type; |
156 | /* SoC specific operation to set SoC PHY PAD */ |
157 | void (*set_soc_pad)(struct sdhci_host *host, |
158 | unsigned char signal_voltage); |
159 | }; |
160 | |
161 | static struct xenon_emmc_phy_regs xenon_emmc_5_0_phy_regs = { |
162 | .timing_adj = XENON_EMMC_5_0_PHY_TIMING_ADJUST, |
163 | .func_ctrl = XENON_EMMC_5_0_PHY_FUNC_CONTROL, |
164 | .pad_ctrl = XENON_EMMC_5_0_PHY_PAD_CONTROL, |
165 | .pad_ctrl2 = XENON_EMMC_5_0_PHY_PAD_CONTROL2, |
166 | .dll_ctrl = XENON_EMMC_5_0_PHY_DLL_CONTROL, |
167 | .logic_timing_adj = XENON_EMMC_5_0_PHY_LOGIC_TIMING_ADJUST, |
168 | .dll_update = XENON_DLL_UPDATE_STROBE_5_0, |
169 | .logic_timing_val = XENON_EMMC_5_0_PHY_LOGIC_TIMING_VALUE, |
170 | }; |
171 | |
172 | static struct xenon_emmc_phy_regs xenon_emmc_5_1_phy_regs = { |
173 | .timing_adj = XENON_EMMC_PHY_TIMING_ADJUST, |
174 | .func_ctrl = XENON_EMMC_PHY_FUNC_CONTROL, |
175 | .pad_ctrl = XENON_EMMC_PHY_PAD_CONTROL, |
176 | .pad_ctrl2 = XENON_EMMC_PHY_PAD_CONTROL2, |
177 | .dll_ctrl = XENON_EMMC_PHY_DLL_CONTROL, |
178 | .logic_timing_adj = XENON_EMMC_PHY_LOGIC_TIMING_ADJUST, |
179 | .dll_update = XENON_DLL_UPDATE, |
180 | .logic_timing_val = XENON_LOGIC_TIMING_VALUE, |
181 | }; |
182 | |
183 | /* |
184 | * eMMC PHY configuration and operations |
185 | */ |
186 | struct xenon_emmc_phy_params { |
187 | bool slow_mode; |
188 | |
189 | u8 znr; |
190 | u8 zpr; |
191 | |
192 | /* Nr of consecutive Sampling Points of a Valid Sampling Window */ |
193 | u8 nr_tun_times; |
194 | /* Divider for calculating Tuning Step */ |
195 | u8 tun_step_divider; |
196 | |
197 | struct soc_pad_ctrl pad_ctrl; |
198 | }; |
199 | |
200 | static int xenon_alloc_emmc_phy(struct sdhci_host *host) |
201 | { |
202 | struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); |
203 | struct xenon_priv *priv = sdhci_pltfm_priv(host: pltfm_host); |
204 | struct xenon_emmc_phy_params *params; |
205 | |
206 | params = devm_kzalloc(mmc_dev(host->mmc), size: sizeof(*params), GFP_KERNEL); |
207 | if (!params) |
208 | return -ENOMEM; |
209 | |
210 | priv->phy_params = params; |
211 | if (priv->phy_type == EMMC_5_0_PHY) |
212 | priv->emmc_phy_regs = &xenon_emmc_5_0_phy_regs; |
213 | else |
214 | priv->emmc_phy_regs = &xenon_emmc_5_1_phy_regs; |
215 | |
216 | return 0; |
217 | } |
218 | |
219 | /* |
220 | * eMMC 5.0/5.1 PHY init/re-init. |
221 | * eMMC PHY init should be executed after: |
222 | * 1. SDCLK frequency changes. |
223 | * 2. SDCLK is stopped and re-enabled. |
224 | * 3. config in emmc_phy_regs->timing_adj and emmc_phy_regs->func_ctrl |
225 | * are changed |
226 | */ |
227 | static int xenon_emmc_phy_init(struct sdhci_host *host) |
228 | { |
229 | u32 reg; |
230 | u32 wait, clock; |
231 | struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); |
232 | struct xenon_priv *priv = sdhci_pltfm_priv(host: pltfm_host); |
233 | struct xenon_emmc_phy_regs *phy_regs = priv->emmc_phy_regs; |
234 | |
235 | reg = sdhci_readl(host, reg: phy_regs->timing_adj); |
236 | reg |= XENON_PHY_INITIALIZAION; |
237 | sdhci_writel(host, val: reg, reg: phy_regs->timing_adj); |
238 | |
239 | /* Add duration of FC_SYNC_RST */ |
240 | wait = ((reg >> XENON_FC_SYNC_RST_DURATION_SHIFT) & |
241 | XENON_FC_SYNC_RST_DURATION_MASK); |
242 | /* Add interval between FC_SYNC_EN and FC_SYNC_RST */ |
243 | wait += ((reg >> XENON_FC_SYNC_RST_EN_DURATION_SHIFT) & |
244 | XENON_FC_SYNC_RST_EN_DURATION_MASK); |
245 | /* Add duration of asserting FC_SYNC_EN */ |
246 | wait += ((reg >> XENON_FC_SYNC_EN_DURATION_SHIFT) & |
247 | XENON_FC_SYNC_EN_DURATION_MASK); |
248 | /* Add duration of waiting for PHY */ |
249 | wait += ((reg >> XENON_WAIT_CYCLE_BEFORE_USING_SHIFT) & |
250 | XENON_WAIT_CYCLE_BEFORE_USING_MASK); |
251 | /* 4 additional bus clock and 4 AXI bus clock are required */ |
252 | wait += 8; |
253 | wait <<= 20; |
254 | |
255 | clock = host->clock; |
256 | if (!clock) |
257 | /* Use the possibly slowest bus frequency value */ |
258 | clock = XENON_LOWEST_SDCLK_FREQ; |
259 | /* get the wait time */ |
260 | wait /= clock; |
261 | wait++; |
262 | /* wait for host eMMC PHY init completes */ |
263 | udelay(wait); |
264 | |
265 | reg = sdhci_readl(host, reg: phy_regs->timing_adj); |
266 | reg &= XENON_PHY_INITIALIZAION; |
267 | if (reg) { |
268 | dev_err(mmc_dev(host->mmc), "eMMC PHY init cannot complete after %d us\n" , |
269 | wait); |
270 | return -ETIMEDOUT; |
271 | } |
272 | |
273 | return 0; |
274 | } |
275 | |
276 | #define ARMADA_3700_SOC_PAD_1_8V 0x1 |
277 | #define ARMADA_3700_SOC_PAD_3_3V 0x0 |
278 | |
279 | static void armada_3700_soc_pad_voltage_set(struct sdhci_host *host, |
280 | unsigned char signal_voltage) |
281 | { |
282 | struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); |
283 | struct xenon_priv *priv = sdhci_pltfm_priv(host: pltfm_host); |
284 | struct xenon_emmc_phy_params *params = priv->phy_params; |
285 | |
286 | if (params->pad_ctrl.pad_type == SOC_PAD_FIXED_1_8V) { |
287 | writel(ARMADA_3700_SOC_PAD_1_8V, addr: params->pad_ctrl.reg); |
288 | } else if (params->pad_ctrl.pad_type == SOC_PAD_SD) { |
289 | if (signal_voltage == MMC_SIGNAL_VOLTAGE_180) |
290 | writel(ARMADA_3700_SOC_PAD_1_8V, addr: params->pad_ctrl.reg); |
291 | else if (signal_voltage == MMC_SIGNAL_VOLTAGE_330) |
292 | writel(ARMADA_3700_SOC_PAD_3_3V, addr: params->pad_ctrl.reg); |
293 | } |
294 | } |
295 | |
296 | /* |
297 | * Set SoC PHY voltage PAD control register, |
298 | * according to the operation voltage on PAD. |
299 | * The detailed operation depends on SoC implementation. |
300 | */ |
301 | static void xenon_emmc_phy_set_soc_pad(struct sdhci_host *host, |
302 | unsigned char signal_voltage) |
303 | { |
304 | struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); |
305 | struct xenon_priv *priv = sdhci_pltfm_priv(host: pltfm_host); |
306 | struct xenon_emmc_phy_params *params = priv->phy_params; |
307 | |
308 | if (!params->pad_ctrl.reg) |
309 | return; |
310 | |
311 | if (params->pad_ctrl.set_soc_pad) |
312 | params->pad_ctrl.set_soc_pad(host, signal_voltage); |
313 | } |
314 | |
315 | /* |
316 | * Enable eMMC PHY HW DLL |
317 | * DLL should be enabled and stable before HS200/SDR104 tuning, |
318 | * and before HS400 data strobe setting. |
319 | */ |
320 | static int xenon_emmc_phy_enable_dll(struct sdhci_host *host) |
321 | { |
322 | u32 reg; |
323 | struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); |
324 | struct xenon_priv *priv = sdhci_pltfm_priv(host: pltfm_host); |
325 | struct xenon_emmc_phy_regs *phy_regs = priv->emmc_phy_regs; |
326 | ktime_t timeout; |
327 | |
328 | if (WARN_ON(host->clock <= MMC_HIGH_52_MAX_DTR)) |
329 | return -EINVAL; |
330 | |
331 | reg = sdhci_readl(host, reg: phy_regs->dll_ctrl); |
332 | if (reg & XENON_DLL_ENABLE) |
333 | return 0; |
334 | |
335 | /* Enable DLL */ |
336 | reg = sdhci_readl(host, reg: phy_regs->dll_ctrl); |
337 | reg |= (XENON_DLL_ENABLE | XENON_DLL_FAST_LOCK); |
338 | |
339 | /* |
340 | * Set Phase as 90 degree, which is most common value. |
341 | * Might set another value if necessary. |
342 | * The granularity is 1 degree. |
343 | */ |
344 | reg &= ~((XENON_DLL_PHASE_MASK << XENON_DLL_PHSEL0_SHIFT) | |
345 | (XENON_DLL_PHASE_MASK << XENON_DLL_PHSEL1_SHIFT)); |
346 | reg |= ((XENON_DLL_PHASE_90_DEGREE << XENON_DLL_PHSEL0_SHIFT) | |
347 | (XENON_DLL_PHASE_90_DEGREE << XENON_DLL_PHSEL1_SHIFT)); |
348 | |
349 | reg &= ~XENON_DLL_BYPASS_EN; |
350 | reg |= phy_regs->dll_update; |
351 | if (priv->phy_type == EMMC_5_1_PHY) |
352 | reg &= ~XENON_DLL_REFCLK_SEL; |
353 | sdhci_writel(host, val: reg, reg: phy_regs->dll_ctrl); |
354 | |
355 | /* Wait max 32 ms */ |
356 | timeout = ktime_add_ms(kt: ktime_get(), msec: 32); |
357 | while (1) { |
358 | bool timedout = ktime_after(cmp1: ktime_get(), cmp2: timeout); |
359 | |
360 | if (sdhci_readw(host, XENON_SLOT_EXT_PRESENT_STATE) & |
361 | XENON_DLL_LOCK_STATE) |
362 | break; |
363 | if (timedout) { |
364 | dev_err(mmc_dev(host->mmc), "Wait for DLL Lock time-out\n" ); |
365 | return -ETIMEDOUT; |
366 | } |
367 | udelay(100); |
368 | } |
369 | return 0; |
370 | } |
371 | |
372 | /* |
373 | * Config to eMMC PHY to prepare for tuning. |
374 | * Enable HW DLL and set the TUNING_STEP |
375 | */ |
376 | static int xenon_emmc_phy_config_tuning(struct sdhci_host *host) |
377 | { |
378 | struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); |
379 | struct xenon_priv *priv = sdhci_pltfm_priv(host: pltfm_host); |
380 | struct xenon_emmc_phy_params *params = priv->phy_params; |
381 | u32 reg, tuning_step; |
382 | int ret; |
383 | |
384 | if (host->clock <= MMC_HIGH_52_MAX_DTR) |
385 | return -EINVAL; |
386 | |
387 | ret = xenon_emmc_phy_enable_dll(host); |
388 | if (ret) |
389 | return ret; |
390 | |
391 | /* Achieve TUNING_STEP with HW DLL help */ |
392 | reg = sdhci_readl(host, XENON_SLOT_DLL_CUR_DLY_VAL); |
393 | tuning_step = reg / params->tun_step_divider; |
394 | if (unlikely(tuning_step > XENON_TUNING_STEP_MASK)) { |
395 | dev_warn(mmc_dev(host->mmc), |
396 | "HS200 TUNING_STEP %d is larger than MAX value\n" , |
397 | tuning_step); |
398 | tuning_step = XENON_TUNING_STEP_MASK; |
399 | } |
400 | |
401 | /* Set TUNING_STEP for later tuning */ |
402 | reg = sdhci_readl(host, XENON_SLOT_OP_STATUS_CTRL); |
403 | reg &= ~(XENON_TUN_CONSECUTIVE_TIMES_MASK << |
404 | XENON_TUN_CONSECUTIVE_TIMES_SHIFT); |
405 | reg |= (params->nr_tun_times << XENON_TUN_CONSECUTIVE_TIMES_SHIFT); |
406 | reg &= ~(XENON_TUNING_STEP_MASK << XENON_TUNING_STEP_SHIFT); |
407 | reg |= (tuning_step << XENON_TUNING_STEP_SHIFT); |
408 | sdhci_writel(host, val: reg, XENON_SLOT_OP_STATUS_CTRL); |
409 | |
410 | return 0; |
411 | } |
412 | |
413 | static void xenon_emmc_phy_disable_strobe(struct sdhci_host *host) |
414 | { |
415 | struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); |
416 | struct xenon_priv *priv = sdhci_pltfm_priv(host: pltfm_host); |
417 | u32 reg; |
418 | |
419 | /* Disable both SDHC Data Strobe and Enhanced Strobe */ |
420 | reg = sdhci_readl(host, XENON_SLOT_EMMC_CTRL); |
421 | reg &= ~(XENON_ENABLE_DATA_STROBE | XENON_ENABLE_RESP_STROBE); |
422 | sdhci_writel(host, val: reg, XENON_SLOT_EMMC_CTRL); |
423 | |
424 | /* Clear Strobe line Pull down or Pull up */ |
425 | if (priv->phy_type == EMMC_5_0_PHY) { |
426 | reg = sdhci_readl(host, XENON_EMMC_5_0_PHY_PAD_CONTROL); |
427 | reg &= ~(XENON_EMMC5_FC_QSP_PD | XENON_EMMC5_FC_QSP_PU); |
428 | sdhci_writel(host, val: reg, XENON_EMMC_5_0_PHY_PAD_CONTROL); |
429 | } else { |
430 | reg = sdhci_readl(host, XENON_EMMC_PHY_PAD_CONTROL1); |
431 | reg &= ~(XENON_EMMC5_1_FC_QSP_PD | XENON_EMMC5_1_FC_QSP_PU); |
432 | sdhci_writel(host, val: reg, XENON_EMMC_PHY_PAD_CONTROL1); |
433 | } |
434 | } |
435 | |
436 | /* Set HS400 Data Strobe and Enhanced Strobe */ |
437 | static void xenon_emmc_phy_strobe_delay_adj(struct sdhci_host *host) |
438 | { |
439 | struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); |
440 | struct xenon_priv *priv = sdhci_pltfm_priv(host: pltfm_host); |
441 | u32 reg; |
442 | |
443 | if (WARN_ON(host->timing != MMC_TIMING_MMC_HS400)) |
444 | return; |
445 | |
446 | if (host->clock <= MMC_HIGH_52_MAX_DTR) |
447 | return; |
448 | |
449 | dev_dbg(mmc_dev(host->mmc), "starts HS400 strobe delay adjustment\n" ); |
450 | |
451 | xenon_emmc_phy_enable_dll(host); |
452 | |
453 | /* Enable SDHC Data Strobe */ |
454 | reg = sdhci_readl(host, XENON_SLOT_EMMC_CTRL); |
455 | reg |= XENON_ENABLE_DATA_STROBE; |
456 | /* |
457 | * Enable SDHC Enhanced Strobe if supported |
458 | * Xenon Enhanced Strobe should be enabled only when |
459 | * 1. card is in HS400 mode and |
460 | * 2. SDCLK is higher than 52MHz |
461 | * 3. DLL is enabled |
462 | */ |
463 | if (host->mmc->ios.enhanced_strobe) |
464 | reg |= XENON_ENABLE_RESP_STROBE; |
465 | sdhci_writel(host, val: reg, XENON_SLOT_EMMC_CTRL); |
466 | |
467 | /* Set Data Strobe Pull down */ |
468 | if (priv->phy_type == EMMC_5_0_PHY) { |
469 | reg = sdhci_readl(host, XENON_EMMC_5_0_PHY_PAD_CONTROL); |
470 | reg |= XENON_EMMC5_FC_QSP_PD; |
471 | reg &= ~XENON_EMMC5_FC_QSP_PU; |
472 | sdhci_writel(host, val: reg, XENON_EMMC_5_0_PHY_PAD_CONTROL); |
473 | } else { |
474 | reg = sdhci_readl(host, XENON_EMMC_PHY_PAD_CONTROL1); |
475 | reg |= XENON_EMMC5_1_FC_QSP_PD; |
476 | reg &= ~XENON_EMMC5_1_FC_QSP_PU; |
477 | sdhci_writel(host, val: reg, XENON_EMMC_PHY_PAD_CONTROL1); |
478 | } |
479 | } |
480 | |
481 | /* |
482 | * If eMMC PHY Slow Mode is required in lower speed mode (SDCLK < 55MHz) |
483 | * in SDR mode, enable Slow Mode to bypass eMMC PHY. |
484 | * SDIO slower SDR mode also requires Slow Mode. |
485 | * |
486 | * If Slow Mode is enabled, return true. |
487 | * Otherwise, return false. |
488 | */ |
489 | static bool xenon_emmc_phy_slow_mode(struct sdhci_host *host, |
490 | unsigned char timing) |
491 | { |
492 | struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); |
493 | struct xenon_priv *priv = sdhci_pltfm_priv(host: pltfm_host); |
494 | struct xenon_emmc_phy_params *params = priv->phy_params; |
495 | struct xenon_emmc_phy_regs *phy_regs = priv->emmc_phy_regs; |
496 | u32 reg; |
497 | int ret; |
498 | |
499 | if (host->clock > MMC_HIGH_52_MAX_DTR) |
500 | return false; |
501 | |
502 | reg = sdhci_readl(host, reg: phy_regs->timing_adj); |
503 | /* When in slower SDR mode, enable Slow Mode for SDIO |
504 | * or when Slow Mode flag is set |
505 | */ |
506 | switch (timing) { |
507 | case MMC_TIMING_LEGACY: |
508 | /* |
509 | * If Slow Mode is required, enable Slow Mode by default |
510 | * in early init phase to avoid any potential issue. |
511 | */ |
512 | if (params->slow_mode) { |
513 | reg |= XENON_TIMING_ADJUST_SLOW_MODE; |
514 | ret = true; |
515 | } else { |
516 | reg &= ~XENON_TIMING_ADJUST_SLOW_MODE; |
517 | ret = false; |
518 | } |
519 | break; |
520 | case MMC_TIMING_UHS_SDR25: |
521 | case MMC_TIMING_UHS_SDR12: |
522 | case MMC_TIMING_SD_HS: |
523 | case MMC_TIMING_MMC_HS: |
524 | if ((priv->init_card_type == MMC_TYPE_SDIO) || |
525 | params->slow_mode) { |
526 | reg |= XENON_TIMING_ADJUST_SLOW_MODE; |
527 | ret = true; |
528 | break; |
529 | } |
530 | fallthrough; |
531 | default: |
532 | reg &= ~XENON_TIMING_ADJUST_SLOW_MODE; |
533 | ret = false; |
534 | } |
535 | |
536 | sdhci_writel(host, val: reg, reg: phy_regs->timing_adj); |
537 | return ret; |
538 | } |
539 | |
540 | /* |
541 | * Set-up eMMC 5.0/5.1 PHY. |
542 | * Specific configuration depends on the current speed mode in use. |
543 | */ |
544 | static void xenon_emmc_phy_set(struct sdhci_host *host, |
545 | unsigned char timing) |
546 | { |
547 | u32 reg; |
548 | struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); |
549 | struct xenon_priv *priv = sdhci_pltfm_priv(host: pltfm_host); |
550 | struct xenon_emmc_phy_params *params = priv->phy_params; |
551 | struct xenon_emmc_phy_regs *phy_regs = priv->emmc_phy_regs; |
552 | |
553 | dev_dbg(mmc_dev(host->mmc), "eMMC PHY setting starts\n" ); |
554 | |
555 | /* Setup pad, set bit[28] and bits[26:24] */ |
556 | reg = sdhci_readl(host, reg: phy_regs->pad_ctrl); |
557 | reg |= (XENON_FC_DQ_RECEN | XENON_FC_CMD_RECEN | |
558 | XENON_FC_QSP_RECEN | XENON_OEN_QSN); |
559 | /* All FC_XX_RECEIVCE should be set as CMOS Type */ |
560 | reg |= XENON_FC_ALL_CMOS_RECEIVER; |
561 | sdhci_writel(host, val: reg, reg: phy_regs->pad_ctrl); |
562 | |
563 | /* Set CMD and DQ Pull Up */ |
564 | if (priv->phy_type == EMMC_5_0_PHY) { |
565 | reg = sdhci_readl(host, XENON_EMMC_5_0_PHY_PAD_CONTROL); |
566 | reg |= (XENON_EMMC5_FC_CMD_PU | XENON_EMMC5_FC_DQ_PU); |
567 | reg &= ~(XENON_EMMC5_FC_CMD_PD | XENON_EMMC5_FC_DQ_PD); |
568 | sdhci_writel(host, val: reg, XENON_EMMC_5_0_PHY_PAD_CONTROL); |
569 | } else { |
570 | reg = sdhci_readl(host, XENON_EMMC_PHY_PAD_CONTROL1); |
571 | reg |= (XENON_EMMC5_1_FC_CMD_PU | XENON_EMMC5_1_FC_DQ_PU); |
572 | reg &= ~(XENON_EMMC5_1_FC_CMD_PD | XENON_EMMC5_1_FC_DQ_PD); |
573 | sdhci_writel(host, val: reg, XENON_EMMC_PHY_PAD_CONTROL1); |
574 | } |
575 | |
576 | if (timing == MMC_TIMING_LEGACY) { |
577 | xenon_emmc_phy_slow_mode(host, timing); |
578 | goto phy_init; |
579 | } |
580 | |
581 | /* |
582 | * If SDIO card, set SDIO Mode |
583 | * Otherwise, clear SDIO Mode |
584 | */ |
585 | reg = sdhci_readl(host, reg: phy_regs->timing_adj); |
586 | if (priv->init_card_type == MMC_TYPE_SDIO) |
587 | reg |= XENON_TIMING_ADJUST_SDIO_MODE; |
588 | else |
589 | reg &= ~XENON_TIMING_ADJUST_SDIO_MODE; |
590 | sdhci_writel(host, val: reg, reg: phy_regs->timing_adj); |
591 | |
592 | if (xenon_emmc_phy_slow_mode(host, timing)) |
593 | goto phy_init; |
594 | |
595 | /* |
596 | * Set preferred ZNR and ZPR value |
597 | * The ZNR and ZPR value vary between different boards. |
598 | * Define them both in sdhci-xenon-emmc-phy.h. |
599 | */ |
600 | reg = sdhci_readl(host, reg: phy_regs->pad_ctrl2); |
601 | reg &= ~((XENON_ZNR_MASK << XENON_ZNR_SHIFT) | XENON_ZPR_MASK); |
602 | reg |= ((params->znr << XENON_ZNR_SHIFT) | params->zpr); |
603 | sdhci_writel(host, val: reg, reg: phy_regs->pad_ctrl2); |
604 | |
605 | /* |
606 | * When setting EMMC_PHY_FUNC_CONTROL register, |
607 | * SD clock should be disabled |
608 | */ |
609 | reg = sdhci_readl(host, SDHCI_CLOCK_CONTROL); |
610 | reg &= ~SDHCI_CLOCK_CARD_EN; |
611 | sdhci_writew(host, val: reg, SDHCI_CLOCK_CONTROL); |
612 | |
613 | reg = sdhci_readl(host, reg: phy_regs->func_ctrl); |
614 | switch (timing) { |
615 | case MMC_TIMING_MMC_HS400: |
616 | reg |= (XENON_DQ_DDR_MODE_MASK << XENON_DQ_DDR_MODE_SHIFT) | |
617 | XENON_CMD_DDR_MODE; |
618 | reg &= ~XENON_DQ_ASYNC_MODE; |
619 | break; |
620 | case MMC_TIMING_UHS_DDR50: |
621 | case MMC_TIMING_MMC_DDR52: |
622 | reg |= (XENON_DQ_DDR_MODE_MASK << XENON_DQ_DDR_MODE_SHIFT) | |
623 | XENON_CMD_DDR_MODE | XENON_DQ_ASYNC_MODE; |
624 | break; |
625 | default: |
626 | reg &= ~((XENON_DQ_DDR_MODE_MASK << XENON_DQ_DDR_MODE_SHIFT) | |
627 | XENON_CMD_DDR_MODE); |
628 | reg |= XENON_DQ_ASYNC_MODE; |
629 | } |
630 | sdhci_writel(host, val: reg, reg: phy_regs->func_ctrl); |
631 | |
632 | /* Enable bus clock */ |
633 | reg = sdhci_readl(host, SDHCI_CLOCK_CONTROL); |
634 | reg |= SDHCI_CLOCK_CARD_EN; |
635 | sdhci_writew(host, val: reg, SDHCI_CLOCK_CONTROL); |
636 | |
637 | if (timing == MMC_TIMING_MMC_HS400) |
638 | /* Hardware team recommend a value for HS400 */ |
639 | sdhci_writel(host, val: phy_regs->logic_timing_val, |
640 | reg: phy_regs->logic_timing_adj); |
641 | else |
642 | xenon_emmc_phy_disable_strobe(host); |
643 | |
644 | phy_init: |
645 | xenon_emmc_phy_init(host); |
646 | |
647 | dev_dbg(mmc_dev(host->mmc), "eMMC PHY setting completes\n" ); |
648 | } |
649 | |
650 | static int get_dt_pad_ctrl_data(struct sdhci_host *host, |
651 | struct device_node *np, |
652 | struct xenon_emmc_phy_params *params) |
653 | { |
654 | struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); |
655 | struct xenon_priv *priv = sdhci_pltfm_priv(host: pltfm_host); |
656 | int ret = 0; |
657 | const char *name; |
658 | struct resource iomem; |
659 | |
660 | if (priv->hw_version == XENON_A3700) |
661 | params->pad_ctrl.set_soc_pad = armada_3700_soc_pad_voltage_set; |
662 | else |
663 | return 0; |
664 | |
665 | if (of_address_to_resource(dev: np, index: 1, r: &iomem)) { |
666 | dev_err(mmc_dev(host->mmc), "Unable to find SoC PAD ctrl register address for %pOFn\n" , |
667 | np); |
668 | return -EINVAL; |
669 | } |
670 | |
671 | params->pad_ctrl.reg = devm_ioremap_resource(mmc_dev(host->mmc), |
672 | res: &iomem); |
673 | if (IS_ERR(ptr: params->pad_ctrl.reg)) |
674 | return PTR_ERR(ptr: params->pad_ctrl.reg); |
675 | |
676 | ret = of_property_read_string(np, propname: "marvell,pad-type" , out_string: &name); |
677 | if (ret) { |
678 | dev_err(mmc_dev(host->mmc), "Unable to determine SoC PHY PAD ctrl type\n" ); |
679 | return ret; |
680 | } |
681 | if (!strcmp(name, "sd" )) { |
682 | params->pad_ctrl.pad_type = SOC_PAD_SD; |
683 | } else if (!strcmp(name, "fixed-1-8v" )) { |
684 | params->pad_ctrl.pad_type = SOC_PAD_FIXED_1_8V; |
685 | } else { |
686 | dev_err(mmc_dev(host->mmc), "Unsupported SoC PHY PAD ctrl type %s\n" , |
687 | name); |
688 | return -EINVAL; |
689 | } |
690 | |
691 | return ret; |
692 | } |
693 | |
694 | static int xenon_emmc_phy_parse_params(struct sdhci_host *host, |
695 | struct device *dev, |
696 | struct xenon_emmc_phy_params *params) |
697 | { |
698 | u32 value; |
699 | |
700 | params->slow_mode = false; |
701 | if (device_property_read_bool(dev, propname: "marvell,xenon-phy-slow-mode" )) |
702 | params->slow_mode = true; |
703 | |
704 | params->znr = XENON_ZNR_DEF_VALUE; |
705 | if (!device_property_read_u32(dev, propname: "marvell,xenon-phy-znr" , val: &value)) |
706 | params->znr = value & XENON_ZNR_MASK; |
707 | |
708 | params->zpr = XENON_ZPR_DEF_VALUE; |
709 | if (!device_property_read_u32(dev, propname: "marvell,xenon-phy-zpr" , val: &value)) |
710 | params->zpr = value & XENON_ZPR_MASK; |
711 | |
712 | params->nr_tun_times = XENON_TUN_CONSECUTIVE_TIMES; |
713 | if (!device_property_read_u32(dev, propname: "marvell,xenon-phy-nr-success-tun" , |
714 | val: &value)) |
715 | params->nr_tun_times = value & XENON_TUN_CONSECUTIVE_TIMES_MASK; |
716 | |
717 | params->tun_step_divider = XENON_TUNING_STEP_DIVIDER; |
718 | if (!device_property_read_u32(dev, propname: "marvell,xenon-phy-tun-step-divider" , |
719 | val: &value)) |
720 | params->tun_step_divider = value & 0xFF; |
721 | |
722 | if (dev->of_node) |
723 | return get_dt_pad_ctrl_data(host, np: dev->of_node, params); |
724 | return 0; |
725 | } |
726 | |
727 | /* Set SoC PHY Voltage PAD */ |
728 | void xenon_soc_pad_ctrl(struct sdhci_host *host, |
729 | unsigned char signal_voltage) |
730 | { |
731 | xenon_emmc_phy_set_soc_pad(host, signal_voltage); |
732 | } |
733 | |
734 | /* |
735 | * Setting PHY when card is working in High Speed Mode. |
736 | * HS400 set Data Strobe and Enhanced Strobe if it is supported. |
737 | * HS200/SDR104 set tuning config to prepare for tuning. |
738 | */ |
739 | static int xenon_hs_delay_adj(struct sdhci_host *host) |
740 | { |
741 | int ret = 0; |
742 | |
743 | if (WARN_ON(host->clock <= XENON_DEFAULT_SDCLK_FREQ)) |
744 | return -EINVAL; |
745 | |
746 | switch (host->timing) { |
747 | case MMC_TIMING_MMC_HS400: |
748 | xenon_emmc_phy_strobe_delay_adj(host); |
749 | return 0; |
750 | case MMC_TIMING_MMC_HS200: |
751 | case MMC_TIMING_UHS_SDR104: |
752 | return xenon_emmc_phy_config_tuning(host); |
753 | case MMC_TIMING_MMC_DDR52: |
754 | case MMC_TIMING_UHS_DDR50: |
755 | /* |
756 | * DDR Mode requires driver to scan Sampling Fixed Delay Line, |
757 | * to find out a perfect operation sampling point. |
758 | * It is hard to implement such a scan in host driver |
759 | * since initiating commands by host driver is not safe. |
760 | * Thus so far just keep PHY Sampling Fixed Delay in |
761 | * default value of DDR mode. |
762 | * |
763 | * If any timing issue occurs in DDR mode on Marvell products, |
764 | * please contact maintainer for internal support in Marvell. |
765 | */ |
766 | dev_warn_once(mmc_dev(host->mmc), "Timing issue might occur in DDR mode\n" ); |
767 | return 0; |
768 | } |
769 | |
770 | return ret; |
771 | } |
772 | |
773 | /* |
774 | * Adjust PHY setting. |
775 | * PHY setting should be adjusted when SDCLK frequency, Bus Width |
776 | * or Speed Mode is changed. |
777 | * Additional config are required when card is working in High Speed mode, |
778 | * after leaving Legacy Mode. |
779 | */ |
780 | int xenon_phy_adj(struct sdhci_host *host, struct mmc_ios *ios) |
781 | { |
782 | struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); |
783 | struct xenon_priv *priv = sdhci_pltfm_priv(host: pltfm_host); |
784 | int ret = 0; |
785 | |
786 | if (!host->clock) { |
787 | priv->clock = 0; |
788 | return 0; |
789 | } |
790 | |
791 | /* |
792 | * The timing, frequency or bus width is changed, |
793 | * better to set eMMC PHY based on current setting |
794 | * and adjust Xenon SDHC delay. |
795 | */ |
796 | if ((host->clock == priv->clock) && |
797 | (ios->bus_width == priv->bus_width) && |
798 | (ios->timing == priv->timing)) |
799 | return 0; |
800 | |
801 | xenon_emmc_phy_set(host, timing: ios->timing); |
802 | |
803 | /* Update the record */ |
804 | priv->bus_width = ios->bus_width; |
805 | |
806 | priv->timing = ios->timing; |
807 | priv->clock = host->clock; |
808 | |
809 | /* Legacy mode is a special case */ |
810 | if (ios->timing == MMC_TIMING_LEGACY) |
811 | return 0; |
812 | |
813 | if (host->clock > XENON_DEFAULT_SDCLK_FREQ) |
814 | ret = xenon_hs_delay_adj(host); |
815 | return ret; |
816 | } |
817 | |
818 | static int xenon_add_phy(struct device *dev, struct sdhci_host *host, |
819 | const char *phy_name) |
820 | { |
821 | struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); |
822 | struct xenon_priv *priv = sdhci_pltfm_priv(host: pltfm_host); |
823 | int ret; |
824 | |
825 | priv->phy_type = match_string(array: phy_types, n: NR_PHY_TYPES, string: phy_name); |
826 | if (priv->phy_type < 0) { |
827 | dev_err(mmc_dev(host->mmc), |
828 | "Unable to determine PHY name %s. Use default eMMC 5.1 PHY\n" , |
829 | phy_name); |
830 | priv->phy_type = EMMC_5_1_PHY; |
831 | } |
832 | |
833 | ret = xenon_alloc_emmc_phy(host); |
834 | if (ret) |
835 | return ret; |
836 | |
837 | return xenon_emmc_phy_parse_params(host, dev, params: priv->phy_params); |
838 | } |
839 | |
840 | int xenon_phy_parse_params(struct device *dev, struct sdhci_host *host) |
841 | { |
842 | const char *phy_type = NULL; |
843 | |
844 | if (!device_property_read_string(dev, propname: "marvell,xenon-phy-type" , val: &phy_type)) |
845 | return xenon_add_phy(dev, host, phy_name: phy_type); |
846 | |
847 | return xenon_add_phy(dev, host, phy_name: "emmc 5.1 phy" ); |
848 | } |
849 | |