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 
mgag200_pixpll_compute_g200(struct mgag200_pll * pixpll,long clock,struct mgag200_pll_values * pixpllc)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
mgag200_pixpll_update_g200(struct mgag200_pll * pixpll,const struct mgag200_pll_values * pixpllc)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 
mgag200_pixpll_compute_g200se_00(struct mgag200_pll * pixpll,long clock,struct mgag200_pll_values * pixpllc)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 
mgag200_pixpll_update_g200se_00(struct mgag200_pll * pixpll,const struct mgag200_pll_values * pixpllc)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 
mgag200_pixpll_compute_g200se_04(struct mgag200_pll * pixpll,long clock,struct mgag200_pll_values * pixpllc)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 
mgag200_pixpll_update_g200se_04(struct mgag200_pll * pixpll,const struct mgag200_pll_values * pixpllc)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 
mgag200_pixpll_compute_g200wb(struct mgag200_pll * pixpll,long clock,struct mgag200_pll_values * pixpllc)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
mgag200_pixpll_update_g200wb(struct mgag200_pll * pixpll,const struct mgag200_pll_values * pixpllc)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 
mgag200_pixpll_compute_g200ev(struct mgag200_pll * pixpll,long clock,struct mgag200_pll_values * pixpllc)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
mgag200_pixpll_update_g200ev(struct mgag200_pll * pixpll,const struct mgag200_pll_values * pixpllc)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 
mgag200_pixpll_compute_g200eh(struct mgag200_pll * pixpll,long clock,struct mgag200_pll_values * pixpllc)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
mgag200_pixpll_update_g200eh(struct mgag200_pll * pixpll,const struct mgag200_pll_values * pixpllc)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 
mgag200_pixpll_compute_g200eh3(struct mgag200_pll * pixpll,long clock,struct mgag200_pll_values * pixpllc)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 
mgag200_pixpll_compute_g200er(struct mgag200_pll * pixpll,long clock,struct mgag200_pll_values * pixpllc)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
mgag200_pixpll_update_g200er(struct mgag200_pll * pixpll,const struct mgag200_pll_values * pixpllc)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 
mgag200_pixpll_compute_g200ew3(struct mgag200_pll * pixpll,long clock,struct mgag200_pll_values * pixpllc)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 
mgag200_pixpll_init(struct mgag200_pll * pixpll,struct mga_device * mdev)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 }
994