1 // SPDX-License-Identifier: GPL-2.0
4 * ATI Mach64 CT/VT/GT/LT Support
8 #include <linux/delay.h>
10 #include <video/mach64.h>
13 #include <asm/machdep.h>
18 static int aty_valid_pll_ct (const struct fb_info
*info
, u32 vclk_per
, struct pll_ct
*pll
);
19 static int aty_dsp_gt (const struct fb_info
*info
, u32 bpp
, struct pll_ct
*pll
);
20 static int aty_var_to_pll_ct(const struct fb_info
*info
, u32 vclk_per
, u32 bpp
, union aty_pll
*pll
);
21 static u32
aty_pll_to_var_ct(const struct fb_info
*info
, const union aty_pll
*pll
);
23 u8
aty_ld_pll_ct(int offset
, const struct atyfb_par
*par
)
28 aty_st_8(CLOCK_CNTL_ADDR
, (offset
<< 2) & PLL_ADDR
, par
);
29 /* read the register value */
30 res
= aty_ld_8(CLOCK_CNTL_DATA
, par
);
34 static void aty_st_pll_ct(int offset
, u8 val
, const struct atyfb_par
*par
)
37 aty_st_8(CLOCK_CNTL_ADDR
, ((offset
<< 2) & PLL_ADDR
) | PLL_WR_EN
, par
);
38 /* write the register value */
39 aty_st_8(CLOCK_CNTL_DATA
, val
& PLL_DATA
, par
);
40 aty_st_8(CLOCK_CNTL_ADDR
, ((offset
<< 2) & PLL_ADDR
) & ~PLL_WR_EN
, par
);
45 * <daniel.mantione@freepascal.org>
48 * ATI Mach64 CT clock synthesis description.
50 * All clocks on the Mach64 can be calculated using the same principle:
53 * CLK = ----------------------
54 * PLL_REF_DIV * POST_DIV
56 * XTALIN is a fixed speed clock. Common speeds are 14.31 MHz and 29.50 MHz.
57 * PLL_REF_DIV can be set by the user, but is the same for all clocks.
58 * FB_DIV can be set by the user for each clock individually, it should be set
59 * between 128 and 255, the chip will generate a bad clock signal for too low
61 * x depends on the type of clock; usually it is 2, but for the MCLK it can also
63 * POST_DIV can be set by the user for each clock individually, Possible values
64 * are 1,2,4,8 and for some clocks other values are available too.
65 * CLK is of course the clock speed that is generated.
67 * The Mach64 has these clocks:
69 * MCLK The clock rate of the chip
70 * XCLK The clock rate of the on-chip memory
71 * VCLK0 First pixel clock of first CRT controller
72 * VCLK1 Second pixel clock of first CRT controller
73 * VCLK2 Third pixel clock of first CRT controller
74 * VCLK3 Fourth pixel clock of first CRT controller
75 * VCLK Selected pixel clock, one of VCLK0, VCLK1, VCLK2, VCLK3
76 * V2CLK Pixel clock of the second CRT controller.
77 * SCLK Multi-purpose clock
79 * - MCLK and XCLK use the same FB_DIV
80 * - VCLK0 .. VCLK3 use the same FB_DIV
81 * - V2CLK is needed when the second CRTC is used (can be used for dualhead);
82 * i.e. CRT monitor connected to laptop has different resolution than built
84 * - SCLK is not available on all cards; it is know to exist on the Rage LT-PRO,
85 * Rage XL and Rage Mobility. It is know not to exist on the Mach64 VT.
86 * - V2CLK is not available on all cards, most likely only the Rage LT-PRO,
87 * the Rage XL and the Rage Mobility
89 * SCLK can be used to:
90 * - Clock the chip instead of MCLK
91 * - Replace XTALIN with a user defined frequency
92 * - Generate the pixel clock for the LCD monitor (instead of VCLK)
96 * It can be quite hard to calculate XCLK and MCLK if they don't run at the
97 * same frequency. Luckily, until now all cards that need asynchrone clock
98 * speeds seem to have SCLK.
99 * So this driver uses SCLK to clock the chip and XCLK to clock the memory.
102 /* ------------------------------------------------------------------------- */
105 * PLL programming (Mach64 CT family)
108 * This procedure sets the display fifo. The display fifo is a buffer that
109 * contains data read from the video memory that waits to be processed by
110 * the CRT controller.
112 * On the more modern Mach64 variants, the chip doesn't calculate the
113 * interval after which the display fifo has to be reloaded from memory
114 * automatically, the driver has to do it instead.
117 #define Maximum_DSP_PRECISION 7
118 static u8 postdividers
[] = {1,2,4,8,3};
120 static int aty_dsp_gt(const struct fb_info
*info
, u32 bpp
, struct pll_ct
*pll
)
122 u32 dsp_off
, dsp_on
, dsp_xclks
;
123 u32 multiplier
, divider
, ras_multiplier
, ras_divider
, tmp
;
127 multiplier
= ((u32
)pll
->mclk_fb_div
) * pll
->vclk_post_div_real
;
128 divider
= ((u32
)pll
->vclk_fb_div
) * pll
->xclk_ref_div
;
130 ras_multiplier
= pll
->xclkmaxrasdelay
;
134 divider
= divider
* (bpp
>> 2);
136 vshift
= (6 - 2) - pll
->xclk_post_div
; /* FIFO is 64 bits wide in accelerator mode ... */
139 vshift
--; /* ... but only 32 bits in VGA mode. */
141 #ifdef CONFIG_FB_ATY_GENERIC_LCD
142 if (pll
->xres
!= 0) {
143 struct atyfb_par
*par
= (struct atyfb_par
*) info
->par
;
145 multiplier
= multiplier
* par
->lcd_width
;
146 divider
= divider
* pll
->xres
& ~7;
148 ras_multiplier
= ras_multiplier
* par
->lcd_width
;
149 ras_divider
= ras_divider
* pll
->xres
& ~7;
152 /* If we don't do this, 32 bits for multiplier & divider won't be
153 enough in certain situations! */
154 while (((multiplier
| divider
) & 1) == 0) {
155 multiplier
= multiplier
>> 1;
156 divider
= divider
>> 1;
159 /* Determine DSP precision first */
160 tmp
= ((multiplier
* pll
->fifo_size
) << vshift
) / divider
;
162 for (dsp_precision
= -5; tmp
; dsp_precision
++)
164 if (dsp_precision
< 0)
166 else if (dsp_precision
> Maximum_DSP_PRECISION
)
167 dsp_precision
= Maximum_DSP_PRECISION
;
169 xshift
= 6 - dsp_precision
;
172 /* Move on to dsp_off */
173 dsp_off
= ((multiplier
* (pll
->fifo_size
- 1)) << vshift
) / divider
-
174 (1 << (vshift
- xshift
));
177 dsp_on = ((multiplier * 20 << vshift) + divider) / divider;
180 dsp_on
= ((multiplier
<< vshift
) + divider
) / divider
;
181 tmp
= ((ras_multiplier
<< xshift
) + ras_divider
) / ras_divider
;
184 dsp_on
= dsp_on
+ (tmp
* 2) + (pll
->xclkpagefaultdelay
<< xshift
);
187 /* Calculate rounding factor and apply it to dsp_on */
188 tmp
= ((1 << (Maximum_DSP_PRECISION
- dsp_precision
)) - 1) >> 1;
189 dsp_on
= ((dsp_on
+ tmp
) / (tmp
+ 1)) * (tmp
+ 1);
191 if (dsp_on
>= ((dsp_off
/ (tmp
+ 1)) * (tmp
+ 1))) {
192 dsp_on
= dsp_off
- (multiplier
<< vshift
) / divider
;
193 dsp_on
= (dsp_on
/ (tmp
+ 1)) * (tmp
+ 1);
196 /* Last but not least: dsp_xclks */
197 dsp_xclks
= ((multiplier
<< (vshift
+ 5)) + divider
) / divider
;
199 /* Get register values. */
200 pll
->dsp_on_off
= (dsp_on
<< 16) + dsp_off
;
201 pll
->dsp_config
= (dsp_precision
<< 20) | (pll
->dsp_loop_latency
<< 16) | dsp_xclks
;
203 printk("atyfb(%s): dsp_config 0x%08x, dsp_on_off 0x%08x\n",
204 __func__
, pll
->dsp_config
, pll
->dsp_on_off
);
209 static int aty_valid_pll_ct(const struct fb_info
*info
, u32 vclk_per
, struct pll_ct
*pll
)
212 struct atyfb_par
*par
= (struct atyfb_par
*) info
->par
;
215 /* FIXME: use the VTB/GTB /{3,6,12} post dividers if they're better suited */
216 q
= par
->ref_clk_per
* pll
->pll_ref_div
* 4 / vclk_per
;
217 if (q
< 16*8 || q
> 255*8) {
218 printk(KERN_CRIT
"atyfb: vclk out of range\n");
221 pll
->vclk_post_div
= (q
< 128*8);
222 pll
->vclk_post_div
+= (q
< 64*8);
223 pll
->vclk_post_div
+= (q
< 32*8);
225 pll
->vclk_post_div_real
= postdividers
[pll
->vclk_post_div
];
226 // pll->vclk_post_div <<= 6;
227 pll
->vclk_fb_div
= q
* pll
->vclk_post_div_real
/ 8;
228 pllvclk
= (1000000 * 2 * pll
->vclk_fb_div
) /
229 (par
->ref_clk_per
* pll
->pll_ref_div
);
231 printk("atyfb(%s): pllvclk=%d MHz, vclk=%d MHz\n",
232 __func__
, pllvclk
, pllvclk
/ pll
->vclk_post_div_real
);
234 pll
->pll_vclk_cntl
= 0x03; /* VCLK = PLL_VCLK/VCLKx_POST */
236 /* Set ECP (scaler/overlay clock) divider */
237 if (par
->pll_limits
.ecp_max
) {
238 int ecp
= pllvclk
/ pll
->vclk_post_div_real
;
241 while (ecp
> par
->pll_limits
.ecp_max
&& ecp_div
< 2) {
245 pll
->pll_vclk_cntl
|= ecp_div
<< 4;
251 static int aty_var_to_pll_ct(const struct fb_info
*info
, u32 vclk_per
, u32 bpp
, union aty_pll
*pll
)
253 struct atyfb_par
*par
= (struct atyfb_par
*) info
->par
;
256 if ((err
= aty_valid_pll_ct(info
, vclk_per
, &pll
->ct
)))
258 if (M64_HAS(GTB_DSP
) && (err
= aty_dsp_gt(info
, bpp
, &pll
->ct
)))
260 /*aty_calc_pll_ct(info, &pll->ct);*/
264 static u32
aty_pll_to_var_ct(const struct fb_info
*info
, const union aty_pll
*pll
)
266 struct atyfb_par
*par
= (struct atyfb_par
*) info
->par
;
268 ret
= par
->ref_clk_per
* pll
->ct
.pll_ref_div
* pll
->ct
.vclk_post_div_real
/ pll
->ct
.vclk_fb_div
/ 2;
269 #ifdef CONFIG_FB_ATY_GENERIC_LCD
270 if(pll
->ct
.xres
> 0) {
271 ret
*= par
->lcd_width
;
276 printk("atyfb(%s): calculated 0x%08X(%i)\n", __func__
, ret
, ret
);
281 void aty_set_pll_ct(const struct fb_info
*info
, const union aty_pll
*pll
)
283 struct atyfb_par
*par
= (struct atyfb_par
*) info
->par
;
284 u32 crtc_gen_cntl
, lcd_gen_cntrl
;
289 printk("atyfb(%s): about to program:\n"
290 "pll_ext_cntl=0x%02x pll_gen_cntl=0x%02x pll_vclk_cntl=0x%02x\n",
292 pll
->ct
.pll_ext_cntl
, pll
->ct
.pll_gen_cntl
, pll
->ct
.pll_vclk_cntl
);
294 printk("atyfb(%s): setting clock %lu for FeedBackDivider %i, ReferenceDivider %i, PostDivider %i(%i)\n",
296 par
->clk_wr_offset
, pll
->ct
.vclk_fb_div
,
297 pll
->ct
.pll_ref_div
, pll
->ct
.vclk_post_div
, pll
->ct
.vclk_post_div_real
);
299 #ifdef CONFIG_FB_ATY_GENERIC_LCD
300 if (par
->lcd_table
!= 0) {
302 lcd_gen_cntrl
= aty_ld_lcd(LCD_GEN_CNTL
, par
);
303 aty_st_lcd(LCD_GEN_CNTL
, lcd_gen_cntrl
& ~LCD_ON
, par
);
306 aty_st_8(CLOCK_CNTL
, par
->clk_wr_offset
| CLOCK_STROBE
, par
);
308 /* Temporarily switch to accelerator mode */
309 crtc_gen_cntl
= aty_ld_le32(CRTC_GEN_CNTL
, par
);
310 if (!(crtc_gen_cntl
& CRTC_EXT_DISP_EN
))
311 aty_st_le32(CRTC_GEN_CNTL
, crtc_gen_cntl
| CRTC_EXT_DISP_EN
, par
);
313 /* Reset VCLK generator */
314 aty_st_pll_ct(PLL_VCLK_CNTL
, pll
->ct
.pll_vclk_cntl
, par
);
316 /* Set post-divider */
317 tmp2
= par
->clk_wr_offset
<< 1;
318 tmp
= aty_ld_pll_ct(VCLK_POST_DIV
, par
);
319 tmp
&= ~(0x03U
<< tmp2
);
320 tmp
|= ((pll
->ct
.vclk_post_div
& 0x03U
) << tmp2
);
321 aty_st_pll_ct(VCLK_POST_DIV
, tmp
, par
);
323 /* Set extended post-divider */
324 tmp
= aty_ld_pll_ct(PLL_EXT_CNTL
, par
);
325 tmp
&= ~(0x10U
<< par
->clk_wr_offset
);
327 tmp
|= pll
->ct
.pll_ext_cntl
;
328 aty_st_pll_ct(PLL_EXT_CNTL
, tmp
, par
);
330 /* Set feedback divider */
331 tmp
= VCLK0_FB_DIV
+ par
->clk_wr_offset
;
332 aty_st_pll_ct(tmp
, (pll
->ct
.vclk_fb_div
& 0xFFU
), par
);
334 aty_st_pll_ct(PLL_GEN_CNTL
, (pll
->ct
.pll_gen_cntl
& (~(PLL_OVERRIDE
| PLL_MCLK_RST
))) | OSC_EN
, par
);
336 /* End VCLK generator reset */
337 aty_st_pll_ct(PLL_VCLK_CNTL
, pll
->ct
.pll_vclk_cntl
& ~(PLL_VCLK_RST
), par
);
340 aty_st_pll_ct(PLL_GEN_CNTL
, pll
->ct
.pll_gen_cntl
, par
);
341 aty_st_pll_ct(PLL_VCLK_CNTL
, pll
->ct
.pll_vclk_cntl
, par
);
344 /* Restore mode register */
345 if (!(crtc_gen_cntl
& CRTC_EXT_DISP_EN
))
346 aty_st_le32(CRTC_GEN_CNTL
, crtc_gen_cntl
, par
);
348 if (M64_HAS(GTB_DSP
)) {
353 else if (par
->ram_type
>= SDRAM
)
357 aty_st_pll_ct(DLL_CNTL
, dll_cntl
, par
);
358 aty_st_pll_ct(VFC_CNTL
, 0x1b, par
);
359 aty_st_le32(DSP_CONFIG
, pll
->ct
.dsp_config
, par
);
360 aty_st_le32(DSP_ON_OFF
, pll
->ct
.dsp_on_off
, par
);
363 aty_st_pll_ct(DLL_CNTL
, dll_cntl
, par
);
365 aty_st_pll_ct(DLL_CNTL
, dll_cntl
| 0x40, par
);
367 aty_st_pll_ct(DLL_CNTL
, dll_cntl
& ~0x40, par
);
369 #ifdef CONFIG_FB_ATY_GENERIC_LCD
370 if (par
->lcd_table
!= 0) {
372 aty_st_lcd(LCD_GEN_CNTL
, lcd_gen_cntrl
, par
);
377 static void aty_get_pll_ct(const struct fb_info
*info
, union aty_pll
*pll
)
379 struct atyfb_par
*par
= (struct atyfb_par
*) info
->par
;
382 clock
= aty_ld_8(CLOCK_CNTL
, par
) & 0x03U
;
384 pll
->ct
.vclk_post_div
= (aty_ld_pll_ct(VCLK_POST_DIV
, par
) >> tmp
) & 0x03U
;
386 pll
->ct
.pll_ext_cntl
= aty_ld_pll_ct(PLL_EXT_CNTL
, par
) & 0x0FU
;
387 pll
->ct
.vclk_fb_div
= aty_ld_pll_ct(VCLK0_FB_DIV
+ clock
, par
) & 0xFFU
;
388 pll
->ct
.pll_ref_div
= aty_ld_pll_ct(PLL_REF_DIV
, par
);
389 pll
->ct
.mclk_fb_div
= aty_ld_pll_ct(MCLK_FB_DIV
, par
);
391 pll
->ct
.pll_gen_cntl
= aty_ld_pll_ct(PLL_GEN_CNTL
, par
);
392 pll
->ct
.pll_vclk_cntl
= aty_ld_pll_ct(PLL_VCLK_CNTL
, par
);
394 if (M64_HAS(GTB_DSP
)) {
395 pll
->ct
.dsp_config
= aty_ld_le32(DSP_CONFIG
, par
);
396 pll
->ct
.dsp_on_off
= aty_ld_le32(DSP_ON_OFF
, par
);
400 static int aty_init_pll_ct(const struct fb_info
*info
, union aty_pll
*pll
)
402 struct atyfb_par
*par
= (struct atyfb_par
*) info
->par
;
403 u8 mpost_div
, xpost_div
, sclk_post_div_real
;
405 u32 dsp_config
, dsp_on_off
, vga_dsp_config
, vga_dsp_on_off
;
407 int pllmclk
, pllsclk
;
409 pll
->ct
.pll_ext_cntl
= aty_ld_pll_ct(PLL_EXT_CNTL
, par
);
410 pll
->ct
.xclk_post_div
= pll
->ct
.pll_ext_cntl
& 0x07;
411 pll
->ct
.xclk_ref_div
= 1;
412 switch (pll
->ct
.xclk_post_div
) {
413 case 0: case 1: case 2: case 3:
417 pll
->ct
.xclk_ref_div
= 3;
418 pll
->ct
.xclk_post_div
= 0;
422 printk(KERN_CRIT
"atyfb: Unsupported xclk source: %d.\n", pll
->ct
.xclk_post_div
);
425 pll
->ct
.mclk_fb_mult
= 2;
426 if(pll
->ct
.pll_ext_cntl
& PLL_MFB_TIMES_4_2B
) {
427 pll
->ct
.mclk_fb_mult
= 4;
428 pll
->ct
.xclk_post_div
-= 1;
432 printk("atyfb(%s): mclk_fb_mult=%d, xclk_post_div=%d\n",
433 __func__
, pll
->ct
.mclk_fb_mult
, pll
->ct
.xclk_post_div
);
436 memcntl
= aty_ld_le32(MEM_CNTL
, par
);
437 trp
= (memcntl
& 0x300) >> 8;
439 pll
->ct
.xclkpagefaultdelay
= ((memcntl
& 0xc00) >> 10) + ((memcntl
& 0x1000) >> 12) + trp
+ 2;
440 pll
->ct
.xclkmaxrasdelay
= ((memcntl
& 0x70000) >> 16) + trp
+ 2;
442 if (M64_HAS(FIFO_32
)) {
443 pll
->ct
.fifo_size
= 32;
445 pll
->ct
.fifo_size
= 24;
446 pll
->ct
.xclkpagefaultdelay
+= 2;
447 pll
->ct
.xclkmaxrasdelay
+= 3;
450 switch (par
->ram_type
) {
452 if (info
->fix
.smem_len
<=ONE_MB
) {
453 pll
->ct
.dsp_loop_latency
= 10;
455 pll
->ct
.dsp_loop_latency
= 8;
456 pll
->ct
.xclkpagefaultdelay
+= 2;
461 if (info
->fix
.smem_len
<=ONE_MB
) {
462 pll
->ct
.dsp_loop_latency
= 9;
464 pll
->ct
.dsp_loop_latency
= 8;
465 pll
->ct
.xclkpagefaultdelay
+= 1;
469 if (info
->fix
.smem_len
<=ONE_MB
) {
470 pll
->ct
.dsp_loop_latency
= 11;
472 pll
->ct
.dsp_loop_latency
= 10;
473 pll
->ct
.xclkpagefaultdelay
+= 1;
477 pll
->ct
.dsp_loop_latency
= 8;
478 pll
->ct
.xclkpagefaultdelay
+= 3;
481 pll
->ct
.dsp_loop_latency
= 11;
482 pll
->ct
.xclkpagefaultdelay
+= 3;
486 if (pll
->ct
.xclkmaxrasdelay
<= pll
->ct
.xclkpagefaultdelay
)
487 pll
->ct
.xclkmaxrasdelay
= pll
->ct
.xclkpagefaultdelay
+ 1;
489 /* Allow BIOS to override */
490 dsp_config
= aty_ld_le32(DSP_CONFIG
, par
);
491 dsp_on_off
= aty_ld_le32(DSP_ON_OFF
, par
);
492 vga_dsp_config
= aty_ld_le32(VGA_DSP_CONFIG
, par
);
493 vga_dsp_on_off
= aty_ld_le32(VGA_DSP_ON_OFF
, par
);
496 pll
->ct
.dsp_loop_latency
= (dsp_config
& DSP_LOOP_LATENCY
) >> 16;
498 FIXME
: is it relevant
for us
?
499 if ((!dsp_on_off
&& !M64_HAS(RESET_3D
)) ||
500 ((dsp_on_off
== vga_dsp_on_off
) &&
501 (!dsp_config
|| !((dsp_config
^ vga_dsp_config
) & DSP_XCLKS_PER_QW
)))) {
502 vga_dsp_on_off
&= VGA_DSP_OFF
;
503 vga_dsp_config
&= VGA_DSP_XCLKS_PER_QW
;
504 if (ATIDivide(vga_dsp_on_off
, vga_dsp_config
, 5, 1) > 24)
505 pll
->ct
.fifo_size
= 32;
507 pll
->ct
.fifo_size
= 24;
510 /* Exit if the user does not want us to tamper with the clock
511 rates of her chip. */
512 if (par
->mclk_per
== 0) {
513 u8 mclk_fb_div
, pll_ext_cntl
;
514 pll
->ct
.pll_ref_div
= aty_ld_pll_ct(PLL_REF_DIV
, par
);
515 pll_ext_cntl
= aty_ld_pll_ct(PLL_EXT_CNTL
, par
);
516 pll
->ct
.xclk_post_div_real
= postdividers
[pll_ext_cntl
& 0x07];
517 mclk_fb_div
= aty_ld_pll_ct(MCLK_FB_DIV
, par
);
518 if (pll_ext_cntl
& PLL_MFB_TIMES_4_2B
)
520 pll
->ct
.mclk_fb_div
= mclk_fb_div
;
524 pll
->ct
.pll_ref_div
= par
->pll_per
* 2 * 255 / par
->ref_clk_per
;
526 /* FIXME: use the VTB/GTB /3 post divider if it's better suited */
527 q
= par
->ref_clk_per
* pll
->ct
.pll_ref_div
* 8 /
528 (pll
->ct
.mclk_fb_mult
* par
->xclk_per
);
530 if (q
< 16*8 || q
> 255*8) {
531 printk(KERN_CRIT
"atxfb: xclk out of range\n");
534 xpost_div
= (q
< 128*8);
535 xpost_div
+= (q
< 64*8);
536 xpost_div
+= (q
< 32*8);
538 pll
->ct
.xclk_post_div_real
= postdividers
[xpost_div
];
539 pll
->ct
.mclk_fb_div
= q
* pll
->ct
.xclk_post_div_real
/ 8;
542 if (machine_is(powermac
)) {
543 /* Override PLL_EXT_CNTL & 0x07. */
544 pll
->ct
.xclk_post_div
= xpost_div
;
545 pll
->ct
.xclk_ref_div
= 1;
550 pllmclk
= (1000000 * pll
->ct
.mclk_fb_mult
* pll
->ct
.mclk_fb_div
) /
551 (par
->ref_clk_per
* pll
->ct
.pll_ref_div
);
552 printk("atyfb(%s): pllmclk=%d MHz, xclk=%d MHz\n",
553 __func__
, pllmclk
, pllmclk
/ pll
->ct
.xclk_post_div_real
);
556 if (M64_HAS(SDRAM_MAGIC_PLL
) && (par
->ram_type
>= SDRAM
))
557 pll
->ct
.pll_gen_cntl
= OSC_EN
;
559 pll
->ct
.pll_gen_cntl
= OSC_EN
| DLL_PWDN
/* | FORCE_DCLK_TRI_STATE */;
561 if (M64_HAS(MAGIC_POSTDIV
))
562 pll
->ct
.pll_ext_cntl
= 0;
564 pll
->ct
.pll_ext_cntl
= xpost_div
;
566 if (pll
->ct
.mclk_fb_mult
== 4)
567 pll
->ct
.pll_ext_cntl
|= PLL_MFB_TIMES_4_2B
;
569 if (par
->mclk_per
== par
->xclk_per
) {
570 pll
->ct
.pll_gen_cntl
|= (xpost_div
<< 4); /* mclk == xclk */
573 * The chip clock is not equal to the memory clock.
574 * Therefore we will use sclk to clock the chip.
576 pll
->ct
.pll_gen_cntl
|= (6 << 4); /* mclk == sclk */
578 q
= par
->ref_clk_per
* pll
->ct
.pll_ref_div
* 4 / par
->mclk_per
;
579 if (q
< 16*8 || q
> 255*8) {
580 printk(KERN_CRIT
"atyfb: mclk out of range\n");
583 mpost_div
= (q
< 128*8);
584 mpost_div
+= (q
< 64*8);
585 mpost_div
+= (q
< 32*8);
587 sclk_post_div_real
= postdividers
[mpost_div
];
588 pll
->ct
.sclk_fb_div
= q
* sclk_post_div_real
/ 8;
589 pll
->ct
.spll_cntl2
= mpost_div
<< 4;
591 pllsclk
= (1000000 * 2 * pll
->ct
.sclk_fb_div
) /
592 (par
->ref_clk_per
* pll
->ct
.pll_ref_div
);
593 printk("atyfb(%s): use sclk, pllsclk=%d MHz, sclk=mclk=%d MHz\n",
594 __func__
, pllsclk
, pllsclk
/ sclk_post_div_real
);
598 /* Disable the extra precision pixel clock controls since we do not use them. */
599 pll
->ct
.ext_vpll_cntl
= aty_ld_pll_ct(EXT_VPLL_CNTL
, par
);
600 pll
->ct
.ext_vpll_cntl
&= ~(EXT_VPLL_EN
| EXT_VPLL_VGA_EN
| EXT_VPLL_INSYNC
);
605 static void aty_resume_pll_ct(const struct fb_info
*info
,
608 struct atyfb_par
*par
= info
->par
;
610 if (par
->mclk_per
!= par
->xclk_per
) {
612 * This disables the sclk, crashes the computer as reported:
613 * aty_st_pll_ct(SPLL_CNTL2, 3, info);
615 * So it seems the sclk must be enabled before it is used;
616 * so PLL_GEN_CNTL must be programmed *after* the sclk.
618 aty_st_pll_ct(SCLK_FB_DIV
, pll
->ct
.sclk_fb_div
, par
);
619 aty_st_pll_ct(SPLL_CNTL2
, pll
->ct
.spll_cntl2
, par
);
621 * SCLK has been started. Wait for the PLL to lock. 5 ms
622 * should be enough according to mach64 programmer's guide.
627 aty_st_pll_ct(PLL_REF_DIV
, pll
->ct
.pll_ref_div
, par
);
628 aty_st_pll_ct(PLL_GEN_CNTL
, pll
->ct
.pll_gen_cntl
, par
);
629 aty_st_pll_ct(MCLK_FB_DIV
, pll
->ct
.mclk_fb_div
, par
);
630 aty_st_pll_ct(PLL_EXT_CNTL
, pll
->ct
.pll_ext_cntl
, par
);
631 aty_st_pll_ct(EXT_VPLL_CNTL
, pll
->ct
.ext_vpll_cntl
, par
);
634 static int dummy(void)
639 const struct aty_dac_ops aty_dac_ct
= {
640 .set_dac
= (void *) dummy
,
643 const struct aty_pll_ops aty_pll_ct
= {
644 .var_to_pll
= aty_var_to_pll_ct
,
645 .pll_to_var
= aty_pll_to_var_ct
,
646 .set_pll
= aty_set_pll_ct
,
647 .get_pll
= aty_get_pll_ct
,
648 .init_pll
= aty_init_pll_ct
,
649 .resume_pll
= aty_resume_pll_ct
,