Merge tag 'cxl-for-5.15' of git://git.kernel.org/pub/scm/linux/kernel/git/cxl/cxl
[linux-2.6-microblaze.git] / drivers / gpu / drm / mgag200 / mgag200_pll.c
1 // SPDX-License-Identifier: GPL-2.0-only
2
3 #include <linux/delay.h>
4
5 #include "mgag200_drv.h"
6
7 /*
8  * G200
9  */
10
11 static int mgag200_pixpll_compute_g200(struct mgag200_pll *pixpll, long clock,
12                                        struct mgag200_pll_values *pixpllc)
13 {
14         struct mga_device *mdev = pixpll->mdev;
15         struct drm_device *dev = &mdev->base;
16         const int post_div_max = 7;
17         const int in_div_min = 1;
18         const int in_div_max = 6;
19         const int feed_div_min = 7;
20         const int feed_div_max = 127;
21         u8 testp, testm, testn;
22         u8 n = 0, m = 0, p, s;
23         long f_vco;
24         long computed;
25         long delta, tmp_delta;
26         long ref_clk = mdev->model.g200.ref_clk;
27         long p_clk_min = mdev->model.g200.pclk_min;
28         long p_clk_max =  mdev->model.g200.pclk_max;
29
30         if (clock > p_clk_max) {
31                 drm_err(dev, "Pixel Clock %ld too high\n", clock);
32                 return -EINVAL;
33         }
34
35         if (clock < p_clk_min >> 3)
36                 clock = p_clk_min >> 3;
37
38         f_vco = clock;
39         for (testp = 0;
40              testp <= post_div_max && f_vco < p_clk_min;
41              testp = (testp << 1) + 1, f_vco <<= 1)
42                 ;
43         p = testp + 1;
44
45         delta = clock;
46
47         for (testm = in_div_min; testm <= in_div_max; testm++) {
48                 for (testn = feed_div_min; testn <= feed_div_max; testn++) {
49                         computed = ref_clk * (testn + 1) / (testm + 1);
50                         if (computed < f_vco)
51                                 tmp_delta = f_vco - computed;
52                         else
53                                 tmp_delta = computed - f_vco;
54                         if (tmp_delta < delta) {
55                                 delta = tmp_delta;
56                                 m = testm + 1;
57                                 n = testn + 1;
58                         }
59                 }
60         }
61         f_vco = ref_clk * n / m;
62         if (f_vco < 100000)
63                 s = 0;
64         else if (f_vco < 140000)
65                 s = 1;
66         else if (f_vco < 180000)
67                 s = 2;
68         else
69                 s = 3;
70
71         drm_dbg_kms(dev, "clock: %ld vco: %ld m: %d n: %d p: %d s: %d\n",
72                     clock, f_vco, m, n, p, s);
73
74         pixpllc->m = m;
75         pixpllc->n = n;
76         pixpllc->p = p;
77         pixpllc->s = s;
78
79         return 0;
80 }
81
82 static void
83 mgag200_pixpll_update_g200(struct mgag200_pll *pixpll, const struct mgag200_pll_values *pixpllc)
84 {
85         struct mga_device *mdev = pixpll->mdev;
86         unsigned int pixpllcm, pixpllcn, pixpllcp, pixpllcs;
87         u8 xpixpllcm, xpixpllcn, xpixpllcp;
88
89         pixpllcm = pixpllc->m - 1;
90         pixpllcn = pixpllc->n - 1;
91         pixpllcp = pixpllc->p - 1;
92         pixpllcs = pixpllc->s;
93
94         xpixpllcm = pixpllcm;
95         xpixpllcn = pixpllcn;
96         xpixpllcp = (pixpllcs << 3) | pixpllcp;
97
98         WREG_MISC_MASKED(MGAREG_MISC_CLKSEL_MGA, MGAREG_MISC_CLKSEL_MASK);
99
100         WREG_DAC(MGA1064_PIX_PLLC_M, xpixpllcm);
101         WREG_DAC(MGA1064_PIX_PLLC_N, xpixpllcn);
102         WREG_DAC(MGA1064_PIX_PLLC_P, xpixpllcp);
103 }
104
105 static const struct mgag200_pll_funcs mgag200_pixpll_funcs_g200 = {
106         .compute = mgag200_pixpll_compute_g200,
107         .update = mgag200_pixpll_update_g200,
108 };
109
110 /*
111  * G200SE
112  */
113
114 static int mgag200_pixpll_compute_g200se_00(struct mgag200_pll *pixpll, long clock,
115                                             struct mgag200_pll_values *pixpllc)
116 {
117         static const unsigned int vcomax = 320000;
118         static const unsigned int vcomin = 160000;
119         static const unsigned int pllreffreq = 25000;
120
121         unsigned int delta, tmpdelta, permitteddelta;
122         unsigned int testp, testm, testn;
123         unsigned int p, m, n, s;
124         unsigned int computed;
125
126         m = n = p = s = 0;
127         permitteddelta = clock * 5 / 1000;
128
129         for (testp = 8; testp > 0; testp /= 2) {
130                 if (clock * testp > vcomax)
131                         continue;
132                 if (clock * testp < vcomin)
133                         continue;
134
135                 for (testn = 17; testn < 256; testn++) {
136                         for (testm = 1; testm < 32; testm++) {
137                                 computed = (pllreffreq * testn) / (testm * testp);
138                                 if (computed > clock)
139                                         tmpdelta = computed - clock;
140                                 else
141                                         tmpdelta = clock - computed;
142                                 if (tmpdelta < delta) {
143                                         delta = tmpdelta;
144                                         m = testm;
145                                         n = testn;
146                                         p = testp;
147                                 }
148                         }
149                 }
150         }
151
152         if (delta > permitteddelta) {
153                 pr_warn("PLL delta too large\n");
154                 return -EINVAL;
155         }
156
157         pixpllc->m = m;
158         pixpllc->n = n;
159         pixpllc->p = p;
160         pixpllc->s = s;
161
162         return 0;
163 }
164
165 static void mgag200_pixpll_update_g200se_00(struct mgag200_pll *pixpll,
166                                             const struct mgag200_pll_values *pixpllc)
167 {
168         unsigned int pixpllcm, pixpllcn, pixpllcp, pixpllcs;
169         u8 xpixpllcm, xpixpllcn, xpixpllcp;
170         struct mga_device *mdev = pixpll->mdev;
171
172         pixpllcm = pixpllc->m - 1;
173         pixpllcn = pixpllc->n - 1;
174         pixpllcp = pixpllc->p - 1;
175         pixpllcs = pixpllc->s;
176
177         xpixpllcm = pixpllcm | ((pixpllcn & BIT(8)) >> 1);
178         xpixpllcn = pixpllcn;
179         xpixpllcp = (pixpllcs << 3) | pixpllcp;
180
181         WREG_MISC_MASKED(MGAREG_MISC_CLKSEL_MGA, MGAREG_MISC_CLKSEL_MASK);
182
183         WREG_DAC(MGA1064_PIX_PLLC_M, xpixpllcm);
184         WREG_DAC(MGA1064_PIX_PLLC_N, xpixpllcn);
185         WREG_DAC(MGA1064_PIX_PLLC_P, xpixpllcp);
186 }
187
188 static int mgag200_pixpll_compute_g200se_04(struct mgag200_pll *pixpll, long clock,
189                                             struct mgag200_pll_values *pixpllc)
190 {
191         static const unsigned int vcomax = 1600000;
192         static const unsigned int vcomin = 800000;
193         static const unsigned int pllreffreq = 25000;
194         static const unsigned int pvalues_e4[] = {16, 14, 12, 10, 8, 6, 4, 2, 1};
195
196         unsigned int delta, tmpdelta, permitteddelta;
197         unsigned int testp, testm, testn;
198         unsigned int p, m, n, s;
199         unsigned int computed;
200         unsigned int fvv;
201         unsigned int i;
202
203         m = n = p = s = 0;
204         delta = 0xffffffff;
205
206         if (clock < 25000)
207                 clock = 25000;
208         clock = clock * 2;
209
210         /* Permited delta is 0.5% as VESA Specification */
211         permitteddelta = clock * 5 / 1000;
212
213         for (i = 0 ; i < ARRAY_SIZE(pvalues_e4); i++) {
214                 testp = pvalues_e4[i];
215
216                 if ((clock * testp) > vcomax)
217                         continue;
218                 if ((clock * testp) < vcomin)
219                         continue;
220
221                 for (testn = 50; testn <= 256; testn++) {
222                         for (testm = 1; testm <= 32; testm++) {
223                                 computed = (pllreffreq * testn) / (testm * testp);
224                                 if (computed > clock)
225                                         tmpdelta = computed - clock;
226                                 else
227                                         tmpdelta = clock - computed;
228
229                                 if (tmpdelta < delta) {
230                                         delta = tmpdelta;
231                                         m = testm;
232                                         n = testn;
233                                         p = testp;
234                                 }
235                         }
236                 }
237         }
238
239         fvv = pllreffreq * n / m;
240         fvv = (fvv - 800000) / 50000;
241         if (fvv > 15)
242                 fvv = 15;
243         s = fvv << 1;
244
245         if (delta > permitteddelta) {
246                 pr_warn("PLL delta too large\n");
247                 return -EINVAL;
248         }
249
250         pixpllc->m = m;
251         pixpllc->n = n;
252         pixpllc->p = p;
253         pixpllc->s = s;
254
255         return 0;
256 }
257
258 static void mgag200_pixpll_update_g200se_04(struct mgag200_pll *pixpll,
259                                             const struct mgag200_pll_values *pixpllc)
260 {
261         unsigned int pixpllcm, pixpllcn, pixpllcp, pixpllcs;
262         u8 xpixpllcm, xpixpllcn, xpixpllcp;
263         struct mga_device *mdev = pixpll->mdev;
264
265         pixpllcm = pixpllc->m - 1;
266         pixpllcn = pixpllc->n - 1;
267         pixpllcp = pixpllc->p - 1;
268         pixpllcs = pixpllc->s;
269
270         xpixpllcm = pixpllcm | ((pixpllcn & BIT(8)) >> 1);
271         xpixpllcn = pixpllcn;
272         xpixpllcp = (pixpllcs << 3) | pixpllcp;
273
274         WREG_MISC_MASKED(MGAREG_MISC_CLKSEL_MGA, MGAREG_MISC_CLKSEL_MASK);
275
276         WREG_DAC(MGA1064_PIX_PLLC_M, xpixpllcm);
277         WREG_DAC(MGA1064_PIX_PLLC_N, xpixpllcn);
278         WREG_DAC(MGA1064_PIX_PLLC_P, xpixpllcp);
279
280         WREG_DAC(0x1a, 0x09);
281         msleep(20);
282         WREG_DAC(0x1a, 0x01);
283 }
284
285 static const struct mgag200_pll_funcs mgag200_pixpll_funcs_g200se_00 = {
286         .compute = mgag200_pixpll_compute_g200se_00,
287         .update = mgag200_pixpll_update_g200se_00,
288 };
289
290 static const struct mgag200_pll_funcs mgag200_pixpll_funcs_g200se_04 = {
291         .compute = mgag200_pixpll_compute_g200se_04,
292         .update = mgag200_pixpll_update_g200se_04,
293 };
294
295 /*
296  * G200WB
297  */
298
299 static int mgag200_pixpll_compute_g200wb(struct mgag200_pll *pixpll, long clock,
300                                          struct mgag200_pll_values *pixpllc)
301 {
302         static const unsigned int vcomax = 550000;
303         static const unsigned int vcomin = 150000;
304         static const unsigned int pllreffreq = 48000;
305
306         unsigned int delta, tmpdelta;
307         unsigned int testp, testm, testn;
308         unsigned int p, m, n, s;
309         unsigned int computed;
310
311         m = n = p = s = 0;
312         delta = 0xffffffff;
313
314         for (testp = 1; testp < 9; testp++) {
315                 if (clock * testp > vcomax)
316                         continue;
317                 if (clock * testp < vcomin)
318                         continue;
319
320                 for (testm = 1; testm < 17; testm++) {
321                         for (testn = 1; testn < 151; testn++) {
322                                 computed = (pllreffreq * testn) / (testm * testp);
323                                 if (computed > clock)
324                                         tmpdelta = computed - clock;
325                                 else
326                                         tmpdelta = clock - computed;
327                                 if (tmpdelta < delta) {
328                                         delta = tmpdelta;
329                                         n = testn;
330                                         m = testm;
331                                         p = testp;
332                                         s = 0;
333                                 }
334                         }
335                 }
336         }
337
338         pixpllc->m = m;
339         pixpllc->n = n;
340         pixpllc->p = p;
341         pixpllc->s = s;
342
343         return 0;
344 }
345
346 static void
347 mgag200_pixpll_update_g200wb(struct mgag200_pll *pixpll, const struct mgag200_pll_values *pixpllc)
348 {
349         unsigned int pixpllcm, pixpllcn, pixpllcp, pixpllcs;
350         u8 xpixpllcm, xpixpllcn, xpixpllcp, tmp;
351         int i, j, tmpcount, vcount;
352         struct mga_device *mdev = pixpll->mdev;
353         bool pll_locked = false;
354
355         pixpllcm = pixpllc->m - 1;
356         pixpllcn = pixpllc->n - 1;
357         pixpllcp = pixpllc->p - 1;
358         pixpllcs = pixpllc->s;
359
360         xpixpllcm = ((pixpllcn & BIT(8)) >> 1) | pixpllcm;
361         xpixpllcn = pixpllcn;
362         xpixpllcp = ((pixpllcn & GENMASK(10, 9)) >> 3) | (pixpllcs << 3) | pixpllcp;
363
364         WREG_MISC_MASKED(MGAREG_MISC_CLKSEL_MGA, MGAREG_MISC_CLKSEL_MASK);
365
366         for (i = 0; i <= 32 && pll_locked == false; i++) {
367                 if (i > 0) {
368                         WREG8(MGAREG_CRTC_INDEX, 0x1e);
369                         tmp = RREG8(MGAREG_CRTC_DATA);
370                         if (tmp < 0xff)
371                                 WREG8(MGAREG_CRTC_DATA, tmp+1);
372                 }
373
374                 /* set pixclkdis to 1 */
375                 WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL);
376                 tmp = RREG8(DAC_DATA);
377                 tmp |= MGA1064_PIX_CLK_CTL_CLK_DIS;
378                 WREG8(DAC_DATA, tmp);
379
380                 WREG8(DAC_INDEX, MGA1064_REMHEADCTL);
381                 tmp = RREG8(DAC_DATA);
382                 tmp |= MGA1064_REMHEADCTL_CLKDIS;
383                 WREG8(DAC_DATA, tmp);
384
385                 /* select PLL Set C */
386                 tmp = RREG8(MGAREG_MEM_MISC_READ);
387                 tmp |= 0x3 << 2;
388                 WREG8(MGAREG_MEM_MISC_WRITE, tmp);
389
390                 WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL);
391                 tmp = RREG8(DAC_DATA);
392                 tmp |= MGA1064_PIX_CLK_CTL_CLK_POW_DOWN | 0x80;
393                 WREG8(DAC_DATA, tmp);
394
395                 udelay(500);
396
397                 /* reset the PLL */
398                 WREG8(DAC_INDEX, MGA1064_VREF_CTL);
399                 tmp = RREG8(DAC_DATA);
400                 tmp &= ~0x04;
401                 WREG8(DAC_DATA, tmp);
402
403                 udelay(50);
404
405                 /* program pixel pll register */
406                 WREG_DAC(MGA1064_PIX_PLLC_N, xpixpllcn);
407                 WREG_DAC(MGA1064_PIX_PLLC_M, xpixpllcm);
408                 WREG_DAC(MGA1064_PIX_PLLC_P, xpixpllcp);
409
410                 udelay(50);
411
412                 /* turn pll on */
413                 WREG8(DAC_INDEX, MGA1064_VREF_CTL);
414                 tmp = RREG8(DAC_DATA);
415                 tmp |= 0x04;
416                 WREG_DAC(MGA1064_VREF_CTL, tmp);
417
418                 udelay(500);
419
420                 /* select the pixel pll */
421                 WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL);
422                 tmp = RREG8(DAC_DATA);
423                 tmp &= ~MGA1064_PIX_CLK_CTL_SEL_MSK;
424                 tmp |= MGA1064_PIX_CLK_CTL_SEL_PLL;
425                 WREG8(DAC_DATA, tmp);
426
427                 WREG8(DAC_INDEX, MGA1064_REMHEADCTL);
428                 tmp = RREG8(DAC_DATA);
429                 tmp &= ~MGA1064_REMHEADCTL_CLKSL_MSK;
430                 tmp |= MGA1064_REMHEADCTL_CLKSL_PLL;
431                 WREG8(DAC_DATA, tmp);
432
433                 /* reset dotclock rate bit */
434                 WREG8(MGAREG_SEQ_INDEX, 1);
435                 tmp = RREG8(MGAREG_SEQ_DATA);
436                 tmp &= ~0x8;
437                 WREG8(MGAREG_SEQ_DATA, tmp);
438
439                 WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL);
440                 tmp = RREG8(DAC_DATA);
441                 tmp &= ~MGA1064_PIX_CLK_CTL_CLK_DIS;
442                 WREG8(DAC_DATA, tmp);
443
444                 vcount = RREG8(MGAREG_VCOUNT);
445
446                 for (j = 0; j < 30 && pll_locked == false; j++) {
447                         tmpcount = RREG8(MGAREG_VCOUNT);
448                         if (tmpcount < vcount)
449                                 vcount = 0;
450                         if ((tmpcount - vcount) > 2)
451                                 pll_locked = true;
452                         else
453                                 udelay(5);
454                 }
455         }
456
457         WREG8(DAC_INDEX, MGA1064_REMHEADCTL);
458         tmp = RREG8(DAC_DATA);
459         tmp &= ~MGA1064_REMHEADCTL_CLKDIS;
460         WREG_DAC(MGA1064_REMHEADCTL, tmp);
461 }
462
463 static const struct mgag200_pll_funcs mgag200_pixpll_funcs_g200wb = {
464         .compute = mgag200_pixpll_compute_g200wb,
465         .update = mgag200_pixpll_update_g200wb,
466 };
467
468 /*
469  * G200EV
470  */
471
472 static int mgag200_pixpll_compute_g200ev(struct mgag200_pll *pixpll, long clock,
473                                          struct mgag200_pll_values *pixpllc)
474 {
475         static const unsigned int vcomax = 550000;
476         static const unsigned int vcomin = 150000;
477         static const unsigned int pllreffreq = 50000;
478
479         unsigned int delta, tmpdelta;
480         unsigned int testp, testm, testn;
481         unsigned int p, m, n, s;
482         unsigned int computed;
483
484         m = n = p = s = 0;
485         delta = 0xffffffff;
486
487         for (testp = 16; testp > 0; testp--) {
488                 if (clock * testp > vcomax)
489                         continue;
490                 if (clock * testp < vcomin)
491                         continue;
492
493                 for (testn = 1; testn < 257; testn++) {
494                         for (testm = 1; testm < 17; testm++) {
495                                 computed = (pllreffreq * testn) /
496                                         (testm * testp);
497                                 if (computed > clock)
498                                         tmpdelta = computed - clock;
499                                 else
500                                         tmpdelta = clock - computed;
501                                 if (tmpdelta < delta) {
502                                         delta = tmpdelta;
503                                         n = testn;
504                                         m = testm;
505                                         p = testp;
506                                 }
507                         }
508                 }
509         }
510
511         pixpllc->m = m;
512         pixpllc->n = n;
513         pixpllc->p = p;
514         pixpllc->s = s;
515
516         return 0;
517 }
518
519 static void
520 mgag200_pixpll_update_g200ev(struct mgag200_pll *pixpll, const struct mgag200_pll_values *pixpllc)
521 {
522         unsigned int pixpllcm, pixpllcn, pixpllcp, pixpllcs;
523         u8 xpixpllcm, xpixpllcn, xpixpllcp, tmp;
524         struct mga_device *mdev = pixpll->mdev;
525
526         pixpllcm = pixpllc->m - 1;
527         pixpllcn = pixpllc->n - 1;
528         pixpllcp = pixpllc->p - 1;
529         pixpllcs = pixpllc->s;
530
531         xpixpllcm = pixpllcm;
532         xpixpllcn = pixpllcn;
533         xpixpllcp = (pixpllcs << 3) | pixpllcp;
534
535         WREG_MISC_MASKED(MGAREG_MISC_CLKSEL_MGA, MGAREG_MISC_CLKSEL_MASK);
536
537         WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL);
538         tmp = RREG8(DAC_DATA);
539         tmp |= MGA1064_PIX_CLK_CTL_CLK_DIS;
540         WREG8(DAC_DATA, tmp);
541
542         tmp = RREG8(MGAREG_MEM_MISC_READ);
543         tmp |= 0x3 << 2;
544         WREG8(MGAREG_MEM_MISC_WRITE, tmp);
545
546         WREG8(DAC_INDEX, MGA1064_PIX_PLL_STAT);
547         tmp = RREG8(DAC_DATA);
548         WREG8(DAC_DATA, tmp & ~0x40);
549
550         WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL);
551         tmp = RREG8(DAC_DATA);
552         tmp |= MGA1064_PIX_CLK_CTL_CLK_POW_DOWN;
553         WREG8(DAC_DATA, tmp);
554
555         WREG_DAC(MGA1064_EV_PIX_PLLC_M, xpixpllcm);
556         WREG_DAC(MGA1064_EV_PIX_PLLC_N, xpixpllcn);
557         WREG_DAC(MGA1064_EV_PIX_PLLC_P, xpixpllcp);
558
559         udelay(50);
560
561         WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL);
562         tmp = RREG8(DAC_DATA);
563         tmp &= ~MGA1064_PIX_CLK_CTL_CLK_POW_DOWN;
564         WREG8(DAC_DATA, tmp);
565
566         udelay(500);
567
568         WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL);
569         tmp = RREG8(DAC_DATA);
570         tmp &= ~MGA1064_PIX_CLK_CTL_SEL_MSK;
571         tmp |= MGA1064_PIX_CLK_CTL_SEL_PLL;
572         WREG8(DAC_DATA, tmp);
573
574         WREG8(DAC_INDEX, MGA1064_PIX_PLL_STAT);
575         tmp = RREG8(DAC_DATA);
576         WREG8(DAC_DATA, tmp | 0x40);
577
578         tmp = RREG8(MGAREG_MEM_MISC_READ);
579         tmp |= (0x3 << 2);
580         WREG8(MGAREG_MEM_MISC_WRITE, tmp);
581
582         WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL);
583         tmp = RREG8(DAC_DATA);
584         tmp &= ~MGA1064_PIX_CLK_CTL_CLK_DIS;
585         WREG8(DAC_DATA, tmp);
586 }
587
588 static const struct mgag200_pll_funcs mgag200_pixpll_funcs_g200ev = {
589         .compute = mgag200_pixpll_compute_g200ev,
590         .update = mgag200_pixpll_update_g200ev,
591 };
592
593 /*
594  * G200EH
595  */
596
597 static int mgag200_pixpll_compute_g200eh(struct mgag200_pll *pixpll, long clock,
598                                          struct mgag200_pll_values *pixpllc)
599 {
600         static const unsigned int vcomax = 800000;
601         static const unsigned int vcomin = 400000;
602         static const unsigned int pllreffreq = 33333;
603
604         unsigned int delta, tmpdelta;
605         unsigned int testp, testm, testn;
606         unsigned int p, m, n, s;
607         unsigned int computed;
608
609         m = n = p = s = 0;
610         delta = 0xffffffff;
611
612         for (testp = 16; testp > 0; testp >>= 1) {
613                 if (clock * testp > vcomax)
614                         continue;
615                 if (clock * testp < vcomin)
616                         continue;
617
618                 for (testm = 1; testm < 33; testm++) {
619                         for (testn = 17; testn < 257; testn++) {
620                                 computed = (pllreffreq * testn) / (testm * testp);
621                                 if (computed > clock)
622                                         tmpdelta = computed - clock;
623                                 else
624                                         tmpdelta = clock - computed;
625                                 if (tmpdelta < delta) {
626                                         delta = tmpdelta;
627                                         n = testn;
628                                         m = testm;
629                                         p = testp;
630                                 }
631                         }
632                 }
633         }
634
635         pixpllc->m = m;
636         pixpllc->n = n;
637         pixpllc->p = p;
638         pixpllc->s = s;
639
640         return 0;
641 }
642
643 static void
644 mgag200_pixpll_update_g200eh(struct mgag200_pll *pixpll, const struct mgag200_pll_values *pixpllc)
645 {
646         unsigned int pixpllcm, pixpllcn, pixpllcp, pixpllcs;
647         u8 xpixpllcm, xpixpllcn, xpixpllcp, tmp;
648         int i, j, tmpcount, vcount;
649         struct mga_device *mdev = pixpll->mdev;
650         bool pll_locked = false;
651
652         pixpllcm = pixpllc->m - 1;
653         pixpllcn = pixpllc->n - 1;
654         pixpllcp = pixpllc->p - 1;
655         pixpllcs = pixpllc->s;
656
657         xpixpllcm = ((pixpllcn & BIT(8)) >> 1) | pixpllcm;
658         xpixpllcn = pixpllcn;
659         xpixpllcp = (pixpllcs << 3) | pixpllcp;
660
661         WREG_MISC_MASKED(MGAREG_MISC_CLKSEL_MGA, MGAREG_MISC_CLKSEL_MASK);
662
663         for (i = 0; i <= 32 && pll_locked == false; i++) {
664                 WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL);
665                 tmp = RREG8(DAC_DATA);
666                 tmp |= MGA1064_PIX_CLK_CTL_CLK_DIS;
667                 WREG8(DAC_DATA, tmp);
668
669                 tmp = RREG8(MGAREG_MEM_MISC_READ);
670                 tmp |= 0x3 << 2;
671                 WREG8(MGAREG_MEM_MISC_WRITE, tmp);
672
673                 WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL);
674                 tmp = RREG8(DAC_DATA);
675                 tmp |= MGA1064_PIX_CLK_CTL_CLK_POW_DOWN;
676                 WREG8(DAC_DATA, tmp);
677
678                 udelay(500);
679
680                 WREG_DAC(MGA1064_EH_PIX_PLLC_M, xpixpllcm);
681                 WREG_DAC(MGA1064_EH_PIX_PLLC_N, xpixpllcn);
682                 WREG_DAC(MGA1064_EH_PIX_PLLC_P, xpixpllcp);
683
684                 udelay(500);
685
686                 WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL);
687                 tmp = RREG8(DAC_DATA);
688                 tmp &= ~MGA1064_PIX_CLK_CTL_SEL_MSK;
689                 tmp |= MGA1064_PIX_CLK_CTL_SEL_PLL;
690                 WREG8(DAC_DATA, tmp);
691
692                 WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL);
693                 tmp = RREG8(DAC_DATA);
694                 tmp &= ~MGA1064_PIX_CLK_CTL_CLK_DIS;
695                 tmp &= ~MGA1064_PIX_CLK_CTL_CLK_POW_DOWN;
696                 WREG8(DAC_DATA, tmp);
697
698                 vcount = RREG8(MGAREG_VCOUNT);
699
700                 for (j = 0; j < 30 && pll_locked == false; j++) {
701                         tmpcount = RREG8(MGAREG_VCOUNT);
702                         if (tmpcount < vcount)
703                                 vcount = 0;
704                         if ((tmpcount - vcount) > 2)
705                                 pll_locked = true;
706                         else
707                                 udelay(5);
708                 }
709         }
710 }
711
712 static const struct mgag200_pll_funcs mgag200_pixpll_funcs_g200eh = {
713         .compute = mgag200_pixpll_compute_g200eh,
714         .update = mgag200_pixpll_update_g200eh,
715 };
716
717 /*
718  * G200EH3
719  */
720
721 static int mgag200_pixpll_compute_g200eh3(struct mgag200_pll *pixpll, long clock,
722                                           struct mgag200_pll_values *pixpllc)
723 {
724         static const unsigned int vcomax = 3000000;
725         static const unsigned int vcomin = 1500000;
726         static const unsigned int pllreffreq = 25000;
727
728         unsigned int delta, tmpdelta;
729         unsigned int testp, testm, testn;
730         unsigned int p, m, n, s;
731         unsigned int computed;
732
733         m = n = p = s = 0;
734         delta = 0xffffffff;
735         testp = 0;
736
737         for (testm = 150; testm >= 6; testm--) {
738                 if (clock * testm > vcomax)
739                         continue;
740                 if (clock * testm < vcomin)
741                         continue;
742                 for (testn = 120; testn >= 60; testn--) {
743                         computed = (pllreffreq * testn) / testm;
744                         if (computed > clock)
745                                 tmpdelta = computed - clock;
746                         else
747                                 tmpdelta = clock - computed;
748                         if (tmpdelta < delta) {
749                                 delta = tmpdelta;
750                                 n = testn + 1;
751                                 m = testm + 1;
752                                 p = testp + 1;
753                         }
754                         if (delta == 0)
755                                 break;
756                 }
757                 if (delta == 0)
758                         break;
759         }
760
761         pixpllc->m = m;
762         pixpllc->n = n;
763         pixpllc->p = p;
764         pixpllc->s = s;
765
766         return 0;
767 }
768
769 static const struct mgag200_pll_funcs mgag200_pixpll_funcs_g200eh3 = {
770         .compute = mgag200_pixpll_compute_g200eh3,
771         .update = mgag200_pixpll_update_g200eh, // same as G200EH
772 };
773
774 /*
775  * G200ER
776  */
777
778 static int mgag200_pixpll_compute_g200er(struct mgag200_pll *pixpll, long clock,
779                                          struct mgag200_pll_values *pixpllc)
780 {
781         static const unsigned int vcomax = 1488000;
782         static const unsigned int vcomin = 1056000;
783         static const unsigned int pllreffreq = 48000;
784         static const unsigned int m_div_val[] = { 1, 2, 4, 8 };
785
786         unsigned int delta, tmpdelta;
787         int testr, testn, testm, testo;
788         unsigned int p, m, n, s;
789         unsigned int computed, vco;
790
791         m = n = p = s = 0;
792         delta = 0xffffffff;
793
794         for (testr = 0; testr < 4; testr++) {
795                 if (delta == 0)
796                         break;
797                 for (testn = 5; testn < 129; testn++) {
798                         if (delta == 0)
799                                 break;
800                         for (testm = 3; testm >= 0; testm--) {
801                                 if (delta == 0)
802                                         break;
803                                 for (testo = 5; testo < 33; testo++) {
804                                         vco = pllreffreq * (testn + 1) /
805                                                 (testr + 1);
806                                         if (vco < vcomin)
807                                                 continue;
808                                         if (vco > vcomax)
809                                                 continue;
810                                         computed = vco / (m_div_val[testm] * (testo + 1));
811                                         if (computed > clock)
812                                                 tmpdelta = computed - clock;
813                                         else
814                                                 tmpdelta = clock - computed;
815                                         if (tmpdelta < delta) {
816                                                 delta = tmpdelta;
817                                                 m = (testm | (testo << 3)) + 1;
818                                                 n = testn + 1;
819                                                 p = testr + 1;
820                                                 s = testr;
821                                         }
822                                 }
823                         }
824                 }
825         }
826
827         pixpllc->m = m;
828         pixpllc->n = n;
829         pixpllc->p = p;
830         pixpllc->s = s;
831
832         return 0;
833 }
834
835 static void
836 mgag200_pixpll_update_g200er(struct mgag200_pll *pixpll, const struct mgag200_pll_values *pixpllc)
837 {
838         unsigned int pixpllcm, pixpllcn, pixpllcp, pixpllcs;
839         u8 xpixpllcm, xpixpllcn, xpixpllcp, tmp;
840         struct mga_device *mdev = pixpll->mdev;
841
842         pixpllcm = pixpllc->m - 1;
843         pixpllcn = pixpllc->n - 1;
844         pixpllcp = pixpllc->p - 1;
845         pixpllcs = pixpllc->s;
846
847         xpixpllcm = pixpllcm;
848         xpixpllcn = pixpllcn;
849         xpixpllcp = (pixpllcs << 3) | pixpllcp;
850
851         WREG_MISC_MASKED(MGAREG_MISC_CLKSEL_MGA, MGAREG_MISC_CLKSEL_MASK);
852
853         WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL);
854         tmp = RREG8(DAC_DATA);
855         tmp |= MGA1064_PIX_CLK_CTL_CLK_DIS;
856         WREG8(DAC_DATA, tmp);
857
858         WREG8(DAC_INDEX, MGA1064_REMHEADCTL);
859         tmp = RREG8(DAC_DATA);
860         tmp |= MGA1064_REMHEADCTL_CLKDIS;
861         WREG8(DAC_DATA, tmp);
862
863         tmp = RREG8(MGAREG_MEM_MISC_READ);
864         tmp |= (0x3<<2) | 0xc0;
865         WREG8(MGAREG_MEM_MISC_WRITE, tmp);
866
867         WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL);
868         tmp = RREG8(DAC_DATA);
869         tmp &= ~MGA1064_PIX_CLK_CTL_CLK_DIS;
870         tmp |= MGA1064_PIX_CLK_CTL_CLK_POW_DOWN;
871         WREG8(DAC_DATA, tmp);
872
873         udelay(500);
874
875         WREG_DAC(MGA1064_ER_PIX_PLLC_N, xpixpllcn);
876         WREG_DAC(MGA1064_ER_PIX_PLLC_M, xpixpllcm);
877         WREG_DAC(MGA1064_ER_PIX_PLLC_P, xpixpllcp);
878
879         udelay(50);
880 }
881
882 static const struct mgag200_pll_funcs mgag200_pixpll_funcs_g200er = {
883         .compute = mgag200_pixpll_compute_g200er,
884         .update = mgag200_pixpll_update_g200er,
885 };
886
887 /*
888  * G200EW3
889  */
890
891 static int mgag200_pixpll_compute_g200ew3(struct mgag200_pll *pixpll, long clock,
892                                           struct mgag200_pll_values *pixpllc)
893 {
894         static const unsigned int vcomax = 800000;
895         static const unsigned int vcomin = 400000;
896         static const unsigned int pllreffreq = 25000;
897
898         unsigned int delta, tmpdelta;
899         unsigned int testp, testm, testn, testp2;
900         unsigned int p, m, n, s;
901         unsigned int computed;
902
903         m = n = p = s = 0;
904         delta = 0xffffffff;
905
906         for (testp = 1; testp < 8; testp++) {
907                 for (testp2 = 1; testp2 < 8; testp2++) {
908                         if (testp < testp2)
909                                 continue;
910                         if ((clock * testp * testp2) > vcomax)
911                                 continue;
912                         if ((clock * testp * testp2) < vcomin)
913                                 continue;
914                         for (testm = 1; testm < 26; testm++) {
915                                 for (testn = 32; testn < 2048 ; testn++) {
916                                         computed = (pllreffreq * testn) / (testm * testp * testp2);
917                                         if (computed > clock)
918                                                 tmpdelta = computed - clock;
919                                         else
920                                                 tmpdelta = clock - computed;
921                                         if (tmpdelta < delta) {
922                                                 delta = tmpdelta;
923                                                 m = testm + 1;
924                                                 n = testn + 1;
925                                                 p = testp + 1;
926                                                 s = testp2;
927                                         }
928                                 }
929                         }
930                 }
931         }
932
933         pixpllc->m = m;
934         pixpllc->n = n;
935         pixpllc->p = p;
936         pixpllc->s = s;
937
938         return 0;
939 }
940
941 static const struct mgag200_pll_funcs mgag200_pixpll_funcs_g200ew3 = {
942         .compute = mgag200_pixpll_compute_g200ew3,
943         .update = mgag200_pixpll_update_g200wb, // same as G200WB
944 };
945
946 /*
947  * PLL initialization
948  */
949
950 int mgag200_pixpll_init(struct mgag200_pll *pixpll, struct mga_device *mdev)
951 {
952         struct drm_device *dev = &mdev->base;
953
954         pixpll->mdev = mdev;
955
956         switch (mdev->type) {
957         case G200_PCI:
958         case G200_AGP:
959                 pixpll->funcs = &mgag200_pixpll_funcs_g200;
960                 break;
961         case G200_SE_A:
962         case G200_SE_B:
963                 if (mdev->model.g200se.unique_rev_id >= 0x04)
964                         pixpll->funcs = &mgag200_pixpll_funcs_g200se_04;
965                 else
966                         pixpll->funcs = &mgag200_pixpll_funcs_g200se_00;
967                 break;
968         case G200_WB:
969                 pixpll->funcs = &mgag200_pixpll_funcs_g200wb;
970                 break;
971         case G200_EV:
972                 pixpll->funcs = &mgag200_pixpll_funcs_g200ev;
973                 break;
974         case G200_EH:
975                 pixpll->funcs = &mgag200_pixpll_funcs_g200eh;
976                 break;
977         case G200_EH3:
978                 pixpll->funcs = &mgag200_pixpll_funcs_g200eh3;
979                 break;
980         case G200_ER:
981                 pixpll->funcs = &mgag200_pixpll_funcs_g200er;
982                 break;
983         case G200_EW3:
984                 pixpll->funcs = &mgag200_pixpll_funcs_g200ew3;
985                 break;
986         default:
987                 drm_err(dev, "unknown device type %d\n", mdev->type);
988                 return -ENODEV;
989         }
990
991         return 0;
992 }