libata cmd64x: whack into a shape that looks like the documentation
[linux-2.6] / drivers / video / S3triofb.c
1 /*
2  *  linux/drivers/video/S3Triofb.c -- Open Firmware based frame buffer device
3  *
4  *      Copyright (C) 1997 Peter De Schrijver
5  *
6  *  This driver is partly based on the PowerMac console driver:
7  *
8  *      Copyright (C) 1996 Paul Mackerras
9  *
10  *  and on the Open Firmware based frame buffer device:
11  *
12  *      Copyright (C) 1997 Geert Uytterhoeven
13  *
14  *  This file is subject to the terms and conditions of the GNU General Public
15  *  License. See the file COPYING in the main directory of this archive for
16  *  more details.
17  */
18
19 /*
20         Bugs : + OF dependencies should be removed.
21                + This driver should be merged with the CyberVision driver. The
22                  CyberVision is a Zorro III implementation of the S3Trio64 chip.
23
24 */
25
26 #include <linux/kernel.h>
27 #include <linux/module.h>
28 #include <linux/errno.h>
29 #include <linux/string.h>
30 #include <linux/mm.h>
31 #include <linux/slab.h>
32 #include <linux/vmalloc.h>
33 #include <linux/delay.h>
34 #include <linux/interrupt.h>
35 #include <linux/fb.h>
36 #include <linux/init.h>
37 #include <linux/selection.h>
38 #include <asm/io.h>
39 #include <asm/prom.h>
40 #include <asm/pci-bridge.h>
41 #include <linux/pci.h>
42
43 #include <video/fbcon.h>
44 #include <video/fbcon-cfb8.h>
45 #include <video/s3blit.h>
46
47
48 #define mem_in8(addr)           in_8((void *)(addr))
49 #define mem_in16(addr)          in_le16((void *)(addr))
50 #define mem_in32(addr)          in_le32((void *)(addr))
51
52 #define mem_out8(val, addr)     out_8((void *)(addr), val)
53 #define mem_out16(val, addr)    out_le16((void *)(addr), val)
54 #define mem_out32(val, addr)    out_le32((void *)(addr), val)
55
56 #define IO_OUT16VAL(v, r)       (((v) << 8) | (r))
57
58 static struct display disp;
59 static struct fb_info fb_info;
60 static struct { u_char red, green, blue, pad; } palette[256];
61 static char s3trio_name[16] = "S3Trio ";
62 static char *s3trio_base;
63
64 static struct fb_fix_screeninfo fb_fix;
65 static struct fb_var_screeninfo fb_var = { 0, };
66
67
68     /*
69      *  Interface used by the world
70      */
71
72 static void __init s3triofb_of_init(struct device_node *dp);
73 static int s3trio_get_fix(struct fb_fix_screeninfo *fix, int con,
74                           struct fb_info *info);
75 static int s3trio_get_var(struct fb_var_screeninfo *var, int con,
76                           struct fb_info *info);
77 static int s3trio_set_var(struct fb_var_screeninfo *var, int con,
78                           struct fb_info *info);
79 static int s3trio_get_cmap(struct fb_cmap *cmap, int kspc, int con,
80                            struct fb_info *info);
81 static int s3trio_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
82                          u_int transp, struct fb_info *info);
83 static int s3trio_pan_display(struct fb_var_screeninfo *var, int con,
84                               struct fb_info *info);
85 static void s3triofb_blank(int blank, struct fb_info *info);
86
87     /*
88      *  Interface to the low level console driver
89      */
90
91 int s3triofb_init(void);
92 static int s3triofbcon_switch(int con, struct fb_info *info);
93 static int s3triofbcon_updatevar(int con, struct fb_info *info);
94
95     /*
96      *  Text console acceleration
97      */
98
99 #ifdef FBCON_HAS_CFB8
100 static struct display_switch fbcon_trio8;
101 #endif
102
103     /*
104      *    Accelerated Functions used by the low level console driver
105      */
106
107 static void Trio_WaitQueue(u_short fifo);
108 static void Trio_WaitBlit(void);
109 static void Trio_BitBLT(u_short curx, u_short cury, u_short destx,
110                         u_short desty, u_short width, u_short height,
111                         u_short mode);
112 static void Trio_RectFill(u_short x, u_short y, u_short width, u_short height,
113                           u_short mode, u_short color);
114 static void Trio_MoveCursor(u_short x, u_short y);
115
116
117     /*
118      *  Internal routines
119      */
120
121 static int s3trio_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue,
122                          u_int *transp, struct fb_info *info);
123
124 static struct fb_ops s3trio_ops = {
125         .owner =        THIS_MODULE,
126         .fb_get_fix =   s3trio_get_fix,
127         .fb_get_var =   s3trio_get_var,
128         .fb_set_var =   s3trio_set_var,
129         .fb_get_cmap =  s3trio_get_cmap,
130         .fb_set_cmap =  gen_set_cmap,
131         .fb_setcolreg = s3trio_setcolreg,
132         .fb_pan_display =s3trio_pan_display,
133         .fb_blank =     s3triofb_blank,
134 };
135
136     /*
137      *  Get the Fixed Part of the Display
138      */
139
140 static int s3trio_get_fix(struct fb_fix_screeninfo *fix, int con,
141                           struct fb_info *info)
142 {
143     memcpy(fix, &fb_fix, sizeof(fb_fix));
144     return 0;
145 }
146
147
148     /*
149      *  Get the User Defined Part of the Display
150      */
151
152 static int s3trio_get_var(struct fb_var_screeninfo *var, int con,
153                           struct fb_info *info)
154 {
155     memcpy(var, &fb_var, sizeof(fb_var));
156     return 0;
157 }
158
159
160     /*
161      *  Set the User Defined Part of the Display
162      */
163
164 static int s3trio_set_var(struct fb_var_screeninfo *var, int con,
165                           struct fb_info *info)
166 {
167     if (var->xres > fb_var.xres || var->yres > fb_var.yres ||
168         var->bits_per_pixel > fb_var.bits_per_pixel )
169         /* || var->nonstd || var->vmode != FB_VMODE_NONINTERLACED) */
170         return -EINVAL;
171     if (var->xres_virtual > fb_var.xres_virtual) {
172         outw(IO_OUT16VAL((var->xres_virtual /8) & 0xff, 0x13), 0x3d4);
173         outw(IO_OUT16VAL(((var->xres_virtual /8 ) & 0x300) >> 3, 0x51), 0x3d4);
174         fb_var.xres_virtual = var->xres_virtual;
175         fb_fix.line_length = var->xres_virtual;
176     }
177     fb_var.yres_virtual = var->yres_virtual;
178     memcpy(var, &fb_var, sizeof(fb_var));
179     return 0;
180 }
181
182
183     /*
184      *  Pan or Wrap the Display
185      *
186      *  This call looks only at xoffset, yoffset and the FB_VMODE_YWRAP flag
187      */
188
189 static int s3trio_pan_display(struct fb_var_screeninfo *var, int con,
190                               struct fb_info *info)
191 {
192     unsigned int base;
193
194     if (var->xoffset > (var->xres_virtual - var->xres))
195         return -EINVAL;
196     if (var->yoffset > (var->yres_virtual - var->yres))
197         return -EINVAL;
198
199     fb_var.xoffset = var->xoffset;
200     fb_var.yoffset = var->yoffset;
201
202     base = var->yoffset * fb_fix.line_length + var->xoffset;
203
204     outw(IO_OUT16VAL((base >> 8) & 0xff, 0x0c),0x03D4);
205     outw(IO_OUT16VAL(base  & 0xff, 0x0d),0x03D4);
206     outw(IO_OUT16VAL((base >> 16) & 0xf, 0x69),0x03D4);
207     return 0;
208 }
209
210
211     /*
212      *  Get the Colormap
213      */
214
215 static int s3trio_get_cmap(struct fb_cmap *cmap, int kspc, int con,
216                            struct fb_info *info)
217 {
218     if (con == info->currcon) /* current console? */
219         return fb_get_cmap(cmap, kspc, s3trio_getcolreg, info);
220     else if (fb_display[con].cmap.len) /* non default colormap? */
221         fb_copy_cmap(&fb_display[con].cmap, cmap, kspc ? 0 : 2);
222     else
223         fb_copy_cmap(fb_default_cmap(1 << fb_display[con].var.bits_per_pixel),
224                      cmap, kspc ? 0 : 2);
225     return 0;
226 }
227
228 int __init s3triofb_init(void)
229 {
230         struct device_node *dp;
231
232         dp = find_devices("S3Trio");
233         if (dp != 0)
234             s3triofb_of_init(dp);
235         return 0;
236 }
237
238 void __init s3trio_resetaccel(void){
239
240
241 #define EC01_ENH_ENB    0x0005
242 #define EC01_LAW_ENB    0x0010
243 #define EC01_MMIO_ENB   0x0020
244
245 #define EC00_RESET      0x8000
246 #define EC00_ENABLE     0x4000
247 #define MF_MULT_MISC    0xE000
248 #define SRC_FOREGROUND  0x0020
249 #define SRC_BACKGROUND  0x0000
250 #define MIX_SRC                 0x0007
251 #define MF_T_CLIP       0x1000
252 #define MF_L_CLIP       0x2000
253 #define MF_B_CLIP       0x3000
254 #define MF_R_CLIP       0x4000
255 #define MF_PIX_CONTROL  0xA000
256 #define MFA_SRC_FOREGR_MIX      0x0000
257 #define MF_PIX_CONTROL  0xA000
258
259         outw(EC00_RESET,  0x42e8);
260         inw(  0x42e8);
261         outw(EC00_ENABLE,  0x42e8);
262         inw(  0x42e8);
263         outw(EC01_ENH_ENB | EC01_LAW_ENB,
264                    0x4ae8);
265         outw(MF_MULT_MISC,  0xbee8); /* 16 bit I/O registers */
266
267         /* Now set some basic accelerator registers */
268         Trio_WaitQueue(0x0400);
269         outw(SRC_FOREGROUND | MIX_SRC, 0xbae8);
270         outw(SRC_BACKGROUND | MIX_SRC,  0xb6e8);/* direct color*/
271         outw(MF_T_CLIP | 0, 0xbee8 );     /* clip virtual area  */
272         outw(MF_L_CLIP | 0, 0xbee8 );
273         outw(MF_R_CLIP | (640 - 1), 0xbee8);
274         outw(MF_B_CLIP | (480 - 1),  0xbee8);
275         Trio_WaitQueue(0x0400);
276         outw(0xffff,  0xaae8);       /* Enable all planes */
277         outw(0xffff, 0xaae8);       /* Enable all planes */
278         outw( MF_PIX_CONTROL | MFA_SRC_FOREGR_MIX,  0xbee8);
279 }
280
281 int __init s3trio_init(struct device_node *dp){
282
283     u_char bus, dev;
284     unsigned int t32;
285     unsigned short cmd;
286
287         pci_device_loc(dp,&bus,&dev);
288                 pcibios_read_config_dword(bus, dev, PCI_VENDOR_ID, &t32);
289                 if(t32 == (PCI_DEVICE_ID_S3_TRIO << 16) + PCI_VENDOR_ID_S3) {
290                         pcibios_read_config_dword(bus, dev, PCI_BASE_ADDRESS_0, &t32);
291                         pcibios_read_config_dword(bus, dev, PCI_BASE_ADDRESS_1, &t32);
292                         pcibios_read_config_word(bus, dev, PCI_COMMAND,&cmd);
293
294                         pcibios_write_config_word(bus, dev, PCI_COMMAND, PCI_COMMAND_IO | PCI_COMMAND_MEMORY);
295
296                         pcibios_write_config_dword(bus, dev, PCI_BASE_ADDRESS_0,0xffffffff);
297                         pcibios_read_config_dword(bus, dev, PCI_BASE_ADDRESS_0, &t32);
298
299 /* This is a gross hack as OF only maps enough memory for the framebuffer and
300    we want to use MMIO too. We should find out which chunk of address space
301    we can use here */
302                         pcibios_write_config_dword(bus,dev,PCI_BASE_ADDRESS_0,0xc6000000);
303
304                         /* unlock s3 */
305
306                         outb(0x01, 0x3C3);
307
308                         outb(inb(0x03CC) | 1, 0x3c2);
309
310                         outw(IO_OUT16VAL(0x48, 0x38),0x03D4);
311                         outw(IO_OUT16VAL(0xA0, 0x39),0x03D4);
312                         outb(0x33,0x3d4);
313                         outw(IO_OUT16VAL((inb(0x3d5) & ~(0x2 | 0x10 |  0x40)) |
314                                           0x20, 0x33), 0x3d4);
315
316                         outw(IO_OUT16VAL(0x6, 0x8), 0x3c4);
317
318                         /* switch to MMIO only mode */
319
320                         outb(0x58, 0x3d4);
321                         outw(IO_OUT16VAL(inb(0x3d5) | 3 | 0x10, 0x58), 0x3d4);
322                         outw(IO_OUT16VAL(8, 0x53), 0x3d4);
323
324                         /* switch off I/O accesses */
325
326 #if 0
327                         pcibios_write_config_word(bus, dev, PCI_COMMAND,
328                                         PCI_COMMAND_IO | PCI_COMMAND_MEMORY);
329 #endif
330                         return 1;
331                 }
332
333         return 0;
334 }
335
336
337     /*
338      *  Initialisation
339      *  We heavily rely on OF for the moment. This needs fixing.
340      */
341
342 static void __init s3triofb_of_init(struct device_node *dp)
343 {
344     int i, *pp, len;
345     unsigned long address, size;
346     u_long *CursorBase;
347
348     strncat(s3trio_name, dp->name, sizeof(s3trio_name));
349     s3trio_name[sizeof(s3trio_name)-1] = '\0';
350     strcpy(fb_fix.id, s3trio_name);
351
352     if((pp = get_property(dp, "vendor-id", &len)) != NULL
353         && *pp!=PCI_VENDOR_ID_S3) {
354         printk("%s: can't find S3 Trio board\n", dp->full_name);
355         return;
356     }
357
358     if((pp = get_property(dp, "device-id", &len)) != NULL
359         && *pp!=PCI_DEVICE_ID_S3_TRIO) {
360         printk("%s: can't find S3 Trio board\n", dp->full_name);
361         return;
362     }
363
364     if ((pp = get_property(dp, "depth", &len)) != NULL
365         && len == sizeof(int) && *pp != 8) {
366         printk("%s: can't use depth = %d\n", dp->full_name, *pp);
367         return;
368     }
369     if ((pp = get_property(dp, "width", &len)) != NULL
370         && len == sizeof(int))
371         fb_var.xres = fb_var.xres_virtual = *pp;
372     if ((pp = get_property(dp, "height", &len)) != NULL
373         && len == sizeof(int))
374         fb_var.yres = fb_var.yres_virtual = *pp;
375     if ((pp = get_property(dp, "linebytes", &len)) != NULL
376         && len == sizeof(int))
377         fb_fix.line_length = *pp;
378     else
379         fb_fix.line_length = fb_var.xres_virtual;
380     fb_fix.smem_len = fb_fix.line_length*fb_var.yres;
381
382     address = 0xc6000000;
383     size = 64*1024*1024;
384     if (!request_mem_region(address, size, "S3triofb"))
385         return;
386
387     s3trio_init(dp);
388     s3trio_base = ioremap(address, size);
389     fb_fix.smem_start = address;
390     fb_fix.type = FB_TYPE_PACKED_PIXELS;
391     fb_fix.type_aux = 0;
392     fb_fix.accel = FB_ACCEL_S3_TRIO64;
393     fb_fix.mmio_start = address+0x1000000;
394     fb_fix.mmio_len = 0x1000000;
395
396     fb_fix.xpanstep = 1;
397     fb_fix.ypanstep = 1;
398
399     s3trio_resetaccel();
400
401     mem_out8(0x30, s3trio_base+0x1008000 + 0x03D4);
402     mem_out8(0x2d, s3trio_base+0x1008000 + 0x03D4);
403     mem_out8(0x2e, s3trio_base+0x1008000 + 0x03D4);
404
405     mem_out8(0x50, s3trio_base+0x1008000 + 0x03D4);
406
407     /* disable HW cursor */
408
409     mem_out8(0x39, s3trio_base+0x1008000 + 0x03D4);
410     mem_out8(0xa0, s3trio_base+0x1008000 + 0x03D5);
411
412     mem_out8(0x45, s3trio_base+0x1008000 + 0x03D4);
413     mem_out8(0, s3trio_base+0x1008000 + 0x03D5);
414
415     mem_out8(0x4e, s3trio_base+0x1008000 + 0x03D4);
416     mem_out8(0, s3trio_base+0x1008000 + 0x03D5);
417
418     mem_out8(0x4f, s3trio_base+0x1008000 + 0x03D4);
419     mem_out8(0, s3trio_base+0x1008000 + 0x03D5);
420
421     /* init HW cursor */
422
423     CursorBase = (u_long *)(s3trio_base + 2*1024*1024 - 0x400);
424         for (i = 0; i < 8; i++) {
425                 *(CursorBase  +(i*4)) = 0xffffff00;
426                 *(CursorBase+1+(i*4)) = 0xffff0000;
427                 *(CursorBase+2+(i*4)) = 0xffff0000;
428                 *(CursorBase+3+(i*4)) = 0xffff0000;
429         }
430         for (i = 8; i < 64; i++) {
431                 *(CursorBase  +(i*4)) = 0xffff0000;
432                 *(CursorBase+1+(i*4)) = 0xffff0000;
433                 *(CursorBase+2+(i*4)) = 0xffff0000;
434                 *(CursorBase+3+(i*4)) = 0xffff0000;
435         }
436
437
438     mem_out8(0x4c, s3trio_base+0x1008000 + 0x03D4);
439     mem_out8(((2*1024 - 1)&0xf00)>>8, s3trio_base+0x1008000 + 0x03D5);
440
441     mem_out8(0x4d, s3trio_base+0x1008000 + 0x03D4);
442     mem_out8((2*1024 - 1) & 0xff, s3trio_base+0x1008000 + 0x03D5);
443
444     mem_out8(0x45, s3trio_base+0x1008000 + 0x03D4);
445     mem_in8(s3trio_base+0x1008000 + 0x03D4);
446
447     mem_out8(0x4a, s3trio_base+0x1008000 + 0x03D4);
448     mem_out8(0x80, s3trio_base+0x1008000 + 0x03D5);
449     mem_out8(0x80, s3trio_base+0x1008000 + 0x03D5);
450     mem_out8(0x80, s3trio_base+0x1008000 + 0x03D5);
451
452     mem_out8(0x4b, s3trio_base+0x1008000 + 0x03D4);
453     mem_out8(0x00, s3trio_base+0x1008000 + 0x03D5);
454     mem_out8(0x00, s3trio_base+0x1008000 + 0x03D5);
455     mem_out8(0x00, s3trio_base+0x1008000 + 0x03D5);
456
457     mem_out8(0x45, s3trio_base+0x1008000 + 0x03D4);
458     mem_out8(0, s3trio_base+0x1008000 + 0x03D5);
459
460     /* setup default color table */
461
462         for(i = 0; i < 16; i++) {
463                 int j = color_table[i];
464                 palette[i].red=default_red[j];
465                 palette[i].green=default_grn[j];
466                 palette[i].blue=default_blu[j];
467         }
468
469     s3trio_setcolreg(255, 56, 100, 160, 0, NULL /* not used */);
470     s3trio_setcolreg(254, 0, 0, 0, 0, NULL /* not used */);
471     memset((char *)s3trio_base, 0, 640*480);
472
473 #if 0
474     Trio_RectFill(0, 0, 90, 90, 7, 1);
475 #endif
476
477     fb_fix.visual = FB_VISUAL_PSEUDOCOLOR ;
478     fb_var.xoffset = fb_var.yoffset = 0;
479     fb_var.bits_per_pixel = 8;
480     fb_var.grayscale = 0;
481     fb_var.red.offset = fb_var.green.offset = fb_var.blue.offset = 0;
482     fb_var.red.length = fb_var.green.length = fb_var.blue.length = 8;
483     fb_var.red.msb_right = fb_var.green.msb_right = fb_var.blue.msb_right = 0;
484     fb_var.transp.offset = fb_var.transp.length = fb_var.transp.msb_right = 0;
485     fb_var.nonstd = 0;
486     fb_var.activate = 0;
487     fb_var.height = fb_var.width = -1;
488     fb_var.accel_flags = FB_ACCELF_TEXT;
489 #warning FIXME: always obey fb_var.accel_flags
490     fb_var.pixclock = 1;
491     fb_var.left_margin = fb_var.right_margin = 0;
492     fb_var.upper_margin = fb_var.lower_margin = 0;
493     fb_var.hsync_len = fb_var.vsync_len = 0;
494     fb_var.sync = 0;
495     fb_var.vmode = FB_VMODE_NONINTERLACED;
496
497     disp.var = fb_var;
498     disp.cmap.start = 0;
499     disp.cmap.len = 0;
500     disp.cmap.red = disp.cmap.green = disp.cmap.blue = disp.cmap.transp = NULL;
501     disp.visual = fb_fix.visual;
502     disp.type = fb_fix.type;
503     disp.type_aux = fb_fix.type_aux;
504     disp.ypanstep = 0;
505     disp.ywrapstep = 0;
506     disp.line_length = fb_fix.line_length;
507     disp.can_soft_blank = 1;
508     disp.inverse = 0;
509 #ifdef FBCON_HAS_CFB8
510     if (fb_var.accel_flags & FB_ACCELF_TEXT)
511         disp.dispsw = &fbcon_trio8;
512     else
513         disp.dispsw = &fbcon_cfb8;
514 #else
515     disp.dispsw = &fbcon_dummy;
516 #endif
517     disp.scrollmode = fb_var.accel_flags & FB_ACCELF_TEXT ? 0 : SCROLL_YREDRAW;
518
519     strcpy(fb_info.modename, "Trio64 ");
520     strncat(fb_info.modename, dp->full_name, sizeof(fb_info.modename));
521     fb_info.currcon = -1;
522     fb_info.fbops = &s3trio_ops;
523     fb_info.screen_base = s3trio_base;  
524 #if 0
525     fb_info.fbvar_num = 1;
526     fb_info.fbvar = &fb_var;
527 #endif
528     fb_info.disp = &disp;
529     fb_info.fontname[0] = '\0';
530     fb_info.changevar = NULL;
531     fb_info.switch_con = &s3triofbcon_switch;
532     fb_info.updatevar = &s3triofbcon_updatevar;
533 #if 0
534     fb_info.setcmap = &s3triofbcon_setcmap;
535 #endif
536
537     fb_info.flags = FBINFO_FLAG_DEFAULT;
538     if (register_framebuffer(&fb_info) < 0) {
539                 iounmap(fb_info.screen_base);
540                 fb_info.screen_base = NULL;
541                 return;
542     }
543
544     printk("fb%d: S3 Trio frame buffer device on %s\n",
545            fb_info.node, dp->full_name);
546 }
547
548
549 static int s3triofbcon_switch(int con, struct fb_info *info)
550 {
551     /* Do we have to save the colormap? */
552     if (fb_display[info->currcon].cmap.len)
553         fb_get_cmap(&fb_display[info->currcon].cmap, 1, s3trio_getcolreg, info);
554
555     info->currcon = con;
556     /* Install new colormap */
557     do_install_cmap(con,info);
558     return 0;
559 }
560
561     /*
562      *  Update the `var' structure (called by fbcon.c)
563      */
564
565 static int s3triofbcon_updatevar(int con, struct fb_info *info)
566 {
567     /* Nothing */
568     return 0;
569 }
570
571     /*
572      *  Blank the display.
573      */
574
575 static int s3triofb_blank(int blank, struct fb_info *info)
576 {
577     unsigned char x;
578
579     mem_out8(0x1, s3trio_base+0x1008000 + 0x03c4);
580     x = mem_in8(s3trio_base+0x1008000 + 0x03c5);
581     mem_out8((x & (~0x20)) | (blank << 5), s3trio_base+0x1008000 + 0x03c5);
582     return 0;   
583 }
584
585     /*
586      *  Read a single color register and split it into
587      *  colors/transparent. Return != 0 for invalid regno.
588      */
589
590 static int s3trio_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue,
591                          u_int *transp, struct fb_info *info)
592 {
593     if (regno > 255)
594         return 1;
595     *red = (palette[regno].red << 8) | palette[regno].red;
596     *green = (palette[regno].green << 8) | palette[regno].green;
597     *blue = (palette[regno].blue << 8) | palette[regno].blue;
598     *transp = 0;
599     return 0;
600 }
601
602
603     /*
604      *  Set a single color register. Return != 0 for invalid regno.
605      */
606
607 static int s3trio_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
608                             u_int transp, struct fb_info *info)
609 {
610     if (regno > 255)
611         return 1;
612
613     red >>= 8;
614     green >>= 8;
615     blue >>= 8;
616     palette[regno].red = red;
617     palette[regno].green = green;
618     palette[regno].blue = blue;
619
620     mem_out8(regno,s3trio_base+0x1008000 + 0x3c8);
621     mem_out8((red & 0xff) >> 2,s3trio_base+0x1008000 + 0x3c9);
622     mem_out8((green & 0xff) >> 2,s3trio_base+0x1008000 + 0x3c9);
623     mem_out8((blue & 0xff) >> 2,s3trio_base+0x1008000 + 0x3c9);
624
625     return 0;
626 }
627
628 static void Trio_WaitQueue(u_short fifo) {
629
630         u_short status;
631
632         do
633         {
634                 status = mem_in16(s3trio_base + 0x1000000 + 0x9AE8);
635         }  while (!(status & fifo));
636
637 }
638
639 static void Trio_WaitBlit(void) {
640
641         u_short status;
642
643         do
644         {
645                 status = mem_in16(s3trio_base + 0x1000000 + 0x9AE8);
646         }  while (status & 0x200);
647
648 }
649
650 static void Trio_BitBLT(u_short curx, u_short cury, u_short destx,
651                         u_short desty, u_short width, u_short height,
652                         u_short mode) {
653
654         u_short blitcmd = 0xc011;
655
656         /* Set drawing direction */
657         /* -Y, X maj, -X (default) */
658
659         if (curx > destx)
660                 blitcmd |= 0x0020;  /* Drawing direction +X */
661         else {
662                 curx  += (width - 1);
663                 destx += (width - 1);
664         }
665
666         if (cury > desty)
667                 blitcmd |= 0x0080;  /* Drawing direction +Y */
668         else {
669                 cury  += (height - 1);
670                 desty += (height - 1);
671         }
672
673         Trio_WaitQueue(0x0400);
674
675         outw(0xa000,  0xBEE8);
676         outw(0x60 | mode,  0xBAE8);
677
678         outw(curx,  0x86E8);
679         outw(cury,  0x82E8);
680
681         outw(destx,  0x8EE8);
682         outw(desty,  0x8AE8);
683
684         outw(height - 1,  0xBEE8);
685         outw(width - 1,  0x96E8);
686
687         outw(blitcmd,  0x9AE8);
688
689 }
690
691 static void Trio_RectFill(u_short x, u_short y, u_short width, u_short height,
692                           u_short mode, u_short color) {
693
694         u_short blitcmd = 0x40b1;
695
696         Trio_WaitQueue(0x0400);
697
698         outw(0xa000,  0xBEE8);
699         outw((0x20 | mode),  0xBAE8);
700         outw(0xe000,  0xBEE8);
701         outw(color,  0xA6E8);
702         outw(x,  0x86E8);
703         outw(y,  0x82E8);
704         outw((height - 1), 0xBEE8);
705         outw((width - 1), 0x96E8);
706         outw(blitcmd,  0x9AE8);
707
708 }
709
710
711 static void Trio_MoveCursor(u_short x, u_short y) {
712
713         mem_out8(0x39, s3trio_base + 0x1008000 + 0x3d4);
714         mem_out8(0xa0, s3trio_base + 0x1008000 + 0x3d5);
715
716         mem_out8(0x46, s3trio_base + 0x1008000 + 0x3d4);
717         mem_out8((x & 0x0700) >> 8, s3trio_base + 0x1008000 + 0x3d5);
718         mem_out8(0x47, s3trio_base + 0x1008000 + 0x3d4);
719         mem_out8(x & 0x00ff, s3trio_base + 0x1008000 + 0x3d5);
720
721         mem_out8(0x48, s3trio_base + 0x1008000 + 0x3d4);
722         mem_out8((y & 0x0700) >> 8, s3trio_base + 0x1008000 + 0x3d5);
723         mem_out8(0x49, s3trio_base + 0x1008000 + 0x3d4);
724         mem_out8(y & 0x00ff, s3trio_base + 0x1008000 + 0x3d5);
725
726 }
727
728
729     /*
730      *  Text console acceleration
731      */
732
733 #ifdef FBCON_HAS_CFB8
734 static void fbcon_trio8_bmove(struct display *p, int sy, int sx, int dy,
735                               int dx, int height, int width)
736 {
737     sx *= 8; dx *= 8; width *= 8;
738     Trio_BitBLT((u_short)sx, (u_short)(sy*fontheight(p)), (u_short)dx,
739                  (u_short)(dy*fontheight(p)), (u_short)width,
740                  (u_short)(height*fontheight(p)), (u_short)S3_NEW);
741 }
742
743 static void fbcon_trio8_clear(struct vc_data *conp, struct display *p, int sy,
744                               int sx, int height, int width)
745 {
746     unsigned char bg;
747
748     sx *= 8; width *= 8;
749     bg = attr_bgcol_ec(p,conp);
750     Trio_RectFill((u_short)sx,
751                    (u_short)(sy*fontheight(p)),
752                    (u_short)width,
753                    (u_short)(height*fontheight(p)),
754                    (u_short)S3_NEW,
755                    (u_short)bg);
756 }
757
758 static void fbcon_trio8_putc(struct vc_data *conp, struct display *p, int c,
759                              int yy, int xx)
760 {
761     Trio_WaitBlit();
762     fbcon_cfb8_putc(conp, p, c, yy, xx);
763 }
764
765 static void fbcon_trio8_putcs(struct vc_data *conp, struct display *p,
766                               const unsigned short *s, int count, int yy, int xx)
767 {
768     Trio_WaitBlit();
769     fbcon_cfb8_putcs(conp, p, s, count, yy, xx);
770 }
771
772 static void fbcon_trio8_revc(struct display *p, int xx, int yy)
773 {
774     Trio_WaitBlit();
775     fbcon_cfb8_revc(p, xx, yy);
776 }
777
778 static struct display_switch fbcon_trio8 = {
779    .setup =             fbcon_cfb8_setup,
780    .bmove =             fbcon_trio8_bmove,
781    .clear =             fbcon_trio8_clear,
782    .putc =              fbcon_trio8_putc,
783    .putcs =             fbcon_trio8_putcs,
784    .revc =              fbcon_trio8_revc,
785    .clear_margins =     fbcon_cfb8_clear_margins,
786    .fontwidthmask =     FONTWIDTH(8)
787 };
788 #endif
789
790 MODULE_LICENSE("GPL");