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