v2.4.8 -> v2.4.8.1
[opensuse:kernel.git] / 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 };