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), edp->supplies);
182	if (ret)
183		return ret;
184
185	ret = clk_bulk_prepare_enable(ARRAY_SIZE(edp->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	       edp->edp + DP_PHY_PD_CTL);
192
193	/* Turn on BIAS current for PHY/PLL */
194	writel(0x17, edp->pll + QSERDES_V4_COM_BIAS_EN_CLKBUFLR_EN);
195
196	writel(DP_PHY_PD_CTL_PSR_PWRDN, edp->edp + DP_PHY_PD_CTL);
197	msleep(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	       edp->edp + DP_PHY_PD_CTL);
203
204	if (cfg && cfg->is_dp)
205		cfg8 = 0xb7;
206	else
207		cfg8 = 0x37;
208
209	writel(0xfc, edp->edp + DP_PHY_MODE);
210
211	writel(0x00, edp->edp + DP_PHY_AUX_CFG0);
212	writel(0x13, edp->edp + DP_PHY_AUX_CFG1);
213	writel(0x24, edp->edp + DP_PHY_AUX_CFG2);
214	writel(0x00, edp->edp + DP_PHY_AUX_CFG3);
215	writel(0x0a, edp->edp + DP_PHY_AUX_CFG4);
216	writel(0x26, edp->edp + DP_PHY_AUX_CFG5);
217	writel(0x0a, edp->edp + DP_PHY_AUX_CFG6);
218	writel(0x03, edp->edp + DP_PHY_AUX_CFG7);
219	writel(cfg8, edp->edp + DP_PHY_AUX_CFG8);
220	writel(0x03, 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, edp->edp + DP_PHY_AUX_INTERRUPT_MASK);
225
226	msleep(20);
227
228	return 0;
229
230out_disable_supplies:
231	regulator_bulk_disable(ARRAY_SIZE(edp->supplies), 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(ldo_config, edp->tx0 + TXn_LDO_CONFIG);
268	writel(swing, edp->tx0 + TXn_TX_DRV_LVL);
269	writel(emph, edp->tx0 + TXn_TX_EMP_POST1_LVL);
270
271	writel(ldo_config, edp->tx1 + TXn_LDO_CONFIG);
272	writel(swing, edp->tx1 + TXn_TX_DRV_LVL);
273	writel(emph, 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(0x01, edp->pll + QSERDES_V4_COM_SSC_EN_CENTER);
317	writel(0x00, edp->pll + QSERDES_V4_COM_SSC_ADJ_PER1);
318	writel(0x36, edp->pll + QSERDES_V4_COM_SSC_PER1);
319	writel(0x01, edp->pll + QSERDES_V4_COM_SSC_PER2);
320	writel(step1, edp->pll + QSERDES_V4_COM_SSC_STEP_SIZE1_MODE0);
321	writel(step2, 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(0x01, edp->pll + QSERDES_V4_COM_SVS_MODE_CLK_SEL);
379	writel(0x0b, edp->pll + QSERDES_V4_COM_SYSCLK_EN_SEL);
380	writel(0x02, edp->pll + QSERDES_V4_COM_SYS_CLK_CTRL);
381	writel(0x0c, edp->pll + QSERDES_V4_COM_CLK_ENABLE1);
382	writel(0x06, edp->pll + QSERDES_V4_COM_SYSCLK_BUF_ENABLE);
383	writel(0x30, edp->pll + QSERDES_V4_COM_CLK_SELECT);
384	writel(hsclk_sel, edp->pll + QSERDES_V4_COM_HSCLK_SEL);
385	writel(0x0f, edp->pll + QSERDES_V4_COM_PLL_IVCO);
386	writel(0x08, edp->pll + QSERDES_V4_COM_LOCK_CMP_EN);
387	writel(0x36, edp->pll + QSERDES_V4_COM_PLL_CCTRL_MODE0);
388	writel(0x16, edp->pll + QSERDES_V4_COM_PLL_RCTRL_MODE0);
389	writel(0x06, edp->pll + QSERDES_V4_COM_CP_CTRL_MODE0);
390	writel(dec_start_mode0, edp->pll + QSERDES_V4_COM_DEC_START_MODE0);
391	writel(0x00, edp->pll + QSERDES_V4_COM_DIV_FRAC_START1_MODE0);
392	writel(div_frac_start2_mode0, edp->pll + QSERDES_V4_COM_DIV_FRAC_START2_MODE0);
393	writel(div_frac_start3_mode0, edp->pll + QSERDES_V4_COM_DIV_FRAC_START3_MODE0);
394	writel(0x02, edp->pll + QSERDES_V4_COM_CMN_CONFIG);
395	writel(0x3f, edp->pll + QSERDES_V4_COM_INTEGLOOP_GAIN0_MODE0);
396	writel(0x00, edp->pll + QSERDES_V4_COM_INTEGLOOP_GAIN1_MODE0);
397	writel(0x00, edp->pll + QSERDES_V4_COM_VCO_TUNE_MAP);
398	writel(lock_cmp1_mode0, edp->pll + QSERDES_V4_COM_LOCK_CMP1_MODE0);
399	writel(lock_cmp2_mode0, edp->pll + QSERDES_V4_COM_LOCK_CMP2_MODE0);
400
401	writel(0x0a, edp->pll + QSERDES_V4_COM_BG_TIMER);
402	writel(0x14, edp->pll + QSERDES_V4_COM_CORECLK_DIV_MODE0);
403	writel(0x00, edp->pll + QSERDES_V4_COM_VCO_TUNE_CTRL);
404	writel(0x17, edp->pll + QSERDES_V4_COM_BIAS_EN_CLKBUFLR_EN);
405	writel(0x0f, edp->pll + QSERDES_V4_COM_CORE_CLK_EN);
406	writel(0xa0, edp->pll + QSERDES_V4_COM_VCO_TUNE1_MODE0);
407	writel(0x03, 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(vco_div, 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	       edp->edp + DP_PHY_PD_CTL);
464	writel(0xfc, 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(ldo_config, edp->tx0 + TXn_LDO_CONFIG);
475	writel(ldo_config, edp->tx1 + TXn_LDO_CONFIG);
476	writel(0x00, edp->tx0 + TXn_LANE_MODE_1);
477	writel(0x00, 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(0x05, edp->edp + DP_PHY_TX0_TX1_LANE_CTL);
491	writel(0x05, edp->edp + DP_PHY_TX2_TX3_LANE_CTL);
492
493	/* TX-0 register configuration */
494	writel(0x03, edp->tx0 + TXn_TRANSCEIVER_BIAS_EN);
495	writel(0x0f, edp->tx0 + TXn_CLKBUF_ENABLE);
496	writel(0x03, edp->tx0 + TXn_RESET_TSYNC_EN);
497	writel(0x01, edp->tx0 + TXn_TRAN_DRVR_EMP_EN);
498	writel(0x04, edp->tx0 + TXn_TX_BAND);
499
500	/* TX-1 register configuration */
501	writel(0x03, edp->tx1 + TXn_TRANSCEIVER_BIAS_EN);
502	writel(0x0f, edp->tx1 + TXn_CLKBUF_ENABLE);
503	writel(0x03, edp->tx1 + TXn_RESET_TSYNC_EN);
504	writel(0x01, edp->tx1 + TXn_TRAN_DRVR_EMP_EN);
505	writel(0x04, edp->tx1 + TXn_TX_BAND);
506
507	ret = qcom_edp_set_vco_div(edp, &pixel_freq);
508	if (ret)
509		return ret;
510
511	writel(0x01, edp->edp + DP_PHY_CFG);
512	writel(0x05, edp->edp + DP_PHY_CFG);
513	writel(0x01, edp->edp + DP_PHY_CFG);
514	writel(0x09, edp->edp + DP_PHY_CFG);
515
516	writel(0x20, 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(0x19, edp->edp + DP_PHY_CFG);
524	writel(0x1f, edp->tx0 + TXn_HIGHZ_DRVR_EN);
525	writel(0x04, edp->tx0 + TXn_HIGHZ_DRVR_EN);
526	writel(0x00, edp->tx0 + TXn_TX_POL_INV);
527	writel(0x1f, edp->tx1 + TXn_HIGHZ_DRVR_EN);
528	writel(0x04, edp->tx1 + TXn_HIGHZ_DRVR_EN);
529	writel(0x00, edp->tx1 + TXn_TX_POL_INV);
530	writel(0x10, edp->tx0 + TXn_TX_DRV_LVL_OFFSET);
531	writel(0x10, edp->tx1 + TXn_TX_DRV_LVL_OFFSET);
532	writel(0x11, edp->tx0 + TXn_RES_CODE_LANE_OFFSET_TX0);
533	writel(0x11, edp->tx0 + TXn_RES_CODE_LANE_OFFSET_TX1);
534	writel(0x11, edp->tx1 + TXn_RES_CODE_LANE_OFFSET_TX0);
535	writel(0x11, edp->tx1 + TXn_RES_CODE_LANE_OFFSET_TX1);
536
537	writel(0x10, edp->tx0 + TXn_TX_EMP_POST1_LVL);
538	writel(0x10, edp->tx1 + TXn_TX_EMP_POST1_LVL);
539	writel(0x1f, edp->tx0 + TXn_TX_DRV_LVL);
540	writel(0x1f, 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(drvr0_en, edp->tx0 + TXn_HIGHZ_DRVR_EN);
563	writel(bias0_en, edp->tx0 + TXn_TRANSCEIVER_BIAS_EN);
564	writel(drvr1_en, edp->tx1 + TXn_HIGHZ_DRVR_EN);
565	writel(bias1_en, edp->tx1 + TXn_TRANSCEIVER_BIAS_EN);
566	writel(cfg1, edp->edp + DP_PHY_CFG_1);
567
568	writel(0x18, edp->edp + DP_PHY_CFG);
569	usleep_range(100, 1000);
570
571	writel(0x19, 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(edp->dp_link_hw.clk, edp->dp_opts.link_rate * 100000);
579	clk_set_rate(edp->dp_pixel_hw.clk, 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, 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), edp->clks);
598	regulator_bulk_disable(ARRAY_SIZE(edp->supplies), 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(edp->dev, struct_size(data, hws, 2), GFP_KERNEL);
746	if (!data)
747		return -ENOMEM;
748	data->num = 2;
749
750	snprintf(name, sizeof(name), "%s::link_clk", dev_name(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(edp->dev, &edp->dp_link_hw);
755	if (ret)
756		return ret;
757
758	snprintf(name, sizeof(name), "%s::vco_div_clk", dev_name(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(edp->dev, &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(edp->dev, 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, sizeof(*edp), GFP_KERNEL);
780	if (!edp)
781		return -ENOMEM;
782
783	edp->dev = dev;
784	edp->cfg = of_device_get_match_data(&pdev->dev);
785
786	edp->edp = devm_platform_ioremap_resource(pdev, 0);
787	if (IS_ERR(edp->edp))
788		return PTR_ERR(edp->edp);
789
790	edp->tx0 = devm_platform_ioremap_resource(pdev, 1);
791	if (IS_ERR(edp->tx0))
792		return PTR_ERR(edp->tx0);
793
794	edp->tx1 = devm_platform_ioremap_resource(pdev, 2);
795	if (IS_ERR(edp->tx1))
796		return PTR_ERR(edp->tx1);
797
798	edp->pll = devm_platform_ioremap_resource(pdev, 3);
799	if (IS_ERR(edp->pll))
800		return PTR_ERR(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), 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), edp->supplies);
811	if (ret)
812		return ret;
813
814	ret = regulator_set_load(edp->supplies[0].consumer, 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(edp->supplies[1].consumer, 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, pdev->dev.of_node);
827	if (ret)
828		return ret;
829
830	edp->phy = devm_phy_create(dev, pdev->dev.of_node, &qcom_edp_ops);
831	if (IS_ERR(edp->phy)) {
832		dev_err(dev, "failed to register phy\n");
833		return PTR_ERR(edp->phy);
834	}
835
836	phy_set_drvdata(edp->phy, edp);
837
838	phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
839	return PTR_ERR_OR_ZERO(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