File: /usr/src/linux/drivers/video/fbcon-sti.c

1     /*
2      * linux/drivers/video/fbcon-sti.c -- Low level frame buffer
3      *  	operations for generic HP video boards using STI (standard
4      *  	text interface) firmware
5      *
6      *  Based on linux/drivers/video/fbcon-artist.c
7      *	Created 5 Apr 1997 by Geert Uytterhoeven
8      *	Copyright (C) 2000 Philipp Rumpf <prumpf@tux.org>
9      *
10      * This file is subject to the terms and conditions of the GNU General Public
11      * License.  See the file COPYING in the main directory of this archive for
12      * more details.  */
13     
14     #include <linux/module.h>
15     #include <linux/tty.h>
16     #include <linux/console.h>
17     #include <linux/string.h>
18     #include <linux/fb.h>
19     #include <linux/delay.h>
20     #include <asm/types.h>
21     
22     #include <video/fbcon.h>
23     #include <video/fbcon-mfb.h>
24     
25     #include "sti.h"
26     
27     /* Translate an address as it would be found in a 2048x2048x1 bit frame
28      * buffer into a logical address Artist actually expects.  Addresses fed
29      * into Artist look like this:
30      *  fixed          Y               X
31      * FFFF FFFF LLLL LLLL LLLC CCCC CCCC CC00
32      *
33      * our "RAM" addresses look like this:
34      * 
35      * FFFF FFFF 0000 0LLL LLLL LLLL CCCC CCCC [CCC]
36      *
37      * */
38     
39     static inline u32
40     ram2log(void * addr)
41     {
42     	u32 a = (unsigned long) addr;
43     	u32 r;
44     
45     #if 0
46     	r  =   a & 0xff000000;		/* fixed part */
47     	r += ((a & 0x000000ff) << 5);
48     	r += ((a & 0x00ffff00) << 3);
49     #else
50     	r  =   a & 0xff000000;		/* fixed part */
51     	r += ((a & 0x000000ff) << 5);
52     	r += ((a & 0x0007ff00) << 5);
53     #endif
54     
55     	return r;
56     }
57     
58     /* All those functions need better names. */
59     
60     static void
61     memcpy_fromhp_tohp(void *dest, void *src, int count)
62     {
63     	unsigned long d = ram2log(dest);
64     	unsigned long s = ram2log(src);
65     
66     	count += 3;
67     	count &= ~3; /* XXX */
68     
69     	while(count) {
70     		count --;
71     		gsc_writel(~gsc_readl(s), d);
72     		d += 32*4;
73     		s += 32*4;
74     	}
75     }
76     
77     static void
78     memcpy_tohp(void *dest, void *src, int count)
79     {
80     	unsigned long d = (unsigned long) dest;
81     	u32 *s = (u32 *)src;
82     
83     	count += 3;
84     	count &= ~3; /* XXX */
85     
86     	d = ram2log(dest);
87     
88     	while(count) {
89     		count--;
90     		gsc_writel(*s++, d);
91     		d += 32*4;
92     	}
93     }
94     
95     static void
96     memcopy_fromhp(void *dest, void *src, int count)
97     {
98     	/* FIXME */
99     	printk("uhm ...\n");
100     }
101     
102     static void
103     memset_tohp(void *dest, u32 word, int count)
104     {
105     	unsigned long d = ram2log(dest);
106     
107     	count += 3;
108     	count &= ~3;
109     
110     	while(count) {
111     		count--;
112     		gsc_writel(word, d);
113     		d += 32;
114     	}
115     }
116     
117     static u8
118     readb_hp(void *src)
119     {
120     	unsigned long s = ram2log(src);
121     
122     	return ~gsc_readb(s);
123     }
124     
125     static void
126     writeb_hp(u8 b, void *dst)
127     {
128     	unsigned long d = ram2log(dst);
129     
130     	if((d&0xf0000000) != 0xf0000000) {
131     		printk("writeb_hp %02x %p (%08lx) (%p)\n",
132     			b, dst, d, __builtin_return_address(0));
133     		return;
134     	}
135     
136     	gsc_writeb(b, d);
137     }
138     
139     static void
140     fbcon_sti_setup(struct display *p)
141     {
142     	if (p->line_length)
143     		p->next_line = p->line_length;
144     	else
145     		p->next_line = p->var.xres_virtual>>3;
146     	p->next_plane = 0;
147     }
148     
149     static void
150     fbcon_sti_bmove(struct display *p, int sy, int sx,
151     		int dy, int dx,
152     		int height, int width)
153     {
154     #if 0 /* Unfortunately, still broken */
155     	sti_bmove(&default_sti /* FIXME */, sy, sx, dy, dx, height, width);
156     #else
157     	u8 *src, *dest;
158     	u_int rows;
159     
160     	if (sx == 0 && dx == 0 && width == p->next_line) {
161     		src = p->screen_base+sy*fontheight(p)*width;
162     		dest = p->screen_base+dy*fontheight(p)*width;
163     		memcpy_fromhp_tohp(dest, src, height*fontheight(p)*width);
164     	} else if (dy <= sy) {
165     		src = p->screen_base+sy*fontheight(p)*p->next_line+sx;
166     		dest = p->screen_base+dy*fontheight(p)*p->next_line+dx;
167     		for (rows = height*fontheight(p); rows--;) {
168     			memcpy_fromhp_tohp(dest, src, width);
169     			src += p->next_line;
170     			dest += p->next_line;
171     		}
172     	} else {
173     		src = p->screen_base+((sy+height)*fontheight(p)-1)*p->next_line+sx;
174     		dest = p->screen_base+((dy+height)*fontheight(p)-1)*p->next_line+dx;
175     		for (rows = height*fontheight(p); rows--;) {
176     			memcpy_fromhp_tohp(dest, src, width);
177     			src -= p->next_line;
178     			dest -= p->next_line;
179     		}
180     	}
181     #endif
182     }
183     
184     static void
185     fbcon_sti_clear(struct vc_data *conp,
186     		struct display *p, int sy, int sx,
187     		int height, int width)
188     {
189     	u8 *dest;
190     	u_int rows;
191     	int inverse = conp ? attr_reverse(p,conp->vc_video_erase_char) : 0;
192     
193     	dest = p->screen_base+sy*fontheight(p)*p->next_line+sx;
194     
195     	if (sx == 0 && width == p->next_line) {
196     		if (inverse)
197     			memset_tohp(dest, ~0, height*fontheight(p)*width);
198     		else
199     			memset_tohp(dest,  0, height*fontheight(p)*width);
200     	} else
201     		for (rows = height*fontheight(p); rows--; dest += p->next_line)
202     			if (inverse)
203     				memset_tohp(dest, 0xffffffff, width);
204     			else
205     				memset_tohp(dest, 0x00000000, width);
206     }
207     
208     static void fbcon_sti_putc(struct vc_data *conp,
209     			   struct display *p, int c,
210     			   int yy, int xx)
211     {
212     	u8 *dest, *cdat;
213     	u_int rows, bold, revs, underl;
214     	u8 d;
215     
216     	dest = p->screen_base+yy*fontheight(p)*p->next_line+xx;
217     	cdat = p->fontdata+(c&p->charmask)*fontheight(p);
218     	bold = attr_bold(p,c);
219     	revs = attr_reverse(p,c);
220     	underl = attr_underline(p,c);
221     
222     	for (rows = fontheight(p); rows--; dest += p->next_line) {
223     		d = *cdat++;
224     		if (underl && !rows)
225     			d = 0xff;
226     		else if (bold)
227     			d |= d>>1;
228     		if (revs)
229     			d = ~d;
230     		writeb_hp (d, dest);
231     	}
232     }
233     
234     static void fbcon_sti_putcs(struct vc_data *conp,
235     			    struct display *p, 
236     			    const unsigned short *s,
237     			    int count, int yy, int xx)
238     {
239     	u8 *dest, *dest0, *cdat;
240     	u_int rows, bold, revs, underl;
241     	u8 d;
242     	u16 c;
243     
244     	if(((unsigned)xx > 200) || ((unsigned) yy > 200)) {
245     		printk("refusing to putcs %p %p %p %d %d %d (%p)\n",
246     			conp, p, s, count, yy, xx, __builtin_return_address(0));
247     		return;
248     	}	
249     
250     
251     	dest0 = p->screen_base+yy*fontheight(p)*p->next_line+xx;
252     	if(((u32)dest0&0xf0000000)!=0xf0000000) {
253     		printk("refusing to putcs %p %p %p %d %d %d (%p) %p = %p + %d * %d * %ld + %d\n",
254     			conp, p, s, count, yy, xx, __builtin_return_address(0),
255     			dest0, p->screen_base, yy, fontheight(p), p->next_line,
256     			xx);
257     		return;
258     	}	
259     
260     	bold = attr_bold(p,scr_readw(s));
261     	revs = attr_reverse(p,scr_readw(s));
262     	underl = attr_underline(p,scr_readw(s));
263     
264     	while (count--) {
265     		c = scr_readw(s++) & p->charmask;
266     		dest = dest0++;
267     		cdat = p->fontdata+c*fontheight(p);
268     		for (rows = fontheight(p); rows--; dest += p->next_line) {
269     			d = *cdat++;
270     			if (0 && underl && !rows)
271     				d = 0xff;
272     			else if (0 && bold)
273     				d |= d>>1;
274     			if (revs)
275     				d = ~d;
276     			writeb_hp (d, dest);
277     		}
278     	}
279     }
280     
281     static void fbcon_sti_revc(struct display *p,
282     			   int xx, int yy)
283     {
284     	u8 *dest, d;
285     	u_int rows;
286     
287     
288     	dest = p->screen_base+yy*fontheight(p)*p->next_line+xx;
289     	for (rows = fontheight(p); rows--; dest += p->next_line) {
290     		d = readb_hp(dest);
291     		writeb_hp (~d, dest);
292     	}
293     }
294     
295     static void
296     fbcon_sti_clear_margins(struct vc_data *conp,
297     			struct display *p,
298     			int bottom_only)
299     {
300     	u8 *dest;
301     	int height, bottom;
302     	int inverse = conp ? attr_reverse(p,conp->vc_video_erase_char) : 0;
303     
304     
305     	/* XXX Need to handle right margin? */
306     
307     	height = p->var.yres - conp->vc_rows * fontheight(p);
308     	if (!height)
309     		return;
310     	bottom = conp->vc_rows + p->yscroll;
311     	if (bottom >= p->vrows)
312     		bottom -= p->vrows;
313     	dest = p->screen_base + bottom * fontheight(p) * p->next_line;
314     	if (inverse)
315     		memset_tohp(dest, 0xffffffff, height * p->next_line);
316     	else
317     		memset_tohp(dest, 0x00000000, height * p->next_line);
318     }
319     
320     
321         /*
322          *  `switch' for the low level operations
323          */
324     
325     struct display_switch fbcon_sti = {
326     	setup:		fbcon_sti_setup, 
327     	bmove:		fbcon_sti_bmove, 
328     	clear:		fbcon_sti_clear,
329     	putc:		fbcon_sti_putc, 
330     	putcs:		fbcon_sti_putcs, 
331     	revc:		fbcon_sti_revc,
332     	clear_margins:	fbcon_sti_clear_margins,
333     	fontwidthmask:	FONTWIDTH(8)
334     };
335     
336     MODULE_LICENSE("GPL");
337