brintos

brintos / linux-shallow public Read only

0
0
Text · 20.9 KiB · 8c8d80b Raw
766 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Copyright (c) 2016, The Linux Foundation. All rights reserved.4 */5 6#include <linux/clk-provider.h>7#include <linux/delay.h>8 9#include "hdmi.h"10 11#define HDMI_VCO_MAX_FREQ			12000000000UL12#define HDMI_VCO_MIN_FREQ			8000000000UL13 14#define HDMI_PCLK_MAX_FREQ			60000000015#define HDMI_PCLK_MIN_FREQ			2500000016 17#define HDMI_HIGH_FREQ_BIT_CLK_THRESHOLD	3400000000UL18#define HDMI_DIG_FREQ_BIT_CLK_THRESHOLD		1500000000UL19#define HDMI_MID_FREQ_BIT_CLK_THRESHOLD		750000000UL20#define HDMI_CORECLK_DIV			521#define HDMI_DEFAULT_REF_CLOCK			1920000022#define HDMI_PLL_CMP_CNT			102423 24#define HDMI_PLL_POLL_MAX_READS			10025#define HDMI_PLL_POLL_TIMEOUT_US		15026 27#define HDMI_NUM_TX_CHANNEL			428 29struct hdmi_pll_8996 {30	struct platform_device *pdev;31	struct clk_hw clk_hw;32 33	/* pll mmio base */34	void __iomem *mmio_qserdes_com;35	/* tx channel base */36	void __iomem *mmio_qserdes_tx[HDMI_NUM_TX_CHANNEL];37};38 39#define hw_clk_to_pll(x) container_of(x, struct hdmi_pll_8996, clk_hw)40 41struct hdmi_8996_phy_pll_reg_cfg {42	u32 tx_lx_lane_mode[HDMI_NUM_TX_CHANNEL];43	u32 tx_lx_tx_band[HDMI_NUM_TX_CHANNEL];44	u32 com_svs_mode_clk_sel;45	u32 com_hsclk_sel;46	u32 com_pll_cctrl_mode0;47	u32 com_pll_rctrl_mode0;48	u32 com_cp_ctrl_mode0;49	u32 com_dec_start_mode0;50	u32 com_div_frac_start1_mode0;51	u32 com_div_frac_start2_mode0;52	u32 com_div_frac_start3_mode0;53	u32 com_integloop_gain0_mode0;54	u32 com_integloop_gain1_mode0;55	u32 com_lock_cmp_en;56	u32 com_lock_cmp1_mode0;57	u32 com_lock_cmp2_mode0;58	u32 com_lock_cmp3_mode0;59	u32 com_core_clk_en;60	u32 com_coreclk_div;61	u32 com_vco_tune_ctrl;62 63	u32 tx_lx_tx_drv_lvl[HDMI_NUM_TX_CHANNEL];64	u32 tx_lx_tx_emp_post1_lvl[HDMI_NUM_TX_CHANNEL];65	u32 tx_lx_vmode_ctrl1[HDMI_NUM_TX_CHANNEL];66	u32 tx_lx_vmode_ctrl2[HDMI_NUM_TX_CHANNEL];67	u32 tx_lx_res_code_lane_tx[HDMI_NUM_TX_CHANNEL];68	u32 tx_lx_hp_pd_enables[HDMI_NUM_TX_CHANNEL];69 70	u32 phy_mode;71};72 73struct hdmi_8996_post_divider {74	u64 vco_freq;75	int hsclk_divsel;76	int vco_ratio;77	int tx_band_sel;78	int half_rate_mode;79};80 81static inline struct hdmi_phy *pll_get_phy(struct hdmi_pll_8996 *pll)82{83	return platform_get_drvdata(pll->pdev);84}85 86static inline void hdmi_pll_write(struct hdmi_pll_8996 *pll, int offset,87				  u32 data)88{89	writel(data, pll->mmio_qserdes_com + offset);90}91 92static inline u32 hdmi_pll_read(struct hdmi_pll_8996 *pll, int offset)93{94	return readl(pll->mmio_qserdes_com + offset);95}96 97static inline void hdmi_tx_chan_write(struct hdmi_pll_8996 *pll, int channel,98				      int offset, int data)99{100	 writel(data, pll->mmio_qserdes_tx[channel] + offset);101}102 103static inline u32 pll_get_cpctrl(u64 frac_start, unsigned long ref_clk,104				 bool gen_ssc)105{106	if ((frac_start != 0) || gen_ssc)107		return (11000000 / (ref_clk / 20));108 109	return 0x23;110}111 112static inline u32 pll_get_rctrl(u64 frac_start, bool gen_ssc)113{114	if ((frac_start != 0) || gen_ssc)115		return 0x16;116 117	return 0x10;118}119 120static inline u32 pll_get_cctrl(u64 frac_start, bool gen_ssc)121{122	if ((frac_start != 0) || gen_ssc)123		return 0x28;124 125	return 0x1;126}127 128static inline u32 pll_get_integloop_gain(u64 frac_start, u64 bclk, u32 ref_clk,129					 bool gen_ssc)130{131	int digclk_divsel = bclk >= HDMI_DIG_FREQ_BIT_CLK_THRESHOLD ? 1 : 2;132	u64 base;133 134	if ((frac_start != 0) || gen_ssc)135		base = (64 * ref_clk) / HDMI_DEFAULT_REF_CLOCK;136	else137		base = (1022 * ref_clk) / 100;138 139	base <<= digclk_divsel;140 141	return (base <= 2046 ? base : 2046);142}143 144static inline u32 pll_get_pll_cmp(u64 fdata, unsigned long ref_clk)145{146	u64 dividend = HDMI_PLL_CMP_CNT * fdata;147	u32 divisor = ref_clk * 10;148	u32 rem;149 150	rem = do_div(dividend, divisor);151	if (rem > (divisor >> 1))152		dividend++;153 154	return dividend - 1;155}156 157static inline u64 pll_cmp_to_fdata(u32 pll_cmp, unsigned long ref_clk)158{159	u64 fdata = ((u64)pll_cmp) * ref_clk * 10;160 161	do_div(fdata, HDMI_PLL_CMP_CNT);162 163	return fdata;164}165 166static int pll_get_post_div(struct hdmi_8996_post_divider *pd, u64 bclk)167{168	int ratio[] = { 2, 3, 4, 5, 6, 9, 10, 12, 14, 15, 20, 21, 25, 28, 35 };169	int hs_divsel[] = { 0, 4, 8, 12, 1, 5, 2, 9, 3, 13, 10, 7, 14, 11, 15 };170	int tx_band_sel[] = { 0, 1, 2, 3 };171	u64 vco_freq[60];172	u64 vco, vco_optimal;173	int half_rate_mode = 0;174	int vco_optimal_index, vco_freq_index;175	int i, j;176 177retry:178	vco_optimal = HDMI_VCO_MAX_FREQ;179	vco_optimal_index = -1;180	vco_freq_index = 0;181	for (i = 0; i < 15; i++) {182		for (j = 0; j < 4; j++) {183			u32 ratio_mult = ratio[i] << tx_band_sel[j];184 185			vco = bclk >> half_rate_mode;186			vco *= ratio_mult;187			vco_freq[vco_freq_index++] = vco;188		}189	}190 191	for (i = 0; i < 60; i++) {192		u64 vco_tmp = vco_freq[i];193 194		if ((vco_tmp >= HDMI_VCO_MIN_FREQ) &&195		    (vco_tmp <= vco_optimal)) {196			vco_optimal = vco_tmp;197			vco_optimal_index = i;198		}199	}200 201	if (vco_optimal_index == -1) {202		if (!half_rate_mode) {203			half_rate_mode = 1;204			goto retry;205		}206	} else {207		pd->vco_freq = vco_optimal;208		pd->tx_band_sel = tx_band_sel[vco_optimal_index % 4];209		pd->vco_ratio = ratio[vco_optimal_index / 4];210		pd->hsclk_divsel = hs_divsel[vco_optimal_index / 4];211 212		return 0;213	}214 215	return -EINVAL;216}217 218static int pll_calculate(unsigned long pix_clk, unsigned long ref_clk,219			 struct hdmi_8996_phy_pll_reg_cfg *cfg)220{221	struct hdmi_8996_post_divider pd;222	u64 bclk;223	u64 tmds_clk;224	u64 dec_start;225	u64 frac_start;226	u64 fdata;227	u32 pll_divisor;228	u32 rem;229	u32 cpctrl;230	u32 rctrl;231	u32 cctrl;232	u32 integloop_gain;233	u32 pll_cmp;234	int i, ret;235 236	/* bit clk = 10 * pix_clk */237	bclk = ((u64)pix_clk) * 10;238 239	if (bclk > HDMI_HIGH_FREQ_BIT_CLK_THRESHOLD)240		tmds_clk = pix_clk >> 2;241	else242		tmds_clk = pix_clk;243 244	ret = pll_get_post_div(&pd, bclk);245	if (ret)246		return ret;247 248	dec_start = pd.vco_freq;249	pll_divisor = 4 * ref_clk;250	do_div(dec_start, pll_divisor);251 252	frac_start = pd.vco_freq * (1 << 20);253 254	rem = do_div(frac_start, pll_divisor);255	frac_start -= dec_start * (1 << 20);256	if (rem > (pll_divisor >> 1))257		frac_start++;258 259	cpctrl = pll_get_cpctrl(frac_start, ref_clk, false);260	rctrl = pll_get_rctrl(frac_start, false);261	cctrl = pll_get_cctrl(frac_start, false);262	integloop_gain = pll_get_integloop_gain(frac_start, bclk,263						ref_clk, false);264 265	fdata = pd.vco_freq;266	do_div(fdata, pd.vco_ratio);267 268	pll_cmp = pll_get_pll_cmp(fdata, ref_clk);269 270	DBG("VCO freq: %llu", pd.vco_freq);271	DBG("fdata: %llu", fdata);272	DBG("pix_clk: %lu", pix_clk);273	DBG("tmds clk: %llu", tmds_clk);274	DBG("HSCLK_SEL: %d", pd.hsclk_divsel);275	DBG("DEC_START: %llu", dec_start);276	DBG("DIV_FRAC_START: %llu", frac_start);277	DBG("PLL_CPCTRL: %u", cpctrl);278	DBG("PLL_RCTRL: %u", rctrl);279	DBG("PLL_CCTRL: %u", cctrl);280	DBG("INTEGLOOP_GAIN: %u", integloop_gain);281	DBG("TX_BAND: %d", pd.tx_band_sel);282	DBG("PLL_CMP: %u", pll_cmp);283 284	/* Convert these values to register specific values */285	if (bclk > HDMI_DIG_FREQ_BIT_CLK_THRESHOLD)286		cfg->com_svs_mode_clk_sel = 1;287	else288		cfg->com_svs_mode_clk_sel = 2;289 290	cfg->com_hsclk_sel = (0x20 | pd.hsclk_divsel);291	cfg->com_pll_cctrl_mode0 = cctrl;292	cfg->com_pll_rctrl_mode0 = rctrl;293	cfg->com_cp_ctrl_mode0 = cpctrl;294	cfg->com_dec_start_mode0 = dec_start;295	cfg->com_div_frac_start1_mode0 = (frac_start & 0xff);296	cfg->com_div_frac_start2_mode0 = ((frac_start & 0xff00) >> 8);297	cfg->com_div_frac_start3_mode0 = ((frac_start & 0xf0000) >> 16);298	cfg->com_integloop_gain0_mode0 = (integloop_gain & 0xff);299	cfg->com_integloop_gain1_mode0 = ((integloop_gain & 0xf00) >> 8);300	cfg->com_lock_cmp1_mode0 = (pll_cmp & 0xff);301	cfg->com_lock_cmp2_mode0 = ((pll_cmp & 0xff00) >> 8);302	cfg->com_lock_cmp3_mode0 = ((pll_cmp & 0x30000) >> 16);303	cfg->com_lock_cmp_en = 0x0;304	cfg->com_core_clk_en = 0x2c;305	cfg->com_coreclk_div = HDMI_CORECLK_DIV;306	cfg->phy_mode = (bclk > HDMI_HIGH_FREQ_BIT_CLK_THRESHOLD) ? 0x10 : 0x0;307	cfg->com_vco_tune_ctrl = 0x0;308 309	cfg->tx_lx_lane_mode[0] =310		cfg->tx_lx_lane_mode[2] = 0x43;311 312	cfg->tx_lx_hp_pd_enables[0] =313		cfg->tx_lx_hp_pd_enables[1] =314		cfg->tx_lx_hp_pd_enables[2] = 0x0c;315	cfg->tx_lx_hp_pd_enables[3] = 0x3;316 317	for (i = 0; i < HDMI_NUM_TX_CHANNEL; i++)318		cfg->tx_lx_tx_band[i] = pd.tx_band_sel + 4;319 320	if (bclk > HDMI_HIGH_FREQ_BIT_CLK_THRESHOLD) {321		cfg->tx_lx_tx_drv_lvl[0] =322			cfg->tx_lx_tx_drv_lvl[1] =323			cfg->tx_lx_tx_drv_lvl[2] = 0x25;324		cfg->tx_lx_tx_drv_lvl[3] = 0x22;325 326		cfg->tx_lx_tx_emp_post1_lvl[0] =327			cfg->tx_lx_tx_emp_post1_lvl[1] =328			cfg->tx_lx_tx_emp_post1_lvl[2] = 0x23;329		cfg->tx_lx_tx_emp_post1_lvl[3] = 0x27;330 331		cfg->tx_lx_vmode_ctrl1[0] =332			cfg->tx_lx_vmode_ctrl1[1] =333			cfg->tx_lx_vmode_ctrl1[2] =334			cfg->tx_lx_vmode_ctrl1[3] = 0x00;335 336		cfg->tx_lx_vmode_ctrl2[0] =337			cfg->tx_lx_vmode_ctrl2[1] =338			cfg->tx_lx_vmode_ctrl2[2] = 0x0D;339 340		cfg->tx_lx_vmode_ctrl2[3] = 0x00;341	} else if (bclk > HDMI_MID_FREQ_BIT_CLK_THRESHOLD) {342		for (i = 0; i < HDMI_NUM_TX_CHANNEL; i++) {343			cfg->tx_lx_tx_drv_lvl[i] = 0x25;344			cfg->tx_lx_tx_emp_post1_lvl[i] = 0x23;345			cfg->tx_lx_vmode_ctrl1[i] = 0x00;346		}347 348		cfg->tx_lx_vmode_ctrl2[0] =349			cfg->tx_lx_vmode_ctrl2[1] =350			cfg->tx_lx_vmode_ctrl2[2] = 0x0D;351		cfg->tx_lx_vmode_ctrl2[3] = 0x00;352	} else {353		for (i = 0; i < HDMI_NUM_TX_CHANNEL; i++) {354			cfg->tx_lx_tx_drv_lvl[i] = 0x20;355			cfg->tx_lx_tx_emp_post1_lvl[i] = 0x20;356			cfg->tx_lx_vmode_ctrl1[i] = 0x00;357			cfg->tx_lx_vmode_ctrl2[i] = 0x0E;358		}359	}360 361	DBG("com_svs_mode_clk_sel = 0x%x", cfg->com_svs_mode_clk_sel);362	DBG("com_hsclk_sel = 0x%x", cfg->com_hsclk_sel);363	DBG("com_lock_cmp_en = 0x%x", cfg->com_lock_cmp_en);364	DBG("com_pll_cctrl_mode0 = 0x%x", cfg->com_pll_cctrl_mode0);365	DBG("com_pll_rctrl_mode0 = 0x%x", cfg->com_pll_rctrl_mode0);366	DBG("com_cp_ctrl_mode0 = 0x%x", cfg->com_cp_ctrl_mode0);367	DBG("com_dec_start_mode0 = 0x%x", cfg->com_dec_start_mode0);368	DBG("com_div_frac_start1_mode0 = 0x%x", cfg->com_div_frac_start1_mode0);369	DBG("com_div_frac_start2_mode0 = 0x%x", cfg->com_div_frac_start2_mode0);370	DBG("com_div_frac_start3_mode0 = 0x%x", cfg->com_div_frac_start3_mode0);371	DBG("com_integloop_gain0_mode0 = 0x%x", cfg->com_integloop_gain0_mode0);372	DBG("com_integloop_gain1_mode0 = 0x%x", cfg->com_integloop_gain1_mode0);373	DBG("com_lock_cmp1_mode0 = 0x%x", cfg->com_lock_cmp1_mode0);374	DBG("com_lock_cmp2_mode0 = 0x%x", cfg->com_lock_cmp2_mode0);375	DBG("com_lock_cmp3_mode0 = 0x%x", cfg->com_lock_cmp3_mode0);376	DBG("com_core_clk_en = 0x%x", cfg->com_core_clk_en);377	DBG("com_coreclk_div = 0x%x", cfg->com_coreclk_div);378	DBG("phy_mode = 0x%x", cfg->phy_mode);379 380	DBG("tx_l0_lane_mode = 0x%x", cfg->tx_lx_lane_mode[0]);381	DBG("tx_l2_lane_mode = 0x%x", cfg->tx_lx_lane_mode[2]);382 383	for (i = 0; i < HDMI_NUM_TX_CHANNEL; i++) {384		DBG("tx_l%d_tx_band = 0x%x", i, cfg->tx_lx_tx_band[i]);385		DBG("tx_l%d_tx_drv_lvl = 0x%x", i, cfg->tx_lx_tx_drv_lvl[i]);386		DBG("tx_l%d_tx_emp_post1_lvl = 0x%x", i,387		    cfg->tx_lx_tx_emp_post1_lvl[i]);388		DBG("tx_l%d_vmode_ctrl1 = 0x%x", i, cfg->tx_lx_vmode_ctrl1[i]);389		DBG("tx_l%d_vmode_ctrl2 = 0x%x", i, cfg->tx_lx_vmode_ctrl2[i]);390	}391 392	return 0;393}394 395static int hdmi_8996_pll_set_clk_rate(struct clk_hw *hw, unsigned long rate,396				      unsigned long parent_rate)397{398	struct hdmi_pll_8996 *pll = hw_clk_to_pll(hw);399	struct hdmi_phy *phy = pll_get_phy(pll);400	struct hdmi_8996_phy_pll_reg_cfg cfg;401	int i, ret;402 403	memset(&cfg, 0x00, sizeof(cfg));404 405	ret = pll_calculate(rate, parent_rate, &cfg);406	if (ret) {407		DRM_ERROR("PLL calculation failed\n");408		return ret;409	}410 411	/* Initially shut down PHY */412	DBG("Disabling PHY");413	hdmi_phy_write(phy, REG_HDMI_8996_PHY_PD_CTL, 0x0);414	udelay(500);415 416	/* Power up sequence */417	hdmi_pll_write(pll, REG_HDMI_PHY_QSERDES_COM_BG_CTRL, 0x04);418 419	hdmi_phy_write(phy, REG_HDMI_8996_PHY_PD_CTL, 0x1);420	hdmi_pll_write(pll, REG_HDMI_PHY_QSERDES_COM_RESETSM_CNTRL, 0x20);421	hdmi_phy_write(phy, REG_HDMI_8996_PHY_TX0_TX1_LANE_CTL, 0x0F);422	hdmi_phy_write(phy, REG_HDMI_8996_PHY_TX2_TX3_LANE_CTL, 0x0F);423 424	for (i = 0; i < HDMI_NUM_TX_CHANNEL; i++) {425		hdmi_tx_chan_write(pll, i,426				   REG_HDMI_PHY_QSERDES_TX_LX_CLKBUF_ENABLE,427				   0x03);428		hdmi_tx_chan_write(pll, i,429				   REG_HDMI_PHY_QSERDES_TX_LX_TX_BAND,430				   cfg.tx_lx_tx_band[i]);431		hdmi_tx_chan_write(pll, i,432				   REG_HDMI_PHY_QSERDES_TX_LX_RESET_TSYNC_EN,433				   0x03);434	}435 436	hdmi_tx_chan_write(pll, 0, REG_HDMI_PHY_QSERDES_TX_LX_LANE_MODE,437			   cfg.tx_lx_lane_mode[0]);438	hdmi_tx_chan_write(pll, 2, REG_HDMI_PHY_QSERDES_TX_LX_LANE_MODE,439			   cfg.tx_lx_lane_mode[2]);440 441	hdmi_pll_write(pll, REG_HDMI_PHY_QSERDES_COM_SYSCLK_BUF_ENABLE, 0x1E);442	hdmi_pll_write(pll, REG_HDMI_PHY_QSERDES_COM_BIAS_EN_CLKBUFLR_EN, 0x07);443	hdmi_pll_write(pll, REG_HDMI_PHY_QSERDES_COM_SYSCLK_EN_SEL, 0x37);444	hdmi_pll_write(pll, REG_HDMI_PHY_QSERDES_COM_SYS_CLK_CTRL, 0x02);445	hdmi_pll_write(pll, REG_HDMI_PHY_QSERDES_COM_CLK_ENABLE1, 0x0E);446 447	/* Bypass VCO calibration */448	hdmi_pll_write(pll, REG_HDMI_PHY_QSERDES_COM_SVS_MODE_CLK_SEL,449		       cfg.com_svs_mode_clk_sel);450 451	hdmi_pll_write(pll, REG_HDMI_PHY_QSERDES_COM_BG_TRIM, 0x0F);452	hdmi_pll_write(pll, REG_HDMI_PHY_QSERDES_COM_PLL_IVCO, 0x0F);453	hdmi_pll_write(pll, REG_HDMI_PHY_QSERDES_COM_VCO_TUNE_CTRL,454		       cfg.com_vco_tune_ctrl);455 456	hdmi_pll_write(pll, REG_HDMI_PHY_QSERDES_COM_BG_CTRL, 0x06);457 458	hdmi_pll_write(pll, REG_HDMI_PHY_QSERDES_COM_CLK_SELECT, 0x30);459	hdmi_pll_write(pll, REG_HDMI_PHY_QSERDES_COM_HSCLK_SEL,460		       cfg.com_hsclk_sel);461	hdmi_pll_write(pll, REG_HDMI_PHY_QSERDES_COM_LOCK_CMP_EN,462		       cfg.com_lock_cmp_en);463 464	hdmi_pll_write(pll, REG_HDMI_PHY_QSERDES_COM_PLL_CCTRL_MODE0,465		       cfg.com_pll_cctrl_mode0);466	hdmi_pll_write(pll, REG_HDMI_PHY_QSERDES_COM_PLL_RCTRL_MODE0,467		       cfg.com_pll_rctrl_mode0);468	hdmi_pll_write(pll, REG_HDMI_PHY_QSERDES_COM_CP_CTRL_MODE0,469		       cfg.com_cp_ctrl_mode0);470	hdmi_pll_write(pll, REG_HDMI_PHY_QSERDES_COM_DEC_START_MODE0,471		       cfg.com_dec_start_mode0);472	hdmi_pll_write(pll, REG_HDMI_PHY_QSERDES_COM_DIV_FRAC_START1_MODE0,473		       cfg.com_div_frac_start1_mode0);474	hdmi_pll_write(pll, REG_HDMI_PHY_QSERDES_COM_DIV_FRAC_START2_MODE0,475		       cfg.com_div_frac_start2_mode0);476	hdmi_pll_write(pll, REG_HDMI_PHY_QSERDES_COM_DIV_FRAC_START3_MODE0,477		       cfg.com_div_frac_start3_mode0);478 479	hdmi_pll_write(pll, REG_HDMI_PHY_QSERDES_COM_INTEGLOOP_GAIN0_MODE0,480		       cfg.com_integloop_gain0_mode0);481	hdmi_pll_write(pll, REG_HDMI_PHY_QSERDES_COM_INTEGLOOP_GAIN1_MODE0,482		       cfg.com_integloop_gain1_mode0);483 484	hdmi_pll_write(pll, REG_HDMI_PHY_QSERDES_COM_LOCK_CMP1_MODE0,485		       cfg.com_lock_cmp1_mode0);486	hdmi_pll_write(pll, REG_HDMI_PHY_QSERDES_COM_LOCK_CMP2_MODE0,487		       cfg.com_lock_cmp2_mode0);488	hdmi_pll_write(pll, REG_HDMI_PHY_QSERDES_COM_LOCK_CMP3_MODE0,489		       cfg.com_lock_cmp3_mode0);490 491	hdmi_pll_write(pll, REG_HDMI_PHY_QSERDES_COM_VCO_TUNE_MAP, 0x00);492	hdmi_pll_write(pll, REG_HDMI_PHY_QSERDES_COM_CORE_CLK_EN,493		       cfg.com_core_clk_en);494	hdmi_pll_write(pll, REG_HDMI_PHY_QSERDES_COM_CORECLK_DIV,495		       cfg.com_coreclk_div);496	hdmi_pll_write(pll, REG_HDMI_PHY_QSERDES_COM_CMN_CONFIG, 0x02);497 498	hdmi_pll_write(pll, REG_HDMI_PHY_QSERDES_COM_RESCODE_DIV_NUM, 0x15);499 500	/* TX lanes setup (TX 0/1/2/3) */501	for (i = 0; i < HDMI_NUM_TX_CHANNEL; i++) {502		hdmi_tx_chan_write(pll, i,503				   REG_HDMI_PHY_QSERDES_TX_LX_TX_DRV_LVL,504				   cfg.tx_lx_tx_drv_lvl[i]);505		hdmi_tx_chan_write(pll, i,506				   REG_HDMI_PHY_QSERDES_TX_LX_TX_EMP_POST1_LVL,507				   cfg.tx_lx_tx_emp_post1_lvl[i]);508		hdmi_tx_chan_write(pll, i,509				   REG_HDMI_PHY_QSERDES_TX_LX_VMODE_CTRL1,510				   cfg.tx_lx_vmode_ctrl1[i]);511		hdmi_tx_chan_write(pll, i,512				   REG_HDMI_PHY_QSERDES_TX_LX_VMODE_CTRL2,513				   cfg.tx_lx_vmode_ctrl2[i]);514		hdmi_tx_chan_write(pll, i,515				   REG_HDMI_PHY_QSERDES_TX_LX_TX_DRV_LVL_OFFSET,516				   0x00);517		hdmi_tx_chan_write(pll, i,518			REG_HDMI_PHY_QSERDES_TX_LX_RES_CODE_LANE_OFFSET,519			0x00);520		hdmi_tx_chan_write(pll, i,521			REG_HDMI_PHY_QSERDES_TX_LX_TRAN_DRVR_EMP_EN,522			0x03);523		hdmi_tx_chan_write(pll, i,524			REG_HDMI_PHY_QSERDES_TX_LX_PARRATE_REC_DETECT_IDLE_EN,525			0x40);526		hdmi_tx_chan_write(pll, i,527				   REG_HDMI_PHY_QSERDES_TX_LX_HP_PD_ENABLES,528				   cfg.tx_lx_hp_pd_enables[i]);529	}530 531	hdmi_phy_write(phy, REG_HDMI_8996_PHY_MODE, cfg.phy_mode);532	hdmi_phy_write(phy, REG_HDMI_8996_PHY_PD_CTL, 0x1F);533 534	/*535	 * Ensure that vco configuration gets flushed to hardware before536	 * enabling the PLL537	 */538	wmb();539 540	return 0;541}542 543static int hdmi_8996_phy_ready_status(struct hdmi_phy *phy)544{545	u32 nb_tries = HDMI_PLL_POLL_MAX_READS;546	unsigned long timeout = HDMI_PLL_POLL_TIMEOUT_US;547	u32 status;548	int phy_ready = 0;549 550	DBG("Waiting for PHY ready");551 552	while (nb_tries--) {553		status = hdmi_phy_read(phy, REG_HDMI_8996_PHY_STATUS);554		phy_ready = status & BIT(0);555 556		if (phy_ready)557			break;558 559		udelay(timeout);560	}561 562	DBG("PHY is %sready", phy_ready ? "" : "*not* ");563 564	return phy_ready;565}566 567static int hdmi_8996_pll_lock_status(struct hdmi_pll_8996 *pll)568{569	u32 status;570	int nb_tries = HDMI_PLL_POLL_MAX_READS;571	unsigned long timeout = HDMI_PLL_POLL_TIMEOUT_US;572	int pll_locked = 0;573 574	DBG("Waiting for PLL lock");575 576	while (nb_tries--) {577		status = hdmi_pll_read(pll,578				       REG_HDMI_PHY_QSERDES_COM_C_READY_STATUS);579		pll_locked = status & BIT(0);580 581		if (pll_locked)582			break;583 584		udelay(timeout);585	}586 587	DBG("HDMI PLL is %slocked", pll_locked ? "" : "*not* ");588 589	return pll_locked;590}591 592static int hdmi_8996_pll_prepare(struct clk_hw *hw)593{594	struct hdmi_pll_8996 *pll = hw_clk_to_pll(hw);595	struct hdmi_phy *phy = pll_get_phy(pll);596	int i, ret = 0;597 598	hdmi_phy_write(phy, REG_HDMI_8996_PHY_CFG, 0x1);599	udelay(100);600 601	hdmi_phy_write(phy, REG_HDMI_8996_PHY_CFG, 0x19);602	udelay(100);603 604	ret = hdmi_8996_pll_lock_status(pll);605	if (!ret)606		return ret;607 608	for (i = 0; i < HDMI_NUM_TX_CHANNEL; i++)609		hdmi_tx_chan_write(pll, i,610			REG_HDMI_PHY_QSERDES_TX_LX_HIGHZ_TRANSCEIVEREN_BIAS_DRVR_EN,611			0x6F);612 613	/* Disable SSC */614	hdmi_pll_write(pll, REG_HDMI_PHY_QSERDES_COM_SSC_PER1, 0x0);615	hdmi_pll_write(pll, REG_HDMI_PHY_QSERDES_COM_SSC_PER2, 0x0);616	hdmi_pll_write(pll, REG_HDMI_PHY_QSERDES_COM_SSC_STEP_SIZE1, 0x0);617	hdmi_pll_write(pll, REG_HDMI_PHY_QSERDES_COM_SSC_STEP_SIZE2, 0x0);618	hdmi_pll_write(pll, REG_HDMI_PHY_QSERDES_COM_SSC_EN_CENTER, 0x2);619 620	ret = hdmi_8996_phy_ready_status(phy);621	if (!ret)622		return ret;623 624	/* Restart the retiming buffer */625	hdmi_phy_write(phy, REG_HDMI_8996_PHY_CFG, 0x18);626	udelay(1);627	hdmi_phy_write(phy, REG_HDMI_8996_PHY_CFG, 0x19);628 629	return 0;630}631 632static long hdmi_8996_pll_round_rate(struct clk_hw *hw,633				     unsigned long rate,634				     unsigned long *parent_rate)635{636	if (rate < HDMI_PCLK_MIN_FREQ)637		return HDMI_PCLK_MIN_FREQ;638	else if (rate > HDMI_PCLK_MAX_FREQ)639		return HDMI_PCLK_MAX_FREQ;640	else641		return rate;642}643 644static unsigned long hdmi_8996_pll_recalc_rate(struct clk_hw *hw,645					       unsigned long parent_rate)646{647	struct hdmi_pll_8996 *pll = hw_clk_to_pll(hw);648	u64 fdata;649	u32 cmp1, cmp2, cmp3, pll_cmp;650 651	cmp1 = hdmi_pll_read(pll, REG_HDMI_PHY_QSERDES_COM_LOCK_CMP1_MODE0);652	cmp2 = hdmi_pll_read(pll, REG_HDMI_PHY_QSERDES_COM_LOCK_CMP2_MODE0);653	cmp3 = hdmi_pll_read(pll, REG_HDMI_PHY_QSERDES_COM_LOCK_CMP3_MODE0);654 655	pll_cmp = cmp1 | (cmp2 << 8) | (cmp3 << 16);656 657	fdata = pll_cmp_to_fdata(pll_cmp + 1, parent_rate);658 659	do_div(fdata, 10);660 661	return fdata;662}663 664static void hdmi_8996_pll_unprepare(struct clk_hw *hw)665{666	struct hdmi_pll_8996 *pll = hw_clk_to_pll(hw);667	struct hdmi_phy *phy = pll_get_phy(pll);668 669	hdmi_phy_write(phy, REG_HDMI_8996_PHY_CFG, 0x6);670	usleep_range(100, 150);671}672 673static int hdmi_8996_pll_is_enabled(struct clk_hw *hw)674{675	struct hdmi_pll_8996 *pll = hw_clk_to_pll(hw);676	u32 status;677	int pll_locked;678 679	status = hdmi_pll_read(pll, REG_HDMI_PHY_QSERDES_COM_C_READY_STATUS);680	pll_locked = status & BIT(0);681 682	return pll_locked;683}684 685static const struct clk_ops hdmi_8996_pll_ops = {686	.set_rate = hdmi_8996_pll_set_clk_rate,687	.round_rate = hdmi_8996_pll_round_rate,688	.recalc_rate = hdmi_8996_pll_recalc_rate,689	.prepare = hdmi_8996_pll_prepare,690	.unprepare = hdmi_8996_pll_unprepare,691	.is_enabled = hdmi_8996_pll_is_enabled,692};693 694static const struct clk_init_data pll_init = {695	.name = "hdmipll",696	.ops = &hdmi_8996_pll_ops,697	.parent_data = (const struct clk_parent_data[]){698		{ .fw_name = "xo", .name = "xo_board" },699	},700	.num_parents = 1,701	.flags = CLK_IGNORE_UNUSED,702};703 704int msm_hdmi_pll_8996_init(struct platform_device *pdev)705{706	struct device *dev = &pdev->dev;707	struct hdmi_pll_8996 *pll;708	int i, ret;709 710	pll = devm_kzalloc(dev, sizeof(*pll), GFP_KERNEL);711	if (!pll)712		return -ENOMEM;713 714	pll->pdev = pdev;715 716	pll->mmio_qserdes_com = msm_ioremap(pdev, "hdmi_pll");717	if (IS_ERR(pll->mmio_qserdes_com)) {718		DRM_DEV_ERROR(dev, "failed to map pll base\n");719		return -ENOMEM;720	}721 722	for (i = 0; i < HDMI_NUM_TX_CHANNEL; i++) {723		char name[32];724 725		snprintf(name, sizeof(name), "hdmi_tx_l%d", i);726 727		pll->mmio_qserdes_tx[i] = msm_ioremap(pdev, name);728		if (IS_ERR(pll->mmio_qserdes_tx[i])) {729			DRM_DEV_ERROR(dev, "failed to map pll base\n");730			return -ENOMEM;731		}732	}733	pll->clk_hw.init = &pll_init;734 735	ret = devm_clk_hw_register(dev, &pll->clk_hw);736	if (ret) {737		DRM_DEV_ERROR(dev, "failed to register pll clock\n");738		return ret;739	}740 741	ret = devm_of_clk_add_hw_provider(dev, of_clk_hw_simple_get, &pll->clk_hw);742	if (ret) {743		DRM_DEV_ERROR(dev, "%s: failed to register clk provider: %d\n", __func__, ret);744		return ret;745	}746 747	return 0;748}749 750static const char * const hdmi_phy_8996_reg_names[] = {751	"vddio",752	"vcca",753};754 755static const char * const hdmi_phy_8996_clk_names[] = {756	"iface", "ref",757};758 759const struct hdmi_phy_cfg msm_hdmi_phy_8996_cfg = {760	.type = MSM_HDMI_PHY_8996,761	.reg_names = hdmi_phy_8996_reg_names,762	.num_regs = ARRAY_SIZE(hdmi_phy_8996_reg_names),763	.clk_names = hdmi_phy_8996_clk_names,764	.num_clks = ARRAY_SIZE(hdmi_phy_8996_clk_names),765};766