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