0001
0002
0003
0004
0005
0006
0007 #include <linux/fb.h>
0008 #include <linux/delay.h>
0009 #include <asm/io.h>
0010 #include <video/mach64.h>
0011 #include "atyfb.h"
0012 #ifdef CONFIG_PPC
0013 #include <asm/machdep.h>
0014 #endif
0015
0016 #undef DEBUG
0017
0018 static int aty_valid_pll_ct (const struct fb_info *info, u32 vclk_per, struct pll_ct *pll);
0019 static int aty_dsp_gt (const struct fb_info *info, u32 bpp, struct pll_ct *pll);
0020 static int aty_var_to_pll_ct(const struct fb_info *info, u32 vclk_per, u32 bpp, union aty_pll *pll);
0021 static u32 aty_pll_to_var_ct(const struct fb_info *info, const union aty_pll *pll);
0022
0023 u8 aty_ld_pll_ct(int offset, const struct atyfb_par *par)
0024 {
0025
0026
0027 aty_st_8(CLOCK_CNTL_ADDR, (offset << 2) & PLL_ADDR, par);
0028
0029 return aty_ld_8(CLOCK_CNTL_DATA, par);
0030 }
0031
0032 static void aty_st_pll_ct(int offset, u8 val, const struct atyfb_par *par)
0033 {
0034
0035 aty_st_8(CLOCK_CNTL_ADDR, ((offset << 2) & PLL_ADDR) | PLL_WR_EN, par);
0036
0037 aty_st_8(CLOCK_CNTL_DATA, val & PLL_DATA, par);
0038 aty_st_8(CLOCK_CNTL_ADDR, ((offset << 2) & PLL_ADDR) & ~PLL_WR_EN, par);
0039 }
0040
0041
0042
0043
0044
0045
0046
0047
0048
0049
0050
0051
0052
0053
0054
0055
0056
0057
0058
0059
0060
0061
0062
0063
0064
0065
0066
0067
0068
0069
0070
0071
0072
0073
0074
0075
0076
0077
0078
0079
0080
0081
0082
0083
0084
0085
0086
0087
0088
0089
0090
0091
0092
0093
0094
0095
0096
0097
0098
0099
0100
0101
0102
0103
0104
0105
0106
0107
0108
0109
0110
0111
0112
0113
0114
0115 #define Maximum_DSP_PRECISION 7
0116 const u8 aty_postdividers[8] = {1,2,4,8,3,5,6,12};
0117
0118 static int aty_dsp_gt(const struct fb_info *info, u32 bpp, struct pll_ct *pll)
0119 {
0120 u32 dsp_off, dsp_on, dsp_xclks;
0121 u32 multiplier, divider, ras_multiplier, ras_divider, tmp;
0122 u8 vshift, xshift;
0123 s8 dsp_precision;
0124
0125 multiplier = ((u32)pll->mclk_fb_div) * pll->vclk_post_div_real;
0126 divider = ((u32)pll->vclk_fb_div) * pll->xclk_ref_div;
0127
0128 ras_multiplier = pll->xclkmaxrasdelay;
0129 ras_divider = 1;
0130
0131 if (bpp>=8)
0132 divider = divider * (bpp >> 2);
0133
0134 vshift = (6 - 2) - pll->xclk_post_div;
0135
0136 if (bpp == 0)
0137 vshift--;
0138
0139 #ifdef CONFIG_FB_ATY_GENERIC_LCD
0140 if (pll->xres != 0) {
0141 struct atyfb_par *par = (struct atyfb_par *) info->par;
0142
0143 multiplier = multiplier * par->lcd_width;
0144 divider = divider * pll->xres & ~7;
0145
0146 ras_multiplier = ras_multiplier * par->lcd_width;
0147 ras_divider = ras_divider * pll->xres & ~7;
0148 }
0149 #endif
0150
0151
0152 while (((multiplier | divider) & 1) == 0) {
0153 multiplier = multiplier >> 1;
0154 divider = divider >> 1;
0155 }
0156
0157
0158 tmp = ((multiplier * pll->fifo_size) << vshift) / divider;
0159
0160 for (dsp_precision = -5; tmp; dsp_precision++)
0161 tmp >>= 1;
0162 if (dsp_precision < 0)
0163 dsp_precision = 0;
0164 else if (dsp_precision > Maximum_DSP_PRECISION)
0165 dsp_precision = Maximum_DSP_PRECISION;
0166
0167 xshift = 6 - dsp_precision;
0168 vshift += xshift;
0169
0170
0171 dsp_off = ((multiplier * (pll->fifo_size - 1)) << vshift) / divider -
0172 (1 << (vshift - xshift));
0173
0174
0175
0176
0177 {
0178 dsp_on = ((multiplier << vshift) + divider) / divider;
0179 tmp = ((ras_multiplier << xshift) + ras_divider) / ras_divider;
0180 if (dsp_on < tmp)
0181 dsp_on = tmp;
0182 dsp_on = dsp_on + (tmp * 2) + (pll->xclkpagefaultdelay << xshift);
0183 }
0184
0185
0186 tmp = ((1 << (Maximum_DSP_PRECISION - dsp_precision)) - 1) >> 1;
0187 dsp_on = ((dsp_on + tmp) / (tmp + 1)) * (tmp + 1);
0188
0189 if (dsp_on >= ((dsp_off / (tmp + 1)) * (tmp + 1))) {
0190 dsp_on = dsp_off - (multiplier << vshift) / divider;
0191 dsp_on = (dsp_on / (tmp + 1)) * (tmp + 1);
0192 }
0193
0194
0195 dsp_xclks = ((multiplier << (vshift + 5)) + divider) / divider;
0196
0197
0198 pll->dsp_on_off = (dsp_on << 16) + dsp_off;
0199 pll->dsp_config = (dsp_precision << 20) | (pll->dsp_loop_latency << 16) | dsp_xclks;
0200 #ifdef DEBUG
0201 printk("atyfb(%s): dsp_config 0x%08x, dsp_on_off 0x%08x\n",
0202 __func__, pll->dsp_config, pll->dsp_on_off);
0203 #endif
0204 return 0;
0205 }
0206
0207 static int aty_valid_pll_ct(const struct fb_info *info, u32 vclk_per, struct pll_ct *pll)
0208 {
0209 u32 q;
0210 struct atyfb_par *par = (struct atyfb_par *) info->par;
0211 int pllvclk;
0212
0213
0214 q = par->ref_clk_per * pll->pll_ref_div * 4 / vclk_per;
0215 if (q < 16*8 || q > 255*8) {
0216 printk(KERN_CRIT "atyfb: vclk out of range\n");
0217 return -EINVAL;
0218 } else {
0219 pll->vclk_post_div = (q < 128*8);
0220 pll->vclk_post_div += (q < 64*8);
0221 pll->vclk_post_div += (q < 32*8);
0222 }
0223 pll->vclk_post_div_real = aty_postdividers[pll->vclk_post_div];
0224
0225 pll->vclk_fb_div = q * pll->vclk_post_div_real / 8;
0226 pllvclk = (1000000 * 2 * pll->vclk_fb_div) /
0227 (par->ref_clk_per * pll->pll_ref_div);
0228 #ifdef DEBUG
0229 printk("atyfb(%s): pllvclk=%d MHz, vclk=%d MHz\n",
0230 __func__, pllvclk, pllvclk / pll->vclk_post_div_real);
0231 #endif
0232 pll->pll_vclk_cntl = 0x03;
0233
0234
0235 if (par->pll_limits.ecp_max) {
0236 int ecp = pllvclk / pll->vclk_post_div_real;
0237 int ecp_div = 0;
0238
0239 while (ecp > par->pll_limits.ecp_max && ecp_div < 2) {
0240 ecp >>= 1;
0241 ecp_div++;
0242 }
0243 pll->pll_vclk_cntl |= ecp_div << 4;
0244 }
0245
0246 return 0;
0247 }
0248
0249 static int aty_var_to_pll_ct(const struct fb_info *info, u32 vclk_per, u32 bpp, union aty_pll *pll)
0250 {
0251 struct atyfb_par *par = (struct atyfb_par *) info->par;
0252 int err;
0253
0254 if ((err = aty_valid_pll_ct(info, vclk_per, &pll->ct)))
0255 return err;
0256 if (M64_HAS(GTB_DSP) && (err = aty_dsp_gt(info, bpp, &pll->ct)))
0257 return err;
0258
0259 return 0;
0260 }
0261
0262 static u32 aty_pll_to_var_ct(const struct fb_info *info, const union aty_pll *pll)
0263 {
0264 struct atyfb_par *par = (struct atyfb_par *) info->par;
0265 u32 ret;
0266 ret = par->ref_clk_per * pll->ct.pll_ref_div * pll->ct.vclk_post_div_real / pll->ct.vclk_fb_div / 2;
0267 #ifdef CONFIG_FB_ATY_GENERIC_LCD
0268 if(pll->ct.xres > 0) {
0269 ret *= par->lcd_width;
0270 ret /= pll->ct.xres;
0271 }
0272 #endif
0273 #ifdef DEBUG
0274 printk("atyfb(%s): calculated 0x%08X(%i)\n", __func__, ret, ret);
0275 #endif
0276 return ret;
0277 }
0278
0279 void aty_set_pll_ct(const struct fb_info *info, const union aty_pll *pll)
0280 {
0281 struct atyfb_par *par = (struct atyfb_par *) info->par;
0282 u32 crtc_gen_cntl;
0283 u8 tmp, tmp2;
0284
0285 #ifdef CONFIG_FB_ATY_GENERIC_LCD
0286 u32 lcd_gen_cntrl = 0;
0287 #endif
0288
0289 #ifdef DEBUG
0290 printk("atyfb(%s): about to program:\n"
0291 "pll_ext_cntl=0x%02x pll_gen_cntl=0x%02x pll_vclk_cntl=0x%02x\n",
0292 __func__,
0293 pll->ct.pll_ext_cntl, pll->ct.pll_gen_cntl, pll->ct.pll_vclk_cntl);
0294
0295 printk("atyfb(%s): setting clock %lu for FeedBackDivider %i, ReferenceDivider %i, PostDivider %i(%i)\n",
0296 __func__,
0297 par->clk_wr_offset, pll->ct.vclk_fb_div,
0298 pll->ct.pll_ref_div, pll->ct.vclk_post_div, pll->ct.vclk_post_div_real);
0299 #endif
0300 #ifdef CONFIG_FB_ATY_GENERIC_LCD
0301 if (par->lcd_table != 0) {
0302
0303 lcd_gen_cntrl = aty_ld_lcd(LCD_GEN_CNTL, par);
0304 aty_st_lcd(LCD_GEN_CNTL, lcd_gen_cntrl & ~LCD_ON, par);
0305 }
0306 #endif
0307 aty_st_8(CLOCK_CNTL, par->clk_wr_offset | CLOCK_STROBE, par);
0308
0309
0310 crtc_gen_cntl = aty_ld_le32(CRTC_GEN_CNTL, par);
0311 if (!(crtc_gen_cntl & CRTC_EXT_DISP_EN))
0312 aty_st_le32(CRTC_GEN_CNTL, crtc_gen_cntl | CRTC_EXT_DISP_EN, par);
0313
0314
0315 aty_st_pll_ct(PLL_VCLK_CNTL, pll->ct.pll_vclk_cntl, par);
0316
0317
0318 tmp2 = par->clk_wr_offset << 1;
0319 tmp = aty_ld_pll_ct(VCLK_POST_DIV, par);
0320 tmp &= ~(0x03U << tmp2);
0321 tmp |= ((pll->ct.vclk_post_div & 0x03U) << tmp2);
0322 aty_st_pll_ct(VCLK_POST_DIV, tmp, par);
0323
0324
0325 tmp = aty_ld_pll_ct(PLL_EXT_CNTL, par);
0326 tmp &= ~(0x10U << par->clk_wr_offset);
0327 tmp &= 0xF0U;
0328 tmp |= pll->ct.pll_ext_cntl;
0329 aty_st_pll_ct(PLL_EXT_CNTL, tmp, par);
0330
0331
0332 tmp = VCLK0_FB_DIV + par->clk_wr_offset;
0333 aty_st_pll_ct(tmp, (pll->ct.vclk_fb_div & 0xFFU), par);
0334
0335 aty_st_pll_ct(PLL_GEN_CNTL, (pll->ct.pll_gen_cntl & (~(PLL_OVERRIDE | PLL_MCLK_RST))) | OSC_EN, par);
0336
0337
0338 aty_st_pll_ct(PLL_VCLK_CNTL, pll->ct.pll_vclk_cntl & ~(PLL_VCLK_RST), par);
0339 mdelay(5);
0340
0341 aty_st_pll_ct(PLL_GEN_CNTL, pll->ct.pll_gen_cntl, par);
0342 aty_st_pll_ct(PLL_VCLK_CNTL, pll->ct.pll_vclk_cntl, par);
0343 mdelay(1);
0344
0345
0346 if (!(crtc_gen_cntl & CRTC_EXT_DISP_EN))
0347 aty_st_le32(CRTC_GEN_CNTL, crtc_gen_cntl, par);
0348
0349 if (M64_HAS(GTB_DSP)) {
0350 u8 dll_cntl;
0351
0352 if (M64_HAS(XL_DLL))
0353 dll_cntl = 0x80;
0354 else if (par->ram_type >= SDRAM)
0355 dll_cntl = 0xa6;
0356 else
0357 dll_cntl = 0xa0;
0358 aty_st_pll_ct(DLL_CNTL, dll_cntl, par);
0359 aty_st_pll_ct(VFC_CNTL, 0x1b, par);
0360 aty_st_le32(DSP_CONFIG, pll->ct.dsp_config, par);
0361 aty_st_le32(DSP_ON_OFF, pll->ct.dsp_on_off, par);
0362
0363 mdelay(10);
0364 aty_st_pll_ct(DLL_CNTL, dll_cntl, par);
0365 mdelay(10);
0366 aty_st_pll_ct(DLL_CNTL, dll_cntl | 0x40, par);
0367 mdelay(10);
0368 aty_st_pll_ct(DLL_CNTL, dll_cntl & ~0x40, par);
0369 }
0370 #ifdef CONFIG_FB_ATY_GENERIC_LCD
0371 if (par->lcd_table != 0) {
0372
0373 aty_st_lcd(LCD_GEN_CNTL, lcd_gen_cntrl, par);
0374 }
0375 #endif
0376 }
0377
0378 static void aty_get_pll_ct(const struct fb_info *info, union aty_pll *pll)
0379 {
0380 struct atyfb_par *par = (struct atyfb_par *) info->par;
0381 u8 tmp, clock;
0382
0383 clock = aty_ld_8(CLOCK_CNTL, par) & 0x03U;
0384 tmp = clock << 1;
0385 pll->ct.vclk_post_div = (aty_ld_pll_ct(VCLK_POST_DIV, par) >> tmp) & 0x03U;
0386
0387 pll->ct.pll_ext_cntl = aty_ld_pll_ct(PLL_EXT_CNTL, par) & 0x0FU;
0388 pll->ct.vclk_fb_div = aty_ld_pll_ct(VCLK0_FB_DIV + clock, par) & 0xFFU;
0389 pll->ct.pll_ref_div = aty_ld_pll_ct(PLL_REF_DIV, par);
0390 pll->ct.mclk_fb_div = aty_ld_pll_ct(MCLK_FB_DIV, par);
0391
0392 pll->ct.pll_gen_cntl = aty_ld_pll_ct(PLL_GEN_CNTL, par);
0393 pll->ct.pll_vclk_cntl = aty_ld_pll_ct(PLL_VCLK_CNTL, par);
0394
0395 if (M64_HAS(GTB_DSP)) {
0396 pll->ct.dsp_config = aty_ld_le32(DSP_CONFIG, par);
0397 pll->ct.dsp_on_off = aty_ld_le32(DSP_ON_OFF, par);
0398 }
0399 }
0400
0401 static int aty_init_pll_ct(const struct fb_info *info, union aty_pll *pll)
0402 {
0403 struct atyfb_par *par = (struct atyfb_par *) info->par;
0404 u8 mpost_div, xpost_div, sclk_post_div_real;
0405 u32 q, memcntl, trp;
0406 u32 dsp_config;
0407 #ifdef DEBUG
0408 int pllmclk, pllsclk;
0409 #endif
0410 pll->ct.pll_ext_cntl = aty_ld_pll_ct(PLL_EXT_CNTL, par);
0411 pll->ct.xclk_post_div = pll->ct.pll_ext_cntl & 0x07;
0412 pll->ct.xclk_ref_div = 1;
0413 switch (pll->ct.xclk_post_div) {
0414 case 0: case 1: case 2: case 3:
0415 break;
0416
0417 case 4:
0418 pll->ct.xclk_ref_div = 3;
0419 pll->ct.xclk_post_div = 0;
0420 break;
0421
0422 default:
0423 printk(KERN_CRIT "atyfb: Unsupported xclk source: %d.\n", pll->ct.xclk_post_div);
0424 return -EINVAL;
0425 }
0426 pll->ct.mclk_fb_mult = 2;
0427 if(pll->ct.pll_ext_cntl & PLL_MFB_TIMES_4_2B) {
0428 pll->ct.mclk_fb_mult = 4;
0429 pll->ct.xclk_post_div -= 1;
0430 }
0431
0432 #ifdef DEBUG
0433 printk("atyfb(%s): mclk_fb_mult=%d, xclk_post_div=%d\n",
0434 __func__, pll->ct.mclk_fb_mult, pll->ct.xclk_post_div);
0435 #endif
0436
0437 memcntl = aty_ld_le32(MEM_CNTL, par);
0438 trp = (memcntl & 0x300) >> 8;
0439
0440 pll->ct.xclkpagefaultdelay = ((memcntl & 0xc00) >> 10) + ((memcntl & 0x1000) >> 12) + trp + 2;
0441 pll->ct.xclkmaxrasdelay = ((memcntl & 0x70000) >> 16) + trp + 2;
0442
0443 if (M64_HAS(FIFO_32)) {
0444 pll->ct.fifo_size = 32;
0445 } else {
0446 pll->ct.fifo_size = 24;
0447 pll->ct.xclkpagefaultdelay += 2;
0448 pll->ct.xclkmaxrasdelay += 3;
0449 }
0450
0451 switch (par->ram_type) {
0452 case DRAM:
0453 if (info->fix.smem_len<=ONE_MB) {
0454 pll->ct.dsp_loop_latency = 10;
0455 } else {
0456 pll->ct.dsp_loop_latency = 8;
0457 pll->ct.xclkpagefaultdelay += 2;
0458 }
0459 break;
0460 case EDO:
0461 case PSEUDO_EDO:
0462 if (info->fix.smem_len<=ONE_MB) {
0463 pll->ct.dsp_loop_latency = 9;
0464 } else {
0465 pll->ct.dsp_loop_latency = 8;
0466 pll->ct.xclkpagefaultdelay += 1;
0467 }
0468 break;
0469 case SDRAM:
0470 if (info->fix.smem_len<=ONE_MB) {
0471 pll->ct.dsp_loop_latency = 11;
0472 } else {
0473 pll->ct.dsp_loop_latency = 10;
0474 pll->ct.xclkpagefaultdelay += 1;
0475 }
0476 break;
0477 case SGRAM:
0478 pll->ct.dsp_loop_latency = 8;
0479 pll->ct.xclkpagefaultdelay += 3;
0480 break;
0481 default:
0482 pll->ct.dsp_loop_latency = 11;
0483 pll->ct.xclkpagefaultdelay += 3;
0484 break;
0485 }
0486
0487 if (pll->ct.xclkmaxrasdelay <= pll->ct.xclkpagefaultdelay)
0488 pll->ct.xclkmaxrasdelay = pll->ct.xclkpagefaultdelay + 1;
0489
0490
0491 dsp_config = aty_ld_le32(DSP_CONFIG, par);
0492 aty_ld_le32(DSP_ON_OFF, par);
0493 aty_ld_le32(VGA_DSP_CONFIG, par);
0494 aty_ld_le32(VGA_DSP_ON_OFF, par);
0495
0496 if (dsp_config)
0497 pll->ct.dsp_loop_latency = (dsp_config & DSP_LOOP_LATENCY) >> 16;
0498 #if 0
0499 FIXME: is it relevant for us?
0500 if ((!dsp_on_off && !M64_HAS(RESET_3D)) ||
0501 ((dsp_on_off == vga_dsp_on_off) &&
0502 (!dsp_config || !((dsp_config ^ vga_dsp_config) & DSP_XCLKS_PER_QW)))) {
0503 vga_dsp_on_off &= VGA_DSP_OFF;
0504 vga_dsp_config &= VGA_DSP_XCLKS_PER_QW;
0505 if (ATIDivide(vga_dsp_on_off, vga_dsp_config, 5, 1) > 24)
0506 pll->ct.fifo_size = 32;
0507 else
0508 pll->ct.fifo_size = 24;
0509 }
0510 #endif
0511
0512
0513 if (par->mclk_per == 0) {
0514 u8 mclk_fb_div, pll_ext_cntl;
0515 pll->ct.pll_ref_div = aty_ld_pll_ct(PLL_REF_DIV, par);
0516 pll_ext_cntl = aty_ld_pll_ct(PLL_EXT_CNTL, par);
0517 pll->ct.xclk_post_div_real = aty_postdividers[pll_ext_cntl & 0x07];
0518 mclk_fb_div = aty_ld_pll_ct(MCLK_FB_DIV, par);
0519 if (pll_ext_cntl & PLL_MFB_TIMES_4_2B)
0520 mclk_fb_div <<= 1;
0521 pll->ct.mclk_fb_div = mclk_fb_div;
0522 return 0;
0523 }
0524
0525 pll->ct.pll_ref_div = par->pll_per * 2 * 255 / par->ref_clk_per;
0526
0527
0528 q = par->ref_clk_per * pll->ct.pll_ref_div * 8 /
0529 (pll->ct.mclk_fb_mult * par->xclk_per);
0530
0531 if (q < 16*8 || q > 255*8) {
0532 printk(KERN_CRIT "atxfb: xclk out of range\n");
0533 return -EINVAL;
0534 } else {
0535 xpost_div = (q < 128*8);
0536 xpost_div += (q < 64*8);
0537 xpost_div += (q < 32*8);
0538 }
0539 pll->ct.xclk_post_div_real = aty_postdividers[xpost_div];
0540 pll->ct.mclk_fb_div = q * pll->ct.xclk_post_div_real / 8;
0541
0542 #ifdef CONFIG_PPC
0543 if (machine_is(powermac)) {
0544
0545 pll->ct.xclk_post_div = xpost_div;
0546 pll->ct.xclk_ref_div = 1;
0547 }
0548 #endif
0549
0550 #ifdef DEBUG
0551 pllmclk = (1000000 * pll->ct.mclk_fb_mult * pll->ct.mclk_fb_div) /
0552 (par->ref_clk_per * pll->ct.pll_ref_div);
0553 printk("atyfb(%s): pllmclk=%d MHz, xclk=%d MHz\n",
0554 __func__, pllmclk, pllmclk / pll->ct.xclk_post_div_real);
0555 #endif
0556
0557 if (M64_HAS(SDRAM_MAGIC_PLL) && (par->ram_type >= SDRAM))
0558 pll->ct.pll_gen_cntl = OSC_EN;
0559 else
0560 pll->ct.pll_gen_cntl = OSC_EN | DLL_PWDN ;
0561
0562 if (M64_HAS(MAGIC_POSTDIV))
0563 pll->ct.pll_ext_cntl = 0;
0564 else
0565 pll->ct.pll_ext_cntl = xpost_div;
0566
0567 if (pll->ct.mclk_fb_mult == 4)
0568 pll->ct.pll_ext_cntl |= PLL_MFB_TIMES_4_2B;
0569
0570 if (par->mclk_per == par->xclk_per) {
0571 pll->ct.pll_gen_cntl |= (xpost_div << 4);
0572 } else {
0573
0574
0575
0576
0577 pll->ct.pll_gen_cntl |= (6 << 4);
0578
0579 q = par->ref_clk_per * pll->ct.pll_ref_div * 4 / par->mclk_per;
0580 if (q < 16*8 || q > 255*8) {
0581 printk(KERN_CRIT "atyfb: mclk out of range\n");
0582 return -EINVAL;
0583 } else {
0584 mpost_div = (q < 128*8);
0585 mpost_div += (q < 64*8);
0586 mpost_div += (q < 32*8);
0587 }
0588 sclk_post_div_real = aty_postdividers[mpost_div];
0589 pll->ct.sclk_fb_div = q * sclk_post_div_real / 8;
0590 pll->ct.spll_cntl2 = mpost_div << 4;
0591 #ifdef DEBUG
0592 pllsclk = (1000000 * 2 * pll->ct.sclk_fb_div) /
0593 (par->ref_clk_per * pll->ct.pll_ref_div);
0594 printk("atyfb(%s): use sclk, pllsclk=%d MHz, sclk=mclk=%d MHz\n",
0595 __func__, pllsclk, pllsclk / sclk_post_div_real);
0596 #endif
0597 }
0598
0599
0600 pll->ct.ext_vpll_cntl = aty_ld_pll_ct(EXT_VPLL_CNTL, par);
0601 pll->ct.ext_vpll_cntl &= ~(EXT_VPLL_EN | EXT_VPLL_VGA_EN | EXT_VPLL_INSYNC);
0602
0603 return 0;
0604 }
0605
0606 static void aty_resume_pll_ct(const struct fb_info *info,
0607 union aty_pll *pll)
0608 {
0609 struct atyfb_par *par = info->par;
0610
0611 if (par->mclk_per != par->xclk_per) {
0612
0613
0614
0615
0616
0617
0618
0619 aty_st_pll_ct(SCLK_FB_DIV, pll->ct.sclk_fb_div, par);
0620 aty_st_pll_ct(SPLL_CNTL2, pll->ct.spll_cntl2, par);
0621
0622
0623
0624
0625 mdelay(5);
0626 }
0627
0628 aty_st_pll_ct(PLL_REF_DIV, pll->ct.pll_ref_div, par);
0629 aty_st_pll_ct(PLL_GEN_CNTL, pll->ct.pll_gen_cntl, par);
0630 aty_st_pll_ct(MCLK_FB_DIV, pll->ct.mclk_fb_div, par);
0631 aty_st_pll_ct(PLL_EXT_CNTL, pll->ct.pll_ext_cntl, par);
0632 aty_st_pll_ct(EXT_VPLL_CNTL, pll->ct.ext_vpll_cntl, par);
0633 }
0634
0635 static int dummy(void)
0636 {
0637 return 0;
0638 }
0639
0640 const struct aty_dac_ops aty_dac_ct = {
0641 .set_dac = (void *) dummy,
0642 };
0643
0644 const struct aty_pll_ops aty_pll_ct = {
0645 .var_to_pll = aty_var_to_pll_ct,
0646 .pll_to_var = aty_pll_to_var_ct,
0647 .set_pll = aty_set_pll_ct,
0648 .get_pll = aty_get_pll_ct,
0649 .init_pll = aty_init_pll_ct,
0650 .resume_pll = aty_resume_pll_ct,
0651 };