1// SPDX-License-Identifier: GPL-2.0
2/*
3 * Copyright (c) 2017, 2020, The Linux Foundation. All rights reserved.
4 * Copyright (c) 2021, Linaro Ltd.
5 */
6
7#include <linux/clk.h>
8#include <linux/clk-provider.h>
9#include <linux/delay.h>
10#include <linux/err.h>
11#include <linux/io.h>
12#include <linux/iopoll.h>
13#include <linux/kernel.h>
14#include <linux/module.h>
15#include <linux/of.h>
16#include <linux/phy/phy.h>
17#include <linux/platform_device.h>
18#include <linux/regulator/consumer.h>
19#include <linux/reset.h>
20#include <linux/slab.h>
21
22#include <dt-bindings/phy/phy.h>
23
24#include "phy-qcom-qmp-dp-phy.h"
25#include "phy-qcom-qmp-qserdes-com-v4.h"
26
27/* EDP_PHY registers */
28#define DP_PHY_CFG 0x0010
29#define DP_PHY_CFG_1 0x0014
30#define DP_PHY_PD_CTL 0x001c
31#define DP_PHY_MODE 0x0020
32
33#define DP_PHY_AUX_CFG0 0x0024
34#define DP_PHY_AUX_CFG1 0x0028
35#define DP_PHY_AUX_CFG2 0x002C
36#define DP_PHY_AUX_CFG3 0x0030
37#define DP_PHY_AUX_CFG4 0x0034
38#define DP_PHY_AUX_CFG5 0x0038
39#define DP_PHY_AUX_CFG6 0x003C
40#define DP_PHY_AUX_CFG7 0x0040
41#define DP_PHY_AUX_CFG8 0x0044
42#define DP_PHY_AUX_CFG9 0x0048
43
44#define DP_PHY_AUX_INTERRUPT_MASK 0x0058
45
46#define DP_PHY_VCO_DIV 0x0074
47#define DP_PHY_TX0_TX1_LANE_CTL 0x007c
48#define DP_PHY_TX2_TX3_LANE_CTL 0x00a0
49
50#define DP_PHY_STATUS 0x00e0
51
52/* LANE_TXn registers */
53#define TXn_CLKBUF_ENABLE 0x0000
54#define TXn_TX_EMP_POST1_LVL 0x0004
55
56#define TXn_TX_DRV_LVL 0x0014
57#define TXn_TX_DRV_LVL_OFFSET 0x0018
58#define TXn_RESET_TSYNC_EN 0x001c
59#define TXn_LDO_CONFIG 0x0084
60#define TXn_TX_BAND 0x0028
61
62#define TXn_RES_CODE_LANE_OFFSET_TX0 0x0044
63#define TXn_RES_CODE_LANE_OFFSET_TX1 0x0048
64
65#define TXn_TRANSCEIVER_BIAS_EN 0x0054
66#define TXn_HIGHZ_DRVR_EN 0x0058
67#define TXn_TX_POL_INV 0x005c
68#define TXn_LANE_MODE_1 0x0064
69
70#define TXn_TRAN_DRVR_EMP_EN 0x0078
71
72struct qcom_edp_cfg {
73 bool is_dp;
74
75 /* DP PHY swing and pre_emphasis tables */
76 const u8 (*swing_hbr_rbr)[4][4];
77 const u8 (*swing_hbr3_hbr2)[4][4];
78 const u8 (*pre_emphasis_hbr_rbr)[4][4];
79 const u8 (*pre_emphasis_hbr3_hbr2)[4][4];
80};
81
82struct qcom_edp {
83 struct device *dev;
84 const struct qcom_edp_cfg *cfg;
85
86 struct phy *phy;
87
88 void __iomem *edp;
89 void __iomem *tx0;
90 void __iomem *tx1;
91 void __iomem *pll;
92
93 struct clk_hw dp_link_hw;
94 struct clk_hw dp_pixel_hw;
95
96 struct phy_configure_opts_dp dp_opts;
97
98 struct clk_bulk_data clks[2];
99 struct regulator_bulk_data supplies[2];
100};
101
102static const u8 dp_swing_hbr_rbr[4][4] = {
103 { 0x08, 0x0f, 0x16, 0x1f },
104 { 0x11, 0x1e, 0x1f, 0xff },
105 { 0x16, 0x1f, 0xff, 0xff },
106 { 0x1f, 0xff, 0xff, 0xff }
107};
108
109static const u8 dp_pre_emp_hbr_rbr[4][4] = {
110 { 0x00, 0x0d, 0x14, 0x1a },
111 { 0x00, 0x0e, 0x15, 0xff },
112 { 0x00, 0x0e, 0xff, 0xff },
113 { 0x03, 0xff, 0xff, 0xff }
114};
115
116static const u8 dp_swing_hbr2_hbr3[4][4] = {
117 { 0x02, 0x12, 0x16, 0x1a },
118 { 0x09, 0x19, 0x1f, 0xff },
119 { 0x10, 0x1f, 0xff, 0xff },
120 { 0x1f, 0xff, 0xff, 0xff }
121};
122
123static const u8 dp_pre_emp_hbr2_hbr3[4][4] = {
124 { 0x00, 0x0c, 0x15, 0x1b },
125 { 0x02, 0x0e, 0x16, 0xff },
126 { 0x02, 0x11, 0xff, 0xff },
127 { 0x04, 0xff, 0xff, 0xff }
128};
129
130static const struct qcom_edp_cfg dp_phy_cfg = {
131 .is_dp = true,
132 .swing_hbr_rbr = &dp_swing_hbr_rbr,
133 .swing_hbr3_hbr2 = &dp_swing_hbr2_hbr3,
134 .pre_emphasis_hbr_rbr = &dp_pre_emp_hbr_rbr,
135 .pre_emphasis_hbr3_hbr2 = &dp_pre_emp_hbr2_hbr3,
136};
137
138static const u8 edp_swing_hbr_rbr[4][4] = {
139 { 0x07, 0x0f, 0x16, 0x1f },
140 { 0x0d, 0x16, 0x1e, 0xff },
141 { 0x11, 0x1b, 0xff, 0xff },
142 { 0x16, 0xff, 0xff, 0xff }
143};
144
145static const u8 edp_pre_emp_hbr_rbr[4][4] = {
146 { 0x05, 0x12, 0x17, 0x1d },
147 { 0x05, 0x11, 0x18, 0xff },
148 { 0x06, 0x11, 0xff, 0xff },
149 { 0x00, 0xff, 0xff, 0xff }
150};
151
152static const u8 edp_swing_hbr2_hbr3[4][4] = {
153 { 0x0b, 0x11, 0x17, 0x1c },
154 { 0x10, 0x19, 0x1f, 0xff },
155 { 0x19, 0x1f, 0xff, 0xff },
156 { 0x1f, 0xff, 0xff, 0xff }
157};
158
159static const u8 edp_pre_emp_hbr2_hbr3[4][4] = {
160 { 0x08, 0x11, 0x17, 0x1b },
161 { 0x00, 0x0c, 0x13, 0xff },
162 { 0x05, 0x10, 0xff, 0xff },
163 { 0x00, 0xff, 0xff, 0xff }
164};
165
166static const struct qcom_edp_cfg edp_phy_cfg = {
167 .is_dp = false,
168 .swing_hbr_rbr = &edp_swing_hbr_rbr,
169 .swing_hbr3_hbr2 = &edp_swing_hbr2_hbr3,
170 .pre_emphasis_hbr_rbr = &edp_pre_emp_hbr_rbr,
171 .pre_emphasis_hbr3_hbr2 = &edp_pre_emp_hbr2_hbr3,
172};
173
174static int qcom_edp_phy_init(struct phy *phy)
175{
176 struct qcom_edp *edp = phy_get_drvdata(phy);
177 const struct qcom_edp_cfg *cfg = edp->cfg;
178 int ret;
179 u8 cfg8;
180
181 ret = regulator_bulk_enable(ARRAY_SIZE(edp->supplies), consumers: edp->supplies);
182 if (ret)
183 return ret;
184
185 ret = clk_bulk_prepare_enable(ARRAY_SIZE(edp->clks), clks: edp->clks);
186 if (ret)
187 goto out_disable_supplies;
188
189 writel(DP_PHY_PD_CTL_PWRDN | DP_PHY_PD_CTL_AUX_PWRDN |
190 DP_PHY_PD_CTL_PLL_PWRDN | DP_PHY_PD_CTL_DP_CLAMP_EN,
191 addr: edp->edp + DP_PHY_PD_CTL);
192
193 /* Turn on BIAS current for PHY/PLL */
194 writel(val: 0x17, addr: edp->pll + QSERDES_V4_COM_BIAS_EN_CLKBUFLR_EN);
195
196 writel(DP_PHY_PD_CTL_PSR_PWRDN, addr: edp->edp + DP_PHY_PD_CTL);
197 msleep(msecs: 20);
198
199 writel(DP_PHY_PD_CTL_PWRDN | DP_PHY_PD_CTL_AUX_PWRDN |
200 DP_PHY_PD_CTL_LANE_0_1_PWRDN | DP_PHY_PD_CTL_LANE_2_3_PWRDN |
201 DP_PHY_PD_CTL_PLL_PWRDN | DP_PHY_PD_CTL_DP_CLAMP_EN,
202 addr: edp->edp + DP_PHY_PD_CTL);
203
204 if (cfg && cfg->is_dp)
205 cfg8 = 0xb7;
206 else
207 cfg8 = 0x37;
208
209 writel(val: 0xfc, addr: edp->edp + DP_PHY_MODE);
210
211 writel(val: 0x00, addr: edp->edp + DP_PHY_AUX_CFG0);
212 writel(val: 0x13, addr: edp->edp + DP_PHY_AUX_CFG1);
213 writel(val: 0x24, addr: edp->edp + DP_PHY_AUX_CFG2);
214 writel(val: 0x00, addr: edp->edp + DP_PHY_AUX_CFG3);
215 writel(val: 0x0a, addr: edp->edp + DP_PHY_AUX_CFG4);
216 writel(val: 0x26, addr: edp->edp + DP_PHY_AUX_CFG5);
217 writel(val: 0x0a, addr: edp->edp + DP_PHY_AUX_CFG6);
218 writel(val: 0x03, addr: edp->edp + DP_PHY_AUX_CFG7);
219 writel(val: cfg8, addr: edp->edp + DP_PHY_AUX_CFG8);
220 writel(val: 0x03, addr: edp->edp + DP_PHY_AUX_CFG9);
221
222 writel(PHY_AUX_STOP_ERR_MASK | PHY_AUX_DEC_ERR_MASK |
223 PHY_AUX_SYNC_ERR_MASK | PHY_AUX_ALIGN_ERR_MASK |
224 PHY_AUX_REQ_ERR_MASK, addr: edp->edp + DP_PHY_AUX_INTERRUPT_MASK);
225
226 msleep(msecs: 20);
227
228 return 0;
229
230out_disable_supplies:
231 regulator_bulk_disable(ARRAY_SIZE(edp->supplies), consumers: edp->supplies);
232
233 return ret;
234}
235
236static int qcom_edp_set_voltages(struct qcom_edp *edp, const struct phy_configure_opts_dp *dp_opts)
237{
238 const struct qcom_edp_cfg *cfg = edp->cfg;
239 unsigned int v_level = 0;
240 unsigned int p_level = 0;
241 u8 ldo_config;
242 u8 swing;
243 u8 emph;
244 int i;
245
246 if (!cfg)
247 return 0;
248
249 for (i = 0; i < dp_opts->lanes; i++) {
250 v_level = max(v_level, dp_opts->voltage[i]);
251 p_level = max(p_level, dp_opts->pre[i]);
252 }
253
254 if (dp_opts->link_rate <= 2700) {
255 swing = (*cfg->swing_hbr_rbr)[v_level][p_level];
256 emph = (*cfg->pre_emphasis_hbr_rbr)[v_level][p_level];
257 } else {
258 swing = (*cfg->swing_hbr3_hbr2)[v_level][p_level];
259 emph = (*cfg->pre_emphasis_hbr3_hbr2)[v_level][p_level];
260 }
261
262 if (swing == 0xff || emph == 0xff)
263 return -EINVAL;
264
265 ldo_config = (cfg && cfg->is_dp) ? 0x1 : 0x0;
266
267 writel(val: ldo_config, addr: edp->tx0 + TXn_LDO_CONFIG);
268 writel(val: swing, addr: edp->tx0 + TXn_TX_DRV_LVL);
269 writel(val: emph, addr: edp->tx0 + TXn_TX_EMP_POST1_LVL);
270
271 writel(val: ldo_config, addr: edp->tx1 + TXn_LDO_CONFIG);
272 writel(val: swing, addr: edp->tx1 + TXn_TX_DRV_LVL);
273 writel(val: emph, addr: edp->tx1 + TXn_TX_EMP_POST1_LVL);
274
275 return 0;
276}
277
278static int qcom_edp_phy_configure(struct phy *phy, union phy_configure_opts *opts)
279{
280 const struct phy_configure_opts_dp *dp_opts = &opts->dp;
281 struct qcom_edp *edp = phy_get_drvdata(phy);
282 int ret = 0;
283
284 memcpy(&edp->dp_opts, dp_opts, sizeof(*dp_opts));
285
286 if (dp_opts->set_voltages)
287 ret = qcom_edp_set_voltages(edp, dp_opts);
288
289 return ret;
290}
291
292static int qcom_edp_configure_ssc(const struct qcom_edp *edp)
293{
294 const struct phy_configure_opts_dp *dp_opts = &edp->dp_opts;
295 u32 step1;
296 u32 step2;
297
298 switch (dp_opts->link_rate) {
299 case 1620:
300 case 2700:
301 case 8100:
302 step1 = 0x45;
303 step2 = 0x06;
304 break;
305
306 case 5400:
307 step1 = 0x5c;
308 step2 = 0x08;
309 break;
310
311 default:
312 /* Other link rates aren't supported */
313 return -EINVAL;
314 }
315
316 writel(val: 0x01, addr: edp->pll + QSERDES_V4_COM_SSC_EN_CENTER);
317 writel(val: 0x00, addr: edp->pll + QSERDES_V4_COM_SSC_ADJ_PER1);
318 writel(val: 0x36, addr: edp->pll + QSERDES_V4_COM_SSC_PER1);
319 writel(val: 0x01, addr: edp->pll + QSERDES_V4_COM_SSC_PER2);
320 writel(val: step1, addr: edp->pll + QSERDES_V4_COM_SSC_STEP_SIZE1_MODE0);
321 writel(val: step2, addr: edp->pll + QSERDES_V4_COM_SSC_STEP_SIZE2_MODE0);
322
323 return 0;
324}
325
326static int qcom_edp_configure_pll(const struct qcom_edp *edp)
327{
328 const struct phy_configure_opts_dp *dp_opts = &edp->dp_opts;
329 u32 div_frac_start2_mode0;
330 u32 div_frac_start3_mode0;
331 u32 dec_start_mode0;
332 u32 lock_cmp1_mode0;
333 u32 lock_cmp2_mode0;
334 u32 hsclk_sel;
335
336 switch (dp_opts->link_rate) {
337 case 1620:
338 hsclk_sel = 0x5;
339 dec_start_mode0 = 0x69;
340 div_frac_start2_mode0 = 0x80;
341 div_frac_start3_mode0 = 0x07;
342 lock_cmp1_mode0 = 0x6f;
343 lock_cmp2_mode0 = 0x08;
344 break;
345
346 case 2700:
347 hsclk_sel = 0x3;
348 dec_start_mode0 = 0x69;
349 div_frac_start2_mode0 = 0x80;
350 div_frac_start3_mode0 = 0x07;
351 lock_cmp1_mode0 = 0x0f;
352 lock_cmp2_mode0 = 0x0e;
353 break;
354
355 case 5400:
356 hsclk_sel = 0x1;
357 dec_start_mode0 = 0x8c;
358 div_frac_start2_mode0 = 0x00;
359 div_frac_start3_mode0 = 0x0a;
360 lock_cmp1_mode0 = 0x1f;
361 lock_cmp2_mode0 = 0x1c;
362 break;
363
364 case 8100:
365 hsclk_sel = 0x0;
366 dec_start_mode0 = 0x69;
367 div_frac_start2_mode0 = 0x80;
368 div_frac_start3_mode0 = 0x07;
369 lock_cmp1_mode0 = 0x2f;
370 lock_cmp2_mode0 = 0x2a;
371 break;
372
373 default:
374 /* Other link rates aren't supported */
375 return -EINVAL;
376 }
377
378 writel(val: 0x01, addr: edp->pll + QSERDES_V4_COM_SVS_MODE_CLK_SEL);
379 writel(val: 0x0b, addr: edp->pll + QSERDES_V4_COM_SYSCLK_EN_SEL);
380 writel(val: 0x02, addr: edp->pll + QSERDES_V4_COM_SYS_CLK_CTRL);
381 writel(val: 0x0c, addr: edp->pll + QSERDES_V4_COM_CLK_ENABLE1);
382 writel(val: 0x06, addr: edp->pll + QSERDES_V4_COM_SYSCLK_BUF_ENABLE);
383 writel(val: 0x30, addr: edp->pll + QSERDES_V4_COM_CLK_SELECT);
384 writel(val: hsclk_sel, addr: edp->pll + QSERDES_V4_COM_HSCLK_SEL);
385 writel(val: 0x0f, addr: edp->pll + QSERDES_V4_COM_PLL_IVCO);
386 writel(val: 0x08, addr: edp->pll + QSERDES_V4_COM_LOCK_CMP_EN);
387 writel(val: 0x36, addr: edp->pll + QSERDES_V4_COM_PLL_CCTRL_MODE0);
388 writel(val: 0x16, addr: edp->pll + QSERDES_V4_COM_PLL_RCTRL_MODE0);
389 writel(val: 0x06, addr: edp->pll + QSERDES_V4_COM_CP_CTRL_MODE0);
390 writel(val: dec_start_mode0, addr: edp->pll + QSERDES_V4_COM_DEC_START_MODE0);
391 writel(val: 0x00, addr: edp->pll + QSERDES_V4_COM_DIV_FRAC_START1_MODE0);
392 writel(val: div_frac_start2_mode0, addr: edp->pll + QSERDES_V4_COM_DIV_FRAC_START2_MODE0);
393 writel(val: div_frac_start3_mode0, addr: edp->pll + QSERDES_V4_COM_DIV_FRAC_START3_MODE0);
394 writel(val: 0x02, addr: edp->pll + QSERDES_V4_COM_CMN_CONFIG);
395 writel(val: 0x3f, addr: edp->pll + QSERDES_V4_COM_INTEGLOOP_GAIN0_MODE0);
396 writel(val: 0x00, addr: edp->pll + QSERDES_V4_COM_INTEGLOOP_GAIN1_MODE0);
397 writel(val: 0x00, addr: edp->pll + QSERDES_V4_COM_VCO_TUNE_MAP);
398 writel(val: lock_cmp1_mode0, addr: edp->pll + QSERDES_V4_COM_LOCK_CMP1_MODE0);
399 writel(val: lock_cmp2_mode0, addr: edp->pll + QSERDES_V4_COM_LOCK_CMP2_MODE0);
400
401 writel(val: 0x0a, addr: edp->pll + QSERDES_V4_COM_BG_TIMER);
402 writel(val: 0x14, addr: edp->pll + QSERDES_V4_COM_CORECLK_DIV_MODE0);
403 writel(val: 0x00, addr: edp->pll + QSERDES_V4_COM_VCO_TUNE_CTRL);
404 writel(val: 0x17, addr: edp->pll + QSERDES_V4_COM_BIAS_EN_CLKBUFLR_EN);
405 writel(val: 0x0f, addr: edp->pll + QSERDES_V4_COM_CORE_CLK_EN);
406 writel(val: 0xa0, addr: edp->pll + QSERDES_V4_COM_VCO_TUNE1_MODE0);
407 writel(val: 0x03, addr: edp->pll + QSERDES_V4_COM_VCO_TUNE2_MODE0);
408
409 return 0;
410}
411
412static int qcom_edp_set_vco_div(const struct qcom_edp *edp, unsigned long *pixel_freq)
413{
414 const struct phy_configure_opts_dp *dp_opts = &edp->dp_opts;
415 u32 vco_div;
416
417 switch (dp_opts->link_rate) {
418 case 1620:
419 vco_div = 0x1;
420 *pixel_freq = 1620000000UL / 2;
421 break;
422
423 case 2700:
424 vco_div = 0x1;
425 *pixel_freq = 2700000000UL / 2;
426 break;
427
428 case 5400:
429 vco_div = 0x2;
430 *pixel_freq = 5400000000UL / 4;
431 break;
432
433 case 8100:
434 vco_div = 0x0;
435 *pixel_freq = 8100000000UL / 6;
436 break;
437
438 default:
439 /* Other link rates aren't supported */
440 return -EINVAL;
441 }
442
443 writel(val: vco_div, addr: edp->edp + DP_PHY_VCO_DIV);
444
445 return 0;
446}
447
448static int qcom_edp_phy_power_on(struct phy *phy)
449{
450 const struct qcom_edp *edp = phy_get_drvdata(phy);
451 const struct qcom_edp_cfg *cfg = edp->cfg;
452 u32 bias0_en, drvr0_en, bias1_en, drvr1_en;
453 unsigned long pixel_freq;
454 u8 ldo_config;
455 int timeout;
456 int ret;
457 u32 val;
458 u8 cfg1;
459
460 writel(DP_PHY_PD_CTL_PWRDN | DP_PHY_PD_CTL_AUX_PWRDN |
461 DP_PHY_PD_CTL_LANE_0_1_PWRDN | DP_PHY_PD_CTL_LANE_2_3_PWRDN |
462 DP_PHY_PD_CTL_PLL_PWRDN | DP_PHY_PD_CTL_DP_CLAMP_EN,
463 addr: edp->edp + DP_PHY_PD_CTL);
464 writel(val: 0xfc, addr: edp->edp + DP_PHY_MODE);
465
466 timeout = readl_poll_timeout(edp->pll + QSERDES_V4_COM_CMN_STATUS,
467 val, val & BIT(7), 5, 200);
468 if (timeout)
469 return timeout;
470
471
472 ldo_config = (cfg && cfg->is_dp) ? 0x1 : 0x0;
473
474 writel(val: ldo_config, addr: edp->tx0 + TXn_LDO_CONFIG);
475 writel(val: ldo_config, addr: edp->tx1 + TXn_LDO_CONFIG);
476 writel(val: 0x00, addr: edp->tx0 + TXn_LANE_MODE_1);
477 writel(val: 0x00, addr: edp->tx1 + TXn_LANE_MODE_1);
478
479 if (edp->dp_opts.ssc) {
480 ret = qcom_edp_configure_ssc(edp);
481 if (ret)
482 return ret;
483 }
484
485 ret = qcom_edp_configure_pll(edp);
486 if (ret)
487 return ret;
488
489 /* TX Lane configuration */
490 writel(val: 0x05, addr: edp->edp + DP_PHY_TX0_TX1_LANE_CTL);
491 writel(val: 0x05, addr: edp->edp + DP_PHY_TX2_TX3_LANE_CTL);
492
493 /* TX-0 register configuration */
494 writel(val: 0x03, addr: edp->tx0 + TXn_TRANSCEIVER_BIAS_EN);
495 writel(val: 0x0f, addr: edp->tx0 + TXn_CLKBUF_ENABLE);
496 writel(val: 0x03, addr: edp->tx0 + TXn_RESET_TSYNC_EN);
497 writel(val: 0x01, addr: edp->tx0 + TXn_TRAN_DRVR_EMP_EN);
498 writel(val: 0x04, addr: edp->tx0 + TXn_TX_BAND);
499
500 /* TX-1 register configuration */
501 writel(val: 0x03, addr: edp->tx1 + TXn_TRANSCEIVER_BIAS_EN);
502 writel(val: 0x0f, addr: edp->tx1 + TXn_CLKBUF_ENABLE);
503 writel(val: 0x03, addr: edp->tx1 + TXn_RESET_TSYNC_EN);
504 writel(val: 0x01, addr: edp->tx1 + TXn_TRAN_DRVR_EMP_EN);
505 writel(val: 0x04, addr: edp->tx1 + TXn_TX_BAND);
506
507 ret = qcom_edp_set_vco_div(edp, pixel_freq: &pixel_freq);
508 if (ret)
509 return ret;
510
511 writel(val: 0x01, addr: edp->edp + DP_PHY_CFG);
512 writel(val: 0x05, addr: edp->edp + DP_PHY_CFG);
513 writel(val: 0x01, addr: edp->edp + DP_PHY_CFG);
514 writel(val: 0x09, addr: edp->edp + DP_PHY_CFG);
515
516 writel(val: 0x20, addr: edp->pll + QSERDES_V4_COM_RESETSM_CNTRL);
517
518 timeout = readl_poll_timeout(edp->pll + QSERDES_V4_COM_C_READY_STATUS,
519 val, val & BIT(0), 500, 10000);
520 if (timeout)
521 return timeout;
522
523 writel(val: 0x19, addr: edp->edp + DP_PHY_CFG);
524 writel(val: 0x1f, addr: edp->tx0 + TXn_HIGHZ_DRVR_EN);
525 writel(val: 0x04, addr: edp->tx0 + TXn_HIGHZ_DRVR_EN);
526 writel(val: 0x00, addr: edp->tx0 + TXn_TX_POL_INV);
527 writel(val: 0x1f, addr: edp->tx1 + TXn_HIGHZ_DRVR_EN);
528 writel(val: 0x04, addr: edp->tx1 + TXn_HIGHZ_DRVR_EN);
529 writel(val: 0x00, addr: edp->tx1 + TXn_TX_POL_INV);
530 writel(val: 0x10, addr: edp->tx0 + TXn_TX_DRV_LVL_OFFSET);
531 writel(val: 0x10, addr: edp->tx1 + TXn_TX_DRV_LVL_OFFSET);
532 writel(val: 0x11, addr: edp->tx0 + TXn_RES_CODE_LANE_OFFSET_TX0);
533 writel(val: 0x11, addr: edp->tx0 + TXn_RES_CODE_LANE_OFFSET_TX1);
534 writel(val: 0x11, addr: edp->tx1 + TXn_RES_CODE_LANE_OFFSET_TX0);
535 writel(val: 0x11, addr: edp->tx1 + TXn_RES_CODE_LANE_OFFSET_TX1);
536
537 writel(val: 0x10, addr: edp->tx0 + TXn_TX_EMP_POST1_LVL);
538 writel(val: 0x10, addr: edp->tx1 + TXn_TX_EMP_POST1_LVL);
539 writel(val: 0x1f, addr: edp->tx0 + TXn_TX_DRV_LVL);
540 writel(val: 0x1f, addr: edp->tx1 + TXn_TX_DRV_LVL);
541
542 if (edp->dp_opts.lanes == 1) {
543 bias0_en = 0x01;
544 bias1_en = 0x00;
545 drvr0_en = 0x06;
546 drvr1_en = 0x07;
547 cfg1 = 0x1;
548 } else if (edp->dp_opts.lanes == 2) {
549 bias0_en = 0x03;
550 bias1_en = 0x00;
551 drvr0_en = 0x04;
552 drvr1_en = 0x07;
553 cfg1 = 0x3;
554 } else {
555 bias0_en = 0x03;
556 bias1_en = 0x03;
557 drvr0_en = 0x04;
558 drvr1_en = 0x04;
559 cfg1 = 0xf;
560 }
561
562 writel(val: drvr0_en, addr: edp->tx0 + TXn_HIGHZ_DRVR_EN);
563 writel(val: bias0_en, addr: edp->tx0 + TXn_TRANSCEIVER_BIAS_EN);
564 writel(val: drvr1_en, addr: edp->tx1 + TXn_HIGHZ_DRVR_EN);
565 writel(val: bias1_en, addr: edp->tx1 + TXn_TRANSCEIVER_BIAS_EN);
566 writel(val: cfg1, addr: edp->edp + DP_PHY_CFG_1);
567
568 writel(val: 0x18, addr: edp->edp + DP_PHY_CFG);
569 usleep_range(min: 100, max: 1000);
570
571 writel(val: 0x19, addr: edp->edp + DP_PHY_CFG);
572
573 ret = readl_poll_timeout(edp->edp + DP_PHY_STATUS,
574 val, val & BIT(1), 500, 10000);
575 if (ret)
576 return ret;
577
578 clk_set_rate(clk: edp->dp_link_hw.clk, rate: edp->dp_opts.link_rate * 100000);
579 clk_set_rate(clk: edp->dp_pixel_hw.clk, rate: pixel_freq);
580
581 return 0;
582}
583
584static int qcom_edp_phy_power_off(struct phy *phy)
585{
586 const struct qcom_edp *edp = phy_get_drvdata(phy);
587
588 writel(DP_PHY_PD_CTL_PSR_PWRDN, addr: edp->edp + DP_PHY_PD_CTL);
589
590 return 0;
591}
592
593static int qcom_edp_phy_exit(struct phy *phy)
594{
595 struct qcom_edp *edp = phy_get_drvdata(phy);
596
597 clk_bulk_disable_unprepare(ARRAY_SIZE(edp->clks), clks: edp->clks);
598 regulator_bulk_disable(ARRAY_SIZE(edp->supplies), consumers: edp->supplies);
599
600 return 0;
601}
602
603static const struct phy_ops qcom_edp_ops = {
604 .init = qcom_edp_phy_init,
605 .configure = qcom_edp_phy_configure,
606 .power_on = qcom_edp_phy_power_on,
607 .power_off = qcom_edp_phy_power_off,
608 .exit = qcom_edp_phy_exit,
609 .owner = THIS_MODULE,
610};
611
612/*
613 * Embedded Display Port PLL driver block diagram for branch clocks
614 *
615 * +------------------------------+
616 * | EDP_VCO_CLK |
617 * | |
618 * | +-------------------+ |
619 * | | (EDP PLL/VCO) | |
620 * | +---------+---------+ |
621 * | v |
622 * | +----------+-----------+ |
623 * | | hsclk_divsel_clk_src | |
624 * | +----------+-----------+ |
625 * +------------------------------+
626 * |
627 * +---------<---------v------------>----------+
628 * | |
629 * +--------v----------------+ |
630 * | edp_phy_pll_link_clk | |
631 * | link_clk | |
632 * +--------+----------------+ |
633 * | |
634 * | |
635 * v v
636 * Input to DISPCC block |
637 * for link clk, crypto clk |
638 * and interface clock |
639 * |
640 * |
641 * +--------<------------+-----------------+---<---+
642 * | | |
643 * +----v---------+ +--------v-----+ +--------v------+
644 * | vco_divided | | vco_divided | | vco_divided |
645 * | _clk_src | | _clk_src | | _clk_src |
646 * | | | | | |
647 * |divsel_six | | divsel_two | | divsel_four |
648 * +-------+------+ +-----+--------+ +--------+------+
649 * | | |
650 * v---->----------v-------------<------v
651 * |
652 * +----------+-----------------+
653 * | edp_phy_pll_vco_div_clk |
654 * +---------+------------------+
655 * |
656 * v
657 * Input to DISPCC block
658 * for EDP pixel clock
659 *
660 */
661static int qcom_edp_dp_pixel_clk_determine_rate(struct clk_hw *hw,
662 struct clk_rate_request *req)
663{
664 switch (req->rate) {
665 case 1620000000UL / 2:
666 case 2700000000UL / 2:
667 /* 5.4 and 8.1 GHz are same link rate as 2.7GHz, i.e. div 4 and div 6 */
668 return 0;
669
670 default:
671 return -EINVAL;
672 }
673}
674
675static unsigned long
676qcom_edp_dp_pixel_clk_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
677{
678 const struct qcom_edp *edp = container_of(hw, struct qcom_edp, dp_pixel_hw);
679 const struct phy_configure_opts_dp *dp_opts = &edp->dp_opts;
680
681 switch (dp_opts->link_rate) {
682 case 1620:
683 return 1620000000UL / 2;
684 case 2700:
685 return 2700000000UL / 2;
686 case 5400:
687 return 5400000000UL / 4;
688 case 8100:
689 return 8100000000UL / 6;
690 default:
691 return 0;
692 }
693}
694
695static const struct clk_ops qcom_edp_dp_pixel_clk_ops = {
696 .determine_rate = qcom_edp_dp_pixel_clk_determine_rate,
697 .recalc_rate = qcom_edp_dp_pixel_clk_recalc_rate,
698};
699
700static int qcom_edp_dp_link_clk_determine_rate(struct clk_hw *hw,
701 struct clk_rate_request *req)
702{
703 switch (req->rate) {
704 case 162000000:
705 case 270000000:
706 case 540000000:
707 case 810000000:
708 return 0;
709
710 default:
711 return -EINVAL;
712 }
713}
714
715static unsigned long
716qcom_edp_dp_link_clk_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
717{
718 const struct qcom_edp *edp = container_of(hw, struct qcom_edp, dp_link_hw);
719 const struct phy_configure_opts_dp *dp_opts = &edp->dp_opts;
720
721 switch (dp_opts->link_rate) {
722 case 1620:
723 case 2700:
724 case 5400:
725 case 8100:
726 return dp_opts->link_rate * 100000;
727
728 default:
729 return 0;
730 }
731}
732
733static const struct clk_ops qcom_edp_dp_link_clk_ops = {
734 .determine_rate = qcom_edp_dp_link_clk_determine_rate,
735 .recalc_rate = qcom_edp_dp_link_clk_recalc_rate,
736};
737
738static int qcom_edp_clks_register(struct qcom_edp *edp, struct device_node *np)
739{
740 struct clk_hw_onecell_data *data;
741 struct clk_init_data init = { };
742 char name[64];
743 int ret;
744
745 data = devm_kzalloc(dev: edp->dev, struct_size(data, hws, 2), GFP_KERNEL);
746 if (!data)
747 return -ENOMEM;
748 data->num = 2;
749
750 snprintf(buf: name, size: sizeof(name), fmt: "%s::link_clk", dev_name(dev: edp->dev));
751 init.ops = &qcom_edp_dp_link_clk_ops;
752 init.name = name;
753 edp->dp_link_hw.init = &init;
754 ret = devm_clk_hw_register(dev: edp->dev, hw: &edp->dp_link_hw);
755 if (ret)
756 return ret;
757
758 snprintf(buf: name, size: sizeof(name), fmt: "%s::vco_div_clk", dev_name(dev: edp->dev));
759 init.ops = &qcom_edp_dp_pixel_clk_ops;
760 init.name = name;
761 edp->dp_pixel_hw.init = &init;
762 ret = devm_clk_hw_register(dev: edp->dev, hw: &edp->dp_pixel_hw);
763 if (ret)
764 return ret;
765
766 data->hws[0] = &edp->dp_link_hw;
767 data->hws[1] = &edp->dp_pixel_hw;
768
769 return devm_of_clk_add_hw_provider(dev: edp->dev, get: of_clk_hw_onecell_get, data);
770}
771
772static int qcom_edp_phy_probe(struct platform_device *pdev)
773{
774 struct phy_provider *phy_provider;
775 struct device *dev = &pdev->dev;
776 struct qcom_edp *edp;
777 int ret;
778
779 edp = devm_kzalloc(dev, size: sizeof(*edp), GFP_KERNEL);
780 if (!edp)
781 return -ENOMEM;
782
783 edp->dev = dev;
784 edp->cfg = of_device_get_match_data(dev: &pdev->dev);
785
786 edp->edp = devm_platform_ioremap_resource(pdev, index: 0);
787 if (IS_ERR(ptr: edp->edp))
788 return PTR_ERR(ptr: edp->edp);
789
790 edp->tx0 = devm_platform_ioremap_resource(pdev, index: 1);
791 if (IS_ERR(ptr: edp->tx0))
792 return PTR_ERR(ptr: edp->tx0);
793
794 edp->tx1 = devm_platform_ioremap_resource(pdev, index: 2);
795 if (IS_ERR(ptr: edp->tx1))
796 return PTR_ERR(ptr: edp->tx1);
797
798 edp->pll = devm_platform_ioremap_resource(pdev, index: 3);
799 if (IS_ERR(ptr: edp->pll))
800 return PTR_ERR(ptr: edp->pll);
801
802 edp->clks[0].id = "aux";
803 edp->clks[1].id = "cfg_ahb";
804 ret = devm_clk_bulk_get(dev, ARRAY_SIZE(edp->clks), clks: edp->clks);
805 if (ret)
806 return ret;
807
808 edp->supplies[0].supply = "vdda-phy";
809 edp->supplies[1].supply = "vdda-pll";
810 ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(edp->supplies), consumers: edp->supplies);
811 if (ret)
812 return ret;
813
814 ret = regulator_set_load(regulator: edp->supplies[0].consumer, load_uA: 21800); /* 1.2 V vdda-phy */
815 if (ret) {
816 dev_err(dev, "failed to set load at %s\n", edp->supplies[0].supply);
817 return ret;
818 }
819
820 ret = regulator_set_load(regulator: edp->supplies[1].consumer, load_uA: 36000); /* 0.9 V vdda-pll */
821 if (ret) {
822 dev_err(dev, "failed to set load at %s\n", edp->supplies[1].supply);
823 return ret;
824 }
825
826 ret = qcom_edp_clks_register(edp, np: pdev->dev.of_node);
827 if (ret)
828 return ret;
829
830 edp->phy = devm_phy_create(dev, node: pdev->dev.of_node, ops: &qcom_edp_ops);
831 if (IS_ERR(ptr: edp->phy)) {
832 dev_err(dev, "failed to register phy\n");
833 return PTR_ERR(ptr: edp->phy);
834 }
835
836 phy_set_drvdata(phy: edp->phy, data: edp);
837
838 phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
839 return PTR_ERR_OR_ZERO(ptr: phy_provider);
840}
841
842static const struct of_device_id qcom_edp_phy_match_table[] = {
843 { .compatible = "qcom,sc7280-edp-phy" },
844 { .compatible = "qcom,sc8180x-edp-phy" },
845 { .compatible = "qcom,sc8280xp-dp-phy", .data = &dp_phy_cfg },
846 { .compatible = "qcom,sc8280xp-edp-phy", .data = &edp_phy_cfg },
847 { }
848};
849MODULE_DEVICE_TABLE(of, qcom_edp_phy_match_table);
850
851static struct platform_driver qcom_edp_phy_driver = {
852 .probe = qcom_edp_phy_probe,
853 .driver = {
854 .name = "qcom-edp-phy",
855 .of_match_table = qcom_edp_phy_match_table,
856 },
857};
858
859module_platform_driver(qcom_edp_phy_driver);
860
861MODULE_AUTHOR("Bjorn Andersson <bjorn.andersson@linaro.org>");
862MODULE_DESCRIPTION("Qualcomm eDP QMP PHY driver");
863MODULE_LICENSE("GPL v2");
864

source code of linux/drivers/phy/qualcomm/phy-qcom-edp.c