Import 2.4.0-test5pre6
[davej-history.git] / drivers / video / S3triofb.c
blob333fd6576ef76b88879590a3610715f104b3fd2c
1 /*
2 * linux/drivers/video/S3Triofb.c -- Open Firmware based frame buffer device
4 * Copyright (C) 1997 Peter De Schrijver
6 * This driver is partly based on the PowerMac console driver:
8 * Copyright (C) 1996 Paul Mackerras
10 * and on the Open Firmware based frame buffer device:
12 * Copyright (C) 1997 Geert Uytterhoeven
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.
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.
26 #include <linux/config.h>
27 #include <linux/kernel.h>
28 #include <linux/module.h>
29 #include <linux/errno.h>
30 #include <linux/string.h>
31 #include <linux/mm.h>
32 #include <linux/tty.h>
33 #include <linux/malloc.h>
34 #include <linux/vmalloc.h>
35 #include <linux/delay.h>
36 #include <linux/interrupt.h>
37 #include <linux/fb.h>
38 #include <linux/init.h>
39 #include <linux/selection.h>
40 #include <asm/io.h>
41 #include <asm/prom.h>
42 #include <asm/pci-bridge.h>
43 #include <linux/pci.h>
44 #ifdef CONFIG_FB_COMPAT_XPMAC
45 #include <asm/vc_ioctl.h>
46 #endif
48 #include <video/fbcon.h>
49 #include <video/fbcon-cfb8.h>
50 #include <video/s3blit.h>
53 #define mem_in8(addr) in_8((void *)(addr))
54 #define mem_in16(addr) in_le16((void *)(addr))
55 #define mem_in32(addr) in_le32((void *)(addr))
57 #define mem_out8(val, addr) out_8((void *)(addr), val)
58 #define mem_out16(val, addr) out_le16((void *)(addr), val)
59 #define mem_out32(val, addr) out_le32((void *)(addr), val)
61 #define IO_OUT16VAL(v, r) (((v) << 8) | (r))
63 #define arraysize(x) (sizeof(x)/sizeof(*(x)))
65 static int currcon = 0;
66 static struct display disp;
67 static struct fb_info fb_info;
68 static struct { u_char red, green, blue, pad; } palette[256];
69 static char s3trio_name[16] = "S3Trio ";
70 static char *s3trio_base;
72 static struct fb_fix_screeninfo fb_fix;
73 static struct fb_var_screeninfo fb_var = { 0, };
77 * Interface used by the world
80 static int s3trio_get_fix(struct fb_fix_screeninfo *fix, int con,
81 struct fb_info *info);
82 static int s3trio_get_var(struct fb_var_screeninfo *var, int con,
83 struct fb_info *info);
84 static int s3trio_set_var(struct fb_var_screeninfo *var, int con,
85 struct fb_info *info);
86 static int s3trio_get_cmap(struct fb_cmap *cmap, int kspc, int con,
87 struct fb_info *info);
88 static int s3trio_set_cmap(struct fb_cmap *cmap, int kspc, int con,
89 struct fb_info *info);
90 static int s3trio_pan_display(struct fb_var_screeninfo *var, int con,
91 struct fb_info *info);
95 * Interface to the low level console driver
98 int s3triofb_init(void);
99 static int s3triofbcon_switch(int con, struct fb_info *info);
100 static int s3triofbcon_updatevar(int con, struct fb_info *info);
101 static void s3triofbcon_blank(int blank, struct fb_info *info);
102 #if 0
103 static int s3triofbcon_setcmap(struct fb_cmap *cmap, int con);
104 #endif
107 * Text console acceleration
110 #ifdef FBCON_HAS_CFB8
111 static struct display_switch fbcon_trio8;
112 #endif
115 * Accelerated Functions used by the low level console driver
118 static void Trio_WaitQueue(u_short fifo);
119 static void Trio_WaitBlit(void);
120 static void Trio_BitBLT(u_short curx, u_short cury, u_short destx,
121 u_short desty, u_short width, u_short height,
122 u_short mode);
123 static void Trio_RectFill(u_short x, u_short y, u_short width, u_short height,
124 u_short mode, u_short color);
125 static void Trio_MoveCursor(u_short x, u_short y);
129 * Internal routines
132 static int s3trio_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue,
133 u_int *transp, struct fb_info *info);
134 static int s3trio_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
135 u_int transp, struct fb_info *info);
136 static void do_install_cmap(int con, struct fb_info *info);
139 static struct fb_ops s3trio_ops = {
140 owner: THIS_MODULE,
141 fb_get_fix: s3trio_get_fix,
142 fb_get_var: s3trio_get_var,
143 fb_set_var: s3trio_set_var,
144 fb_get_cmap: s3trio_get_cmap,
145 fb_set_cmap: s3trio_set_cmap,
146 fb_pan_display: s3trio_pan_display,
150 * Get the Fixed Part of the Display
153 static int s3trio_get_fix(struct fb_fix_screeninfo *fix, int con,
154 struct fb_info *info)
156 memcpy(fix, &fb_fix, sizeof(fb_fix));
157 return 0;
162 * Get the User Defined Part of the Display
165 static int s3trio_get_var(struct fb_var_screeninfo *var, int con,
166 struct fb_info *info)
168 memcpy(var, &fb_var, sizeof(fb_var));
169 return 0;
174 * Set the User Defined Part of the Display
177 static int s3trio_set_var(struct fb_var_screeninfo *var, int con,
178 struct fb_info *info)
180 if (var->xres > fb_var.xres || var->yres > fb_var.yres ||
181 var->bits_per_pixel > fb_var.bits_per_pixel )
182 /* || var->nonstd || var->vmode != FB_VMODE_NONINTERLACED) */
183 return -EINVAL;
184 if (var->xres_virtual > fb_var.xres_virtual) {
185 outw(IO_OUT16VAL((var->xres_virtual /8) & 0xff, 0x13), 0x3d4);
186 outw(IO_OUT16VAL(((var->xres_virtual /8 ) & 0x300) >> 3, 0x51), 0x3d4);
187 fb_var.xres_virtual = var->xres_virtual;
188 fb_fix.line_length = var->xres_virtual;
190 fb_var.yres_virtual = var->yres_virtual;
191 memcpy(var, &fb_var, sizeof(fb_var));
192 return 0;
197 * Pan or Wrap the Display
199 * This call looks only at xoffset, yoffset and the FB_VMODE_YWRAP flag
202 static int s3trio_pan_display(struct fb_var_screeninfo *var, int con,
203 struct fb_info *info)
205 unsigned int base;
207 if (var->xoffset > (var->xres_virtual - var->xres))
208 return -EINVAL;
209 if (var->yoffset > (var->yres_virtual - var->yres))
210 return -EINVAL;
212 fb_var.xoffset = var->xoffset;
213 fb_var.yoffset = var->yoffset;
215 base = var->yoffset * fb_fix.line_length + var->xoffset;
217 outw(IO_OUT16VAL((base >> 8) & 0xff, 0x0c),0x03D4);
218 outw(IO_OUT16VAL(base & 0xff, 0x0d),0x03D4);
219 outw(IO_OUT16VAL((base >> 16) & 0xf, 0x69),0x03D4);
220 return 0;
225 * Get the Colormap
228 static int s3trio_get_cmap(struct fb_cmap *cmap, int kspc, int con,
229 struct fb_info *info)
231 if (con == currcon) /* current console? */
232 return fb_get_cmap(cmap, kspc, s3trio_getcolreg, info);
233 else if (fb_display[con].cmap.len) /* non default colormap? */
234 fb_copy_cmap(&fb_display[con].cmap, cmap, kspc ? 0 : 2);
235 else
236 fb_copy_cmap(fb_default_cmap(1 << fb_display[con].var.bits_per_pixel),
237 cmap, kspc ? 0 : 2);
238 return 0;
242 * Set the Colormap
245 static int s3trio_set_cmap(struct fb_cmap *cmap, int kspc, int con,
246 struct fb_info *info)
248 int err;
251 if (!fb_display[con].cmap.len) { /* no colormap allocated? */
252 if ((err = fb_alloc_cmap(&fb_display[con].cmap,
253 1<<fb_display[con].var.bits_per_pixel, 0)))
254 return err;
256 if (con == currcon) /* current console? */
257 return fb_set_cmap(cmap, kspc, s3trio_setcolreg, info);
258 else
259 fb_copy_cmap(cmap, &fb_display[con].cmap, kspc ? 0 : 1);
260 return 0;
264 int __init s3triofb_init(void)
266 #ifdef __powerpc__
267 /* We don't want to be called like this. */
268 /* We rely on Open Firmware (offb) instead. */
269 #else /* !__powerpc__ */
270 /* To be merged with cybervision */
271 #endif /* !__powerpc__ */
272 return 0;
275 void __init s3trio_resetaccel(void){
278 #define EC01_ENH_ENB 0x0005
279 #define EC01_LAW_ENB 0x0010
280 #define EC01_MMIO_ENB 0x0020
282 #define EC00_RESET 0x8000
283 #define EC00_ENABLE 0x4000
284 #define MF_MULT_MISC 0xE000
285 #define SRC_FOREGROUND 0x0020
286 #define SRC_BACKGROUND 0x0000
287 #define MIX_SRC 0x0007
288 #define MF_T_CLIP 0x1000
289 #define MF_L_CLIP 0x2000
290 #define MF_B_CLIP 0x3000
291 #define MF_R_CLIP 0x4000
292 #define MF_PIX_CONTROL 0xA000
293 #define MFA_SRC_FOREGR_MIX 0x0000
294 #define MF_PIX_CONTROL 0xA000
296 outw(EC00_RESET, 0x42e8);
297 inw( 0x42e8);
298 outw(EC00_ENABLE, 0x42e8);
299 inw( 0x42e8);
300 outw(EC01_ENH_ENB | EC01_LAW_ENB,
301 0x4ae8);
302 outw(MF_MULT_MISC, 0xbee8); /* 16 bit I/O registers */
304 /* Now set some basic accelerator registers */
305 Trio_WaitQueue(0x0400);
306 outw(SRC_FOREGROUND | MIX_SRC, 0xbae8);
307 outw(SRC_BACKGROUND | MIX_SRC, 0xb6e8);/* direct color*/
308 outw(MF_T_CLIP | 0, 0xbee8 ); /* clip virtual area */
309 outw(MF_L_CLIP | 0, 0xbee8 );
310 outw(MF_R_CLIP | (640 - 1), 0xbee8);
311 outw(MF_B_CLIP | (480 - 1), 0xbee8);
312 Trio_WaitQueue(0x0400);
313 outw(0xffff, 0xaae8); /* Enable all planes */
314 outw(0xffff, 0xaae8); /* Enable all planes */
315 outw( MF_PIX_CONTROL | MFA_SRC_FOREGR_MIX, 0xbee8);
318 int __init s3trio_init(struct device_node *dp){
320 u_char bus, dev;
321 unsigned int t32;
322 unsigned short cmd;
324 pci_device_loc(dp,&bus,&dev);
325 pcibios_read_config_dword(bus, dev, PCI_VENDOR_ID, &t32);
326 if(t32 == (PCI_DEVICE_ID_S3_TRIO << 16) + PCI_VENDOR_ID_S3) {
327 pcibios_read_config_dword(bus, dev, PCI_BASE_ADDRESS_0, &t32);
328 pcibios_read_config_dword(bus, dev, PCI_BASE_ADDRESS_1, &t32);
329 pcibios_read_config_word(bus, dev, PCI_COMMAND,&cmd);
331 pcibios_write_config_word(bus, dev, PCI_COMMAND, PCI_COMMAND_IO | PCI_COMMAND_MEMORY);
333 pcibios_write_config_dword(bus, dev, PCI_BASE_ADDRESS_0,0xffffffff);
334 pcibios_read_config_dword(bus, dev, PCI_BASE_ADDRESS_0, &t32);
336 /* This is a gross hack as OF only maps enough memory for the framebuffer and
337 we want to use MMIO too. We should find out which chunk of address space
338 we can use here */
339 pcibios_write_config_dword(bus,dev,PCI_BASE_ADDRESS_0,0xc6000000);
341 /* unlock s3 */
343 outb(0x01, 0x3C3);
345 outb(inb(0x03CC) | 1, 0x3c2);
347 outw(IO_OUT16VAL(0x48, 0x38),0x03D4);
348 outw(IO_OUT16VAL(0xA0, 0x39),0x03D4);
349 outb(0x33,0x3d4);
350 outw(IO_OUT16VAL((inb(0x3d5) & ~(0x2 | 0x10 | 0x40)) |
351 0x20, 0x33), 0x3d4);
353 outw(IO_OUT16VAL(0x6, 0x8), 0x3c4);
355 /* switch to MMIO only mode */
357 outb(0x58, 0x3d4);
358 outw(IO_OUT16VAL(inb(0x3d5) | 3 | 0x10, 0x58), 0x3d4);
359 outw(IO_OUT16VAL(8, 0x53), 0x3d4);
361 /* switch off I/O accesses */
363 #if 0
364 pcibios_write_config_word(bus, dev, PCI_COMMAND,
365 PCI_COMMAND_IO | PCI_COMMAND_MEMORY);
366 #endif
367 return 1;
370 return 0;
375 * Initialisation
376 * We heavily rely on OF for the moment. This needs fixing.
379 void __init s3triofb_init_of(struct device_node *dp)
381 int i, *pp, len;
382 unsigned long address;
383 u_long *CursorBase;
385 strncat(s3trio_name, dp->name, sizeof(s3trio_name));
386 s3trio_name[sizeof(s3trio_name)-1] = '\0';
387 strcpy(fb_fix.id, s3trio_name);
389 if((pp = (int *)get_property(dp, "vendor-id", &len)) != NULL
390 && *pp!=PCI_VENDOR_ID_S3) {
391 printk("%s: can't find S3 Trio board\n", dp->full_name);
392 return;
395 if((pp = (int *)get_property(dp, "device-id", &len)) != NULL
396 && *pp!=PCI_DEVICE_ID_S3_TRIO) {
397 printk("%s: can't find S3 Trio board\n", dp->full_name);
398 return;
401 if ((pp = (int *)get_property(dp, "depth", &len)) != NULL
402 && len == sizeof(int) && *pp != 8) {
403 printk("%s: can't use depth = %d\n", dp->full_name, *pp);
404 return;
406 if ((pp = (int *)get_property(dp, "width", &len)) != NULL
407 && len == sizeof(int))
408 fb_var.xres = fb_var.xres_virtual = *pp;
409 if ((pp = (int *)get_property(dp, "height", &len)) != NULL
410 && len == sizeof(int))
411 fb_var.yres = fb_var.yres_virtual = *pp;
412 if ((pp = (int *)get_property(dp, "linebytes", &len)) != NULL
413 && len == sizeof(int))
414 fb_fix.line_length = *pp;
415 else
416 fb_fix.line_length = fb_var.xres_virtual;
417 fb_fix.smem_len = fb_fix.line_length*fb_var.yres;
419 s3trio_init(dp);
420 address = 0xc6000000;
421 s3trio_base = ioremap(address,64*1024*1024);
422 fb_fix.smem_start = address;
423 fb_fix.type = FB_TYPE_PACKED_PIXELS;
424 fb_fix.type_aux = 0;
425 fb_fix.accel = FB_ACCEL_S3_TRIO64;
426 fb_fix.mmio_start = address+0x1000000;
427 fb_fix.mmio_len = 0x1000000;
429 fb_fix.xpanstep = 1;
430 fb_fix.ypanstep = 1;
432 s3trio_resetaccel();
434 mem_out8(0x30, s3trio_base+0x1008000 + 0x03D4);
435 mem_out8(0x2d, s3trio_base+0x1008000 + 0x03D4);
436 mem_out8(0x2e, s3trio_base+0x1008000 + 0x03D4);
438 mem_out8(0x50, s3trio_base+0x1008000 + 0x03D4);
440 /* disable HW cursor */
442 mem_out8(0x39, s3trio_base+0x1008000 + 0x03D4);
443 mem_out8(0xa0, s3trio_base+0x1008000 + 0x03D5);
445 mem_out8(0x45, s3trio_base+0x1008000 + 0x03D4);
446 mem_out8(0, s3trio_base+0x1008000 + 0x03D5);
448 mem_out8(0x4e, s3trio_base+0x1008000 + 0x03D4);
449 mem_out8(0, s3trio_base+0x1008000 + 0x03D5);
451 mem_out8(0x4f, s3trio_base+0x1008000 + 0x03D4);
452 mem_out8(0, s3trio_base+0x1008000 + 0x03D5);
454 /* init HW cursor */
456 CursorBase = (u_long *)(s3trio_base + 2*1024*1024 - 0x400);
457 for (i = 0; i < 8; i++) {
458 *(CursorBase +(i*4)) = 0xffffff00;
459 *(CursorBase+1+(i*4)) = 0xffff0000;
460 *(CursorBase+2+(i*4)) = 0xffff0000;
461 *(CursorBase+3+(i*4)) = 0xffff0000;
463 for (i = 8; i < 64; i++) {
464 *(CursorBase +(i*4)) = 0xffff0000;
465 *(CursorBase+1+(i*4)) = 0xffff0000;
466 *(CursorBase+2+(i*4)) = 0xffff0000;
467 *(CursorBase+3+(i*4)) = 0xffff0000;
471 mem_out8(0x4c, s3trio_base+0x1008000 + 0x03D4);
472 mem_out8(((2*1024 - 1)&0xf00)>>8, s3trio_base+0x1008000 + 0x03D5);
474 mem_out8(0x4d, s3trio_base+0x1008000 + 0x03D4);
475 mem_out8((2*1024 - 1) & 0xff, s3trio_base+0x1008000 + 0x03D5);
477 mem_out8(0x45, s3trio_base+0x1008000 + 0x03D4);
478 mem_in8(s3trio_base+0x1008000 + 0x03D4);
480 mem_out8(0x4a, s3trio_base+0x1008000 + 0x03D4);
481 mem_out8(0x80, s3trio_base+0x1008000 + 0x03D5);
482 mem_out8(0x80, s3trio_base+0x1008000 + 0x03D5);
483 mem_out8(0x80, s3trio_base+0x1008000 + 0x03D5);
485 mem_out8(0x4b, s3trio_base+0x1008000 + 0x03D4);
486 mem_out8(0x00, s3trio_base+0x1008000 + 0x03D5);
487 mem_out8(0x00, s3trio_base+0x1008000 + 0x03D5);
488 mem_out8(0x00, s3trio_base+0x1008000 + 0x03D5);
490 mem_out8(0x45, s3trio_base+0x1008000 + 0x03D4);
491 mem_out8(0, s3trio_base+0x1008000 + 0x03D5);
493 /* setup default color table */
495 for(i = 0; i < 16; i++) {
496 int j = color_table[i];
497 palette[i].red=default_red[j];
498 palette[i].green=default_grn[j];
499 palette[i].blue=default_blu[j];
502 s3trio_setcolreg(255, 56, 100, 160, 0, NULL /* not used */);
503 s3trio_setcolreg(254, 0, 0, 0, 0, NULL /* not used */);
504 memset((char *)s3trio_base, 0, 640*480);
506 #if 0
507 Trio_RectFill(0, 0, 90, 90, 7, 1);
508 #endif
510 fb_fix.visual = FB_VISUAL_PSEUDOCOLOR ;
511 fb_var.xoffset = fb_var.yoffset = 0;
512 fb_var.bits_per_pixel = 8;
513 fb_var.grayscale = 0;
514 fb_var.red.offset = fb_var.green.offset = fb_var.blue.offset = 0;
515 fb_var.red.length = fb_var.green.length = fb_var.blue.length = 8;
516 fb_var.red.msb_right = fb_var.green.msb_right = fb_var.blue.msb_right = 0;
517 fb_var.transp.offset = fb_var.transp.length = fb_var.transp.msb_right = 0;
518 fb_var.nonstd = 0;
519 fb_var.activate = 0;
520 fb_var.height = fb_var.width = -1;
521 fb_var.accel_flags = FB_ACCELF_TEXT;
522 #warning FIXME: always obey fb_var.accel_flags
523 fb_var.pixclock = 1;
524 fb_var.left_margin = fb_var.right_margin = 0;
525 fb_var.upper_margin = fb_var.lower_margin = 0;
526 fb_var.hsync_len = fb_var.vsync_len = 0;
527 fb_var.sync = 0;
528 fb_var.vmode = FB_VMODE_NONINTERLACED;
530 disp.var = fb_var;
531 disp.cmap.start = 0;
532 disp.cmap.len = 0;
533 disp.cmap.red = disp.cmap.green = disp.cmap.blue = disp.cmap.transp = NULL;
534 disp.screen_base = s3trio_base;
535 disp.visual = fb_fix.visual;
536 disp.type = fb_fix.type;
537 disp.type_aux = fb_fix.type_aux;
538 disp.ypanstep = 0;
539 disp.ywrapstep = 0;
540 disp.line_length = fb_fix.line_length;
541 disp.can_soft_blank = 1;
542 disp.inverse = 0;
543 #ifdef FBCON_HAS_CFB8
544 if (fb_var.accel_flags & FB_ACCELF_TEXT)
545 disp.dispsw = &fbcon_trio8;
546 else
547 disp.dispsw = &fbcon_cfb8;
548 #else
549 disp.dispsw = &fbcon_dummy;
550 #endif
551 disp.scrollmode = fb_var.accel_flags & FB_ACCELF_TEXT ? 0 : SCROLL_YREDRAW;
553 strcpy(fb_info.modename, "Trio64 ");
554 strncat(fb_info.modename, dp->full_name, sizeof(fb_info.modename));
555 fb_info.node = -1;
556 fb_info.fbops = &s3trio_ops;
557 #if 0
558 fb_info.fbvar_num = 1;
559 fb_info.fbvar = &fb_var;
560 #endif
561 fb_info.disp = &disp;
562 fb_info.fontname[0] = '\0';
563 fb_info.changevar = NULL;
564 fb_info.switch_con = &s3triofbcon_switch;
565 fb_info.updatevar = &s3triofbcon_updatevar;
566 fb_info.blank = &s3triofbcon_blank;
567 #if 0
568 fb_info.setcmap = &s3triofbcon_setcmap;
569 #endif
571 #ifdef CONFIG_FB_COMPAT_XPMAC
572 if (!console_fb_info) {
573 display_info.height = fb_var.yres;
574 display_info.width = fb_var.xres;
575 display_info.depth = 8;
576 display_info.pitch = fb_fix.line_length;
577 display_info.mode = 0;
578 strncpy(display_info.name, dp->name, sizeof(display_info.name));
579 display_info.fb_address = (unsigned long)fb_fix.smem_start;
580 display_info.disp_reg_address = address + 0x1008000;
581 display_info.cmap_adr_address = address + 0x1008000 + 0x3c8;
582 display_info.cmap_data_address = address + 0x1008000 + 0x3c9;
583 console_fb_info = &fb_info;
585 #endif /* CONFIG_FB_COMPAT_XPMAC) */
587 fb_info.flags = FBINFO_FLAG_DEFAULT;
588 if (register_framebuffer(&fb_info) < 0)
589 return;
591 printk("fb%d: S3 Trio frame buffer device on %s\n",
592 GET_FB_IDX(fb_info.node), dp->full_name);
596 static int s3triofbcon_switch(int con, struct fb_info *info)
598 /* Do we have to save the colormap? */
599 if (fb_display[currcon].cmap.len)
600 fb_get_cmap(&fb_display[currcon].cmap, 1, s3trio_getcolreg, info);
602 currcon = con;
603 /* Install new colormap */
604 do_install_cmap(con,info);
605 return 0;
609 * Update the `var' structure (called by fbcon.c)
612 static int s3triofbcon_updatevar(int con, struct fb_info *info)
614 /* Nothing */
615 return 0;
619 * Blank the display.
622 static void s3triofbcon_blank(int blank, struct fb_info *info)
624 unsigned char x;
626 mem_out8(0x1, s3trio_base+0x1008000 + 0x03c4);
627 x = mem_in8(s3trio_base+0x1008000 + 0x03c5);
628 mem_out8((x & (~0x20)) | (blank << 5), s3trio_base+0x1008000 + 0x03c5);
632 * Set the colormap
635 #if 0
636 static int s3triofbcon_setcmap(struct fb_cmap *cmap, int con)
638 return(s3trio_set_cmap(cmap, 1, con, &fb_info));
640 #endif
644 * Read a single color register and split it into
645 * colors/transparent. Return != 0 for invalid regno.
648 static int s3trio_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue,
649 u_int *transp, struct fb_info *info)
651 if (regno > 255)
652 return 1;
653 *red = (palette[regno].red << 8) | palette[regno].red;
654 *green = (palette[regno].green << 8) | palette[regno].green;
655 *blue = (palette[regno].blue << 8) | palette[regno].blue;
656 *transp = 0;
657 return 0;
662 * Set a single color register. Return != 0 for invalid regno.
665 static int s3trio_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
666 u_int transp, struct fb_info *info)
668 if (regno > 255)
669 return 1;
671 red >>= 8;
672 green >>= 8;
673 blue >>= 8;
674 palette[regno].red = red;
675 palette[regno].green = green;
676 palette[regno].blue = blue;
678 mem_out8(regno,s3trio_base+0x1008000 + 0x3c8);
679 mem_out8((red & 0xff) >> 2,s3trio_base+0x1008000 + 0x3c9);
680 mem_out8((green & 0xff) >> 2,s3trio_base+0x1008000 + 0x3c9);
681 mem_out8((blue & 0xff) >> 2,s3trio_base+0x1008000 + 0x3c9);
683 return 0;
687 static void do_install_cmap(int con, struct fb_info *info)
689 if (con != currcon)
690 return;
691 if (fb_display[con].cmap.len)
692 fb_set_cmap(&fb_display[con].cmap, 1, s3trio_setcolreg, &fb_info);
693 else
694 fb_set_cmap(fb_default_cmap(fb_display[con].var.bits_per_pixel), 1,
695 s3trio_setcolreg, &fb_info);
698 int s3triofb_setup(char *options) {
700 return 0;
704 static void Trio_WaitQueue(u_short fifo) {
706 u_short status;
710 status = mem_in16(s3trio_base + 0x1000000 + 0x9AE8);
711 } while (!(status & fifo));
715 static void Trio_WaitBlit(void) {
717 u_short status;
721 status = mem_in16(s3trio_base + 0x1000000 + 0x9AE8);
722 } while (status & 0x200);
726 static void Trio_BitBLT(u_short curx, u_short cury, u_short destx,
727 u_short desty, u_short width, u_short height,
728 u_short mode) {
730 u_short blitcmd = 0xc011;
732 /* Set drawing direction */
733 /* -Y, X maj, -X (default) */
735 if (curx > destx)
736 blitcmd |= 0x0020; /* Drawing direction +X */
737 else {
738 curx += (width - 1);
739 destx += (width - 1);
742 if (cury > desty)
743 blitcmd |= 0x0080; /* Drawing direction +Y */
744 else {
745 cury += (height - 1);
746 desty += (height - 1);
749 Trio_WaitQueue(0x0400);
751 outw(0xa000, 0xBEE8);
752 outw(0x60 | mode, 0xBAE8);
754 outw(curx, 0x86E8);
755 outw(cury, 0x82E8);
757 outw(destx, 0x8EE8);
758 outw(desty, 0x8AE8);
760 outw(height - 1, 0xBEE8);
761 outw(width - 1, 0x96E8);
763 outw(blitcmd, 0x9AE8);
767 static void Trio_RectFill(u_short x, u_short y, u_short width, u_short height,
768 u_short mode, u_short color) {
770 u_short blitcmd = 0x40b1;
772 Trio_WaitQueue(0x0400);
774 outw(0xa000, 0xBEE8);
775 outw((0x20 | mode), 0xBAE8);
776 outw(0xe000, 0xBEE8);
777 outw(color, 0xA6E8);
778 outw(x, 0x86E8);
779 outw(y, 0x82E8);
780 outw((height - 1), 0xBEE8);
781 outw((width - 1), 0x96E8);
782 outw(blitcmd, 0x9AE8);
787 static void Trio_MoveCursor(u_short x, u_short y) {
789 mem_out8(0x39, s3trio_base + 0x1008000 + 0x3d4);
790 mem_out8(0xa0, s3trio_base + 0x1008000 + 0x3d5);
792 mem_out8(0x46, s3trio_base + 0x1008000 + 0x3d4);
793 mem_out8((x & 0x0700) >> 8, s3trio_base + 0x1008000 + 0x3d5);
794 mem_out8(0x47, s3trio_base + 0x1008000 + 0x3d4);
795 mem_out8(x & 0x00ff, s3trio_base + 0x1008000 + 0x3d5);
797 mem_out8(0x48, s3trio_base + 0x1008000 + 0x3d4);
798 mem_out8((y & 0x0700) >> 8, s3trio_base + 0x1008000 + 0x3d5);
799 mem_out8(0x49, s3trio_base + 0x1008000 + 0x3d4);
800 mem_out8(y & 0x00ff, s3trio_base + 0x1008000 + 0x3d5);
806 * Text console acceleration
809 #ifdef FBCON_HAS_CFB8
810 static void fbcon_trio8_bmove(struct display *p, int sy, int sx, int dy,
811 int dx, int height, int width)
813 sx *= 8; dx *= 8; width *= 8;
814 Trio_BitBLT((u_short)sx, (u_short)(sy*fontheight(p)), (u_short)dx,
815 (u_short)(dy*fontheight(p)), (u_short)width,
816 (u_short)(height*fontheight(p)), (u_short)S3_NEW);
819 static void fbcon_trio8_clear(struct vc_data *conp, struct display *p, int sy,
820 int sx, int height, int width)
822 unsigned char bg;
824 sx *= 8; width *= 8;
825 bg = attr_bgcol_ec(p,conp);
826 Trio_RectFill((u_short)sx,
827 (u_short)(sy*fontheight(p)),
828 (u_short)width,
829 (u_short)(height*fontheight(p)),
830 (u_short)S3_NEW,
831 (u_short)bg);
834 static void fbcon_trio8_putc(struct vc_data *conp, struct display *p, int c,
835 int yy, int xx)
837 Trio_WaitBlit();
838 fbcon_cfb8_putc(conp, p, c, yy, xx);
841 static void fbcon_trio8_putcs(struct vc_data *conp, struct display *p,
842 const unsigned short *s, int count, int yy, int xx)
844 Trio_WaitBlit();
845 fbcon_cfb8_putcs(conp, p, s, count, yy, xx);
848 static void fbcon_trio8_revc(struct display *p, int xx, int yy)
850 Trio_WaitBlit();
851 fbcon_cfb8_revc(p, xx, yy);
854 static struct display_switch fbcon_trio8 = {
855 setup: fbcon_cfb8_setup,
856 bmove: fbcon_trio8_bmove,
857 clear: fbcon_trio8_clear,
858 putc: fbcon_trio8_putc,
859 putcs: fbcon_trio8_putcs,
860 revc: fbcon_trio8_revc,
861 clear_margins: fbcon_cfb8_clear_margins,
862 fontwidthmask: FONTWIDTH(8)
864 #endif