1// SPDX-License-Identifier: GPL-2.0
2
3/*
4 *  ATI Mach64 GX Support
5 */
6
7#include <linux/delay.h>
8#include <linux/fb.h>
9
10#include <asm/io.h>
11
12#include <video/mach64.h>
13#include "atyfb.h"
14
15/* Definitions for the ICS 2595 == ATI 18818_1 Clockchip */
16
17#define REF_FREQ_2595       1432	/*  14.33 MHz  (exact   14.31818) */
18#define REF_DIV_2595          46	/* really 43 on ICS 2595 !!!  */
19				  /* ohne Prescaler */
20#define MAX_FREQ_2595      15938	/* 159.38 MHz  (really 170.486) */
21#define MIN_FREQ_2595       8000	/*  80.00 MHz  (        85.565) */
22				  /* mit Prescaler 2, 4, 8 */
23#define ABS_MIN_FREQ_2595   1000	/*  10.00 MHz  (really  10.697) */
24#define N_ADJ_2595           257
25
26#define STOP_BITS_2595     0x1800
27
28
29#define MIN_N_408		2
30
31#define MIN_N_1703		6
32
33#define MIN_M		2
34#define MAX_M		30
35#define MIN_N		35
36#define MAX_N		255-8
37
38
39    /*
40     *  Support Functions
41     */
42
43static void aty_dac_waste4(const struct atyfb_par *par)
44{
45	(void) aty_ld_8(DAC_REGS, par);
46
47	(void) aty_ld_8(DAC_REGS + 2, par);
48	(void) aty_ld_8(DAC_REGS + 2, par);
49	(void) aty_ld_8(DAC_REGS + 2, par);
50	(void) aty_ld_8(DAC_REGS + 2, par);
51}
52
53static void aty_StrobeClock(const struct atyfb_par *par)
54{
55	u8 tmp;
56
57	udelay(26);
58
59	tmp = aty_ld_8(CLOCK_CNTL, par);
60	aty_st_8(CLOCK_CNTL + par->clk_wr_offset, tmp | CLOCK_STROBE, par);
61	return;
62}
63
64
65    /*
66     *  IBM RGB514 DAC and Clock Chip
67     */
68
69static void aty_st_514(int offset, u8 val, const struct atyfb_par *par)
70{
71	aty_st_8(DAC_CNTL, 1, par);
72	/* right addr byte */
73	aty_st_8(DAC_W_INDEX, offset & 0xff, par);
74	/* left addr byte */
75	aty_st_8(DAC_DATA, (offset >> 8) & 0xff, par);
76	aty_st_8(DAC_MASK, val, par);
77	aty_st_8(DAC_CNTL, 0, par);
78}
79
80static int aty_set_dac_514(const struct fb_info *info,
81			   const union aty_pll *pll, u32 bpp, u32 accel)
82{
83	struct atyfb_par *par = (struct atyfb_par *) info->par;
84	static struct {
85		u8 pixel_dly;
86		u8 misc2_cntl;
87		u8 pixel_rep;
88		u8 pixel_cntl_index;
89		u8 pixel_cntl_v1;
90	} tab[3] = {
91		{
92		0, 0x41, 0x03, 0x71, 0x45},	/* 8 bpp */
93		{
94		0, 0x45, 0x04, 0x0c, 0x01},	/* 555 */
95		{
96		0, 0x45, 0x06, 0x0e, 0x00},	/* XRGB */
97	};
98	int i;
99
100	switch (bpp) {
101	case 8:
102	default:
103		i = 0;
104		break;
105	case 16:
106		i = 1;
107		break;
108	case 32:
109		i = 2;
110		break;
111	}
112	aty_st_514(0x90, 0x00, par);	/* VRAM Mask Low */
113	aty_st_514(0x04, tab[i].pixel_dly, par);	/* Horizontal Sync Control */
114	aty_st_514(0x05, 0x00, par);	/* Power Management */
115	aty_st_514(0x02, 0x01, par);	/* Misc Clock Control */
116	aty_st_514(0x71, tab[i].misc2_cntl, par);	/* Misc Control 2 */
117	aty_st_514(0x0a, tab[i].pixel_rep, par);	/* Pixel Format */
118	aty_st_514(tab[i].pixel_cntl_index, tab[i].pixel_cntl_v1, par);
119	/* Misc Control 2 / 16 BPP Control / 32 BPP Control */
120	return 0;
121}
122
123static int aty_var_to_pll_514(const struct fb_info *info, u32 vclk_per,
124			      u32 bpp, union aty_pll *pll)
125{
126	/*
127	 *  FIXME: use real calculations instead of using fixed values from the old
128	 *         driver
129	 */
130	static struct {
131		u32 limit;	/* pixlock rounding limit (arbitrary) */
132		u8 m;		/* (df<<6) | vco_div_count */
133		u8 n;		/* ref_div_count */
134	} RGB514_clocks[7] = {
135		{
136		8000, (3 << 6) | 20, 9},	/*  7395 ps / 135.2273 MHz */
137		{
138		10000, (1 << 6) | 19, 3},	/*  9977 ps / 100.2273 MHz */
139		{
140		13000, (1 << 6) | 2, 3},	/* 12509 ps /  79.9432 MHz */
141		{
142		14000, (2 << 6) | 8, 7},	/* 13394 ps /  74.6591 MHz */
143		{
144		16000, (1 << 6) | 44, 6},	/* 15378 ps /  65.0284 MHz */
145		{
146		25000, (1 << 6) | 15, 5},	/* 17460 ps /  57.2727 MHz */
147		{
148		50000, (0 << 6) | 53, 7},	/* 33145 ps /  30.1705 MHz */
149	};
150	int i;
151
152	for (i = 0; i < ARRAY_SIZE(RGB514_clocks); i++)
153		if (vclk_per <= RGB514_clocks[i].limit) {
154			pll->ibm514.m = RGB514_clocks[i].m;
155			pll->ibm514.n = RGB514_clocks[i].n;
156			return 0;
157		}
158	return -EINVAL;
159}
160
161static u32 aty_pll_514_to_var(const struct fb_info *info,
162			      const union aty_pll *pll)
163{
164	struct atyfb_par *par = (struct atyfb_par *) info->par;
165	u8 df, vco_div_count, ref_div_count;
166
167	df = pll->ibm514.m >> 6;
168	vco_div_count = pll->ibm514.m & 0x3f;
169	ref_div_count = pll->ibm514.n;
170
171	return ((par->ref_clk_per * ref_div_count) << (3 - df))/
172	    		(vco_div_count + 65);
173}
174
175static void aty_set_pll_514(const struct fb_info *info,
176			    const union aty_pll *pll)
177{
178	struct atyfb_par *par = (struct atyfb_par *) info->par;
179
180	aty_st_514(0x06, 0x02, par);	/* DAC Operation */
181	aty_st_514(0x10, 0x01, par);	/* PLL Control 1 */
182	aty_st_514(0x70, 0x01, par);	/* Misc Control 1 */
183	aty_st_514(0x8f, 0x1f, par);	/* PLL Ref. Divider Input */
184	aty_st_514(0x03, 0x00, par);	/* Sync Control */
185	aty_st_514(0x05, 0x00, par);	/* Power Management */
186	aty_st_514(0x20, pll->ibm514.m, par);	/* F0 / M0 */
187	aty_st_514(0x21, pll->ibm514.n, par);	/* F1 / N0 */
188}
189
190const struct aty_dac_ops aty_dac_ibm514 = {
191	.set_dac	= aty_set_dac_514,
192};
193
194const struct aty_pll_ops aty_pll_ibm514 = {
195	.var_to_pll	= aty_var_to_pll_514,
196	.pll_to_var	= aty_pll_514_to_var,
197	.set_pll	= aty_set_pll_514,
198};
199
200
201    /*
202     *  ATI 68860-B DAC
203     */
204
205static int aty_set_dac_ATI68860_B(const struct fb_info *info,
206				  const union aty_pll *pll, u32 bpp,
207				  u32 accel)
208{
209	struct atyfb_par *par = (struct atyfb_par *) info->par;
210	u32 gModeReg, devSetupRegA, temp, mask;
211
212	gModeReg = 0;
213	devSetupRegA = 0;
214
215	switch (bpp) {
216	case 8:
217		gModeReg = 0x83;
218		devSetupRegA =
219		    0x60 | 0x00 /*(info->mach64DAC8Bit ? 0x00 : 0x01) */ ;
220		break;
221	case 15:
222		gModeReg = 0xA0;
223		devSetupRegA = 0x60;
224		break;
225	case 16:
226		gModeReg = 0xA1;
227		devSetupRegA = 0x60;
228		break;
229	case 24:
230		gModeReg = 0xC0;
231		devSetupRegA = 0x60;
232		break;
233	case 32:
234		gModeReg = 0xE3;
235		devSetupRegA = 0x60;
236		break;
237	}
238
239	if (!accel) {
240		gModeReg = 0x80;
241		devSetupRegA = 0x61;
242	}
243
244	temp = aty_ld_8(DAC_CNTL, par);
245	aty_st_8(DAC_CNTL, (temp & ~DAC_EXT_SEL_RS2) | DAC_EXT_SEL_RS3,
246		 par);
247
248	aty_st_8(DAC_REGS + 2, 0x1D, par);
249	aty_st_8(DAC_REGS + 3, gModeReg, par);
250	aty_st_8(DAC_REGS, 0x02, par);
251
252	temp = aty_ld_8(DAC_CNTL, par);
253	aty_st_8(DAC_CNTL, temp | DAC_EXT_SEL_RS2 | DAC_EXT_SEL_RS3, par);
254
255	if (info->fix.smem_len < ONE_MB)
256		mask = 0x04;
257	else if (info->fix.smem_len == ONE_MB)
258		mask = 0x08;
259	else
260		mask = 0x0C;
261
262	/* The following assumes that the BIOS has correctly set R7 of the
263	 * Device Setup Register A at boot time.
264	 */
265#define A860_DELAY_L	0x80
266
267	temp = aty_ld_8(DAC_REGS, par);
268	aty_st_8(DAC_REGS, (devSetupRegA | mask) | (temp & A860_DELAY_L),
269		 par);
270	temp = aty_ld_8(DAC_CNTL, par);
271	aty_st_8(DAC_CNTL, (temp & ~(DAC_EXT_SEL_RS2 | DAC_EXT_SEL_RS3)),
272		 par);
273
274	aty_st_le32(BUS_CNTL, 0x890e20f1, par);
275	aty_st_le32(DAC_CNTL, 0x47052100, par);
276	return 0;
277}
278
279const struct aty_dac_ops aty_dac_ati68860b = {
280	.set_dac	= aty_set_dac_ATI68860_B,
281};
282
283
284    /*
285     *  AT&T 21C498 DAC
286     */
287
288static int aty_set_dac_ATT21C498(const struct fb_info *info,
289				 const union aty_pll *pll, u32 bpp,
290				 u32 accel)
291{
292	struct atyfb_par *par = (struct atyfb_par *) info->par;
293	u32 dotClock;
294	int muxmode = 0;
295	int DACMask = 0;
296
297	dotClock = 100000000 / pll->ics2595.period_in_ps;
298
299	switch (bpp) {
300	case 8:
301		if (dotClock > 8000) {
302			DACMask = 0x24;
303			muxmode = 1;
304		} else
305			DACMask = 0x04;
306		break;
307	case 15:
308		DACMask = 0x16;
309		break;
310	case 16:
311		DACMask = 0x36;
312		break;
313	case 24:
314		DACMask = 0xE6;
315		break;
316	case 32:
317		DACMask = 0xE6;
318		break;
319	}
320
321	if (1 /* info->mach64DAC8Bit */ )
322		DACMask |= 0x02;
323
324	aty_dac_waste4(par);
325	aty_st_8(DAC_REGS + 2, DACMask, par);
326
327	aty_st_le32(BUS_CNTL, 0x890e20f1, par);
328	aty_st_le32(DAC_CNTL, 0x00072000, par);
329	return muxmode;
330}
331
332const struct aty_dac_ops aty_dac_att21c498 = {
333	.set_dac	= aty_set_dac_ATT21C498,
334};
335
336
337    /*
338     *  ATI 18818 / ICS 2595 Clock Chip
339     */
340
341static int aty_var_to_pll_18818(const struct fb_info *info, u32 vclk_per,
342				u32 bpp, union aty_pll *pll)
343{
344	u32 MHz100;		/* in 0.01 MHz */
345	u32 program_bits;
346	u32 post_divider;
347
348	/* Calculate the programming word */
349	MHz100 = 100000000 / vclk_per;
350
351	program_bits = -1;
352	post_divider = 1;
353
354	if (MHz100 > MAX_FREQ_2595) {
355		return -EINVAL;
356	} else if (MHz100 < ABS_MIN_FREQ_2595) {
357		return -EINVAL;
358	} else {
359		while (MHz100 < MIN_FREQ_2595) {
360			MHz100 *= 2;
361			post_divider *= 2;
362		}
363	}
364	MHz100 *= 1000;
365	MHz100 = (REF_DIV_2595 * MHz100) / REF_FREQ_2595;
366
367	MHz100 += 500;		/* + 0.5 round */
368	MHz100 /= 1000;
369
370	if (program_bits == -1) {
371		program_bits = MHz100 - N_ADJ_2595;
372		switch (post_divider) {
373		case 1:
374			program_bits |= 0x0600;
375			break;
376		case 2:
377			program_bits |= 0x0400;
378			break;
379		case 4:
380			program_bits |= 0x0200;
381			break;
382		case 8:
383		default:
384			break;
385		}
386	}
387
388	program_bits |= STOP_BITS_2595;
389
390	pll->ics2595.program_bits = program_bits;
391	pll->ics2595.locationAddr = 0;
392	pll->ics2595.post_divider = post_divider;
393	pll->ics2595.period_in_ps = vclk_per;
394
395	return 0;
396}
397
398static u32 aty_pll_18818_to_var(const struct fb_info *info,
399				const union aty_pll *pll)
400{
401	return (pll->ics2595.period_in_ps);	/* default for now */
402}
403
404static void aty_ICS2595_put1bit(u8 data, const struct atyfb_par *par)
405{
406	u8 tmp;
407
408	data &= 0x01;
409	tmp = aty_ld_8(CLOCK_CNTL, par);
410	aty_st_8(CLOCK_CNTL + par->clk_wr_offset,
411		 (tmp & ~0x04) | (data << 2), par);
412
413	tmp = aty_ld_8(CLOCK_CNTL, par);
414	aty_st_8(CLOCK_CNTL + par->clk_wr_offset, (tmp & ~0x08) | (0 << 3),
415		 par);
416
417	aty_StrobeClock(par);
418
419	tmp = aty_ld_8(CLOCK_CNTL, par);
420	aty_st_8(CLOCK_CNTL + par->clk_wr_offset, (tmp & ~0x08) | (1 << 3),
421		 par);
422
423	aty_StrobeClock(par);
424	return;
425}
426
427static void aty_set_pll18818(const struct fb_info *info,
428			     const union aty_pll *pll)
429{
430	struct atyfb_par *par = (struct atyfb_par *) info->par;
431	u32 program_bits;
432	u32 locationAddr;
433
434	u32 i;
435
436	u8 old_clock_cntl;
437	u8 old_crtc_ext_disp;
438
439	old_clock_cntl = aty_ld_8(CLOCK_CNTL, par);
440	aty_st_8(CLOCK_CNTL + par->clk_wr_offset, 0, par);
441
442	old_crtc_ext_disp = aty_ld_8(CRTC_GEN_CNTL + 3, par);
443	aty_st_8(CRTC_GEN_CNTL + 3,
444		 old_crtc_ext_disp | (CRTC_EXT_DISP_EN >> 24), par);
445
446	mdelay(15);		/* delay for 50 (15) ms */
447
448	program_bits = pll->ics2595.program_bits;
449	locationAddr = pll->ics2595.locationAddr;
450
451	/* Program the clock chip */
452	aty_st_8(CLOCK_CNTL + par->clk_wr_offset, 0, par);	/* Strobe = 0 */
453	aty_StrobeClock(par);
454	aty_st_8(CLOCK_CNTL + par->clk_wr_offset, 1, par);	/* Strobe = 0 */
455	aty_StrobeClock(par);
456
457	aty_ICS2595_put1bit(1, par);	/* Send start bits */
458	aty_ICS2595_put1bit(0, par);	/* Start bit */
459	aty_ICS2595_put1bit(0, par);	/* Read / ~Write */
460
461	for (i = 0; i < 5; i++) {	/* Location 0..4 */
462		aty_ICS2595_put1bit(locationAddr & 1, par);
463		locationAddr >>= 1;
464	}
465
466	for (i = 0; i < 8 + 1 + 2 + 2; i++) {
467		aty_ICS2595_put1bit(program_bits & 1, par);
468		program_bits >>= 1;
469	}
470
471	mdelay(1);		/* delay for 1 ms */
472
473	(void) aty_ld_8(DAC_REGS, par);	/* Clear DAC Counter */
474	aty_st_8(CRTC_GEN_CNTL + 3, old_crtc_ext_disp, par);
475	aty_st_8(CLOCK_CNTL + par->clk_wr_offset,
476		 old_clock_cntl | CLOCK_STROBE, par);
477
478	mdelay(50);		/* delay for 50 (15) ms */
479	aty_st_8(CLOCK_CNTL + par->clk_wr_offset,
480		 ((pll->ics2595.locationAddr & 0x0F) | CLOCK_STROBE), par);
481	return;
482}
483
484const struct aty_pll_ops aty_pll_ati18818_1 = {
485	.var_to_pll	= aty_var_to_pll_18818,
486	.pll_to_var	= aty_pll_18818_to_var,
487	.set_pll	= aty_set_pll18818,
488};
489
490
491    /*
492     *  STG 1703 Clock Chip
493     */
494
495static int aty_var_to_pll_1703(const struct fb_info *info, u32 vclk_per,
496			       u32 bpp, union aty_pll *pll)
497{
498	u32 mhz100;		/* in 0.01 MHz */
499	u32 program_bits;
500	/* u32 post_divider; */
501	u32 mach64MinFreq, mach64MaxFreq, mach64RefFreq;
502	u32 temp, tempB;
503	u16 remainder, preRemainder;
504	short divider = 0, tempA;
505
506	/* Calculate the programming word */
507	mhz100 = 100000000 / vclk_per;
508	mach64MinFreq = MIN_FREQ_2595;
509	mach64MaxFreq = MAX_FREQ_2595;
510	mach64RefFreq = REF_FREQ_2595;	/* 14.32 MHz */
511
512	/* Calculate program word */
513	if (mhz100 == 0)
514		program_bits = 0xE0;
515	else {
516		if (mhz100 < mach64MinFreq)
517			mhz100 = mach64MinFreq;
518		if (mhz100 > mach64MaxFreq)
519			mhz100 = mach64MaxFreq;
520
521		divider = 0;
522		while (mhz100 < (mach64MinFreq << 3)) {
523			mhz100 <<= 1;
524			divider += 0x20;
525		}
526
527		temp = (unsigned int) (mhz100);
528		temp = (unsigned int) (temp * (MIN_N_1703 + 2));
529		temp -= (short) (mach64RefFreq << 1);
530
531		tempA = MIN_N_1703;
532		preRemainder = 0xffff;
533
534		do {
535			tempB = temp;
536			remainder = tempB % mach64RefFreq;
537			tempB = tempB / mach64RefFreq;
538
539			if ((tempB & 0xffff) <= 127
540			    && (remainder <= preRemainder)) {
541				preRemainder = remainder;
542				divider &= ~0x1f;
543				divider |= tempA;
544				divider =
545				    (divider & 0x00ff) +
546				    ((tempB & 0xff) << 8);
547			}
548
549			temp += mhz100;
550			tempA++;
551		} while (tempA <= (MIN_N_1703 << 1));
552
553		program_bits = divider;
554	}
555
556	pll->ics2595.program_bits = program_bits;
557	pll->ics2595.locationAddr = 0;
558	pll->ics2595.post_divider = divider;	/* fuer nix */
559	pll->ics2595.period_in_ps = vclk_per;
560
561	return 0;
562}
563
564static u32 aty_pll_1703_to_var(const struct fb_info *info,
565			       const union aty_pll *pll)
566{
567	return (pll->ics2595.period_in_ps);	/* default for now */
568}
569
570static void aty_set_pll_1703(const struct fb_info *info,
571			     const union aty_pll *pll)
572{
573	struct atyfb_par *par = (struct atyfb_par *) info->par;
574	u32 program_bits;
575	u32 locationAddr;
576
577	char old_crtc_ext_disp;
578
579	old_crtc_ext_disp = aty_ld_8(CRTC_GEN_CNTL + 3, par);
580	aty_st_8(CRTC_GEN_CNTL + 3,
581		 old_crtc_ext_disp | (CRTC_EXT_DISP_EN >> 24), par);
582
583	program_bits = pll->ics2595.program_bits;
584	locationAddr = pll->ics2595.locationAddr;
585
586	/* Program clock */
587	aty_dac_waste4(par);
588
589	(void) aty_ld_8(DAC_REGS + 2, par);
590	aty_st_8(DAC_REGS + 2, (locationAddr << 1) + 0x20, par);
591	aty_st_8(DAC_REGS + 2, 0, par);
592	aty_st_8(DAC_REGS + 2, (program_bits & 0xFF00) >> 8, par);
593	aty_st_8(DAC_REGS + 2, (program_bits & 0xFF), par);
594
595	(void) aty_ld_8(DAC_REGS, par);	/* Clear DAC Counter */
596	aty_st_8(CRTC_GEN_CNTL + 3, old_crtc_ext_disp, par);
597	return;
598}
599
600const struct aty_pll_ops aty_pll_stg1703 = {
601	.var_to_pll	= aty_var_to_pll_1703,
602	.pll_to_var	= aty_pll_1703_to_var,
603	.set_pll	= aty_set_pll_1703,
604};
605
606
607    /*
608     *  Chrontel 8398 Clock Chip
609     */
610
611static int aty_var_to_pll_8398(const struct fb_info *info, u32 vclk_per,
612			       u32 bpp, union aty_pll *pll)
613{
614	u32 tempA, tempB, fOut, longMHz100, diff, preDiff;
615
616	u32 mhz100;		/* in 0.01 MHz */
617	u32 program_bits;
618	/* u32 post_divider; */
619	u32 mach64MinFreq, mach64MaxFreq;
620	u16 m, n, k = 0, save_m, save_n, twoToKth;
621
622	/* Calculate the programming word */
623	mhz100 = 100000000 / vclk_per;
624	mach64MinFreq = MIN_FREQ_2595;
625	mach64MaxFreq = MAX_FREQ_2595;
626
627	save_m = 0;
628	save_n = 0;
629
630	/* Calculate program word */
631	if (mhz100 == 0)
632		program_bits = 0xE0;
633	else {
634		if (mhz100 < mach64MinFreq)
635			mhz100 = mach64MinFreq;
636		if (mhz100 > mach64MaxFreq)
637			mhz100 = mach64MaxFreq;
638
639		longMHz100 = mhz100 * 256 / 100;	/* 8 bit scale this */
640
641		while (mhz100 < (mach64MinFreq << 3)) {
642			mhz100 <<= 1;
643			k++;
644		}
645
646		twoToKth = 1 << k;
647		diff = 0;
648		preDiff = 0xFFFFFFFF;
649
650		for (m = MIN_M; m <= MAX_M; m++) {
651			for (n = MIN_N; n <= MAX_N; n++) {
652				tempA = 938356;		/* 14.31818 * 65536 */
653				tempA *= (n + 8);	/* 43..256 */
654				tempB = twoToKth * 256;
655				tempB *= (m + 2);	/* 4..32 */
656				fOut = tempA / tempB;	/* 8 bit scale */
657
658				if (longMHz100 > fOut)
659					diff = longMHz100 - fOut;
660				else
661					diff = fOut - longMHz100;
662
663				if (diff < preDiff) {
664					save_m = m;
665					save_n = n;
666					preDiff = diff;
667				}
668			}
669		}
670
671		program_bits = (k << 6) + (save_m) + (save_n << 8);
672	}
673
674	pll->ics2595.program_bits = program_bits;
675	pll->ics2595.locationAddr = 0;
676	pll->ics2595.post_divider = 0;
677	pll->ics2595.period_in_ps = vclk_per;
678
679	return 0;
680}
681
682static u32 aty_pll_8398_to_var(const struct fb_info *info,
683			       const union aty_pll *pll)
684{
685	return (pll->ics2595.period_in_ps);	/* default for now */
686}
687
688static void aty_set_pll_8398(const struct fb_info *info,
689			     const union aty_pll *pll)
690{
691	struct atyfb_par *par = (struct atyfb_par *) info->par;
692	u32 program_bits;
693	u32 locationAddr;
694
695	char old_crtc_ext_disp;
696	char tmp;
697
698	old_crtc_ext_disp = aty_ld_8(CRTC_GEN_CNTL + 3, par);
699	aty_st_8(CRTC_GEN_CNTL + 3,
700		 old_crtc_ext_disp | (CRTC_EXT_DISP_EN >> 24), par);
701
702	program_bits = pll->ics2595.program_bits;
703	locationAddr = pll->ics2595.locationAddr;
704
705	/* Program clock */
706	tmp = aty_ld_8(DAC_CNTL, par);
707	aty_st_8(DAC_CNTL, tmp | DAC_EXT_SEL_RS2 | DAC_EXT_SEL_RS3, par);
708
709	aty_st_8(DAC_REGS, locationAddr, par);
710	aty_st_8(DAC_REGS + 1, (program_bits & 0xff00) >> 8, par);
711	aty_st_8(DAC_REGS + 1, (program_bits & 0xff), par);
712
713	tmp = aty_ld_8(DAC_CNTL, par);
714	aty_st_8(DAC_CNTL, (tmp & ~DAC_EXT_SEL_RS2) | DAC_EXT_SEL_RS3,
715		 par);
716
717	(void) aty_ld_8(DAC_REGS, par);	/* Clear DAC Counter */
718	aty_st_8(CRTC_GEN_CNTL + 3, old_crtc_ext_disp, par);
719
720	return;
721}
722
723const struct aty_pll_ops aty_pll_ch8398 = {
724	.var_to_pll	= aty_var_to_pll_8398,
725	.pll_to_var	= aty_pll_8398_to_var,
726	.set_pll	= aty_set_pll_8398,
727};
728
729
730    /*
731     *  AT&T 20C408 Clock Chip
732     */
733
734static int aty_var_to_pll_408(const struct fb_info *info, u32 vclk_per,
735			      u32 bpp, union aty_pll *pll)
736{
737	u32 mhz100;		/* in 0.01 MHz */
738	u32 program_bits;
739	/* u32 post_divider; */
740	u32 mach64MinFreq, mach64MaxFreq, mach64RefFreq;
741	u32 temp, tempB;
742	u16 remainder, preRemainder;
743	short divider = 0, tempA;
744
745	/* Calculate the programming word */
746	mhz100 = 100000000 / vclk_per;
747	mach64MinFreq = MIN_FREQ_2595;
748	mach64MaxFreq = MAX_FREQ_2595;
749	mach64RefFreq = REF_FREQ_2595;	/* 14.32 MHz */
750
751	/* Calculate program word */
752	if (mhz100 == 0)
753		program_bits = 0xFF;
754	else {
755		if (mhz100 < mach64MinFreq)
756			mhz100 = mach64MinFreq;
757		if (mhz100 > mach64MaxFreq)
758			mhz100 = mach64MaxFreq;
759
760		while (mhz100 < (mach64MinFreq << 3)) {
761			mhz100 <<= 1;
762			divider += 0x40;
763		}
764
765		temp = (unsigned int) mhz100;
766		temp = (unsigned int) (temp * (MIN_N_408 + 2));
767		temp -= ((short) (mach64RefFreq << 1));
768
769		tempA = MIN_N_408;
770		preRemainder = 0xFFFF;
771
772		do {
773			tempB = temp;
774			remainder = tempB % mach64RefFreq;
775			tempB = tempB / mach64RefFreq;
776			if (((tempB & 0xFFFF) <= 255)
777			    && (remainder <= preRemainder)) {
778				preRemainder = remainder;
779				divider &= ~0x3f;
780				divider |= tempA;
781				divider =
782				    (divider & 0x00FF) +
783				    ((tempB & 0xFF) << 8);
784			}
785			temp += mhz100;
786			tempA++;
787		} while (tempA <= 32);
788
789		program_bits = divider;
790	}
791
792	pll->ics2595.program_bits = program_bits;
793	pll->ics2595.locationAddr = 0;
794	pll->ics2595.post_divider = divider;	/* fuer nix */
795	pll->ics2595.period_in_ps = vclk_per;
796
797	return 0;
798}
799
800static u32 aty_pll_408_to_var(const struct fb_info *info,
801			      const union aty_pll *pll)
802{
803	return (pll->ics2595.period_in_ps);	/* default for now */
804}
805
806static void aty_set_pll_408(const struct fb_info *info,
807			    const union aty_pll *pll)
808{
809	struct atyfb_par *par = (struct atyfb_par *) info->par;
810	u32 program_bits;
811	u32 locationAddr;
812
813	u8 tmpA, tmpB, tmpC;
814	char old_crtc_ext_disp;
815
816	old_crtc_ext_disp = aty_ld_8(CRTC_GEN_CNTL + 3, par);
817	aty_st_8(CRTC_GEN_CNTL + 3,
818		 old_crtc_ext_disp | (CRTC_EXT_DISP_EN >> 24), par);
819
820	program_bits = pll->ics2595.program_bits;
821	locationAddr = pll->ics2595.locationAddr;
822
823	/* Program clock */
824	aty_dac_waste4(par);
825	tmpB = aty_ld_8(DAC_REGS + 2, par) | 1;
826	aty_dac_waste4(par);
827	aty_st_8(DAC_REGS + 2, tmpB, par);
828
829	tmpA = tmpB;
830	tmpC = tmpA;
831	tmpA |= 8;
832	tmpB = 1;
833
834	aty_st_8(DAC_REGS, tmpB, par);
835	aty_st_8(DAC_REGS + 2, tmpA, par);
836
837	udelay(400);		/* delay for 400 us */
838
839	locationAddr = (locationAddr << 2) + 0x40;
840	tmpB = locationAddr;
841	tmpA = program_bits >> 8;
842
843	aty_st_8(DAC_REGS, tmpB, par);
844	aty_st_8(DAC_REGS + 2, tmpA, par);
845
846	tmpB = locationAddr + 1;
847	tmpA = (u8) program_bits;
848
849	aty_st_8(DAC_REGS, tmpB, par);
850	aty_st_8(DAC_REGS + 2, tmpA, par);
851
852	tmpB = locationAddr + 2;
853	tmpA = 0x77;
854
855	aty_st_8(DAC_REGS, tmpB, par);
856	aty_st_8(DAC_REGS + 2, tmpA, par);
857
858	udelay(400);		/* delay for 400 us */
859	tmpA = tmpC & (~(1 | 8));
860	tmpB = 1;
861
862	aty_st_8(DAC_REGS, tmpB, par);
863	aty_st_8(DAC_REGS + 2, tmpA, par);
864
865	(void) aty_ld_8(DAC_REGS, par);	/* Clear DAC Counter */
866	aty_st_8(CRTC_GEN_CNTL + 3, old_crtc_ext_disp, par);
867	return;
868}
869
870const struct aty_pll_ops aty_pll_att20c408 = {
871	.var_to_pll	= aty_var_to_pll_408,
872	.pll_to_var	= aty_pll_408_to_var,
873	.set_pll	= aty_set_pll_408,
874};
875
876
877    /*
878     *  Unsupported DAC and Clock Chip
879     */
880
881static int aty_set_dac_unsupported(const struct fb_info *info,
882				   const union aty_pll *pll, u32 bpp,
883				   u32 accel)
884{
885	struct atyfb_par *par = (struct atyfb_par *) info->par;
886
887	aty_st_le32(BUS_CNTL, 0x890e20f1, par);
888	aty_st_le32(DAC_CNTL, 0x47052100, par);
889	/* new in 2.2.3p1 from Geert. ???????? */
890	aty_st_le32(BUS_CNTL, 0x590e10ff, par);
891	aty_st_le32(DAC_CNTL, 0x47012100, par);
892	return 0;
893}
894
895static int dummy(void)
896{
897	return 0;
898}
899
900const struct aty_dac_ops aty_dac_unsupported = {
901	.set_dac	= aty_set_dac_unsupported,
902};
903
904const struct aty_pll_ops aty_pll_unsupported = {
905	.var_to_pll	= (void *) dummy,
906	.pll_to_var	= (void *) dummy,
907	.set_pll	= (void *) dummy,
908};
909