3 * ATI Mach64 CT/VT/GT/LT Support
7 #include <linux/delay.h>
9 #include <video/mach64.h>
14 static int aty_valid_pll_ct (const struct fb_info
*info
, u32 vclk_per
, struct pll_ct
*pll
);
15 static int aty_dsp_gt (const struct fb_info
*info
, u32 bpp
, struct pll_ct
*pll
);
16 static int aty_var_to_pll_ct(const struct fb_info
*info
, u32 vclk_per
, u32 bpp
, union aty_pll
*pll
);
17 static u32
aty_pll_to_var_ct(const struct fb_info
*info
, const union aty_pll
*pll
);
19 u8
aty_ld_pll_ct(int offset
, const struct atyfb_par
*par
)
24 aty_st_8(CLOCK_CNTL_ADDR
, (offset
<< 2) & PLL_ADDR
, par
);
25 /* read the register value */
26 res
= aty_ld_8(CLOCK_CNTL_DATA
, par
);
30 void aty_st_pll_ct(int offset
, u8 val
, const struct atyfb_par
*par
)
33 aty_st_8(CLOCK_CNTL_ADDR
, ((offset
<< 2) & PLL_ADDR
) | PLL_WR_EN
, par
);
34 /* write the register value */
35 aty_st_8(CLOCK_CNTL_DATA
, val
& PLL_DATA
, par
);
36 aty_st_8(CLOCK_CNTL_ADDR
, ((offset
<< 2) & PLL_ADDR
) & ~PLL_WR_EN
, par
);
41 * <daniel.mantione@freepascal.org>
44 * ATI Mach64 CT clock synthesis description.
46 * All clocks on the Mach64 can be calculated using the same principle:
49 * CLK = ----------------------
50 * PLL_REF_DIV * POST_DIV
52 * XTALIN is a fixed speed clock. Common speeds are 14.31 MHz and 29.50 MHz.
53 * PLL_REF_DIV can be set by the user, but is the same for all clocks.
54 * FB_DIV can be set by the user for each clock individually, it should be set
55 * between 128 and 255, the chip will generate a bad clock signal for too low
57 * x depends on the type of clock; usually it is 2, but for the MCLK it can also
59 * POST_DIV can be set by the user for each clock individually, Possible values
60 * are 1,2,4,8 and for some clocks other values are available too.
61 * CLK is of course the clock speed that is generated.
63 * The Mach64 has these clocks:
65 * MCLK The clock rate of the chip
66 * XCLK The clock rate of the on-chip memory
67 * VCLK0 First pixel clock of first CRT controller
68 * VCLK1 Second pixel clock of first CRT controller
69 * VCLK2 Third pixel clock of first CRT controller
70 * VCLK3 Fourth pixel clock of first CRT controller
71 * VCLK Selected pixel clock, one of VCLK0, VCLK1, VCLK2, VCLK3
72 * V2CLK Pixel clock of the second CRT controller.
73 * SCLK Multi-purpose clock
75 * - MCLK and XCLK use the same FB_DIV
76 * - VCLK0 .. VCLK3 use the same FB_DIV
77 * - V2CLK is needed when the second CRTC is used (can be used for dualhead);
78 * i.e. CRT monitor connected to laptop has different resolution than built
80 * - SCLK is not available on all cards; it is know to exist on the Rage LT-PRO,
81 * Rage XL and Rage Mobility. It is know not to exist on the Mach64 VT.
82 * - V2CLK is not available on all cards, most likely only the Rage LT-PRO,
83 * the Rage XL and the Rage Mobility
85 * SCLK can be used to:
86 * - Clock the chip instead of MCLK
87 * - Replace XTALIN with a user defined frequency
88 * - Generate the pixel clock for the LCD monitor (instead of VCLK)
92 * It can be quite hard to calculate XCLK and MCLK if they don't run at the
93 * same frequency. Luckily, until now all cards that need asynchrone clock
94 * speeds seem to have SCLK.
95 * So this driver uses SCLK to clock the chip and XCLK to clock the memory.
98 /* ------------------------------------------------------------------------- */
101 * PLL programming (Mach64 CT family)
104 * This procedure sets the display fifo. The display fifo is a buffer that
105 * contains data read from the video memory that waits to be processed by
106 * the CRT controller.
108 * On the more modern Mach64 variants, the chip doesn't calculate the
109 * interval after which the display fifo has to be reloaded from memory
110 * automatically, the driver has to do it instead.
113 #define Maximum_DSP_PRECISION 7
114 static u8 postdividers
[] = {1,2,4,8,3};
116 static int aty_dsp_gt(const struct fb_info
*info
, u32 bpp
, struct pll_ct
*pll
)
118 u32 dsp_off
, dsp_on
, dsp_xclks
;
119 u32 multiplier
, divider
, ras_multiplier
, ras_divider
, tmp
;
123 multiplier
= ((u32
)pll
->mclk_fb_div
) * pll
->vclk_post_div_real
;
124 divider
= ((u32
)pll
->vclk_fb_div
) * pll
->xclk_ref_div
;
126 ras_multiplier
= pll
->xclkmaxrasdelay
;
130 divider
= divider
* (bpp
>> 2);
132 vshift
= (6 - 2) - pll
->xclk_post_div
; /* FIFO is 64 bits wide in accelerator mode ... */
135 vshift
--; /* ... but only 32 bits in VGA mode. */
137 #ifdef CONFIG_FB_ATY_GENERIC_LCD
138 if (pll
->xres
!= 0) {
139 struct atyfb_par
*par
= (struct atyfb_par
*) info
->par
;
141 multiplier
= multiplier
* par
->lcd_width
;
142 divider
= divider
* pll
->xres
& ~7;
144 ras_multiplier
= ras_multiplier
* par
->lcd_width
;
145 ras_divider
= ras_divider
* pll
->xres
& ~7;
148 /* If we don't do this, 32 bits for multiplier & divider won't be
149 enough in certain situations! */
150 while (((multiplier
| divider
) & 1) == 0) {
151 multiplier
= multiplier
>> 1;
152 divider
= divider
>> 1;
155 /* Determine DSP precision first */
156 tmp
= ((multiplier
* pll
->fifo_size
) << vshift
) / divider
;
158 for (dsp_precision
= -5; tmp
; dsp_precision
++)
160 if (dsp_precision
< 0)
162 else if (dsp_precision
> Maximum_DSP_PRECISION
)
163 dsp_precision
= Maximum_DSP_PRECISION
;
165 xshift
= 6 - dsp_precision
;
168 /* Move on to dsp_off */
169 dsp_off
= ((multiplier
* (pll
->fifo_size
- 1)) << vshift
) / divider
-
170 (1 << (vshift
- xshift
));
173 dsp_on = ((multiplier * 20 << vshift) + divider) / divider;
176 dsp_on
= ((multiplier
<< vshift
) + divider
) / divider
;
177 tmp
= ((ras_multiplier
<< xshift
) + ras_divider
) / ras_divider
;
180 dsp_on
= dsp_on
+ (tmp
* 2) + (pll
->xclkpagefaultdelay
<< xshift
);
183 /* Calculate rounding factor and apply it to dsp_on */
184 tmp
= ((1 << (Maximum_DSP_PRECISION
- dsp_precision
)) - 1) >> 1;
185 dsp_on
= ((dsp_on
+ tmp
) / (tmp
+ 1)) * (tmp
+ 1);
187 if (dsp_on
>= ((dsp_off
/ (tmp
+ 1)) * (tmp
+ 1))) {
188 dsp_on
= dsp_off
- (multiplier
<< vshift
) / divider
;
189 dsp_on
= (dsp_on
/ (tmp
+ 1)) * (tmp
+ 1);
192 /* Last but not least: dsp_xclks */
193 dsp_xclks
= ((multiplier
<< (vshift
+ 5)) + divider
) / divider
;
195 /* Get register values. */
196 pll
->dsp_on_off
= (dsp_on
<< 16) + dsp_off
;
197 pll
->dsp_config
= (dsp_precision
<< 20) | (pll
->dsp_loop_latency
<< 16) | dsp_xclks
;
199 printk("atyfb(%s): dsp_config 0x%08x, dsp_on_off 0x%08x\n",
200 __FUNCTION__
, pll
->dsp_config
, pll
->dsp_on_off
);
205 static int aty_valid_pll_ct(const struct fb_info
*info
, u32 vclk_per
, struct pll_ct
*pll
)
208 struct atyfb_par
*par
= (struct atyfb_par
*) info
->par
;
211 /* FIXME: use the VTB/GTB /{3,6,12} post dividers if they're better suited */
212 q
= par
->ref_clk_per
* pll
->pll_ref_div
* 4 / vclk_per
;
213 if (q
< 16*8 || q
> 255*8) {
214 printk(KERN_CRIT
"atyfb: vclk out of range\n");
217 pll
->vclk_post_div
= (q
< 128*8);
218 pll
->vclk_post_div
+= (q
< 64*8);
219 pll
->vclk_post_div
+= (q
< 32*8);
221 pll
->vclk_post_div_real
= postdividers
[pll
->vclk_post_div
];
222 // pll->vclk_post_div <<= 6;
223 pll
->vclk_fb_div
= q
* pll
->vclk_post_div_real
/ 8;
224 pllvclk
= (1000000 * 2 * pll
->vclk_fb_div
) /
225 (par
->ref_clk_per
* pll
->pll_ref_div
);
227 printk("atyfb(%s): pllvclk=%d MHz, vclk=%d MHz\n",
228 __FUNCTION__
, pllvclk
, pllvclk
/ pll
->vclk_post_div_real
);
230 pll
->pll_vclk_cntl
= 0x03; /* VCLK = PLL_VCLK/VCLKx_POST */
232 /* Set ECP (scaler/overlay clock) divider */
233 if (par
->pll_limits
.ecp_max
) {
234 int ecp
= pllvclk
/ pll
->vclk_post_div_real
;
237 while (ecp
> par
->pll_limits
.ecp_max
&& ecp_div
< 2) {
241 pll
->pll_vclk_cntl
|= ecp_div
<< 4;
247 static int aty_var_to_pll_ct(const struct fb_info
*info
, u32 vclk_per
, u32 bpp
, union aty_pll
*pll
)
249 struct atyfb_par
*par
= (struct atyfb_par
*) info
->par
;
252 if ((err
= aty_valid_pll_ct(info
, vclk_per
, &pll
->ct
)))
254 if (M64_HAS(GTB_DSP
) && (err
= aty_dsp_gt(info
, bpp
, &pll
->ct
)))
256 /*aty_calc_pll_ct(info, &pll->ct);*/
260 static u32
aty_pll_to_var_ct(const struct fb_info
*info
, const union aty_pll
*pll
)
262 struct atyfb_par
*par
= (struct atyfb_par
*) info
->par
;
264 ret
= par
->ref_clk_per
* pll
->ct
.pll_ref_div
* pll
->ct
.vclk_post_div_real
/ pll
->ct
.vclk_fb_div
/ 2;
265 #ifdef CONFIG_FB_ATY_GENERIC_LCD
266 if(pll
->ct
.xres
> 0) {
267 ret
*= par
->lcd_width
;
272 printk("atyfb(%s): calculated 0x%08X(%i)\n", __FUNCTION__
, ret
, ret
);
277 void aty_set_pll_ct(const struct fb_info
*info
, const union aty_pll
*pll
)
279 struct atyfb_par
*par
= (struct atyfb_par
*) info
->par
;
280 u32 crtc_gen_cntl
, lcd_gen_cntrl
;
285 printk("atyfb(%s): about to program:\n"
286 "pll_ext_cntl=0x%02x pll_gen_cntl=0x%02x pll_vclk_cntl=0x%02x\n",
288 pll
->ct
.pll_ext_cntl
, pll
->ct
.pll_gen_cntl
, pll
->ct
.pll_vclk_cntl
);
290 printk("atyfb(%s): setting clock %lu for FeedBackDivider %i, ReferenceDivider %i, PostDivider %i(%i)\n",
292 par
->clk_wr_offset
, pll
->ct
.vclk_fb_div
,
293 pll
->ct
.pll_ref_div
, pll
->ct
.vclk_post_div
, pll
->ct
.vclk_post_div_real
);
295 #ifdef CONFIG_FB_ATY_GENERIC_LCD
296 if (par
->lcd_table
!= 0) {
298 lcd_gen_cntrl
= aty_ld_lcd(LCD_GEN_CNTL
, par
);
299 aty_st_lcd(LCD_GEN_CNTL
, lcd_gen_cntrl
& ~LCD_ON
, par
);
302 aty_st_8(CLOCK_CNTL
, par
->clk_wr_offset
| CLOCK_STROBE
, par
);
304 /* Temporarily switch to accelerator mode */
305 crtc_gen_cntl
= aty_ld_le32(CRTC_GEN_CNTL
, par
);
306 if (!(crtc_gen_cntl
& CRTC_EXT_DISP_EN
))
307 aty_st_le32(CRTC_GEN_CNTL
, crtc_gen_cntl
| CRTC_EXT_DISP_EN
, par
);
309 /* Reset VCLK generator */
310 aty_st_pll_ct(PLL_VCLK_CNTL
, pll
->ct
.pll_vclk_cntl
, par
);
312 /* Set post-divider */
313 tmp2
= par
->clk_wr_offset
<< 1;
314 tmp
= aty_ld_pll_ct(VCLK_POST_DIV
, par
);
315 tmp
&= ~(0x03U
<< tmp2
);
316 tmp
|= ((pll
->ct
.vclk_post_div
& 0x03U
) << tmp2
);
317 aty_st_pll_ct(VCLK_POST_DIV
, tmp
, par
);
319 /* Set extended post-divider */
320 tmp
= aty_ld_pll_ct(PLL_EXT_CNTL
, par
);
321 tmp
&= ~(0x10U
<< par
->clk_wr_offset
);
323 tmp
|= pll
->ct
.pll_ext_cntl
;
324 aty_st_pll_ct(PLL_EXT_CNTL
, tmp
, par
);
326 /* Set feedback divider */
327 tmp
= VCLK0_FB_DIV
+ par
->clk_wr_offset
;
328 aty_st_pll_ct(tmp
, (pll
->ct
.vclk_fb_div
& 0xFFU
), par
);
330 aty_st_pll_ct(PLL_GEN_CNTL
, (pll
->ct
.pll_gen_cntl
& (~(PLL_OVERRIDE
| PLL_MCLK_RST
))) | OSC_EN
, par
);
332 /* End VCLK generator reset */
333 aty_st_pll_ct(PLL_VCLK_CNTL
, pll
->ct
.pll_vclk_cntl
& ~(PLL_VCLK_RST
), par
);
336 aty_st_pll_ct(PLL_GEN_CNTL
, pll
->ct
.pll_gen_cntl
, par
);
337 aty_st_pll_ct(PLL_VCLK_CNTL
, pll
->ct
.pll_vclk_cntl
, par
);
340 /* Restore mode register */
341 if (!(crtc_gen_cntl
& CRTC_EXT_DISP_EN
))
342 aty_st_le32(CRTC_GEN_CNTL
, crtc_gen_cntl
, par
);
344 if (M64_HAS(GTB_DSP
)) {
349 else if (par
->ram_type
>= SDRAM
)
353 aty_st_pll_ct(DLL_CNTL
, dll_cntl
, par
);
354 aty_st_pll_ct(VFC_CNTL
, 0x1b, par
);
355 aty_st_le32(DSP_CONFIG
, pll
->ct
.dsp_config
, par
);
356 aty_st_le32(DSP_ON_OFF
, pll
->ct
.dsp_on_off
, par
);
359 aty_st_pll_ct(DLL_CNTL
, dll_cntl
, par
);
361 aty_st_pll_ct(DLL_CNTL
, dll_cntl
| 0x40, par
);
363 aty_st_pll_ct(DLL_CNTL
, dll_cntl
& ~0x40, par
);
365 #ifdef CONFIG_FB_ATY_GENERIC_LCD
366 if (par
->lcd_table
!= 0) {
368 aty_st_lcd(LCD_GEN_CNTL
, lcd_gen_cntrl
, par
);
373 static void __init
aty_get_pll_ct(const struct fb_info
*info
,
376 struct atyfb_par
*par
= (struct atyfb_par
*) info
->par
;
379 clock
= aty_ld_8(CLOCK_CNTL
, par
) & 0x03U
;
381 pll
->ct
.vclk_post_div
= (aty_ld_pll_ct(VCLK_POST_DIV
, par
) >> tmp
) & 0x03U
;
383 pll
->ct
.pll_ext_cntl
= aty_ld_pll_ct(PLL_EXT_CNTL
, par
) & 0x0FU
;
384 pll
->ct
.vclk_fb_div
= aty_ld_pll_ct(VCLK0_FB_DIV
+ clock
, par
) & 0xFFU
;
385 pll
->ct
.pll_ref_div
= aty_ld_pll_ct(PLL_REF_DIV
, par
);
386 pll
->ct
.mclk_fb_div
= aty_ld_pll_ct(MCLK_FB_DIV
, par
);
388 pll
->ct
.pll_gen_cntl
= aty_ld_pll_ct(PLL_GEN_CNTL
, par
);
389 pll
->ct
.pll_vclk_cntl
= aty_ld_pll_ct(PLL_VCLK_CNTL
, par
);
391 if (M64_HAS(GTB_DSP
)) {
392 pll
->ct
.dsp_config
= aty_ld_le32(DSP_CONFIG
, par
);
393 pll
->ct
.dsp_on_off
= aty_ld_le32(DSP_ON_OFF
, par
);
397 static int __init
aty_init_pll_ct(const struct fb_info
*info
,
400 struct atyfb_par
*par
= (struct atyfb_par
*) info
->par
;
401 u8 mpost_div
, xpost_div
, sclk_post_div_real
, sclk_fb_div
, spll_cntl2
;
402 u32 q
, i
, memcntl
, trp
;
403 u32 dsp_config
, dsp_on_off
, vga_dsp_config
, vga_dsp_on_off
;
405 int pllmclk
, pllsclk
;
407 pll
->ct
.pll_ext_cntl
= aty_ld_pll_ct(PLL_EXT_CNTL
, par
);
408 pll
->ct
.xclk_post_div
= pll
->ct
.pll_ext_cntl
& 0x07;
409 pll
->ct
.xclk_ref_div
= 1;
410 switch (pll
->ct
.xclk_post_div
) {
411 case 0: case 1: case 2: case 3:
415 pll
->ct
.xclk_ref_div
= 3;
416 pll
->ct
.xclk_post_div
= 0;
420 printk(KERN_CRIT
"atyfb: Unsupported xclk source: %d.\n", pll
->ct
.xclk_post_div
);
423 pll
->ct
.mclk_fb_mult
= 2;
424 if(pll
->ct
.pll_ext_cntl
& PLL_MFB_TIMES_4_2B
) {
425 pll
->ct
.mclk_fb_mult
= 4;
426 pll
->ct
.xclk_post_div
-= 1;
430 printk("atyfb(%s): mclk_fb_mult=%d, xclk_post_div=%d\n",
431 __FUNCTION__
, pll
->ct
.mclk_fb_mult
, pll
->ct
.xclk_post_div
);
434 memcntl
= aty_ld_le32(MEM_CNTL
, par
);
435 trp
= (memcntl
& 0x300) >> 8;
437 pll
->ct
.xclkpagefaultdelay
= ((memcntl
& 0xc00) >> 10) + ((memcntl
& 0x1000) >> 12) + trp
+ 2;
438 pll
->ct
.xclkmaxrasdelay
= ((memcntl
& 0x70000) >> 16) + trp
+ 2;
440 if (M64_HAS(FIFO_32
)) {
441 pll
->ct
.fifo_size
= 32;
443 pll
->ct
.fifo_size
= 24;
444 pll
->ct
.xclkpagefaultdelay
+= 2;
445 pll
->ct
.xclkmaxrasdelay
+= 3;
448 switch (par
->ram_type
) {
450 if (info
->fix
.smem_len
<=ONE_MB
) {
451 pll
->ct
.dsp_loop_latency
= 10;
453 pll
->ct
.dsp_loop_latency
= 8;
454 pll
->ct
.xclkpagefaultdelay
+= 2;
459 if (info
->fix
.smem_len
<=ONE_MB
) {
460 pll
->ct
.dsp_loop_latency
= 9;
462 pll
->ct
.dsp_loop_latency
= 8;
463 pll
->ct
.xclkpagefaultdelay
+= 1;
467 if (info
->fix
.smem_len
<=ONE_MB
) {
468 pll
->ct
.dsp_loop_latency
= 11;
470 pll
->ct
.dsp_loop_latency
= 10;
471 pll
->ct
.xclkpagefaultdelay
+= 1;
475 pll
->ct
.dsp_loop_latency
= 8;
476 pll
->ct
.xclkpagefaultdelay
+= 3;
479 pll
->ct
.dsp_loop_latency
= 11;
480 pll
->ct
.xclkpagefaultdelay
+= 3;
484 if (pll
->ct
.xclkmaxrasdelay
<= pll
->ct
.xclkpagefaultdelay
)
485 pll
->ct
.xclkmaxrasdelay
= pll
->ct
.xclkpagefaultdelay
+ 1;
487 /* Allow BIOS to override */
488 dsp_config
= aty_ld_le32(DSP_CONFIG
, par
);
489 dsp_on_off
= aty_ld_le32(DSP_ON_OFF
, par
);
490 vga_dsp_config
= aty_ld_le32(VGA_DSP_CONFIG
, par
);
491 vga_dsp_on_off
= aty_ld_le32(VGA_DSP_ON_OFF
, par
);
494 pll
->ct
.dsp_loop_latency
= (dsp_config
& DSP_LOOP_LATENCY
) >> 16;
496 FIXME
: is it relevant
for us
?
497 if ((!dsp_on_off
&& !M64_HAS(RESET_3D
)) ||
498 ((dsp_on_off
== vga_dsp_on_off
) &&
499 (!dsp_config
|| !((dsp_config
^ vga_dsp_config
) & DSP_XCLKS_PER_QW
)))) {
500 vga_dsp_on_off
&= VGA_DSP_OFF
;
501 vga_dsp_config
&= VGA_DSP_XCLKS_PER_QW
;
502 if (ATIDivide(vga_dsp_on_off
, vga_dsp_config
, 5, 1) > 24)
503 pll
->ct
.fifo_size
= 32;
505 pll
->ct
.fifo_size
= 24;
508 /* Exit if the user does not want us to tamper with the clock
509 rates of her chip. */
510 if (par
->mclk_per
== 0) {
511 u8 mclk_fb_div
, pll_ext_cntl
;
512 pll
->ct
.pll_ref_div
= aty_ld_pll_ct(PLL_REF_DIV
, par
);
513 pll_ext_cntl
= aty_ld_pll_ct(PLL_EXT_CNTL
, par
);
514 pll
->ct
.xclk_post_div_real
= postdividers
[pll_ext_cntl
& 0x07];
515 mclk_fb_div
= aty_ld_pll_ct(MCLK_FB_DIV
, par
);
516 if (pll_ext_cntl
& PLL_MFB_TIMES_4_2B
)
518 pll
->ct
.mclk_fb_div
= mclk_fb_div
;
522 pll
->ct
.pll_ref_div
= par
->pll_per
* 2 * 255 / par
->ref_clk_per
;
524 /* FIXME: use the VTB/GTB /3 post divider if it's better suited */
525 q
= par
->ref_clk_per
* pll
->ct
.pll_ref_div
* 8 /
526 (pll
->ct
.mclk_fb_mult
* par
->xclk_per
);
528 if (q
< 16*8 || q
> 255*8) {
529 printk(KERN_CRIT
"atxfb: xclk out of range\n");
532 xpost_div
= (q
< 128*8);
533 xpost_div
+= (q
< 64*8);
534 xpost_div
+= (q
< 32*8);
536 pll
->ct
.xclk_post_div_real
= postdividers
[xpost_div
];
537 pll
->ct
.mclk_fb_div
= q
* pll
->ct
.xclk_post_div_real
/ 8;
540 pllmclk
= (1000000 * pll
->ct
.mclk_fb_mult
* pll
->ct
.mclk_fb_div
) /
541 (par
->ref_clk_per
* pll
->ct
.pll_ref_div
);
542 printk("atyfb(%s): pllmclk=%d MHz, xclk=%d MHz\n",
543 __FUNCTION__
, pllmclk
, pllmclk
/ pll
->ct
.xclk_post_div_real
);
546 if (M64_HAS(SDRAM_MAGIC_PLL
) && (par
->ram_type
>= SDRAM
))
547 pll
->ct
.pll_gen_cntl
= OSC_EN
;
549 pll
->ct
.pll_gen_cntl
= OSC_EN
| DLL_PWDN
/* | FORCE_DCLK_TRI_STATE */;
551 if (M64_HAS(MAGIC_POSTDIV
))
552 pll
->ct
.pll_ext_cntl
= 0;
554 pll
->ct
.pll_ext_cntl
= xpost_div
;
556 if (pll
->ct
.mclk_fb_mult
== 4)
557 pll
->ct
.pll_ext_cntl
|= PLL_MFB_TIMES_4_2B
;
559 if (par
->mclk_per
== par
->xclk_per
) {
560 pll
->ct
.pll_gen_cntl
|= (xpost_div
<< 4); /* mclk == xclk */
563 * The chip clock is not equal to the memory clock.
564 * Therefore we will use sclk to clock the chip.
566 pll
->ct
.pll_gen_cntl
|= (6 << 4); /* mclk == sclk */
568 q
= par
->ref_clk_per
* pll
->ct
.pll_ref_div
* 4 / par
->mclk_per
;
569 if (q
< 16*8 || q
> 255*8) {
570 printk(KERN_CRIT
"atyfb: mclk out of range\n");
573 mpost_div
= (q
< 128*8);
574 mpost_div
+= (q
< 64*8);
575 mpost_div
+= (q
< 32*8);
577 sclk_post_div_real
= postdividers
[mpost_div
];
578 sclk_fb_div
= q
* sclk_post_div_real
/ 8;
579 spll_cntl2
= mpost_div
<< 4;
581 pllsclk
= (1000000 * 2 * sclk_fb_div
) /
582 (par
->ref_clk_per
* pll
->ct
.pll_ref_div
);
583 printk("atyfb(%s): use sclk, pllsclk=%d MHz, sclk=mclk=%d MHz\n",
584 __FUNCTION__
, pllsclk
, pllsclk
/ sclk_post_div_real
);
587 * This disables the sclk, crashes the computer as reported:
588 * aty_st_pll_ct(SPLL_CNTL2, 3, info);
590 * So it seems the sclk must be enabled before it is used;
591 * so PLL_GEN_CNTL must be programmed *after* the sclk.
593 aty_st_pll_ct(SCLK_FB_DIV
, sclk_fb_div
, par
);
594 aty_st_pll_ct(SPLL_CNTL2
, spll_cntl2
, par
);
596 * The sclk has been started. However, I believe the first clock
597 * ticks it generates are not very stable. Hope this primitive loop
598 * helps for Rage Mobilities that sometimes crash when
599 * we switch to sclk. (Daniel Mantione, 13-05-2003)
601 for (i
=0;i
<=0x1ffff;i
++);
604 aty_st_pll_ct(PLL_REF_DIV
, pll
->ct
.pll_ref_div
, par
);
605 aty_st_pll_ct(PLL_GEN_CNTL
, pll
->ct
.pll_gen_cntl
, par
);
606 aty_st_pll_ct(MCLK_FB_DIV
, pll
->ct
.mclk_fb_div
, par
);
607 aty_st_pll_ct(PLL_EXT_CNTL
, pll
->ct
.pll_ext_cntl
, par
);
608 /* Disable the extra precision pixel clock controls since we do not use them. */
609 aty_st_pll_ct(EXT_VPLL_CNTL
, aty_ld_pll_ct(EXT_VPLL_CNTL
, par
) &
610 ~(EXT_VPLL_EN
| EXT_VPLL_VGA_EN
| EXT_VPLL_INSYNC
), par
);
615 static int dummy(void)
620 const struct aty_dac_ops aty_dac_ct
= {
621 .set_dac
= (void *) dummy
,
624 const struct aty_pll_ops aty_pll_ct
= {
625 .var_to_pll
= aty_var_to_pll_ct
,
626 .pll_to_var
= aty_pll_to_var_ct
,
627 .set_pll
= aty_set_pll_ct
,
628 .get_pll
= aty_get_pll_ct
,
629 .init_pll
= aty_init_pll_ct