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