atyfb.c
来自「讲述linux的初始化过程」· C语言 代码 · 共 2,436 行 · 第 1/5 页
C
2,436 行
pll->program_bits = program_bits; pll->locationAddr = 0; pll->post_divider = divider; /* fuer nix */ pll->period_in_ps = period_in_ps; return 0;}static u32 aty_pll_1703_to_var(const struct pll_18818 *pll){ return(pll->period_in_ps); /* default for now */}static void aty_set_pll_1703(const struct fb_info_aty *info, const struct pll_18818 *pll){ u32 program_bits; u32 locationAddr; char old_crtc_ext_disp; old_crtc_ext_disp = aty_ld_8(CRTC_GEN_CNTL + 3, info); aty_st_8(CRTC_GEN_CNTL + 3, old_crtc_ext_disp | (CRTC_EXT_DISP_EN >> 24), info); program_bits = pll->program_bits; locationAddr = pll->locationAddr; /* Program clock */ aty_dac_waste4(info); (void)aty_ld_8(DAC_REGS + 2, info); aty_st_8(DAC_REGS+2, (locationAddr << 1) + 0x20, info); aty_st_8(DAC_REGS+2, 0, info); aty_st_8(DAC_REGS+2, (program_bits & 0xFF00) >> 8, info); aty_st_8(DAC_REGS+2, (program_bits & 0xFF), info); (void)aty_ld_8(DAC_REGS, info); /* Clear DAC Counter */ aty_st_8(CRTC_GEN_CNTL + 3, old_crtc_ext_disp, info); return;}static int aty_var_to_pll_8398(u32 period_in_ps, struct pll_18818 *pll){ u32 tempA, tempB, fOut, longMHz100, diff, preDiff; u32 mhz100; /* in 0.01 MHz */ u32 program_bits; /* u32 post_divider; */ u32 mach64MinFreq, mach64MaxFreq, mach64RefFreq; u16 m, n, k=0, save_m, save_n, twoToKth; /* Calculate the programming word */ mhz100 = 100000000 / period_in_ps; mach64MinFreq = MIN_FREQ_2595; mach64MaxFreq = MAX_FREQ_2595; mach64RefFreq = REF_FREQ_2595; /* 14.32 MHz */ save_m = 0; save_n = 0; /* Calculate program word */ if (mhz100 == 0) program_bits = 0xE0; else { if (mhz100 < mach64MinFreq) mhz100 = mach64MinFreq; if (mhz100 > mach64MaxFreq) mhz100 = mach64MaxFreq; longMHz100 = mhz100 * 256 / 100; /* 8 bit scale this */ while (mhz100 < (mach64MinFreq << 3)) { mhz100 <<= 1; k++; } twoToKth = 1 << k; diff = 0; preDiff = 0xFFFFFFFF; for (m = MIN_M; m <= MAX_M; m++) { for (n = MIN_N; n <= MAX_N; n++) { tempA = (14.31818 * 65536); tempA *= (n + 8); /* 43..256 */ tempB = twoToKth * 256; tempB *= (m + 2); /* 4..32 */ fOut = tempA / tempB; /* 8 bit scale */ if (longMHz100 > fOut) diff = longMHz100 - fOut; else diff = fOut - longMHz100; if (diff < preDiff) { save_m = m; save_n = n; preDiff = diff; } } } program_bits = (k << 6) + (save_m) + (save_n << 8); } pll->program_bits = program_bits; pll->locationAddr = 0; pll->post_divider = 0; pll->period_in_ps = period_in_ps; return 0;}static u32 aty_pll_8398_to_var(const struct pll_18818 *pll){ return(pll->period_in_ps); /* default for now */}static void aty_set_pll_8398(const struct fb_info_aty *info, const struct pll_18818 *pll){ u32 program_bits; u32 locationAddr; char old_crtc_ext_disp; char tmp; old_crtc_ext_disp = aty_ld_8(CRTC_GEN_CNTL + 3, info); aty_st_8(CRTC_GEN_CNTL + 3, old_crtc_ext_disp | (CRTC_EXT_DISP_EN >> 24), info); program_bits = pll->program_bits; locationAddr = pll->locationAddr; /* Program clock */ tmp = aty_ld_8(DAC_CNTL, info); aty_st_8(DAC_CNTL, tmp | DAC_EXT_SEL_RS2 | DAC_EXT_SEL_RS3, info); aty_st_8(DAC_REGS, locationAddr, info); aty_st_8(DAC_REGS+1, (program_bits & 0xff00) >> 8, info); aty_st_8(DAC_REGS+1, (program_bits & 0xff), info); tmp = aty_ld_8(DAC_CNTL, info); aty_st_8(DAC_CNTL, (tmp & ~DAC_EXT_SEL_RS2) | DAC_EXT_SEL_RS3, info); (void)aty_ld_8(DAC_REGS, info); /* Clear DAC Counter */ aty_st_8(CRTC_GEN_CNTL + 3, old_crtc_ext_disp, info); return;}static int aty_var_to_pll_514(u32 vclk_per, struct pll_gx *pll){ /* * FIXME: use real calculations instead of using fixed values from the old * driver */ static struct { u32 limit; /* pixlock rounding limit (arbitrary) */ u8 m; /* (df<<6) | vco_div_count */ u8 n; /* ref_div_count */ } RGB514_clocks[7] = { { 8000, (3<<6) | 20, 9 }, /* 7395 ps / 135.2273 MHz */ { 10000, (1<<6) | 19, 3 }, /* 9977 ps / 100.2273 MHz */ { 13000, (1<<6) | 2, 3 }, /* 12509 ps / 79.9432 MHz */ { 14000, (2<<6) | 8, 7 }, /* 13394 ps / 74.6591 MHz */ { 16000, (1<<6) | 44, 6 }, /* 15378 ps / 65.0284 MHz */ { 25000, (1<<6) | 15, 5 }, /* 17460 ps / 57.2727 MHz */ { 50000, (0<<6) | 53, 7 }, /* 33145 ps / 30.1705 MHz */ }; int i; for (i = 0; i < sizeof(RGB514_clocks)/sizeof(*RGB514_clocks); i++) if (vclk_per <= RGB514_clocks[i].limit) { pll->m = RGB514_clocks[i].m; pll->n = RGB514_clocks[i].n; return 0; } return -EINVAL;}static void aty_StrobeClock(const struct fb_info_aty *info){ u8 tmp; udelay(26); tmp = aty_ld_8(CLOCK_CNTL, info); aty_st_8(CLOCK_CNTL + info->clk_wr_offset, tmp | CLOCK_STROBE, info); return;}static void aty_ICS2595_put1bit(u8 data, const struct fb_info_aty *info){ u8 tmp; data &= 0x01; tmp = aty_ld_8(CLOCK_CNTL, info); aty_st_8(CLOCK_CNTL + info->clk_wr_offset, (tmp & ~0x04) | (data << 2), info); tmp = aty_ld_8(CLOCK_CNTL, info); aty_st_8(CLOCK_CNTL + info->clk_wr_offset, (tmp & ~0x08) | (0 << 3), info); aty_StrobeClock(info); tmp = aty_ld_8(CLOCK_CNTL, info); aty_st_8(CLOCK_CNTL + info->clk_wr_offset, (tmp & ~0x08) | (1 << 3), info); aty_StrobeClock(info); return;}static u32 aty_pll_gx_to_var(const struct pll_gx *pll, const struct fb_info_aty *info){ u8 df, vco_div_count, ref_div_count; df = pll->m >> 6; vco_div_count = pll->m & 0x3f; ref_div_count = pll->n; return ((info->ref_clk_per*ref_div_count)<<(3-df))/(vco_div_count+65);} /* * PLL programming (Mach64 CT family) */static void aty_set_pll_ct(const struct fb_info_aty *info, const struct pll_ct *pll){ aty_st_pll(PLL_REF_DIV, pll->pll_ref_div, info); aty_st_pll(PLL_GEN_CNTL, pll->pll_gen_cntl, info); aty_st_pll(MCLK_FB_DIV, pll->mclk_fb_div, info); aty_st_pll(PLL_VCLK_CNTL, pll->pll_vclk_cntl, info); aty_st_pll(VCLK_POST_DIV, pll->vclk_post_div, info); aty_st_pll(VCLK0_FB_DIV, pll->vclk_fb_div, info); aty_st_pll(PLL_EXT_CNTL, pll->pll_ext_cntl, info); if (!(Gx == GX_CHIP_ID || Gx == CX_CHIP_ID || Gx == CT_CHIP_ID || Gx == ET_CHIP_ID || ((Gx == VT_CHIP_ID || Gx == GT_CHIP_ID) && !(Rev & 0x07)))) { if (info->ram_type >= SDRAM) aty_st_pll(DLL_CNTL, 0xa6, info); else aty_st_pll(DLL_CNTL, 0xa0, info); aty_st_pll(VFC_CNTL, 0x1b, info); aty_st_le32(DSP_CONFIG, pll->dsp_config, info); aty_st_le32(DSP_ON_OFF, pll->dsp_on_off, info); }}static int aty_dsp_gt(const struct fb_info_aty *info, u8 bpp, struct pll_ct *pll){ u32 dsp_xclks_per_row, dsp_loop_latency, dsp_precision, dsp_off, dsp_on; u32 xclks_per_row, fifo_off, fifo_on, y, fifo_size, page_size; /* xclocks_per_row<<11 */ xclks_per_row = (pll->mclk_fb_div*pll->vclk_post_div_real*64<<11)/ (pll->vclk_fb_div*pll->mclk_post_div_real*bpp); if (xclks_per_row < (1<<11)) FAIL("Dotclock to high"); if (Gx == GT_CHIP_ID || Gx == GU_CHIP_ID || Gx == VT_CHIP_ID || Gx == VU_CHIP_ID || Gx == GV_CHIP_ID || Gx == GW_CHIP_ID || Gx == GZ_CHIP_ID) { fifo_size = 24; dsp_loop_latency = 0; } else { fifo_size = 32; dsp_loop_latency = 2; } dsp_precision = 0; y = (xclks_per_row*fifo_size)>>11; while (y) { y >>= 1; dsp_precision++; } dsp_precision -= 5; /* fifo_off<<6 */ fifo_off = ((xclks_per_row*(fifo_size-1))>>5)+(3<<6); if (info->total_vram > 1*1024*1024) { if (info->ram_type >= SDRAM) { /* >1 MB SDRAM */ dsp_loop_latency += 8; page_size = 8; } else { /* >1 MB DRAM */ dsp_loop_latency += 6; page_size = 9; } } else { if (info->ram_type >= SDRAM) { /* <2 MB SDRAM */ dsp_loop_latency += 9; page_size = 10; } else { /* <2 MB DRAM */ dsp_loop_latency += 8; page_size = 10; } } /* fifo_on<<6 */ if (xclks_per_row >= (page_size<<11)) fifo_on = ((2*page_size+1)<<6)+(xclks_per_row>>5); else fifo_on = (3*page_size+2)<<6; dsp_xclks_per_row = xclks_per_row>>dsp_precision; dsp_on = fifo_on>>dsp_precision; dsp_off = fifo_off>>dsp_precision; pll->dsp_config = (dsp_xclks_per_row & 0x3fff) | ((dsp_loop_latency & 0xf)<<16) | ((dsp_precision & 7)<<20); pll->dsp_on_off = (dsp_on & 0x7ff) | ((dsp_off & 0x7ff)<<16); return 0;}static int aty_valid_pll_ct(const struct fb_info_aty *info, u32 vclk_per, struct pll_ct *pll){ u32 q, x; /* x is a workaround for sparc64-linux-gcc */ x = x; /* x is a workaround for sparc64-linux-gcc */ pll->pll_ref_div = info->pll_per*2*255/info->ref_clk_per; /* FIXME: use the VTB/GTB /3 post divider if it's better suited */ q = info->ref_clk_per*pll->pll_ref_div*4/info->mclk_per; /* actually 8*q */ if (q < 16*8 || q > 255*8) FAIL("mclk out of range"); else if (q < 32*8) pll->mclk_post_div_real = 8; else if (q < 64*8) pll->mclk_post_div_real = 4; else if (q < 128*8) pll->mclk_post_div_real = 2; else pll->mclk_post_div_real = 1; pll->mclk_fb_div = q*pll->mclk_post_div_real/8; /* FIXME: use the VTB/GTB /{3,6,12} post dividers if they're better suited */ q = info->ref_clk_per*pll->pll_ref_div*4/vclk_per; /* actually 8*q */ if (q < 16*8 || q > 255*8) FAIL("vclk out of range"); else if (q < 32*8) pll->vclk_post_div_real = 8; else if (q < 64*8) pll->vclk_post_div_real = 4; else if (q < 128*8) pll->vclk_post_div_real = 2; else pll->vclk_post_div_real = 1; pll->vclk_fb_div = q*pll->vclk_post_div_real/8; return 0;}static void aty_calc_pll_ct(const struct fb_info_aty *info, struct pll_ct *pll){ u8 mpostdiv = 0; u8 vpostdiv = 0; if ((((Gx == GT_CHIP_ID) && (Rev & 0x03)) || (Gx == GU_CHIP_ID) || (Gx == GV_CHIP_ID) || (Gx == GW_CHIP_ID) || (Gx == GZ_CHIP_ID) || (Gx == LG_CHIP_ID) || (Gx == GB_CHIP_ID) || (Gx == GD_CHIP_ID) || (Gx == GI_CHIP_ID) || (Gx == GP_CHIP_ID) || (Gx == GQ_CHIP_ID) || (Gx == VU_CHIP_ID)) && (info->ram_type >= SDRAM)) pll->pll_gen_cntl = 0x04; else pll->pll_gen_cntl = 0x84; switch (pll->mclk_post_div_real) { case 1: mpostdiv = 0; break; case 2: mpostdiv = 1; break; case 3: mpostdiv = 4; break; case 4: mpostdiv = 2; break; case 8: mpostdiv = 3; break; } pll->pll_gen_cntl |= mpostdiv<<4; /* mclk */ if (Gx == VT_CHIP_ID && (Rev == 0x40 || Rev == 0x48)) pll->pll_ext_cntl = 0; else pll->pll_ext_cntl = mpostdiv; /* xclk == mclk */ switch (pll->vclk_post_div_real) { case 2: vpostdiv = 1; break; case 3: pll->pll_ext_cntl |= 0x10; case 1: vpostdiv = 0; break; case 6: pll->pll_ext_cntl |= 0x10; case 4: vpostdiv = 2; break; case 12: pll->pll_ext_cntl |= 0x10; case 8: vpostdiv = 3; break; } pll->pll_vclk_cntl = 0x03; /* VCLK = PLL_VCLK/VCLKx_POST */ pll->vclk_post_div = vpostdiv;}static int aty_var_to_pll_ct(const struct fb_info_aty *info, u32 vclk_per, u8 bpp, struct pll_ct *pll){ int err; if ((err = aty_valid_pll_ct(info, vclk_per, pll))) return err; if (!(Gx == GX_CHIP_ID || Gx == CX_CHIP_ID || Gx == CT_CHIP_ID || Gx == ET_CHIP_ID || ((Gx == VT_CHIP_ID || Gx == GT_CHIP_ID) && !(Rev & 0x07)))) { if ((err = aty_dsp_gt(info, bpp, pll))) return err; } aty_calc_pll_ct(info, pll); return 0;}static u32 aty_pll_ct_to_var(const struct pll_ct *pll, const struct fb_info_aty *info){ u32 ref_clk_per = info->ref_clk_per; u8 pll_ref_div = pll->pll_ref_div; u8 vclk_fb_div = pll->vclk_fb_div; u8 vclk_post_div = pll->vclk_post_div_real; return ref_clk_per*pll_ref_div*vclk_post_div/vclk_fb_div/2;}/* ------------------------------------------------------------------------- */static void atyfb_set_par(const struct atyfb_par *par, struct fb_info_aty *info){ u32 i; int accelmode; int muxmode; u8 tmp; accelmode = par->accel_flags; /* hack */ info->current_par = *par; if (info->blitter_may_be_busy) wait_for_idle(info); tmp = aty_ld_8(CRTC_GEN_CNTL + 3, info); aty_set_crtc(info, &par-
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?