cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

phy-qcom-edp.c (19483B)


      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/of_device.h>
     17#include <linux/of_address.h>
     18#include <linux/phy/phy.h>
     19#include <linux/platform_device.h>
     20#include <linux/regulator/consumer.h>
     21#include <linux/reset.h>
     22#include <linux/slab.h>
     23
     24#include <dt-bindings/phy/phy.h>
     25
     26#include "phy-qcom-qmp.h"
     27
     28/* EDP_PHY registers */
     29#define DP_PHY_CFG                              0x0010
     30#define DP_PHY_CFG_1                            0x0014
     31#define DP_PHY_PD_CTL                           0x001c
     32#define DP_PHY_MODE                             0x0020
     33
     34#define DP_PHY_AUX_CFG0				0x0024
     35#define DP_PHY_AUX_CFG1				0x0028
     36#define DP_PHY_AUX_CFG2				0x002C
     37#define DP_PHY_AUX_CFG3				0x0030
     38#define DP_PHY_AUX_CFG4				0x0034
     39#define DP_PHY_AUX_CFG5				0x0038
     40#define DP_PHY_AUX_CFG6				0x003C
     41#define DP_PHY_AUX_CFG7				0x0040
     42#define DP_PHY_AUX_CFG8				0x0044
     43#define DP_PHY_AUX_CFG9				0x0048
     44
     45#define DP_PHY_AUX_INTERRUPT_MASK		0x0058
     46
     47#define DP_PHY_VCO_DIV                          0x0074
     48#define DP_PHY_TX0_TX1_LANE_CTL                 0x007c
     49#define DP_PHY_TX2_TX3_LANE_CTL                 0x00a0
     50
     51#define DP_PHY_STATUS                           0x00e0
     52
     53/* LANE_TXn registers */
     54#define TXn_CLKBUF_ENABLE                       0x0000
     55#define TXn_TX_EMP_POST1_LVL                    0x0004
     56
     57#define TXn_TX_DRV_LVL                          0x0014
     58#define TXn_TX_DRV_LVL_OFFSET                   0x0018
     59#define TXn_RESET_TSYNC_EN                      0x001c
     60#define TXn_LDO_CONFIG                          0x0084
     61#define TXn_TX_BAND                             0x0028
     62
     63#define TXn_RES_CODE_LANE_OFFSET_TX0            0x0044
     64#define TXn_RES_CODE_LANE_OFFSET_TX1            0x0048
     65
     66#define TXn_TRANSCEIVER_BIAS_EN                 0x0054
     67#define TXn_HIGHZ_DRVR_EN                       0x0058
     68#define TXn_TX_POL_INV                          0x005c
     69#define TXn_LANE_MODE_1                         0x0064
     70
     71#define TXn_TRAN_DRVR_EMP_EN                    0x0078
     72
     73struct qcom_edp {
     74	struct device *dev;
     75
     76	struct phy *phy;
     77
     78	void __iomem *edp;
     79	void __iomem *tx0;
     80	void __iomem *tx1;
     81	void __iomem *pll;
     82
     83	struct clk_hw dp_link_hw;
     84	struct clk_hw dp_pixel_hw;
     85
     86	struct phy_configure_opts_dp dp_opts;
     87
     88	struct clk_bulk_data clks[2];
     89	struct regulator_bulk_data supplies[2];
     90};
     91
     92static int qcom_edp_phy_init(struct phy *phy)
     93{
     94	struct qcom_edp *edp = phy_get_drvdata(phy);
     95	int ret;
     96
     97	ret = regulator_bulk_enable(ARRAY_SIZE(edp->supplies), edp->supplies);
     98	if (ret)
     99		return ret;
    100
    101	ret = clk_bulk_prepare_enable(ARRAY_SIZE(edp->clks), edp->clks);
    102	if (ret)
    103		goto out_disable_supplies;
    104
    105	writel(DP_PHY_PD_CTL_PWRDN | DP_PHY_PD_CTL_AUX_PWRDN |
    106	       DP_PHY_PD_CTL_PLL_PWRDN | DP_PHY_PD_CTL_DP_CLAMP_EN,
    107	       edp->edp + DP_PHY_PD_CTL);
    108
    109	/* Turn on BIAS current for PHY/PLL */
    110	writel(0x17, edp->pll + QSERDES_V4_COM_BIAS_EN_CLKBUFLR_EN);
    111
    112	writel(DP_PHY_PD_CTL_PSR_PWRDN, edp->edp + DP_PHY_PD_CTL);
    113	msleep(20);
    114
    115	writel(DP_PHY_PD_CTL_PWRDN | DP_PHY_PD_CTL_AUX_PWRDN |
    116	       DP_PHY_PD_CTL_LANE_0_1_PWRDN | DP_PHY_PD_CTL_LANE_2_3_PWRDN |
    117	       DP_PHY_PD_CTL_PLL_PWRDN | DP_PHY_PD_CTL_DP_CLAMP_EN,
    118	       edp->edp + DP_PHY_PD_CTL);
    119
    120	writel(0x00, edp->edp + DP_PHY_AUX_CFG0);
    121	writel(0x13, edp->edp + DP_PHY_AUX_CFG1);
    122	writel(0x24, edp->edp + DP_PHY_AUX_CFG2);
    123	writel(0x00, edp->edp + DP_PHY_AUX_CFG3);
    124	writel(0x0a, edp->edp + DP_PHY_AUX_CFG4);
    125	writel(0x26, edp->edp + DP_PHY_AUX_CFG5);
    126	writel(0x0a, edp->edp + DP_PHY_AUX_CFG6);
    127	writel(0x03, edp->edp + DP_PHY_AUX_CFG7);
    128	writel(0x37, edp->edp + DP_PHY_AUX_CFG8);
    129	writel(0x03, edp->edp + DP_PHY_AUX_CFG9);
    130
    131	writel(PHY_AUX_STOP_ERR_MASK | PHY_AUX_DEC_ERR_MASK |
    132	       PHY_AUX_SYNC_ERR_MASK | PHY_AUX_ALIGN_ERR_MASK |
    133	       PHY_AUX_REQ_ERR_MASK, edp->edp + DP_PHY_AUX_INTERRUPT_MASK);
    134
    135	msleep(20);
    136
    137	return 0;
    138
    139out_disable_supplies:
    140	regulator_bulk_disable(ARRAY_SIZE(edp->supplies), edp->supplies);
    141
    142	return ret;
    143}
    144
    145static int qcom_edp_phy_configure(struct phy *phy, union phy_configure_opts *opts)
    146{
    147	const struct phy_configure_opts_dp *dp_opts = &opts->dp;
    148	struct qcom_edp *edp = phy_get_drvdata(phy);
    149
    150	memcpy(&edp->dp_opts, dp_opts, sizeof(*dp_opts));
    151
    152	return 0;
    153}
    154
    155static int qcom_edp_configure_ssc(const struct qcom_edp *edp)
    156{
    157	const struct phy_configure_opts_dp *dp_opts = &edp->dp_opts;
    158	u32 step1;
    159	u32 step2;
    160
    161	switch (dp_opts->link_rate) {
    162	case 1620:
    163	case 2700:
    164	case 8100:
    165		step1 = 0x45;
    166		step2 = 0x06;
    167		break;
    168
    169	case 5400:
    170		step1 = 0x5c;
    171		step2 = 0x08;
    172		break;
    173
    174	default:
    175		/* Other link rates aren't supported */
    176		return -EINVAL;
    177	}
    178
    179	writel(0x01, edp->pll + QSERDES_V4_COM_SSC_EN_CENTER);
    180	writel(0x00, edp->pll + QSERDES_V4_COM_SSC_ADJ_PER1);
    181	writel(0x36, edp->pll + QSERDES_V4_COM_SSC_PER1);
    182	writel(0x01, edp->pll + QSERDES_V4_COM_SSC_PER2);
    183	writel(step1, edp->pll + QSERDES_V4_COM_SSC_STEP_SIZE1_MODE0);
    184	writel(step2, edp->pll + QSERDES_V4_COM_SSC_STEP_SIZE2_MODE0);
    185
    186	return 0;
    187}
    188
    189static int qcom_edp_configure_pll(const struct qcom_edp *edp)
    190{
    191	const struct phy_configure_opts_dp *dp_opts = &edp->dp_opts;
    192	u32 div_frac_start2_mode0;
    193	u32 div_frac_start3_mode0;
    194	u32 dec_start_mode0;
    195	u32 lock_cmp1_mode0;
    196	u32 lock_cmp2_mode0;
    197	u32 hsclk_sel;
    198
    199	switch (dp_opts->link_rate) {
    200	case 1620:
    201		hsclk_sel = 0x5;
    202		dec_start_mode0 = 0x69;
    203		div_frac_start2_mode0 = 0x80;
    204		div_frac_start3_mode0 = 0x07;
    205		lock_cmp1_mode0 = 0x6f;
    206		lock_cmp2_mode0 = 0x08;
    207		break;
    208
    209	case 2700:
    210		hsclk_sel = 0x3;
    211		dec_start_mode0 = 0x69;
    212		div_frac_start2_mode0 = 0x80;
    213		div_frac_start3_mode0 = 0x07;
    214		lock_cmp1_mode0 = 0x0f;
    215		lock_cmp2_mode0 = 0x0e;
    216		break;
    217
    218	case 5400:
    219		hsclk_sel = 0x1;
    220		dec_start_mode0 = 0x8c;
    221		div_frac_start2_mode0 = 0x00;
    222		div_frac_start3_mode0 = 0x0a;
    223		lock_cmp1_mode0 = 0x1f;
    224		lock_cmp2_mode0 = 0x1c;
    225		break;
    226
    227	case 8100:
    228		hsclk_sel = 0x0;
    229		dec_start_mode0 = 0x69;
    230		div_frac_start2_mode0 = 0x80;
    231		div_frac_start3_mode0 = 0x07;
    232		lock_cmp1_mode0 = 0x2f;
    233		lock_cmp2_mode0 = 0x2a;
    234		break;
    235
    236	default:
    237		/* Other link rates aren't supported */
    238		return -EINVAL;
    239	}
    240
    241	writel(0x01, edp->pll + QSERDES_V4_COM_SVS_MODE_CLK_SEL);
    242	writel(0x0b, edp->pll + QSERDES_V4_COM_SYSCLK_EN_SEL);
    243	writel(0x02, edp->pll + QSERDES_V4_COM_SYS_CLK_CTRL);
    244	writel(0x0c, edp->pll + QSERDES_V4_COM_CLK_ENABLE1);
    245	writel(0x06, edp->pll + QSERDES_V4_COM_SYSCLK_BUF_ENABLE);
    246	writel(0x30, edp->pll + QSERDES_V4_COM_CLK_SELECT);
    247	writel(hsclk_sel, edp->pll + QSERDES_V4_COM_HSCLK_SEL);
    248	writel(0x0f, edp->pll + QSERDES_V4_COM_PLL_IVCO);
    249	writel(0x08, edp->pll + QSERDES_V4_COM_LOCK_CMP_EN);
    250	writel(0x36, edp->pll + QSERDES_V4_COM_PLL_CCTRL_MODE0);
    251	writel(0x16, edp->pll + QSERDES_V4_COM_PLL_RCTRL_MODE0);
    252	writel(0x06, edp->pll + QSERDES_V4_COM_CP_CTRL_MODE0);
    253	writel(dec_start_mode0, edp->pll + QSERDES_V4_COM_DEC_START_MODE0);
    254	writel(0x00, edp->pll + QSERDES_V4_COM_DIV_FRAC_START1_MODE0);
    255	writel(div_frac_start2_mode0, edp->pll + QSERDES_V4_COM_DIV_FRAC_START2_MODE0);
    256	writel(div_frac_start3_mode0, edp->pll + QSERDES_V4_COM_DIV_FRAC_START3_MODE0);
    257	writel(0x02, edp->pll + QSERDES_V4_COM_CMN_CONFIG);
    258	writel(0x3f, edp->pll + QSERDES_V4_COM_INTEGLOOP_GAIN0_MODE0);
    259	writel(0x00, edp->pll + QSERDES_V4_COM_INTEGLOOP_GAIN1_MODE0);
    260	writel(0x00, edp->pll + QSERDES_V4_COM_VCO_TUNE_MAP);
    261	writel(lock_cmp1_mode0, edp->pll + QSERDES_V4_COM_LOCK_CMP1_MODE0);
    262	writel(lock_cmp2_mode0, edp->pll + QSERDES_V4_COM_LOCK_CMP2_MODE0);
    263
    264	writel(0x0a, edp->pll + QSERDES_V4_COM_BG_TIMER);
    265	writel(0x14, edp->pll + QSERDES_V4_COM_CORECLK_DIV_MODE0);
    266	writel(0x00, edp->pll + QSERDES_V4_COM_VCO_TUNE_CTRL);
    267	writel(0x17, edp->pll + QSERDES_V4_COM_BIAS_EN_CLKBUFLR_EN);
    268	writel(0x0f, edp->pll + QSERDES_V4_COM_CORE_CLK_EN);
    269	writel(0xa0, edp->pll + QSERDES_V4_COM_VCO_TUNE1_MODE0);
    270	writel(0x03, edp->pll + QSERDES_V4_COM_VCO_TUNE2_MODE0);
    271
    272	return 0;
    273}
    274
    275static int qcom_edp_set_vco_div(const struct qcom_edp *edp)
    276{
    277	const struct phy_configure_opts_dp *dp_opts = &edp->dp_opts;
    278	unsigned long pixel_freq;
    279	u32 vco_div;
    280
    281	switch (dp_opts->link_rate) {
    282	case 1620:
    283		vco_div = 0x1;
    284		pixel_freq = 1620000000UL / 2;
    285		break;
    286
    287	case 2700:
    288		vco_div = 0x1;
    289		pixel_freq = 2700000000UL / 2;
    290		break;
    291
    292	case 5400:
    293		vco_div = 0x2;
    294		pixel_freq = 5400000000UL / 4;
    295		break;
    296
    297	case 8100:
    298		vco_div = 0x0;
    299		pixel_freq = 8100000000UL / 6;
    300		break;
    301
    302	default:
    303		/* Other link rates aren't supported */
    304		return -EINVAL;
    305	}
    306
    307	writel(vco_div, edp->edp + DP_PHY_VCO_DIV);
    308
    309	clk_set_rate(edp->dp_link_hw.clk, dp_opts->link_rate * 100000);
    310	clk_set_rate(edp->dp_pixel_hw.clk, pixel_freq);
    311
    312	return 0;
    313}
    314
    315static int qcom_edp_phy_power_on(struct phy *phy)
    316{
    317	const struct qcom_edp *edp = phy_get_drvdata(phy);
    318	int timeout;
    319	int ret;
    320	u32 val;
    321
    322	writel(DP_PHY_PD_CTL_PWRDN | DP_PHY_PD_CTL_AUX_PWRDN |
    323	       DP_PHY_PD_CTL_LANE_0_1_PWRDN | DP_PHY_PD_CTL_LANE_2_3_PWRDN |
    324	       DP_PHY_PD_CTL_PLL_PWRDN | DP_PHY_PD_CTL_DP_CLAMP_EN,
    325	       edp->edp + DP_PHY_PD_CTL);
    326	writel(0xfc, edp->edp + DP_PHY_MODE);
    327
    328	timeout = readl_poll_timeout(edp->pll + QSERDES_V4_COM_CMN_STATUS,
    329				     val, val & BIT(7), 5, 200);
    330	if (timeout)
    331		return timeout;
    332
    333	writel(0x01, edp->tx0 + TXn_LDO_CONFIG);
    334	writel(0x01, edp->tx1 + TXn_LDO_CONFIG);
    335	writel(0x00, edp->tx0 + TXn_LANE_MODE_1);
    336	writel(0x00, edp->tx1 + TXn_LANE_MODE_1);
    337
    338	if (edp->dp_opts.ssc) {
    339		ret = qcom_edp_configure_ssc(edp);
    340		if (ret)
    341			return ret;
    342	}
    343
    344	ret = qcom_edp_configure_pll(edp);
    345	if (ret)
    346		return ret;
    347
    348	/* TX Lane configuration */
    349	writel(0x05, edp->edp + DP_PHY_TX0_TX1_LANE_CTL);
    350	writel(0x05, edp->edp + DP_PHY_TX2_TX3_LANE_CTL);
    351
    352	/* TX-0 register configuration */
    353	writel(0x03, edp->tx0 + TXn_TRANSCEIVER_BIAS_EN);
    354	writel(0x0f, edp->tx0 + TXn_CLKBUF_ENABLE);
    355	writel(0x03, edp->tx0 + TXn_RESET_TSYNC_EN);
    356	writel(0x01, edp->tx0 + TXn_TRAN_DRVR_EMP_EN);
    357	writel(0x04, edp->tx0 + TXn_TX_BAND);
    358
    359	/* TX-1 register configuration */
    360	writel(0x03, edp->tx1 + TXn_TRANSCEIVER_BIAS_EN);
    361	writel(0x0f, edp->tx1 + TXn_CLKBUF_ENABLE);
    362	writel(0x03, edp->tx1 + TXn_RESET_TSYNC_EN);
    363	writel(0x01, edp->tx1 + TXn_TRAN_DRVR_EMP_EN);
    364	writel(0x04, edp->tx1 + TXn_TX_BAND);
    365
    366	ret = qcom_edp_set_vco_div(edp);
    367	if (ret)
    368		return ret;
    369
    370	writel(0x01, edp->edp + DP_PHY_CFG);
    371	writel(0x05, edp->edp + DP_PHY_CFG);
    372	writel(0x01, edp->edp + DP_PHY_CFG);
    373	writel(0x09, edp->edp + DP_PHY_CFG);
    374
    375	writel(0x20, edp->pll + QSERDES_V4_COM_RESETSM_CNTRL);
    376
    377	timeout = readl_poll_timeout(edp->pll + QSERDES_V4_COM_C_READY_STATUS,
    378				     val, val & BIT(0), 500, 10000);
    379	if (timeout)
    380		return timeout;
    381
    382	writel(0x19, edp->edp + DP_PHY_CFG);
    383	writel(0x1f, edp->tx0 + TXn_HIGHZ_DRVR_EN);
    384	writel(0x04, edp->tx0 + TXn_HIGHZ_DRVR_EN);
    385	writel(0x00, edp->tx0 + TXn_TX_POL_INV);
    386	writel(0x1f, edp->tx1 + TXn_HIGHZ_DRVR_EN);
    387	writel(0x04, edp->tx1 + TXn_HIGHZ_DRVR_EN);
    388	writel(0x00, edp->tx1 + TXn_TX_POL_INV);
    389	writel(0x10, edp->tx0 + TXn_TX_DRV_LVL_OFFSET);
    390	writel(0x10, edp->tx1 + TXn_TX_DRV_LVL_OFFSET);
    391	writel(0x11, edp->tx0 + TXn_RES_CODE_LANE_OFFSET_TX0);
    392	writel(0x11, edp->tx0 + TXn_RES_CODE_LANE_OFFSET_TX1);
    393	writel(0x11, edp->tx1 + TXn_RES_CODE_LANE_OFFSET_TX0);
    394	writel(0x11, edp->tx1 + TXn_RES_CODE_LANE_OFFSET_TX1);
    395
    396	writel(0x10, edp->tx0 + TXn_TX_EMP_POST1_LVL);
    397	writel(0x10, edp->tx1 + TXn_TX_EMP_POST1_LVL);
    398	writel(0x1f, edp->tx0 + TXn_TX_DRV_LVL);
    399	writel(0x1f, edp->tx1 + TXn_TX_DRV_LVL);
    400
    401	writel(0x4, edp->tx0 + TXn_HIGHZ_DRVR_EN);
    402	writel(0x3, edp->tx0 + TXn_TRANSCEIVER_BIAS_EN);
    403	writel(0x4, edp->tx1 + TXn_HIGHZ_DRVR_EN);
    404	writel(0x0, edp->tx1 + TXn_TRANSCEIVER_BIAS_EN);
    405	writel(0x3, edp->edp + DP_PHY_CFG_1);
    406
    407	writel(0x18, edp->edp + DP_PHY_CFG);
    408	usleep_range(100, 1000);
    409
    410	writel(0x19, edp->edp + DP_PHY_CFG);
    411
    412	return readl_poll_timeout(edp->edp + DP_PHY_STATUS,
    413				  val, val & BIT(1), 500, 10000);
    414}
    415
    416static int qcom_edp_phy_power_off(struct phy *phy)
    417{
    418	const struct qcom_edp *edp = phy_get_drvdata(phy);
    419
    420	writel(DP_PHY_PD_CTL_PSR_PWRDN, edp->edp + DP_PHY_PD_CTL);
    421
    422	return 0;
    423}
    424
    425static int qcom_edp_phy_exit(struct phy *phy)
    426{
    427	struct qcom_edp *edp = phy_get_drvdata(phy);
    428
    429	clk_bulk_disable_unprepare(ARRAY_SIZE(edp->clks), edp->clks);
    430	regulator_bulk_disable(ARRAY_SIZE(edp->supplies), edp->supplies);
    431
    432	return 0;
    433}
    434
    435static const struct phy_ops qcom_edp_ops = {
    436	.init		= qcom_edp_phy_init,
    437	.configure	= qcom_edp_phy_configure,
    438	.power_on	= qcom_edp_phy_power_on,
    439	.power_off	= qcom_edp_phy_power_off,
    440	.exit		= qcom_edp_phy_exit,
    441	.owner		= THIS_MODULE,
    442};
    443
    444/*
    445 * Embedded Display Port PLL driver block diagram for branch clocks
    446 *
    447 *              +------------------------------+
    448 *              |        EDP_VCO_CLK           |
    449 *              |                              |
    450 *              |    +-------------------+     |
    451 *              |    |  (EDP PLL/VCO)    |     |
    452 *              |    +---------+---------+     |
    453 *              |              v               |
    454 *              |   +----------+-----------+   |
    455 *              |   | hsclk_divsel_clk_src |   |
    456 *              |   +----------+-----------+   |
    457 *              +------------------------------+
    458 *                              |
    459 *          +---------<---------v------------>----------+
    460 *          |                                           |
    461 * +--------v----------------+                          |
    462 * |   edp_phy_pll_link_clk  |                          |
    463 * |     link_clk            |                          |
    464 * +--------+----------------+                          |
    465 *          |                                           |
    466 *          |                                           |
    467 *          v                                           v
    468 * Input to DISPCC block                                |
    469 * for link clk, crypto clk                             |
    470 * and interface clock                                  |
    471 *                                                      |
    472 *                                                      |
    473 *      +--------<------------+-----------------+---<---+
    474 *      |                     |                 |
    475 * +----v---------+  +--------v-----+  +--------v------+
    476 * | vco_divided  |  | vco_divided  |  | vco_divided   |
    477 * |    _clk_src  |  |    _clk_src  |  |    _clk_src   |
    478 * |              |  |              |  |               |
    479 * |divsel_six    |  |  divsel_two  |  |  divsel_four  |
    480 * +-------+------+  +-----+--------+  +--------+------+
    481 *         |                 |                  |
    482 *         v---->----------v-------------<------v
    483 *                         |
    484 *              +----------+-----------------+
    485 *              |   edp_phy_pll_vco_div_clk  |
    486 *              +---------+------------------+
    487 *                        |
    488 *                        v
    489 *              Input to DISPCC block
    490 *              for EDP pixel clock
    491 *
    492 */
    493static int qcom_edp_dp_pixel_clk_determine_rate(struct clk_hw *hw,
    494						struct clk_rate_request *req)
    495{
    496	switch (req->rate) {
    497	case 1620000000UL / 2:
    498	case 2700000000UL / 2:
    499	/* 5.4 and 8.1 GHz are same link rate as 2.7GHz, i.e. div 4 and div 6 */
    500		return 0;
    501
    502	default:
    503		return -EINVAL;
    504	}
    505}
    506
    507static unsigned long
    508qcom_edp_dp_pixel_clk_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
    509{
    510	const struct qcom_edp *edp = container_of(hw, struct qcom_edp, dp_pixel_hw);
    511	const struct phy_configure_opts_dp *dp_opts = &edp->dp_opts;
    512
    513	switch (dp_opts->link_rate) {
    514	case 1620:
    515		return 1620000000UL / 2;
    516	case 2700:
    517		return 2700000000UL / 2;
    518	case 5400:
    519		return 5400000000UL / 4;
    520	case 8100:
    521		return 8100000000UL / 6;
    522	default:
    523		return 0;
    524	}
    525}
    526
    527static const struct clk_ops qcom_edp_dp_pixel_clk_ops = {
    528	.determine_rate = qcom_edp_dp_pixel_clk_determine_rate,
    529	.recalc_rate = qcom_edp_dp_pixel_clk_recalc_rate,
    530};
    531
    532static int qcom_edp_dp_link_clk_determine_rate(struct clk_hw *hw,
    533					       struct clk_rate_request *req)
    534{
    535	switch (req->rate) {
    536	case 162000000:
    537	case 270000000:
    538	case 540000000:
    539	case 810000000:
    540		return 0;
    541
    542	default:
    543		return -EINVAL;
    544	}
    545}
    546
    547static unsigned long
    548qcom_edp_dp_link_clk_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
    549{
    550	const struct qcom_edp *edp = container_of(hw, struct qcom_edp, dp_link_hw);
    551	const struct phy_configure_opts_dp *dp_opts = &edp->dp_opts;
    552
    553	switch (dp_opts->link_rate) {
    554	case 1620:
    555	case 2700:
    556	case 5400:
    557	case 8100:
    558		return dp_opts->link_rate * 100000;
    559
    560	default:
    561		return 0;
    562	}
    563}
    564
    565static const struct clk_ops qcom_edp_dp_link_clk_ops = {
    566	.determine_rate = qcom_edp_dp_link_clk_determine_rate,
    567	.recalc_rate = qcom_edp_dp_link_clk_recalc_rate,
    568};
    569
    570static int qcom_edp_clks_register(struct qcom_edp *edp, struct device_node *np)
    571{
    572	struct clk_hw_onecell_data *data;
    573	struct clk_init_data init = { };
    574	int ret;
    575
    576	data = devm_kzalloc(edp->dev, struct_size(data, hws, 2), GFP_KERNEL);
    577	if (!data)
    578		return -ENOMEM;
    579
    580	init.ops = &qcom_edp_dp_link_clk_ops;
    581	init.name = "edp_phy_pll_link_clk";
    582	edp->dp_link_hw.init = &init;
    583	ret = devm_clk_hw_register(edp->dev, &edp->dp_link_hw);
    584	if (ret)
    585		return ret;
    586
    587	init.ops = &qcom_edp_dp_pixel_clk_ops;
    588	init.name = "edp_phy_pll_vco_div_clk";
    589	edp->dp_pixel_hw.init = &init;
    590	ret = devm_clk_hw_register(edp->dev, &edp->dp_pixel_hw);
    591	if (ret)
    592		return ret;
    593
    594	data->hws[0] = &edp->dp_link_hw;
    595	data->hws[1] = &edp->dp_pixel_hw;
    596	data->num = 2;
    597
    598	return devm_of_clk_add_hw_provider(edp->dev, of_clk_hw_onecell_get, data);
    599}
    600
    601static int qcom_edp_phy_probe(struct platform_device *pdev)
    602{
    603	struct phy_provider *phy_provider;
    604	struct device *dev = &pdev->dev;
    605	struct qcom_edp *edp;
    606	int ret;
    607
    608	edp = devm_kzalloc(dev, sizeof(*edp), GFP_KERNEL);
    609	if (!edp)
    610		return -ENOMEM;
    611
    612	edp->dev = dev;
    613
    614	edp->edp = devm_platform_ioremap_resource(pdev, 0);
    615	if (IS_ERR(edp->edp))
    616		return PTR_ERR(edp->edp);
    617
    618	edp->tx0 = devm_platform_ioremap_resource(pdev, 1);
    619	if (IS_ERR(edp->tx0))
    620		return PTR_ERR(edp->tx0);
    621
    622	edp->tx1 = devm_platform_ioremap_resource(pdev, 2);
    623	if (IS_ERR(edp->tx1))
    624		return PTR_ERR(edp->tx1);
    625
    626	edp->pll = devm_platform_ioremap_resource(pdev, 3);
    627	if (IS_ERR(edp->pll))
    628		return PTR_ERR(edp->pll);
    629
    630	edp->clks[0].id = "aux";
    631	edp->clks[1].id = "cfg_ahb";
    632	ret = devm_clk_bulk_get(dev, ARRAY_SIZE(edp->clks), edp->clks);
    633	if (ret)
    634		return ret;
    635
    636	edp->supplies[0].supply = "vdda-phy";
    637	edp->supplies[1].supply = "vdda-pll";
    638	ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(edp->supplies), edp->supplies);
    639	if (ret)
    640		return ret;
    641
    642	ret = qcom_edp_clks_register(edp, pdev->dev.of_node);
    643	if (ret)
    644		return ret;
    645
    646	edp->phy = devm_phy_create(dev, pdev->dev.of_node, &qcom_edp_ops);
    647	if (IS_ERR(edp->phy)) {
    648		dev_err(dev, "failed to register phy\n");
    649		return PTR_ERR(edp->phy);
    650	}
    651
    652	phy_set_drvdata(edp->phy, edp);
    653
    654	phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
    655	return PTR_ERR_OR_ZERO(phy_provider);
    656}
    657
    658static const struct of_device_id qcom_edp_phy_match_table[] = {
    659	{ .compatible = "qcom,sc7280-edp-phy" },
    660	{ .compatible = "qcom,sc8180x-edp-phy" },
    661	{ }
    662};
    663MODULE_DEVICE_TABLE(of, qcom_edp_phy_match_table);
    664
    665static struct platform_driver qcom_edp_phy_driver = {
    666	.probe		= qcom_edp_phy_probe,
    667	.driver = {
    668		.name	= "qcom-edp-phy",
    669		.of_match_table = qcom_edp_phy_match_table,
    670	},
    671};
    672
    673module_platform_driver(qcom_edp_phy_driver);
    674
    675MODULE_AUTHOR("Bjorn Andersson <bjorn.andersson@linaro.org>");
    676MODULE_DESCRIPTION("Qualcomm eDP QMP PHY driver");
    677MODULE_LICENSE("GPL v2");