Linux Audio

Check our new training course

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