| /* |
| * Copyright © 2015 Intel Corporation |
| * |
| * Permission is hereby granted, free of charge, to any person obtaining a |
| * copy of this software and associated documentation files (the "Software"), |
| * to deal in the Software without restriction, including without limitation |
| * the rights to use, copy, modify, merge, publish, distribute, sublicense, |
| * and/or sell copies of the Software, and to permit persons to whom the |
| * Software is furnished to do so, subject to the following conditions: |
| * |
| * The above copyright notice and this permission notice (including the next |
| * paragraph) shall be included in all copies or substantial portions of the |
| * Software. |
| * |
| * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
| * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
| * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
| * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
| * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
| * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER |
| * DEALINGS IN THE SOFTWARE. |
| */ |
| |
| #include <assert.h> |
| #include <inttypes.h> |
| #include <limits.h> |
| #include <stdio.h> |
| #include <stdbool.h> |
| #include <stdint.h> |
| #include <stdlib.h> |
| #include <string.h> |
| |
| #include "igt_stats.h" |
| |
| #define U64_MAX ((uint64_t)~0ULL) |
| #define ARRAY_SIZE(arr) (sizeof(arr)/sizeof(arr[0])) |
| |
| #define WARN(cond, msg) printf(msg) |
| |
| #define KHz(x) (1000 * (x)) |
| #define MHz(x) KHz(1000 * (x)) |
| |
| #define abs_diff(a, b) ({ \ |
| typeof(a) __a = (a); \ |
| typeof(b) __b = (b); \ |
| (void) (&__a == &__b); \ |
| __a > __b ? (__a - __b) : (__b - __a); }) |
| |
| static inline uint64_t div64_u64(uint64_t dividend, uint64_t divisor) |
| { |
| return dividend / divisor; |
| } |
| |
| static inline uint64_t div_u64(uint64_t dividend, uint32_t divisor) |
| { |
| return dividend / divisor; |
| } |
| |
| struct skl_wrpll_params { |
| uint32_t dco_fraction; |
| uint32_t dco_integer; |
| uint32_t qdiv_ratio; |
| uint32_t qdiv_mode; |
| uint32_t kdiv; |
| uint32_t pdiv; |
| uint32_t central_freq; |
| |
| /* for this test code only */ |
| uint64_t central_freq_hz; |
| unsigned int p0, p1, p2; |
| }; |
| |
| static bool |
| skl_ddi_calculate_wrpll1(int clock /* in Hz */, |
| struct skl_wrpll_params *wrpll_params) |
| { |
| uint64_t afe_clock = clock * 5; /* AFE Clock is 5x Pixel clock */ |
| uint64_t dco_central_freq[3] = {8400000000ULL, |
| 9000000000ULL, |
| 9600000000ULL}; |
| uint32_t min_dco_pdeviation = 100; /* DCO freq must be within +1%/-6% */ |
| uint32_t min_dco_ndeviation = 600; /* of the DCO central freq */ |
| uint32_t min_dco_index = 3; |
| uint32_t P0[4] = {1, 2, 3, 7}; |
| uint32_t P2[4] = {1, 2, 3, 5}; |
| bool found = false; |
| uint32_t candidate_p = 0; |
| uint32_t candidate_p0[3] = {0}, candidate_p1[3] = {0}; |
| uint32_t candidate_p2[3] = {0}; |
| uint32_t dco_central_freq_deviation[3]; |
| uint32_t i, P1, k, dco_count; |
| bool retry_with_odd = false; |
| |
| /* Determine P0, P1 or P2 */ |
| for (dco_count = 0; dco_count < 3; dco_count++) { |
| found = false; |
| candidate_p = |
| div64_u64(dco_central_freq[dco_count], afe_clock); |
| if (retry_with_odd == false) |
| candidate_p = (candidate_p % 2 == 0 ? |
| candidate_p : candidate_p + 1); |
| |
| for (P1 = 1; P1 < candidate_p; P1++) { |
| for (i = 0; i < 4; i++) { |
| if (!(P0[i] != 1 || P1 == 1)) |
| continue; |
| |
| for (k = 0; k < 4; k++) { |
| if (P1 != 1 && P2[k] != 2) |
| continue; |
| |
| if (candidate_p == P0[i] * P1 * P2[k]) { |
| /* Found possible P0, P1, P2 */ |
| found = true; |
| candidate_p0[dco_count] = P0[i]; |
| candidate_p1[dco_count] = P1; |
| candidate_p2[dco_count] = P2[k]; |
| goto found; |
| } |
| |
| } |
| } |
| } |
| |
| found: |
| if (found) { |
| uint64_t dco_freq = candidate_p * afe_clock; |
| |
| #if 0 |
| printf("Trying with (%d,%d,%d)\n", |
| candidate_p0[dco_count], |
| candidate_p1[dco_count], |
| candidate_p2[dco_count]); |
| #endif |
| |
| dco_central_freq_deviation[dco_count] = |
| div64_u64(10000 * |
| abs_diff(dco_freq, |
| dco_central_freq[dco_count]), |
| dco_central_freq[dco_count]); |
| |
| #if 0 |
| printf("Deviation %d\n", |
| dco_central_freq_deviation[dco_count]); |
| |
| printf("dco_freq: %"PRIu64", " |
| "dco_central_freq %"PRIu64"\n", |
| dco_freq, dco_central_freq[dco_count]); |
| #endif |
| |
| /* positive deviation */ |
| if (dco_freq > dco_central_freq[dco_count]) { |
| if (dco_central_freq_deviation[dco_count] < |
| min_dco_pdeviation) { |
| min_dco_pdeviation = |
| dco_central_freq_deviation[dco_count]; |
| min_dco_index = dco_count; |
| } |
| /* negative deviation */ |
| } else if (dco_central_freq_deviation[dco_count] < |
| min_dco_ndeviation) { |
| min_dco_ndeviation = |
| dco_central_freq_deviation[dco_count]; |
| min_dco_index = dco_count; |
| } |
| } |
| |
| if (min_dco_index > 2 && dco_count == 2) { |
| /* oh well, we tried... */ |
| if (retry_with_odd) |
| break; |
| |
| retry_with_odd = true; |
| dco_count = 0; |
| } |
| } |
| |
| if (min_dco_index > 2) { |
| WARN(1, "No valid values found for the given pixel clock\n"); |
| return false; |
| } else { |
| uint64_t dco_freq; |
| |
| wrpll_params->central_freq = dco_central_freq[min_dco_index]; |
| |
| switch (dco_central_freq[min_dco_index]) { |
| case 9600000000ULL: |
| wrpll_params->central_freq = 0; |
| break; |
| case 9000000000ULL: |
| wrpll_params->central_freq = 1; |
| break; |
| case 8400000000ULL: |
| wrpll_params->central_freq = 3; |
| } |
| |
| switch (candidate_p0[min_dco_index]) { |
| case 1: |
| wrpll_params->pdiv = 0; |
| break; |
| case 2: |
| wrpll_params->pdiv = 1; |
| break; |
| case 3: |
| wrpll_params->pdiv = 2; |
| break; |
| case 7: |
| wrpll_params->pdiv = 4; |
| break; |
| default: |
| WARN(1, "Incorrect PDiv\n"); |
| } |
| |
| switch (candidate_p2[min_dco_index]) { |
| case 5: |
| wrpll_params->kdiv = 0; |
| break; |
| case 2: |
| wrpll_params->kdiv = 1; |
| break; |
| case 3: |
| wrpll_params->kdiv = 2; |
| break; |
| case 1: |
| wrpll_params->kdiv = 3; |
| break; |
| default: |
| WARN(1, "Incorrect KDiv\n"); |
| } |
| |
| wrpll_params->qdiv_ratio = candidate_p1[min_dco_index]; |
| wrpll_params->qdiv_mode = |
| (wrpll_params->qdiv_ratio == 1) ? 0 : 1; |
| |
| dco_freq = candidate_p0[min_dco_index] * |
| candidate_p1[min_dco_index] * |
| candidate_p2[min_dco_index] * afe_clock; |
| |
| /* |
| * Intermediate values are in Hz. |
| * Divide by MHz to match bsepc |
| */ |
| wrpll_params->dco_integer = div_u64(dco_freq, (24 * MHz(1))); |
| wrpll_params->dco_fraction = |
| div_u64(((div_u64(dco_freq, 24) - |
| wrpll_params->dco_integer * MHz(1)) * 0x8000), MHz(1)); |
| |
| } |
| |
| /* for this unit test only */ |
| wrpll_params->central_freq_hz = dco_central_freq[min_dco_index]; |
| wrpll_params->p0 = candidate_p0[min_dco_index]; |
| wrpll_params->p1 = candidate_p1[min_dco_index]; |
| wrpll_params->p2 = candidate_p2[min_dco_index]; |
| |
| return true; |
| } |
| |
| struct skl_wrpll_context { |
| uint64_t min_deviation; /* current minimal deviation */ |
| uint64_t central_freq; /* chosen central freq */ |
| uint64_t dco_freq; /* chosen dco freq */ |
| unsigned int p; /* chosen divider */ |
| }; |
| |
| static void skl_wrpll_context_init(struct skl_wrpll_context *ctx) |
| { |
| memset(ctx, 0, sizeof(*ctx)); |
| |
| ctx->min_deviation = U64_MAX; |
| } |
| |
| /* DCO freq must be within +1%/-6% of the DCO central freq */ |
| #define SKL_MAX_PDEVIATION 100 |
| #define SKL_MAX_NDEVIATION 600 |
| |
| |
| /* |
| * Returns true if we're sure to have found the definitive divider (ie |
| * deviation == 0). |
| */ |
| static bool skl_wrpll_try_divider(struct skl_wrpll_context *ctx, |
| uint64_t central_freq, |
| uint64_t dco_freq, |
| unsigned int divider) |
| { |
| uint64_t deviation; |
| bool found = false; |
| |
| deviation = div64_u64(10000 * abs_diff(dco_freq, central_freq), |
| central_freq); |
| |
| /* positive deviation */ |
| if (dco_freq >= central_freq) { |
| if (deviation < SKL_MAX_PDEVIATION && |
| deviation < ctx->min_deviation) { |
| ctx->min_deviation = deviation; |
| ctx->central_freq = central_freq; |
| ctx->dco_freq = dco_freq; |
| ctx->p = divider; |
| #if 0 |
| found = true; |
| #endif |
| } |
| |
| /* we can't improve a 0 deviation */ |
| if (deviation == 0) |
| return true; |
| /* negative deviation */ |
| } else if (deviation < SKL_MAX_NDEVIATION && |
| deviation < ctx->min_deviation) { |
| ctx->min_deviation = deviation; |
| ctx->central_freq = central_freq; |
| ctx->dco_freq = dco_freq; |
| ctx->p = divider; |
| #if 0 |
| found = true; |
| #endif |
| } |
| |
| if (found) { |
| printf("Divider %d\n", divider); |
| printf("Deviation %"PRIu64"\n", deviation); |
| printf("dco_freq: %"PRIu64", dco_central_freq %"PRIu64"\n", |
| dco_freq, central_freq); |
| } |
| |
| return false; |
| } |
| |
| static void skl_wrpll_get_multipliers(unsigned int p, |
| unsigned int *p0 /* out */, |
| unsigned int *p1 /* out */, |
| unsigned int *p2 /* out */) |
| { |
| /* even dividers */ |
| if (p % 2 == 0) { |
| unsigned int half = p / 2; |
| |
| if (half == 1 || half == 2 || half == 3 || half == 5) { |
| *p0 = 2; |
| *p1 = 1; |
| *p2 = half; |
| } else if (half % 2 == 0) { |
| *p0 = 2; |
| *p1 = half / 2; |
| *p2 = 2; |
| } else if (half % 3 == 0) { |
| *p0 = 3; |
| *p1 = half / 3; |
| *p2 = 2; |
| } else if (half % 7 == 0) { |
| *p0 = 7; |
| *p1 = half / 7; |
| *p2 = 2; |
| } |
| } else if (p == 3 || p == 9) { /* 3, 5, 7, 9, 15, 21, 35 */ |
| *p0 = 3; |
| *p1 = 1; |
| *p2 = p / 3; |
| } else if (p == 5 || p == 7) { |
| *p0 = p; |
| *p1 = 1; |
| *p2 = 1; |
| } else if (p == 15) { |
| *p0 = 3; |
| *p1 = 1; |
| *p2 = 5; |
| } else if (p == 21) { |
| *p0 = 7; |
| *p1 = 1; |
| *p2 = 3; |
| } else if (p == 35) { |
| *p0 = 7; |
| *p1 = 1; |
| *p2 = 5; |
| } |
| } |
| |
| static void test_multipliers(void) |
| { |
| static const int even_dividers[] = { 4, 6, 8, 10, 12, 14, 16, 18, 20, |
| 24, 28, 30, 32, 36, 40, 42, 44, |
| 48, 52, 54, 56, 60, 64, 66, 68, |
| 70, 72, 76, 78, 80, 84, 88, 90, |
| 92, 96, 98 }; |
| static const int odd_dividers[] = { 3, 5, 7, 9, 15, 21, 35 }; |
| static const struct { |
| const int *list; |
| int n_dividers; |
| } dividers[] = { |
| { even_dividers, ARRAY_SIZE(even_dividers) }, |
| { odd_dividers, ARRAY_SIZE(odd_dividers) }, |
| }; |
| unsigned int d, i; |
| |
| for (d = 0; d < ARRAY_SIZE(dividers); d++) { |
| for (i = 0; i < dividers[d].n_dividers; i++) { |
| unsigned int p = dividers[d].list[i]; |
| unsigned p0, p1, p2; |
| |
| p0 = p1 = p2 = 0; |
| |
| skl_wrpll_get_multipliers(p, &p0, &p1, &p2); |
| |
| assert(p0); |
| assert(p1); |
| assert(p2); |
| assert(p == p0 * p1 * p2); |
| } |
| } |
| } |
| |
| static bool |
| skl_ddi_calculate_wrpll2(int clock /* in Hz */, |
| struct skl_wrpll_params *wrpll_params) |
| { |
| uint64_t afe_clock = clock * 5; /* AFE Clock is 5x Pixel clock */ |
| uint64_t dco_central_freq[3] = {8400000000ULL, |
| 9000000000ULL, |
| 9600000000ULL}; |
| static const int even_dividers[] = { 4, 6, 8, 10, 12, 14, 16, 18, 20, |
| 24, 28, 30, 32, 36, 40, 42, 44, |
| 48, 52, 54, 56, 60, 64, 66, 68, |
| 70, 72, 76, 78, 80, 84, 88, 90, |
| 92, 96, 98 }; |
| static const int odd_dividers[] = { 3, 5, 7, 9, 15, 21, 35 }; |
| static const struct { |
| const int *list; |
| int n_dividers; |
| } dividers[] = { |
| { even_dividers, ARRAY_SIZE(even_dividers) }, |
| { odd_dividers, ARRAY_SIZE(odd_dividers) }, |
| }; |
| struct skl_wrpll_context ctx; |
| unsigned int dco, d, i; |
| unsigned int p0, p1, p2; |
| |
| skl_wrpll_context_init(&ctx); |
| |
| for (d = 0; d < ARRAY_SIZE(dividers); d++) { |
| for (dco = 0; dco < ARRAY_SIZE(dco_central_freq); dco++) { |
| for (i = 0; i < dividers[d].n_dividers; i++) { |
| unsigned int p = dividers[d].list[i]; |
| uint64_t dco_freq = p * afe_clock; |
| |
| if (skl_wrpll_try_divider(&ctx, |
| dco_central_freq[dco], |
| dco_freq, |
| p)) |
| goto skip_remaining_dividers; |
| } |
| } |
| |
| skip_remaining_dividers: |
| /* |
| * If a solution is found with an even divider, prefer |
| * this one. |
| */ |
| if (d == 0 && ctx.p) |
| break; |
| } |
| |
| if (!ctx.p) |
| return false; |
| |
| skl_wrpll_get_multipliers(ctx.p, &p0, &p1, &p2); |
| |
| /* for this unit test only */ |
| wrpll_params->central_freq_hz = ctx.central_freq; |
| wrpll_params->p0 = p0; |
| wrpll_params->p1 = p1; |
| wrpll_params->p2 = p2; |
| |
| return true; |
| } |
| |
| static const struct { |
| uint32_t clock; /* in Hz */ |
| } modes[] = { |
| { 19750000 }, |
| { 20000000 }, |
| { 21000000 }, |
| { 21912000 }, |
| { 22000000 }, |
| { 23000000 }, |
| { 23500000 }, |
| { 23750000 }, |
| { 24000000 }, |
| { 25000000 }, |
| { 25175000 }, |
| { 25200000 }, |
| { 26000000 }, |
| { 27000000 }, |
| { 27027000 }, |
| { 27500000 }, |
| { 28000000 }, |
| { 28320000 }, |
| { 28322000 }, |
| { 28750000 }, |
| { 29000000 }, |
| { 29750000 }, |
| { 30000000 }, |
| { 30750000 }, |
| { 31000000 }, |
| { 31500000 }, |
| { 32000000 }, |
| { 32500000 }, |
| { 33000000 }, |
| { 34000000 }, |
| { 35000000 }, |
| { 35500000 }, |
| { 36000000 }, |
| { 36750000 }, |
| { 37000000 }, |
| { 37762500 }, |
| { 37800000 }, |
| { 38000000 }, |
| { 38250000 }, |
| { 39000000 }, |
| { 40000000 }, |
| { 40500000 }, |
| { 40541000 }, |
| { 40750000 }, |
| { 41000000 }, |
| { 41500000 }, |
| { 41540000 }, |
| { 42000000 }, |
| { 42500000 }, |
| { 43000000 }, |
| { 43163000 }, |
| { 44000000 }, |
| { 44900000 }, |
| { 45000000 }, |
| { 45250000 }, |
| { 46000000 }, |
| { 46750000 }, |
| { 47000000 }, |
| { 48000000 }, |
| { 49000000 }, |
| { 49500000 }, |
| { 50000000 }, |
| { 50500000 }, |
| { 51000000 }, |
| { 52000000 }, |
| { 52406000 }, |
| { 53000000 }, |
| { 54000000 }, |
| { 54054000 }, |
| { 54500000 }, |
| { 55000000 }, |
| { 56000000 }, |
| { 56250000 }, |
| { 56750000 }, |
| { 57000000 }, |
| { 58000000 }, |
| { 58250000 }, |
| { 58750000 }, |
| { 59000000 }, |
| { 59341000 }, |
| { 59400000 }, |
| { 60000000 }, |
| { 60500000 }, |
| { 61000000 }, |
| { 62000000 }, |
| { 62250000 }, |
| { 63000000 }, |
| { 63500000 }, |
| { 64000000 }, |
| { 65000000 }, |
| { 65250000 }, |
| { 65500000 }, |
| { 66000000 }, |
| { 66667000 }, |
| { 66750000 }, |
| { 67000000 }, |
| { 67750000 }, |
| { 68000000 }, |
| { 68179000 }, |
| { 68250000 }, |
| { 69000000 }, |
| { 70000000 }, |
| { 71000000 }, |
| { 72000000 }, |
| { 73000000 }, |
| { 74000000 }, |
| { 74176000 }, |
| { 74250000 }, |
| { 74481000 }, |
| { 74500000 }, |
| { 75000000 }, |
| { 75250000 }, |
| { 76000000 }, |
| { 77000000 }, |
| { 78000000 }, |
| { 78750000 }, |
| { 79000000 }, |
| { 79500000 }, |
| { 80000000 }, |
| { 81000000 }, |
| { 81081000 }, |
| { 81624000 }, |
| { 82000000 }, |
| { 83000000 }, |
| { 83950000 }, |
| { 84000000 }, |
| { 84750000 }, |
| { 85000000 }, |
| { 85250000 }, |
| { 85750000 }, |
| { 86000000 }, |
| { 87000000 }, |
| { 88000000 }, |
| { 88500000 }, |
| { 89000000 }, |
| { 89012000 }, |
| { 89100000 }, |
| { 90000000 }, |
| { 91000000 }, |
| { 92000000 }, |
| { 93000000 }, |
| { 94000000 }, |
| { 94500000 }, |
| { 95000000 }, |
| { 95654000 }, |
| { 95750000 }, |
| { 96000000 }, |
| { 97000000 }, |
| { 97750000 }, |
| { 98000000 }, |
| { 99000000 }, |
| { 99750000 }, |
| { 100000000 }, |
| { 100500000 }, |
| { 101000000 }, |
| { 101250000 }, |
| { 102000000 }, |
| { 102250000 }, |
| { 103000000 }, |
| { 104000000 }, |
| { 105000000 }, |
| { 106000000 }, |
| { 107000000 }, |
| { 107214000 }, |
| { 108000000 }, |
| { 108108000 }, |
| { 109000000 }, |
| { 110000000 }, |
| { 110013000 }, |
| { 110250000 }, |
| { 110500000 }, |
| { 111000000 }, |
| { 111264000 }, |
| { 111375000 }, |
| { 112000000 }, |
| { 112500000 }, |
| { 113100000 }, |
| { 113309000 }, |
| { 114000000 }, |
| { 115000000 }, |
| { 116000000 }, |
| { 117000000 }, |
| { 117500000 }, |
| { 118000000 }, |
| { 119000000 }, |
| { 119500000 }, |
| { 119651000 }, |
| { 120000000 }, |
| { 121000000 }, |
| { 121250000 }, |
| { 121750000 }, |
| { 122000000 }, |
| { 122614000 }, |
| { 123000000 }, |
| { 123379000 }, |
| { 124000000 }, |
| { 125000000 }, |
| { 125250000 }, |
| { 125750000 }, |
| { 126000000 }, |
| { 127000000 }, |
| { 127250000 }, |
| { 128000000 }, |
| { 129000000 }, |
| { 129859000 }, |
| { 130000000 }, |
| { 130250000 }, |
| { 131000000 }, |
| { 131500000 }, |
| { 131850000 }, |
| { 132000000 }, |
| { 132750000 }, |
| { 133000000 }, |
| { 133330000 }, |
| { 134000000 }, |
| { 135000000 }, |
| { 135250000 }, |
| { 136000000 }, |
| { 137000000 }, |
| { 138000000 }, |
| { 138500000 }, |
| { 138750000 }, |
| { 139000000 }, |
| { 139050000 }, |
| { 139054000 }, |
| { 140000000 }, |
| { 141000000 }, |
| { 141500000 }, |
| { 142000000 }, |
| { 143000000 }, |
| { 143472000 }, |
| { 144000000 }, |
| { 145000000 }, |
| { 146000000 }, |
| { 146250000 }, |
| { 147000000 }, |
| { 147891000 }, |
| { 148000000 }, |
| { 148250000 }, |
| { 148352000 }, |
| { 148500000 }, |
| { 149000000 }, |
| { 150000000 }, |
| { 151000000 }, |
| { 152000000 }, |
| { 152280000 }, |
| { 153000000 }, |
| { 154000000 }, |
| { 155000000 }, |
| { 155250000 }, |
| { 155750000 }, |
| { 156000000 }, |
| { 157000000 }, |
| { 157500000 }, |
| { 158000000 }, |
| { 158250000 }, |
| { 159000000 }, |
| { 159500000 }, |
| { 160000000 }, |
| { 161000000 }, |
| { 162000000 }, |
| { 162162000 }, |
| { 162500000 }, |
| { 163000000 }, |
| { 164000000 }, |
| { 165000000 }, |
| { 166000000 }, |
| { 167000000 }, |
| { 168000000 }, |
| { 169000000 }, |
| { 169128000 }, |
| { 169500000 }, |
| { 170000000 }, |
| { 171000000 }, |
| { 172000000 }, |
| { 172750000 }, |
| { 172800000 }, |
| { 173000000 }, |
| { 174000000 }, |
| { 174787000 }, |
| { 175000000 }, |
| { 176000000 }, |
| { 177000000 }, |
| { 178000000 }, |
| { 178500000 }, |
| { 179000000 }, |
| { 179500000 }, |
| { 180000000 }, |
| { 181000000 }, |
| { 182000000 }, |
| { 183000000 }, |
| { 184000000 }, |
| { 184750000 }, |
| { 185000000 }, |
| { 186000000 }, |
| { 187000000 }, |
| { 188000000 }, |
| { 189000000 }, |
| { 190000000 }, |
| { 190960000 }, |
| { 191000000 }, |
| { 192000000 }, |
| { 192250000 }, |
| { 193000000 }, |
| { 193250000 }, |
| { 194000000 }, |
| { 194208000 }, |
| { 195000000 }, |
| { 196000000 }, |
| { 197000000 }, |
| { 197750000 }, |
| { 198000000 }, |
| { 198500000 }, |
| { 199000000 }, |
| { 200000000 }, |
| { 201000000 }, |
| { 202000000 }, |
| { 202500000 }, |
| { 203000000 }, |
| { 204000000 }, |
| { 204750000 }, |
| { 205000000 }, |
| { 206000000 }, |
| { 207000000 }, |
| { 207500000 }, |
| { 208000000 }, |
| { 208900000 }, |
| { 209000000 }, |
| { 209250000 }, |
| { 210000000 }, |
| { 211000000 }, |
| { 212000000 }, |
| { 213000000 }, |
| { 213750000 }, |
| { 214000000 }, |
| { 214750000 }, |
| { 215000000 }, |
| { 216000000 }, |
| { 217000000 }, |
| { 218000000 }, |
| { 218250000 }, |
| { 218750000 }, |
| { 219000000 }, |
| { 220000000 }, |
| { 220640000 }, |
| { 220750000 }, |
| { 221000000 }, |
| { 222000000 }, |
| { 222525000 }, |
| { 222750000 }, |
| { 227000000 }, |
| { 230250000 }, |
| { 233500000 }, |
| { 235000000 }, |
| { 238000000 }, |
| { 241500000 }, |
| { 245250000 }, |
| { 247750000 }, |
| { 253250000 }, |
| { 256250000 }, |
| { 262500000 }, |
| { 267250000 }, |
| { 268500000 }, |
| { 270000000 }, |
| { 272500000 }, |
| { 273750000 }, |
| { 280750000 }, |
| { 281250000 }, |
| { 286000000 }, |
| { 291750000 }, |
| { 296703000 }, |
| { 297000000 }, |
| { 298000000 }, |
| }; |
| |
| struct test_ops { |
| bool (*compute)(int clock, struct skl_wrpll_params *params); |
| } tests[] = { |
| { .compute = skl_ddi_calculate_wrpll1 }, |
| { .compute = skl_ddi_calculate_wrpll2 }, |
| }; |
| |
| static void test_run(struct test_ops *test) |
| { |
| unsigned int m; |
| unsigned p_odd_even[2] = { 0, 0 }; |
| igt_stats_t stats; |
| |
| igt_stats_init_with_size(&stats, ARRAY_SIZE(modes)); |
| igt_stats_set_population(&stats, true); |
| |
| for (m = 0; m < ARRAY_SIZE(modes); m++) { |
| struct skl_wrpll_params params = {}; |
| int clock = modes[m].clock; |
| unsigned int p; |
| |
| if (!test->compute(clock, ¶ms)) { |
| fprintf(stderr, "Couldn't compute divider for %dHz\n", |
| clock); |
| continue; |
| } |
| |
| p = params.p0 * params.p1 * params.p2; |
| |
| /* |
| * make sure we respect the +1%/-6% contraint around the |
| * central frequency |
| */ |
| { |
| uint64_t dco_freq = (uint64_t)p * clock * 5; |
| uint64_t central_freq = params.central_freq_hz; |
| uint64_t deviation; |
| uint64_t diff; |
| |
| diff = abs_diff(dco_freq, central_freq); |
| deviation = div64_u64(10000 * diff, central_freq); |
| |
| igt_stats_push(&stats, deviation); |
| |
| if (dco_freq > central_freq) { |
| if (deviation > 100) |
| printf("failed constraint for %dHz " |
| "deviation=%"PRIu64"\n", clock, |
| deviation); |
| } else if (deviation > 600) |
| printf("failed constraint for %dHz " |
| "deviation=%"PRIu64"\n", clock, |
| deviation); |
| } |
| |
| /* |
| * count how many even/odd dividers we have through the whole |
| * list of tested frequencies |
| */ |
| { |
| p_odd_even[p % 2]++; |
| } |
| } |
| |
| printf("even/odd dividers: %d/%d\n", p_odd_even[0], p_odd_even[1]); |
| printf("mean central freq deviation: %.2lf\n", |
| igt_stats_get_mean(&stats)); |
| |
| igt_stats_fini(&stats); |
| } |
| |
| int main(int argc, char **argv) |
| { |
| unsigned int t; |
| |
| test_multipliers(); |
| |
| for (t = 0; t < ARRAY_SIZE(tests); t++) { |
| printf("=== Testing algorithm #%d\n", t + 1); |
| test_run(&tests[t]); |
| } |
| |
| |
| return 0; |
| } |