1 /*
2 * Copyright © 2017 Intel Corporation
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21 * DEALINGS IN THE SOFTWARE.
22 */
23
24 #include <assert.h>
25 #include <inttypes.h>
26 #include <stdio.h>
27 #include <stdbool.h>
28 #include <stdint.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <math.h>
32
33 #define U32_MAX ((uint32_t)~0ULL)
34 #define ARRAY_SIZE(arr) (sizeof(arr)/sizeof(arr[0]))
35
div_u64(uint64_t dividend,uint32_t divisor)36 static inline uint64_t div_u64(uint64_t dividend, uint32_t divisor)
37 {
38 return dividend / divisor;
39 }
40
41 struct skl_wrpll_params {
42 uint32_t dco_fraction;
43 uint32_t dco_integer;
44 uint32_t qdiv_ratio;
45 uint32_t qdiv_mode;
46 uint32_t kdiv;
47 uint32_t pdiv;
48
49 /* for this test code only */
50 unsigned int ref_clock;
51 } __attribute__((packed));
52
dump_params(const char * name,struct skl_wrpll_params * params)53 static void dump_params(const char *name, struct skl_wrpll_params *params)
54 {
55 printf("%s:\n", name);
56 printf("Pdiv: %d\n", params->pdiv);
57 printf("Qdiv: %d\n", params->qdiv_ratio);
58 printf("Kdiv: %d\n", params->kdiv);
59 printf("qdiv mode: %d\n", params->qdiv_mode);
60 printf("dco integer: %d\n", params->dco_integer);
61 printf("dco fraction: %d\n", params->dco_fraction);
62 }
63
compare_params(unsigned int clock,const char * name1,struct skl_wrpll_params * p1,const char * name2,struct skl_wrpll_params * p2)64 static void compare_params(unsigned int clock,
65 const char *name1, struct skl_wrpll_params *p1,
66 const char *name2, struct skl_wrpll_params *p2)
67 {
68 if (memcmp(p1, p2, sizeof(struct skl_wrpll_params)) == 0)
69 return;
70
71 printf("=======================================\n");
72 printf("Difference with clock: %10.6f MHz\n", clock/1000000.0);
73 printf("Reference clock: %10.6f MHz\n\n", p1->ref_clock/1000.0);
74 dump_params(name1, p1);
75 printf("\n");
76 dump_params(name2, p2);
77 printf("=======================================\n");
78 }
79
cnl_wrpll_params_populate(struct skl_wrpll_params * params,uint32_t dco_freq,uint32_t ref_freq,uint32_t pdiv,uint32_t qdiv,uint32_t kdiv)80 static void cnl_wrpll_params_populate(struct skl_wrpll_params *params,
81 uint32_t dco_freq, uint32_t ref_freq,
82 uint32_t pdiv, uint32_t qdiv,
83 uint32_t kdiv)
84 {
85 uint32_t dco;
86
87 params->qdiv_ratio = qdiv;
88 params->qdiv_mode = (qdiv == 1) ? 0 : 1;
89 params->pdiv = pdiv;
90 params->kdiv = kdiv;
91
92 if (kdiv != 2 && qdiv != 1)
93 printf("kdiv != 2 and qdiv != 1\n");
94
95 dco = div_u64((uint64_t)dco_freq << 15, ref_freq);
96
97 params->dco_integer = dco >> 15;
98 params->dco_fraction = dco & 0x7fff;
99 }
100
cnl_wrpll_get_multipliers(int bestdiv,int * pdiv,int * qdiv,int * kdiv)101 static void cnl_wrpll_get_multipliers(int bestdiv,
102 int *pdiv,
103 int *qdiv,
104 int *kdiv)
105 {
106 /* even dividers */
107 if (bestdiv % 2 == 0) {
108 if (bestdiv == 2) {
109 *pdiv = 2;
110 *qdiv = 1;
111 *kdiv = 1;
112 } else if (bestdiv % 4 == 0) {
113 *pdiv = 2;
114 *qdiv = bestdiv / 4;
115 *kdiv = 2;
116 } else if (bestdiv % 6 == 0) {
117 *pdiv = 3;
118 *qdiv = bestdiv / 6;
119 *kdiv = 2;
120 } else if (bestdiv % 5 == 0) {
121 *pdiv = 5;
122 *qdiv = bestdiv / 10;
123 *kdiv = 2;
124 } else if (bestdiv % 14 == 0) {
125 *pdiv = 7;
126 *qdiv = bestdiv / 14;
127 *kdiv = 2;
128 }
129 } else {
130 if (bestdiv == 3 || bestdiv == 5 || bestdiv == 7) {
131 *pdiv = bestdiv;
132 *qdiv = 1;
133 *kdiv = 1;
134 } else { /* 9, 15, 21 */
135 *pdiv = bestdiv / 3;
136 *qdiv = 1;
137 *kdiv = 3;
138 }
139 }
140 }
141
142 static bool
cnl_ddi_calculate_wrpll1(int clock,struct skl_wrpll_params * params)143 cnl_ddi_calculate_wrpll1(int clock /* in Hz */,
144 struct skl_wrpll_params *params)
145 {
146 double afe_clock = (clock/1000000.0) * 5; /* clocks in MHz */
147 double dco_min = 7998;
148 double dco_max = 10000;
149 double dco_mid = (dco_min + dco_max) / 2;
150 static const int dividers[] = { 2, 4, 6, 8, 10, 12, 14, 16,
151 18, 20, 24, 28, 30, 32, 36, 40,
152 42, 44, 48, 50, 52, 54, 56, 60,
153 64, 66, 68, 70, 72, 76, 78, 80,
154 84, 88, 90, 92, 96, 98, 100, 102,
155 3, 5, 7, 9, 15, 21 };
156 double dco, dco_centrality = 0;
157 double best_dco_centrality = 999999;
158 int d, best_div = 0, pdiv = 0, qdiv = 0, kdiv = 0;
159 double ref_clock = params->ref_clock/1000.0; /* MHz */
160 uint32_t dco_int, dco_frac;
161
162 for (d = 0; d < ARRAY_SIZE(dividers); d++) {
163 dco = afe_clock * dividers[d];
164
165 if ((dco <= dco_max) && (dco >= dco_min)) {
166 dco_centrality = fabs(dco - dco_mid);
167
168 if (dco_centrality < best_dco_centrality) {
169 best_dco_centrality = dco_centrality;
170 best_div = dividers[d];
171 dco_int = (uint32_t)(dco/ref_clock);
172 dco_frac = round((dco/ref_clock - dco_int) * (1<<15));
173 }
174 }
175 }
176
177 if (best_div != 0) {
178 cnl_wrpll_get_multipliers(best_div, &pdiv, &qdiv, &kdiv);
179
180 params->qdiv_ratio = qdiv;
181 params->qdiv_mode = (qdiv == 1) ? 0 : 1;
182 params->pdiv = pdiv;
183 params->kdiv = kdiv;
184 params->dco_integer = dco_int;
185 params->dco_fraction = dco_frac;
186 } else {
187 return false;
188 }
189
190 return true;
191 }
192
193 static bool
cnl_ddi_calculate_wrpll2(int clock,struct skl_wrpll_params * params)194 cnl_ddi_calculate_wrpll2(int clock,
195 struct skl_wrpll_params *params)
196 {
197 uint32_t afe_clock = clock * 5 / 1000; /* clock in kHz */
198 uint32_t dco_min = 7998000;
199 uint32_t dco_max = 10000000;
200 uint32_t dco_mid = (dco_min + dco_max) / 2;
201 static const int dividers[] = { 2, 4, 6, 8, 10, 12, 14, 16,
202 18, 20, 24, 28, 30, 32, 36, 40,
203 42, 44, 48, 50, 52, 54, 56, 60,
204 64, 66, 68, 70, 72, 76, 78, 80,
205 84, 88, 90, 92, 96, 98, 100, 102,
206 3, 5, 7, 9, 15, 21 };
207 uint32_t dco, best_dco = 0, dco_centrality = 0;
208 uint32_t best_dco_centrality = U32_MAX; /* Spec meaning of 999999 MHz */
209 int d, best_div = 0, pdiv = 0, qdiv = 0, kdiv = 0;
210 uint32_t ref_clock = params->ref_clock;
211
212 for (d = 0; d < ARRAY_SIZE(dividers); d++) {
213 dco = afe_clock * dividers[d];
214
215 if ((dco <= dco_max) && (dco >= dco_min)) {
216 dco_centrality = abs(dco - dco_mid);
217
218 if (dco_centrality < best_dco_centrality) {
219 best_dco_centrality = dco_centrality;
220 best_div = dividers[d];
221 best_dco = dco;
222 }
223 }
224 }
225
226 if (best_div == 0)
227 return false;
228
229 cnl_wrpll_get_multipliers(best_div, &pdiv, &qdiv, &kdiv);
230
231 cnl_wrpll_params_populate(params, best_dco, ref_clock,
232 pdiv, qdiv, kdiv);
233
234 return true;
235 }
236
test_multipliers(unsigned int clock)237 static void test_multipliers(unsigned int clock)
238 {
239 uint64_t afe_clock = clock * 5 / 1000; /* clocks in kHz */
240 unsigned int dco_min = 7998000;
241 unsigned int dco_max = 10000000;
242 unsigned int dco_mid = (dco_min + dco_max) / 2;
243
244 static const int dividerlist[] = { 2, 4, 6, 8, 10, 12, 14, 16,
245 18, 20, 24, 28, 30, 32, 36, 40,
246 42, 44, 48, 50, 52, 54, 56, 60,
247 64, 66, 68, 70, 72, 76, 78, 80,
248 84, 88, 90, 92, 96, 98, 100, 102,
249 3, 5, 7, 9, 15, 21 };
250 unsigned int dco, dco_centrality = 0;
251 unsigned int best_dco_centrality = U32_MAX;
252 int d, best_div = 0, pdiv = 0, qdiv = 0, kdiv = 0;
253
254 for (d = 0; d < ARRAY_SIZE(dividerlist); d++) {
255 dco = afe_clock * dividerlist[d];
256
257 if ((dco <= dco_max) && (dco >= dco_min)) {
258 dco_centrality = abs(dco - dco_mid);
259
260 if (dco_centrality < best_dco_centrality) {
261 best_dco_centrality = dco_centrality;
262 best_div = dividerlist[d];
263 }
264 }
265
266 if (best_div != 0) {
267 cnl_wrpll_get_multipliers(best_div, &pdiv, &qdiv, &kdiv);
268
269 if ((kdiv != 2) && (qdiv == 1))
270 continue;
271 else
272 break;
273 }
274 }
275
276 assert(pdiv);
277 assert(qdiv);
278 assert(kdiv);
279
280 if (kdiv != 2)
281 assert(qdiv == 1);
282 }
283
284 static const struct {
285 uint32_t clock; /* in Hz */
286 } modes[] = {
287 {19750000},
288 {23500000},
289 {23750000},
290 {25175000},
291 {25200000},
292 {26000000},
293 {27000000},
294 {27027000},
295 {27500000},
296 {28750000},
297 {29750000},
298 {30750000},
299 {31500000},
300 {35000000},
301 {35500000},
302 {36750000},
303 {37000000},
304 {37088000},
305 {37125000},
306 {37762500},
307 {37800000},
308 {38250000},
309 {40500000},
310 {40541000},
311 {40750000},
312 {41000000},
313 {41500000},
314 {42500000},
315 {45250000},
316 {46360000},
317 {46406000},
318 {46750000},
319 {49000000},
320 {50500000},
321 {52000000},
322 {54000000},
323 {54054000},
324 {54500000},
325 {55632000},
326 {55688000},
327 {56000000},
328 {56750000},
329 {58250000},
330 {58750000},
331 {59341000},
332 {59400000},
333 {60500000},
334 {62250000},
335 {63500000},
336 {64000000},
337 {65250000},
338 {65500000},
339 {66750000},
340 {67750000},
341 {68250000},
342 {69000000},
343 {72000000},
344 {74176000},
345 {74250000},
346 {74500000},
347 {75250000},
348 {76000000},
349 {79500000},
350 {81000000},
351 {81081000},
352 {82000000},
353 {83000000},
354 {84750000},
355 {85250000},
356 {85750000},
357 {88500000},
358 {89012000},
359 {89100000},
360 {91000000},
361 {92719800},
362 {92812500},
363 {94500000},
364 {95750000},
365 {97750000},
366 {99000000},
367 {99750000},
368 {100000000},
369 {100500000},
370 {101000000},
371 {101250000},
372 {102250000},
373 {107892000},
374 {108000000},
375 {108108000},
376 {109000000},
377 {110250000},
378 {110500000},
379 {111264000},
380 {111375000},
381 {112500000},
382 {117500000},
383 {119000000},
384 {119500000},
385 {121250000},
386 {121750000},
387 {125250000},
388 {125750000},
389 {127250000},
390 {130000000},
391 {130250000},
392 {131000000},
393 {131500000},
394 {132750000},
395 {135250000},
396 {138500000},
397 {138750000},
398 {141500000},
399 {146250000},
400 {148250000},
401 {148352000},
402 {148500000},
403 {154000000},
404 {155250000},
405 {155750000},
406 {156000000},
407 {158250000},
408 {159500000},
409 {161000000},
410 {162000000},
411 {162162000},
412 {162500000},
413 {169500000},
414 {172750000},
415 {173000000},
416 {175000000},
417 {178500000},
418 {179500000},
419 {184750000},
420 {185440000},
421 {185625000},
422 {187000000},
423 {192250000},
424 {193250000},
425 {197750000},
426 {198500000},
427 {204750000},
428 {207500000},
429 {209250000},
430 {213750000},
431 {214750000},
432 {216000000},
433 {218750000},
434 {219000000},
435 {220750000},
436 {222525000},
437 {222750000},
438 {227000000},
439 {230250000},
440 {233500000},
441 {235000000},
442 {238000000},
443 {241500000},
444 {243000000},
445 {245250000},
446 {247750000},
447 {253250000},
448 {256250000},
449 {262500000},
450 {267250000},
451 {268500000},
452 {270000000},
453 {272500000},
454 {273750000},
455 {280750000},
456 {281250000},
457 {286000000},
458 {291750000},
459 {296703000},
460 {297000000},
461 {298000000},
462 {303750000},
463 {322250000},
464 {324000000},
465 {337750000},
466 {370878750},
467 {371250000},
468 {373250000},
469 {414500000},
470 {432000000},
471 {445054500},
472 {445500000},
473 {497750000},
474 {533250000},
475 {540000000},
476 {592500000},
477 {594000000},
478 {648000000},
479 {810000000},
480 };
481
test_run(unsigned int ref_clock)482 static void test_run(unsigned int ref_clock)
483 {
484 unsigned int m;
485 struct skl_wrpll_params params[2];
486
487 for (m = 0; m < ARRAY_SIZE(modes); m++) {
488 int clock = modes[m].clock;
489 bool skip = false;
490
491 params[0].ref_clock = params[1].ref_clock = ref_clock;
492
493 if (!cnl_ddi_calculate_wrpll1(clock, ¶ms[0])) {
494 fprintf(stderr, "Reference: Couldn't compute divider for %dHz, reference %dHz\n",
495 clock, params[0].ref_clock*1000);
496 skip = true;
497 }
498
499 if (!skip) {
500 if (!cnl_ddi_calculate_wrpll2(clock, ¶ms[1])) {
501 fprintf(stderr, "i915 implementation: Couldn't compute divider for %dHz, reference %dHz\n",
502 clock, params[1].ref_clock*1000);
503 }
504
505 compare_params(clock, "Reference", ¶ms[0],
506 "i915 implementation", ¶ms[1]);
507 }
508 }
509 }
510
main(int argc,char ** argv)511 int main(int argc, char **argv)
512 {
513 unsigned int m;
514 unsigned int f;
515 unsigned int ref_clocks[] = {19200, 24000}; /* in kHz */
516
517 for (m = 0; m < ARRAY_SIZE(modes); m++)
518 test_multipliers(modes[m].clock);
519
520 for (f = 0; f < ARRAY_SIZE(ref_clocks); f++) {
521 printf("=== Testing with ref clock %d kHz\n", ref_clocks[f]);
522 test_run(ref_clocks[f]);
523 }
524
525 return 0;
526 }
527