1 // SPDX-License-Identifier: MIT 2 /* 3 * Copyright © 2025 Synopsys, Inc., Intel Corporation 4 */ 5 6 #include <linux/math.h> 7 8 #include "intel_cx0_phy_regs.h" 9 #include "intel_display_types.h" 10 #include "intel_snps_phy.h" 11 #include "intel_snps_phy_regs.h" 12 #include "intel_snps_hdmi_pll.h" 13 14 #define INTEL_SNPS_PHY_HDMI_4999MHZ 4999999900ULL 15 #define INTEL_SNPS_PHY_HDMI_16GHZ 16000000000ULL 16 #define INTEL_SNPS_PHY_HDMI_9999MHZ (2 * INTEL_SNPS_PHY_HDMI_4999MHZ) 17 18 #define CURVE0_MULTIPLIER 1000000000 19 #define CURVE1_MULTIPLIER 100 20 #define CURVE2_MULTIPLIER 1000000000000ULL 21 22 struct pll_output_params { 23 u32 ssc_up_spread; 24 u32 mpll_div5_en; 25 u32 hdmi_div; 26 u32 ana_cp_int; 27 u32 ana_cp_prop; 28 u32 refclk_postscalar; 29 u32 tx_clk_div; 30 u32 fracn_quot; 31 u32 fracn_rem; 32 u32 fracn_den; 33 u32 fracn_en; 34 u32 pmix_en; 35 u32 multiplier; 36 int mpll_ana_v2i; 37 int ana_freq_vco; 38 }; 39 40 static s64 interp(s64 x, s64 x1, s64 x2, s64 y1, s64 y2) 41 { 42 s64 dydx; 43 44 dydx = DIV_ROUND_UP_ULL((y2 - y1) * 100000, (x2 - x1)); 45 46 return (y1 + DIV_ROUND_UP_ULL(dydx * (x - x1), 100000)); 47 } 48 49 static void get_ana_cp_int_prop(u32 vco_clk, 50 u32 refclk_postscalar, 51 int mpll_ana_v2i, 52 int c, int a, 53 const u64 curve_freq_hz[2][8], 54 const u64 curve_0[2][8], 55 const u64 curve_1[2][8], 56 const u64 curve_2[2][8], 57 u32 *ana_cp_int, 58 u32 *ana_cp_prop) 59 { 60 u64 vco_div_refclk_float; 61 u64 curve_0_interpolated; 62 u64 curve_2_interpolated; 63 u64 curve_1_interpolated; 64 u64 curve_2_scaled1; 65 u64 curve_2_scaled2; 66 u64 adjusted_vco_clk1; 67 u64 adjusted_vco_clk2; 68 u64 curve_2_scaled_int; 69 u64 interpolated_product; 70 u64 scaled_interpolated_sqrt; 71 u64 scaled_vco_div_refclk1; 72 u64 scaled_vco_div_refclk2; 73 u64 ana_cp_int_temp; 74 u64 temp; 75 76 vco_div_refclk_float = vco_clk * DIV_ROUND_DOWN_ULL(1000000000000ULL, refclk_postscalar); 77 78 /* Interpolate curve values at the target vco_clk frequency */ 79 curve_0_interpolated = interp(vco_clk, curve_freq_hz[c][a], curve_freq_hz[c][a + 1], 80 curve_0[c][a], curve_0[c][a + 1]); 81 82 curve_2_interpolated = interp(vco_clk, curve_freq_hz[c][a], curve_freq_hz[c][a + 1], 83 curve_2[c][a], curve_2[c][a + 1]); 84 85 curve_1_interpolated = interp(vco_clk, curve_freq_hz[c][a], curve_freq_hz[c][a + 1], 86 curve_1[c][a], curve_1[c][a + 1]); 87 88 curve_1_interpolated = DIV_ROUND_DOWN_ULL(curve_1_interpolated, CURVE1_MULTIPLIER); 89 90 /* 91 * Scale curve_2_interpolated based on mpll_ana_v2i, for integer part 92 * ana_cp_int and for the proportional part ana_cp_prop 93 */ 94 temp = curve_2_interpolated * (4 - mpll_ana_v2i); 95 curve_2_scaled1 = DIV_ROUND_DOWN_ULL(temp, 16000); 96 curve_2_scaled2 = DIV_ROUND_DOWN_ULL(temp, 160); 97 98 /* Scale vco_div_refclk for ana_cp_int */ 99 scaled_vco_div_refclk1 = 112008301 * DIV_ROUND_DOWN_ULL(vco_div_refclk_float, 100000); 100 101 adjusted_vco_clk1 = CURVE2_MULTIPLIER * 102 DIV_ROUND_DOWN_ULL(scaled_vco_div_refclk1, (curve_0_interpolated * 103 DIV_ROUND_DOWN_ULL(curve_1_interpolated, CURVE0_MULTIPLIER))); 104 105 ana_cp_int_temp = 106 DIV_ROUND_CLOSEST_ULL(DIV_ROUND_DOWN_ULL(adjusted_vco_clk1, curve_2_scaled1), 107 CURVE2_MULTIPLIER); 108 109 *ana_cp_int = max(1, min(ana_cp_int_temp, 127)); 110 111 curve_2_scaled_int = curve_2_scaled1 * (*ana_cp_int); 112 113 interpolated_product = curve_1_interpolated * 114 (curve_2_scaled_int * DIV_ROUND_DOWN_ULL(curve_0_interpolated, 115 CURVE0_MULTIPLIER)); 116 117 scaled_interpolated_sqrt = 118 int_sqrt(DIV_ROUND_UP_ULL(interpolated_product, vco_div_refclk_float) * 119 DIV_ROUND_DOWN_ULL(1000000000000ULL, 55)); 120 121 /* Scale vco_div_refclk for ana_cp_int */ 122 scaled_vco_div_refclk2 = DIV_ROUND_UP_ULL(vco_div_refclk_float, 1000000); 123 adjusted_vco_clk2 = 1460281 * DIV_ROUND_UP_ULL(scaled_interpolated_sqrt * 124 scaled_vco_div_refclk2, 125 curve_1_interpolated); 126 127 *ana_cp_prop = DIV_ROUND_UP_ULL(adjusted_vco_clk2, curve_2_scaled2); 128 *ana_cp_prop = max(1, min(*ana_cp_prop, 127)); 129 } 130 131 static void compute_hdmi_tmds_pll(u64 pixel_clock, u32 refclk, 132 u32 ref_range, 133 u32 ana_cp_int_gs, 134 u32 ana_cp_prop_gs, 135 const u64 curve_freq_hz[2][8], 136 const u64 curve_0[2][8], 137 const u64 curve_1[2][8], 138 const u64 curve_2[2][8], 139 u32 prescaler_divider, 140 struct pll_output_params *pll_params) 141 { 142 u64 datarate = pixel_clock * 10000; 143 u32 ssc_up_spread = 1; 144 u32 mpll_div5_en = 1; 145 u32 hdmi_div = 1; 146 u32 ana_cp_int; 147 u32 ana_cp_prop; 148 u32 refclk_postscalar = refclk >> prescaler_divider; 149 u32 tx_clk_div; 150 u64 vco_clk; 151 u64 vco_clk_do_div; 152 u32 vco_div_refclk_integer; 153 u32 vco_div_refclk_fracn; 154 u32 fracn_quot; 155 u32 fracn_rem; 156 u32 fracn_den; 157 u32 fracn_en; 158 u32 pmix_en; 159 u32 multiplier; 160 int mpll_ana_v2i; 161 int ana_freq_vco = 0; 162 int c, a = 0; 163 int i; 164 165 /* Select appropriate v2i point */ 166 if (datarate <= INTEL_SNPS_PHY_HDMI_9999MHZ) { 167 mpll_ana_v2i = 2; 168 tx_clk_div = ilog2(DIV_ROUND_DOWN_ULL(INTEL_SNPS_PHY_HDMI_9999MHZ, datarate)); 169 } else { 170 mpll_ana_v2i = 3; 171 tx_clk_div = ilog2(DIV_ROUND_DOWN_ULL(INTEL_SNPS_PHY_HDMI_16GHZ, datarate)); 172 } 173 vco_clk = (datarate << tx_clk_div) >> 1; 174 175 vco_div_refclk_integer = DIV_ROUND_DOWN_ULL(vco_clk, refclk_postscalar); 176 vco_clk_do_div = do_div(vco_clk, refclk_postscalar); 177 vco_div_refclk_fracn = DIV_ROUND_DOWN_ULL(vco_clk_do_div << 32, refclk_postscalar); 178 179 fracn_quot = vco_div_refclk_fracn >> 16; 180 fracn_rem = vco_div_refclk_fracn & 0xffff; 181 fracn_rem = fracn_rem - (fracn_rem >> 15); 182 fracn_den = 0xffff; 183 fracn_en = (fracn_quot != 0 || fracn_rem != 0) ? 1 : 0; 184 pmix_en = fracn_en; 185 multiplier = (vco_div_refclk_integer - 16) * 2; 186 /* Curve selection for ana_cp_* calculations. One curve hardcoded per v2i range */ 187 c = mpll_ana_v2i - 2; 188 189 /* Find the right segment of the table */ 190 for (i = 0; i < 8; i += 2) { 191 if (vco_clk <= curve_freq_hz[c][i + 1]) { 192 a = i; 193 ana_freq_vco = 3 - (a >> 1); 194 break; 195 } 196 } 197 198 get_ana_cp_int_prop(vco_clk, refclk_postscalar, mpll_ana_v2i, c, a, 199 curve_freq_hz, curve_0, curve_1, curve_2, 200 &ana_cp_int, &ana_cp_prop); 201 202 pll_params->ssc_up_spread = ssc_up_spread; 203 pll_params->mpll_div5_en = mpll_div5_en; 204 pll_params->hdmi_div = hdmi_div; 205 pll_params->ana_cp_int = ana_cp_int; 206 pll_params->refclk_postscalar = refclk_postscalar; 207 pll_params->tx_clk_div = tx_clk_div; 208 pll_params->fracn_quot = fracn_quot; 209 pll_params->fracn_rem = fracn_rem; 210 pll_params->fracn_den = fracn_den; 211 pll_params->fracn_en = fracn_en; 212 pll_params->pmix_en = pmix_en; 213 pll_params->multiplier = multiplier; 214 pll_params->ana_cp_prop = ana_cp_prop; 215 pll_params->mpll_ana_v2i = mpll_ana_v2i; 216 pll_params->ana_freq_vco = ana_freq_vco; 217 } 218 219 void intel_snps_hdmi_pll_compute_mpllb(struct intel_mpllb_state *pll_state, u64 pixel_clock) 220 { 221 /* x axis frequencies. One curve in each array per v2i point */ 222 static const u64 dg2_curve_freq_hz[2][8] = { 223 { 2500000000ULL, 3000000000ULL, 3000000000ULL, 3500000000ULL, 3500000000ULL, 224 4000000000ULL, 4000000000ULL, 5000000000ULL }, 225 { 4000000000ULL, 4600000000ULL, 4601000000ULL, 5400000000ULL, 5401000000ULL, 226 6600000000ULL, 6601000000ULL, 8001000000ULL } 227 }; 228 229 /* y axis heights multiplied with 1000000000 */ 230 static const u64 dg2_curve_0[2][8] = { 231 { 34149871, 39803269, 36034544, 40601014, 35646940, 40016109, 35127987, 41889522 }, 232 { 70000000, 78770454, 70451838, 80427119, 70991400, 84230173, 72945921, 87064218 } 233 }; 234 235 /* Multiplied with 100 */ 236 static const u64 dg2_curve_1[2][8] = { 237 { 85177000000000ULL, 79385227160000ULL, 95672603580000ULL, 88857207160000ULL, 238 109379790900000ULL, 103528193900000ULL, 131941242400000ULL, 117279000000000ULL }, 239 { 60255000000000ULL, 55569000000000ULL, 72036000000000ULL, 69509000000000ULL, 240 81785000000000ULL, 731030000000000ULL, 96591000000000ULL, 69077000000000ULL } 241 }; 242 243 /* Multiplied with 1000000000000 */ 244 static const u64 dg2_curve_2[2][8] = { 245 { 2186930000ULL, 2835287134ULL, 2395395343ULL, 2932270687ULL, 2351887545ULL, 246 2861031697ULL, 2294149152ULL, 3091730000ULL }, 247 { 4560000000ULL, 5570000000ULL, 4610000000ULL, 5770000000ULL, 4670000000ULL, 248 6240000000ULL, 4890000000ULL, 6600000000ULL } 249 }; 250 251 struct pll_output_params pll_params; 252 u32 refclk = 100000000; 253 u32 prescaler_divider = 1; 254 u32 ref_range = 3; 255 u32 ana_cp_int_gs = 64; 256 u32 ana_cp_prop_gs = 124; 257 258 compute_hdmi_tmds_pll(pixel_clock, refclk, ref_range, ana_cp_int_gs, ana_cp_prop_gs, 259 dg2_curve_freq_hz, dg2_curve_0, dg2_curve_1, dg2_curve_2, 260 prescaler_divider, &pll_params); 261 262 pll_state->clock = pixel_clock; 263 pll_state->ref_control = 264 REG_FIELD_PREP(SNPS_PHY_REF_CONTROL_REF_RANGE, ref_range); 265 pll_state->mpllb_cp = 266 REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_INT, pll_params.ana_cp_int) | 267 REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_PROP, pll_params.ana_cp_prop) | 268 REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_INT_GS, ana_cp_int_gs) | 269 REG_FIELD_PREP(SNPS_PHY_MPLLB_CP_PROP_GS, ana_cp_prop_gs); 270 pll_state->mpllb_div = 271 REG_FIELD_PREP(SNPS_PHY_MPLLB_DIV5_CLK_EN, pll_params.mpll_div5_en) | 272 REG_FIELD_PREP(SNPS_PHY_MPLLB_TX_CLK_DIV, pll_params.tx_clk_div) | 273 REG_FIELD_PREP(SNPS_PHY_MPLLB_PMIX_EN, pll_params.pmix_en) | 274 REG_FIELD_PREP(SNPS_PHY_MPLLB_V2I, pll_params.mpll_ana_v2i) | 275 REG_FIELD_PREP(SNPS_PHY_MPLLB_FREQ_VCO, pll_params.ana_freq_vco); 276 pll_state->mpllb_div2 = 277 REG_FIELD_PREP(SNPS_PHY_MPLLB_REF_CLK_DIV, prescaler_divider) | 278 REG_FIELD_PREP(SNPS_PHY_MPLLB_MULTIPLIER, pll_params.multiplier) | 279 REG_FIELD_PREP(SNPS_PHY_MPLLB_HDMI_DIV, pll_params.hdmi_div); 280 pll_state->mpllb_fracn1 = 281 REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_CGG_UPDATE_EN, 1) | 282 REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_EN, pll_params.fracn_en) | 283 REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_DEN, pll_params.fracn_den); 284 pll_state->mpllb_fracn2 = 285 REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_QUOT, pll_params.fracn_quot) | 286 REG_FIELD_PREP(SNPS_PHY_MPLLB_FRACN_REM, pll_params.fracn_rem); 287 pll_state->mpllb_sscen = 288 REG_FIELD_PREP(SNPS_PHY_MPLLB_SSC_UP_SPREAD, pll_params.ssc_up_spread); 289 } 290 291 void intel_snps_hdmi_pll_compute_c10pll(struct intel_c10pll_state *pll_state, u64 pixel_clock) 292 { 293 /* x axis frequencies. One curve in each array per v2i point */ 294 static const u64 c10_curve_freq_hz[2][8] = { 295 { 2500000000ULL, 3000000000ULL, 3000000000ULL, 3500000000ULL, 3500000000ULL, 296 4000000000ULL, 4000000000ULL, 5000000000ULL }, 297 { 4000000000ULL, 4600000000ULL, 4601000000ULL, 5400000000ULL, 5401000000ULL, 298 6600000000ULL, 6601000000ULL, 8001000000ULL } 299 }; 300 301 /* y axis heights multiplied with 1000000000 */ 302 static const u64 c10_curve_0[2][8] = { 303 { 41174500, 48605500, 42973700, 49433100, 42408600, 47681900, 40297400, 49131400 }, 304 { 82056800, 94420700, 82323400, 96370600, 81273300, 98630100, 81728700, 99105700} 305 }; 306 307 static const u64 c10_curve_1[2][8] = { 308 { 73300000000000ULL, 66000000000000ULL, 83100000000000ULL, 75300000000000ULL, 309 99700000000000ULL, 92300000000000ULL, 125000000000000ULL, 110000000000000ULL }, 310 { 53700000000000ULL, 47700000000000ULL, 62200000000000ULL, 54400000000000ULL, 311 75100000000000ULL, 63400000000000ULL, 90600000000000ULL, 76300000000000ULL } 312 }; 313 314 /* Multiplied with 1000000000000 */ 315 static const u64 c10_curve_2[2][8] = { 316 { 2415790000ULL, 3136460000ULL, 2581990000ULL, 3222670000ULL, 2529330000ULL, 317 3042020000ULL, 2336970000ULL, 3191460000ULL}, 318 { 4808390000ULL, 5994250000ULL, 4832730000ULL, 6193730000ULL, 4737700000ULL, 319 6428750000ULL, 4779200000ULL, 6479340000ULL } 320 }; 321 322 struct pll_output_params pll_params; 323 u32 refclk = 38400000; 324 u32 prescaler_divider = 0; 325 u32 ref_range = 1; 326 u32 ana_cp_int_gs = 30; 327 u32 ana_cp_prop_gs = 28; 328 329 compute_hdmi_tmds_pll(pixel_clock, refclk, ref_range, 330 ana_cp_int_gs, ana_cp_prop_gs, 331 c10_curve_freq_hz, c10_curve_0, 332 c10_curve_1, c10_curve_2, prescaler_divider, 333 &pll_params); 334 335 pll_state->tx = 0x10; 336 pll_state->cmn = 0x1; 337 pll_state->pll[0] = REG_FIELD_PREP(C10_PLL0_DIV5CLK_EN, pll_params.mpll_div5_en) | 338 REG_FIELD_PREP(C10_PLL0_FRACEN, pll_params.fracn_en) | 339 REG_FIELD_PREP(C10_PLL0_PMIX_EN, pll_params.pmix_en) | 340 REG_FIELD_PREP(C10_PLL0_ANA_FREQ_VCO_MASK, pll_params.ana_freq_vco); 341 pll_state->pll[2] = REG_FIELD_PREP(C10_PLL2_MULTIPLIERL_MASK, pll_params.multiplier); 342 pll_state->pll[3] = REG_FIELD_PREP(C10_PLL3_MULTIPLIERH_MASK, pll_params.multiplier >> 8); 343 pll_state->pll[8] = REG_FIELD_PREP(C10_PLL8_SSC_UP_SPREAD, pll_params.ssc_up_spread); 344 pll_state->pll[9] = REG_FIELD_PREP(C10_PLL9_FRACN_DENL_MASK, pll_params.fracn_den); 345 pll_state->pll[10] = REG_FIELD_PREP(C10_PLL10_FRACN_DENH_MASK, pll_params.fracn_den >> 8); 346 pll_state->pll[11] = REG_FIELD_PREP(C10_PLL11_FRACN_QUOT_L_MASK, pll_params.fracn_quot); 347 pll_state->pll[12] = REG_FIELD_PREP(C10_PLL12_FRACN_QUOT_H_MASK, 348 pll_params.fracn_quot >> 8); 349 350 pll_state->pll[13] = REG_FIELD_PREP(C10_PLL13_FRACN_REM_L_MASK, pll_params.fracn_rem); 351 pll_state->pll[14] = REG_FIELD_PREP(C10_PLL14_FRACN_REM_H_MASK, pll_params.fracn_rem >> 8); 352 pll_state->pll[15] = REG_FIELD_PREP(C10_PLL15_TXCLKDIV_MASK, pll_params.tx_clk_div) | 353 REG_FIELD_PREP(C10_PLL15_HDMIDIV_MASK, pll_params.hdmi_div); 354 pll_state->pll[16] = REG_FIELD_PREP(C10_PLL16_ANA_CPINT, pll_params.ana_cp_int) | 355 REG_FIELD_PREP(C10_PLL16_ANA_CPINTGS_L, ana_cp_int_gs); 356 pll_state->pll[17] = REG_FIELD_PREP(C10_PLL17_ANA_CPINTGS_H_MASK, ana_cp_int_gs >> 1) | 357 REG_FIELD_PREP(C10_PLL17_ANA_CPPROP_L_MASK, pll_params.ana_cp_prop); 358 pll_state->pll[18] = 359 REG_FIELD_PREP(C10_PLL18_ANA_CPPROP_H_MASK, pll_params.ana_cp_prop >> 2) | 360 REG_FIELD_PREP(C10_PLL18_ANA_CPPROPGS_L_MASK, ana_cp_prop_gs); 361 362 pll_state->pll[19] = REG_FIELD_PREP(C10_PLL19_ANA_CPPROPGS_H_MASK, ana_cp_prop_gs >> 3) | 363 REG_FIELD_PREP(C10_PLL19_ANA_V2I_MASK, pll_params.mpll_ana_v2i); 364 } 365