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