Merge master.kernel.org:/pub/scm/linux/kernel/git/davem/sparc-2.6
[linux-2.6] / drivers / video / i810 / i810_gtf.c
1 /*-*- linux-c -*-
2  *  linux/drivers/video/i810_main.h -- Intel 810 Non-discrete Video Timings 
3  *                                     (VESA GTF)
4  *
5  *      Copyright (C) 2001 Antonino Daplas<adaplas@pol.net>
6  *      All Rights Reserved      
7  *
8  *
9  *  This file is subject to the terms and conditions of the GNU General Public
10  *  License. See the file COPYING in the main directory of this archive for
11  *  more details.
12  */
13 #include <linux/kernel.h>
14
15 #include "i810_regs.h"
16 #include "i810.h"
17 #include "i810_main.h"
18
19 /*
20  * FIFO and Watermark tables - based almost wholly on i810_wmark.c in 
21  * XFree86 v4.03 by Precision Insight.  Slightly modified for integer 
22  * operation, instead of float
23  */
24
25 struct wm_info {
26    u32 freq;
27    u32  wm;
28 };
29
30 static struct wm_info i810_wm_8_100[] = {
31         { 15, 0x0070c000 },  { 19, 0x0070c000 },  { 25, 0x22003000 },
32         { 28, 0x22003000 },  { 31, 0x22003000 },  { 36, 0x22007000 },
33         { 40, 0x22007000 },  { 45, 0x22007000 },  { 49, 0x22008000 },
34         { 50, 0x22008000 },  { 56, 0x22008000 },  { 65, 0x22008000 },
35         { 75, 0x22008000 },  { 78, 0x22008000 },  { 80, 0x22008000 },
36         { 94, 0x22008000 },  { 96, 0x22107000 },  { 99, 0x22107000 },
37         { 108, 0x22107000 }, { 121, 0x22107000 }, { 128, 0x22107000 },
38         { 132, 0x22109000 }, { 135, 0x22109000 }, { 157, 0x2210b000 },
39         { 162, 0x2210b000 }, { 175, 0x2210b000 }, { 189, 0x2220e000 },
40         { 195, 0x2220e000 }, { 202, 0x2220e000 }, { 204, 0x2220e000 },
41         { 218, 0x2220f000 }, { 229, 0x22210000 }, { 234, 0x22210000 }, 
42 };
43
44 static struct wm_info i810_wm_16_100[] = {
45         { 15, 0x0070c000 },  { 19, 0x0020c000 },  { 25, 0x22006000 },
46         { 28, 0x22006000 },  { 31, 0x22007000 },  { 36, 0x22007000 },
47         { 40, 0x22007000 },  { 45, 0x22007000 },  { 49, 0x22009000 },
48         { 50, 0x22009000 },  { 56, 0x22108000 },  { 65, 0x2210e000 },
49         { 75, 0x2210e000 },  { 78, 0x2210e000 },  { 80, 0x22210000 },
50         { 94, 0x22210000 },  { 96, 0x22210000 },  { 99, 0x22210000 },
51         { 108, 0x22210000 }, { 121, 0x22210000 }, { 128, 0x22210000 },
52         { 132, 0x22314000 }, { 135, 0x22314000 }, { 157, 0x22415000 },
53         { 162, 0x22416000 }, { 175, 0x22416000 }, { 189, 0x22416000 },
54         { 195, 0x22416000 }, { 202, 0x22416000 }, { 204, 0x22416000 },
55         { 218, 0x22416000 }, { 229, 0x22416000 },
56 };
57
58 static struct wm_info i810_wm_24_100[] = {
59         { 15, 0x0020c000 },  { 19, 0x0040c000 },  { 25, 0x22009000 },
60         { 28, 0x22009000 },  { 31, 0x2200a000 },  { 36, 0x2210c000 },
61         { 40, 0x2210c000 },  { 45, 0x2210c000 },  { 49, 0x22111000 },
62         { 50, 0x22111000 },  { 56, 0x22111000 },  { 65, 0x22214000 },
63         { 75, 0x22214000 },  { 78, 0x22215000 },  { 80, 0x22216000 },
64         { 94, 0x22218000 },  { 96, 0x22418000 },  { 99, 0x22418000 },
65         { 108, 0x22418000 }, { 121, 0x22418000 }, { 128, 0x22419000 },
66         { 132, 0x22519000 }, { 135, 0x4441d000 }, { 157, 0x44419000 },
67         { 162, 0x44419000 }, { 175, 0x44419000 }, { 189, 0x44419000 },
68         { 195, 0x44419000 }, { 202, 0x44419000 }, { 204, 0x44419000 },
69 };
70
71 static struct wm_info i810_wm_8_133[] = {
72         { 15, 0x0070c000 },  { 19, 0x0070c000 },  { 25, 0x22003000 },
73         { 28, 0x22003000 },  { 31, 0x22003000 },  { 36, 0x22007000 },
74         { 40, 0x22007000 },  { 45, 0x22007000 },  { 49, 0x22008000 },
75         { 50, 0x22008000 },  { 56, 0x22008000 },  { 65, 0x22008000 },
76         { 75, 0x22008000 },  { 78, 0x22008000 },  { 80, 0x22008000 },
77         { 94, 0x22008000 },  { 96, 0x22107000 },  { 99, 0x22107000 },
78         { 108, 0x22107000 }, { 121, 0x22107000 }, { 128, 0x22107000 },
79         { 132, 0x22109000 }, { 135, 0x22109000 }, { 157, 0x2210b000 },
80         { 162, 0x2210b000 }, { 175, 0x2210b000 }, { 189, 0x2220e000 },
81         { 195, 0x2220e000 }, { 202, 0x2220e000 }, { 204, 0x2220e000 },
82         { 218, 0x2220f000 }, { 229, 0x22210000 }, { 234, 0x22210000 }, 
83 };
84
85 static struct wm_info i810_wm_16_133[] = {
86         { 15, 0x0020c000 },  { 19, 0x0020c000 },  { 25, 0x22006000 },
87         { 28, 0x22006000 },  { 31, 0x22007000 },  { 36, 0x22007000 },
88         { 40, 0x22007000 },  { 45, 0x22007000 },  { 49, 0x22009000 },
89         { 50, 0x22009000 },  { 56, 0x22108000 },  { 65, 0x2210e000 },
90         { 75, 0x2210e000 },  { 78, 0x2210e000 },  { 80, 0x22210000 },
91         { 94, 0x22210000 },  { 96, 0x22210000 },  { 99, 0x22210000 },
92         { 108, 0x22210000 }, { 121, 0x22210000 }, { 128, 0x22210000 },
93         { 132, 0x22314000 }, { 135, 0x22314000 }, { 157, 0x22415000 },
94         { 162, 0x22416000 }, { 175, 0x22416000 }, { 189, 0x22416000 },
95         { 195, 0x22416000 }, { 202, 0x22416000 }, { 204, 0x22416000 },
96         { 218, 0x22416000 }, { 229, 0x22416000 },
97 };
98
99 static struct wm_info i810_wm_24_133[] = {
100         { 15, 0x0020c000 },  { 19, 0x00408000 },  { 25, 0x22009000 },
101         { 28, 0x22009000 },  { 31, 0x2200a000 },  { 36, 0x2210c000 },
102         { 40, 0x2210c000 },  { 45, 0x2210c000 },  { 49, 0x22111000 },
103         { 50, 0x22111000 },  { 56, 0x22111000 },  { 65, 0x22214000 },
104         { 75, 0x22214000 },  { 78, 0x22215000 },  { 80, 0x22216000 },
105         { 94, 0x22218000 },  { 96, 0x22418000 },  { 99, 0x22418000 },
106         { 108, 0x22418000 }, { 121, 0x22418000 }, { 128, 0x22419000 },
107         { 132, 0x22519000 }, { 135, 0x4441d000 }, { 157, 0x44419000 },
108         { 162, 0x44419000 }, { 175, 0x44419000 }, { 189, 0x44419000 },
109         { 195, 0x44419000 }, { 202, 0x44419000 }, { 204, 0x44419000 },
110 };
111
112 void round_off_xres(u32 *xres) { }
113 void round_off_yres(u32 *xres, u32 *yres) { }
114
115 /**
116  * i810fb_encode_registers - encode @var to hardware register values
117  * @var: pointer to var structure
118  * @par: pointer to hardware par structure
119  * 
120  * DESCRIPTION: 
121  * Timing values in @var will be converted to appropriate
122  * register values of @par.  
123  */
124 void i810fb_encode_registers(const struct fb_var_screeninfo *var,
125                              struct i810fb_par *par, u32 xres, u32 yres)
126 {
127         int n, blank_s, blank_e;
128         u8 __iomem *mmio = par->mmio_start_virtual;
129         u8 msr = 0;
130
131         /* Horizontal */
132         /* htotal */
133         n = ((xres + var->right_margin + var->hsync_len + 
134               var->left_margin) >> 3) - 5;
135         par->regs.cr00 =  (u8) n;
136         par->regs.cr35 = (u8) ((n >> 8) & 1);
137         
138         /* xres */
139         par->regs.cr01 = (u8) ((xres >> 3) - 1);
140
141         /* hblank */
142         blank_e = (xres + var->right_margin + var->hsync_len + 
143                    var->left_margin) >> 3;
144         blank_e--;
145         blank_s = blank_e - 127;
146         if (blank_s < (xres >> 3))
147                 blank_s = xres >> 3;
148         par->regs.cr02 = (u8) blank_s;
149         par->regs.cr03 = (u8) (blank_e & 0x1F);
150         par->regs.cr05 = (u8) ((blank_e & (1 << 5)) << 2);
151         par->regs.cr39 = (u8) ((blank_e >> 6) & 1);
152
153         /* hsync */
154         par->regs.cr04 = (u8) ((xres + var->right_margin) >> 3);
155         par->regs.cr05 |= (u8) (((xres + var->right_margin + 
156                                   var->hsync_len) >> 3) & 0x1F);
157         
158         /* Vertical */
159         /* vtotal */
160         n = yres + var->lower_margin + var->vsync_len + var->upper_margin - 2;
161         par->regs.cr06 = (u8) (n & 0xFF);
162         par->regs.cr30 = (u8) ((n >> 8) & 0x0F);
163
164         /* vsync */ 
165         n = yres + var->lower_margin;
166         par->regs.cr10 = (u8) (n & 0xFF);
167         par->regs.cr32 = (u8) ((n >> 8) & 0x0F);
168         par->regs.cr11 = i810_readb(CR11, mmio) & ~0x0F;
169         par->regs.cr11 |= (u8) ((yres + var->lower_margin + 
170                                  var->vsync_len) & 0x0F);
171
172         /* yres */
173         n = yres - 1;
174         par->regs.cr12 = (u8) (n & 0xFF);
175         par->regs.cr31 = (u8) ((n >> 8) & 0x0F);
176         
177         /* vblank */
178         blank_e = yres + var->lower_margin + var->vsync_len + 
179                 var->upper_margin;
180         blank_e--;
181         blank_s = blank_e - 127;
182         if (blank_s < yres)
183                 blank_s = yres;
184         par->regs.cr15 = (u8) (blank_s & 0xFF);
185         par->regs.cr33 = (u8) ((blank_s >> 8) & 0x0F);
186         par->regs.cr16 = (u8) (blank_e & 0xFF);
187         par->regs.cr09 = 0;     
188
189         /* sync polarity */
190         if (!(var->sync & FB_SYNC_HOR_HIGH_ACT))
191                 msr |= 1 << 6;
192         if (!(var->sync & FB_SYNC_VERT_HIGH_ACT))
193                 msr |= 1 << 7;
194         par->regs.msr = msr;
195
196         /* interlace */
197         if (var->vmode & FB_VMODE_INTERLACED) 
198                 par->interlace = (1 << 7) | ((u8) (var->yres >> 4));
199         else 
200                 par->interlace = 0;
201
202         if (var->vmode & FB_VMODE_DOUBLE)
203                 par->regs.cr09 |= 1 << 7;
204
205         /* overlay */
206         par->ovract = ((var->xres + var->right_margin + var->hsync_len + 
207                         var->left_margin - 32) | ((var->xres - 32) << 16));
208 }       
209
210 void i810fb_fill_var_timings(struct fb_var_screeninfo *var) { }
211
212 /**
213  * i810_get_watermark - gets watermark
214  * @var: pointer to fb_var_screeninfo
215  * @par: pointer to i810fb_par structure
216  *
217  * DESCRIPTION:
218  * Gets the required watermark based on 
219  * pixelclock and RAMBUS frequency.
220  * 
221  * RETURNS:
222  * watermark
223  */
224 u32 i810_get_watermark(const struct fb_var_screeninfo *var,
225                        struct i810fb_par *par)
226 {
227         struct wm_info *wmark = NULL;
228         u32 i, size = 0, pixclock, wm_best = 0, min, diff;
229
230         if (par->mem_freq == 100) {
231                 switch (var->bits_per_pixel) { 
232                 case 8:
233                         wmark = i810_wm_8_100;
234                         size = ARRAY_SIZE(i810_wm_8_100);
235                         break;
236                 case 16:
237                         wmark = i810_wm_16_100;
238                         size = ARRAY_SIZE(i810_wm_16_100);
239                         break;
240                 case 24:
241                 case 32:
242                         wmark = i810_wm_24_100;
243                         size = ARRAY_SIZE(i810_wm_24_100);
244                 }
245         } else {
246                 switch(var->bits_per_pixel) {
247                 case 8:
248                         wmark = i810_wm_8_133;
249                         size = ARRAY_SIZE(i810_wm_8_133);
250                         break;
251                 case 16:
252                         wmark = i810_wm_16_133;
253                         size = ARRAY_SIZE(i810_wm_16_133);
254                         break;
255                 case 24:
256                 case 32:
257                         wmark = i810_wm_24_133;
258                         size = ARRAY_SIZE(i810_wm_24_133);
259                 }
260         }
261
262         pixclock = 1000000/var->pixclock;
263         min = ~0;
264         for (i = 0; i < size; i++) {
265                 if (pixclock <= wmark[i].freq) 
266                         diff = wmark[i].freq - pixclock;
267                 else 
268                         diff = pixclock - wmark[i].freq;
269                 if (diff < min) {
270                         wm_best = wmark[i].wm;
271                         min = diff;
272                 }
273         }
274         return wm_best;         
275 }       
276