blob: 1c5ed538370ea9a3293871ef89f0fe0be5090770 [file] [log] [blame]
Venkatesh Yadav Abbarapufb59d472024-09-20 09:46:50 +05301// SPDX-License-Identifier: GPL-2.0
2/*
3 * Copyright (C) 2024 Advanced Micro Devices, Inc.
4 */
5
6#include <clk.h>
7#include <dm.h>
8#include <ufs.h>
9#include <asm/io.h>
10#include <dm/device_compat.h>
11#include <zynqmp_firmware.h>
12#include <linux/bitops.h>
13#include <linux/delay.h>
14#include <linux/err.h>
15#include <linux/time.h>
16#include <reset.h>
17
18#include "ufs.h"
19#include "ufshcd-dwc.h"
20#include "ufshci-dwc.h"
21
Venkatesh Yadav Abbarapufb59d472024-09-20 09:46:50 +053022#define SRAM_CSR_INIT_DONE_MASK BIT(0)
23#define SRAM_CSR_EXT_LD_DONE_MASK BIT(1)
24#define SRAM_CSR_BYPASS_MASK BIT(2)
25
26#define MPHY_FAST_RX_AFE_CAL BIT(2)
27#define MPHY_FW_CALIB_CFG_VAL BIT(8)
28
29#define TX_RX_CFG_RDY_MASK GENMASK(3, 0)
30
31#define TIMEOUT_MICROSEC 1000000L
32
Venkatesh Yadav Abbarapufb59d472024-09-20 09:46:50 +053033struct ufs_versal2_priv {
34 struct ufs_hba *hba;
35 struct reset_ctl *rstc;
36 struct reset_ctl *rstphy;
37 u32 phy_mode;
38 u32 host_clk;
Venkatesh Yadav Abbarapufb59d472024-09-20 09:46:50 +053039 u8 attcompval0;
40 u8 attcompval1;
41 u8 ctlecompval0;
42 u8 ctlecompval1;
43};
44
45static int ufs_versal2_phy_reg_write(struct ufs_hba *hba, u32 addr, u32 val)
46{
47 static struct ufshcd_dme_attr_val phy_write_attrs[] = {
48 { UIC_ARG_MIB(CBCREGADDRLSB), 0, DME_LOCAL },
49 { UIC_ARG_MIB(CBCREGADDRMSB), 0, DME_LOCAL },
50 { UIC_ARG_MIB(CBCREGWRLSB), 0, DME_LOCAL },
51 { UIC_ARG_MIB(CBCREGWRMSB), 0, DME_LOCAL },
52 { UIC_ARG_MIB(CBCREGRDWRSEL), 1, DME_LOCAL },
53 { UIC_ARG_MIB(VS_MPHYCFGUPDT), 1, DME_LOCAL }
54 };
55
56 phy_write_attrs[0].mib_val = (u8)addr;
57 phy_write_attrs[1].mib_val = (u8)(addr >> 8);
58 phy_write_attrs[2].mib_val = (u8)val;
59 phy_write_attrs[3].mib_val = (u8)(val >> 8);
60
61 return ufshcd_dwc_dme_set_attrs(hba, phy_write_attrs, ARRAY_SIZE(phy_write_attrs));
62}
63
64static int ufs_versal2_phy_reg_read(struct ufs_hba *hba, u32 addr, u32 *val)
65{
66 u32 mib_val;
67 int ret;
68 static struct ufshcd_dme_attr_val phy_read_attrs[] = {
69 { UIC_ARG_MIB(CBCREGADDRLSB), 0, DME_LOCAL },
70 { UIC_ARG_MIB(CBCREGADDRMSB), 0, DME_LOCAL },
71 { UIC_ARG_MIB(CBCREGRDWRSEL), 0, DME_LOCAL },
72 { UIC_ARG_MIB(VS_MPHYCFGUPDT), 1, DME_LOCAL }
73 };
74
75 phy_read_attrs[0].mib_val = (u8)addr;
76 phy_read_attrs[1].mib_val = (u8)(addr >> 8);
77
78 ret = ufshcd_dwc_dme_set_attrs(hba, phy_read_attrs, ARRAY_SIZE(phy_read_attrs));
79 if (ret)
80 return ret;
81
82 ret = ufshcd_dme_get(hba, UIC_ARG_MIB(CBCREGRDLSB), &mib_val);
83 if (ret)
84 return ret;
85
86 *val = mib_val;
87 ret = ufshcd_dme_get(hba, UIC_ARG_MIB(CBCREGRDMSB), &mib_val);
88 if (ret)
89 return ret;
90
91 *val |= (mib_val << 8);
92
93 return 0;
94}
95
Venkatesh Yadav Abbarapufb59d472024-09-20 09:46:50 +053096static int ufs_versal2_enable_phy(struct ufs_hba *hba)
97{
98 u32 offset, reg;
99 int ret;
100
101 ret = ufshcd_dme_set(hba, UIC_ARG_MIB(VS_MPHYDISABLE), 0);
102 if (ret)
103 return ret;
104
105 ret = ufshcd_dme_set(hba, UIC_ARG_MIB(VS_MPHYCFGUPDT), 1);
106 if (ret)
107 return ret;
108
109 /* Check Tx/Rx FSM states */
110 for (offset = 0; offset < 2; offset++) {
111 u32 time_left, mibsel;
112
113 time_left = TIMEOUT_MICROSEC;
114 mibsel = UIC_ARG_MIB_SEL(MTX_FSM_STATE, UIC_ARG_MPHY_TX_GEN_SEL_INDEX(offset));
115 do {
116 ret = ufshcd_dme_get(hba, mibsel, &reg);
117 if (ret)
118 return ret;
119
120 if (reg == TX_STATE_HIBERN8 || reg == TX_STATE_SLEEP ||
121 reg == TX_STATE_LSBURST)
122 break;
123
124 time_left--;
125 mdelay(5);
126 } while (time_left);
127
128 if (!time_left) {
129 dev_err(hba->dev, "Invalid Tx FSM state.\n");
130 return -ETIMEDOUT;
131 }
132
133 time_left = TIMEOUT_MICROSEC;
134 mibsel = UIC_ARG_MIB_SEL(MRX_FSM_STATE, UIC_ARG_MPHY_RX_GEN_SEL_INDEX(offset));
135 do {
136 ret = ufshcd_dme_get(hba, mibsel, &reg);
137 if (ret)
138 return ret;
139
140 if (reg == RX_STATE_HIBERN8 || reg == RX_STATE_SLEEP ||
141 reg == RX_STATE_LSBURST)
142 break;
143
144 time_left--;
145 mdelay(5);
146 } while (time_left);
147
148 if (!time_left) {
149 dev_err(hba->dev, "Invalid Rx FSM state.\n");
150 return -ETIMEDOUT;
151 }
152 }
153
154 return 0;
155}
156
157static int ufs_versal2_setup_phy(struct ufs_hba *hba)
158{
159 struct ufs_versal2_priv *priv = dev_get_priv(hba->dev);
160 int ret;
161 u32 reg;
162
163 /* Bypass RX-AFE offset calibrations (ATT/CTLE) */
164 ret = ufs_versal2_phy_reg_read(hba, FAST_FLAGS(0), &reg);
165 if (ret)
166 return ret;
167
168 reg |= MPHY_FAST_RX_AFE_CAL;
169 ret = ufs_versal2_phy_reg_write(hba, FAST_FLAGS(0), reg);
170 if (ret)
171 return ret;
172
173 ret = ufs_versal2_phy_reg_read(hba, FAST_FLAGS(1), &reg);
174 if (ret)
175 return ret;
176
177 reg |= MPHY_FAST_RX_AFE_CAL;
178 ret = ufs_versal2_phy_reg_write(hba, FAST_FLAGS(1), reg);
179 if (ret)
180 return ret;
181
182 /* Program ATT and CTLE compensation values */
183 if (priv->attcompval0) {
184 ret = ufs_versal2_phy_reg_write(hba, RX_AFE_ATT_IDAC(0), priv->attcompval0);
185 if (ret)
186 return ret;
187 }
188
189 if (priv->attcompval1) {
190 ret = ufs_versal2_phy_reg_write(hba, RX_AFE_ATT_IDAC(1), priv->attcompval1);
191 if (ret)
192 return ret;
193 }
194
195 if (priv->ctlecompval0) {
196 ret = ufs_versal2_phy_reg_write(hba, RX_AFE_CTLE_IDAC(0), priv->ctlecompval0);
197 if (ret)
198 return ret;
199 }
200
201 if (priv->ctlecompval1) {
202 ret = ufs_versal2_phy_reg_write(hba, RX_AFE_CTLE_IDAC(1), priv->ctlecompval1);
203 if (ret)
204 return ret;
205 }
206
207 ret = ufs_versal2_phy_reg_read(hba, FW_CALIB_CCFG(0), &reg);
208 if (ret)
209 return ret;
210
211 reg |= MPHY_FW_CALIB_CFG_VAL;
212 ret = ufs_versal2_phy_reg_write(hba, FW_CALIB_CCFG(0), reg);
213 if (ret)
214 return ret;
215
216 ret = ufs_versal2_phy_reg_read(hba, FW_CALIB_CCFG(1), &reg);
217 if (ret)
218 return ret;
219
220 reg |= MPHY_FW_CALIB_CFG_VAL;
221 return ufs_versal2_phy_reg_write(hba, FW_CALIB_CCFG(1), reg);
222}
223
224static int ufs_versal2_phy_init(struct ufs_hba *hba)
225{
226 struct ufs_versal2_priv *priv = dev_get_priv(hba->dev);
227 u32 reg, time_left;
228 int ret;
229 static const struct ufshcd_dme_attr_val rmmi_attrs[] = {
230 { UIC_ARG_MIB(CBREFCLKCTRL2), CBREFREFCLK_GATE_OVR_EN, DME_LOCAL },
231 { UIC_ARG_MIB(CBCRCTRL), 1, DME_LOCAL },
232 { UIC_ARG_MIB(CBC10DIRECTCONF2), 1, DME_LOCAL },
233 { UIC_ARG_MIB(VS_MPHYCFGUPDT), 1, DME_LOCAL }
234 };
235
236 /* Wait for Tx/Rx config_rdy */
237 time_left = TIMEOUT_MICROSEC;
238 do {
239 time_left--;
Venkatesh Yadav Abbarapu1b243002025-03-20 10:13:24 +0100240 ret = zynqmp_pm_ufs_get_txrx_cfgrdy(&reg);
Venkatesh Yadav Abbarapufb59d472024-09-20 09:46:50 +0530241 if (ret)
242 return ret;
243
244 reg &= TX_RX_CFG_RDY_MASK;
245 if (!reg)
246 break;
247
248 mdelay(5);
249 } while (time_left);
250
251 if (!time_left) {
252 dev_err(hba->dev, "Tx/Rx configuration signal busy.\n");
253 return -ETIMEDOUT;
254 }
255
256 ret = ufshcd_dwc_dme_set_attrs(hba, rmmi_attrs, ARRAY_SIZE(rmmi_attrs));
257 if (ret)
258 return ret;
259
260 /* DeAssert PHY reset */
261 ret = reset_deassert(priv->rstphy);
262 if (ret) {
263 dev_err(hba->dev, "ufsphy reset deassert failed\n");
264 return ret;
265 }
266
267 /* Wait for SRAM init done */
268 time_left = TIMEOUT_MICROSEC;
269 do {
270 time_left--;
Venkatesh Yadav Abbarapu1b243002025-03-20 10:13:24 +0100271 ret = zynqmp_pm_ufs_sram_csr_read(&reg);
Venkatesh Yadav Abbarapufb59d472024-09-20 09:46:50 +0530272 if (ret)
273 return ret;
274
275 reg &= SRAM_CSR_INIT_DONE_MASK;
276 if (reg)
277 break;
278
279 mdelay(5);
280 } while (time_left);
281
282 if (!time_left) {
283 dev_err(hba->dev, "SRAM initialization failed.\n");
284 return -ETIMEDOUT;
285 }
286
287 ret = ufs_versal2_setup_phy(hba);
288 if (ret)
289 return ret;
290
291 return ufs_versal2_enable_phy(hba);
292}
293
294static int ufs_versal2_init(struct ufs_hba *hba)
295{
296 struct ufs_versal2_priv *priv = dev_get_priv(hba->dev);
297 struct clk clk;
298 unsigned long core_clk_rate = 0;
Venkatesh Yadav Abbarapu1b243002025-03-20 10:13:24 +0100299 u32 cal;
Venkatesh Yadav Abbarapufb59d472024-09-20 09:46:50 +0530300 int ret = 0;
301
302 priv->phy_mode = UFSHCD_DWC_PHY_MODE_ROM;
Venkatesh Yadav Abbarapufb59d472024-09-20 09:46:50 +0530303
304 ret = clk_get_by_name(hba->dev, "core_clk", &clk);
305 if (ret) {
306 dev_err(hba->dev, "failed to get core_clk clock\n");
307 return ret;
308 }
309
310 core_clk_rate = clk_get_rate(&clk);
311 if (IS_ERR_VALUE(core_clk_rate)) {
312 dev_err(hba->dev, "%s: unable to find core_clk rate\n",
313 __func__);
314 return core_clk_rate;
315 }
316 priv->host_clk = core_clk_rate;
317
318 priv->rstc = devm_reset_control_get(hba->dev, "ufshc-rst");
319 if (IS_ERR(priv->rstc)) {
320 dev_err(hba->dev, "failed to get reset ctl: ufshc-rst\n");
321 return PTR_ERR(priv->rstc);
322 }
323 priv->rstphy = devm_reset_control_get(hba->dev, "ufsphy-rst");
324 if (IS_ERR(priv->rstphy)) {
325 dev_err(hba->dev, "failed to get reset ctl: ufsphy-rst\n");
326 return PTR_ERR(priv->rstphy);
327 }
328
Venkatesh Yadav Abbarapu1b243002025-03-20 10:13:24 +0100329 ret = zynqmp_pm_ufs_cal_reg(&cal);
330 if (ret)
331 return ret;
332
333 priv->attcompval0 = (u8)cal;
334 priv->attcompval1 = (u8)(cal >> 8);
335 priv->ctlecompval0 = (u8)(cal >> 16);
336 priv->ctlecompval1 = (u8)(cal >> 24);
337
Venkatesh Yadav Abbarapufb59d472024-09-20 09:46:50 +0530338 return ret;
339}
340
341static int ufs_versal2_hce_enable_notify(struct ufs_hba *hba,
342 enum ufs_notify_change_status status)
343{
344 struct ufs_versal2_priv *priv = dev_get_priv(hba->dev);
345 u32 sram_csr;
346 int ret;
347
348 switch (status) {
349 case PRE_CHANGE:
350 /* Assert RST_UFS Reset for UFS block in PMX_IOU */
351 ret = reset_assert(priv->rstc);
352 if (ret) {
353 dev_err(hba->dev, "ufshc reset assert failed, err = %d\n", ret);
354 return ret;
355 }
356
357 /* Assert PHY reset */
358 ret = reset_assert(priv->rstphy);
359 if (ret) {
360 dev_err(hba->dev, "ufsphy reset assert failed, err = %d\n", ret);
361 return ret;
362 }
363
Venkatesh Yadav Abbarapu1b243002025-03-20 10:13:24 +0100364 ret = zynqmp_pm_ufs_sram_csr_read(&sram_csr);
Venkatesh Yadav Abbarapufb59d472024-09-20 09:46:50 +0530365 if (ret)
366 return ret;
367
368 if (!priv->phy_mode) {
369 sram_csr &= ~SRAM_CSR_EXT_LD_DONE_MASK;
370 sram_csr |= SRAM_CSR_BYPASS_MASK;
371 } else {
372 dev_err(hba->dev, "Invalid phy-mode %d.\n", priv->phy_mode);
373 return -EINVAL;
374 }
375
Venkatesh Yadav Abbarapu1b243002025-03-20 10:13:24 +0100376 ret = zynqmp_pm_ufs_sram_csr_write(&sram_csr);
Venkatesh Yadav Abbarapufb59d472024-09-20 09:46:50 +0530377 if (ret)
378 return ret;
379
380 /* De Assert RST_UFS Reset for UFS block in PMX_IOU */
381 ret = reset_deassert(priv->rstc);
382 if (ret)
383 dev_err(hba->dev, "ufshc reset deassert failed, err = %d\n", ret);
384
385 break;
386 case POST_CHANGE:
387 ret = ufs_versal2_phy_init(hba);
388 if (ret)
389 dev_err(hba->dev, "Phy init failed (%d)\n", ret);
390
391 break;
392 default:
393 ret = -EINVAL;
394 break;
395 }
396
397 return ret;
398}
399
400static int ufs_versal2_link_startup_notify(struct ufs_hba *hba,
401 enum ufs_notify_change_status status)
402{
403 struct ufs_versal2_priv *priv = dev_get_priv(hba->dev);
404 int ret = 0;
405
406 switch (status) {
407 case PRE_CHANGE:
408 if (priv->host_clk) {
409 u32 core_clk_div = priv->host_clk / TIMEOUT_MICROSEC;
410
411 ufshcd_writel(hba, core_clk_div, DWC_UFS_REG_HCLKDIV);
412 }
413 break;
414 case POST_CHANGE:
415 ret = ufshcd_dwc_link_startup_notify(hba, status);
416 break;
417 default:
418 ret = -EINVAL;
419 break;
420 }
421
422 return ret;
423}
424
425static struct ufs_hba_ops ufs_versal2_hba_ops = {
426 .init = ufs_versal2_init,
427 .link_startup_notify = ufs_versal2_link_startup_notify,
428 .hce_enable_notify = ufs_versal2_hce_enable_notify,
429};
430
431static int ufs_versal2_probe(struct udevice *dev)
432{
433 int ret;
434
435 /* Perform generic probe */
436 ret = ufshcd_probe(dev, &ufs_versal2_hba_ops);
437 if (ret)
438 dev_err(dev, "ufshcd_probe() failed %d\n", ret);
439
440 return ret;
441}
442
443static int ufs_versal2_bind(struct udevice *dev)
444{
445 struct udevice *scsi_dev;
446
447 return ufs_scsi_bind(dev, &scsi_dev);
448}
449
450static const struct udevice_id ufs_versal2_ids[] = {
451 {
452 .compatible = "amd,versal2-ufs",
453 },
454 {},
455};
456
457U_BOOT_DRIVER(ufs_versal2_pltfm) = {
458 .name = "ufs-versal2-pltfm",
459 .id = UCLASS_UFS,
460 .of_match = ufs_versal2_ids,
461 .probe = ufs_versal2_probe,
462 .bind = ufs_versal2_bind,
463};