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