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 | |
43 | static 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 | |
53 | static 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, val: tmp | CLOCK_STROBE, par); |
61 | return; |
62 | } |
63 | |
64 | |
65 | /* |
66 | * IBM RGB514 DAC and Clock Chip |
67 | */ |
68 | |
69 | static void aty_st_514(int offset, u8 val, const struct atyfb_par *par) |
70 | { |
71 | aty_st_8(DAC_CNTL, val: 1, par); |
72 | /* right addr byte */ |
73 | aty_st_8(DAC_W_INDEX, val: offset & 0xff, par); |
74 | /* left addr byte */ |
75 | aty_st_8(DAC_DATA, val: (offset >> 8) & 0xff, par); |
76 | aty_st_8(DAC_MASK, val, par); |
77 | aty_st_8(DAC_CNTL, val: 0, par); |
78 | } |
79 | |
80 | static 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(offset: 0x90, val: 0x00, par); /* VRAM Mask Low */ |
113 | aty_st_514(offset: 0x04, val: tab[i].pixel_dly, par); /* Horizontal Sync Control */ |
114 | aty_st_514(offset: 0x05, val: 0x00, par); /* Power Management */ |
115 | aty_st_514(offset: 0x02, val: 0x01, par); /* Misc Clock Control */ |
116 | aty_st_514(offset: 0x71, val: tab[i].misc2_cntl, par); /* Misc Control 2 */ |
117 | aty_st_514(offset: 0x0a, val: tab[i].pixel_rep, par); /* Pixel Format */ |
118 | aty_st_514(offset: tab[i].pixel_cntl_index, val: tab[i].pixel_cntl_v1, par); |
119 | /* Misc Control 2 / 16 BPP Control / 32 BPP Control */ |
120 | return 0; |
121 | } |
122 | |
123 | static 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 | |
161 | static 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 | |
175 | static 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(offset: 0x06, val: 0x02, par); /* DAC Operation */ |
181 | aty_st_514(offset: 0x10, val: 0x01, par); /* PLL Control 1 */ |
182 | aty_st_514(offset: 0x70, val: 0x01, par); /* Misc Control 1 */ |
183 | aty_st_514(offset: 0x8f, val: 0x1f, par); /* PLL Ref. Divider Input */ |
184 | aty_st_514(offset: 0x03, val: 0x00, par); /* Sync Control */ |
185 | aty_st_514(offset: 0x05, val: 0x00, par); /* Power Management */ |
186 | aty_st_514(offset: 0x20, val: pll->ibm514.m, par); /* F0 / M0 */ |
187 | aty_st_514(offset: 0x21, val: pll->ibm514.n, par); /* F1 / N0 */ |
188 | } |
189 | |
190 | const struct aty_dac_ops aty_dac_ibm514 = { |
191 | .set_dac = aty_set_dac_514, |
192 | }; |
193 | |
194 | const 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 | |
205 | static 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, val: (temp & ~DAC_EXT_SEL_RS2) | DAC_EXT_SEL_RS3, |
246 | par); |
247 | |
248 | aty_st_8(DAC_REGS + 2, val: 0x1D, par); |
249 | aty_st_8(DAC_REGS + 3, val: gModeReg, par); |
250 | aty_st_8(DAC_REGS, val: 0x02, par); |
251 | |
252 | temp = aty_ld_8(DAC_CNTL, par); |
253 | aty_st_8(DAC_CNTL, val: 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, val: (devSetupRegA | mask) | (temp & A860_DELAY_L), |
269 | par); |
270 | temp = aty_ld_8(DAC_CNTL, par); |
271 | aty_st_8(DAC_CNTL, val: (temp & ~(DAC_EXT_SEL_RS2 | DAC_EXT_SEL_RS3)), |
272 | par); |
273 | |
274 | aty_st_le32(BUS_CNTL, val: 0x890e20f1, par); |
275 | aty_st_le32(DAC_CNTL, val: 0x47052100, par); |
276 | return 0; |
277 | } |
278 | |
279 | const 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 | |
288 | static 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, val: DACMask, par); |
326 | |
327 | aty_st_le32(BUS_CNTL, val: 0x890e20f1, par); |
328 | aty_st_le32(DAC_CNTL, val: 0x00072000, par); |
329 | return muxmode; |
330 | } |
331 | |
332 | const 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 | |
341 | static 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 | |
398 | static 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 | |
404 | static 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 | val: (tmp & ~0x04) | (data << 2), par); |
412 | |
413 | tmp = aty_ld_8(CLOCK_CNTL, par); |
414 | aty_st_8(CLOCK_CNTL + par->clk_wr_offset, val: (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, val: (tmp & ~0x08) | (1 << 3), |
421 | par); |
422 | |
423 | aty_StrobeClock(par); |
424 | return; |
425 | } |
426 | |
427 | static 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, val: 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 | val: 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, val: 0, par); /* Strobe = 0 */ |
453 | aty_StrobeClock(par); |
454 | aty_st_8(CLOCK_CNTL + par->clk_wr_offset, val: 1, par); /* Strobe = 0 */ |
455 | aty_StrobeClock(par); |
456 | |
457 | aty_ICS2595_put1bit(data: 1, par); /* Send start bits */ |
458 | aty_ICS2595_put1bit(data: 0, par); /* Start bit */ |
459 | aty_ICS2595_put1bit(data: 0, par); /* Read / ~Write */ |
460 | |
461 | for (i = 0; i < 5; i++) { /* Location 0..4 */ |
462 | aty_ICS2595_put1bit(data: locationAddr & 1, par); |
463 | locationAddr >>= 1; |
464 | } |
465 | |
466 | for (i = 0; i < 8 + 1 + 2 + 2; i++) { |
467 | aty_ICS2595_put1bit(data: 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, val: old_crtc_ext_disp, par); |
475 | aty_st_8(CLOCK_CNTL + par->clk_wr_offset, |
476 | val: 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 | val: ((pll->ics2595.locationAddr & 0x0F) | CLOCK_STROBE), par); |
481 | return; |
482 | } |
483 | |
484 | const 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 | |
495 | static 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 | |
564 | static 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 | |
570 | static 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 | val: 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, val: (locationAddr << 1) + 0x20, par); |
591 | aty_st_8(DAC_REGS + 2, val: 0, par); |
592 | aty_st_8(DAC_REGS + 2, val: (program_bits & 0xFF00) >> 8, par); |
593 | aty_st_8(DAC_REGS + 2, val: (program_bits & 0xFF), par); |
594 | |
595 | (void) aty_ld_8(DAC_REGS, par); /* Clear DAC Counter */ |
596 | aty_st_8(CRTC_GEN_CNTL + 3, val: old_crtc_ext_disp, par); |
597 | return; |
598 | } |
599 | |
600 | const 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 | |
611 | static 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 | |
682 | static 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 | |
688 | static 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 | val: 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, val: tmp | DAC_EXT_SEL_RS2 | DAC_EXT_SEL_RS3, par); |
708 | |
709 | aty_st_8(DAC_REGS, val: locationAddr, par); |
710 | aty_st_8(DAC_REGS + 1, val: (program_bits & 0xff00) >> 8, par); |
711 | aty_st_8(DAC_REGS + 1, val: (program_bits & 0xff), par); |
712 | |
713 | tmp = aty_ld_8(DAC_CNTL, par); |
714 | aty_st_8(DAC_CNTL, val: (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, val: old_crtc_ext_disp, par); |
719 | |
720 | return; |
721 | } |
722 | |
723 | const 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 | |
734 | static 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 | |
800 | static 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 | |
806 | static 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 | val: 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, val: tmpB, par); |
828 | |
829 | tmpA = tmpB; |
830 | tmpC = tmpA; |
831 | tmpA |= 8; |
832 | tmpB = 1; |
833 | |
834 | aty_st_8(DAC_REGS, val: tmpB, par); |
835 | aty_st_8(DAC_REGS + 2, val: 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, val: tmpB, par); |
844 | aty_st_8(DAC_REGS + 2, val: tmpA, par); |
845 | |
846 | tmpB = locationAddr + 1; |
847 | tmpA = (u8) program_bits; |
848 | |
849 | aty_st_8(DAC_REGS, val: tmpB, par); |
850 | aty_st_8(DAC_REGS + 2, val: tmpA, par); |
851 | |
852 | tmpB = locationAddr + 2; |
853 | tmpA = 0x77; |
854 | |
855 | aty_st_8(DAC_REGS, val: tmpB, par); |
856 | aty_st_8(DAC_REGS + 2, val: 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, val: tmpB, par); |
863 | aty_st_8(DAC_REGS + 2, val: tmpA, par); |
864 | |
865 | (void) aty_ld_8(DAC_REGS, par); /* Clear DAC Counter */ |
866 | aty_st_8(CRTC_GEN_CNTL + 3, val: old_crtc_ext_disp, par); |
867 | return; |
868 | } |
869 | |
870 | const 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 | |
881 | static 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, val: 0x890e20f1, par); |
888 | aty_st_le32(DAC_CNTL, val: 0x47052100, par); |
889 | /* new in 2.2.3p1 from Geert. ???????? */ |
890 | aty_st_le32(BUS_CNTL, val: 0x590e10ff, par); |
891 | aty_st_le32(DAC_CNTL, val: 0x47012100, par); |
892 | return 0; |
893 | } |
894 | |
895 | static int dummy(void) |
896 | { |
897 | return 0; |
898 | } |
899 | |
900 | const struct aty_dac_ops aty_dac_unsupported = { |
901 | .set_dac = aty_set_dac_unsupported, |
902 | }; |
903 | |
904 | const 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 | |