#include #include #include #include #include "intel_gpu_tools.h" #define LC_FREQ 2700 #define LC_FREQ_2K (LC_FREQ * 2000) #define P_MIN 2 #define P_MAX 64 #define P_INC 2 #define R2_MIN 5 #define R2_MAX 256 #define R2_INC 1 #define N2_MIN 5 #define N2_MAX 256 #define N2_INC 1 /* Constraints for PLL good behavior */ #define REF_MIN 48 #define REF_MAX 400 #define VCO_MIN 2400 #define VCO_MAX 4800 #define ABS_DIFF(a, b) ((a > b) ? (a - b) : (b - a)) struct wrpll_rnp { unsigned p, n2, r2; }; static unsigned wrpll_get_budget_for_freq(int clock) { unsigned budget; switch (clock) { case 25175000: case 25200000: case 27000000: case 27027000: case 37762500: case 37800000: case 40500000: case 40541000: case 54000000: case 54054000: case 59341000: case 59400000: case 72000000: case 74176000: case 74250000: case 81000000: case 81081000: case 89012000: case 89100000: case 108000000: case 108108000: case 111264000: case 111375000: case 148352000: case 148500000: case 162000000: case 162162000: case 222525000: case 222750000: case 296703000: case 297000000: budget = 0; break; case 233500000: case 245250000: case 247750000: case 253250000: case 298000000: budget = 1500; break; case 169128000: case 169500000: case 179500000: case 202000000: budget = 2000; break; case 256250000: case 262500000: case 270000000: case 272500000: case 273750000: case 280750000: case 281250000: case 286000000: case 291750000: budget = 4000; break; case 267250000: case 268500000: budget = 5000; break; default: budget = 1000; break; } return budget; } static void wrpll_update_rnp(uint64_t freq2k, unsigned budget, unsigned r2, unsigned n2, unsigned p, struct wrpll_rnp *best) { uint64_t a, b, c, d; /* No best (r,n,p) yet */ if (best->p == 0) { best->p = p; best->n2 = n2; best->r2 = r2; return; } /* * Output clock is (LC_FREQ_2K / 2000) * N / (P * R), which compares to * freq2k. * * delta = 1e6 * * abs(freq2k - (LC_FREQ_2K * n2/(p * r2))) / * freq2k; * * and we would like delta <= budget. * * If the discrepancy is above the PPM-based budget, always prefer to * improve upon the previous solution. However, if you're within the * budget, try to maximize Ref * VCO, that is N / (P * R^2). */ a = freq2k * budget * p * r2; b = freq2k * budget * best->p * best->r2; c = 1e6 * ABS_DIFF((freq2k * p * r2), (LC_FREQ_2K * n2)); d = 1e6 * ABS_DIFF((freq2k * best->p * best->r2), (LC_FREQ_2K * best->n2)); if (a < c && b < d) { /* If both are above the budget, pick the closer */ if (best->p * best->r2 * ABS_DIFF((freq2k * p * r2), (LC_FREQ_2K * n2)) < p * r2 * ABS_DIFF((freq2k * best->p * best->r2), (LC_FREQ_2K * best->n2))) { best->p = p; best->n2 = n2; best->r2 = r2; } } else if (a >= c && b < d) { /* If A is below the threshold but B is above it? Update. */ best->p = p; best->n2 = n2; best->r2 = r2; } else if (a >= c && b >= d) { /* Both are below the limit, so pick the higher n2/(r2*r2) */ if (n2 * best->r2 * best->r2 > best->n2 * r2 * r2) { best->p = p; best->n2 = n2; best->r2 = r2; } } /* Otherwise a < c && b >= d, do nothing */ } static void wrpll_compute_rnp(int clock /* in Hz */, unsigned *r2_out, unsigned *n2_out, unsigned *p_out) { uint64_t freq2k; unsigned p, n2, r2; struct wrpll_rnp best = { 0, 0, 0 }; unsigned budget; freq2k = clock / 100; budget = wrpll_get_budget_for_freq(clock); /* Special case handling for 540 pixel clock: bypass WR PLL entirely * and directly pass the LC PLL to it. */ if (freq2k == 5400000) { *n2_out = 2; *p_out = 1; *r2_out = 2; return; } /* * Ref * 2000 = LC_FREQ_2K / R, where Ref is the actual reference input * seen by the WR PLL. In particular: * REF_MIN <= LC_FREQ_2K / (R * 2000) and * REF_MAX >= LC_FREQ_2K / (R * 2000). * Eliminating fractions gives: * 2000 * REF_MAX * R >= LC_FREQ_2K >= 2000 * R * REF_MIN, R2 = 2*R */ for (r2 = R2_MIN; r2 <= R2_MAX; r2 += R2_INC) { if (1000 * REF_MAX * r2 < LC_FREQ_2K) continue; if (1000 * REF_MIN * r2 > LC_FREQ_2K) continue; /* * VCO is N * Ref, that is: VCO = N * LC_FREQ_2K / (R * 2000). * * Once again, VCO_MAX >= N * LC_FREQ_2K / (R * 2000) >= VCO_MIN, * or: VCO_MAX * R * 2000 >= N * LC_FREQ_2K >= VCO_MIN * R * 2000, * where R2=2*R and N2=2*N */ for (n2 = N2_MIN; n2 <= N2_MAX; n2 += N2_INC) { if (VCO_MAX * r2 * 2000 < n2 * LC_FREQ_2K) continue; if (VCO_MIN * r2 * 2000 > n2 * LC_FREQ_2K) continue; for (p = P_MIN; p <= P_MAX; p += P_INC) wrpll_update_rnp(freq2k, budget, r2, n2, p, &best); } } *n2_out = best.n2; *p_out = best.p; *r2_out = best.r2; } /* WRPLL clock dividers */ struct wrpll_tmds_clock { uint32_t clock; uint16_t p; /* Post divider */ uint16_t n2; /* Feedback divider */ uint16_t r2; /* Reference divider */ }; /* Table of matching values for WRPLL clocks programming for each frequency. * The code assumes this table is sorted. */ static const struct wrpll_tmds_clock wrpll_tmds_clock_table[] = { {19750, 38, 25, 18}, {20000, 48, 32, 18}, {21000, 36, 21, 15}, {21912, 42, 29, 17}, {22000, 36, 22, 15}, {23000, 36, 23, 15}, {23500, 40, 40, 23}, {23750, 26, 16, 14}, {24000, 36, 24, 15}, {25000, 36, 25, 15}, {25175, 26, 40, 33}, {25200, 30, 21, 15}, {26000, 36, 26, 15}, {27000, 30, 21, 14}, {27027, 18, 100, 111}, {27500, 30, 29, 19}, {28000, 34, 30, 17}, {28320, 26, 30, 22}, {28322, 32, 42, 25}, {28750, 24, 23, 18}, {29000, 30, 29, 18}, {29750, 32, 30, 17}, {30000, 30, 25, 15}, {30750, 30, 41, 24}, {31000, 30, 31, 18}, {31500, 30, 28, 16}, {32000, 30, 32, 18}, {32500, 28, 32, 19}, {33000, 24, 22, 15}, {34000, 28, 30, 17}, {35000, 26, 32, 19}, {35500, 24, 30, 19}, {36000, 26, 26, 15}, {36750, 26, 46, 26}, {37000, 24, 23, 14}, {37762, 22, 40, 26}, {37800, 20, 21, 15}, {38000, 24, 27, 16}, {38250, 24, 34, 20}, {39000, 24, 26, 15}, {40000, 24, 32, 18}, {40500, 20, 21, 14}, {40541, 22, 147, 89}, {40750, 18, 19, 14}, {41000, 16, 17, 14}, {41500, 22, 44, 26}, {41540, 22, 44, 26}, {42000, 18, 21, 15}, {42500, 22, 45, 26}, {43000, 20, 43, 27}, {43163, 20, 24, 15}, {44000, 18, 22, 15}, {44900, 20, 108, 65}, {45000, 20, 25, 15}, {45250, 20, 52, 31}, {46000, 18, 23, 15}, {46750, 20, 45, 26}, {47000, 20, 40, 23}, {48000, 18, 24, 15}, {49000, 18, 49, 30}, {49500, 16, 22, 15}, {50000, 18, 25, 15}, {50500, 18, 32, 19}, {51000, 18, 34, 20}, {52000, 18, 26, 15}, {52406, 14, 34, 25}, {53000, 16, 22, 14}, {54000, 16, 24, 15}, {54054, 16, 173, 108}, {54500, 14, 24, 17}, {55000, 12, 22, 18}, {56000, 14, 45, 31}, {56250, 16, 25, 15}, {56750, 14, 25, 17}, {57000, 16, 27, 16}, {58000, 16, 43, 25}, {58250, 16, 38, 22}, {58750, 16, 40, 23}, {59000, 14, 26, 17}, {59341, 14, 40, 26}, {59400, 16, 44, 25}, {60000, 16, 32, 18}, {60500, 12, 39, 29}, {61000, 14, 49, 31}, {62000, 14, 37, 23}, {62250, 14, 42, 26}, {63000, 12, 21, 15}, {63500, 14, 28, 17}, {64000, 12, 27, 19}, {65000, 14, 32, 19}, {65250, 12, 29, 20}, {65500, 12, 32, 22}, {66000, 12, 22, 15}, {66667, 14, 38, 22}, {66750, 10, 21, 17}, {67000, 14, 33, 19}, {67750, 14, 58, 33}, {68000, 14, 30, 17}, {68179, 14, 46, 26}, {68250, 14, 46, 26}, {69000, 12, 23, 15}, {70000, 12, 28, 18}, {71000, 12, 30, 19}, {72000, 12, 24, 15}, {73000, 10, 23, 17}, {74000, 12, 23, 14}, {74176, 8, 100, 91}, {74250, 10, 22, 16}, {74481, 12, 43, 26}, {74500, 10, 29, 21}, {75000, 12, 25, 15}, {75250, 10, 39, 28}, {76000, 12, 27, 16}, {77000, 12, 53, 31}, {78000, 12, 26, 15}, {78750, 12, 28, 16}, {79000, 10, 38, 26}, {79500, 10, 28, 19}, {80000, 12, 32, 18}, {81000, 10, 21, 14}, {81081, 6, 100, 111}, {81624, 8, 29, 24}, {82000, 8, 17, 14}, {83000, 10, 40, 26}, {83950, 10, 28, 18}, {84000, 10, 28, 18}, {84750, 6, 16, 17}, {85000, 6, 17, 18}, {85250, 10, 30, 19}, {85750, 10, 27, 17}, {86000, 10, 43, 27}, {87000, 10, 29, 18}, {88000, 10, 44, 27}, {88500, 10, 41, 25}, {89000, 10, 28, 17}, {89012, 6, 90, 91}, {89100, 10, 33, 20}, {90000, 10, 25, 15}, {91000, 10, 32, 19}, {92000, 10, 46, 27}, {93000, 10, 31, 18}, {94000, 10, 40, 23}, {94500, 10, 28, 16}, {95000, 10, 44, 25}, {95654, 10, 39, 22}, {95750, 10, 39, 22}, {96000, 10, 32, 18}, {97000, 8, 23, 16}, {97750, 8, 42, 29}, {98000, 8, 45, 31}, {99000, 8, 22, 15}, {99750, 8, 34, 23}, {100000, 6, 20, 18}, {100500, 6, 19, 17}, {101000, 6, 37, 33}, {101250, 8, 21, 14}, {102000, 6, 17, 15}, {102250, 6, 25, 22}, {103000, 8, 29, 19}, {104000, 8, 37, 24}, {105000, 8, 28, 18}, {106000, 8, 22, 14}, {107000, 8, 46, 29}, {107214, 8, 27, 17}, {108000, 8, 24, 15}, {108108, 8, 173, 108}, {109000, 6, 23, 19}, {110000, 6, 22, 18}, {110013, 6, 22, 18}, {110250, 8, 49, 30}, {110500, 8, 36, 22}, {111000, 8, 23, 14}, {111264, 8, 150, 91}, {111375, 8, 33, 20}, {112000, 8, 63, 38}, {112500, 8, 25, 15}, {113100, 8, 57, 34}, {113309, 8, 42, 25}, {114000, 8, 27, 16}, {115000, 6, 23, 18}, {116000, 8, 43, 25}, {117000, 8, 26, 15}, {117500, 8, 40, 23}, {118000, 6, 38, 29}, {119000, 8, 30, 17}, {119500, 8, 46, 26}, {119651, 8, 39, 22}, {120000, 8, 32, 18}, {121000, 6, 39, 29}, {121250, 6, 31, 23}, {121750, 6, 23, 17}, {122000, 6, 42, 31}, {122614, 6, 30, 22}, {123000, 6, 41, 30}, {123379, 6, 37, 27}, {124000, 6, 51, 37}, {125000, 6, 25, 18}, {125250, 4, 13, 14}, {125750, 4, 27, 29}, {126000, 6, 21, 15}, {127000, 6, 24, 17}, {127250, 6, 41, 29}, {128000, 6, 27, 19}, {129000, 6, 43, 30}, {129859, 4, 25, 26}, {130000, 6, 26, 18}, {130250, 6, 42, 29}, {131000, 6, 32, 22}, {131500, 6, 38, 26}, {131850, 6, 41, 28}, {132000, 6, 22, 15}, {132750, 6, 28, 19}, {133000, 6, 34, 23}, {133330, 6, 37, 25}, {134000, 6, 61, 41}, {135000, 6, 21, 14}, {135250, 6, 167, 111}, {136000, 6, 62, 41}, {137000, 6, 35, 23}, {138000, 6, 23, 15}, {138500, 6, 40, 26}, {138750, 6, 37, 24}, {139000, 6, 34, 22}, {139050, 6, 34, 22}, {139054, 6, 34, 22}, {140000, 6, 28, 18}, {141000, 6, 36, 23}, {141500, 6, 22, 14}, {142000, 6, 30, 19}, {143000, 6, 27, 17}, {143472, 4, 17, 16}, {144000, 6, 24, 15}, {145000, 6, 29, 18}, {146000, 6, 47, 29}, {146250, 6, 26, 16}, {147000, 6, 49, 30}, {147891, 6, 23, 14}, {148000, 6, 23, 14}, {148250, 6, 28, 17}, {148352, 4, 100, 91}, {148500, 6, 33, 20}, {149000, 6, 48, 29}, {150000, 6, 25, 15}, {151000, 4, 19, 17}, {152000, 6, 27, 16}, {152280, 6, 44, 26}, {153000, 6, 34, 20}, {154000, 6, 53, 31}, {155000, 6, 31, 18}, {155250, 6, 50, 29}, {155750, 6, 45, 26}, {156000, 6, 26, 15}, {157000, 6, 61, 35}, {157500, 6, 28, 16}, {158000, 6, 65, 37}, {158250, 6, 44, 25}, {159000, 6, 53, 30}, {159500, 6, 39, 22}, {160000, 6, 32, 18}, {161000, 4, 31, 26}, {162000, 4, 18, 15}, {162162, 4, 131, 109}, {162500, 4, 53, 44}, {163000, 4, 29, 24}, {164000, 4, 17, 14}, {165000, 4, 22, 18}, {166000, 4, 32, 26}, {167000, 4, 26, 21}, {168000, 4, 46, 37}, {169000, 4, 104, 83}, {169128, 4, 64, 51}, {169500, 4, 39, 31}, {170000, 4, 34, 27}, {171000, 4, 19, 15}, {172000, 4, 51, 40}, {172750, 4, 32, 25}, {172800, 4, 32, 25}, {173000, 4, 41, 32}, {174000, 4, 49, 38}, {174787, 4, 22, 17}, {175000, 4, 35, 27}, {176000, 4, 30, 23}, {177000, 4, 38, 29}, {178000, 4, 29, 22}, {178500, 4, 37, 28}, {179000, 4, 53, 40}, {179500, 4, 73, 55}, {180000, 4, 20, 15}, {181000, 4, 55, 41}, {182000, 4, 31, 23}, {183000, 4, 42, 31}, {184000, 4, 30, 22}, {184750, 4, 26, 19}, {185000, 4, 37, 27}, {186000, 4, 51, 37}, {187000, 4, 36, 26}, {188000, 4, 32, 23}, {189000, 4, 21, 15}, {190000, 4, 38, 27}, {190960, 4, 41, 29}, {191000, 4, 41, 29}, {192000, 4, 27, 19}, {192250, 4, 37, 26}, {193000, 4, 20, 14}, {193250, 4, 53, 37}, {194000, 4, 23, 16}, {194208, 4, 23, 16}, {195000, 4, 26, 18}, {196000, 4, 45, 31}, {197000, 4, 35, 24}, {197750, 4, 41, 28}, {198000, 4, 22, 15}, {198500, 4, 25, 17}, {199000, 4, 28, 19}, {200000, 4, 37, 25}, {201000, 4, 61, 41}, {202000, 4, 112, 75}, {202500, 4, 21, 14}, {203000, 4, 146, 97}, {204000, 4, 62, 41}, {204750, 4, 44, 29}, {205000, 4, 38, 25}, {206000, 4, 29, 19}, {207000, 4, 23, 15}, {207500, 4, 40, 26}, {208000, 4, 37, 24}, {208900, 4, 48, 31}, {209000, 4, 48, 31}, {209250, 4, 31, 20}, {210000, 4, 28, 18}, {211000, 4, 25, 16}, {212000, 4, 22, 14}, {213000, 4, 30, 19}, {213750, 4, 38, 24}, {214000, 4, 46, 29}, {214750, 4, 35, 22}, {215000, 4, 43, 27}, {216000, 4, 24, 15}, {217000, 4, 37, 23}, {218000, 4, 42, 26}, {218250, 4, 42, 26}, {218750, 4, 34, 21}, {219000, 4, 47, 29}, {220000, 4, 44, 27}, {220640, 4, 49, 30}, {220750, 4, 36, 22}, {221000, 4, 36, 22}, {222000, 4, 23, 14}, {222525, 4, 28, 17}, {222750, 4, 33, 20}, {227000, 4, 37, 22}, {230250, 4, 29, 17}, {233500, 4, 38, 22}, {235000, 4, 40, 23}, {238000, 4, 30, 17}, {241500, 2, 17, 19}, {245250, 2, 20, 22}, {247750, 2, 22, 24}, {253250, 2, 15, 16}, {256250, 2, 18, 19}, {262500, 2, 31, 32}, {267250, 2, 66, 67}, {268500, 2, 94, 95}, {270000, 2, 14, 14}, {272500, 2, 77, 76}, {273750, 2, 57, 56}, {280750, 2, 24, 23}, {281250, 2, 23, 22}, {286000, 2, 17, 16}, {291750, 2, 26, 24}, {296703, 2, 56, 51}, {297000, 2, 22, 20}, {298000, 2, 21, 19}, }; int main(void) { int i; for (i = 0; i < ARRAY_SIZE(wrpll_tmds_clock_table); i++) { const struct wrpll_tmds_clock *ref = &wrpll_tmds_clock_table[i]; unsigned r2, n2, p; wrpll_compute_rnp(ref->clock * 1000, &r2, &n2, &p); if (ref->r2 != r2 || ref->n2 != n2 || ref->p != p) { printf("Computed value differs for %li Hz:\n" " Reference: (%u,%u,%u)\n" " Computed: (%u,%u,%u)\n", (int64_t)ref->clock * 1000, ref->r2, ref->n2, ref->p, r2, n2, p); abort(); } } return 0; }