1 2/* 3 * ATI Mach64 CT/VT/GT/LT Support 4 */ 5 6#include <linux/fb.h> 7#include <linux/delay.h> 8#include <asm/io.h> 9#include <video/mach64.h> 10#include "atyfb.h" 11 12#undef DEBUG 13 14static int aty_valid_pll_ct (const struct fb_info *info, u32 vclk_per, struct pll_ct *pll); 15static int aty_dsp_gt (const struct fb_info *info, u32 bpp, struct pll_ct *pll); 16static int aty_var_to_pll_ct(const struct fb_info *info, u32 vclk_per, u32 bpp, union aty_pll *pll); 17static u32 aty_pll_to_var_ct(const struct fb_info *info, const union aty_pll *pll); 18 19u8 aty_ld_pll_ct(int offset, const struct atyfb_par *par) 20{ 21 u8 res; 22 23 /* write addr byte */ 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); 27 return res; 28} 29 30static void aty_st_pll_ct(int offset, u8 val, const struct atyfb_par *par) 31{ 32 /* write addr byte */ 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); 37} 38 39/* 40 * by Daniel Mantione 41 * <daniel.mantione@freepascal.org> 42 * 43 * 44 * ATI Mach64 CT clock synthesis description. 45 * 46 * All clocks on the Mach64 can be calculated using the same principle: 47 * 48 * XTALIN * x * FB_DIV 49 * CLK = ---------------------- 50 * PLL_REF_DIV * POST_DIV 51 * 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 56 * values. 57 * x depends on the type of clock; usually it is 2, but for the MCLK it can also 58 * be set to 4. 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. 62 * 63 * The Mach64 has these clocks: 64 * 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 74 * 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 79 * in LCD monitor. 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 84 * 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) 89 */ 90 91 /* 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. 96 */ 97 98/* ------------------------------------------------------------------------- */ 99 100/* 101 * PLL programming (Mach64 CT family) 102 * 103 * 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. 107 * 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. 111 */ 112 113#define Maximum_DSP_PRECISION 7 114static u8 postdividers[] = {1,2,4,8,3}; 115 116static int aty_dsp_gt(const struct fb_info *info, u32 bpp, struct pll_ct *pll) 117{ 118 u32 dsp_off, dsp_on, dsp_xclks; 119 u32 multiplier, divider, ras_multiplier, ras_divider, tmp; 120 u8 vshift, xshift; 121 s8 dsp_precision; 122 123 multiplier = ((u32)pll->mclk_fb_div) * pll->vclk_post_div_real; 124 divider = ((u32)pll->vclk_fb_div) * pll->xclk_ref_div; 125 126 ras_multiplier = pll->xclkmaxrasdelay; 127 ras_divider = 1; 128 129 if (bpp>=8) 130 divider = divider * (bpp >> 2); 131 132 vshift = (6 - 2) - pll->xclk_post_div; /* FIFO is 64 bits wide in accelerator mode ... */ 133 134 if (bpp == 0) 135 vshift--; /* ... but only 32 bits in VGA mode. */ 136 137#ifdef CONFIG_FB_ATY_GENERIC_LCD 138 if (pll->xres != 0) { 139 struct atyfb_par *par = (struct atyfb_par *) info->par; 140 141 multiplier = multiplier * par->lcd_width; 142 divider = divider * pll->xres & ~7; 143 144 ras_multiplier = ras_multiplier * par->lcd_width; 145 ras_divider = ras_divider * pll->xres & ~7; 146 } 147#endif 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; 153 } 154 155 /* Determine DSP precision first */ 156 tmp = ((multiplier * pll->fifo_size) << vshift) / divider; 157 158 for (dsp_precision = -5; tmp; dsp_precision++) 159 tmp >>= 1; 160 if (dsp_precision < 0) 161 dsp_precision = 0; 162 else if (dsp_precision > Maximum_DSP_PRECISION) 163 dsp_precision = Maximum_DSP_PRECISION; 164 165 xshift = 6 - dsp_precision; 166 vshift += xshift; 167 168 /* Move on to dsp_off */ 169 dsp_off = ((multiplier * (pll->fifo_size - 1)) << vshift) / divider - 170 (1 << (vshift - xshift)); 171 172/* if (bpp == 0) 173 dsp_on = ((multiplier * 20 << vshift) + divider) / divider; 174 else */ 175 { 176 dsp_on = ((multiplier << vshift) + divider) / divider; 177 tmp = ((ras_multiplier << xshift) + ras_divider) / ras_divider; 178 if (dsp_on < tmp) 179 dsp_on = tmp; 180 dsp_on = dsp_on + (tmp * 2) + (pll->xclkpagefaultdelay << xshift); 181 } 182 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); 186 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); 190 } 191 192 /* Last but not least: dsp_xclks */ 193 dsp_xclks = ((multiplier << (vshift + 5)) + divider) / divider; 194 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; 198#ifdef DEBUG 199 printk("atyfb(%s): dsp_config 0x%08x, dsp_on_off 0x%08x\n", 200 __FUNCTION__, pll->dsp_config, pll->dsp_on_off); 201#endif 202 return 0; 203} 204 205static int aty_valid_pll_ct(const struct fb_info *info, u32 vclk_per, struct pll_ct *pll) 206{ 207 u32 q; 208 struct atyfb_par *par = (struct atyfb_par *) info->par; 209 int pllvclk; 210 211 q = par->ref_clk_per * pll->pll_ref_div * 4 / vclk_per; 212 if (q < 16*8 || q > 255*8) { 213 printk(KERN_CRIT "atyfb: vclk out of range\n"); 214 return -EINVAL; 215 } else { 216 pll->vclk_post_div = (q < 128*8); 217 pll->vclk_post_div += (q < 64*8); 218 pll->vclk_post_div += (q < 32*8); 219 } 220 pll->vclk_post_div_real = postdividers[pll->vclk_post_div]; 221 // pll->vclk_post_div <<= 6; 222 pll->vclk_fb_div = q * pll->vclk_post_div_real / 8; 223 pllvclk = (1000000 * 2 * pll->vclk_fb_div) / 224 (par->ref_clk_per * pll->pll_ref_div); 225#ifdef DEBUG 226 printk("atyfb(%s): pllvclk=%d MHz, vclk=%d MHz\n", 227 __FUNCTION__, pllvclk, pllvclk / pll->vclk_post_div_real); 228#endif 229 pll->pll_vclk_cntl = 0x03; /* VCLK = PLL_VCLK/VCLKx_POST */ 230 231 /* Set ECP (scaler/overlay clock) divider */ 232 if (par->pll_limits.ecp_max) { 233 int ecp = pllvclk / pll->vclk_post_div_real; 234 int ecp_div = 0; 235 236 while (ecp > par->pll_limits.ecp_max && ecp_div < 2) { 237 ecp >>= 1; 238 ecp_div++; 239 } 240 pll->pll_vclk_cntl |= ecp_div << 4; 241 } 242 243 return 0; 244} 245 246static int aty_var_to_pll_ct(const struct fb_info *info, u32 vclk_per, u32 bpp, union aty_pll *pll) 247{ 248 struct atyfb_par *par = (struct atyfb_par *) info->par; 249 int err; 250 251 if ((err = aty_valid_pll_ct(info, vclk_per, &pll->ct))) 252 return err; 253 if (M64_HAS(GTB_DSP) && (err = aty_dsp_gt(info, bpp, &pll->ct))) 254 return err; 255 /*aty_calc_pll_ct(info, &pll->ct);*/ 256 return 0; 257} 258 259static u32 aty_pll_to_var_ct(const struct fb_info *info, const union aty_pll *pll) 260{ 261 struct atyfb_par *par = (struct atyfb_par *) info->par; 262 u32 ret; 263 ret = par->ref_clk_per * pll->ct.pll_ref_div * pll->ct.vclk_post_div_real / pll->ct.vclk_fb_div / 2; 264#ifdef CONFIG_FB_ATY_GENERIC_LCD 265 if(pll->ct.xres > 0) { 266 ret *= par->lcd_width; 267 ret /= pll->ct.xres; 268 } 269#endif 270#ifdef DEBUG 271 printk("atyfb(%s): calculated 0x%08X(%i)\n", __FUNCTION__, ret, ret); 272#endif 273 return ret; 274} 275 276void aty_set_pll_ct(const struct fb_info *info, const union aty_pll *pll) 277{ 278 struct atyfb_par *par = (struct atyfb_par *) info->par; 279 u32 crtc_gen_cntl, lcd_gen_cntrl; 280 u8 tmp, tmp2; 281 282 lcd_gen_cntrl = 0; 283#ifdef DEBUG 284 printk("atyfb(%s): about to program:\n" 285 "pll_ext_cntl=0x%02x pll_gen_cntl=0x%02x pll_vclk_cntl=0x%02x\n", 286 __FUNCTION__, 287 pll->ct.pll_ext_cntl, pll->ct.pll_gen_cntl, pll->ct.pll_vclk_cntl); 288 289 printk("atyfb(%s): setting clock %lu for FeedBackDivider %i, ReferenceDivider %i, PostDivider %i(%i)\n", 290 __FUNCTION__, 291 par->clk_wr_offset, pll->ct.vclk_fb_div, 292 pll->ct.pll_ref_div, pll->ct.vclk_post_div, pll->ct.vclk_post_div_real); 293#endif 294#ifdef CONFIG_FB_ATY_GENERIC_LCD 295 if (par->lcd_table != 0) { 296 /* turn off LCD */ 297 lcd_gen_cntrl = aty_ld_lcd(LCD_GEN_CNTL, par); 298 aty_st_lcd(LCD_GEN_CNTL, lcd_gen_cntrl & ~LCD_ON, par); 299 } 300#endif 301 aty_st_8(CLOCK_CNTL, par->clk_wr_offset | CLOCK_STROBE, par); 302 303 /* Temporarily switch to accelerator mode */ 304 crtc_gen_cntl = aty_ld_le32(CRTC_GEN_CNTL, par); 305 if (!(crtc_gen_cntl & CRTC_EXT_DISP_EN)) 306 aty_st_le32(CRTC_GEN_CNTL, crtc_gen_cntl | CRTC_EXT_DISP_EN, par); 307 308 /* Reset VCLK generator */ 309 aty_st_pll_ct(PLL_VCLK_CNTL, pll->ct.pll_vclk_cntl, par); 310 311 /* Set post-divider */ 312 tmp2 = par->clk_wr_offset << 1; 313 tmp = aty_ld_pll_ct(VCLK_POST_DIV, par); 314 tmp &= ~(0x03U << tmp2); 315 tmp |= ((pll->ct.vclk_post_div & 0x03U) << tmp2); 316 aty_st_pll_ct(VCLK_POST_DIV, tmp, par); 317 318 /* Set extended post-divider */ 319 tmp = aty_ld_pll_ct(PLL_EXT_CNTL, par); 320 tmp &= ~(0x10U << par->clk_wr_offset); 321 tmp &= 0xF0U; 322 tmp |= pll->ct.pll_ext_cntl; 323 aty_st_pll_ct(PLL_EXT_CNTL, tmp, par); 324 325 /* Set feedback divider */ 326 tmp = VCLK0_FB_DIV + par->clk_wr_offset; 327 aty_st_pll_ct(tmp, (pll->ct.vclk_fb_div & 0xFFU), par); 328 329 aty_st_pll_ct(PLL_GEN_CNTL, (pll->ct.pll_gen_cntl & (~(PLL_OVERRIDE | PLL_MCLK_RST))) | OSC_EN, par); 330 331 /* End VCLK generator reset */ 332 aty_st_pll_ct(PLL_VCLK_CNTL, pll->ct.pll_vclk_cntl & ~(PLL_VCLK_RST), par); 333 mdelay(5); 334 335 aty_st_pll_ct(PLL_GEN_CNTL, pll->ct.pll_gen_cntl, par); 336 aty_st_pll_ct(PLL_VCLK_CNTL, pll->ct.pll_vclk_cntl, par); 337 mdelay(1); 338 339 /* Restore mode register */ 340 if (!(crtc_gen_cntl & CRTC_EXT_DISP_EN)) 341 aty_st_le32(CRTC_GEN_CNTL, crtc_gen_cntl, par); 342 343 if (M64_HAS(GTB_DSP)) { 344 u8 dll_cntl; 345 346 if (M64_HAS(XL_DLL)) 347 dll_cntl = 0x80; 348 else if (par->ram_type >= SDRAM) 349 dll_cntl = 0xa6; 350 else 351 dll_cntl = 0xa0; 352 aty_st_pll_ct(DLL_CNTL, dll_cntl, par); 353 aty_st_pll_ct(VFC_CNTL, 0x1b, par); 354 aty_st_le32(DSP_CONFIG, pll->ct.dsp_config, par); 355 aty_st_le32(DSP_ON_OFF, pll->ct.dsp_on_off, par); 356 357 mdelay(10); 358 aty_st_pll_ct(DLL_CNTL, dll_cntl, par); 359 mdelay(10); 360 aty_st_pll_ct(DLL_CNTL, dll_cntl | 0x40, par); 361 mdelay(10); 362 aty_st_pll_ct(DLL_CNTL, dll_cntl & ~0x40, par); 363 } 364#ifdef CONFIG_FB_ATY_GENERIC_LCD 365 if (par->lcd_table != 0) { 366 /* restore LCD */ 367 aty_st_lcd(LCD_GEN_CNTL, lcd_gen_cntrl, par); 368 } 369#endif 370} 371 372static void __devinit aty_get_pll_ct(const struct fb_info *info, 373 union aty_pll *pll) 374{ 375 struct atyfb_par *par = (struct atyfb_par *) info->par; 376 u8 tmp, clock; 377 378 clock = aty_ld_8(CLOCK_CNTL, par) & 0x03U; 379 tmp = clock << 1; 380 pll->ct.vclk_post_div = (aty_ld_pll_ct(VCLK_POST_DIV, par) >> tmp) & 0x03U; 381 382 pll->ct.pll_ext_cntl = aty_ld_pll_ct(PLL_EXT_CNTL, par) & 0x0FU; 383 pll->ct.vclk_fb_div = aty_ld_pll_ct(VCLK0_FB_DIV + clock, par) & 0xFFU; 384 pll->ct.pll_ref_div = aty_ld_pll_ct(PLL_REF_DIV, par); 385 pll->ct.mclk_fb_div = aty_ld_pll_ct(MCLK_FB_DIV, par); 386 387 pll->ct.pll_gen_cntl = aty_ld_pll_ct(PLL_GEN_CNTL, par); 388 pll->ct.pll_vclk_cntl = aty_ld_pll_ct(PLL_VCLK_CNTL, par); 389 390 if (M64_HAS(GTB_DSP)) { 391 pll->ct.dsp_config = aty_ld_le32(DSP_CONFIG, par); 392 pll->ct.dsp_on_off = aty_ld_le32(DSP_ON_OFF, par); 393 } 394} 395 396static int __devinit aty_init_pll_ct(const struct fb_info *info, 397 union aty_pll *pll) 398{ 399 struct atyfb_par *par = (struct atyfb_par *) info->par; 400 u8 mpost_div, xpost_div, sclk_post_div_real; 401 u32 q, memcntl, trp; 402 u32 dsp_config, dsp_on_off, vga_dsp_config, vga_dsp_on_off; 403#ifdef DEBUG 404 int pllmclk, pllsclk; 405#endif 406 pll->ct.pll_ext_cntl = aty_ld_pll_ct(PLL_EXT_CNTL, par); 407 pll->ct.xclk_post_div = pll->ct.pll_ext_cntl & 0x07; 408 pll->ct.xclk_ref_div = 1; 409 switch (pll->ct.xclk_post_div) { 410 case 0: case 1: case 2: case 3: 411 break; 412 413 case 4: 414 pll->ct.xclk_ref_div = 3; 415 pll->ct.xclk_post_div = 0; 416 break; 417 418 default: 419 printk(KERN_CRIT "atyfb: Unsupported xclk source: %d.\n", pll->ct.xclk_post_div); 420 return -EINVAL; 421 } 422 pll->ct.mclk_fb_mult = 2; 423 if(pll->ct.pll_ext_cntl & PLL_MFB_TIMES_4_2B) { 424 pll->ct.mclk_fb_mult = 4; 425 pll->ct.xclk_post_div -= 1; 426 } 427 428#ifdef DEBUG 429 printk("atyfb(%s): mclk_fb_mult=%d, xclk_post_div=%d\n", 430 __FUNCTION__, pll->ct.mclk_fb_mult, pll->ct.xclk_post_div); 431#endif 432 433 memcntl = aty_ld_le32(MEM_CNTL, par); 434 trp = (memcntl & 0x300) >> 8; 435 436 pll->ct.xclkpagefaultdelay = ((memcntl & 0xc00) >> 10) + ((memcntl & 0x1000) >> 12) + trp + 2; 437 pll->ct.xclkmaxrasdelay = ((memcntl & 0x70000) >> 16) + trp + 2; 438 439 if (M64_HAS(FIFO_32)) { 440 pll->ct.fifo_size = 32; 441 } else { 442 pll->ct.fifo_size = 24; 443 pll->ct.xclkpagefaultdelay += 2; 444 pll->ct.xclkmaxrasdelay += 3; 445 } 446 447 switch (par->ram_type) { 448 case DRAM: 449 if (info->fix.smem_len<=ONE_MB) { 450 pll->ct.dsp_loop_latency = 10; 451 } else { 452 pll->ct.dsp_loop_latency = 8; 453 pll->ct.xclkpagefaultdelay += 2; 454 } 455 break; 456 case EDO: 457 case PSEUDO_EDO: 458 if (info->fix.smem_len<=ONE_MB) { 459 pll->ct.dsp_loop_latency = 9; 460 } else { 461 pll->ct.dsp_loop_latency = 8; 462 pll->ct.xclkpagefaultdelay += 1; 463 } 464 break; 465 case SDRAM: 466 if (info->fix.smem_len<=ONE_MB) { 467 pll->ct.dsp_loop_latency = 11; 468 } else { 469 pll->ct.dsp_loop_latency = 10; 470 pll->ct.xclkpagefaultdelay += 1; 471 } 472 break; 473 case SGRAM: 474 pll->ct.dsp_loop_latency = 8; 475 pll->ct.xclkpagefaultdelay += 3; 476 break; 477 default: 478 pll->ct.dsp_loop_latency = 11; 479 pll->ct.xclkpagefaultdelay += 3; 480 break; 481 } 482 483 if (pll->ct.xclkmaxrasdelay <= pll->ct.xclkpagefaultdelay) 484 pll->ct.xclkmaxrasdelay = pll->ct.xclkpagefaultdelay + 1; 485 486 /* Allow BIOS to override */ 487 dsp_config = aty_ld_le32(DSP_CONFIG, par); 488 dsp_on_off = aty_ld_le32(DSP_ON_OFF, par); 489 vga_dsp_config = aty_ld_le32(VGA_DSP_CONFIG, par); 490 vga_dsp_on_off = aty_ld_le32(VGA_DSP_ON_OFF, par); 491 492 if (dsp_config) 493 pll->ct.dsp_loop_latency = (dsp_config & DSP_LOOP_LATENCY) >> 16; 494 /* Exit if the user does not want us to tamper with the clock 495 rates of her chip. */ 496 if (par->mclk_per == 0) { 497 u8 mclk_fb_div, pll_ext_cntl; 498 pll->ct.pll_ref_div = aty_ld_pll_ct(PLL_REF_DIV, par); 499 pll_ext_cntl = aty_ld_pll_ct(PLL_EXT_CNTL, par); 500 pll->ct.xclk_post_div_real = postdividers[pll_ext_cntl & 0x07]; 501 mclk_fb_div = aty_ld_pll_ct(MCLK_FB_DIV, par); 502 if (pll_ext_cntl & PLL_MFB_TIMES_4_2B) 503 mclk_fb_div <<= 1; 504 pll->ct.mclk_fb_div = mclk_fb_div; 505 return 0; 506 } 507 508 pll->ct.pll_ref_div = par->pll_per * 2 * 255 / par->ref_clk_per; 509 510 q = par->ref_clk_per * pll->ct.pll_ref_div * 8 / 511 (pll->ct.mclk_fb_mult * par->xclk_per); 512 513 if (q < 16*8 || q > 255*8) { 514 printk(KERN_CRIT "atxfb: xclk out of range\n"); 515 return -EINVAL; 516 } else { 517 xpost_div = (q < 128*8); 518 xpost_div += (q < 64*8); 519 xpost_div += (q < 32*8); 520 } 521 pll->ct.xclk_post_div_real = postdividers[xpost_div]; 522 pll->ct.mclk_fb_div = q * pll->ct.xclk_post_div_real / 8; 523 524#ifdef DEBUG 525 pllmclk = (1000000 * pll->ct.mclk_fb_mult * pll->ct.mclk_fb_div) / 526 (par->ref_clk_per * pll->ct.pll_ref_div); 527 printk("atyfb(%s): pllmclk=%d MHz, xclk=%d MHz\n", 528 __FUNCTION__, pllmclk, pllmclk / pll->ct.xclk_post_div_real); 529#endif 530 531 if (M64_HAS(SDRAM_MAGIC_PLL) && (par->ram_type >= SDRAM)) 532 pll->ct.pll_gen_cntl = OSC_EN; 533 else 534 pll->ct.pll_gen_cntl = OSC_EN | DLL_PWDN /* | FORCE_DCLK_TRI_STATE */; 535 536 if (M64_HAS(MAGIC_POSTDIV)) 537 pll->ct.pll_ext_cntl = 0; 538 else 539 pll->ct.pll_ext_cntl = xpost_div; 540 541 if (pll->ct.mclk_fb_mult == 4) 542 pll->ct.pll_ext_cntl |= PLL_MFB_TIMES_4_2B; 543 544 if (par->mclk_per == par->xclk_per) { 545 pll->ct.pll_gen_cntl |= (xpost_div << 4); /* mclk == xclk */ 546 } else { 547 /* 548 * The chip clock is not equal to the memory clock. 549 * Therefore we will use sclk to clock the chip. 550 */ 551 pll->ct.pll_gen_cntl |= (6 << 4); /* mclk == sclk */ 552 553 q = par->ref_clk_per * pll->ct.pll_ref_div * 4 / par->mclk_per; 554 if (q < 16*8 || q > 255*8) { 555 printk(KERN_CRIT "atyfb: mclk out of range\n"); 556 return -EINVAL; 557 } else { 558 mpost_div = (q < 128*8); 559 mpost_div += (q < 64*8); 560 mpost_div += (q < 32*8); 561 } 562 sclk_post_div_real = postdividers[mpost_div]; 563 pll->ct.sclk_fb_div = q * sclk_post_div_real / 8; 564 pll->ct.spll_cntl2 = mpost_div << 4; 565#ifdef DEBUG 566 pllsclk = (1000000 * 2 * pll->ct.sclk_fb_div) / 567 (par->ref_clk_per * pll->ct.pll_ref_div); 568 printk("atyfb(%s): use sclk, pllsclk=%d MHz, sclk=mclk=%d MHz\n", 569 __FUNCTION__, pllsclk, pllsclk / sclk_post_div_real); 570#endif 571 } 572 573 /* Disable the extra precision pixel clock controls since we do not use them. */ 574 pll->ct.ext_vpll_cntl = aty_ld_pll_ct(EXT_VPLL_CNTL, par); 575 pll->ct.ext_vpll_cntl &= ~(EXT_VPLL_EN | EXT_VPLL_VGA_EN | EXT_VPLL_INSYNC); 576 577 return 0; 578} 579 580static void aty_resume_pll_ct(const struct fb_info *info, 581 union aty_pll *pll) 582{ 583 struct atyfb_par *par = info->par; 584 585 if (par->mclk_per != par->xclk_per) { 586 /* 587 * This disables the sclk, crashes the computer as reported: 588 * aty_st_pll_ct(SPLL_CNTL2, 3, info); 589 * 590 * So it seems the sclk must be enabled before it is used; 591 * so PLL_GEN_CNTL must be programmed *after* the sclk. 592 */ 593 aty_st_pll_ct(SCLK_FB_DIV, pll->ct.sclk_fb_div, par); 594 aty_st_pll_ct(SPLL_CNTL2, pll->ct.spll_cntl2, par); 595 /* 596 * SCLK has been started. Wait for the PLL to lock. 5 ms 597 * should be enough according to mach64 programmer's guide. 598 */ 599 mdelay(5); 600 } 601 602 aty_st_pll_ct(PLL_REF_DIV, pll->ct.pll_ref_div, par); 603 aty_st_pll_ct(PLL_GEN_CNTL, pll->ct.pll_gen_cntl, par); 604 aty_st_pll_ct(MCLK_FB_DIV, pll->ct.mclk_fb_div, par); 605 aty_st_pll_ct(PLL_EXT_CNTL, pll->ct.pll_ext_cntl, par); 606 aty_st_pll_ct(EXT_VPLL_CNTL, pll->ct.ext_vpll_cntl, par); 607} 608 609static int dummy(void) 610{ 611 return 0; 612} 613 614const struct aty_dac_ops aty_dac_ct = { 615 .set_dac = (void *) dummy, 616}; 617 618const struct aty_pll_ops aty_pll_ct = { 619 .var_to_pll = aty_var_to_pll_ct, 620 .pll_to_var = aty_pll_to_var_ct, 621 .set_pll = aty_set_pll_ct, 622 .get_pll = aty_get_pll_ct, 623 .init_pll = aty_init_pll_ct, 624 .resume_pll = aty_resume_pll_ct, 625}; 626