]>
Commit | Line | Data |
---|---|---|
214de087 JT |
1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* | |
3 | * ROCKCHIP Type-C PHY driver. | |
4 | * | |
5 | * Copyright (C) 2020 Amarula Solutions(India) | |
6 | * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd | |
7 | * Author: Chris Zhong <zyw@rock-chips.com> | |
8 | * Kever Yang <kever.yang@rock-chips.com> | |
9 | */ | |
10 | ||
d678a59d | 11 | #include <common.h> |
214de087 JT |
12 | #include <clk.h> |
13 | #include <dm.h> | |
401d1c4f | 14 | #include <asm/global_data.h> |
214de087 JT |
15 | #include <dm/device_compat.h> |
16 | #include <dm/lists.h> | |
17 | #include <generic-phy.h> | |
18 | #include <reset.h> | |
19 | #include <syscon.h> | |
20 | #include <asm/gpio.h> | |
21 | #include <asm/io.h> | |
22 | #include <linux/iopoll.h> | |
23 | #include <asm/arch-rockchip/clock.h> | |
24 | ||
25 | DECLARE_GLOBAL_DATA_PTR; | |
26 | ||
27 | #define usleep_range(a, b) udelay((b)) | |
28 | ||
29 | #define CMN_SSM_BANDGAP (0x21 << 2) | |
30 | #define CMN_SSM_BIAS (0x22 << 2) | |
31 | #define CMN_PLLSM0_PLLEN (0x29 << 2) | |
32 | #define CMN_PLLSM0_PLLPRE (0x2a << 2) | |
33 | #define CMN_PLLSM0_PLLVREF (0x2b << 2) | |
34 | #define CMN_PLLSM0_PLLLOCK (0x2c << 2) | |
35 | #define CMN_PLLSM1_PLLEN (0x31 << 2) | |
36 | #define CMN_PLLSM1_PLLPRE (0x32 << 2) | |
37 | #define CMN_PLLSM1_PLLVREF (0x33 << 2) | |
38 | #define CMN_PLLSM1_PLLLOCK (0x34 << 2) | |
39 | #define CMN_PLLSM1_USER_DEF_CTRL (0x37 << 2) | |
40 | #define CMN_ICAL_OVRD (0xc1 << 2) | |
41 | #define CMN_PLL0_VCOCAL_OVRD (0x83 << 2) | |
42 | #define CMN_PLL0_VCOCAL_INIT (0x84 << 2) | |
43 | #define CMN_PLL0_VCOCAL_ITER (0x85 << 2) | |
44 | #define CMN_PLL0_LOCK_REFCNT_START (0x90 << 2) | |
45 | #define CMN_PLL0_LOCK_PLLCNT_START (0x92 << 2) | |
46 | #define CMN_PLL0_LOCK_PLLCNT_THR (0x93 << 2) | |
47 | #define CMN_PLL0_INTDIV (0x94 << 2) | |
48 | #define CMN_PLL0_FRACDIV (0x95 << 2) | |
49 | #define CMN_PLL0_HIGH_THR (0x96 << 2) | |
50 | #define CMN_PLL0_DSM_DIAG (0x97 << 2) | |
51 | #define CMN_PLL0_SS_CTRL1 (0x98 << 2) | |
52 | #define CMN_PLL0_SS_CTRL2 (0x99 << 2) | |
53 | #define CMN_PLL1_VCOCAL_START (0xa1 << 2) | |
54 | #define CMN_PLL1_VCOCAL_OVRD (0xa3 << 2) | |
55 | #define CMN_PLL1_VCOCAL_INIT (0xa4 << 2) | |
56 | #define CMN_PLL1_VCOCAL_ITER (0xa5 << 2) | |
57 | #define CMN_PLL1_LOCK_REFCNT_START (0xb0 << 2) | |
58 | #define CMN_PLL1_LOCK_PLLCNT_START (0xb2 << 2) | |
59 | #define CMN_PLL1_LOCK_PLLCNT_THR (0xb3 << 2) | |
60 | #define CMN_PLL1_INTDIV (0xb4 << 2) | |
61 | #define CMN_PLL1_FRACDIV (0xb5 << 2) | |
62 | #define CMN_PLL1_HIGH_THR (0xb6 << 2) | |
63 | #define CMN_PLL1_DSM_DIAG (0xb7 << 2) | |
64 | #define CMN_PLL1_SS_CTRL1 (0xb8 << 2) | |
65 | #define CMN_PLL1_SS_CTRL2 (0xb9 << 2) | |
66 | #define CMN_RXCAL_OVRD (0xd1 << 2) | |
67 | ||
68 | #define CMN_TXPUCAL_CTRL (0xe0 << 2) | |
69 | #define CMN_TXPUCAL_OVRD (0xe1 << 2) | |
70 | #define CMN_TXPDCAL_CTRL (0xf0 << 2) | |
71 | #define CMN_TXPDCAL_OVRD (0xf1 << 2) | |
72 | ||
73 | /* For CMN_TXPUCAL_CTRL, CMN_TXPDCAL_CTRL */ | |
74 | #define CMN_TXPXCAL_START BIT(15) | |
75 | #define CMN_TXPXCAL_DONE BIT(14) | |
76 | #define CMN_TXPXCAL_NO_RESPONSE BIT(13) | |
77 | #define CMN_TXPXCAL_CURRENT_RESPONSE BIT(12) | |
78 | ||
79 | #define CMN_TXPU_ADJ_CTRL (0x108 << 2) | |
80 | #define CMN_TXPD_ADJ_CTRL (0x10c << 2) | |
81 | ||
82 | /* | |
83 | * For CMN_TXPUCAL_CTRL, CMN_TXPDCAL_CTRL, | |
84 | * CMN_TXPU_ADJ_CTRL, CMN_TXPDCAL_CTRL | |
85 | * | |
86 | * NOTE: some of these registers are documented to be 2's complement | |
87 | * signed numbers, but then documented to be always positive. Weird. | |
88 | * In such a case, using CMN_CALIB_CODE_POS() avoids the unnecessary | |
89 | * sign extension. | |
90 | */ | |
91 | #define CMN_CALIB_CODE_WIDTH 7 | |
92 | #define CMN_CALIB_CODE_OFFSET 0 | |
93 | #define CMN_CALIB_CODE_MASK GENMASK(CMN_CALIB_CODE_WIDTH, 0) | |
94 | #define CMN_CALIB_CODE(x) \ | |
95 | sign_extend32((x) >> CMN_CALIB_CODE_OFFSET, CMN_CALIB_CODE_WIDTH) | |
96 | ||
97 | #define CMN_CALIB_CODE_POS_MASK GENMASK(CMN_CALIB_CODE_WIDTH - 1, 0) | |
98 | #define CMN_CALIB_CODE_POS(x) \ | |
99 | (((x) >> CMN_CALIB_CODE_OFFSET) & CMN_CALIB_CODE_POS_MASK) | |
100 | ||
101 | #define CMN_DIAG_PLL0_FBH_OVRD (0x1c0 << 2) | |
102 | #define CMN_DIAG_PLL0_FBL_OVRD (0x1c1 << 2) | |
103 | #define CMN_DIAG_PLL0_OVRD (0x1c2 << 2) | |
104 | #define CMN_DIAG_PLL0_V2I_TUNE (0x1c5 << 2) | |
105 | #define CMN_DIAG_PLL0_CP_TUNE (0x1c6 << 2) | |
106 | #define CMN_DIAG_PLL0_LF_PROG (0x1c7 << 2) | |
107 | #define CMN_DIAG_PLL1_FBH_OVRD (0x1d0 << 2) | |
108 | #define CMN_DIAG_PLL1_FBL_OVRD (0x1d1 << 2) | |
109 | #define CMN_DIAG_PLL1_OVRD (0x1d2 << 2) | |
110 | #define CMN_DIAG_PLL1_V2I_TUNE (0x1d5 << 2) | |
111 | #define CMN_DIAG_PLL1_CP_TUNE (0x1d6 << 2) | |
112 | #define CMN_DIAG_PLL1_LF_PROG (0x1d7 << 2) | |
113 | #define CMN_DIAG_PLL1_PTATIS_TUNE1 (0x1d8 << 2) | |
114 | #define CMN_DIAG_PLL1_PTATIS_TUNE2 (0x1d9 << 2) | |
115 | #define CMN_DIAG_PLL1_INCLK_CTRL (0x1da << 2) | |
116 | #define CMN_DIAG_HSCLK_SEL (0x1e0 << 2) | |
117 | ||
118 | #define XCVR_PSM_RCTRL(n) ((0x4001 | ((n) << 9)) << 2) | |
119 | #define XCVR_PSM_CAL_TMR(n) ((0x4002 | ((n) << 9)) << 2) | |
120 | #define XCVR_PSM_A0IN_TMR(n) ((0x4003 | ((n) << 9)) << 2) | |
121 | #define TX_TXCC_CAL_SCLR_MULT(n) ((0x4047 | ((n) << 9)) << 2) | |
122 | #define TX_TXCC_CPOST_MULT_00(n) ((0x404c | ((n) << 9)) << 2) | |
123 | #define TX_TXCC_CPOST_MULT_01(n) ((0x404d | ((n) << 9)) << 2) | |
124 | #define TX_TXCC_CPOST_MULT_10(n) ((0x404e | ((n) << 9)) << 2) | |
125 | #define TX_TXCC_CPOST_MULT_11(n) ((0x404f | ((n) << 9)) << 2) | |
126 | #define TX_TXCC_MGNFS_MULT_000(n) ((0x4050 | ((n) << 9)) << 2) | |
127 | #define TX_TXCC_MGNFS_MULT_001(n) ((0x4051 | ((n) << 9)) << 2) | |
128 | #define TX_TXCC_MGNFS_MULT_010(n) ((0x4052 | ((n) << 9)) << 2) | |
129 | #define TX_TXCC_MGNFS_MULT_011(n) ((0x4053 | ((n) << 9)) << 2) | |
130 | #define TX_TXCC_MGNFS_MULT_100(n) ((0x4054 | ((n) << 9)) << 2) | |
131 | #define TX_TXCC_MGNFS_MULT_101(n) ((0x4055 | ((n) << 9)) << 2) | |
132 | #define TX_TXCC_MGNFS_MULT_110(n) ((0x4056 | ((n) << 9)) << 2) | |
133 | #define TX_TXCC_MGNFS_MULT_111(n) ((0x4057 | ((n) << 9)) << 2) | |
134 | #define TX_TXCC_MGNLS_MULT_000(n) ((0x4058 | ((n) << 9)) << 2) | |
135 | #define TX_TXCC_MGNLS_MULT_001(n) ((0x4059 | ((n) << 9)) << 2) | |
136 | #define TX_TXCC_MGNLS_MULT_010(n) ((0x405a | ((n) << 9)) << 2) | |
137 | #define TX_TXCC_MGNLS_MULT_011(n) ((0x405b | ((n) << 9)) << 2) | |
138 | #define TX_TXCC_MGNLS_MULT_100(n) ((0x405c | ((n) << 9)) << 2) | |
139 | #define TX_TXCC_MGNLS_MULT_101(n) ((0x405d | ((n) << 9)) << 2) | |
140 | #define TX_TXCC_MGNLS_MULT_110(n) ((0x405e | ((n) << 9)) << 2) | |
141 | #define TX_TXCC_MGNLS_MULT_111(n) ((0x405f | ((n) << 9)) << 2) | |
142 | ||
143 | #define XCVR_DIAG_PLLDRC_CTRL(n) ((0x40e0 | ((n) << 9)) << 2) | |
144 | #define XCVR_DIAG_BIDI_CTRL(n) ((0x40e8 | ((n) << 9)) << 2) | |
145 | #define XCVR_DIAG_LANE_FCM_EN_MGN(n) ((0x40f2 | ((n) << 9)) << 2) | |
146 | #define TX_PSC_A0(n) ((0x4100 | ((n) << 9)) << 2) | |
147 | #define TX_PSC_A1(n) ((0x4101 | ((n) << 9)) << 2) | |
148 | #define TX_PSC_A2(n) ((0x4102 | ((n) << 9)) << 2) | |
149 | #define TX_PSC_A3(n) ((0x4103 | ((n) << 9)) << 2) | |
150 | #define TX_RCVDET_CTRL(n) ((0x4120 | ((n) << 9)) << 2) | |
151 | #define TX_RCVDET_EN_TMR(n) ((0x4122 | ((n) << 9)) << 2) | |
152 | #define TX_RCVDET_ST_TMR(n) ((0x4123 | ((n) << 9)) << 2) | |
153 | #define TX_DIAG_TX_DRV(n) ((0x41e1 | ((n) << 9)) << 2) | |
154 | #define TX_DIAG_BGREF_PREDRV_DELAY (0x41e7 << 2) | |
155 | ||
156 | /* Use this for "n" in macros like "_MULT_XXX" to target the aux channel */ | |
157 | #define AUX_CH_LANE 8 | |
158 | ||
159 | #define TX_ANA_CTRL_REG_1 (0x5020 << 2) | |
160 | ||
161 | #define TXDA_DP_AUX_EN BIT(15) | |
162 | #define AUXDA_SE_EN BIT(14) | |
163 | #define TXDA_CAL_LATCH_EN BIT(13) | |
164 | #define AUXDA_POLARITY BIT(12) | |
165 | #define TXDA_DRV_POWER_ISOLATION_EN BIT(11) | |
166 | #define TXDA_DRV_POWER_EN_PH_2_N BIT(10) | |
167 | #define TXDA_DRV_POWER_EN_PH_1_N BIT(9) | |
168 | #define TXDA_BGREF_EN BIT(8) | |
169 | #define TXDA_DRV_LDO_EN BIT(7) | |
170 | #define TXDA_DECAP_EN_DEL BIT(6) | |
171 | #define TXDA_DECAP_EN BIT(5) | |
172 | #define TXDA_UPHY_SUPPLY_EN_DEL BIT(4) | |
173 | #define TXDA_UPHY_SUPPLY_EN BIT(3) | |
174 | #define TXDA_LOW_LEAKAGE_EN BIT(2) | |
175 | #define TXDA_DRV_IDLE_LOWI_EN BIT(1) | |
176 | #define TXDA_DRV_CMN_MODE_EN BIT(0) | |
177 | ||
178 | #define TX_ANA_CTRL_REG_2 (0x5021 << 2) | |
179 | ||
180 | #define AUXDA_DEBOUNCING_CLK BIT(15) | |
181 | #define TXDA_LPBK_RECOVERED_CLK_EN BIT(14) | |
182 | #define TXDA_LPBK_ISI_GEN_EN BIT(13) | |
183 | #define TXDA_LPBK_SERIAL_EN BIT(12) | |
184 | #define TXDA_LPBK_LINE_EN BIT(11) | |
185 | #define TXDA_DRV_LDO_REDC_SINKIQ BIT(10) | |
186 | #define XCVR_DECAP_EN_DEL BIT(9) | |
187 | #define XCVR_DECAP_EN BIT(8) | |
188 | #define TXDA_MPHY_ENABLE_HS_NT BIT(7) | |
189 | #define TXDA_MPHY_SA_MODE BIT(6) | |
190 | #define TXDA_DRV_LDO_RBYR_FB_EN BIT(5) | |
191 | #define TXDA_DRV_RST_PULL_DOWN BIT(4) | |
192 | #define TXDA_DRV_LDO_BG_FB_EN BIT(3) | |
193 | #define TXDA_DRV_LDO_BG_REF_EN BIT(2) | |
194 | #define TXDA_DRV_PREDRV_EN_DEL BIT(1) | |
195 | #define TXDA_DRV_PREDRV_EN BIT(0) | |
196 | ||
197 | #define TXDA_COEFF_CALC_CTRL (0x5022 << 2) | |
198 | ||
199 | #define TX_HIGH_Z BIT(6) | |
200 | #define TX_VMARGIN_OFFSET 3 | |
201 | #define TX_VMARGIN_MASK 0x7 | |
202 | #define LOW_POWER_SWING_EN BIT(2) | |
203 | #define TX_FCM_DRV_MAIN_EN BIT(1) | |
204 | #define TX_FCM_FULL_MARGIN BIT(0) | |
205 | ||
206 | #define TX_DIG_CTRL_REG_2 (0x5024 << 2) | |
207 | ||
208 | #define TX_HIGH_Z_TM_EN BIT(15) | |
209 | #define TX_RESCAL_CODE_OFFSET 0 | |
210 | #define TX_RESCAL_CODE_MASK 0x3f | |
211 | ||
212 | #define TXDA_CYA_AUXDA_CYA (0x5025 << 2) | |
213 | #define TX_ANA_CTRL_REG_3 (0x5026 << 2) | |
214 | #define TX_ANA_CTRL_REG_4 (0x5027 << 2) | |
215 | #define TX_ANA_CTRL_REG_5 (0x5029 << 2) | |
216 | ||
217 | #define RX_PSC_A0(n) ((0x8000 | ((n) << 9)) << 2) | |
218 | #define RX_PSC_A1(n) ((0x8001 | ((n) << 9)) << 2) | |
219 | #define RX_PSC_A2(n) ((0x8002 | ((n) << 9)) << 2) | |
220 | #define RX_PSC_A3(n) ((0x8003 | ((n) << 9)) << 2) | |
221 | #define RX_PSC_CAL(n) ((0x8006 | ((n) << 9)) << 2) | |
222 | #define RX_PSC_RDY(n) ((0x8007 | ((n) << 9)) << 2) | |
223 | #define RX_IQPI_ILL_CAL_OVRD (0x8023 << 2) | |
224 | #define RX_EPI_ILL_CAL_OVRD (0x8033 << 2) | |
225 | #define RX_SDCAL0_OVRD (0x8041 << 2) | |
226 | #define RX_SDCAL1_OVRD (0x8049 << 2) | |
227 | #define RX_SLC_INIT (0x806d << 2) | |
228 | #define RX_SLC_RUN (0x806e << 2) | |
229 | #define RX_CDRLF_CNFG2 (0x8081 << 2) | |
230 | #define RX_SIGDET_HL_FILT_TMR(n) ((0x8090 | ((n) << 9)) << 2) | |
231 | #define RX_SLC_IOP0_OVRD (0x8101 << 2) | |
232 | #define RX_SLC_IOP1_OVRD (0x8105 << 2) | |
233 | #define RX_SLC_QOP0_OVRD (0x8109 << 2) | |
234 | #define RX_SLC_QOP1_OVRD (0x810d << 2) | |
235 | #define RX_SLC_EOP0_OVRD (0x8111 << 2) | |
236 | #define RX_SLC_EOP1_OVRD (0x8115 << 2) | |
237 | #define RX_SLC_ION0_OVRD (0x8119 << 2) | |
238 | #define RX_SLC_ION1_OVRD (0x811d << 2) | |
239 | #define RX_SLC_QON0_OVRD (0x8121 << 2) | |
240 | #define RX_SLC_QON1_OVRD (0x8125 << 2) | |
241 | #define RX_SLC_EON0_OVRD (0x8129 << 2) | |
242 | #define RX_SLC_EON1_OVRD (0x812d << 2) | |
243 | #define RX_SLC_IEP0_OVRD (0x8131 << 2) | |
244 | #define RX_SLC_IEP1_OVRD (0x8135 << 2) | |
245 | #define RX_SLC_QEP0_OVRD (0x8139 << 2) | |
246 | #define RX_SLC_QEP1_OVRD (0x813d << 2) | |
247 | #define RX_SLC_EEP0_OVRD (0x8141 << 2) | |
248 | #define RX_SLC_EEP1_OVRD (0x8145 << 2) | |
249 | #define RX_SLC_IEN0_OVRD (0x8149 << 2) | |
250 | #define RX_SLC_IEN1_OVRD (0x814d << 2) | |
251 | #define RX_SLC_QEN0_OVRD (0x8151 << 2) | |
252 | #define RX_SLC_QEN1_OVRD (0x8155 << 2) | |
253 | #define RX_SLC_EEN0_OVRD (0x8159 << 2) | |
254 | #define RX_SLC_EEN1_OVRD (0x815d << 2) | |
255 | #define RX_REE_CTRL_DATA_MASK(n) ((0x81bb | ((n) << 9)) << 2) | |
256 | #define RX_DIAG_SIGDET_TUNE(n) ((0x81dc | ((n) << 9)) << 2) | |
257 | #define RX_DIAG_SC2C_DELAY (0x81e1 << 2) | |
258 | ||
259 | #define PMA_LANE_CFG (0xc000 << 2) | |
260 | #define PIPE_CMN_CTRL1 (0xc001 << 2) | |
261 | #define PIPE_CMN_CTRL2 (0xc002 << 2) | |
262 | #define PIPE_COM_LOCK_CFG1 (0xc003 << 2) | |
263 | #define PIPE_COM_LOCK_CFG2 (0xc004 << 2) | |
264 | #define PIPE_RCV_DET_INH (0xc005 << 2) | |
265 | #define DP_MODE_CTL (0xc008 << 2) | |
266 | #define DP_CLK_CTL (0xc009 << 2) | |
267 | #define STS (0xc00F << 2) | |
268 | #define PHY_ISO_CMN_CTRL (0xc010 << 2) | |
269 | #define PHY_DP_TX_CTL (0xc408 << 2) | |
270 | #define PMA_CMN_CTRL1 (0xc800 << 2) | |
271 | #define PHY_PMA_ISO_CMN_CTRL (0xc810 << 2) | |
272 | #define PHY_ISOLATION_CTRL (0xc81f << 2) | |
273 | #define PHY_PMA_ISO_XCVR_CTRL(n) ((0xcc11 | ((n) << 6)) << 2) | |
274 | #define PHY_PMA_ISO_LINK_MODE(n) ((0xcc12 | ((n) << 6)) << 2) | |
275 | #define PHY_PMA_ISO_PWRST_CTRL(n) ((0xcc13 | ((n) << 6)) << 2) | |
276 | #define PHY_PMA_ISO_TX_DATA_LO(n) ((0xcc14 | ((n) << 6)) << 2) | |
277 | #define PHY_PMA_ISO_TX_DATA_HI(n) ((0xcc15 | ((n) << 6)) << 2) | |
278 | #define PHY_PMA_ISO_RX_DATA_LO(n) ((0xcc16 | ((n) << 6)) << 2) | |
279 | #define PHY_PMA_ISO_RX_DATA_HI(n) ((0xcc17 | ((n) << 6)) << 2) | |
280 | #define TX_BIST_CTRL(n) ((0x4140 | ((n) << 9)) << 2) | |
281 | #define TX_BIST_UDDWR(n) ((0x4141 | ((n) << 9)) << 2) | |
282 | ||
283 | /* | |
284 | * Selects which PLL clock will be driven on the analog high speed | |
285 | * clock 0: PLL 0 div 1 | |
286 | * clock 1: PLL 1 div 2 | |
287 | */ | |
288 | #define CLK_PLL_CONFIG 0X30 | |
289 | #define CLK_PLL_MASK 0x33 | |
290 | ||
291 | #define CMN_READY BIT(0) | |
292 | ||
293 | #define DP_PLL_CLOCK_ENABLE BIT(2) | |
294 | #define DP_PLL_ENABLE BIT(0) | |
295 | #define DP_PLL_DATA_RATE_RBR ((2 << 12) | (4 << 8)) | |
296 | #define DP_PLL_DATA_RATE_HBR ((2 << 12) | (4 << 8)) | |
297 | #define DP_PLL_DATA_RATE_HBR2 ((1 << 12) | (2 << 8)) | |
298 | ||
299 | #define DP_MODE_A0 BIT(4) | |
300 | #define DP_MODE_A2 BIT(6) | |
301 | #define DP_MODE_ENTER_A0 0xc101 | |
302 | #define DP_MODE_ENTER_A2 0xc104 | |
303 | ||
304 | #define PHY_MODE_SET_TIMEOUT 100000 | |
305 | ||
306 | #define PIN_ASSIGN_C_E 0x51d9 | |
307 | #define PIN_ASSIGN_D_F 0x5100 | |
308 | ||
309 | #define MODE_DISCONNECT 0 | |
310 | #define MODE_UFP_USB BIT(0) | |
311 | #define MODE_DFP_USB BIT(1) | |
312 | #define MODE_DFP_DP BIT(2) | |
313 | ||
314 | struct usb3phy_reg { | |
315 | u32 offset; | |
316 | u32 enable_bit; | |
317 | u32 write_enable; | |
318 | }; | |
319 | ||
320 | /** | |
321 | * struct rockchip_usb3phy_port_cfg: usb3-phy port configuration. | |
322 | * @reg: the base address for usb3-phy config. | |
323 | * @typec_conn_dir: the register of type-c connector direction. | |
324 | * @usb3tousb2_en: the register of type-c force usb2 to usb2 enable. | |
325 | * @external_psm: the register of type-c phy external psm clock. | |
326 | * @pipe_status: the register of type-c phy pipe status. | |
327 | * @usb3_host_disable: the register of type-c usb3 host disable. | |
328 | * @usb3_host_port: the register of type-c usb3 host port. | |
329 | * @uphy_dp_sel: the register of type-c phy DP select control. | |
330 | */ | |
331 | struct rockchip_usb3phy_port_cfg { | |
332 | unsigned int reg; | |
333 | struct usb3phy_reg typec_conn_dir; | |
334 | struct usb3phy_reg usb3tousb2_en; | |
335 | struct usb3phy_reg external_psm; | |
336 | struct usb3phy_reg pipe_status; | |
337 | struct usb3phy_reg usb3_host_disable; | |
338 | struct usb3phy_reg usb3_host_port; | |
339 | struct usb3phy_reg uphy_dp_sel; | |
340 | }; | |
341 | ||
342 | struct rockchip_tcphy { | |
343 | void __iomem *reg_base; | |
344 | void __iomem *grf_base; | |
345 | struct clk clk_core; | |
346 | struct clk clk_ref; | |
347 | struct reset_ctl uphy_rst; | |
348 | struct reset_ctl pipe_rst; | |
349 | struct reset_ctl tcphy_rst; | |
350 | const struct rockchip_usb3phy_port_cfg *port_cfgs; | |
351 | u8 mode; | |
352 | }; | |
353 | ||
354 | struct phy_reg { | |
355 | u16 value; | |
356 | u32 addr; | |
357 | }; | |
358 | ||
359 | static struct phy_reg usb3_pll_cfg[] = { | |
360 | { 0xf0, CMN_PLL0_VCOCAL_INIT }, | |
361 | { 0x18, CMN_PLL0_VCOCAL_ITER }, | |
362 | { 0xd0, CMN_PLL0_INTDIV }, | |
363 | { 0x4a4a, CMN_PLL0_FRACDIV }, | |
364 | { 0x34, CMN_PLL0_HIGH_THR }, | |
365 | { 0x1ee, CMN_PLL0_SS_CTRL1 }, | |
366 | { 0x7f03, CMN_PLL0_SS_CTRL2 }, | |
367 | { 0x20, CMN_PLL0_DSM_DIAG }, | |
368 | { 0, CMN_DIAG_PLL0_OVRD }, | |
369 | { 0, CMN_DIAG_PLL0_FBH_OVRD }, | |
370 | { 0, CMN_DIAG_PLL0_FBL_OVRD }, | |
371 | { 0x7, CMN_DIAG_PLL0_V2I_TUNE }, | |
372 | { 0x45, CMN_DIAG_PLL0_CP_TUNE }, | |
373 | { 0x8, CMN_DIAG_PLL0_LF_PROG }, | |
374 | }; | |
375 | ||
376 | static inline int property_enable(struct rockchip_tcphy *priv, | |
377 | const struct usb3phy_reg *reg, bool en) | |
378 | { | |
379 | u32 mask = 1 << reg->write_enable; | |
380 | u32 val = en << reg->enable_bit; | |
381 | ||
382 | return writel(val | mask, priv->grf_base + reg->offset); | |
383 | } | |
384 | ||
385 | static int rockchip_tcphy_get_mode(struct rockchip_tcphy *priv) | |
386 | { | |
387 | /* TODO: Add proper logic to find DP or USB3 mode */ | |
388 | return MODE_DFP_USB | MODE_UFP_USB; | |
389 | } | |
390 | ||
391 | static void rockchip_tcphy_cfg_24m(struct rockchip_tcphy *priv) | |
392 | { | |
393 | u32 i, rdata; | |
394 | ||
395 | /* | |
396 | * cmn_ref_clk_sel = 3, select the 24Mhz for clk parent | |
397 | * cmn_psm_clk_dig_div = 2, set the clk division to 2 | |
398 | */ | |
399 | writel(0x830, priv->reg_base + PMA_CMN_CTRL1); | |
400 | for (i = 0; i < 4; i++) { | |
401 | /* | |
402 | * The following PHY configuration assumes a 24 MHz reference | |
403 | * clock. | |
404 | */ | |
405 | writel(0x90, priv->reg_base + XCVR_DIAG_LANE_FCM_EN_MGN(i)); | |
406 | writel(0x960, priv->reg_base + TX_RCVDET_EN_TMR(i)); | |
407 | writel(0x30, priv->reg_base + TX_RCVDET_ST_TMR(i)); | |
408 | } | |
409 | ||
410 | rdata = readl(priv->reg_base + CMN_DIAG_HSCLK_SEL); | |
411 | rdata &= ~CLK_PLL_MASK; | |
412 | rdata |= CLK_PLL_CONFIG; | |
413 | writel(rdata, priv->reg_base + CMN_DIAG_HSCLK_SEL); | |
414 | } | |
415 | ||
416 | static void rockchip_tcphy_cfg_usb3_pll(struct rockchip_tcphy *priv) | |
417 | { | |
418 | u32 i; | |
419 | ||
420 | /* load the configuration of PLL0 */ | |
421 | for (i = 0; i < ARRAY_SIZE(usb3_pll_cfg); i++) | |
422 | writel(usb3_pll_cfg[i].value, | |
423 | priv->reg_base + usb3_pll_cfg[i].addr); | |
424 | } | |
425 | ||
426 | static void rockchip_tcphy_tx_usb3_cfg_lane(struct rockchip_tcphy *priv, | |
427 | u32 lane) | |
428 | { | |
429 | writel(0x7799, priv->reg_base + TX_PSC_A0(lane)); | |
430 | writel(0x7798, priv->reg_base + TX_PSC_A1(lane)); | |
431 | writel(0x5098, priv->reg_base + TX_PSC_A2(lane)); | |
432 | writel(0x5098, priv->reg_base + TX_PSC_A3(lane)); | |
433 | writel(0, priv->reg_base + TX_TXCC_MGNFS_MULT_000(lane)); | |
434 | writel(0xbf, priv->reg_base + XCVR_DIAG_BIDI_CTRL(lane)); | |
435 | } | |
436 | ||
437 | static void rockchip_tcphy_rx_usb3_cfg_lane(struct rockchip_tcphy *priv, | |
438 | u32 lane) | |
439 | { | |
440 | writel(0xa6fd, priv->reg_base + RX_PSC_A0(lane)); | |
441 | writel(0xa6fd, priv->reg_base + RX_PSC_A1(lane)); | |
442 | writel(0xa410, priv->reg_base + RX_PSC_A2(lane)); | |
443 | writel(0x2410, priv->reg_base + RX_PSC_A3(lane)); | |
444 | writel(0x23ff, priv->reg_base + RX_PSC_CAL(lane)); | |
445 | writel(0x13, priv->reg_base + RX_SIGDET_HL_FILT_TMR(lane)); | |
446 | writel(0x03e7, priv->reg_base + RX_REE_CTRL_DATA_MASK(lane)); | |
447 | writel(0x1004, priv->reg_base + RX_DIAG_SIGDET_TUNE(lane)); | |
448 | writel(0x2010, priv->reg_base + RX_PSC_RDY(lane)); | |
449 | writel(0xfb, priv->reg_base + XCVR_DIAG_BIDI_CTRL(lane)); | |
450 | } | |
451 | ||
e9e1bd1f | 452 | static int rockchip_tcphy_init(struct phy *phy, struct rockchip_tcphy *priv) |
214de087 JT |
453 | { |
454 | const struct rockchip_usb3phy_port_cfg *cfg = priv->port_cfgs; | |
455 | u32 val; | |
456 | int ret; | |
457 | ||
458 | ret = clk_enable(&priv->clk_core); | |
459 | if (ret) { | |
460 | dev_err(phy->dev, "failed to enable core clk (ret=%d)\n", ret); | |
461 | return ret; | |
462 | } | |
463 | ||
464 | ret = clk_enable(&priv->clk_ref); | |
465 | if (ret) { | |
466 | dev_err(phy->dev, "failed to enable ref clk (ret=%d)\n", ret); | |
467 | goto err_clk_core; | |
468 | } | |
469 | ||
470 | ret = reset_deassert(&priv->tcphy_rst); | |
471 | if (ret) { | |
472 | dev_err(phy->dev, "failed to deassert uphy-tcphy reset (ret=%d)\n", | |
473 | ret); | |
474 | goto err_clk_ref; | |
475 | } | |
476 | ||
477 | property_enable(priv, &cfg->typec_conn_dir, 0); | |
478 | ||
479 | rockchip_tcphy_cfg_24m(priv); | |
480 | ||
481 | rockchip_tcphy_cfg_usb3_pll(priv); | |
482 | ||
483 | rockchip_tcphy_tx_usb3_cfg_lane(priv, 0); | |
484 | rockchip_tcphy_rx_usb3_cfg_lane(priv, 1); | |
485 | ||
486 | ret = reset_deassert(&priv->uphy_rst); | |
487 | if (ret) { | |
488 | dev_err(phy->dev, "failed to deassert uphy rst (ret=%d)\n", | |
489 | ret); | |
490 | goto err_tcphy_rst; | |
491 | } | |
492 | ||
493 | ret = readl_poll_sleep_timeout(priv->reg_base + PMA_CMN_CTRL1, | |
494 | val, val & CMN_READY, 10, | |
495 | PHY_MODE_SET_TIMEOUT); | |
496 | if (ret < 0) { | |
497 | dev_err(phy->dev, "PMA Timeout!\n"); | |
498 | ret = -ETIMEDOUT; | |
499 | goto err_uphy_rst; | |
500 | } | |
501 | ||
502 | ret = reset_deassert(&priv->pipe_rst); | |
503 | if (ret) { | |
504 | dev_err(phy->dev, "failed to deassert pipe rst (ret=%d)\n", | |
505 | ret); | |
506 | goto err_uphy_rst; | |
507 | } | |
508 | ||
509 | return 0; | |
510 | ||
511 | err_uphy_rst: | |
512 | reset_assert(&priv->uphy_rst); | |
513 | err_tcphy_rst: | |
514 | reset_assert(&priv->tcphy_rst); | |
515 | err_clk_ref: | |
516 | clk_disable(&priv->clk_ref); | |
517 | err_clk_core: | |
518 | clk_disable(&priv->clk_core); | |
519 | return ret; | |
520 | } | |
521 | ||
522 | static void rockchip_tcphy_exit(struct rockchip_tcphy *priv) | |
523 | { | |
524 | reset_assert(&priv->tcphy_rst); | |
525 | reset_assert(&priv->uphy_rst); | |
526 | reset_assert(&priv->pipe_rst); | |
527 | clk_disable(&priv->clk_core); | |
528 | clk_disable(&priv->clk_ref); | |
529 | } | |
530 | ||
531 | static int tcphy_cfg_usb3_to_usb2_only(struct rockchip_tcphy *priv, | |
532 | bool value) | |
533 | { | |
534 | const struct rockchip_usb3phy_port_cfg *cfg = priv->port_cfgs; | |
535 | ||
536 | property_enable(priv, &cfg->usb3tousb2_en, value); | |
537 | property_enable(priv, &cfg->usb3_host_disable, value); | |
538 | property_enable(priv, &cfg->usb3_host_port, !value); | |
539 | ||
540 | return 0; | |
541 | } | |
542 | ||
543 | static int rockchip_usb3_phy_power_on(struct phy *phy) | |
544 | { | |
545 | struct udevice *parent = dev_get_parent(phy->dev); | |
546 | struct rockchip_tcphy *priv = dev_get_priv(parent); | |
547 | const struct rockchip_usb3phy_port_cfg *cfg = priv->port_cfgs; | |
548 | const struct usb3phy_reg *reg = &cfg->pipe_status; | |
549 | int timeout, new_mode; | |
550 | u32 val; | |
551 | int ret; | |
552 | ||
553 | new_mode = rockchip_tcphy_get_mode(priv); | |
554 | if (new_mode < 0) { | |
555 | dev_err(phy->dev, "invalid mode %d\n", new_mode); | |
556 | return new_mode; | |
557 | } | |
558 | ||
559 | if (priv->mode == new_mode) | |
560 | return 0; | |
561 | ||
562 | if (priv->mode == MODE_DISCONNECT) { | |
e9e1bd1f | 563 | ret = rockchip_tcphy_init(phy, priv); |
214de087 | 564 | if (ret) { |
e9e1bd1f | 565 | dev_err(phy->dev, "failed to init tcphy (ret=%d)\n", ret); |
214de087 JT |
566 | return ret; |
567 | } | |
568 | } | |
569 | ||
570 | /* wait TCPHY for pipe ready */ | |
571 | for (timeout = 0; timeout < 100; timeout++) { | |
572 | val = readl(priv->grf_base + reg->offset); | |
573 | if (!(val & BIT(reg->enable_bit))) { | |
574 | priv->mode |= new_mode & (MODE_DFP_USB | MODE_UFP_USB); | |
575 | ||
576 | /* enable usb3 host */ | |
577 | tcphy_cfg_usb3_to_usb2_only(priv, false); | |
578 | return 0; | |
579 | } | |
580 | usleep_range(10, 20); | |
581 | } | |
582 | ||
583 | if (priv->mode == MODE_DISCONNECT) | |
584 | rockchip_tcphy_exit(priv); | |
585 | ||
586 | return -ETIMEDOUT; | |
587 | } | |
588 | ||
589 | static int rockchip_usb3_phy_power_off(struct phy *phy) | |
590 | { | |
591 | struct udevice *parent = dev_get_parent(phy->dev); | |
592 | struct rockchip_tcphy *priv = dev_get_priv(parent); | |
593 | ||
594 | tcphy_cfg_usb3_to_usb2_only(priv, false); | |
595 | ||
596 | if (priv->mode == MODE_DISCONNECT) | |
597 | goto exit; | |
598 | ||
599 | priv->mode &= ~(MODE_UFP_USB | MODE_DFP_USB); | |
600 | if (priv->mode == MODE_DISCONNECT) | |
601 | rockchip_tcphy_exit(priv); | |
602 | ||
603 | exit: | |
604 | return 0; | |
605 | } | |
606 | ||
607 | static struct phy_ops rockchip_tcphy_usb3_ops = { | |
608 | .power_on = rockchip_usb3_phy_power_on, | |
609 | .power_off = rockchip_usb3_phy_power_off, | |
610 | }; | |
611 | ||
612 | static void rockchip_tcphy_pre_init(struct udevice *dev) | |
613 | { | |
614 | struct rockchip_tcphy *priv = dev_get_priv(dev); | |
615 | const struct rockchip_usb3phy_port_cfg *cfg = priv->port_cfgs; | |
616 | ||
617 | reset_assert(&priv->tcphy_rst); | |
618 | reset_assert(&priv->uphy_rst); | |
619 | reset_assert(&priv->pipe_rst); | |
620 | ||
621 | /* select external psm clock */ | |
622 | property_enable(priv, &cfg->external_psm, 1); | |
623 | property_enable(priv, &cfg->usb3tousb2_en, 0); | |
624 | ||
625 | priv->mode = MODE_DISCONNECT; | |
626 | } | |
627 | ||
628 | static int rockchip_tcphy_parse_dt(struct udevice *dev) | |
629 | { | |
630 | struct rockchip_tcphy *priv = dev_get_priv(dev); | |
631 | int ret; | |
632 | ||
633 | priv->grf_base = syscon_get_first_range(ROCKCHIP_SYSCON_GRF); | |
634 | if (IS_ERR(priv->grf_base)) | |
635 | return PTR_ERR(priv->grf_base); | |
636 | ||
637 | ret = clk_get_by_name(dev, "tcpdcore", &priv->clk_core); | |
638 | if (ret) { | |
639 | dev_err(dev, "failed to get tcpdcore clk (ret=%d)\n", ret); | |
640 | return ret; | |
641 | } | |
642 | ||
643 | ret = clk_get_by_name(dev, "tcpdphy-ref", &priv->clk_ref); | |
644 | if (ret) { | |
645 | dev_err(dev, "failed to get tcpdphy-ref clk (ret=%d)\n", ret); | |
646 | return ret; | |
647 | } | |
648 | ||
649 | ret = reset_get_by_name(dev, "uphy", &priv->uphy_rst); | |
650 | if (ret) { | |
651 | dev_err(dev, "failed to get uphy reset (ret=%d)\n", ret); | |
652 | return ret; | |
653 | } | |
654 | ||
655 | ret = reset_get_by_name(dev, "uphy-pipe", &priv->pipe_rst); | |
656 | if (ret) { | |
657 | dev_err(dev, "failed to get uphy-pipe reset (ret=%d)\n", ret); | |
658 | return ret; | |
659 | } | |
660 | ||
661 | ret = reset_get_by_name(dev, "uphy-tcphy", &priv->tcphy_rst); | |
662 | if (ret) { | |
663 | dev_err(dev, "failed to get uphy-tcphy reset (ret=%d)\n", ret); | |
664 | return ret; | |
665 | } | |
666 | ||
667 | return 0; | |
668 | } | |
669 | ||
670 | static int rockchip_tcphy_probe(struct udevice *dev) | |
671 | { | |
672 | struct rockchip_tcphy *priv = dev_get_priv(dev); | |
673 | const struct rockchip_usb3phy_port_cfg *phy_cfgs; | |
674 | unsigned int reg; | |
675 | int index, ret; | |
676 | ||
a12a73b6 JJ |
677 | priv->reg_base = dev_read_addr_ptr(dev); |
678 | if (!priv->reg_base) | |
679 | return -EINVAL; | |
214de087 JT |
680 | |
681 | ret = dev_read_u32_index(dev, "reg", 1, ®); | |
682 | if (ret) { | |
683 | dev_err(dev, "failed to read reg property (ret = %d)\n", ret); | |
684 | return ret; | |
685 | } | |
686 | ||
687 | phy_cfgs = (const struct rockchip_usb3phy_port_cfg *) | |
688 | dev_get_driver_data(dev); | |
689 | if (!phy_cfgs) | |
690 | return -EINVAL; | |
691 | ||
692 | /* find out a proper config which can be matched with dt. */ | |
693 | index = 0; | |
694 | while (phy_cfgs[index].reg) { | |
695 | if (phy_cfgs[index].reg == reg) { | |
696 | priv->port_cfgs = &phy_cfgs[index]; | |
697 | break; | |
698 | } | |
699 | ||
700 | ++index; | |
701 | } | |
702 | ||
703 | if (!priv->port_cfgs) { | |
704 | dev_err(dev, "failed find proper phy-cfg\n"); | |
705 | return -EINVAL; | |
706 | } | |
707 | ||
708 | ret = rockchip_tcphy_parse_dt(dev); | |
709 | if (ret) | |
710 | return ret; | |
711 | ||
712 | rockchip_tcphy_pre_init(dev); | |
713 | ||
714 | return 0; | |
715 | } | |
716 | ||
717 | static int rockchip_tcphy_bind(struct udevice *dev) | |
718 | { | |
719 | struct udevice *tcphy_dev; | |
720 | ofnode node; | |
721 | const char *name; | |
722 | int ret = 0; | |
723 | ||
724 | dev_for_each_subnode(node, dev) { | |
725 | if (!ofnode_valid(node)) { | |
726 | dev_info(dev, "subnode %s not found\n", dev->name); | |
727 | return -ENXIO; | |
728 | } | |
729 | ||
730 | name = ofnode_get_name(node); | |
731 | dev_dbg(dev, "subnode %s\n", name); | |
732 | ||
733 | if (!strcasecmp(name, "dp-port")) { | |
734 | dev_dbg(dev, "Warning: dp-port not supported yet!\n"); | |
735 | continue; | |
736 | } else if (!strcasecmp(name, "usb3-port")) { | |
737 | ret = device_bind_driver_to_node(dev, | |
738 | "rockchip_tcphy_usb3_port", | |
739 | name, node, &tcphy_dev); | |
740 | if (ret) { | |
741 | dev_err(dev, | |
742 | "'%s' cannot bind 'rockchip_tcphy_usb3_port'\n", | |
743 | name); | |
744 | return ret; | |
745 | } | |
746 | } | |
747 | } | |
748 | ||
749 | return ret; | |
750 | } | |
751 | ||
752 | static const struct rockchip_usb3phy_port_cfg rk3399_typec_phy_cfgs[] = { | |
753 | { | |
754 | .reg = 0xff7c0000, | |
755 | .typec_conn_dir = { 0xe580, 0, 16 }, | |
756 | .usb3tousb2_en = { 0xe580, 3, 19 }, | |
757 | .external_psm = { 0xe588, 14, 30 }, | |
758 | .pipe_status = { 0xe5c0, 0, 0 }, | |
759 | .usb3_host_disable = { 0x2434, 0, 16 }, | |
760 | .usb3_host_port = { 0x2434, 12, 28 }, | |
761 | .uphy_dp_sel = { 0x6268, 19, 19 }, | |
762 | }, | |
763 | { | |
764 | .reg = 0xff800000, | |
765 | .typec_conn_dir = { 0xe58c, 0, 16 }, | |
766 | .usb3tousb2_en = { 0xe58c, 3, 19 }, | |
767 | .external_psm = { 0xe594, 14, 30 }, | |
768 | .pipe_status = { 0xe5c0, 16, 16 }, | |
769 | .usb3_host_disable = { 0x2444, 0, 16 }, | |
770 | .usb3_host_port = { 0x2444, 12, 28 }, | |
771 | .uphy_dp_sel = { 0x6268, 3, 19 }, | |
772 | }, | |
773 | { /* sentinel */ } | |
774 | }; | |
775 | ||
776 | static const struct udevice_id rockchip_typec_phy_ids[] = { | |
777 | { | |
778 | .compatible = "rockchip,rk3399-typec-phy", | |
779 | .data = (ulong)&rk3399_typec_phy_cfgs, | |
780 | }, | |
781 | { /* sentinel */ } | |
782 | }; | |
783 | ||
784 | U_BOOT_DRIVER(rockchip_tcphy_usb3_port) = { | |
785 | .name = "rockchip_tcphy_usb3_port", | |
786 | .id = UCLASS_PHY, | |
787 | .ops = &rockchip_tcphy_usb3_ops, | |
788 | }; | |
789 | ||
790 | U_BOOT_DRIVER(rockchip_typec_phy) = { | |
791 | .name = "rockchip_typec_phy", | |
792 | .id = UCLASS_PHY, | |
793 | .of_match = rockchip_typec_phy_ids, | |
794 | .probe = rockchip_tcphy_probe, | |
795 | .bind = rockchip_tcphy_bind, | |
41575d8e | 796 | .priv_auto = sizeof(struct rockchip_tcphy), |
214de087 | 797 | }; |