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