3 * ATI Mach64 CT/VT/GT/LT Support
7 #include <linux/delay.h>
9 #include <video/mach64.h>
12 #include <asm/machdep.h>
17 static int aty_valid_pll_ct (const struct fb_info
*info
, u32 vclk_per
, struct pll_ct
*pll
);
18 static int aty_dsp_gt (const struct fb_info
*info
, u32 bpp
, struct pll_ct
*pll
);
19 static int aty_var_to_pll_ct(const struct fb_info
*info
, u32 vclk_per
, u32 bpp
, union aty_pll
*pll
);
20 static u32
aty_pll_to_var_ct(const struct fb_info
*info
, const union aty_pll
*pll
);
22 u8
aty_ld_pll_ct(int offset
, const struct atyfb_par
*par
)
27 aty_st_8(CLOCK_CNTL_ADDR
, (offset
<< 2) & PLL_ADDR
, par
);
28 /* read the register value */
29 res
= aty_ld_8(CLOCK_CNTL_DATA
, par
);
33 static void aty_st_pll_ct(int offset
, u8 val
, const struct atyfb_par
*par
)
36 aty_st_8(CLOCK_CNTL_ADDR
, ((offset
<< 2) & PLL_ADDR
) | PLL_WR_EN
, par
);
37 /* write the register value */
38 aty_st_8(CLOCK_CNTL_DATA
, val
& PLL_DATA
, par
);
39 aty_st_8(CLOCK_CNTL_ADDR
, ((offset
<< 2) & PLL_ADDR
) & ~PLL_WR_EN
, par
);
44 * <daniel.mantione@freepascal.org>
47 * ATI Mach64 CT clock synthesis description.
49 * All clocks on the Mach64 can be calculated using the same principle:
52 * CLK = ----------------------
53 * PLL_REF_DIV * POST_DIV
55 * XTALIN is a fixed speed clock. Common speeds are 14.31 MHz and 29.50 MHz.
56 * PLL_REF_DIV can be set by the user, but is the same for all clocks.
57 * FB_DIV can be set by the user for each clock individually, it should be set
58 * between 128 and 255, the chip will generate a bad clock signal for too low
60 * x depends on the type of clock; usually it is 2, but for the MCLK it can also
62 * POST_DIV can be set by the user for each clock individually, Possible values
63 * are 1,2,4,8 and for some clocks other values are available too.
64 * CLK is of course the clock speed that is generated.
66 * The Mach64 has these clocks:
68 * MCLK The clock rate of the chip
69 * XCLK The clock rate of the on-chip memory
70 * VCLK0 First pixel clock of first CRT controller
71 * VCLK1 Second pixel clock of first CRT controller
72 * VCLK2 Third pixel clock of first CRT controller
73 * VCLK3 Fourth pixel clock of first CRT controller
74 * VCLK Selected pixel clock, one of VCLK0, VCLK1, VCLK2, VCLK3
75 * V2CLK Pixel clock of the second CRT controller.
76 * SCLK Multi-purpose clock
78 * - MCLK and XCLK use the same FB_DIV
79 * - VCLK0 .. VCLK3 use the same FB_DIV
80 * - V2CLK is needed when the second CRTC is used (can be used for dualhead);
81 * i.e. CRT monitor connected to laptop has different resolution than built
83 * - SCLK is not available on all cards; it is know to exist on the Rage LT-PRO,
84 * Rage XL and Rage Mobility. It is know not to exist on the Mach64 VT.
85 * - V2CLK is not available on all cards, most likely only the Rage LT-PRO,
86 * the Rage XL and the Rage Mobility
88 * SCLK can be used to:
89 * - Clock the chip instead of MCLK
90 * - Replace XTALIN with a user defined frequency
91 * - Generate the pixel clock for the LCD monitor (instead of VCLK)
95 * It can be quite hard to calculate XCLK and MCLK if they don't run at the
96 * same frequency. Luckily, until now all cards that need asynchrone clock
97 * speeds seem to have SCLK.
98 * So this driver uses SCLK to clock the chip and XCLK to clock the memory.
101 /* ------------------------------------------------------------------------- */
104 * PLL programming (Mach64 CT family)
107 * This procedure sets the display fifo. The display fifo is a buffer that
108 * contains data read from the video memory that waits to be processed by
109 * the CRT controller.
111 * On the more modern Mach64 variants, the chip doesn't calculate the
112 * interval after which the display fifo has to be reloaded from memory
113 * automatically, the driver has to do it instead.
116 #define Maximum_DSP_PRECISION 7
117 static u8 postdividers
[] = {1,2,4,8,3};
119 static int aty_dsp_gt(const struct fb_info
*info
, u32 bpp
, struct pll_ct
*pll
)
121 u32 dsp_off
, dsp_on
, dsp_xclks
;
122 u32 multiplier
, divider
, ras_multiplier
, ras_divider
, tmp
;
126 multiplier
= ((u32
)pll
->mclk_fb_div
) * pll
->vclk_post_div_real
;
127 divider
= ((u32
)pll
->vclk_fb_div
) * pll
->xclk_ref_div
;
129 ras_multiplier
= pll
->xclkmaxrasdelay
;
133 divider
= divider
* (bpp
>> 2);
135 vshift
= (6 - 2) - pll
->xclk_post_div
; /* FIFO is 64 bits wide in accelerator mode ... */
138 vshift
--; /* ... but only 32 bits in VGA mode. */
140 #ifdef CONFIG_FB_ATY_GENERIC_LCD
141 if (pll
->xres
!= 0) {
142 struct atyfb_par
*par
= (struct atyfb_par
*) info
->par
;
144 multiplier
= multiplier
* par
->lcd_width
;
145 divider
= divider
* pll
->xres
& ~7;
147 ras_multiplier
= ras_multiplier
* par
->lcd_width
;
148 ras_divider
= ras_divider
* pll
->xres
& ~7;
151 /* If we don't do this, 32 bits for multiplier & divider won't be
152 enough in certain situations! */
153 while (((multiplier
| divider
) & 1) == 0) {
154 multiplier
= multiplier
>> 1;
155 divider
= divider
>> 1;
158 /* Determine DSP precision first */
159 tmp
= ((multiplier
* pll
->fifo_size
) << vshift
) / divider
;
161 for (dsp_precision
= -5; tmp
; dsp_precision
++)
163 if (dsp_precision
< 0)
165 else if (dsp_precision
> Maximum_DSP_PRECISION
)
166 dsp_precision
= Maximum_DSP_PRECISION
;
168 xshift
= 6 - dsp_precision
;
171 /* Move on to dsp_off */
172 dsp_off
= ((multiplier
* (pll
->fifo_size
- 1)) << vshift
) / divider
-
173 (1 << (vshift
- xshift
));
176 dsp_on = ((multiplier * 20 << vshift) + divider) / divider;
179 dsp_on
= ((multiplier
<< vshift
) + divider
) / divider
;
180 tmp
= ((ras_multiplier
<< xshift
) + ras_divider
) / ras_divider
;
183 dsp_on
= dsp_on
+ (tmp
* 2) + (pll
->xclkpagefaultdelay
<< xshift
);
186 /* Calculate rounding factor and apply it to dsp_on */
187 tmp
= ((1 << (Maximum_DSP_PRECISION
- dsp_precision
)) - 1) >> 1;
188 dsp_on
= ((dsp_on
+ tmp
) / (tmp
+ 1)) * (tmp
+ 1);
190 if (dsp_on
>= ((dsp_off
/ (tmp
+ 1)) * (tmp
+ 1))) {
191 dsp_on
= dsp_off
- (multiplier
<< vshift
) / divider
;
192 dsp_on
= (dsp_on
/ (tmp
+ 1)) * (tmp
+ 1);
195 /* Last but not least: dsp_xclks */
196 dsp_xclks
= ((multiplier
<< (vshift
+ 5)) + divider
) / divider
;
198 /* Get register values. */
199 pll
->dsp_on_off
= (dsp_on
<< 16) + dsp_off
;
200 pll
->dsp_config
= (dsp_precision
<< 20) | (pll
->dsp_loop_latency
<< 16) | dsp_xclks
;
202 printk("atyfb(%s): dsp_config 0x%08x, dsp_on_off 0x%08x\n",
203 __func__
, pll
->dsp_config
, pll
->dsp_on_off
);
208 static int aty_valid_pll_ct(const struct fb_info
*info
, u32 vclk_per
, struct pll_ct
*pll
)
211 struct atyfb_par
*par
= (struct atyfb_par
*) info
->par
;
214 /* FIXME: use the VTB/GTB /{3,6,12} post dividers if they're better suited */
215 q
= par
->ref_clk_per
* pll
->pll_ref_div
* 4 / vclk_per
;
216 if (q
< 16*8 || q
> 255*8) {
217 printk(KERN_CRIT
"atyfb: vclk out of range\n");
220 pll
->vclk_post_div
= (q
< 128*8);
221 pll
->vclk_post_div
+= (q
< 64*8);
222 pll
->vclk_post_div
+= (q
< 32*8);
224 pll
->vclk_post_div_real
= postdividers
[pll
->vclk_post_div
];
225 // pll->vclk_post_div <<= 6;
226 pll
->vclk_fb_div
= q
* pll
->vclk_post_div_real
/ 8;
227 pllvclk
= (1000000 * 2 * pll
->vclk_fb_div
) /
228 (par
->ref_clk_per
* pll
->pll_ref_div
);
230 printk("atyfb(%s): pllvclk=%d MHz, vclk=%d MHz\n",
231 __func__
, pllvclk
, pllvclk
/ pll
->vclk_post_div_real
);
233 pll
->pll_vclk_cntl
= 0x03; /* VCLK = PLL_VCLK/VCLKx_POST */
235 /* Set ECP (scaler/overlay clock) divider */
236 if (par
->pll_limits
.ecp_max
) {
237 int ecp
= pllvclk
/ pll
->vclk_post_div_real
;
240 while (ecp
> par
->pll_limits
.ecp_max
&& ecp_div
< 2) {
244 pll
->pll_vclk_cntl
|= ecp_div
<< 4;
250 static int aty_var_to_pll_ct(const struct fb_info
*info
, u32 vclk_per
, u32 bpp
, union aty_pll
*pll
)
252 struct atyfb_par
*par
= (struct atyfb_par
*) info
->par
;
255 if ((err
= aty_valid_pll_ct(info
, vclk_per
, &pll
->ct
)))
257 if (M64_HAS(GTB_DSP
) && (err
= aty_dsp_gt(info
, bpp
, &pll
->ct
)))
259 /*aty_calc_pll_ct(info, &pll->ct);*/
263 static u32
aty_pll_to_var_ct(const struct fb_info
*info
, const union aty_pll
*pll
)
265 struct atyfb_par
*par
= (struct atyfb_par
*) info
->par
;
267 ret
= par
->ref_clk_per
* pll
->ct
.pll_ref_div
* pll
->ct
.vclk_post_div_real
/ pll
->ct
.vclk_fb_div
/ 2;
268 #ifdef CONFIG_FB_ATY_GENERIC_LCD
269 if(pll
->ct
.xres
> 0) {
270 ret
*= par
->lcd_width
;
275 printk("atyfb(%s): calculated 0x%08X(%i)\n", __func__
, ret
, ret
);
280 void aty_set_pll_ct(const struct fb_info
*info
, const union aty_pll
*pll
)
282 struct atyfb_par
*par
= (struct atyfb_par
*) info
->par
;
283 u32 crtc_gen_cntl
, lcd_gen_cntrl
;
288 printk("atyfb(%s): about to program:\n"
289 "pll_ext_cntl=0x%02x pll_gen_cntl=0x%02x pll_vclk_cntl=0x%02x\n",
291 pll
->ct
.pll_ext_cntl
, pll
->ct
.pll_gen_cntl
, pll
->ct
.pll_vclk_cntl
);
293 printk("atyfb(%s): setting clock %lu for FeedBackDivider %i, ReferenceDivider %i, PostDivider %i(%i)\n",
295 par
->clk_wr_offset
, pll
->ct
.vclk_fb_div
,
296 pll
->ct
.pll_ref_div
, pll
->ct
.vclk_post_div
, pll
->ct
.vclk_post_div_real
);
298 #ifdef CONFIG_FB_ATY_GENERIC_LCD
299 if (par
->lcd_table
!= 0) {
301 lcd_gen_cntrl
= aty_ld_lcd(LCD_GEN_CNTL
, par
);
302 aty_st_lcd(LCD_GEN_CNTL
, lcd_gen_cntrl
& ~LCD_ON
, par
);
305 aty_st_8(CLOCK_CNTL
, par
->clk_wr_offset
| CLOCK_STROBE
, par
);
307 /* Temporarily switch to accelerator mode */
308 crtc_gen_cntl
= aty_ld_le32(CRTC_GEN_CNTL
, par
);
309 if (!(crtc_gen_cntl
& CRTC_EXT_DISP_EN
))
310 aty_st_le32(CRTC_GEN_CNTL
, crtc_gen_cntl
| CRTC_EXT_DISP_EN
, par
);
312 /* Reset VCLK generator */
313 aty_st_pll_ct(PLL_VCLK_CNTL
, pll
->ct
.pll_vclk_cntl
, par
);
315 /* Set post-divider */
316 tmp2
= par
->clk_wr_offset
<< 1;
317 tmp
= aty_ld_pll_ct(VCLK_POST_DIV
, par
);
318 tmp
&= ~(0x03U
<< tmp2
);
319 tmp
|= ((pll
->ct
.vclk_post_div
& 0x03U
) << tmp2
);
320 aty_st_pll_ct(VCLK_POST_DIV
, tmp
, par
);
322 /* Set extended post-divider */
323 tmp
= aty_ld_pll_ct(PLL_EXT_CNTL
, par
);
324 tmp
&= ~(0x10U
<< par
->clk_wr_offset
);
326 tmp
|= pll
->ct
.pll_ext_cntl
;
327 aty_st_pll_ct(PLL_EXT_CNTL
, tmp
, par
);
329 /* Set feedback divider */
330 tmp
= VCLK0_FB_DIV
+ par
->clk_wr_offset
;
331 aty_st_pll_ct(tmp
, (pll
->ct
.vclk_fb_div
& 0xFFU
), par
);
333 aty_st_pll_ct(PLL_GEN_CNTL
, (pll
->ct
.pll_gen_cntl
& (~(PLL_OVERRIDE
| PLL_MCLK_RST
))) | OSC_EN
, par
);
335 /* End VCLK generator reset */
336 aty_st_pll_ct(PLL_VCLK_CNTL
, pll
->ct
.pll_vclk_cntl
& ~(PLL_VCLK_RST
), par
);
339 aty_st_pll_ct(PLL_GEN_CNTL
, pll
->ct
.pll_gen_cntl
, par
);
340 aty_st_pll_ct(PLL_VCLK_CNTL
, pll
->ct
.pll_vclk_cntl
, par
);
343 /* Restore mode register */
344 if (!(crtc_gen_cntl
& CRTC_EXT_DISP_EN
))
345 aty_st_le32(CRTC_GEN_CNTL
, crtc_gen_cntl
, par
);
347 if (M64_HAS(GTB_DSP
)) {
352 else if (par
->ram_type
>= SDRAM
)
356 aty_st_pll_ct(DLL_CNTL
, dll_cntl
, par
);
357 aty_st_pll_ct(VFC_CNTL
, 0x1b, par
);
358 aty_st_le32(DSP_CONFIG
, pll
->ct
.dsp_config
, par
);
359 aty_st_le32(DSP_ON_OFF
, pll
->ct
.dsp_on_off
, par
);
362 aty_st_pll_ct(DLL_CNTL
, dll_cntl
, par
);
364 aty_st_pll_ct(DLL_CNTL
, dll_cntl
| 0x40, par
);
366 aty_st_pll_ct(DLL_CNTL
, dll_cntl
& ~0x40, par
);
368 #ifdef CONFIG_FB_ATY_GENERIC_LCD
369 if (par
->lcd_table
!= 0) {
371 aty_st_lcd(LCD_GEN_CNTL
, lcd_gen_cntrl
, par
);
376 static void aty_get_pll_ct(const struct fb_info
*info
, union aty_pll
*pll
)
378 struct atyfb_par
*par
= (struct atyfb_par
*) info
->par
;
381 clock
= aty_ld_8(CLOCK_CNTL
, par
) & 0x03U
;
383 pll
->ct
.vclk_post_div
= (aty_ld_pll_ct(VCLK_POST_DIV
, par
) >> tmp
) & 0x03U
;
385 pll
->ct
.pll_ext_cntl
= aty_ld_pll_ct(PLL_EXT_CNTL
, par
) & 0x0FU
;
386 pll
->ct
.vclk_fb_div
= aty_ld_pll_ct(VCLK0_FB_DIV
+ clock
, par
) & 0xFFU
;
387 pll
->ct
.pll_ref_div
= aty_ld_pll_ct(PLL_REF_DIV
, par
);
388 pll
->ct
.mclk_fb_div
= aty_ld_pll_ct(MCLK_FB_DIV
, par
);
390 pll
->ct
.pll_gen_cntl
= aty_ld_pll_ct(PLL_GEN_CNTL
, par
);
391 pll
->ct
.pll_vclk_cntl
= aty_ld_pll_ct(PLL_VCLK_CNTL
, par
);
393 if (M64_HAS(GTB_DSP
)) {
394 pll
->ct
.dsp_config
= aty_ld_le32(DSP_CONFIG
, par
);
395 pll
->ct
.dsp_on_off
= aty_ld_le32(DSP_ON_OFF
, par
);
399 static int aty_init_pll_ct(const struct fb_info
*info
, union aty_pll
*pll
)
401 struct atyfb_par
*par
= (struct atyfb_par
*) info
->par
;
402 u8 mpost_div
, xpost_div
, sclk_post_div_real
;
404 u32 dsp_config
, dsp_on_off
, vga_dsp_config
, vga_dsp_on_off
;
406 int pllmclk
, pllsclk
;
408 pll
->ct
.pll_ext_cntl
= aty_ld_pll_ct(PLL_EXT_CNTL
, par
);
409 pll
->ct
.xclk_post_div
= pll
->ct
.pll_ext_cntl
& 0x07;
410 pll
->ct
.xclk_ref_div
= 1;
411 switch (pll
->ct
.xclk_post_div
) {
412 case 0: case 1: case 2: case 3:
416 pll
->ct
.xclk_ref_div
= 3;
417 pll
->ct
.xclk_post_div
= 0;
421 printk(KERN_CRIT
"atyfb: Unsupported xclk source: %d.\n", pll
->ct
.xclk_post_div
);
424 pll
->ct
.mclk_fb_mult
= 2;
425 if(pll
->ct
.pll_ext_cntl
& PLL_MFB_TIMES_4_2B
) {
426 pll
->ct
.mclk_fb_mult
= 4;
427 pll
->ct
.xclk_post_div
-= 1;
431 printk("atyfb(%s): mclk_fb_mult=%d, xclk_post_div=%d\n",
432 __func__
, pll
->ct
.mclk_fb_mult
, pll
->ct
.xclk_post_div
);
435 memcntl
= aty_ld_le32(MEM_CNTL
, par
);
436 trp
= (memcntl
& 0x300) >> 8;
438 pll
->ct
.xclkpagefaultdelay
= ((memcntl
& 0xc00) >> 10) + ((memcntl
& 0x1000) >> 12) + trp
+ 2;
439 pll
->ct
.xclkmaxrasdelay
= ((memcntl
& 0x70000) >> 16) + trp
+ 2;
441 if (M64_HAS(FIFO_32
)) {
442 pll
->ct
.fifo_size
= 32;
444 pll
->ct
.fifo_size
= 24;
445 pll
->ct
.xclkpagefaultdelay
+= 2;
446 pll
->ct
.xclkmaxrasdelay
+= 3;
449 switch (par
->ram_type
) {
451 if (info
->fix
.smem_len
<=ONE_MB
) {
452 pll
->ct
.dsp_loop_latency
= 10;
454 pll
->ct
.dsp_loop_latency
= 8;
455 pll
->ct
.xclkpagefaultdelay
+= 2;
460 if (info
->fix
.smem_len
<=ONE_MB
) {
461 pll
->ct
.dsp_loop_latency
= 9;
463 pll
->ct
.dsp_loop_latency
= 8;
464 pll
->ct
.xclkpagefaultdelay
+= 1;
468 if (info
->fix
.smem_len
<=ONE_MB
) {
469 pll
->ct
.dsp_loop_latency
= 11;
471 pll
->ct
.dsp_loop_latency
= 10;
472 pll
->ct
.xclkpagefaultdelay
+= 1;
476 pll
->ct
.dsp_loop_latency
= 8;
477 pll
->ct
.xclkpagefaultdelay
+= 3;
480 pll
->ct
.dsp_loop_latency
= 11;
481 pll
->ct
.xclkpagefaultdelay
+= 3;
485 if (pll
->ct
.xclkmaxrasdelay
<= pll
->ct
.xclkpagefaultdelay
)
486 pll
->ct
.xclkmaxrasdelay
= pll
->ct
.xclkpagefaultdelay
+ 1;
488 /* Allow BIOS to override */
489 dsp_config
= aty_ld_le32(DSP_CONFIG
, par
);
490 dsp_on_off
= aty_ld_le32(DSP_ON_OFF
, par
);
491 vga_dsp_config
= aty_ld_le32(VGA_DSP_CONFIG
, par
);
492 vga_dsp_on_off
= aty_ld_le32(VGA_DSP_ON_OFF
, par
);
495 pll
->ct
.dsp_loop_latency
= (dsp_config
& DSP_LOOP_LATENCY
) >> 16;
497 FIXME
: is it relevant
for us
?
498 if ((!dsp_on_off
&& !M64_HAS(RESET_3D
)) ||
499 ((dsp_on_off
== vga_dsp_on_off
) &&
500 (!dsp_config
|| !((dsp_config
^ vga_dsp_config
) & DSP_XCLKS_PER_QW
)))) {
501 vga_dsp_on_off
&= VGA_DSP_OFF
;
502 vga_dsp_config
&= VGA_DSP_XCLKS_PER_QW
;
503 if (ATIDivide(vga_dsp_on_off
, vga_dsp_config
, 5, 1) > 24)
504 pll
->ct
.fifo_size
= 32;
506 pll
->ct
.fifo_size
= 24;
509 /* Exit if the user does not want us to tamper with the clock
510 rates of her chip. */
511 if (par
->mclk_per
== 0) {
512 u8 mclk_fb_div
, pll_ext_cntl
;
513 pll
->ct
.pll_ref_div
= aty_ld_pll_ct(PLL_REF_DIV
, par
);
514 pll_ext_cntl
= aty_ld_pll_ct(PLL_EXT_CNTL
, par
);
515 pll
->ct
.xclk_post_div_real
= postdividers
[pll_ext_cntl
& 0x07];
516 mclk_fb_div
= aty_ld_pll_ct(MCLK_FB_DIV
, par
);
517 if (pll_ext_cntl
& PLL_MFB_TIMES_4_2B
)
519 pll
->ct
.mclk_fb_div
= mclk_fb_div
;
523 pll
->ct
.pll_ref_div
= par
->pll_per
* 2 * 255 / par
->ref_clk_per
;
525 /* FIXME: use the VTB/GTB /3 post divider if it's better suited */
526 q
= par
->ref_clk_per
* pll
->ct
.pll_ref_div
* 8 /
527 (pll
->ct
.mclk_fb_mult
* par
->xclk_per
);
529 if (q
< 16*8 || q
> 255*8) {
530 printk(KERN_CRIT
"atxfb: xclk out of range\n");
533 xpost_div
= (q
< 128*8);
534 xpost_div
+= (q
< 64*8);
535 xpost_div
+= (q
< 32*8);
537 pll
->ct
.xclk_post_div_real
= postdividers
[xpost_div
];
538 pll
->ct
.mclk_fb_div
= q
* pll
->ct
.xclk_post_div_real
/ 8;
541 if (machine_is(powermac
)) {
542 /* Override PLL_EXT_CNTL & 0x07. */
543 pll
->ct
.xclk_post_div
= xpost_div
;
544 pll
->ct
.xclk_ref_div
= 1;
549 pllmclk
= (1000000 * pll
->ct
.mclk_fb_mult
* pll
->ct
.mclk_fb_div
) /
550 (par
->ref_clk_per
* pll
->ct
.pll_ref_div
);
551 printk("atyfb(%s): pllmclk=%d MHz, xclk=%d MHz\n",
552 __func__
, pllmclk
, pllmclk
/ pll
->ct
.xclk_post_div_real
);
555 if (M64_HAS(SDRAM_MAGIC_PLL
) && (par
->ram_type
>= SDRAM
))
556 pll
->ct
.pll_gen_cntl
= OSC_EN
;
558 pll
->ct
.pll_gen_cntl
= OSC_EN
| DLL_PWDN
/* | FORCE_DCLK_TRI_STATE */;
560 if (M64_HAS(MAGIC_POSTDIV
))
561 pll
->ct
.pll_ext_cntl
= 0;
563 pll
->ct
.pll_ext_cntl
= xpost_div
;
565 if (pll
->ct
.mclk_fb_mult
== 4)
566 pll
->ct
.pll_ext_cntl
|= PLL_MFB_TIMES_4_2B
;
568 if (par
->mclk_per
== par
->xclk_per
) {
569 pll
->ct
.pll_gen_cntl
|= (xpost_div
<< 4); /* mclk == xclk */
572 * The chip clock is not equal to the memory clock.
573 * Therefore we will use sclk to clock the chip.
575 pll
->ct
.pll_gen_cntl
|= (6 << 4); /* mclk == sclk */
577 q
= par
->ref_clk_per
* pll
->ct
.pll_ref_div
* 4 / par
->mclk_per
;
578 if (q
< 16*8 || q
> 255*8) {
579 printk(KERN_CRIT
"atyfb: mclk out of range\n");
582 mpost_div
= (q
< 128*8);
583 mpost_div
+= (q
< 64*8);
584 mpost_div
+= (q
< 32*8);
586 sclk_post_div_real
= postdividers
[mpost_div
];
587 pll
->ct
.sclk_fb_div
= q
* sclk_post_div_real
/ 8;
588 pll
->ct
.spll_cntl2
= mpost_div
<< 4;
590 pllsclk
= (1000000 * 2 * pll
->ct
.sclk_fb_div
) /
591 (par
->ref_clk_per
* pll
->ct
.pll_ref_div
);
592 printk("atyfb(%s): use sclk, pllsclk=%d MHz, sclk=mclk=%d MHz\n",
593 __func__
, pllsclk
, pllsclk
/ sclk_post_div_real
);
597 /* Disable the extra precision pixel clock controls since we do not use them. */
598 pll
->ct
.ext_vpll_cntl
= aty_ld_pll_ct(EXT_VPLL_CNTL
, par
);
599 pll
->ct
.ext_vpll_cntl
&= ~(EXT_VPLL_EN
| EXT_VPLL_VGA_EN
| EXT_VPLL_INSYNC
);
604 static void aty_resume_pll_ct(const struct fb_info
*info
,
607 struct atyfb_par
*par
= info
->par
;
609 if (par
->mclk_per
!= par
->xclk_per
) {
611 * This disables the sclk, crashes the computer as reported:
612 * aty_st_pll_ct(SPLL_CNTL2, 3, info);
614 * So it seems the sclk must be enabled before it is used;
615 * so PLL_GEN_CNTL must be programmed *after* the sclk.
617 aty_st_pll_ct(SCLK_FB_DIV
, pll
->ct
.sclk_fb_div
, par
);
618 aty_st_pll_ct(SPLL_CNTL2
, pll
->ct
.spll_cntl2
, par
);
620 * SCLK has been started. Wait for the PLL to lock. 5 ms
621 * should be enough according to mach64 programmer's guide.
626 aty_st_pll_ct(PLL_REF_DIV
, pll
->ct
.pll_ref_div
, par
);
627 aty_st_pll_ct(PLL_GEN_CNTL
, pll
->ct
.pll_gen_cntl
, par
);
628 aty_st_pll_ct(MCLK_FB_DIV
, pll
->ct
.mclk_fb_div
, par
);
629 aty_st_pll_ct(PLL_EXT_CNTL
, pll
->ct
.pll_ext_cntl
, par
);
630 aty_st_pll_ct(EXT_VPLL_CNTL
, pll
->ct
.ext_vpll_cntl
, par
);
633 static int dummy(void)
638 const struct aty_dac_ops aty_dac_ct
= {
639 .set_dac
= (void *) dummy
,
642 const struct aty_pll_ops aty_pll_ct
= {
643 .var_to_pll
= aty_var_to_pll_ct
,
644 .pll_to_var
= aty_pll_to_var_ct
,
645 .set_pll
= aty_set_pll_ct
,
646 .get_pll
= aty_get_pll_ct
,
647 .init_pll
= aty_init_pll_ct
,
648 .resume_pll
= aty_resume_pll_ct
,