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