add missing include files for btext console. add YhLu's fixes to ragexl code
[coreboot.git] / src / drivers / ati / ragexl / mach64_ct.c
1 #define DEBUG_PLL 0
2
3 /* FIXME: remove the FAIL definition */
4 #define FAIL(x) do { printk_spew(x); return -EINVAL; } while (0)
5
6 static int aty_valid_pll_ct(const struct fb_info_aty *info, u32 vclk_per,
7                             struct pll_ct *pll);
8 static int aty_dsp_gt(const struct fb_info_aty *info, u32 bpp,
9                       struct pll_ct *pll);
10 static int aty_var_to_pll_ct(const struct fb_info_aty *info, u32 vclk_per,
11                              u8 bpp, union aty_pll *pll);
12 #if 0
13 static u32 aty_pll_ct_to_var(const struct fb_info_aty *info,
14                              const union aty_pll *pll);
15 #endif
16
17 /* ------------------------------------------------------------------------- */
18
19     /*
20      *  PLL programming (Mach64 CT family)
21      */
22 static int aty_dsp_gt(const struct fb_info_aty *info, u32 bpp,
23                       struct pll_ct *pll)
24 {
25     u32 dsp_xclks_per_row, dsp_loop_latency, dsp_precision, dsp_off, dsp_on;
26     u32 xclks_per_row, fifo_off, fifo_on, y, fifo_size;
27     u32 memcntl, n, t_pfc, t_rp, t_ras, t_rcd, t_crd, t_rcc, t_lat;
28
29 #if DEBUG_PLL==1
30     printk_debug("aty_dsp_gt : mclk_fb_mult=%d\n", pll->mclk_fb_mult);
31 #endif
32     
33     /* (64*xclk/vclk/bpp)<<11 = xclocks_per_row<<11 */
34     xclks_per_row = ((u32)pll->mclk_fb_mult * (u32)pll->mclk_fb_div *
35                      (u32)pll->vclk_post_div_real * 64) << 11;
36     xclks_per_row /=
37             (2 * (u32)pll->vclk_fb_div * (u32)pll->xclk_post_div_real * bpp);
38
39     if (xclks_per_row < (1<<11))
40         FAIL("Dotclock too high");
41     if (M64_HAS(FIFO_24)) {
42         fifo_size = 24;
43         dsp_loop_latency = 0;
44     } else {
45         fifo_size = 32;
46         dsp_loop_latency = 2;
47     }
48     dsp_precision = 0;
49     y = (xclks_per_row*fifo_size)>>11;
50     while (y) {
51         y >>= 1;
52         dsp_precision++;
53     }
54     dsp_precision -= 5;
55
56     /* fifo_off<<6 */
57     fifo_off = ((xclks_per_row*(fifo_size-1))>>5); // + (3<<6);
58
59     if (info->total_vram > 1*1024*1024) {
60         switch (info->ram_type) {
61         case WRAM:
62             /* >1 MB WRAM */
63             dsp_loop_latency += 9;
64             n = 4;
65             break;
66         case SDRAM:
67         case SGRAM:
68             /* >1 MB SDRAM */
69             dsp_loop_latency += 8;
70             n = 2;
71             break;
72         default:
73             /* >1 MB DRAM */
74             dsp_loop_latency += 6;
75             n = 3;
76             break;
77         }
78     } else {
79         if (info->ram_type >= SDRAM) {
80             /* <2 MB SDRAM */
81             dsp_loop_latency += 9;
82             n = 2;
83         } else {
84             /* <2 MB DRAM */
85             dsp_loop_latency += 8;
86             n = 3;
87         }
88     }
89
90     memcntl = aty_ld_le32(MEM_CNTL, info);
91     t_rcd = ((memcntl >> 10) & 0x03) + 1;
92     t_crd = ((memcntl >> 12) & 0x01);
93     t_rp  = ((memcntl >>  8) & 0x03) + 1;
94     t_ras = ((memcntl >> 16) & 0x07) + 1;
95     t_lat =  (memcntl >>  4) & 0x03;
96     
97     t_pfc = t_rp + t_rcd + t_crd;
98
99     t_rcc = max(t_rp + t_ras, t_pfc + n);
100     
101     /* fifo_on<<6 */
102     fifo_on = (2 * t_rcc + t_pfc + n - 1) << 6;
103
104     dsp_xclks_per_row = xclks_per_row>>dsp_precision;
105     dsp_on = fifo_on>>dsp_precision;
106     dsp_off = fifo_off>>dsp_precision;
107
108     pll->dsp_config = (dsp_xclks_per_row & 0x3fff) |
109                       ((dsp_loop_latency & 0xf)<<16) |
110                       ((dsp_precision & 7)<<20);
111     pll->dsp_on_off = (dsp_off & 0x7ff) | ((dsp_on & 0x7ff)<<16);
112     return 0;
113 }
114
115
116 static int aty_valid_pll_ct(const struct fb_info_aty *info, u32 vclk_per,
117                             struct pll_ct *pll)
118 {
119 #if DEBUG_PLL==1
120     int pllmclk, pllsclk;
121 #endif
122
123     u32 q, x;                   /* x is a workaround for sparc64-linux-gcc */
124     x = x;                      /* x is a workaround for sparc64-linux-gcc */
125     
126     pll->pll_ref_div = info->pll_per*2*255/info->ref_clk_per;
127     
128     /* FIXME: use the VTB/GTB /3 post divider if it's better suited */
129
130     /* actually 8*q */
131     q = info->ref_clk_per*pll->pll_ref_div*4/info->mclk_per;
132
133     if (q < 16*8 || q > 255*8)
134         FAIL("mclk out of range\n");
135     else if (q < 32*8)
136         pll->mclk_post_div_real = 8;
137     else if (q < 64*8)
138         pll->mclk_post_div_real = 4;
139     else if (q < 128*8)
140         pll->mclk_post_div_real = 2;
141     else
142         pll->mclk_post_div_real = 1;
143     pll->sclk_fb_div = q*pll->mclk_post_div_real/8;
144
145 #if DEBUG_PLL==1    
146     pllsclk = (1000000 * 2 * pll->sclk_fb_div) /
147             (info->ref_clk_per * pll->pll_ref_div);
148
149     printk_debug("aty_valid_pll_ct: pllsclk=%d MHz, mclk=%d MHz\n",
150            pllsclk, pllsclk / pll->mclk_post_div_real);
151 #endif
152     
153     pll->mclk_fb_mult = M64_HAS(MFB_TIMES_4) ? 4 : 2;
154
155     /* actually 8*q */
156     q = info->ref_clk_per * pll->pll_ref_div * 8 /
157             (pll->mclk_fb_mult * info->xclk_per);
158
159     if (q < 16*8 || q > 255*8)
160         FAIL("mclk out of range\n");
161     else if (q < 32*8)
162         pll->xclk_post_div_real = 8;
163     else if (q < 64*8)
164         pll->xclk_post_div_real = 4;
165     else if (q < 128*8)
166         pll->xclk_post_div_real = 2;
167     else
168         pll->xclk_post_div_real = 1;
169     pll->mclk_fb_div = q*pll->xclk_post_div_real/8;
170
171 #if DEBUG_PLL==1
172     pllmclk = (1000000 * pll->mclk_fb_mult * pll->mclk_fb_div) /
173             (info->ref_clk_per * pll->pll_ref_div);
174     printk_debug("aty_valid_pll_ct: pllmclk=%d MHz, xclk=%d MHz\n",
175            pllmclk, pllmclk / pll->xclk_post_div_real);
176 #endif
177     
178     /* FIXME: use the VTB/GTB /{3,6,12} post dividers if they're better suited */
179     q = info->ref_clk_per*pll->pll_ref_div*4/vclk_per;  /* actually 8*q */
180     if (q < 16*8 || q > 255*8)
181         FAIL("vclk out of range\n");
182     else if (q < 32*8)
183         pll->vclk_post_div_real = 8;
184     else if (q < 64*8)
185         pll->vclk_post_div_real = 4;
186     else if (q < 128*8)
187         pll->vclk_post_div_real = 2;
188     else
189         pll->vclk_post_div_real = 1;
190     pll->vclk_fb_div = q*pll->vclk_post_div_real/8;
191     return 0;
192 }
193
194 static void aty_calc_pll_ct(const struct fb_info_aty *info, struct pll_ct *pll)
195 {
196     u8 xpostdiv = 0;
197     u8 mpostdiv = 0;
198     u8 vpostdiv = 0;
199     
200     if (M64_HAS(SDRAM_MAGIC_PLL) && (info->ram_type >= SDRAM))
201             pll->pll_gen_cntl = 0x64; /* mclk = sclk */
202     else
203         pll->pll_gen_cntl = 0xe4; /* mclk = sclk */
204
205     switch (pll->mclk_post_div_real) {
206         case 1:
207             mpostdiv = 0;
208             break;
209         case 2:
210             mpostdiv = 1;
211             break;
212         case 4:
213             mpostdiv = 2;
214             break;
215         case 8:
216             mpostdiv = 3;
217             break;
218     }
219
220     pll->spll_cntl2 = mpostdiv << 4; /* sclk == pllsclk / mpostdiv */
221     
222     switch (pll->xclk_post_div_real) {
223         case 1:
224             xpostdiv = 0;
225             break;
226         case 2:
227             xpostdiv = 1;
228             break;
229         case 3:
230             xpostdiv = 4;
231             break;
232         case 4:
233             xpostdiv = 2;
234             break;
235         case 8:
236             xpostdiv = 3;
237             break;
238     }
239
240     if (M64_HAS(MAGIC_POSTDIV))
241         pll->pll_ext_cntl = 0;
242     else
243         pll->pll_ext_cntl = xpostdiv;   /* xclk == pllmclk / xpostdiv */
244
245     if (pll->mclk_fb_mult == 4)
246             pll->pll_ext_cntl |= 0x08;
247
248     switch (pll->vclk_post_div_real) {
249         case 2:
250             vpostdiv = 1;
251             break;
252         case 3:
253             pll->pll_ext_cntl |= 0x10;
254         case 1:
255             vpostdiv = 0;
256             break;
257         case 6:
258             pll->pll_ext_cntl |= 0x10;
259         case 4:
260             vpostdiv = 2;
261             break;
262         case 12:
263             pll->pll_ext_cntl |= 0x10;
264         case 8:
265             vpostdiv = 3;
266             break;
267     }
268
269     pll->pll_vclk_cntl = 0x03;  /* VCLK = PLL_VCLK/VCLKx_POST */
270     pll->vclk_post_div = vpostdiv;
271 }
272
273 int aty_var_to_pll_ct(const struct fb_info_aty *info, u32 vclk_per,
274                              u8 bpp, union aty_pll *pll)
275 {
276     int err;
277     if ((err = aty_valid_pll_ct(info, vclk_per, &pll->ct)))
278         return err;
279     if (M64_HAS(GTB_DSP) && (err = aty_dsp_gt(info, bpp, &pll->ct)))
280         return err;
281     aty_calc_pll_ct(info, &pll->ct);
282     return 0;
283 }
284 #if 0
285 u32 aty_pll_ct_to_var(const struct fb_info_aty *info,
286                              const union aty_pll *pll)
287 {
288     u32 ref_clk_per = info->ref_clk_per;
289     u8 pll_ref_div = pll->ct.pll_ref_div;
290     u8 vclk_fb_div = pll->ct.vclk_fb_div;
291     u8 vclk_post_div = pll->ct.vclk_post_div_real;
292
293     return ref_clk_per*pll_ref_div*vclk_post_div/vclk_fb_div/2;
294 }
295 #endif
296 void aty_set_pll_ct(const struct fb_info_aty *info, const union aty_pll *pll)
297 {
298 #if DEBUG_PLL==1
299     printk_debug("aty_set_pll_ct: about to program:\n"
300            "refdiv=%d, extcntl=0x%02x, mfbdiv=%d\n"
301            "spllcntl2=0x%02x, sfbdiv=%d, gencntl=0x%02x\n"
302            "vclkcntl=0x%02x, vpostdiv=0x%02x, vfbdiv=%d\n"
303            "clocksel=%d\n",
304            pll->ct.pll_ref_div, pll->ct.pll_ext_cntl,
305            pll->ct.mclk_fb_div, pll->ct.spll_cntl2,
306            pll->ct.sclk_fb_div, pll->ct.pll_gen_cntl,
307            pll->ct.pll_vclk_cntl, pll->ct.vclk_post_div,
308            pll->ct.vclk_fb_div, aty_ld_le32(CLOCK_CNTL, info) & 0x03);
309 #endif
310
311     aty_st_pll(PLL_REF_DIV, pll->ct.pll_ref_div, info);
312
313     aty_st_pll(PLL_EXT_CNTL, pll->ct.pll_ext_cntl, info);
314     aty_st_pll(MCLK_FB_DIV, pll->ct.mclk_fb_div, info); // for XCLK
315     
316     aty_st_pll(SPLL_CNTL2, pll->ct.spll_cntl2, info);
317     aty_st_pll(SCLK_FB_DIV, pll->ct.sclk_fb_div, info); // for MCLK
318
319     aty_st_pll(PLL_GEN_CNTL, pll->ct.pll_gen_cntl, info);
320     
321     aty_st_pll(EXT_VPLL_CNTL, 0, info);
322     aty_st_pll(PLL_VCLK_CNTL, pll->ct.pll_vclk_cntl, info);
323     aty_st_pll(VCLK_POST_DIV, pll->ct.vclk_post_div, info);
324     aty_st_pll(VCLK0_FB_DIV, pll->ct.vclk_fb_div, info);
325
326     if (M64_HAS(GTB_DSP)) {
327         u8 dll_cntl;
328
329         if (M64_HAS(XL_DLL))
330             dll_cntl = 0x80;
331         else if (info->ram_type >= SDRAM)
332             dll_cntl = 0xa6;
333         else
334             dll_cntl = 0xa0;
335         aty_st_pll(DLL_CNTL, dll_cntl, info);
336         aty_st_pll(VFC_CNTL, 0x1b, info);
337         aty_st_le32(DSP_CONFIG, pll->ct.dsp_config, info);
338         aty_st_le32(DSP_ON_OFF, pll->ct.dsp_on_off, info);
339
340         mdelay(10);
341         aty_st_pll(DLL_CNTL, dll_cntl, info);
342         mdelay(10);
343         aty_st_pll(DLL_CNTL, dll_cntl | 0x40, info);
344         mdelay(10);
345         aty_st_pll(DLL_CNTL, dll_cntl & ~0x40, info);
346     }
347 }
348 #if 0
349 static int dummy(void)
350 {
351     return 0;
352 }
353 static  struct aty_dac_ops aty_dac_ct = {
354     set_dac:    (void *)dummy,
355 };
356
357 static struct aty_pll_ops aty_pll_ct = {
358     var_to_pll: aty_var_to_pll_ct,
359 #if 0
360     pll_to_var: aty_pll_ct_to_var,
361     set_pll:    aty_set_pll_ct,
362 #endif
363 };
364 #endif