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