1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
|
// SPDX-License-Identifier: GPL-2.0-only
#include <linux/bitfield.h>
#include <linux/cleanup.h>
#include <linux/io.h>
#include <linux/iopoll.h>
#include <linux/module.h>
#include <linux/regmap.h>
#include <linux/usb.h>
#include <dt-bindings/phy/phy.h>
#include "phy-k3-common.h"
/* PHY Registers */
#define PHY_VERSION 0x0
#define PHY_RESET_CFG 0x04
#define PHY_RESET_RXBUF_RST BIT(0)
#define PHY_RESET_SOFT_RST_PCS BIT(1)
#define PHY_RESET_SOFT_RST_AHB BIT(2)
#define PHY_RESET_EN_SD_AFTER_LOCK BIT(6)
#define PHY_CLK_CFG 0x08
#define PHY_CLK_PLL_READY BIT(0)
#define PHY_CLK_TXCLK_INV BIT(2)
#define PHY_CLK_RXCLK_EN BIT(3)
#define PHY_CLK_TXCLK_EN BIT(4)
#define PHY_CLK_PCLK_EN BIT(5)
#define PHY_CLK_PIPE_PCLK_EN BIT(6)
#define PHY_CLK_REFCLK_FREQ GENMASK(10, 7)
#define PHY_CLK_REFCLK_24M 2
#define PHY_CLK_SW_INIT_DONE BIT(11)
#define PHY_CLK_PU_SSC_OUT BIT(23)
#define PHY_MODE_CFG 0x0C
#define PHY_MODE_PCIE_INT_EN BIT(0)
#define PHY_MODE_LFPS_TPERIOD GENMASK(9, 8)
#define PHY_MODE_LFPS_TPERIOD_USB 3
#define PHY_PU_SEL 0x40
#define PHY_PU_CFG_STATUS BIT(9)
#define PHY_PU_OVRD_STATUS BIT(10)
#define PHY_PU_CK_REG 0x54
#define PHY_PU_REFCLK_100 BIT(25)
#define PHY_PLL_REG1 0x58
#define PHY_PLL_FREF_SEL GENMASK(15, 13)
#define PHY_PLL_FREF_24M 0x1
#define PHY_PLL_SSC_DEP_SEL GENMASK(27, 24)
#define PHY_PLL_SSC_5000PPM 0xa
#define PHY_PLL_SSC_MODE GENMASK(29, 28)
#define PHY_PLL_SSC_MODE_CENTER_SPREAD 0
#define PHY_PLL_SSC_MODE_UP_SPREAD 1
#define PHY_PLL_SSC_MODE_DOWN_SPREAD 2
#define PHY_PLL_SSC_MODE_DOWN_SPREAD1 3
#define PHY_PLL_REG2 0x5c
#define PHY_PLL_SEL_REF100 BIT(21)
/* PHY RX Register Definitions */
#define PHY_RX_REG_A 0x60
#define PHY_RX_REG0_MASK GENMASK(7, 0)
#define PHY_RX_REG1_MASK GENMASK(15, 8)
#define PHY_RX_REG2_MASK GENMASK(23, 16)
#define PHY_RX_REG3_MASK GENMASK(31, 24)
#define PHY_RX_REG0_RLOAD BIT(4)
#define PHY_RX_REG1_RTERM GENMASK(11, 8)
#define PHY_RX_REG1_RC_CALI GENMASK(15, 12)
#define PHY_RX_REG2_CSEL GENMASK(19, 16)
#define PHY_RX_REG2_FORCE_CSEL BIT(20)
#define PHY_RX_REG2_PSEL GENMASK(23, 21)
#define PHY_RX_REG3_I_LOAD GENMASK(26, 24)
#define PHY_RX_REG3_SEL_CBOOST_CODE BIT(27)
#define PHY_RX_REG3_ADJ_BIAS GENMASK(29, 28)
#define PHY_RX_REG3_RDEG1 GENMASK(31, 30)
#define PHY_RX_REG_B 0x64
#define PHY_RX_REG4_MASK GENMASK(7, 0)
#define PHY_RX_REG5_MASK GENMASK(15, 8)
#define PHY_RX_REG6_MASK GENMASK(23, 16)
#define PHY_RX_REGB_MASK GENMASK(23, 0)
#define PHY_RX_REG4_RDEG2 GENMASK(2, 1)
#define PHY_RX_REG4_ENVOS BIT(4)
#define PHY_RX_REG4_RTERM_SEL BIT(5)
#define PHY_RX_REG4_MANUAL_CFG BIT(7)
#define PHY_RX_REG5_RCELL_VCM GENMASK(11, 8)
#define PHY_RX_REG5_RCELL_BIAS GENMASK(15, 12)
#define PHY_RX_REG6_H1_REG GENMASK(19, 16)
#define PHY_RX_REG6_ADAPT_GAIN GENMASK(21, 20)
#define PHY_RX_REG6_BYPASS_ADPT BIT(22)
#define PHY_ADPT_CFG0 0x140
#define PHY_ADPT_AFE_RST_OVRD_EN BIT(1)
#define PHY_ADPT_AFE_RST_OVRD_VAL BIT(4)
#define PHY_RXEQ_TIME 0xb4
#define PHY_RXEQ_TIME_OVRD_POST_C_SOC BIT(21)
#define PHY_RXEQ_TIME_CFG_AMP_SOC GENMASK(23, 22)
#define PHY_RXEQ_TIME_AMP_SOC_650M 0
#define PHY_RXEQ_TIME_AMP_SOC_800M 1
#define PHY_RXEQ_TIME_AMP_SOC_870M 2
#define PHY_RXEQ_TIME_AMP_SOC_900M 3
#define PHY_RXEQ_TIME_OVRD_AMP_SOC BIT(24)
#define PCIE_PU_ADDR_CLK_CFG 0x0008
#define PHY_CLK_PLL_READY BIT(0)
#define PCIE_INITAL_TIMER GENMASK(6, 3)
#define CFG_INTERNAL_TIMER_ADJ GENMASK(10, 7)
#define CFG_SW_PHY_INIT_DONE BIT(11)
/* Lane RX/TX configuration (per‑lane, at lane_base) */
#define PCIE_RX_REG1 0x050
#define PCIE_RX_REFCLK_MODE GENMASK(1, 0)
#define PCIE_RX_REFCLK_MODE_DRIVER 1
#define PCIE_RX_SEL_TRI_CODE BIT(2)
#define PCIE_RX_LEGACY GENMASK(15, 8)
#define PCIE_RX_LEGACY_DEFAULT 0x65
#define PCIE_TX_REG1 0x064
#define PCIE_PLL_TIMEOUT 500000
#define PCIE_POLL_DELAY 500
static int k3_usb3phy_init_single(struct k3_lane_group *lg, void __iomem *base)
{
struct phy *phy = lg->phy;
u32 val, tmp;
int ret;
/* Do not wait CDR lock before sampling data */
val = readl(base + PHY_RESET_CFG);
val = u32_replace_bits(val, 0, PHY_RESET_EN_SD_AFTER_LOCK);
writel(val, base + PHY_RESET_CFG);
/* Power down 100MHz refclk buffer */
val = readl(base + PHY_PU_CK_REG);
val = u32_replace_bits(val, 0, PHY_PU_REFCLK_100);
writel(val, base + PHY_PU_CK_REG);
/* Program PLL REG1 configure the SSC */
val = FIELD_PREP(PHY_PLL_SSC_MODE, PHY_PLL_SSC_MODE_DOWN_SPREAD1) |
FIELD_PREP(PHY_PLL_SSC_DEP_SEL, PHY_PLL_SSC_5000PPM) |
FIELD_PREP(PHY_PLL_FREF_SEL, PHY_PLL_FREF_24M);
writel(val, base + PHY_PLL_REG1);
/* Un-select 100MHz PLL reference */
val = readl(base + PHY_PLL_REG2);
val = u32_replace_bits(val, 0, PHY_PLL_SEL_REF100);
writel(val, base + PHY_PLL_REG2);
/* USB LFPS period configuration */
val = readl(base + PHY_MODE_CFG);
val = u32_replace_bits(val, PHY_MODE_LFPS_TPERIOD_USB, PHY_MODE_LFPS_TPERIOD);
writel(val, base + PHY_MODE_CFG);
/* Force AFE adaptation reset */
val = readl(base + PHY_ADPT_CFG0);
val |= PHY_ADPT_AFE_RST_OVRD_EN | PHY_ADPT_AFE_RST_OVRD_VAL;
writel(val, base + PHY_ADPT_CFG0);
/* Override driver amplitude value to 900m */
val = readl(base + PHY_RXEQ_TIME);
val |= PHY_RXEQ_TIME_OVRD_AMP_SOC;
val = u32_replace_bits(val, PHY_RXEQ_TIME_AMP_SOC_900M, PHY_RXEQ_TIME_CFG_AMP_SOC);
writel(val, base + PHY_RXEQ_TIME);
/* Configure RX parameters */
val = PHY_RX_REG0_RLOAD |
FIELD_PREP(PHY_RX_REG1_RTERM, 0x8) |
FIELD_PREP(PHY_RX_REG1_RC_CALI, 0x7) |
FIELD_PREP(PHY_RX_REG2_CSEL, 0x8) |
PHY_RX_REG2_FORCE_CSEL |
FIELD_PREP(PHY_RX_REG2_PSEL, 0x4) |
FIELD_PREP(PHY_RX_REG3_I_LOAD, 0x7) |
PHY_RX_REG3_SEL_CBOOST_CODE |
FIELD_PREP(PHY_RX_REG3_ADJ_BIAS, 0x1) |
FIELD_PREP(PHY_RX_REG3_RDEG1, 0x3);
writel(val, base + PHY_RX_REG_A);
val = readl(base + PHY_RX_REG_B);
tmp = FIELD_PREP(PHY_RX_REG4_RDEG2, 0x2) |
PHY_RX_REG4_ENVOS | PHY_RX_REG4_RTERM_SEL | PHY_RX_REG4_MANUAL_CFG |
FIELD_PREP(PHY_RX_REG5_RCELL_VCM, 0x8) |
FIELD_PREP(PHY_RX_REG5_RCELL_BIAS, 0x8) |
FIELD_PREP(PHY_RX_REG6_H1_REG, 0x8) |
FIELD_PREP(PHY_RX_REG6_ADAPT_GAIN, 0x2);
val = u32_replace_bits(val, tmp, PHY_RX_REGB_MASK);
writel(val, base + PHY_RX_REG_B);
/*
* Inform PHY that all PLL-related configuration is done.
* PLL will not start locking until PHY_CLK_SW_INIT_DONE is set.
*/
val = PHY_CLK_SW_INIT_DONE | PHY_CLK_PU_SSC_OUT |
FIELD_PREP(PHY_CLK_REFCLK_FREQ, PHY_CLK_REFCLK_24M) |
PHY_CLK_RXCLK_EN | PHY_CLK_TXCLK_EN |
PHY_CLK_PCLK_EN | PHY_CLK_PIPE_PCLK_EN;
writel(val, base + PHY_CLK_CFG);
ret = readl_poll_timeout(base + PHY_CLK_CFG, val,
(val & PHY_CLK_PLL_READY),
PCIE_POLL_DELAY, PCIE_PLL_TIMEOUT);
if (ret) {
dev_err(&phy->dev, "PHY PLL polling timeout\n");
return ret;
}
return 0;
}
static int k3_usb3phy_init(struct phy *phy)
{
struct k3_lane_group *lg = phy_get_drvdata(phy);
int ret, i;
for (i = 0; i < lg->data->lanes; i++) {
ret = k3_usb3phy_init_single(lg, lg->base + lg->data->offsets[i]);
if (ret < 0)
return ret;
}
return 0;
}
const struct phy_ops k3_usb3_phy_ops = {
.init = k3_usb3phy_init,
.owner = THIS_MODULE,
};
EXPORT_SYMBOL_GPL(k3_usb3_phy_ops);
static int k3_pcie_phy_init(struct phy *phy)
{
struct k3_lane_group *lg = phy_get_drvdata(phy);
void __iomem *phy_base = lg->base + lg->data->offsets[0];
u32 val;
int ret;
int i;
val = readl(phy_base + PHY_PLL_REG1);
val = u32_replace_bits(val, 0x2, GENMASK(15, 12));
writel(val, phy_base + PHY_PLL_REG1);
val = readl(phy_base + PHY_PLL_REG2);
val = u32_replace_bits(val, 0, BIT(21));
writel(val, phy_base + PHY_PLL_REG2);
for (i = 0; i < lg->data->lanes; i++) {
void __iomem *lane_base = lg->base + lg->data->offsets[i];
val = readl(lane_base + PCIE_RX_REG1);
val = u32_replace_bits(val, 0, 0x3);
writel(val, lane_base + PCIE_RX_REG1);
}
val = readl(phy_base + PHY_PLL_REG2);
val |= BIT(20);
writel(val, phy_base + PHY_PLL_REG2);
/* The write is needed as clock requires renegotiation */
val = FIELD_PREP(PCIE_RX_REFCLK_MODE, PCIE_RX_REFCLK_MODE_DRIVER) |
PCIE_RX_SEL_TRI_CODE |
FIELD_PREP(PCIE_RX_LEGACY, PCIE_RX_LEGACY_DEFAULT);
writel(val, phy_base + PCIE_RX_REG1);
/* pll_reg1 of lane0, disable SSC: pll[27:24] = 0 */
val = readl(phy_base + PHY_PLL_REG1);
val = u32_replace_bits(val, 0, GENMASK(27, 24));
writel(val, phy_base + PHY_PLL_REG1);
for (i = 0; i < lg->data->lanes; i++) {
void __iomem *lane_base = lg->base + lg->data->offsets[i];
/* set cfg_tx_send_dummy_data to be 1'b1 for disable dash data */
val = readl(lane_base + PHY_PU_SEL);
val = u32_replace_bits(val, 1, BIT(13));
writel(val, lane_base + PHY_PU_SEL);
/* disable en_sample_data_after_cdr_locked */
val = readl(lane_base + PHY_RESET_CFG);
val = u32_replace_bits(val, 0, BIT(6));
writel(val, lane_base + PHY_RESET_CFG);
/* Dynamic Lock */
val = readl(lane_base + PHY_MODE_CFG);
val = u32_replace_bits(val, 1, BIT(2));
writel(val, lane_base + PHY_MODE_CFG);
val = FIELD_PREP(PHY_RX_REG0_MASK, 0x10) |
FIELD_PREP(PHY_RX_REG1_MASK, 0x78) |
FIELD_PREP(PHY_RX_REG2_MASK, 0x98) |
FIELD_PREP(PHY_RX_REG3_MASK, 0xdf);
writel(val, lane_base + PHY_RX_REG_A);
val = readl(lane_base + PHY_RX_REG_B);
val &= ~PHY_RX_REGB_MASK;
val |= FIELD_PREP(PHY_RX_REG4_MASK, 0xb4) |
FIELD_PREP(PHY_RX_REG5_MASK, 0x88) |
FIELD_PREP(PHY_RX_REG6_MASK, 0x28);
writel(val, lane_base + PHY_RX_REG_B);
/* Set init done */
val = readl(lane_base + PCIE_PU_ADDR_CLK_CFG);
val = u32_replace_bits(val, 1, CFG_SW_PHY_INIT_DONE);
writel(val, lane_base + PCIE_PU_ADDR_CLK_CFG);
}
ret = readl_poll_timeout(phy_base + PCIE_PU_ADDR_CLK_CFG, val,
(val & PHY_CLK_PLL_READY), PCIE_POLL_DELAY,
PCIE_PLL_TIMEOUT);
if (ret) {
dev_err(&lg->phy->dev, "PHY PLL lock timeout\n");
return ret;
}
return 0;
}
const struct phy_ops k3_pcie_phy_ops = {
.init = k3_pcie_phy_init,
.owner = THIS_MODULE,
};
EXPORT_SYMBOL_GPL(k3_pcie_phy_ops);
/* PHY rcal init requires APB_SPARE regmap access */
#define APB_SPARE_PU_CAL 0x178
#define PU_CAL BIT(17)
#define APB_SPARE_RCAL_HSIO 0x17c
#define APB_SPARE_PU_CAL_DONE BIT(8)
#define RCAL_OVRD_PTRIM GENMASK(23, 20)
#define RCAL_OVRD_NTRIM GENMASK(27, 24)
#define RCAL_OVRD_PTRIM_EN BIT(28)
#define RCAL_OVRD_NTRIM_EN BIT(29)
#define RCAL_OVRD_STABLE_VAL BIT(30)
#define RCAL_OVRD_STABLE_EN BIT(31)
#define RCAL_OVRD_TRIM_EN (RCAL_OVRD_NTRIM_EN | RCAL_OVRD_PTRIM_EN)
#define RCAL_OVRD_TRIM_MASK (RCAL_OVRD_NTRIM | RCAL_OVRD_PTRIM)
#define PU_CAL_TIMEOUT 2000000
static DEFINE_MUTEX(calibrate_lock);
int k3_phy_calibrate(struct regmap *apb_spare)
{
unsigned int val = 0;
int ret;
guard(mutex)(&calibrate_lock);
regmap_read(apb_spare, APB_SPARE_RCAL_HSIO, &val);
if (val & APB_SPARE_PU_CAL_DONE)
return 0;
regmap_update_bits(apb_spare, APB_SPARE_PU_CAL, PU_CAL,
PU_CAL);
ret = regmap_read_poll_timeout(apb_spare, APB_SPARE_RCAL_HSIO,
val, (val & APB_SPARE_PU_CAL_DONE), PCIE_POLL_DELAY,
PU_CAL_TIMEOUT);
if (ret)
regmap_update_bits(apb_spare, APB_SPARE_RCAL_HSIO,
RCAL_OVRD_TRIM_EN | RCAL_OVRD_STABLE_VAL |
RCAL_OVRD_TRIM_MASK | RCAL_OVRD_STABLE_EN,
RCAL_OVRD_TRIM_EN | RCAL_OVRD_STABLE_VAL |
FIELD_PREP(RCAL_OVRD_NTRIM, 0x6) |
FIELD_PREP(RCAL_OVRD_PTRIM, 0xa) |
RCAL_OVRD_STABLE_EN);
return 0;
}
EXPORT_SYMBOL_GPL(k3_phy_calibrate);
MODULE_DESCRIPTION("SpacemiT K3 PHY common ops");
MODULE_LICENSE("GPL");
|