909 lines · c
1// SPDX-License-Identifier: GPL-2.02 3/*4 * ATI Mach64 GX Support5 */6 7#include <linux/delay.h>8#include <linux/fb.h>9 10#include <asm/io.h>11 12#include <video/mach64.h>13#include "atyfb.h"14 15/* Definitions for the ICS 2595 == ATI 18818_1 Clockchip */16 17#define REF_FREQ_2595 1432 /* 14.33 MHz (exact 14.31818) */18#define REF_DIV_2595 46 /* really 43 on ICS 2595 !!! */19 /* ohne Prescaler */20#define MAX_FREQ_2595 15938 /* 159.38 MHz (really 170.486) */21#define MIN_FREQ_2595 8000 /* 80.00 MHz ( 85.565) */22 /* mit Prescaler 2, 4, 8 */23#define ABS_MIN_FREQ_2595 1000 /* 10.00 MHz (really 10.697) */24#define N_ADJ_2595 25725 26#define STOP_BITS_2595 0x180027 28 29#define MIN_N_408 230 31#define MIN_N_1703 632 33#define MIN_M 234#define MAX_M 3035#define MIN_N 3536#define MAX_N 255-837 38 39 /*40 * Support Functions41 */42 43static void aty_dac_waste4(const struct atyfb_par *par)44{45 (void) aty_ld_8(DAC_REGS, par);46 47 (void) aty_ld_8(DAC_REGS + 2, par);48 (void) aty_ld_8(DAC_REGS + 2, par);49 (void) aty_ld_8(DAC_REGS + 2, par);50 (void) aty_ld_8(DAC_REGS + 2, par);51}52 53static void aty_StrobeClock(const struct atyfb_par *par)54{55 u8 tmp;56 57 udelay(26);58 59 tmp = aty_ld_8(CLOCK_CNTL, par);60 aty_st_8(CLOCK_CNTL + par->clk_wr_offset, tmp | CLOCK_STROBE, par);61 return;62}63 64 65 /*66 * IBM RGB514 DAC and Clock Chip67 */68 69static void aty_st_514(int offset, u8 val, const struct atyfb_par *par)70{71 aty_st_8(DAC_CNTL, 1, par);72 /* right addr byte */73 aty_st_8(DAC_W_INDEX, offset & 0xff, par);74 /* left addr byte */75 aty_st_8(DAC_DATA, (offset >> 8) & 0xff, par);76 aty_st_8(DAC_MASK, val, par);77 aty_st_8(DAC_CNTL, 0, par);78}79 80static int aty_set_dac_514(const struct fb_info *info,81 const union aty_pll *pll, u32 bpp, u32 accel)82{83 struct atyfb_par *par = (struct atyfb_par *) info->par;84 static struct {85 u8 pixel_dly;86 u8 misc2_cntl;87 u8 pixel_rep;88 u8 pixel_cntl_index;89 u8 pixel_cntl_v1;90 } tab[3] = {91 {92 0, 0x41, 0x03, 0x71, 0x45}, /* 8 bpp */93 {94 0, 0x45, 0x04, 0x0c, 0x01}, /* 555 */95 {96 0, 0x45, 0x06, 0x0e, 0x00}, /* XRGB */97 };98 int i;99 100 switch (bpp) {101 case 8:102 default:103 i = 0;104 break;105 case 16:106 i = 1;107 break;108 case 32:109 i = 2;110 break;111 }112 aty_st_514(0x90, 0x00, par); /* VRAM Mask Low */113 aty_st_514(0x04, tab[i].pixel_dly, par); /* Horizontal Sync Control */114 aty_st_514(0x05, 0x00, par); /* Power Management */115 aty_st_514(0x02, 0x01, par); /* Misc Clock Control */116 aty_st_514(0x71, tab[i].misc2_cntl, par); /* Misc Control 2 */117 aty_st_514(0x0a, tab[i].pixel_rep, par); /* Pixel Format */118 aty_st_514(tab[i].pixel_cntl_index, tab[i].pixel_cntl_v1, par);119 /* Misc Control 2 / 16 BPP Control / 32 BPP Control */120 return 0;121}122 123static int aty_var_to_pll_514(const struct fb_info *info, u32 vclk_per,124 u32 bpp, union aty_pll *pll)125{126 /*127 * FIXME: use real calculations instead of using fixed values from the old128 * driver129 */130 static struct {131 u32 limit; /* pixlock rounding limit (arbitrary) */132 u8 m; /* (df<<6) | vco_div_count */133 u8 n; /* ref_div_count */134 } RGB514_clocks[7] = {135 {136 8000, (3 << 6) | 20, 9}, /* 7395 ps / 135.2273 MHz */137 {138 10000, (1 << 6) | 19, 3}, /* 9977 ps / 100.2273 MHz */139 {140 13000, (1 << 6) | 2, 3}, /* 12509 ps / 79.9432 MHz */141 {142 14000, (2 << 6) | 8, 7}, /* 13394 ps / 74.6591 MHz */143 {144 16000, (1 << 6) | 44, 6}, /* 15378 ps / 65.0284 MHz */145 {146 25000, (1 << 6) | 15, 5}, /* 17460 ps / 57.2727 MHz */147 {148 50000, (0 << 6) | 53, 7}, /* 33145 ps / 30.1705 MHz */149 };150 int i;151 152 for (i = 0; i < ARRAY_SIZE(RGB514_clocks); i++)153 if (vclk_per <= RGB514_clocks[i].limit) {154 pll->ibm514.m = RGB514_clocks[i].m;155 pll->ibm514.n = RGB514_clocks[i].n;156 return 0;157 }158 return -EINVAL;159}160 161static u32 aty_pll_514_to_var(const struct fb_info *info,162 const union aty_pll *pll)163{164 struct atyfb_par *par = (struct atyfb_par *) info->par;165 u8 df, vco_div_count, ref_div_count;166 167 df = pll->ibm514.m >> 6;168 vco_div_count = pll->ibm514.m & 0x3f;169 ref_div_count = pll->ibm514.n;170 171 return ((par->ref_clk_per * ref_div_count) << (3 - df))/172 (vco_div_count + 65);173}174 175static void aty_set_pll_514(const struct fb_info *info,176 const union aty_pll *pll)177{178 struct atyfb_par *par = (struct atyfb_par *) info->par;179 180 aty_st_514(0x06, 0x02, par); /* DAC Operation */181 aty_st_514(0x10, 0x01, par); /* PLL Control 1 */182 aty_st_514(0x70, 0x01, par); /* Misc Control 1 */183 aty_st_514(0x8f, 0x1f, par); /* PLL Ref. Divider Input */184 aty_st_514(0x03, 0x00, par); /* Sync Control */185 aty_st_514(0x05, 0x00, par); /* Power Management */186 aty_st_514(0x20, pll->ibm514.m, par); /* F0 / M0 */187 aty_st_514(0x21, pll->ibm514.n, par); /* F1 / N0 */188}189 190const struct aty_dac_ops aty_dac_ibm514 = {191 .set_dac = aty_set_dac_514,192};193 194const struct aty_pll_ops aty_pll_ibm514 = {195 .var_to_pll = aty_var_to_pll_514,196 .pll_to_var = aty_pll_514_to_var,197 .set_pll = aty_set_pll_514,198};199 200 201 /*202 * ATI 68860-B DAC203 */204 205static int aty_set_dac_ATI68860_B(const struct fb_info *info,206 const union aty_pll *pll, u32 bpp,207 u32 accel)208{209 struct atyfb_par *par = (struct atyfb_par *) info->par;210 u32 gModeReg, devSetupRegA, temp, mask;211 212 gModeReg = 0;213 devSetupRegA = 0;214 215 switch (bpp) {216 case 8:217 gModeReg = 0x83;218 devSetupRegA =219 0x60 | 0x00 /*(info->mach64DAC8Bit ? 0x00 : 0x01) */ ;220 break;221 case 15:222 gModeReg = 0xA0;223 devSetupRegA = 0x60;224 break;225 case 16:226 gModeReg = 0xA1;227 devSetupRegA = 0x60;228 break;229 case 24:230 gModeReg = 0xC0;231 devSetupRegA = 0x60;232 break;233 case 32:234 gModeReg = 0xE3;235 devSetupRegA = 0x60;236 break;237 }238 239 if (!accel) {240 gModeReg = 0x80;241 devSetupRegA = 0x61;242 }243 244 temp = aty_ld_8(DAC_CNTL, par);245 aty_st_8(DAC_CNTL, (temp & ~DAC_EXT_SEL_RS2) | DAC_EXT_SEL_RS3,246 par);247 248 aty_st_8(DAC_REGS + 2, 0x1D, par);249 aty_st_8(DAC_REGS + 3, gModeReg, par);250 aty_st_8(DAC_REGS, 0x02, par);251 252 temp = aty_ld_8(DAC_CNTL, par);253 aty_st_8(DAC_CNTL, temp | DAC_EXT_SEL_RS2 | DAC_EXT_SEL_RS3, par);254 255 if (info->fix.smem_len < ONE_MB)256 mask = 0x04;257 else if (info->fix.smem_len == ONE_MB)258 mask = 0x08;259 else260 mask = 0x0C;261 262 /* The following assumes that the BIOS has correctly set R7 of the263 * Device Setup Register A at boot time.264 */265#define A860_DELAY_L 0x80266 267 temp = aty_ld_8(DAC_REGS, par);268 aty_st_8(DAC_REGS, (devSetupRegA | mask) | (temp & A860_DELAY_L),269 par);270 temp = aty_ld_8(DAC_CNTL, par);271 aty_st_8(DAC_CNTL, (temp & ~(DAC_EXT_SEL_RS2 | DAC_EXT_SEL_RS3)),272 par);273 274 aty_st_le32(BUS_CNTL, 0x890e20f1, par);275 aty_st_le32(DAC_CNTL, 0x47052100, par);276 return 0;277}278 279const struct aty_dac_ops aty_dac_ati68860b = {280 .set_dac = aty_set_dac_ATI68860_B,281};282 283 284 /*285 * AT&T 21C498 DAC286 */287 288static int aty_set_dac_ATT21C498(const struct fb_info *info,289 const union aty_pll *pll, u32 bpp,290 u32 accel)291{292 struct atyfb_par *par = (struct atyfb_par *) info->par;293 u32 dotClock;294 int muxmode = 0;295 int DACMask = 0;296 297 dotClock = 100000000 / pll->ics2595.period_in_ps;298 299 switch (bpp) {300 case 8:301 if (dotClock > 8000) {302 DACMask = 0x24;303 muxmode = 1;304 } else305 DACMask = 0x04;306 break;307 case 15:308 DACMask = 0x16;309 break;310 case 16:311 DACMask = 0x36;312 break;313 case 24:314 DACMask = 0xE6;315 break;316 case 32:317 DACMask = 0xE6;318 break;319 }320 321 if (1 /* info->mach64DAC8Bit */ )322 DACMask |= 0x02;323 324 aty_dac_waste4(par);325 aty_st_8(DAC_REGS + 2, DACMask, par);326 327 aty_st_le32(BUS_CNTL, 0x890e20f1, par);328 aty_st_le32(DAC_CNTL, 0x00072000, par);329 return muxmode;330}331 332const struct aty_dac_ops aty_dac_att21c498 = {333 .set_dac = aty_set_dac_ATT21C498,334};335 336 337 /*338 * ATI 18818 / ICS 2595 Clock Chip339 */340 341static int aty_var_to_pll_18818(const struct fb_info *info, u32 vclk_per,342 u32 bpp, union aty_pll *pll)343{344 u32 MHz100; /* in 0.01 MHz */345 u32 program_bits;346 u32 post_divider;347 348 /* Calculate the programming word */349 MHz100 = 100000000 / vclk_per;350 351 program_bits = -1;352 post_divider = 1;353 354 if (MHz100 > MAX_FREQ_2595) {355 return -EINVAL;356 } else if (MHz100 < ABS_MIN_FREQ_2595) {357 return -EINVAL;358 } else {359 while (MHz100 < MIN_FREQ_2595) {360 MHz100 *= 2;361 post_divider *= 2;362 }363 }364 MHz100 *= 1000;365 MHz100 = (REF_DIV_2595 * MHz100) / REF_FREQ_2595;366 367 MHz100 += 500; /* + 0.5 round */368 MHz100 /= 1000;369 370 if (program_bits == -1) {371 program_bits = MHz100 - N_ADJ_2595;372 switch (post_divider) {373 case 1:374 program_bits |= 0x0600;375 break;376 case 2:377 program_bits |= 0x0400;378 break;379 case 4:380 program_bits |= 0x0200;381 break;382 case 8:383 default:384 break;385 }386 }387 388 program_bits |= STOP_BITS_2595;389 390 pll->ics2595.program_bits = program_bits;391 pll->ics2595.locationAddr = 0;392 pll->ics2595.post_divider = post_divider;393 pll->ics2595.period_in_ps = vclk_per;394 395 return 0;396}397 398static u32 aty_pll_18818_to_var(const struct fb_info *info,399 const union aty_pll *pll)400{401 return (pll->ics2595.period_in_ps); /* default for now */402}403 404static void aty_ICS2595_put1bit(u8 data, const struct atyfb_par *par)405{406 u8 tmp;407 408 data &= 0x01;409 tmp = aty_ld_8(CLOCK_CNTL, par);410 aty_st_8(CLOCK_CNTL + par->clk_wr_offset,411 (tmp & ~0x04) | (data << 2), par);412 413 tmp = aty_ld_8(CLOCK_CNTL, par);414 aty_st_8(CLOCK_CNTL + par->clk_wr_offset, (tmp & ~0x08) | (0 << 3),415 par);416 417 aty_StrobeClock(par);418 419 tmp = aty_ld_8(CLOCK_CNTL, par);420 aty_st_8(CLOCK_CNTL + par->clk_wr_offset, (tmp & ~0x08) | (1 << 3),421 par);422 423 aty_StrobeClock(par);424 return;425}426 427static void aty_set_pll18818(const struct fb_info *info,428 const union aty_pll *pll)429{430 struct atyfb_par *par = (struct atyfb_par *) info->par;431 u32 program_bits;432 u32 locationAddr;433 434 u32 i;435 436 u8 old_clock_cntl;437 u8 old_crtc_ext_disp;438 439 old_clock_cntl = aty_ld_8(CLOCK_CNTL, par);440 aty_st_8(CLOCK_CNTL + par->clk_wr_offset, 0, par);441 442 old_crtc_ext_disp = aty_ld_8(CRTC_GEN_CNTL + 3, par);443 aty_st_8(CRTC_GEN_CNTL + 3,444 old_crtc_ext_disp | (CRTC_EXT_DISP_EN >> 24), par);445 446 mdelay(15); /* delay for 50 (15) ms */447 448 program_bits = pll->ics2595.program_bits;449 locationAddr = pll->ics2595.locationAddr;450 451 /* Program the clock chip */452 aty_st_8(CLOCK_CNTL + par->clk_wr_offset, 0, par); /* Strobe = 0 */453 aty_StrobeClock(par);454 aty_st_8(CLOCK_CNTL + par->clk_wr_offset, 1, par); /* Strobe = 0 */455 aty_StrobeClock(par);456 457 aty_ICS2595_put1bit(1, par); /* Send start bits */458 aty_ICS2595_put1bit(0, par); /* Start bit */459 aty_ICS2595_put1bit(0, par); /* Read / ~Write */460 461 for (i = 0; i < 5; i++) { /* Location 0..4 */462 aty_ICS2595_put1bit(locationAddr & 1, par);463 locationAddr >>= 1;464 }465 466 for (i = 0; i < 8 + 1 + 2 + 2; i++) {467 aty_ICS2595_put1bit(program_bits & 1, par);468 program_bits >>= 1;469 }470 471 mdelay(1); /* delay for 1 ms */472 473 (void) aty_ld_8(DAC_REGS, par); /* Clear DAC Counter */474 aty_st_8(CRTC_GEN_CNTL + 3, old_crtc_ext_disp, par);475 aty_st_8(CLOCK_CNTL + par->clk_wr_offset,476 old_clock_cntl | CLOCK_STROBE, par);477 478 mdelay(50); /* delay for 50 (15) ms */479 aty_st_8(CLOCK_CNTL + par->clk_wr_offset,480 ((pll->ics2595.locationAddr & 0x0F) | CLOCK_STROBE), par);481 return;482}483 484const struct aty_pll_ops aty_pll_ati18818_1 = {485 .var_to_pll = aty_var_to_pll_18818,486 .pll_to_var = aty_pll_18818_to_var,487 .set_pll = aty_set_pll18818,488};489 490 491 /*492 * STG 1703 Clock Chip493 */494 495static int aty_var_to_pll_1703(const struct fb_info *info, u32 vclk_per,496 u32 bpp, union aty_pll *pll)497{498 u32 mhz100; /* in 0.01 MHz */499 u32 program_bits;500 /* u32 post_divider; */501 u32 mach64MinFreq, mach64MaxFreq, mach64RefFreq;502 u32 temp, tempB;503 u16 remainder, preRemainder;504 short divider = 0, tempA;505 506 /* Calculate the programming word */507 mhz100 = 100000000 / vclk_per;508 mach64MinFreq = MIN_FREQ_2595;509 mach64MaxFreq = MAX_FREQ_2595;510 mach64RefFreq = REF_FREQ_2595; /* 14.32 MHz */511 512 /* Calculate program word */513 if (mhz100 == 0)514 program_bits = 0xE0;515 else {516 if (mhz100 < mach64MinFreq)517 mhz100 = mach64MinFreq;518 if (mhz100 > mach64MaxFreq)519 mhz100 = mach64MaxFreq;520 521 divider = 0;522 while (mhz100 < (mach64MinFreq << 3)) {523 mhz100 <<= 1;524 divider += 0x20;525 }526 527 temp = (unsigned int) (mhz100);528 temp = (unsigned int) (temp * (MIN_N_1703 + 2));529 temp -= (short) (mach64RefFreq << 1);530 531 tempA = MIN_N_1703;532 preRemainder = 0xffff;533 534 do {535 tempB = temp;536 remainder = tempB % mach64RefFreq;537 tempB = tempB / mach64RefFreq;538 539 if ((tempB & 0xffff) <= 127540 && (remainder <= preRemainder)) {541 preRemainder = remainder;542 divider &= ~0x1f;543 divider |= tempA;544 divider =545 (divider & 0x00ff) +546 ((tempB & 0xff) << 8);547 }548 549 temp += mhz100;550 tempA++;551 } while (tempA <= (MIN_N_1703 << 1));552 553 program_bits = divider;554 }555 556 pll->ics2595.program_bits = program_bits;557 pll->ics2595.locationAddr = 0;558 pll->ics2595.post_divider = divider; /* fuer nix */559 pll->ics2595.period_in_ps = vclk_per;560 561 return 0;562}563 564static u32 aty_pll_1703_to_var(const struct fb_info *info,565 const union aty_pll *pll)566{567 return (pll->ics2595.period_in_ps); /* default for now */568}569 570static void aty_set_pll_1703(const struct fb_info *info,571 const union aty_pll *pll)572{573 struct atyfb_par *par = (struct atyfb_par *) info->par;574 u32 program_bits;575 u32 locationAddr;576 577 char old_crtc_ext_disp;578 579 old_crtc_ext_disp = aty_ld_8(CRTC_GEN_CNTL + 3, par);580 aty_st_8(CRTC_GEN_CNTL + 3,581 old_crtc_ext_disp | (CRTC_EXT_DISP_EN >> 24), par);582 583 program_bits = pll->ics2595.program_bits;584 locationAddr = pll->ics2595.locationAddr;585 586 /* Program clock */587 aty_dac_waste4(par);588 589 (void) aty_ld_8(DAC_REGS + 2, par);590 aty_st_8(DAC_REGS + 2, (locationAddr << 1) + 0x20, par);591 aty_st_8(DAC_REGS + 2, 0, par);592 aty_st_8(DAC_REGS + 2, (program_bits & 0xFF00) >> 8, par);593 aty_st_8(DAC_REGS + 2, (program_bits & 0xFF), par);594 595 (void) aty_ld_8(DAC_REGS, par); /* Clear DAC Counter */596 aty_st_8(CRTC_GEN_CNTL + 3, old_crtc_ext_disp, par);597 return;598}599 600const struct aty_pll_ops aty_pll_stg1703 = {601 .var_to_pll = aty_var_to_pll_1703,602 .pll_to_var = aty_pll_1703_to_var,603 .set_pll = aty_set_pll_1703,604};605 606 607 /*608 * Chrontel 8398 Clock Chip609 */610 611static int aty_var_to_pll_8398(const struct fb_info *info, u32 vclk_per,612 u32 bpp, union aty_pll *pll)613{614 u32 tempA, tempB, fOut, longMHz100, diff, preDiff;615 616 u32 mhz100; /* in 0.01 MHz */617 u32 program_bits;618 /* u32 post_divider; */619 u32 mach64MinFreq, mach64MaxFreq;620 u16 m, n, k = 0, save_m, save_n, twoToKth;621 622 /* Calculate the programming word */623 mhz100 = 100000000 / vclk_per;624 mach64MinFreq = MIN_FREQ_2595;625 mach64MaxFreq = MAX_FREQ_2595;626 627 save_m = 0;628 save_n = 0;629 630 /* Calculate program word */631 if (mhz100 == 0)632 program_bits = 0xE0;633 else {634 if (mhz100 < mach64MinFreq)635 mhz100 = mach64MinFreq;636 if (mhz100 > mach64MaxFreq)637 mhz100 = mach64MaxFreq;638 639 longMHz100 = mhz100 * 256 / 100; /* 8 bit scale this */640 641 while (mhz100 < (mach64MinFreq << 3)) {642 mhz100 <<= 1;643 k++;644 }645 646 twoToKth = 1 << k;647 diff = 0;648 preDiff = 0xFFFFFFFF;649 650 for (m = MIN_M; m <= MAX_M; m++) {651 for (n = MIN_N; n <= MAX_N; n++) {652 tempA = 938356; /* 14.31818 * 65536 */653 tempA *= (n + 8); /* 43..256 */654 tempB = twoToKth * 256;655 tempB *= (m + 2); /* 4..32 */656 fOut = tempA / tempB; /* 8 bit scale */657 658 if (longMHz100 > fOut)659 diff = longMHz100 - fOut;660 else661 diff = fOut - longMHz100;662 663 if (diff < preDiff) {664 save_m = m;665 save_n = n;666 preDiff = diff;667 }668 }669 }670 671 program_bits = (k << 6) + (save_m) + (save_n << 8);672 }673 674 pll->ics2595.program_bits = program_bits;675 pll->ics2595.locationAddr = 0;676 pll->ics2595.post_divider = 0;677 pll->ics2595.period_in_ps = vclk_per;678 679 return 0;680}681 682static u32 aty_pll_8398_to_var(const struct fb_info *info,683 const union aty_pll *pll)684{685 return (pll->ics2595.period_in_ps); /* default for now */686}687 688static void aty_set_pll_8398(const struct fb_info *info,689 const union aty_pll *pll)690{691 struct atyfb_par *par = (struct atyfb_par *) info->par;692 u32 program_bits;693 u32 locationAddr;694 695 char old_crtc_ext_disp;696 char tmp;697 698 old_crtc_ext_disp = aty_ld_8(CRTC_GEN_CNTL + 3, par);699 aty_st_8(CRTC_GEN_CNTL + 3,700 old_crtc_ext_disp | (CRTC_EXT_DISP_EN >> 24), par);701 702 program_bits = pll->ics2595.program_bits;703 locationAddr = pll->ics2595.locationAddr;704 705 /* Program clock */706 tmp = aty_ld_8(DAC_CNTL, par);707 aty_st_8(DAC_CNTL, tmp | DAC_EXT_SEL_RS2 | DAC_EXT_SEL_RS3, par);708 709 aty_st_8(DAC_REGS, locationAddr, par);710 aty_st_8(DAC_REGS + 1, (program_bits & 0xff00) >> 8, par);711 aty_st_8(DAC_REGS + 1, (program_bits & 0xff), par);712 713 tmp = aty_ld_8(DAC_CNTL, par);714 aty_st_8(DAC_CNTL, (tmp & ~DAC_EXT_SEL_RS2) | DAC_EXT_SEL_RS3,715 par);716 717 (void) aty_ld_8(DAC_REGS, par); /* Clear DAC Counter */718 aty_st_8(CRTC_GEN_CNTL + 3, old_crtc_ext_disp, par);719 720 return;721}722 723const struct aty_pll_ops aty_pll_ch8398 = {724 .var_to_pll = aty_var_to_pll_8398,725 .pll_to_var = aty_pll_8398_to_var,726 .set_pll = aty_set_pll_8398,727};728 729 730 /*731 * AT&T 20C408 Clock Chip732 */733 734static int aty_var_to_pll_408(const struct fb_info *info, u32 vclk_per,735 u32 bpp, union aty_pll *pll)736{737 u32 mhz100; /* in 0.01 MHz */738 u32 program_bits;739 /* u32 post_divider; */740 u32 mach64MinFreq, mach64MaxFreq, mach64RefFreq;741 u32 temp, tempB;742 u16 remainder, preRemainder;743 short divider = 0, tempA;744 745 /* Calculate the programming word */746 mhz100 = 100000000 / vclk_per;747 mach64MinFreq = MIN_FREQ_2595;748 mach64MaxFreq = MAX_FREQ_2595;749 mach64RefFreq = REF_FREQ_2595; /* 14.32 MHz */750 751 /* Calculate program word */752 if (mhz100 == 0)753 program_bits = 0xFF;754 else {755 if (mhz100 < mach64MinFreq)756 mhz100 = mach64MinFreq;757 if (mhz100 > mach64MaxFreq)758 mhz100 = mach64MaxFreq;759 760 while (mhz100 < (mach64MinFreq << 3)) {761 mhz100 <<= 1;762 divider += 0x40;763 }764 765 temp = (unsigned int) mhz100;766 temp = (unsigned int) (temp * (MIN_N_408 + 2));767 temp -= ((short) (mach64RefFreq << 1));768 769 tempA = MIN_N_408;770 preRemainder = 0xFFFF;771 772 do {773 tempB = temp;774 remainder = tempB % mach64RefFreq;775 tempB = tempB / mach64RefFreq;776 if (((tempB & 0xFFFF) <= 255)777 && (remainder <= preRemainder)) {778 preRemainder = remainder;779 divider &= ~0x3f;780 divider |= tempA;781 divider =782 (divider & 0x00FF) +783 ((tempB & 0xFF) << 8);784 }785 temp += mhz100;786 tempA++;787 } while (tempA <= 32);788 789 program_bits = divider;790 }791 792 pll->ics2595.program_bits = program_bits;793 pll->ics2595.locationAddr = 0;794 pll->ics2595.post_divider = divider; /* fuer nix */795 pll->ics2595.period_in_ps = vclk_per;796 797 return 0;798}799 800static u32 aty_pll_408_to_var(const struct fb_info *info,801 const union aty_pll *pll)802{803 return (pll->ics2595.period_in_ps); /* default for now */804}805 806static void aty_set_pll_408(const struct fb_info *info,807 const union aty_pll *pll)808{809 struct atyfb_par *par = (struct atyfb_par *) info->par;810 u32 program_bits;811 u32 locationAddr;812 813 u8 tmpA, tmpB, tmpC;814 char old_crtc_ext_disp;815 816 old_crtc_ext_disp = aty_ld_8(CRTC_GEN_CNTL + 3, par);817 aty_st_8(CRTC_GEN_CNTL + 3,818 old_crtc_ext_disp | (CRTC_EXT_DISP_EN >> 24), par);819 820 program_bits = pll->ics2595.program_bits;821 locationAddr = pll->ics2595.locationAddr;822 823 /* Program clock */824 aty_dac_waste4(par);825 tmpB = aty_ld_8(DAC_REGS + 2, par) | 1;826 aty_dac_waste4(par);827 aty_st_8(DAC_REGS + 2, tmpB, par);828 829 tmpA = tmpB;830 tmpC = tmpA;831 tmpA |= 8;832 tmpB = 1;833 834 aty_st_8(DAC_REGS, tmpB, par);835 aty_st_8(DAC_REGS + 2, tmpA, par);836 837 udelay(400); /* delay for 400 us */838 839 locationAddr = (locationAddr << 2) + 0x40;840 tmpB = locationAddr;841 tmpA = program_bits >> 8;842 843 aty_st_8(DAC_REGS, tmpB, par);844 aty_st_8(DAC_REGS + 2, tmpA, par);845 846 tmpB = locationAddr + 1;847 tmpA = (u8) program_bits;848 849 aty_st_8(DAC_REGS, tmpB, par);850 aty_st_8(DAC_REGS + 2, tmpA, par);851 852 tmpB = locationAddr + 2;853 tmpA = 0x77;854 855 aty_st_8(DAC_REGS, tmpB, par);856 aty_st_8(DAC_REGS + 2, tmpA, par);857 858 udelay(400); /* delay for 400 us */859 tmpA = tmpC & (~(1 | 8));860 tmpB = 1;861 862 aty_st_8(DAC_REGS, tmpB, par);863 aty_st_8(DAC_REGS + 2, tmpA, par);864 865 (void) aty_ld_8(DAC_REGS, par); /* Clear DAC Counter */866 aty_st_8(CRTC_GEN_CNTL + 3, old_crtc_ext_disp, par);867 return;868}869 870const struct aty_pll_ops aty_pll_att20c408 = {871 .var_to_pll = aty_var_to_pll_408,872 .pll_to_var = aty_pll_408_to_var,873 .set_pll = aty_set_pll_408,874};875 876 877 /*878 * Unsupported DAC and Clock Chip879 */880 881static int aty_set_dac_unsupported(const struct fb_info *info,882 const union aty_pll *pll, u32 bpp,883 u32 accel)884{885 struct atyfb_par *par = (struct atyfb_par *) info->par;886 887 aty_st_le32(BUS_CNTL, 0x890e20f1, par);888 aty_st_le32(DAC_CNTL, 0x47052100, par);889 /* new in 2.2.3p1 from Geert. ???????? */890 aty_st_le32(BUS_CNTL, 0x590e10ff, par);891 aty_st_le32(DAC_CNTL, 0x47012100, par);892 return 0;893}894 895static int dummy(void)896{897 return 0;898}899 900const struct aty_dac_ops aty_dac_unsupported = {901 .set_dac = aty_set_dac_unsupported,902};903 904const struct aty_pll_ops aty_pll_unsupported = {905 .var_to_pll = (void *) dummy,906 .pll_to_var = (void *) dummy,907 .set_pll = (void *) dummy,908};909