--- zzzz-none-000/linux-2.4.17/drivers/video/aty/mach64_ct.c 2001-07-31 21:43:29.000000000 +0000 +++ sangam-fb-322/linux-2.4.17/drivers/video/aty/mach64_ct.c 2004-11-24 13:23:13.000000000 +0000 @@ -4,6 +4,7 @@ */ #include +#include #include @@ -12,15 +13,14 @@ #include "mach64.h" #include "atyfb.h" +#undef DEBUG /* FIXME: remove the FAIL definition */ #define FAIL(x) do { printk(x "\n"); return -EINVAL; } while (0) -static void aty_st_pll(int offset, u8 val, const struct fb_info_aty *info); - static int aty_valid_pll_ct(const struct fb_info_aty *info, u32 vclk_per, struct pll_ct *pll); -static int aty_dsp_gt(const struct fb_info_aty *info, u8 bpp, +static int aty_dsp_gt(const struct fb_info_aty *info, u32 bpp, struct pll_ct *pll); static int aty_var_to_pll_ct(const struct fb_info_aty *info, u32 vclk_per, u8 bpp, union aty_pll *pll); @@ -28,34 +28,30 @@ const union aty_pll *pll); - -static void aty_st_pll(int offset, u8 val, const struct fb_info_aty *info) -{ - /* write addr byte */ - aty_st_8(CLOCK_CNTL + 1, (offset << 2) | PLL_WR_EN, info); - /* write the register value */ - aty_st_8(CLOCK_CNTL + 2, val, info); - aty_st_8(CLOCK_CNTL + 1, (offset << 2) & ~PLL_WR_EN, info); -} - - /* ------------------------------------------------------------------------- */ /* * PLL programming (Mach64 CT family) */ - -static int aty_dsp_gt(const struct fb_info_aty *info, u8 bpp, +static int aty_dsp_gt(const struct fb_info_aty *info, u32 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; + u32 xclks_per_row, fifo_off, fifo_on, y, fifo_size; + u32 memcntl, n, t_pfc, t_rp, t_ras, t_rcd, t_crd, t_rcc, t_lat; + +#ifdef DEBUG + printk(__FUNCTION__ ": mclk_fb_mult=%d\n", pll->mclk_fb_mult); +#endif + + /* (64*xclk/vclk/bpp)<<11 = xclocks_per_row<<11 */ + xclks_per_row = ((u32)pll->mclk_fb_mult * (u32)pll->mclk_fb_div * + (u32)pll->vclk_post_div_real * 64) << 11; + xclks_per_row /= + (2 * (u32)pll->vclk_fb_div * (u32)pll->xclk_post_div_real * bpp); - /* 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"); + FAIL("Dotclock too high"); if (M64_HAS(FIFO_24)) { fifo_size = 24; dsp_loop_latency = 0; @@ -70,35 +66,54 @@ dsp_precision++; } dsp_precision -= 5; + /* fifo_off<<6 */ - fifo_off = ((xclks_per_row*(fifo_size-1))>>5)+(3<<6); + fifo_off = ((xclks_per_row*(fifo_size-1))>>5); // + (3<<6); if (info->total_vram > 1*1024*1024) { - if (info->ram_type >= SDRAM) { + switch (info->ram_type) { + case WRAM: + /* >1 MB WRAM */ + dsp_loop_latency += 9; + n = 4; + break; + case SDRAM: + case SGRAM: /* >1 MB SDRAM */ dsp_loop_latency += 8; - page_size = 8; - } else { + n = 2; + break; + default: /* >1 MB DRAM */ dsp_loop_latency += 6; - page_size = 9; + n = 3; + break; } } else { if (info->ram_type >= SDRAM) { /* <2 MB SDRAM */ dsp_loop_latency += 9; - page_size = 10; + n = 2; } else { /* <2 MB DRAM */ dsp_loop_latency += 8; - page_size = 10; + n = 3; } } + + memcntl = aty_ld_le32(MEM_CNTL, info); + t_rcd = ((memcntl >> 10) & 0x03) + 1; + t_crd = ((memcntl >> 12) & 0x01); + t_rp = ((memcntl >> 8) & 0x03) + 1; + t_ras = ((memcntl >> 16) & 0x07) + 1; + t_lat = (memcntl >> 4) & 0x03; + + t_pfc = t_rp + t_rcd + t_crd; + + t_rcc = max(t_rp + t_ras, t_pfc + n); + /* 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; + fifo_on = (2 * t_rcc + t_pfc + n - 1) << 6; dsp_xclks_per_row = xclks_per_row>>dsp_precision; dsp_on = fifo_on>>dsp_precision; @@ -107,20 +122,27 @@ 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); + pll->dsp_on_off = (dsp_off & 0x7ff) | ((dsp_on & 0x7ff)<<16); return 0; } + static int aty_valid_pll_ct(const struct fb_info_aty *info, u32 vclk_per, struct pll_ct *pll) { +#ifdef DEBUG + int pllmclk, pllsclk; +#endif 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 */ + + /* actually 8*q */ + q = info->ref_clk_per*pll->pll_ref_div*4/info->mclk_per; + if (q < 16*8 || q > 255*8) FAIL("mclk out of range"); else if (q < 32*8) @@ -131,8 +153,40 @@ pll->mclk_post_div_real = 2; else pll->mclk_post_div_real = 1; - pll->mclk_fb_div = q*pll->mclk_post_div_real/8; + pll->sclk_fb_div = q*pll->mclk_post_div_real/8; + +#ifdef DEBUG + pllsclk = (1000000 * 2 * pll->sclk_fb_div) / + (info->ref_clk_per * pll->pll_ref_div); + printk(__FUNCTION__ ": pllsclk=%d MHz, mclk=%d MHz\n", + pllsclk, pllsclk / pll->mclk_post_div_real); +#endif + + pll->mclk_fb_mult = M64_HAS(MFB_TIMES_4) ? 4 : 2; + + /* actually 8*q */ + q = info->ref_clk_per * pll->pll_ref_div * 8 / + (pll->mclk_fb_mult * info->xclk_per); + if (q < 16*8 || q > 255*8) + FAIL("mclk out of range"); + else if (q < 32*8) + pll->xclk_post_div_real = 8; + else if (q < 64*8) + pll->xclk_post_div_real = 4; + else if (q < 128*8) + pll->xclk_post_div_real = 2; + else + pll->xclk_post_div_real = 1; + pll->mclk_fb_div = q*pll->xclk_post_div_real/8; + +#ifdef DEBUG + pllmclk = (1000000 * pll->mclk_fb_mult * pll->mclk_fb_div) / + (info->ref_clk_per * pll->pll_ref_div); + printk(__FUNCTION__ ": pllmclk=%d MHz, xclk=%d MHz\n", + pllmclk, pllmclk / pll->xclk_post_div_real); +#endif + /* 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) @@ -151,13 +205,14 @@ void aty_calc_pll_ct(const struct fb_info_aty *info, struct pll_ct *pll) { + u8 xpostdiv = 0; u8 mpostdiv = 0; u8 vpostdiv = 0; - + if (M64_HAS(SDRAM_MAGIC_PLL) && (info->ram_type >= SDRAM)) - pll->pll_gen_cntl = 0x04; + pll->pll_gen_cntl = 0x64; /* mclk = sclk */ else - pll->pll_gen_cntl = 0x84; + pll->pll_gen_cntl = 0xe4; /* mclk = sclk */ switch (pll->mclk_post_div_real) { case 1: @@ -166,9 +221,6 @@ case 2: mpostdiv = 1; break; - case 3: - mpostdiv = 4; - break; case 4: mpostdiv = 2; break; @@ -176,12 +228,34 @@ mpostdiv = 3; break; } - pll->pll_gen_cntl |= mpostdiv<<4; /* mclk */ + + pll->spll_cntl2 = mpostdiv << 4; /* sclk == pllsclk / mpostdiv */ + + switch (pll->xclk_post_div_real) { + case 1: + xpostdiv = 0; + break; + case 2: + xpostdiv = 1; + break; + case 3: + xpostdiv = 4; + break; + case 4: + xpostdiv = 2; + break; + case 8: + xpostdiv = 3; + break; + } if (M64_HAS(MAGIC_POSTDIV)) pll->pll_ext_cntl = 0; else - pll->pll_ext_cntl = mpostdiv; /* xclk == mclk */ + pll->pll_ext_cntl = xpostdiv; /* xclk == pllmclk / xpostdiv */ + + if (pll->mclk_fb_mult == 4) + pll->pll_ext_cntl |= 0x08; switch (pll->vclk_post_div_real) { case 2: @@ -234,24 +308,54 @@ void aty_set_pll_ct(const struct fb_info_aty *info, const union aty_pll *pll) { +#ifdef DEBUG + printk(__FUNCTION__ ": about to program:\n" + "refdiv=%d, extcntl=0x%02x, mfbdiv=%d\n" + "spllcntl2=0x%02x, sfbdiv=%d, gencntl=0x%02x\n" + "vclkcntl=0x%02x, vpostdiv=0x%02x, vfbdiv=%d\n" + "clocksel=%d\n", + pll->ct.pll_ref_div, pll->ct.pll_ext_cntl, + pll->ct.mclk_fb_div, pll->ct.spll_cntl2, + pll->ct.sclk_fb_div, pll->ct.pll_gen_cntl, + pll->ct.pll_vclk_cntl, pll->ct.vclk_post_div, + pll->ct.vclk_fb_div, aty_ld_le32(CLOCK_CNTL, info) & 0x03); +#endif + aty_st_pll(PLL_REF_DIV, pll->ct.pll_ref_div, info); + + aty_st_pll(PLL_EXT_CNTL, pll->ct.pll_ext_cntl, info); + aty_st_pll(MCLK_FB_DIV, pll->ct.mclk_fb_div, info); // for XCLK + + aty_st_pll(SPLL_CNTL2, pll->ct.spll_cntl2, info); + aty_st_pll(SCLK_FB_DIV, pll->ct.sclk_fb_div, info); // for MCLK + aty_st_pll(PLL_GEN_CNTL, pll->ct.pll_gen_cntl, info); - aty_st_pll(MCLK_FB_DIV, pll->ct.mclk_fb_div, info); + + aty_st_pll(EXT_VPLL_CNTL, 0, info); aty_st_pll(PLL_VCLK_CNTL, pll->ct.pll_vclk_cntl, info); aty_st_pll(VCLK_POST_DIV, pll->ct.vclk_post_div, info); aty_st_pll(VCLK0_FB_DIV, pll->ct.vclk_fb_div, info); - aty_st_pll(PLL_EXT_CNTL, pll->ct.pll_ext_cntl, info); if (M64_HAS(GTB_DSP)) { + u8 dll_cntl; + if (M64_HAS(XL_DLL)) - aty_st_pll(DLL_CNTL, 0x80, info); + dll_cntl = 0x80; else if (info->ram_type >= SDRAM) - aty_st_pll(DLL_CNTL, 0xa6, info); + dll_cntl = 0xa6; else - aty_st_pll(DLL_CNTL, 0xa0, info); + dll_cntl = 0xa0; + aty_st_pll(DLL_CNTL, dll_cntl, info); aty_st_pll(VFC_CNTL, 0x1b, info); aty_st_le32(DSP_CONFIG, pll->ct.dsp_config, info); aty_st_le32(DSP_ON_OFF, pll->ct.dsp_on_off, info); + + mdelay(10); + aty_st_pll(DLL_CNTL, dll_cntl, info); + mdelay(10); + aty_st_pll(DLL_CNTL, dll_cntl | 0x40, info); + mdelay(10); + aty_st_pll(DLL_CNTL, dll_cntl & ~0x40, info); } }