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