hdmi_phy_8996.c 21 KB

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