import of ftp.dlink.com/GPL/DSMG-600_reB/ppclinux.tar.gz
[linux-2.4.21-pre4.git] / drivers / video / riva / accel.c
1 /*
2  * linux/drivers/video/accel.c - nVidia RIVA 128/TNT/TNT2 fb driver
3  *
4  * Copyright 2000 Jindrich Makovicka, Ani Joshi
5  *
6  * This file is subject to the terms and conditions of the GNU General Public
7  * License.  See the file COPYING in the main directory of this archive
8  * for more details.
9  */
10
11 #include "rivafb.h"
12
13 /* acceleration routines */
14
15 inline void wait_for_idle(struct rivafb_info *rinfo)
16 {
17         while (rinfo->riva.Busy(&rinfo->riva));
18 }
19
20 /* set copy ROP, no mask */
21 static void riva_setup_ROP(struct rivafb_info *rinfo)
22 {
23         RIVA_FIFO_FREE(rinfo->riva, Patt, 5);
24         rinfo->riva.Patt->Shape = 0;
25         rinfo->riva.Patt->Color0 = 0xffffffff;
26         rinfo->riva.Patt->Color1 = 0xffffffff;
27         rinfo->riva.Patt->Monochrome[0] = 0xffffffff;
28         rinfo->riva.Patt->Monochrome[1] = 0xffffffff;
29
30         RIVA_FIFO_FREE(rinfo->riva, Rop, 1);
31         rinfo->riva.Rop->Rop3 = 0xCC;
32 }
33
34 void riva_setup_accel(struct rivafb_info *rinfo)
35 {
36         RIVA_FIFO_FREE(rinfo->riva, Clip, 2);
37         rinfo->riva.Clip->TopLeft     = 0x0;
38         rinfo->riva.Clip->WidthHeight = 0x80008000;
39         riva_setup_ROP(rinfo);
40         wait_for_idle(rinfo);
41 }
42
43 static void riva_rectfill(struct rivafb_info *rinfo, int sy,
44                           int sx, int height, int width, u_int color)
45 {
46         RIVA_FIFO_FREE(rinfo->riva, Bitmap, 1);
47         rinfo->riva.Bitmap->Color1A = color;
48
49         RIVA_FIFO_FREE(rinfo->riva, Bitmap, 2);
50         rinfo->riva.Bitmap->UnclippedRectangle[0].TopLeft     = (sx << 16) | sy; 
51         rinfo->riva.Bitmap->UnclippedRectangle[0].WidthHeight = (width << 16) | height;
52 }
53
54 static void fbcon_riva_bmove(struct display *p, int sy, int sx, int dy, int dx,
55                             int height, int width)
56 {
57         struct rivafb_info *rinfo = (struct rivafb_info *)(p->fb_info);
58
59         sx *= fontwidth(p);
60         sy *= fontheight(p);
61         dx *= fontwidth(p);
62         dy *= fontheight(p);
63         width *= fontwidth(p);
64         height *= fontheight(p);
65
66         RIVA_FIFO_FREE(rinfo->riva, Blt, 3);
67         rinfo->riva.Blt->TopLeftSrc  = (sy << 16) | sx;
68         rinfo->riva.Blt->TopLeftDst  = (dy << 16) | dx;
69         rinfo->riva.Blt->WidthHeight = (height  << 16) | width;
70
71         wait_for_idle(rinfo);
72 }
73
74 static void riva_clear_margins(struct vc_data *conp, struct display *p,
75                                 int bottom_only, u32 bgx)
76 {
77         struct rivafb_info *rinfo = (struct rivafb_info *)(p->fb_info);
78
79         unsigned int right_start = conp->vc_cols*fontwidth(p);
80         unsigned int bottom_start = conp->vc_rows*fontheight(p);
81         unsigned int right_width, bottom_width;
82
83         if (!bottom_only && (right_width = p->var.xres - right_start))
84                 riva_rectfill(rinfo, 0, right_start, p->var.yres_virtual,
85                               right_width, bgx);
86         if ((bottom_width = p->var.yres - bottom_start))
87                 riva_rectfill(rinfo, p->var.yoffset + bottom_start, 0,
88                               bottom_width, right_start, bgx);
89 }
90
91 static u8 byte_rev[256] = {
92         0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0, 0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,
93         0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8, 0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8, 
94         0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4, 0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4, 
95         0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec, 0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc, 
96         0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2, 0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2, 
97         0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea, 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa, 
98         0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6, 0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6, 
99         0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee, 0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe, 
100         0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1, 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1, 
101         0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9, 0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9, 
102         0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5, 0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5, 
103         0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed, 0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd, 
104         0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3, 0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3, 
105         0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb, 0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb, 
106         0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7, 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7, 
107         0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef, 0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff,
108 };
109
110 static inline void fbcon_reverse_order(u32 *l)
111 {
112         u8 *a = (u8 *)l;
113         *a = byte_rev[*a], a++;
114 /*      *a = byte_rev[*a], a++;
115         *a = byte_rev[*a], a++;*/
116         *a = byte_rev[*a];
117 }
118
119 static void fbcon_riva_writechr(struct vc_data *conp, struct display *p,
120                                 int c, int fgx, int bgx, int yy, int xx)
121 {
122         u8 *cdat;
123         struct rivafb_info *rinfo = (struct rivafb_info *)(p->fb_info);
124         int w, h;
125         volatile u32 *d;
126         u32 cdat2;
127         int i, j, cnt;
128
129         w = fontwidth(p);
130         h = fontheight(p);
131
132         if (w <= 8)
133                 cdat = p->fontdata + (c & p->charmask) * h;
134         else
135                 cdat = p->fontdata + ((c & p->charmask) * h << 1);
136
137         RIVA_FIFO_FREE(rinfo->riva, Bitmap, 7);
138         rinfo->riva.Bitmap->ClipE.TopLeft     = (yy << 16) | (xx & 0xFFFF);
139         rinfo->riva.Bitmap->ClipE.BottomRight = ((yy+h) << 16) | ((xx+w) & 0xffff);
140         rinfo->riva.Bitmap->Color0E           = bgx;
141         rinfo->riva.Bitmap->Color1E           = fgx;
142         rinfo->riva.Bitmap->WidthHeightInE  = (h << 16) | 32;
143         rinfo->riva.Bitmap->WidthHeightOutE = (h << 16) | 32;
144         rinfo->riva.Bitmap->PointE          = (yy << 16) | (xx & 0xFFFF);
145         
146         d = &rinfo->riva.Bitmap->MonochromeData01E;
147         for (i = h; i > 0; i-=16) {
148                 if (i >= 16)
149                         cnt = 16;
150                 else
151                         cnt = i;
152                 RIVA_FIFO_FREE(rinfo->riva, Bitmap, cnt);
153                 for (j = 0; j < cnt; j++) {
154                         if (w <= 8) 
155                                 cdat2 = *cdat++;
156                         else
157                                 cdat2 = *((u16*)cdat)++;
158                         fbcon_reverse_order(&cdat2);
159                         d[j] = cdat2;
160                 }
161         }
162 }
163
164 #ifdef FBCON_HAS_CFB8
165 void fbcon_riva8_setup(struct display *p)
166 {
167     p->next_line = p->line_length ? p->line_length : p->var.xres_virtual;
168     p->next_plane = 0;
169 }
170
171 static void fbcon_riva8_clear(struct vc_data *conp, struct display *p, int sy,
172                              int sx, int height, int width)
173 {
174         u32 bgx;
175
176         struct rivafb_info *rinfo = (struct rivafb_info *)(p->fb_info);
177
178         bgx = attr_bgcol_ec(p, conp);
179
180         sx *= fontwidth(p);
181         sy *= fontheight(p);
182         width *= fontwidth(p);
183         height *= fontheight(p);
184
185         riva_rectfill(rinfo, sy, sx, height, width, bgx);
186 }
187
188 static void fbcon_riva8_putc(struct vc_data *conp, struct display *p, int c,
189                             int yy, int xx)
190 {
191         u32 fgx,bgx;
192
193         fgx = attr_fgcol(p,c);
194         bgx = attr_bgcol(p,c);
195         
196         xx *= fontwidth(p);
197         yy *= fontheight(p);
198
199         fbcon_riva_writechr(conp, p, c, fgx, bgx, yy, xx);
200 }
201
202 static void fbcon_riva8_putcs(struct vc_data *conp, struct display *p,
203                              const unsigned short *s, int count, int yy,
204                              int xx)
205 {
206         u16 c;
207         u32 fgx,bgx;
208
209         xx *= fontwidth(p);
210         yy *= fontheight(p);
211
212         c = scr_readw(s);
213         fgx = attr_fgcol(p, c);
214         bgx = attr_bgcol(p, c);
215         while (count--) {
216                 c = scr_readw(s++);
217                 fbcon_riva_writechr(conp, p, c, fgx, bgx, yy, xx);
218                 xx += fontwidth(p);
219         }
220 }
221
222 static void fbcon_riva8_revc(struct display *p, int xx, int yy)
223 {
224         struct rivafb_info *rinfo = (struct rivafb_info *) (p->fb_info);
225
226         xx *= fontwidth(p);
227         yy *= fontheight(p);
228
229         RIVA_FIFO_FREE(rinfo->riva, Rop, 1);
230         rinfo->riva.Rop->Rop3 = 0x66; // XOR
231         riva_rectfill(rinfo, yy, xx, fontheight(p), fontwidth(p), 0x0f);
232         RIVA_FIFO_FREE(rinfo->riva, Rop, 1);
233         rinfo->riva.Rop->Rop3 = 0xCC; // back to COPY
234 }
235
236 static void fbcon_riva8_clear_margins(struct vc_data *conp, struct display *p,
237                                        int bottom_only)
238 {
239         riva_clear_margins(conp, p, bottom_only, attr_bgcol_ec(p, conp));
240 }
241
242 struct display_switch fbcon_riva8 = {
243         setup:          fbcon_riva8_setup,
244         bmove:          fbcon_riva_bmove,
245         clear:          fbcon_riva8_clear,
246         putc:           fbcon_riva8_putc,
247         putcs:          fbcon_riva8_putcs,
248         revc:           fbcon_riva8_revc,
249         clear_margins:  fbcon_riva8_clear_margins,
250         fontwidthmask:  FONTWIDTHRANGE(4, 16)
251 };
252 #endif
253
254 #if defined(FBCON_HAS_CFB16) || defined(FBCON_HAS_CFB32)
255 static void fbcon_riva1632_revc(struct display *p, int xx, int yy)
256 {
257         struct rivafb_info *rinfo = (struct rivafb_info *) (p->fb_info);
258
259         xx *= fontwidth(p);
260         yy *= fontheight(p);
261
262         RIVA_FIFO_FREE(rinfo->riva, Rop, 1);
263         rinfo->riva.Rop->Rop3 = 0x66; // XOR
264         riva_rectfill(rinfo, yy, xx, fontheight(p), fontwidth(p), 0xffffffff);
265         RIVA_FIFO_FREE(rinfo->riva, Rop, 1);
266         rinfo->riva.Rop->Rop3 = 0xCC; // back to COPY
267 }
268 #endif
269
270 #ifdef FBCON_HAS_CFB16
271 void fbcon_riva16_setup(struct display *p)
272 {
273     p->next_line = p->line_length ? p->line_length : p->var.xres_virtual<<1;
274     p->next_plane = 0;
275 }
276
277 static void fbcon_riva16_clear(struct vc_data *conp, struct display *p, int sy,
278                              int sx, int height, int width)
279 {
280         u32 bgx;
281
282         struct rivafb_info *rinfo = (struct rivafb_info *)(p->fb_info);
283
284         bgx = ((u_int16_t*)p->dispsw_data)[attr_bgcol_ec(p, conp)];
285
286         sx *= fontwidth(p);
287         sy *= fontheight(p);
288         width *= fontwidth(p);
289         height *= fontheight(p);
290
291         riva_rectfill(rinfo, sy, sx, height, width, bgx);
292 }
293
294 static inline void convert_bgcolor_16(u32 *col)
295 {
296         *col = ((*col & 0x00007C00) << 9)
297              | ((*col & 0x000003E0) << 6)
298              | ((*col & 0x0000001F) << 3)
299              |          0xFF000000;
300 }
301
302 static void fbcon_riva16_putc(struct vc_data *conp, struct display *p, int c,
303                             int yy, int xx)
304 {
305         u32 fgx,bgx;
306
307         fgx = ((u16 *)p->dispsw_data)[attr_fgcol(p,c)];
308         bgx = ((u16 *)p->dispsw_data)[attr_bgcol(p,c)];
309         if (p->var.green.length == 6)
310                 convert_bgcolor_16(&bgx);
311         xx *= fontwidth(p);
312         yy *= fontheight(p);
313
314         fbcon_riva_writechr(conp, p, c, fgx, bgx, yy, xx);
315 }
316
317 static void fbcon_riva16_putcs(struct vc_data *conp, struct display *p,
318                              const unsigned short *s, int count, int yy,
319                              int xx)
320 {
321         u16 c;
322         u32 fgx,bgx;
323
324         xx *= fontwidth(p);
325         yy *= fontheight(p);
326
327         c = scr_readw(s);
328         fgx = ((u16 *)p->dispsw_data)[attr_fgcol(p, c)];
329         bgx = ((u16 *)p->dispsw_data)[attr_bgcol(p, c)];
330         if (p->var.green.length == 6)
331                 convert_bgcolor_16(&bgx);
332         while (count--) {
333                 c = scr_readw(s++);
334                 fbcon_riva_writechr(conp, p, c, fgx, bgx, yy, xx);
335                 xx += fontwidth(p);
336         }
337 }
338
339 static void fbcon_riva16_clear_margins(struct vc_data *conp, struct display *p,
340                                        int bottom_only)
341 {
342         riva_clear_margins(conp, p, bottom_only, ((u16 *)p->dispsw_data)[attr_bgcol_ec(p, conp)]);
343 }
344
345 struct display_switch fbcon_riva16 = {
346         setup:          fbcon_riva16_setup,
347         bmove:          fbcon_riva_bmove,
348         clear:          fbcon_riva16_clear,
349         putc:           fbcon_riva16_putc,
350         putcs:          fbcon_riva16_putcs,
351         revc:           fbcon_riva1632_revc,
352         clear_margins:  fbcon_riva16_clear_margins,
353         fontwidthmask:  FONTWIDTHRANGE(4, 16)
354 };
355 #endif
356
357 #ifdef FBCON_HAS_CFB32
358 void fbcon_riva32_setup(struct display *p)
359 {
360     p->next_line = p->line_length ? p->line_length : p->var.xres_virtual<<2;
361     p->next_plane = 0;
362 }
363
364 static void fbcon_riva32_clear(struct vc_data *conp, struct display *p, int sy,
365                              int sx, int height, int width)
366 {
367         u32 bgx;
368
369         struct rivafb_info *rinfo = (struct rivafb_info *)(p->fb_info);
370
371         bgx = ((u_int32_t*)p->dispsw_data)[attr_bgcol_ec(p, conp)];
372
373         sx *= fontwidth(p);
374         sy *= fontheight(p);
375         width *= fontwidth(p);
376         height *= fontheight(p);
377
378         riva_rectfill(rinfo, sy, sx, height, width, bgx);
379 }
380
381 static void fbcon_riva32_putc(struct vc_data *conp, struct display *p, int c,
382                             int yy, int xx)
383 {
384         u32 fgx,bgx;
385
386         fgx = ((u32 *)p->dispsw_data)[attr_fgcol(p,c)];
387         bgx = ((u32 *)p->dispsw_data)[attr_bgcol(p,c)];
388         xx *= fontwidth(p);
389         yy *= fontheight(p);
390         fbcon_riva_writechr(conp, p, c, fgx, bgx, yy, xx);
391 }
392
393 static void fbcon_riva32_putcs(struct vc_data *conp, struct display *p,
394                              const unsigned short *s, int count, int yy,
395                              int xx)
396 {
397         u16 c;
398         u32 fgx,bgx;
399
400         xx *= fontwidth(p);
401         yy *= fontheight(p);
402
403         c = scr_readw(s);
404         fgx = ((u32 *)p->dispsw_data)[attr_fgcol(p, c)];
405         bgx = ((u32 *)p->dispsw_data)[attr_bgcol(p, c)];
406         while (count--) {
407                 c = scr_readw(s++);
408                 fbcon_riva_writechr(conp, p, c, fgx, bgx, yy, xx);
409                 xx += fontwidth(p);
410         }
411 }
412
413 static void fbcon_riva32_clear_margins(struct vc_data *conp, struct display *p,
414                                        int bottom_only)
415 {
416         riva_clear_margins(conp, p, bottom_only, ((u32 *)p->dispsw_data)[attr_bgcol_ec(p, conp)]);
417 }
418
419 struct display_switch fbcon_riva32 = {
420         setup:          fbcon_riva32_setup,
421         bmove:          fbcon_riva_bmove,
422         clear:          fbcon_riva32_clear,
423         putc:           fbcon_riva32_putc,
424         putcs:          fbcon_riva32_putcs,
425         revc:           fbcon_riva1632_revc,
426         clear_margins:  fbcon_riva32_clear_margins,
427         fontwidthmask:  FONTWIDTHRANGE(4, 16)
428 };
429 #endif