2 #define PLL_CRTC_DECODE 0
4 /* FIXME: remove the FAIL definition */
6 #define FAIL(x) do { printk(BIOS_DEBUG, x); return -EINVAL; } while (0)
11 static int aty_valid_pll_ct(const struct fb_info_aty *info, u32 vclk_per,
13 static int aty_dsp_gt(const struct fb_info_aty *info, u32 bpp,
15 static int aty_var_to_pll_ct(const struct fb_info_aty *info, u32 vclk_per,
16 u8 bpp, union aty_pll *pll);
17 #if PLL_CRTC_DECODE==1
18 static u32 aty_pll_ct_to_var(const struct fb_info_aty *info,
19 const union aty_pll *pll);
22 /* ------------------------------------------------------------------------- */
25 * PLL programming (Mach64 CT family)
27 static int aty_dsp_gt(const struct fb_info_aty *info, u32 bpp,
30 u32 dsp_xclks_per_row, dsp_loop_latency, dsp_precision, dsp_off, dsp_on;
31 u32 xclks_per_row, fifo_off, fifo_on, y, fifo_size;
32 u32 memcntl, n, t_pfc, t_rp, t_ras, t_rcd, t_crd, t_rcc, t_lat;
35 printk(BIOS_DEBUG, "aty_dsp_gt : mclk_fb_mult=%d\n", pll->mclk_fb_mult);
38 /* (64*xclk/vclk/bpp)<<11 = xclocks_per_row<<11 */
39 xclks_per_row = ((u32)pll->mclk_fb_mult * (u32)pll->mclk_fb_div *
40 (u32)pll->vclk_post_div_real * 64) << 11;
42 (2 * (u32)pll->vclk_fb_div * (u32)pll->xclk_post_div_real * bpp);
44 if (xclks_per_row < (1<<11))
45 FAIL("Dotclock too high");
46 if (M64_HAS(FIFO_24)) {
54 y = (xclks_per_row*fifo_size)>>11;
62 fifo_off = ((xclks_per_row*(fifo_size-1))>>5); // + (3<<6);
64 if (info->total_vram > 1*1024*1024) {
65 switch (info->ram_type) {
68 dsp_loop_latency += 9;
74 dsp_loop_latency += 8;
79 dsp_loop_latency += 6;
84 if (info->ram_type >= SDRAM) {
86 dsp_loop_latency += 9;
90 dsp_loop_latency += 8;
95 memcntl = aty_ld_le32(MEM_CNTL, info);
96 t_rcd = ((memcntl >> 10) & 0x03) + 1;
97 t_crd = ((memcntl >> 12) & 0x01);
98 t_rp = ((memcntl >> 8) & 0x03) + 1;
99 t_ras = ((memcntl >> 16) & 0x07) + 1;
100 t_lat = (memcntl >> 4) & 0x03;
102 t_pfc = t_rp + t_rcd + t_crd;
104 t_rcc = max(t_rp + t_ras, t_pfc + n);
107 fifo_on = (2 * t_rcc + t_pfc + n - 1) << 6;
109 dsp_xclks_per_row = xclks_per_row>>dsp_precision;
110 dsp_on = fifo_on>>dsp_precision;
111 dsp_off = fifo_off>>dsp_precision;
113 pll->dsp_config = (dsp_xclks_per_row & 0x3fff) |
114 ((dsp_loop_latency & 0xf)<<16) |
115 ((dsp_precision & 7)<<20);
116 pll->dsp_on_off = (dsp_off & 0x7ff) | ((dsp_on & 0x7ff)<<16);
121 static int aty_valid_pll_ct(const struct fb_info_aty *info, u32 vclk_per,
125 int pllmclk, pllsclk;
129 pll->pll_ref_div = info->pll_per*2*255/info->ref_clk_per;
131 /* FIXME: use the VTB/GTB /3 post divider if it's better suited */
134 q = info->ref_clk_per*pll->pll_ref_div*4/info->mclk_per;
136 if (q < 16*8 || q > 255*8)
137 FAIL("mclk out of range\n");
139 pll->mclk_post_div_real = 8;
141 pll->mclk_post_div_real = 4;
143 pll->mclk_post_div_real = 2;
145 pll->mclk_post_div_real = 1;
146 pll->sclk_fb_div = q*pll->mclk_post_div_real/8;
149 pllsclk = (1000000 * 2 * pll->sclk_fb_div) /
150 (info->ref_clk_per * pll->pll_ref_div);
152 printk(BIOS_DEBUG, "aty_valid_pll_ct: pllsclk=%d MHz, mclk=%d MHz\n",
153 pllsclk, pllsclk / pll->mclk_post_div_real);
156 pll->mclk_fb_mult = M64_HAS(MFB_TIMES_4) ? 4 : 2;
159 q = info->ref_clk_per * pll->pll_ref_div * 8 /
160 (pll->mclk_fb_mult * info->xclk_per);
162 if (q < 16*8 || q > 255*8)
163 FAIL("mclk out of range\n");
165 pll->xclk_post_div_real = 8;
167 pll->xclk_post_div_real = 4;
169 pll->xclk_post_div_real = 2;
171 pll->xclk_post_div_real = 1;
172 pll->mclk_fb_div = q*pll->xclk_post_div_real/8;
175 pllmclk = (1000000 * pll->mclk_fb_mult * pll->mclk_fb_div) /
176 (info->ref_clk_per * pll->pll_ref_div);
177 printk(BIOS_DEBUG, "aty_valid_pll_ct: pllmclk=%d MHz, xclk=%d MHz\n",
178 pllmclk, pllmclk / pll->xclk_post_div_real);
181 /* FIXME: use the VTB/GTB /{3,6,12} post dividers if they're better suited */
182 q = info->ref_clk_per*pll->pll_ref_div*4/vclk_per; /* actually 8*q */
183 if (q < 16*8 || q > 255*8)
184 FAIL("vclk out of range\n");
186 pll->vclk_post_div_real = 8;
188 pll->vclk_post_div_real = 4;
190 pll->vclk_post_div_real = 2;
192 pll->vclk_post_div_real = 1;
193 pll->vclk_fb_div = q*pll->vclk_post_div_real/8;
197 static void aty_calc_pll_ct(const struct fb_info_aty *info, struct pll_ct *pll)
203 if (M64_HAS(SDRAM_MAGIC_PLL) && (info->ram_type >= SDRAM))
204 pll->pll_gen_cntl = 0x64; /* mclk = sclk */
206 pll->pll_gen_cntl = 0xe4; /* mclk = sclk */
208 switch (pll->mclk_post_div_real) {
223 pll->spll_cntl2 = mpostdiv << 4; /* sclk == pllsclk / mpostdiv */
225 switch (pll->xclk_post_div_real) {
243 if (M64_HAS(MAGIC_POSTDIV))
244 pll->pll_ext_cntl = 0;
246 pll->pll_ext_cntl = xpostdiv; /* xclk == pllmclk / xpostdiv */
248 if (pll->mclk_fb_mult == 4)
249 pll->pll_ext_cntl |= 0x08;
251 switch (pll->vclk_post_div_real) {
256 pll->pll_ext_cntl |= 0x10;
261 pll->pll_ext_cntl |= 0x10;
266 pll->pll_ext_cntl |= 0x10;
272 pll->pll_vclk_cntl = 0x03; /* VCLK = PLL_VCLK/VCLKx_POST */
273 pll->vclk_post_div = vpostdiv;
276 int aty_var_to_pll_ct(const struct fb_info_aty *info, u32 vclk_per,
277 u8 bpp, union aty_pll *pll)
280 if ((err = aty_valid_pll_ct(info, vclk_per, &pll->ct)))
282 if (M64_HAS(GTB_DSP) && (err = aty_dsp_gt(info, bpp, &pll->ct)))
284 aty_calc_pll_ct(info, &pll->ct);
287 #if CONFIG_CONSOLE_BTEXT==1
288 #if PLL_CRTC_DECODE==1
289 u32 aty_pll_ct_to_var(const struct fb_info_aty *info,
290 const union aty_pll *pll)
292 u32 ref_clk_per = info->ref_clk_per;
293 u8 pll_ref_div = pll->ct.pll_ref_div;
294 u8 vclk_fb_div = pll->ct.vclk_fb_div;
295 u8 vclk_post_div = pll->ct.vclk_post_div_real;
297 return ref_clk_per*pll_ref_div*vclk_post_div/vclk_fb_div/2;
300 void aty_set_pll_ct(const struct fb_info_aty *info, const union aty_pll *pll)
303 printk(BIOS_DEBUG, "aty_set_pll_ct: about to program:\n"
304 "refdiv=%d, extcntl=0x%02x, mfbdiv=%d\n"
305 "spllcntl2=0x%02x, sfbdiv=%d, gencntl=0x%02x\n"
306 "vclkcntl=0x%02x, vpostdiv=0x%02x, vfbdiv=%d\n"
308 pll->ct.pll_ref_div, pll->ct.pll_ext_cntl,
309 pll->ct.mclk_fb_div, pll->ct.spll_cntl2,
310 pll->ct.sclk_fb_div, pll->ct.pll_gen_cntl,
311 pll->ct.pll_vclk_cntl, pll->ct.vclk_post_div,
312 pll->ct.vclk_fb_div, aty_ld_le32(CLOCK_CNTL, info) & 0x03);
315 aty_st_pll(PLL_REF_DIV, pll->ct.pll_ref_div, info);
317 aty_st_pll(PLL_EXT_CNTL, pll->ct.pll_ext_cntl, info);
318 aty_st_pll(MCLK_FB_DIV, pll->ct.mclk_fb_div, info); // for XCLK
320 aty_st_pll(SPLL_CNTL2, pll->ct.spll_cntl2, info);
321 aty_st_pll(SCLK_FB_DIV, pll->ct.sclk_fb_div, info); // for MCLK
323 aty_st_pll(PLL_GEN_CNTL, pll->ct.pll_gen_cntl, info);
325 aty_st_pll(EXT_VPLL_CNTL, 0, info);
326 aty_st_pll(PLL_VCLK_CNTL, pll->ct.pll_vclk_cntl, info);
327 aty_st_pll(VCLK_POST_DIV, pll->ct.vclk_post_div, info);
328 aty_st_pll(VCLK0_FB_DIV, pll->ct.vclk_fb_div, info);
330 if (M64_HAS(GTB_DSP)) {
335 else if (info->ram_type >= SDRAM)
339 aty_st_pll(DLL_CNTL, dll_cntl, info);
340 aty_st_pll(VFC_CNTL, 0x1b, info);
341 aty_st_le32(DSP_CONFIG, pll->ct.dsp_config, info);
342 aty_st_le32(DSP_ON_OFF, pll->ct.dsp_on_off, info);
345 aty_st_pll(DLL_CNTL, dll_cntl, info);
347 aty_st_pll(DLL_CNTL, dll_cntl | 0x40, info);
349 aty_st_pll(DLL_CNTL, dll_cntl & ~0x40, info);
353 static int dummy(void)
357 static struct aty_dac_ops aty_dac_ct = {
358 set_dac: (void *)dummy,
361 static struct aty_pll_ops aty_pll_ct = {
362 var_to_pll: aty_var_to_pll_ct,
364 pll_to_var: aty_pll_ct_to_var,
365 set_pll: aty_set_pll_ct,
370 #endif /* CONFIG_CONSOLE_BTEXT */