1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd |
4 | * Author: Chris Zhong <zyw@rock-chips.com> |
5 | * Kever Yang <kever.yang@rock-chips.com> |
6 | * |
7 | * The ROCKCHIP Type-C PHY has two PLL clocks. The first PLL clock |
8 | * is used for USB3, the second PLL clock is used for DP. This Type-C PHY has |
9 | * 3 working modes: USB3 only mode, DP only mode, and USB3+DP mode. |
10 | * At USB3 only mode, both PLL clocks need to be initialized, this allows the |
11 | * PHY to switch mode between USB3 and USB3+DP, without disconnecting the USB |
12 | * device. |
13 | * In The DP only mode, only the DP PLL needs to be powered on, and the 4 lanes |
14 | * are all used for DP. |
15 | * |
16 | * This driver gets extcon cable state and property, then decides which mode to |
17 | * select: |
18 | * |
19 | * 1. USB3 only mode: |
20 | * EXTCON_USB or EXTCON_USB_HOST state is true, and |
21 | * EXTCON_PROP_USB_SS property is true. |
22 | * EXTCON_DISP_DP state is false. |
23 | * |
24 | * 2. DP only mode: |
25 | * EXTCON_DISP_DP state is true, and |
26 | * EXTCON_PROP_USB_SS property is false. |
27 | * If EXTCON_USB_HOST state is true, it is DP + USB2 mode, since the USB2 phy |
28 | * is a separate phy, so this case is still DP only mode. |
29 | * |
30 | * 3. USB3+DP mode: |
31 | * EXTCON_USB_HOST and EXTCON_DISP_DP are both true, and |
32 | * EXTCON_PROP_USB_SS property is true. |
33 | * |
34 | * This Type-C PHY driver supports normal and flip orientation. The orientation |
35 | * is reported by the EXTCON_PROP_USB_TYPEC_POLARITY property: true is flip |
36 | * orientation, false is normal orientation. |
37 | */ |
38 | |
39 | #include <linux/clk.h> |
40 | #include <linux/clk-provider.h> |
41 | #include <linux/delay.h> |
42 | #include <linux/extcon.h> |
43 | #include <linux/io.h> |
44 | #include <linux/iopoll.h> |
45 | #include <linux/kernel.h> |
46 | #include <linux/module.h> |
47 | #include <linux/mutex.h> |
48 | #include <linux/of.h> |
49 | #include <linux/of_address.h> |
50 | #include <linux/of_platform.h> |
51 | #include <linux/platform_device.h> |
52 | #include <linux/regmap.h> |
53 | #include <linux/reset.h> |
54 | |
55 | #include <linux/mfd/syscon.h> |
56 | #include <linux/phy/phy.h> |
57 | |
58 | #define CMN_SSM_BANDGAP (0x21 << 2) |
59 | #define CMN_SSM_BIAS (0x22 << 2) |
60 | #define CMN_PLLSM0_PLLEN (0x29 << 2) |
61 | #define CMN_PLLSM0_PLLPRE (0x2a << 2) |
62 | #define CMN_PLLSM0_PLLVREF (0x2b << 2) |
63 | #define CMN_PLLSM0_PLLLOCK (0x2c << 2) |
64 | #define CMN_PLLSM1_PLLEN (0x31 << 2) |
65 | #define CMN_PLLSM1_PLLPRE (0x32 << 2) |
66 | #define CMN_PLLSM1_PLLVREF (0x33 << 2) |
67 | #define CMN_PLLSM1_PLLLOCK (0x34 << 2) |
68 | #define CMN_PLLSM1_USER_DEF_CTRL (0x37 << 2) |
69 | #define CMN_ICAL_OVRD (0xc1 << 2) |
70 | #define CMN_PLL0_VCOCAL_OVRD (0x83 << 2) |
71 | #define CMN_PLL0_VCOCAL_INIT (0x84 << 2) |
72 | #define CMN_PLL0_VCOCAL_ITER (0x85 << 2) |
73 | #define CMN_PLL0_LOCK_REFCNT_START (0x90 << 2) |
74 | #define CMN_PLL0_LOCK_PLLCNT_START (0x92 << 2) |
75 | #define CMN_PLL0_LOCK_PLLCNT_THR (0x93 << 2) |
76 | #define CMN_PLL0_INTDIV (0x94 << 2) |
77 | #define CMN_PLL0_FRACDIV (0x95 << 2) |
78 | #define CMN_PLL0_HIGH_THR (0x96 << 2) |
79 | #define CMN_PLL0_DSM_DIAG (0x97 << 2) |
80 | #define CMN_PLL0_SS_CTRL1 (0x98 << 2) |
81 | #define CMN_PLL0_SS_CTRL2 (0x99 << 2) |
82 | #define CMN_PLL1_VCOCAL_START (0xa1 << 2) |
83 | #define CMN_PLL1_VCOCAL_OVRD (0xa3 << 2) |
84 | #define CMN_PLL1_VCOCAL_INIT (0xa4 << 2) |
85 | #define CMN_PLL1_VCOCAL_ITER (0xa5 << 2) |
86 | #define CMN_PLL1_LOCK_REFCNT_START (0xb0 << 2) |
87 | #define CMN_PLL1_LOCK_PLLCNT_START (0xb2 << 2) |
88 | #define CMN_PLL1_LOCK_PLLCNT_THR (0xb3 << 2) |
89 | #define CMN_PLL1_INTDIV (0xb4 << 2) |
90 | #define CMN_PLL1_FRACDIV (0xb5 << 2) |
91 | #define CMN_PLL1_HIGH_THR (0xb6 << 2) |
92 | #define CMN_PLL1_DSM_DIAG (0xb7 << 2) |
93 | #define CMN_PLL1_SS_CTRL1 (0xb8 << 2) |
94 | #define CMN_PLL1_SS_CTRL2 (0xb9 << 2) |
95 | #define CMN_RXCAL_OVRD (0xd1 << 2) |
96 | |
97 | #define CMN_TXPUCAL_CTRL (0xe0 << 2) |
98 | #define CMN_TXPUCAL_OVRD (0xe1 << 2) |
99 | #define CMN_TXPDCAL_CTRL (0xf0 << 2) |
100 | #define CMN_TXPDCAL_OVRD (0xf1 << 2) |
101 | |
102 | /* For CMN_TXPUCAL_CTRL, CMN_TXPDCAL_CTRL */ |
103 | #define CMN_TXPXCAL_START BIT(15) |
104 | #define CMN_TXPXCAL_DONE BIT(14) |
105 | #define CMN_TXPXCAL_NO_RESPONSE BIT(13) |
106 | #define CMN_TXPXCAL_CURRENT_RESPONSE BIT(12) |
107 | |
108 | #define CMN_TXPU_ADJ_CTRL (0x108 << 2) |
109 | #define CMN_TXPD_ADJ_CTRL (0x10c << 2) |
110 | |
111 | /* |
112 | * For CMN_TXPUCAL_CTRL, CMN_TXPDCAL_CTRL, |
113 | * CMN_TXPU_ADJ_CTRL, CMN_TXPDCAL_CTRL |
114 | * |
115 | * NOTE: some of these registers are documented to be 2's complement |
116 | * signed numbers, but then documented to be always positive. Weird. |
117 | * In such a case, using CMN_CALIB_CODE_POS() avoids the unnecessary |
118 | * sign extension. |
119 | */ |
120 | #define CMN_CALIB_CODE_WIDTH 7 |
121 | #define CMN_CALIB_CODE_OFFSET 0 |
122 | #define CMN_CALIB_CODE_MASK GENMASK(CMN_CALIB_CODE_WIDTH, 0) |
123 | #define CMN_CALIB_CODE(x) \ |
124 | sign_extend32((x) >> CMN_CALIB_CODE_OFFSET, CMN_CALIB_CODE_WIDTH) |
125 | |
126 | #define CMN_CALIB_CODE_POS_MASK GENMASK(CMN_CALIB_CODE_WIDTH - 1, 0) |
127 | #define CMN_CALIB_CODE_POS(x) \ |
128 | (((x) >> CMN_CALIB_CODE_OFFSET) & CMN_CALIB_CODE_POS_MASK) |
129 | |
130 | #define CMN_DIAG_PLL0_FBH_OVRD (0x1c0 << 2) |
131 | #define CMN_DIAG_PLL0_FBL_OVRD (0x1c1 << 2) |
132 | #define CMN_DIAG_PLL0_OVRD (0x1c2 << 2) |
133 | #define CMN_DIAG_PLL0_V2I_TUNE (0x1c5 << 2) |
134 | #define CMN_DIAG_PLL0_CP_TUNE (0x1c6 << 2) |
135 | #define CMN_DIAG_PLL0_LF_PROG (0x1c7 << 2) |
136 | #define CMN_DIAG_PLL1_FBH_OVRD (0x1d0 << 2) |
137 | #define CMN_DIAG_PLL1_FBL_OVRD (0x1d1 << 2) |
138 | #define CMN_DIAG_PLL1_OVRD (0x1d2 << 2) |
139 | #define CMN_DIAG_PLL1_V2I_TUNE (0x1d5 << 2) |
140 | #define CMN_DIAG_PLL1_CP_TUNE (0x1d6 << 2) |
141 | #define CMN_DIAG_PLL1_LF_PROG (0x1d7 << 2) |
142 | #define CMN_DIAG_PLL1_PTATIS_TUNE1 (0x1d8 << 2) |
143 | #define CMN_DIAG_PLL1_PTATIS_TUNE2 (0x1d9 << 2) |
144 | #define CMN_DIAG_PLL1_INCLK_CTRL (0x1da << 2) |
145 | #define CMN_DIAG_HSCLK_SEL (0x1e0 << 2) |
146 | |
147 | #define XCVR_PSM_RCTRL(n) ((0x4001 | ((n) << 9)) << 2) |
148 | #define XCVR_PSM_CAL_TMR(n) ((0x4002 | ((n) << 9)) << 2) |
149 | #define XCVR_PSM_A0IN_TMR(n) ((0x4003 | ((n) << 9)) << 2) |
150 | #define TX_TXCC_CAL_SCLR_MULT(n) ((0x4047 | ((n) << 9)) << 2) |
151 | #define TX_TXCC_CPOST_MULT_00(n) ((0x404c | ((n) << 9)) << 2) |
152 | #define TX_TXCC_CPOST_MULT_01(n) ((0x404d | ((n) << 9)) << 2) |
153 | #define TX_TXCC_CPOST_MULT_10(n) ((0x404e | ((n) << 9)) << 2) |
154 | #define TX_TXCC_CPOST_MULT_11(n) ((0x404f | ((n) << 9)) << 2) |
155 | #define TX_TXCC_MGNFS_MULT_000(n) ((0x4050 | ((n) << 9)) << 2) |
156 | #define TX_TXCC_MGNFS_MULT_001(n) ((0x4051 | ((n) << 9)) << 2) |
157 | #define TX_TXCC_MGNFS_MULT_010(n) ((0x4052 | ((n) << 9)) << 2) |
158 | #define TX_TXCC_MGNFS_MULT_011(n) ((0x4053 | ((n) << 9)) << 2) |
159 | #define TX_TXCC_MGNFS_MULT_100(n) ((0x4054 | ((n) << 9)) << 2) |
160 | #define TX_TXCC_MGNFS_MULT_101(n) ((0x4055 | ((n) << 9)) << 2) |
161 | #define TX_TXCC_MGNFS_MULT_110(n) ((0x4056 | ((n) << 9)) << 2) |
162 | #define TX_TXCC_MGNFS_MULT_111(n) ((0x4057 | ((n) << 9)) << 2) |
163 | #define TX_TXCC_MGNLS_MULT_000(n) ((0x4058 | ((n) << 9)) << 2) |
164 | #define TX_TXCC_MGNLS_MULT_001(n) ((0x4059 | ((n) << 9)) << 2) |
165 | #define TX_TXCC_MGNLS_MULT_010(n) ((0x405a | ((n) << 9)) << 2) |
166 | #define TX_TXCC_MGNLS_MULT_011(n) ((0x405b | ((n) << 9)) << 2) |
167 | #define TX_TXCC_MGNLS_MULT_100(n) ((0x405c | ((n) << 9)) << 2) |
168 | #define TX_TXCC_MGNLS_MULT_101(n) ((0x405d | ((n) << 9)) << 2) |
169 | #define TX_TXCC_MGNLS_MULT_110(n) ((0x405e | ((n) << 9)) << 2) |
170 | #define TX_TXCC_MGNLS_MULT_111(n) ((0x405f | ((n) << 9)) << 2) |
171 | |
172 | #define XCVR_DIAG_PLLDRC_CTRL(n) ((0x40e0 | ((n) << 9)) << 2) |
173 | #define XCVR_DIAG_BIDI_CTRL(n) ((0x40e8 | ((n) << 9)) << 2) |
174 | #define XCVR_DIAG_LANE_FCM_EN_MGN(n) ((0x40f2 | ((n) << 9)) << 2) |
175 | #define TX_PSC_A0(n) ((0x4100 | ((n) << 9)) << 2) |
176 | #define TX_PSC_A1(n) ((0x4101 | ((n) << 9)) << 2) |
177 | #define TX_PSC_A2(n) ((0x4102 | ((n) << 9)) << 2) |
178 | #define TX_PSC_A3(n) ((0x4103 | ((n) << 9)) << 2) |
179 | #define TX_RCVDET_CTRL(n) ((0x4120 | ((n) << 9)) << 2) |
180 | #define TX_RCVDET_EN_TMR(n) ((0x4122 | ((n) << 9)) << 2) |
181 | #define TX_RCVDET_ST_TMR(n) ((0x4123 | ((n) << 9)) << 2) |
182 | #define TX_DIAG_TX_DRV(n) ((0x41e1 | ((n) << 9)) << 2) |
183 | #define TX_DIAG_BGREF_PREDRV_DELAY (0x41e7 << 2) |
184 | |
185 | /* Use this for "n" in macros like "_MULT_XXX" to target the aux channel */ |
186 | #define AUX_CH_LANE 8 |
187 | |
188 | #define TX_ANA_CTRL_REG_1 (0x5020 << 2) |
189 | |
190 | #define TXDA_DP_AUX_EN BIT(15) |
191 | #define AUXDA_SE_EN BIT(14) |
192 | #define TXDA_CAL_LATCH_EN BIT(13) |
193 | #define AUXDA_POLARITY BIT(12) |
194 | #define TXDA_DRV_POWER_ISOLATION_EN BIT(11) |
195 | #define TXDA_DRV_POWER_EN_PH_2_N BIT(10) |
196 | #define TXDA_DRV_POWER_EN_PH_1_N BIT(9) |
197 | #define TXDA_BGREF_EN BIT(8) |
198 | #define TXDA_DRV_LDO_EN BIT(7) |
199 | #define TXDA_DECAP_EN_DEL BIT(6) |
200 | #define TXDA_DECAP_EN BIT(5) |
201 | #define TXDA_UPHY_SUPPLY_EN_DEL BIT(4) |
202 | #define TXDA_UPHY_SUPPLY_EN BIT(3) |
203 | #define TXDA_LOW_LEAKAGE_EN BIT(2) |
204 | #define TXDA_DRV_IDLE_LOWI_EN BIT(1) |
205 | #define TXDA_DRV_CMN_MODE_EN BIT(0) |
206 | |
207 | #define TX_ANA_CTRL_REG_2 (0x5021 << 2) |
208 | |
209 | #define AUXDA_DEBOUNCING_CLK BIT(15) |
210 | #define TXDA_LPBK_RECOVERED_CLK_EN BIT(14) |
211 | #define TXDA_LPBK_ISI_GEN_EN BIT(13) |
212 | #define TXDA_LPBK_SERIAL_EN BIT(12) |
213 | #define TXDA_LPBK_LINE_EN BIT(11) |
214 | #define TXDA_DRV_LDO_REDC_SINKIQ BIT(10) |
215 | #define XCVR_DECAP_EN_DEL BIT(9) |
216 | #define XCVR_DECAP_EN BIT(8) |
217 | #define TXDA_MPHY_ENABLE_HS_NT BIT(7) |
218 | #define TXDA_MPHY_SA_MODE BIT(6) |
219 | #define TXDA_DRV_LDO_RBYR_FB_EN BIT(5) |
220 | #define TXDA_DRV_RST_PULL_DOWN BIT(4) |
221 | #define TXDA_DRV_LDO_BG_FB_EN BIT(3) |
222 | #define TXDA_DRV_LDO_BG_REF_EN BIT(2) |
223 | #define TXDA_DRV_PREDRV_EN_DEL BIT(1) |
224 | #define TXDA_DRV_PREDRV_EN BIT(0) |
225 | |
226 | #define TXDA_COEFF_CALC_CTRL (0x5022 << 2) |
227 | |
228 | #define TX_HIGH_Z BIT(6) |
229 | #define TX_VMARGIN_OFFSET 3 |
230 | #define TX_VMARGIN_MASK 0x7 |
231 | #define LOW_POWER_SWING_EN BIT(2) |
232 | #define TX_FCM_DRV_MAIN_EN BIT(1) |
233 | #define TX_FCM_FULL_MARGIN BIT(0) |
234 | |
235 | #define TX_DIG_CTRL_REG_2 (0x5024 << 2) |
236 | |
237 | #define TX_HIGH_Z_TM_EN BIT(15) |
238 | #define TX_RESCAL_CODE_OFFSET 0 |
239 | #define TX_RESCAL_CODE_MASK 0x3f |
240 | |
241 | #define TXDA_CYA_AUXDA_CYA (0x5025 << 2) |
242 | #define TX_ANA_CTRL_REG_3 (0x5026 << 2) |
243 | #define TX_ANA_CTRL_REG_4 (0x5027 << 2) |
244 | #define TX_ANA_CTRL_REG_5 (0x5029 << 2) |
245 | |
246 | #define RX_PSC_A0(n) ((0x8000 | ((n) << 9)) << 2) |
247 | #define RX_PSC_A1(n) ((0x8001 | ((n) << 9)) << 2) |
248 | #define RX_PSC_A2(n) ((0x8002 | ((n) << 9)) << 2) |
249 | #define RX_PSC_A3(n) ((0x8003 | ((n) << 9)) << 2) |
250 | #define RX_PSC_CAL(n) ((0x8006 | ((n) << 9)) << 2) |
251 | #define RX_PSC_RDY(n) ((0x8007 | ((n) << 9)) << 2) |
252 | #define RX_IQPI_ILL_CAL_OVRD (0x8023 << 2) |
253 | #define RX_EPI_ILL_CAL_OVRD (0x8033 << 2) |
254 | #define RX_SDCAL0_OVRD (0x8041 << 2) |
255 | #define RX_SDCAL1_OVRD (0x8049 << 2) |
256 | #define RX_SLC_INIT (0x806d << 2) |
257 | #define RX_SLC_RUN (0x806e << 2) |
258 | #define RX_CDRLF_CNFG2 (0x8081 << 2) |
259 | #define RX_SIGDET_HL_FILT_TMR(n) ((0x8090 | ((n) << 9)) << 2) |
260 | #define RX_SLC_IOP0_OVRD (0x8101 << 2) |
261 | #define RX_SLC_IOP1_OVRD (0x8105 << 2) |
262 | #define RX_SLC_QOP0_OVRD (0x8109 << 2) |
263 | #define RX_SLC_QOP1_OVRD (0x810d << 2) |
264 | #define RX_SLC_EOP0_OVRD (0x8111 << 2) |
265 | #define RX_SLC_EOP1_OVRD (0x8115 << 2) |
266 | #define RX_SLC_ION0_OVRD (0x8119 << 2) |
267 | #define RX_SLC_ION1_OVRD (0x811d << 2) |
268 | #define RX_SLC_QON0_OVRD (0x8121 << 2) |
269 | #define RX_SLC_QON1_OVRD (0x8125 << 2) |
270 | #define RX_SLC_EON0_OVRD (0x8129 << 2) |
271 | #define RX_SLC_EON1_OVRD (0x812d << 2) |
272 | #define RX_SLC_IEP0_OVRD (0x8131 << 2) |
273 | #define RX_SLC_IEP1_OVRD (0x8135 << 2) |
274 | #define RX_SLC_QEP0_OVRD (0x8139 << 2) |
275 | #define RX_SLC_QEP1_OVRD (0x813d << 2) |
276 | #define RX_SLC_EEP0_OVRD (0x8141 << 2) |
277 | #define RX_SLC_EEP1_OVRD (0x8145 << 2) |
278 | #define RX_SLC_IEN0_OVRD (0x8149 << 2) |
279 | #define RX_SLC_IEN1_OVRD (0x814d << 2) |
280 | #define RX_SLC_QEN0_OVRD (0x8151 << 2) |
281 | #define RX_SLC_QEN1_OVRD (0x8155 << 2) |
282 | #define RX_SLC_EEN0_OVRD (0x8159 << 2) |
283 | #define RX_SLC_EEN1_OVRD (0x815d << 2) |
284 | #define RX_REE_CTRL_DATA_MASK(n) ((0x81bb | ((n) << 9)) << 2) |
285 | #define RX_DIAG_SIGDET_TUNE(n) ((0x81dc | ((n) << 9)) << 2) |
286 | #define RX_DIAG_SC2C_DELAY (0x81e1 << 2) |
287 | |
288 | #define PMA_LANE_CFG (0xc000 << 2) |
289 | #define PIPE_CMN_CTRL1 (0xc001 << 2) |
290 | #define PIPE_CMN_CTRL2 (0xc002 << 2) |
291 | #define PIPE_COM_LOCK_CFG1 (0xc003 << 2) |
292 | #define PIPE_COM_LOCK_CFG2 (0xc004 << 2) |
293 | #define PIPE_RCV_DET_INH (0xc005 << 2) |
294 | #define DP_MODE_CTL (0xc008 << 2) |
295 | #define DP_CLK_CTL (0xc009 << 2) |
296 | #define STS (0xc00F << 2) |
297 | #define PHY_ISO_CMN_CTRL (0xc010 << 2) |
298 | #define PHY_DP_TX_CTL (0xc408 << 2) |
299 | #define PMA_CMN_CTRL1 (0xc800 << 2) |
300 | #define PHY_PMA_ISO_CMN_CTRL (0xc810 << 2) |
301 | #define PHY_ISOLATION_CTRL (0xc81f << 2) |
302 | #define PHY_PMA_ISO_XCVR_CTRL(n) ((0xcc11 | ((n) << 6)) << 2) |
303 | #define PHY_PMA_ISO_LINK_MODE(n) ((0xcc12 | ((n) << 6)) << 2) |
304 | #define PHY_PMA_ISO_PWRST_CTRL(n) ((0xcc13 | ((n) << 6)) << 2) |
305 | #define PHY_PMA_ISO_TX_DATA_LO(n) ((0xcc14 | ((n) << 6)) << 2) |
306 | #define PHY_PMA_ISO_TX_DATA_HI(n) ((0xcc15 | ((n) << 6)) << 2) |
307 | #define PHY_PMA_ISO_RX_DATA_LO(n) ((0xcc16 | ((n) << 6)) << 2) |
308 | #define PHY_PMA_ISO_RX_DATA_HI(n) ((0xcc17 | ((n) << 6)) << 2) |
309 | #define TX_BIST_CTRL(n) ((0x4140 | ((n) << 9)) << 2) |
310 | #define TX_BIST_UDDWR(n) ((0x4141 | ((n) << 9)) << 2) |
311 | |
312 | /* |
313 | * Selects which PLL clock will be driven on the analog high speed |
314 | * clock 0: PLL 0 div 1 |
315 | * clock 1: PLL 1 div 2 |
316 | */ |
317 | #define CLK_PLL_CONFIG 0X30 |
318 | #define CLK_PLL_MASK 0x33 |
319 | |
320 | #define CMN_READY BIT(0) |
321 | |
322 | #define DP_PLL_CLOCK_ENABLE BIT(2) |
323 | #define DP_PLL_ENABLE BIT(0) |
324 | #define DP_PLL_DATA_RATE_RBR ((2 << 12) | (4 << 8)) |
325 | #define DP_PLL_DATA_RATE_HBR ((2 << 12) | (4 << 8)) |
326 | #define DP_PLL_DATA_RATE_HBR2 ((1 << 12) | (2 << 8)) |
327 | |
328 | #define DP_MODE_A0 BIT(4) |
329 | #define DP_MODE_A2 BIT(6) |
330 | #define DP_MODE_ENTER_A0 0xc101 |
331 | #define DP_MODE_ENTER_A2 0xc104 |
332 | |
333 | #define PHY_MODE_SET_TIMEOUT 100000 |
334 | |
335 | #define PIN_ASSIGN_C_E 0x51d9 |
336 | #define PIN_ASSIGN_D_F 0x5100 |
337 | |
338 | #define MODE_DISCONNECT 0 |
339 | #define MODE_UFP_USB BIT(0) |
340 | #define MODE_DFP_USB BIT(1) |
341 | #define MODE_DFP_DP BIT(2) |
342 | |
343 | struct usb3phy_reg { |
344 | u32 offset; |
345 | u32 enable_bit; |
346 | u32 write_enable; |
347 | }; |
348 | |
349 | /** |
350 | * struct rockchip_usb3phy_port_cfg - usb3-phy port configuration. |
351 | * @reg: the base address for usb3-phy config. |
352 | * @typec_conn_dir: the register of type-c connector direction. |
353 | * @usb3tousb2_en: the register of type-c force usb2 to usb2 enable. |
354 | * @external_psm: the register of type-c phy external psm clock. |
355 | * @pipe_status: the register of type-c phy pipe status. |
356 | * @usb3_host_disable: the register of type-c usb3 host disable. |
357 | * @usb3_host_port: the register of type-c usb3 host port. |
358 | * @uphy_dp_sel: the register of type-c phy DP select control. |
359 | */ |
360 | struct rockchip_usb3phy_port_cfg { |
361 | unsigned int reg; |
362 | struct usb3phy_reg typec_conn_dir; |
363 | struct usb3phy_reg usb3tousb2_en; |
364 | struct usb3phy_reg external_psm; |
365 | struct usb3phy_reg pipe_status; |
366 | struct usb3phy_reg usb3_host_disable; |
367 | struct usb3phy_reg usb3_host_port; |
368 | struct usb3phy_reg uphy_dp_sel; |
369 | }; |
370 | |
371 | struct rockchip_typec_phy { |
372 | struct device *dev; |
373 | void __iomem *base; |
374 | struct extcon_dev *extcon; |
375 | struct regmap *grf_regs; |
376 | struct clk *clk_core; |
377 | struct clk *clk_ref; |
378 | struct reset_control *uphy_rst; |
379 | struct reset_control *pipe_rst; |
380 | struct reset_control *tcphy_rst; |
381 | const struct rockchip_usb3phy_port_cfg *port_cfgs; |
382 | /* mutex to protect access to individual PHYs */ |
383 | struct mutex lock; |
384 | |
385 | bool flip; |
386 | u8 mode; |
387 | }; |
388 | |
389 | struct phy_reg { |
390 | u16 value; |
391 | u32 addr; |
392 | }; |
393 | |
394 | static struct phy_reg usb3_pll_cfg[] = { |
395 | { 0xf0, CMN_PLL0_VCOCAL_INIT }, |
396 | { 0x18, CMN_PLL0_VCOCAL_ITER }, |
397 | { 0xd0, CMN_PLL0_INTDIV }, |
398 | { 0x4a4a, CMN_PLL0_FRACDIV }, |
399 | { 0x34, CMN_PLL0_HIGH_THR }, |
400 | { 0x1ee, CMN_PLL0_SS_CTRL1 }, |
401 | { 0x7f03, CMN_PLL0_SS_CTRL2 }, |
402 | { 0x20, CMN_PLL0_DSM_DIAG }, |
403 | { 0, CMN_DIAG_PLL0_OVRD }, |
404 | { 0, CMN_DIAG_PLL0_FBH_OVRD }, |
405 | { 0, CMN_DIAG_PLL0_FBL_OVRD }, |
406 | { 0x7, CMN_DIAG_PLL0_V2I_TUNE }, |
407 | { 0x45, CMN_DIAG_PLL0_CP_TUNE }, |
408 | { 0x8, CMN_DIAG_PLL0_LF_PROG }, |
409 | }; |
410 | |
411 | static struct phy_reg dp_pll_cfg[] = { |
412 | { 0xf0, CMN_PLL1_VCOCAL_INIT }, |
413 | { 0x18, CMN_PLL1_VCOCAL_ITER }, |
414 | { 0x30b9, CMN_PLL1_VCOCAL_START }, |
415 | { 0x21c, CMN_PLL1_INTDIV }, |
416 | { 0, CMN_PLL1_FRACDIV }, |
417 | { 0x5, CMN_PLL1_HIGH_THR }, |
418 | { 0x35, CMN_PLL1_SS_CTRL1 }, |
419 | { 0x7f1e, CMN_PLL1_SS_CTRL2 }, |
420 | { 0x20, CMN_PLL1_DSM_DIAG }, |
421 | { 0, CMN_PLLSM1_USER_DEF_CTRL }, |
422 | { 0, CMN_DIAG_PLL1_OVRD }, |
423 | { 0, CMN_DIAG_PLL1_FBH_OVRD }, |
424 | { 0, CMN_DIAG_PLL1_FBL_OVRD }, |
425 | { 0x6, CMN_DIAG_PLL1_V2I_TUNE }, |
426 | { 0x45, CMN_DIAG_PLL1_CP_TUNE }, |
427 | { 0x8, CMN_DIAG_PLL1_LF_PROG }, |
428 | { 0x100, CMN_DIAG_PLL1_PTATIS_TUNE1 }, |
429 | { 0x7, CMN_DIAG_PLL1_PTATIS_TUNE2 }, |
430 | { 0x4, CMN_DIAG_PLL1_INCLK_CTRL }, |
431 | }; |
432 | |
433 | static const struct rockchip_usb3phy_port_cfg rk3399_usb3phy_port_cfgs[] = { |
434 | { |
435 | .reg = 0xff7c0000, |
436 | .typec_conn_dir = { 0xe580, 0, 16 }, |
437 | .usb3tousb2_en = { 0xe580, 3, 19 }, |
438 | .external_psm = { 0xe588, 14, 30 }, |
439 | .pipe_status = { 0xe5c0, 0, 0 }, |
440 | .usb3_host_disable = { 0x2434, 0, 16 }, |
441 | .usb3_host_port = { 0x2434, 12, 28 }, |
442 | .uphy_dp_sel = { 0x6268, 19, 19 }, |
443 | }, |
444 | { |
445 | .reg = 0xff800000, |
446 | .typec_conn_dir = { 0xe58c, 0, 16 }, |
447 | .usb3tousb2_en = { 0xe58c, 3, 19 }, |
448 | .external_psm = { 0xe594, 14, 30 }, |
449 | .pipe_status = { 0xe5c0, 16, 16 }, |
450 | .usb3_host_disable = { 0x2444, 0, 16 }, |
451 | .usb3_host_port = { 0x2444, 12, 28 }, |
452 | .uphy_dp_sel = { 0x6268, 3, 19 }, |
453 | }, |
454 | { /* sentinel */ } |
455 | }; |
456 | |
457 | static void tcphy_cfg_24m(struct rockchip_typec_phy *tcphy) |
458 | { |
459 | u32 i, rdata; |
460 | |
461 | /* |
462 | * cmn_ref_clk_sel = 3, select the 24Mhz for clk parent |
463 | * cmn_psm_clk_dig_div = 2, set the clk division to 2 |
464 | */ |
465 | writel(val: 0x830, addr: tcphy->base + PMA_CMN_CTRL1); |
466 | for (i = 0; i < 4; i++) { |
467 | /* |
468 | * The following PHY configuration assumes a 24 MHz reference |
469 | * clock. |
470 | */ |
471 | writel(val: 0x90, addr: tcphy->base + XCVR_DIAG_LANE_FCM_EN_MGN(i)); |
472 | writel(val: 0x960, addr: tcphy->base + TX_RCVDET_EN_TMR(i)); |
473 | writel(val: 0x30, addr: tcphy->base + TX_RCVDET_ST_TMR(i)); |
474 | } |
475 | |
476 | rdata = readl(addr: tcphy->base + CMN_DIAG_HSCLK_SEL); |
477 | rdata &= ~CLK_PLL_MASK; |
478 | rdata |= CLK_PLL_CONFIG; |
479 | writel(val: rdata, addr: tcphy->base + CMN_DIAG_HSCLK_SEL); |
480 | } |
481 | |
482 | static void tcphy_cfg_usb3_pll(struct rockchip_typec_phy *tcphy) |
483 | { |
484 | u32 i; |
485 | |
486 | /* load the configuration of PLL0 */ |
487 | for (i = 0; i < ARRAY_SIZE(usb3_pll_cfg); i++) |
488 | writel(val: usb3_pll_cfg[i].value, |
489 | addr: tcphy->base + usb3_pll_cfg[i].addr); |
490 | } |
491 | |
492 | static void tcphy_cfg_dp_pll(struct rockchip_typec_phy *tcphy) |
493 | { |
494 | u32 i; |
495 | |
496 | /* set the default mode to RBR */ |
497 | writel(DP_PLL_CLOCK_ENABLE | DP_PLL_ENABLE | DP_PLL_DATA_RATE_RBR, |
498 | addr: tcphy->base + DP_CLK_CTL); |
499 | |
500 | /* load the configuration of PLL1 */ |
501 | for (i = 0; i < ARRAY_SIZE(dp_pll_cfg); i++) |
502 | writel(val: dp_pll_cfg[i].value, addr: tcphy->base + dp_pll_cfg[i].addr); |
503 | } |
504 | |
505 | static void tcphy_tx_usb3_cfg_lane(struct rockchip_typec_phy *tcphy, u32 lane) |
506 | { |
507 | writel(val: 0x7799, addr: tcphy->base + TX_PSC_A0(lane)); |
508 | writel(val: 0x7798, addr: tcphy->base + TX_PSC_A1(lane)); |
509 | writel(val: 0x5098, addr: tcphy->base + TX_PSC_A2(lane)); |
510 | writel(val: 0x5098, addr: tcphy->base + TX_PSC_A3(lane)); |
511 | writel(val: 0, addr: tcphy->base + TX_TXCC_MGNFS_MULT_000(lane)); |
512 | writel(val: 0xbf, addr: tcphy->base + XCVR_DIAG_BIDI_CTRL(lane)); |
513 | } |
514 | |
515 | static void tcphy_rx_usb3_cfg_lane(struct rockchip_typec_phy *tcphy, u32 lane) |
516 | { |
517 | writel(val: 0xa6fd, addr: tcphy->base + RX_PSC_A0(lane)); |
518 | writel(val: 0xa6fd, addr: tcphy->base + RX_PSC_A1(lane)); |
519 | writel(val: 0xa410, addr: tcphy->base + RX_PSC_A2(lane)); |
520 | writel(val: 0x2410, addr: tcphy->base + RX_PSC_A3(lane)); |
521 | writel(val: 0x23ff, addr: tcphy->base + RX_PSC_CAL(lane)); |
522 | writel(val: 0x13, addr: tcphy->base + RX_SIGDET_HL_FILT_TMR(lane)); |
523 | writel(val: 0x03e7, addr: tcphy->base + RX_REE_CTRL_DATA_MASK(lane)); |
524 | writel(val: 0x1004, addr: tcphy->base + RX_DIAG_SIGDET_TUNE(lane)); |
525 | writel(val: 0x2010, addr: tcphy->base + RX_PSC_RDY(lane)); |
526 | writel(val: 0xfb, addr: tcphy->base + XCVR_DIAG_BIDI_CTRL(lane)); |
527 | } |
528 | |
529 | static void tcphy_dp_cfg_lane(struct rockchip_typec_phy *tcphy, u32 lane) |
530 | { |
531 | u16 rdata; |
532 | |
533 | writel(val: 0xbefc, addr: tcphy->base + XCVR_PSM_RCTRL(lane)); |
534 | writel(val: 0x6799, addr: tcphy->base + TX_PSC_A0(lane)); |
535 | writel(val: 0x6798, addr: tcphy->base + TX_PSC_A1(lane)); |
536 | writel(val: 0x98, addr: tcphy->base + TX_PSC_A2(lane)); |
537 | writel(val: 0x98, addr: tcphy->base + TX_PSC_A3(lane)); |
538 | |
539 | writel(val: 0, addr: tcphy->base + TX_TXCC_MGNFS_MULT_000(lane)); |
540 | writel(val: 0, addr: tcphy->base + TX_TXCC_MGNFS_MULT_001(lane)); |
541 | writel(val: 0, addr: tcphy->base + TX_TXCC_MGNFS_MULT_010(lane)); |
542 | writel(val: 0, addr: tcphy->base + TX_TXCC_MGNFS_MULT_011(lane)); |
543 | writel(val: 0, addr: tcphy->base + TX_TXCC_MGNFS_MULT_100(lane)); |
544 | writel(val: 0, addr: tcphy->base + TX_TXCC_MGNFS_MULT_101(lane)); |
545 | writel(val: 0, addr: tcphy->base + TX_TXCC_MGNFS_MULT_110(lane)); |
546 | writel(val: 0, addr: tcphy->base + TX_TXCC_MGNFS_MULT_111(lane)); |
547 | writel(val: 0, addr: tcphy->base + TX_TXCC_CPOST_MULT_10(lane)); |
548 | writel(val: 0, addr: tcphy->base + TX_TXCC_CPOST_MULT_01(lane)); |
549 | writel(val: 0, addr: tcphy->base + TX_TXCC_CPOST_MULT_00(lane)); |
550 | writel(val: 0, addr: tcphy->base + TX_TXCC_CPOST_MULT_11(lane)); |
551 | |
552 | writel(val: 0x128, addr: tcphy->base + TX_TXCC_CAL_SCLR_MULT(lane)); |
553 | writel(val: 0x400, addr: tcphy->base + TX_DIAG_TX_DRV(lane)); |
554 | |
555 | rdata = readl(addr: tcphy->base + XCVR_DIAG_PLLDRC_CTRL(lane)); |
556 | rdata = (rdata & 0x8fff) | 0x6000; |
557 | writel(val: rdata, addr: tcphy->base + XCVR_DIAG_PLLDRC_CTRL(lane)); |
558 | } |
559 | |
560 | static inline int property_enable(struct rockchip_typec_phy *tcphy, |
561 | const struct usb3phy_reg *reg, bool en) |
562 | { |
563 | u32 mask = 1 << reg->write_enable; |
564 | u32 val = en << reg->enable_bit; |
565 | |
566 | return regmap_write(map: tcphy->grf_regs, reg: reg->offset, val: val | mask); |
567 | } |
568 | |
569 | static void tcphy_dp_aux_set_flip(struct rockchip_typec_phy *tcphy) |
570 | { |
571 | u16 tx_ana_ctrl_reg_1; |
572 | |
573 | /* |
574 | * Select the polarity of the xcvr: |
575 | * 1, Reverses the polarity (If TYPEC, Pulls ups aux_p and pull |
576 | * down aux_m) |
577 | * 0, Normal polarity (if TYPEC, pulls up aux_m and pulls down |
578 | * aux_p) |
579 | */ |
580 | tx_ana_ctrl_reg_1 = readl(addr: tcphy->base + TX_ANA_CTRL_REG_1); |
581 | if (!tcphy->flip) |
582 | tx_ana_ctrl_reg_1 |= AUXDA_POLARITY; |
583 | else |
584 | tx_ana_ctrl_reg_1 &= ~AUXDA_POLARITY; |
585 | writel(val: tx_ana_ctrl_reg_1, addr: tcphy->base + TX_ANA_CTRL_REG_1); |
586 | } |
587 | |
588 | static void tcphy_dp_aux_calibration(struct rockchip_typec_phy *tcphy) |
589 | { |
590 | u16 val; |
591 | u16 tx_ana_ctrl_reg_1; |
592 | u16 tx_ana_ctrl_reg_2; |
593 | s32 pu_calib_code, pd_calib_code; |
594 | s32 pu_adj, pd_adj; |
595 | u16 calib; |
596 | |
597 | /* |
598 | * Calculate calibration code as per docs: use an average of the |
599 | * pull down and pull up. Then add in adjustments. |
600 | */ |
601 | val = readl(addr: tcphy->base + CMN_TXPUCAL_CTRL); |
602 | pu_calib_code = CMN_CALIB_CODE_POS(val); |
603 | val = readl(addr: tcphy->base + CMN_TXPDCAL_CTRL); |
604 | pd_calib_code = CMN_CALIB_CODE_POS(val); |
605 | val = readl(addr: tcphy->base + CMN_TXPU_ADJ_CTRL); |
606 | pu_adj = CMN_CALIB_CODE(val); |
607 | val = readl(addr: tcphy->base + CMN_TXPD_ADJ_CTRL); |
608 | pd_adj = CMN_CALIB_CODE(val); |
609 | calib = (pu_calib_code + pd_calib_code) / 2 + pu_adj + pd_adj; |
610 | |
611 | /* disable txda_cal_latch_en for rewrite the calibration values */ |
612 | tx_ana_ctrl_reg_1 = readl(addr: tcphy->base + TX_ANA_CTRL_REG_1); |
613 | tx_ana_ctrl_reg_1 &= ~TXDA_CAL_LATCH_EN; |
614 | writel(val: tx_ana_ctrl_reg_1, addr: tcphy->base + TX_ANA_CTRL_REG_1); |
615 | |
616 | /* write the calibration, then delay 10 ms as sample in docs */ |
617 | val = readl(addr: tcphy->base + TX_DIG_CTRL_REG_2); |
618 | val &= ~(TX_RESCAL_CODE_MASK << TX_RESCAL_CODE_OFFSET); |
619 | val |= calib << TX_RESCAL_CODE_OFFSET; |
620 | writel(val, addr: tcphy->base + TX_DIG_CTRL_REG_2); |
621 | usleep_range(min: 10000, max: 10050); |
622 | |
623 | /* |
624 | * Enable signal for latch that sample and holds calibration values. |
625 | * Activate this signal for 1 clock cycle to sample new calibration |
626 | * values. |
627 | */ |
628 | tx_ana_ctrl_reg_1 |= TXDA_CAL_LATCH_EN; |
629 | writel(val: tx_ana_ctrl_reg_1, addr: tcphy->base + TX_ANA_CTRL_REG_1); |
630 | usleep_range(min: 150, max: 200); |
631 | |
632 | /* set TX Voltage Level and TX Deemphasis to 0 */ |
633 | writel(val: 0, addr: tcphy->base + PHY_DP_TX_CTL); |
634 | |
635 | /* re-enable decap */ |
636 | tx_ana_ctrl_reg_2 = XCVR_DECAP_EN; |
637 | writel(val: tx_ana_ctrl_reg_2, addr: tcphy->base + TX_ANA_CTRL_REG_2); |
638 | udelay(1); |
639 | tx_ana_ctrl_reg_2 |= XCVR_DECAP_EN_DEL; |
640 | writel(val: tx_ana_ctrl_reg_2, addr: tcphy->base + TX_ANA_CTRL_REG_2); |
641 | |
642 | writel(val: 0, addr: tcphy->base + TX_ANA_CTRL_REG_3); |
643 | |
644 | tx_ana_ctrl_reg_1 |= TXDA_UPHY_SUPPLY_EN; |
645 | writel(val: tx_ana_ctrl_reg_1, addr: tcphy->base + TX_ANA_CTRL_REG_1); |
646 | udelay(1); |
647 | tx_ana_ctrl_reg_1 |= TXDA_UPHY_SUPPLY_EN_DEL; |
648 | writel(val: tx_ana_ctrl_reg_1, addr: tcphy->base + TX_ANA_CTRL_REG_1); |
649 | |
650 | writel(val: 0, addr: tcphy->base + TX_ANA_CTRL_REG_5); |
651 | |
652 | /* |
653 | * Programs txda_drv_ldo_prog[15:0], Sets driver LDO |
654 | * voltage 16'h1001 for DP-AUX-TX and RX |
655 | */ |
656 | writel(val: 0x1001, addr: tcphy->base + TX_ANA_CTRL_REG_4); |
657 | |
658 | /* re-enables Bandgap reference for LDO */ |
659 | tx_ana_ctrl_reg_1 |= TXDA_DRV_LDO_EN; |
660 | writel(val: tx_ana_ctrl_reg_1, addr: tcphy->base + TX_ANA_CTRL_REG_1); |
661 | udelay(5); |
662 | tx_ana_ctrl_reg_1 |= TXDA_BGREF_EN; |
663 | writel(val: tx_ana_ctrl_reg_1, addr: tcphy->base + TX_ANA_CTRL_REG_1); |
664 | |
665 | /* |
666 | * re-enables the transmitter pre-driver, driver data selection MUX, |
667 | * and receiver detect circuits. |
668 | */ |
669 | tx_ana_ctrl_reg_2 |= TXDA_DRV_PREDRV_EN; |
670 | writel(val: tx_ana_ctrl_reg_2, addr: tcphy->base + TX_ANA_CTRL_REG_2); |
671 | udelay(1); |
672 | tx_ana_ctrl_reg_2 |= TXDA_DRV_PREDRV_EN_DEL; |
673 | writel(val: tx_ana_ctrl_reg_2, addr: tcphy->base + TX_ANA_CTRL_REG_2); |
674 | |
675 | /* |
676 | * Do all the undocumented magic: |
677 | * - Turn on TXDA_DP_AUX_EN, whatever that is, even though sample |
678 | * never shows this going on. |
679 | * - Turn on TXDA_DECAP_EN (and TXDA_DECAP_EN_DEL) even though |
680 | * docs say for aux it's always 0. |
681 | * - Turn off the LDO and BGREF, which we just spent time turning |
682 | * on above (???). |
683 | * |
684 | * Without this magic, things seem worse. |
685 | */ |
686 | tx_ana_ctrl_reg_1 |= TXDA_DP_AUX_EN; |
687 | tx_ana_ctrl_reg_1 |= TXDA_DECAP_EN; |
688 | tx_ana_ctrl_reg_1 &= ~TXDA_DRV_LDO_EN; |
689 | tx_ana_ctrl_reg_1 &= ~TXDA_BGREF_EN; |
690 | writel(val: tx_ana_ctrl_reg_1, addr: tcphy->base + TX_ANA_CTRL_REG_1); |
691 | udelay(1); |
692 | tx_ana_ctrl_reg_1 |= TXDA_DECAP_EN_DEL; |
693 | writel(val: tx_ana_ctrl_reg_1, addr: tcphy->base + TX_ANA_CTRL_REG_1); |
694 | |
695 | /* |
696 | * Undo the work we did to set the LDO voltage. |
697 | * This doesn't seem to help nor hurt, but it kinda goes with the |
698 | * undocumented magic above. |
699 | */ |
700 | writel(val: 0, addr: tcphy->base + TX_ANA_CTRL_REG_4); |
701 | |
702 | /* Don't set voltage swing to 400 mV peak to peak (differential) */ |
703 | writel(val: 0, addr: tcphy->base + TXDA_COEFF_CALC_CTRL); |
704 | |
705 | /* Init TXDA_CYA_AUXDA_CYA for unknown magic reasons */ |
706 | writel(val: 0, addr: tcphy->base + TXDA_CYA_AUXDA_CYA); |
707 | |
708 | /* |
709 | * More undocumented magic, presumably the goal of which is to |
710 | * make the "auxda_source_aux_oen" be ignored and instead to decide |
711 | * about "high impedance state" based on what software puts in the |
712 | * register TXDA_COEFF_CALC_CTRL (see TX_HIGH_Z). Since we only |
713 | * program that register once and we don't set the bit TX_HIGH_Z, |
714 | * presumably the goal here is that we should never put the analog |
715 | * driver in high impedance state. |
716 | */ |
717 | val = readl(addr: tcphy->base + TX_DIG_CTRL_REG_2); |
718 | val |= TX_HIGH_Z_TM_EN; |
719 | writel(val, addr: tcphy->base + TX_DIG_CTRL_REG_2); |
720 | } |
721 | |
722 | static int tcphy_phy_init(struct rockchip_typec_phy *tcphy, u8 mode) |
723 | { |
724 | const struct rockchip_usb3phy_port_cfg *cfg = tcphy->port_cfgs; |
725 | int ret, i; |
726 | u32 val; |
727 | |
728 | ret = clk_prepare_enable(clk: tcphy->clk_core); |
729 | if (ret) { |
730 | dev_err(tcphy->dev, "Failed to prepare_enable core clock\n" ); |
731 | return ret; |
732 | } |
733 | |
734 | ret = clk_prepare_enable(clk: tcphy->clk_ref); |
735 | if (ret) { |
736 | dev_err(tcphy->dev, "Failed to prepare_enable ref clock\n" ); |
737 | goto err_clk_core; |
738 | } |
739 | |
740 | reset_control_deassert(rstc: tcphy->tcphy_rst); |
741 | |
742 | property_enable(tcphy, reg: &cfg->typec_conn_dir, en: tcphy->flip); |
743 | tcphy_dp_aux_set_flip(tcphy); |
744 | |
745 | tcphy_cfg_24m(tcphy); |
746 | |
747 | if (mode == MODE_DFP_DP) { |
748 | tcphy_cfg_dp_pll(tcphy); |
749 | for (i = 0; i < 4; i++) |
750 | tcphy_dp_cfg_lane(tcphy, lane: i); |
751 | |
752 | writel(PIN_ASSIGN_C_E, addr: tcphy->base + PMA_LANE_CFG); |
753 | } else { |
754 | tcphy_cfg_usb3_pll(tcphy); |
755 | tcphy_cfg_dp_pll(tcphy); |
756 | if (tcphy->flip) { |
757 | tcphy_tx_usb3_cfg_lane(tcphy, lane: 3); |
758 | tcphy_rx_usb3_cfg_lane(tcphy, lane: 2); |
759 | tcphy_dp_cfg_lane(tcphy, lane: 0); |
760 | tcphy_dp_cfg_lane(tcphy, lane: 1); |
761 | } else { |
762 | tcphy_tx_usb3_cfg_lane(tcphy, lane: 0); |
763 | tcphy_rx_usb3_cfg_lane(tcphy, lane: 1); |
764 | tcphy_dp_cfg_lane(tcphy, lane: 2); |
765 | tcphy_dp_cfg_lane(tcphy, lane: 3); |
766 | } |
767 | |
768 | writel(PIN_ASSIGN_D_F, addr: tcphy->base + PMA_LANE_CFG); |
769 | } |
770 | |
771 | writel(DP_MODE_ENTER_A2, addr: tcphy->base + DP_MODE_CTL); |
772 | |
773 | reset_control_deassert(rstc: tcphy->uphy_rst); |
774 | |
775 | ret = readx_poll_timeout(readl, tcphy->base + PMA_CMN_CTRL1, |
776 | val, val & CMN_READY, 10, |
777 | PHY_MODE_SET_TIMEOUT); |
778 | if (ret < 0) { |
779 | dev_err(tcphy->dev, "wait pma ready timeout\n" ); |
780 | ret = -ETIMEDOUT; |
781 | goto err_wait_pma; |
782 | } |
783 | |
784 | reset_control_deassert(rstc: tcphy->pipe_rst); |
785 | |
786 | return 0; |
787 | |
788 | err_wait_pma: |
789 | reset_control_assert(rstc: tcphy->uphy_rst); |
790 | reset_control_assert(rstc: tcphy->tcphy_rst); |
791 | clk_disable_unprepare(clk: tcphy->clk_ref); |
792 | err_clk_core: |
793 | clk_disable_unprepare(clk: tcphy->clk_core); |
794 | return ret; |
795 | } |
796 | |
797 | static void tcphy_phy_deinit(struct rockchip_typec_phy *tcphy) |
798 | { |
799 | reset_control_assert(rstc: tcphy->tcphy_rst); |
800 | reset_control_assert(rstc: tcphy->uphy_rst); |
801 | reset_control_assert(rstc: tcphy->pipe_rst); |
802 | clk_disable_unprepare(clk: tcphy->clk_core); |
803 | clk_disable_unprepare(clk: tcphy->clk_ref); |
804 | } |
805 | |
806 | static int tcphy_get_mode(struct rockchip_typec_phy *tcphy) |
807 | { |
808 | struct extcon_dev *edev = tcphy->extcon; |
809 | union extcon_property_value property; |
810 | unsigned int id; |
811 | u8 mode; |
812 | int ret, ufp, dp; |
813 | |
814 | if (!edev) |
815 | return MODE_DFP_USB; |
816 | |
817 | ufp = extcon_get_state(edev, EXTCON_USB); |
818 | dp = extcon_get_state(edev, EXTCON_DISP_DP); |
819 | |
820 | mode = MODE_DFP_USB; |
821 | id = EXTCON_USB_HOST; |
822 | |
823 | if (ufp > 0) { |
824 | mode = MODE_UFP_USB; |
825 | id = EXTCON_USB; |
826 | } else if (dp > 0) { |
827 | mode = MODE_DFP_DP; |
828 | id = EXTCON_DISP_DP; |
829 | |
830 | ret = extcon_get_property(edev, id, EXTCON_PROP_USB_SS, |
831 | prop_val: &property); |
832 | if (ret) { |
833 | dev_err(tcphy->dev, "get superspeed property failed\n" ); |
834 | return ret; |
835 | } |
836 | |
837 | if (property.intval) |
838 | mode |= MODE_DFP_USB; |
839 | } |
840 | |
841 | ret = extcon_get_property(edev, id, EXTCON_PROP_USB_TYPEC_POLARITY, |
842 | prop_val: &property); |
843 | if (ret) { |
844 | dev_err(tcphy->dev, "get polarity property failed\n" ); |
845 | return ret; |
846 | } |
847 | |
848 | tcphy->flip = property.intval ? 1 : 0; |
849 | |
850 | return mode; |
851 | } |
852 | |
853 | static int tcphy_cfg_usb3_to_usb2_only(struct rockchip_typec_phy *tcphy, |
854 | bool value) |
855 | { |
856 | const struct rockchip_usb3phy_port_cfg *cfg = tcphy->port_cfgs; |
857 | |
858 | property_enable(tcphy, reg: &cfg->usb3tousb2_en, en: value); |
859 | property_enable(tcphy, reg: &cfg->usb3_host_disable, en: value); |
860 | property_enable(tcphy, reg: &cfg->usb3_host_port, en: !value); |
861 | |
862 | return 0; |
863 | } |
864 | |
865 | static int rockchip_usb3_phy_power_on(struct phy *phy) |
866 | { |
867 | struct rockchip_typec_phy *tcphy = phy_get_drvdata(phy); |
868 | const struct rockchip_usb3phy_port_cfg *cfg = tcphy->port_cfgs; |
869 | const struct usb3phy_reg *reg = &cfg->pipe_status; |
870 | int timeout, new_mode, ret = 0; |
871 | u32 val; |
872 | |
873 | mutex_lock(&tcphy->lock); |
874 | |
875 | new_mode = tcphy_get_mode(tcphy); |
876 | if (new_mode < 0) { |
877 | ret = new_mode; |
878 | goto unlock_ret; |
879 | } |
880 | |
881 | /* DP-only mode; fall back to USB2 */ |
882 | if (!(new_mode & (MODE_DFP_USB | MODE_UFP_USB))) { |
883 | tcphy_cfg_usb3_to_usb2_only(tcphy, value: true); |
884 | goto unlock_ret; |
885 | } |
886 | |
887 | if (tcphy->mode == new_mode) |
888 | goto unlock_ret; |
889 | |
890 | if (tcphy->mode == MODE_DISCONNECT) { |
891 | ret = tcphy_phy_init(tcphy, mode: new_mode); |
892 | if (ret) |
893 | goto unlock_ret; |
894 | } |
895 | |
896 | /* wait TCPHY for pipe ready */ |
897 | for (timeout = 0; timeout < 100; timeout++) { |
898 | regmap_read(map: tcphy->grf_regs, reg: reg->offset, val: &val); |
899 | if (!(val & BIT(reg->enable_bit))) { |
900 | tcphy->mode |= new_mode & (MODE_DFP_USB | MODE_UFP_USB); |
901 | |
902 | /* enable usb3 host */ |
903 | tcphy_cfg_usb3_to_usb2_only(tcphy, value: false); |
904 | goto unlock_ret; |
905 | } |
906 | usleep_range(min: 10, max: 20); |
907 | } |
908 | |
909 | if (tcphy->mode == MODE_DISCONNECT) |
910 | tcphy_phy_deinit(tcphy); |
911 | |
912 | ret = -ETIMEDOUT; |
913 | |
914 | unlock_ret: |
915 | mutex_unlock(lock: &tcphy->lock); |
916 | return ret; |
917 | } |
918 | |
919 | static int rockchip_usb3_phy_power_off(struct phy *phy) |
920 | { |
921 | struct rockchip_typec_phy *tcphy = phy_get_drvdata(phy); |
922 | |
923 | mutex_lock(&tcphy->lock); |
924 | tcphy_cfg_usb3_to_usb2_only(tcphy, value: false); |
925 | |
926 | if (tcphy->mode == MODE_DISCONNECT) |
927 | goto unlock; |
928 | |
929 | tcphy->mode &= ~(MODE_UFP_USB | MODE_DFP_USB); |
930 | if (tcphy->mode == MODE_DISCONNECT) |
931 | tcphy_phy_deinit(tcphy); |
932 | |
933 | unlock: |
934 | mutex_unlock(lock: &tcphy->lock); |
935 | return 0; |
936 | } |
937 | |
938 | static const struct phy_ops rockchip_usb3_phy_ops = { |
939 | .power_on = rockchip_usb3_phy_power_on, |
940 | .power_off = rockchip_usb3_phy_power_off, |
941 | .owner = THIS_MODULE, |
942 | }; |
943 | |
944 | static int rockchip_dp_phy_power_on(struct phy *phy) |
945 | { |
946 | struct rockchip_typec_phy *tcphy = phy_get_drvdata(phy); |
947 | const struct rockchip_usb3phy_port_cfg *cfg = tcphy->port_cfgs; |
948 | int new_mode, ret = 0; |
949 | u32 val; |
950 | |
951 | mutex_lock(&tcphy->lock); |
952 | |
953 | new_mode = tcphy_get_mode(tcphy); |
954 | if (new_mode < 0) { |
955 | ret = new_mode; |
956 | goto unlock_ret; |
957 | } |
958 | |
959 | if (!(new_mode & MODE_DFP_DP)) { |
960 | ret = -ENODEV; |
961 | goto unlock_ret; |
962 | } |
963 | |
964 | if (tcphy->mode == new_mode) |
965 | goto unlock_ret; |
966 | |
967 | /* |
968 | * If the PHY has been power on, but the mode is not DP only mode, |
969 | * re-init the PHY for setting all of 4 lanes to DP. |
970 | */ |
971 | if (new_mode == MODE_DFP_DP && tcphy->mode != MODE_DISCONNECT) { |
972 | tcphy_phy_deinit(tcphy); |
973 | ret = tcphy_phy_init(tcphy, mode: new_mode); |
974 | } else if (tcphy->mode == MODE_DISCONNECT) { |
975 | ret = tcphy_phy_init(tcphy, mode: new_mode); |
976 | } |
977 | if (ret) |
978 | goto unlock_ret; |
979 | |
980 | property_enable(tcphy, reg: &cfg->uphy_dp_sel, en: 1); |
981 | |
982 | ret = readx_poll_timeout(readl, tcphy->base + DP_MODE_CTL, |
983 | val, val & DP_MODE_A2, 1000, |
984 | PHY_MODE_SET_TIMEOUT); |
985 | if (ret < 0) { |
986 | dev_err(tcphy->dev, "failed to wait TCPHY enter A2\n" ); |
987 | goto power_on_finish; |
988 | } |
989 | |
990 | tcphy_dp_aux_calibration(tcphy); |
991 | |
992 | writel(DP_MODE_ENTER_A0, addr: tcphy->base + DP_MODE_CTL); |
993 | |
994 | ret = readx_poll_timeout(readl, tcphy->base + DP_MODE_CTL, |
995 | val, val & DP_MODE_A0, 1000, |
996 | PHY_MODE_SET_TIMEOUT); |
997 | if (ret < 0) { |
998 | writel(DP_MODE_ENTER_A2, addr: tcphy->base + DP_MODE_CTL); |
999 | dev_err(tcphy->dev, "failed to wait TCPHY enter A0\n" ); |
1000 | goto power_on_finish; |
1001 | } |
1002 | |
1003 | tcphy->mode |= MODE_DFP_DP; |
1004 | |
1005 | power_on_finish: |
1006 | if (tcphy->mode == MODE_DISCONNECT) |
1007 | tcphy_phy_deinit(tcphy); |
1008 | unlock_ret: |
1009 | mutex_unlock(lock: &tcphy->lock); |
1010 | return ret; |
1011 | } |
1012 | |
1013 | static int rockchip_dp_phy_power_off(struct phy *phy) |
1014 | { |
1015 | struct rockchip_typec_phy *tcphy = phy_get_drvdata(phy); |
1016 | |
1017 | mutex_lock(&tcphy->lock); |
1018 | |
1019 | if (tcphy->mode == MODE_DISCONNECT) |
1020 | goto unlock; |
1021 | |
1022 | tcphy->mode &= ~MODE_DFP_DP; |
1023 | |
1024 | writel(DP_MODE_ENTER_A2, addr: tcphy->base + DP_MODE_CTL); |
1025 | |
1026 | if (tcphy->mode == MODE_DISCONNECT) |
1027 | tcphy_phy_deinit(tcphy); |
1028 | |
1029 | unlock: |
1030 | mutex_unlock(lock: &tcphy->lock); |
1031 | return 0; |
1032 | } |
1033 | |
1034 | static const struct phy_ops rockchip_dp_phy_ops = { |
1035 | .power_on = rockchip_dp_phy_power_on, |
1036 | .power_off = rockchip_dp_phy_power_off, |
1037 | .owner = THIS_MODULE, |
1038 | }; |
1039 | |
1040 | static int tcphy_parse_dt(struct rockchip_typec_phy *tcphy, |
1041 | struct device *dev) |
1042 | { |
1043 | tcphy->grf_regs = syscon_regmap_lookup_by_phandle(np: dev->of_node, |
1044 | property: "rockchip,grf" ); |
1045 | if (IS_ERR(ptr: tcphy->grf_regs)) { |
1046 | dev_err(dev, "could not find grf dt node\n" ); |
1047 | return PTR_ERR(ptr: tcphy->grf_regs); |
1048 | } |
1049 | |
1050 | tcphy->clk_core = devm_clk_get(dev, id: "tcpdcore" ); |
1051 | if (IS_ERR(ptr: tcphy->clk_core)) { |
1052 | dev_err(dev, "could not get uphy core clock\n" ); |
1053 | return PTR_ERR(ptr: tcphy->clk_core); |
1054 | } |
1055 | |
1056 | tcphy->clk_ref = devm_clk_get(dev, id: "tcpdphy-ref" ); |
1057 | if (IS_ERR(ptr: tcphy->clk_ref)) { |
1058 | dev_err(dev, "could not get uphy ref clock\n" ); |
1059 | return PTR_ERR(ptr: tcphy->clk_ref); |
1060 | } |
1061 | |
1062 | tcphy->uphy_rst = devm_reset_control_get(dev, id: "uphy" ); |
1063 | if (IS_ERR(ptr: tcphy->uphy_rst)) { |
1064 | dev_err(dev, "no uphy_rst reset control found\n" ); |
1065 | return PTR_ERR(ptr: tcphy->uphy_rst); |
1066 | } |
1067 | |
1068 | tcphy->pipe_rst = devm_reset_control_get(dev, id: "uphy-pipe" ); |
1069 | if (IS_ERR(ptr: tcphy->pipe_rst)) { |
1070 | dev_err(dev, "no pipe_rst reset control found\n" ); |
1071 | return PTR_ERR(ptr: tcphy->pipe_rst); |
1072 | } |
1073 | |
1074 | tcphy->tcphy_rst = devm_reset_control_get(dev, id: "uphy-tcphy" ); |
1075 | if (IS_ERR(ptr: tcphy->tcphy_rst)) { |
1076 | dev_err(dev, "no tcphy_rst reset control found\n" ); |
1077 | return PTR_ERR(ptr: tcphy->tcphy_rst); |
1078 | } |
1079 | |
1080 | return 0; |
1081 | } |
1082 | |
1083 | static void typec_phy_pre_init(struct rockchip_typec_phy *tcphy) |
1084 | { |
1085 | const struct rockchip_usb3phy_port_cfg *cfg = tcphy->port_cfgs; |
1086 | |
1087 | reset_control_assert(rstc: tcphy->tcphy_rst); |
1088 | reset_control_assert(rstc: tcphy->uphy_rst); |
1089 | reset_control_assert(rstc: tcphy->pipe_rst); |
1090 | |
1091 | /* select external psm clock */ |
1092 | property_enable(tcphy, reg: &cfg->external_psm, en: 1); |
1093 | property_enable(tcphy, reg: &cfg->usb3tousb2_en, en: 0); |
1094 | |
1095 | tcphy->mode = MODE_DISCONNECT; |
1096 | } |
1097 | |
1098 | static int rockchip_typec_phy_probe(struct platform_device *pdev) |
1099 | { |
1100 | struct device *dev = &pdev->dev; |
1101 | struct device_node *np = dev->of_node; |
1102 | struct device_node *child_np; |
1103 | struct rockchip_typec_phy *tcphy; |
1104 | struct phy_provider *phy_provider; |
1105 | struct resource *res; |
1106 | const struct rockchip_usb3phy_port_cfg *phy_cfgs; |
1107 | int index, ret; |
1108 | |
1109 | tcphy = devm_kzalloc(dev, size: sizeof(*tcphy), GFP_KERNEL); |
1110 | if (!tcphy) |
1111 | return -ENOMEM; |
1112 | |
1113 | phy_cfgs = of_device_get_match_data(dev); |
1114 | if (!phy_cfgs) { |
1115 | dev_err(dev, "phy configs are not assigned!\n" ); |
1116 | return -EINVAL; |
1117 | } |
1118 | |
1119 | tcphy->base = devm_platform_get_and_ioremap_resource(pdev, index: 0, res: &res); |
1120 | if (IS_ERR(ptr: tcphy->base)) |
1121 | return PTR_ERR(ptr: tcphy->base); |
1122 | |
1123 | /* find out a proper config which can be matched with dt. */ |
1124 | index = 0; |
1125 | while (phy_cfgs[index].reg) { |
1126 | if (phy_cfgs[index].reg == res->start) { |
1127 | tcphy->port_cfgs = &phy_cfgs[index]; |
1128 | break; |
1129 | } |
1130 | |
1131 | ++index; |
1132 | } |
1133 | |
1134 | if (!tcphy->port_cfgs) { |
1135 | dev_err(dev, "no phy-config can be matched with %pOFn node\n" , |
1136 | np); |
1137 | return -EINVAL; |
1138 | } |
1139 | |
1140 | ret = tcphy_parse_dt(tcphy, dev); |
1141 | if (ret) |
1142 | return ret; |
1143 | |
1144 | tcphy->dev = dev; |
1145 | platform_set_drvdata(pdev, data: tcphy); |
1146 | mutex_init(&tcphy->lock); |
1147 | |
1148 | typec_phy_pre_init(tcphy); |
1149 | |
1150 | tcphy->extcon = extcon_get_edev_by_phandle(dev, index: 0); |
1151 | if (IS_ERR(ptr: tcphy->extcon)) { |
1152 | if (PTR_ERR(ptr: tcphy->extcon) == -ENODEV) { |
1153 | tcphy->extcon = NULL; |
1154 | } else { |
1155 | if (PTR_ERR(ptr: tcphy->extcon) != -EPROBE_DEFER) |
1156 | dev_err(dev, "Invalid or missing extcon\n" ); |
1157 | return PTR_ERR(ptr: tcphy->extcon); |
1158 | } |
1159 | } |
1160 | |
1161 | pm_runtime_enable(dev); |
1162 | |
1163 | for_each_available_child_of_node(np, child_np) { |
1164 | struct phy *phy; |
1165 | |
1166 | if (of_node_name_eq(np: child_np, name: "dp-port" )) |
1167 | phy = devm_phy_create(dev, node: child_np, |
1168 | ops: &rockchip_dp_phy_ops); |
1169 | else if (of_node_name_eq(np: child_np, name: "usb3-port" )) |
1170 | phy = devm_phy_create(dev, node: child_np, |
1171 | ops: &rockchip_usb3_phy_ops); |
1172 | else |
1173 | continue; |
1174 | |
1175 | if (IS_ERR(ptr: phy)) { |
1176 | dev_err(dev, "failed to create phy: %pOFn\n" , |
1177 | child_np); |
1178 | pm_runtime_disable(dev); |
1179 | of_node_put(node: child_np); |
1180 | return PTR_ERR(ptr: phy); |
1181 | } |
1182 | |
1183 | phy_set_drvdata(phy, data: tcphy); |
1184 | } |
1185 | |
1186 | phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); |
1187 | if (IS_ERR(ptr: phy_provider)) { |
1188 | dev_err(dev, "Failed to register phy provider\n" ); |
1189 | pm_runtime_disable(dev); |
1190 | return PTR_ERR(ptr: phy_provider); |
1191 | } |
1192 | |
1193 | return 0; |
1194 | } |
1195 | |
1196 | static void rockchip_typec_phy_remove(struct platform_device *pdev) |
1197 | { |
1198 | pm_runtime_disable(dev: &pdev->dev); |
1199 | } |
1200 | |
1201 | static const struct of_device_id rockchip_typec_phy_dt_ids[] = { |
1202 | { |
1203 | .compatible = "rockchip,rk3399-typec-phy" , |
1204 | .data = &rk3399_usb3phy_port_cfgs |
1205 | }, |
1206 | { /* sentinel */ } |
1207 | }; |
1208 | |
1209 | MODULE_DEVICE_TABLE(of, rockchip_typec_phy_dt_ids); |
1210 | |
1211 | static struct platform_driver rockchip_typec_phy_driver = { |
1212 | .probe = rockchip_typec_phy_probe, |
1213 | .remove_new = rockchip_typec_phy_remove, |
1214 | .driver = { |
1215 | .name = "rockchip-typec-phy" , |
1216 | .of_match_table = rockchip_typec_phy_dt_ids, |
1217 | }, |
1218 | }; |
1219 | |
1220 | module_platform_driver(rockchip_typec_phy_driver); |
1221 | |
1222 | MODULE_AUTHOR("Chris Zhong <zyw@rock-chips.com>" ); |
1223 | MODULE_AUTHOR("Kever Yang <kever.yang@rock-chips.com>" ); |
1224 | MODULE_DESCRIPTION("Rockchip USB TYPE-C PHY driver" ); |
1225 | MODULE_LICENSE("GPL v2" ); |
1226 | |