ca5283de27eb757e8ba4d315e514b0a28e550ee6
[coreboot.git] / src / drivers / ati / ragexl / mach64_ct.c
1 #define DEBUG_PLL 0
2 #define PLL_CRTC_DECODE 0
3
4 /* FIXME: remove the FAIL definition */
5 #if 0
6 #define FAIL(x) do { printk(BIOS_DEBUG, x); return -EINVAL; } while (0)
7 #else
8 #define FAIL(x) 
9 #endif
10
11 static int aty_valid_pll_ct(const struct fb_info_aty *info, u32 vclk_per,
12                             struct pll_ct *pll);
13 static int aty_dsp_gt(const struct fb_info_aty *info, u32 bpp,
14                       struct pll_ct *pll);
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);
20 #endif
21
22 /* ------------------------------------------------------------------------- */
23
24     /*
25      *  PLL programming (Mach64 CT family)
26      */
27 static int aty_dsp_gt(const struct fb_info_aty *info, u32 bpp,
28                       struct pll_ct *pll)
29 {
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;
33
34 #if DEBUG_PLL==1
35     printk(BIOS_DEBUG, "aty_dsp_gt : mclk_fb_mult=%d\n", pll->mclk_fb_mult);
36 #endif
37     
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;
41     xclks_per_row /=
42             (2 * (u32)pll->vclk_fb_div * (u32)pll->xclk_post_div_real * bpp);
43
44     if (xclks_per_row < (1<<11))
45         FAIL("Dotclock too high");
46     if (M64_HAS(FIFO_24)) {
47         fifo_size = 24;
48         dsp_loop_latency = 0;
49     } else {
50         fifo_size = 32;
51         dsp_loop_latency = 2;
52     }
53     dsp_precision = 0;
54     y = (xclks_per_row*fifo_size)>>11;
55     while (y) {
56         y >>= 1;
57         dsp_precision++;
58     }
59     dsp_precision -= 5;
60
61     /* fifo_off<<6 */
62     fifo_off = ((xclks_per_row*(fifo_size-1))>>5); // + (3<<6);
63
64     if (info->total_vram > 1*1024*1024) {
65         switch (info->ram_type) {
66         case WRAM:
67             /* >1 MB WRAM */
68             dsp_loop_latency += 9;
69             n = 4;
70             break;
71         case SDRAM:
72         case SGRAM:
73             /* >1 MB SDRAM */
74             dsp_loop_latency += 8;
75             n = 2;
76             break;
77         default:
78             /* >1 MB DRAM */
79             dsp_loop_latency += 6;
80             n = 3;
81             break;
82         }
83     } else {
84         if (info->ram_type >= SDRAM) {
85             /* <2 MB SDRAM */
86             dsp_loop_latency += 9;
87             n = 2;
88         } else {
89             /* <2 MB DRAM */
90             dsp_loop_latency += 8;
91             n = 3;
92         }
93     }
94
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;
101     
102     t_pfc = t_rp + t_rcd + t_crd;
103
104     t_rcc = max(t_rp + t_ras, t_pfc + n);
105     
106     /* fifo_on<<6 */
107     fifo_on = (2 * t_rcc + t_pfc + n - 1) << 6;
108
109     dsp_xclks_per_row = xclks_per_row>>dsp_precision;
110     dsp_on = fifo_on>>dsp_precision;
111     dsp_off = fifo_off>>dsp_precision;
112
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);
117     return 0;
118 }
119
120
121 static int aty_valid_pll_ct(const struct fb_info_aty *info, u32 vclk_per,
122                             struct pll_ct *pll)
123 {
124 #if DEBUG_PLL==1
125     int pllmclk, pllsclk;
126 #endif
127     u32 q;
128     
129     pll->pll_ref_div = info->pll_per*2*255/info->ref_clk_per;
130     
131     /* FIXME: use the VTB/GTB /3 post divider if it's better suited */
132
133     /* actually 8*q */
134     q = info->ref_clk_per*pll->pll_ref_div*4/info->mclk_per;
135
136     if (q < 16*8 || q > 255*8)
137         FAIL("mclk out of range\n");
138     else if (q < 32*8)
139         pll->mclk_post_div_real = 8;
140     else if (q < 64*8)
141         pll->mclk_post_div_real = 4;
142     else if (q < 128*8)
143         pll->mclk_post_div_real = 2;
144     else
145         pll->mclk_post_div_real = 1;
146     pll->sclk_fb_div = q*pll->mclk_post_div_real/8;
147
148 #if DEBUG_PLL==1    
149     pllsclk = (1000000 * 2 * pll->sclk_fb_div) /
150             (info->ref_clk_per * pll->pll_ref_div);
151
152     printk(BIOS_DEBUG, "aty_valid_pll_ct: pllsclk=%d MHz, mclk=%d MHz\n",
153            pllsclk, pllsclk / pll->mclk_post_div_real);
154 #endif
155     
156     pll->mclk_fb_mult = M64_HAS(MFB_TIMES_4) ? 4 : 2;
157
158     /* actually 8*q */
159     q = info->ref_clk_per * pll->pll_ref_div * 8 /
160             (pll->mclk_fb_mult * info->xclk_per);
161
162     if (q < 16*8 || q > 255*8)
163         FAIL("mclk out of range\n");
164     else if (q < 32*8)
165         pll->xclk_post_div_real = 8;
166     else if (q < 64*8)
167         pll->xclk_post_div_real = 4;
168     else if (q < 128*8)
169         pll->xclk_post_div_real = 2;
170     else
171         pll->xclk_post_div_real = 1;
172     pll->mclk_fb_div = q*pll->xclk_post_div_real/8;
173
174 #if DEBUG_PLL==1
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);
179 #endif
180     
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");
185     else if (q < 32*8)
186         pll->vclk_post_div_real = 8;
187     else if (q < 64*8)
188         pll->vclk_post_div_real = 4;
189     else if (q < 128*8)
190         pll->vclk_post_div_real = 2;
191     else
192         pll->vclk_post_div_real = 1;
193     pll->vclk_fb_div = q*pll->vclk_post_div_real/8;
194     return 0;
195 }
196
197 static void aty_calc_pll_ct(const struct fb_info_aty *info, struct pll_ct *pll)
198 {
199     u8 xpostdiv = 0;
200     u8 mpostdiv = 0;
201     u8 vpostdiv = 0;
202     
203     if (M64_HAS(SDRAM_MAGIC_PLL) && (info->ram_type >= SDRAM))
204             pll->pll_gen_cntl = 0x64; /* mclk = sclk */
205     else
206         pll->pll_gen_cntl = 0xe4; /* mclk = sclk */
207
208     switch (pll->mclk_post_div_real) {
209         case 1:
210             mpostdiv = 0;
211             break;
212         case 2:
213             mpostdiv = 1;
214             break;
215         case 4:
216             mpostdiv = 2;
217             break;
218         case 8:
219             mpostdiv = 3;
220             break;
221     }
222
223     pll->spll_cntl2 = mpostdiv << 4; /* sclk == pllsclk / mpostdiv */
224     
225     switch (pll->xclk_post_div_real) {
226         case 1:
227             xpostdiv = 0;
228             break;
229         case 2:
230             xpostdiv = 1;
231             break;
232         case 3:
233             xpostdiv = 4;
234             break;
235         case 4:
236             xpostdiv = 2;
237             break;
238         case 8:
239             xpostdiv = 3;
240             break;
241     }
242
243     if (M64_HAS(MAGIC_POSTDIV))
244         pll->pll_ext_cntl = 0;
245     else
246         pll->pll_ext_cntl = xpostdiv;   /* xclk == pllmclk / xpostdiv */
247
248     if (pll->mclk_fb_mult == 4)
249             pll->pll_ext_cntl |= 0x08;
250
251     switch (pll->vclk_post_div_real) {
252         case 2:
253             vpostdiv = 1;
254             break;
255         case 3:
256             pll->pll_ext_cntl |= 0x10;
257         case 1:
258             vpostdiv = 0;
259             break;
260         case 6:
261             pll->pll_ext_cntl |= 0x10;
262         case 4:
263             vpostdiv = 2;
264             break;
265         case 12:
266             pll->pll_ext_cntl |= 0x10;
267         case 8:
268             vpostdiv = 3;
269             break;
270     }
271
272     pll->pll_vclk_cntl = 0x03;  /* VCLK = PLL_VCLK/VCLKx_POST */
273     pll->vclk_post_div = vpostdiv;
274 }
275
276 int aty_var_to_pll_ct(const struct fb_info_aty *info, u32 vclk_per,
277                              u8 bpp, union aty_pll *pll)
278 {
279     int err;
280     if ((err = aty_valid_pll_ct(info, vclk_per, &pll->ct)))
281         return err;
282     if (M64_HAS(GTB_DSP) && (err = aty_dsp_gt(info, bpp, &pll->ct)))
283         return err;
284     aty_calc_pll_ct(info, &pll->ct);
285     return 0;
286 }
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)
291 {
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;
296
297     return ref_clk_per*pll_ref_div*vclk_post_div/vclk_fb_div/2;
298 }
299 #endif
300 void aty_set_pll_ct(const struct fb_info_aty *info, const union aty_pll *pll)
301 {
302 #if DEBUG_PLL==1
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"
307            "clocksel=%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);
313 #endif
314
315     aty_st_pll(PLL_REF_DIV, pll->ct.pll_ref_div, info);
316
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
319     
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
322
323     aty_st_pll(PLL_GEN_CNTL, pll->ct.pll_gen_cntl, info);
324     
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);
329
330     if (M64_HAS(GTB_DSP)) {
331         u8 dll_cntl;
332
333         if (M64_HAS(XL_DLL))
334             dll_cntl = 0x80;
335         else if (info->ram_type >= SDRAM)
336             dll_cntl = 0xa6;
337         else
338             dll_cntl = 0xa0;
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);
343
344         mdelay(10);
345         aty_st_pll(DLL_CNTL, dll_cntl, info);
346         mdelay(10);
347         aty_st_pll(DLL_CNTL, dll_cntl | 0x40, info);
348         mdelay(10);
349         aty_st_pll(DLL_CNTL, dll_cntl & ~0x40, info);
350     }
351 }
352 #if 0
353 static int dummy(void)
354 {
355     return 0;
356 }
357 static  struct aty_dac_ops aty_dac_ct = {
358     set_dac:    (void *)dummy,
359 };
360
361 static struct aty_pll_ops aty_pll_ct = {
362     var_to_pll: aty_var_to_pll_ct,
363 #if 0
364     pll_to_var: aty_pll_ct_to_var,
365     set_pll:    aty_set_pll_ct,
366 #endif
367 };
368 #endif
369
370 #endif /* CONFIG_CONSOLE_BTEXT */