* better
[mascara-docs.git] / i386 / linux-2.3.21 / drivers / video / S3triofb.c
blob22fb32ab1ed2ca42da68d5c4d68921b53619130e
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_open(struct fb_info *info, int user);
81 static int s3trio_release(struct fb_info *info, int user);
82 static int s3trio_get_fix(struct fb_fix_screeninfo *fix, int con,
83 struct fb_info *info);
84 static int s3trio_get_var(struct fb_var_screeninfo *var, int con,
85 struct fb_info *info);
86 static int s3trio_set_var(struct fb_var_screeninfo *var, int con,
87 struct fb_info *info);
88 static int s3trio_get_cmap(struct fb_cmap *cmap, int kspc, int con,
89 struct fb_info *info);
90 static int s3trio_set_cmap(struct fb_cmap *cmap, int kspc, int con,
91 struct fb_info *info);
92 static int s3trio_pan_display(struct fb_var_screeninfo *var, int con,
93 struct fb_info *info);
94 static int s3trio_ioctl(struct inode *inode, struct file *file, u_int cmd,
95 u_long arg, int con, struct fb_info *info);
99 * Interface to the low level console driver
102 int s3triofb_init(void);
103 static int s3triofbcon_switch(int con, struct fb_info *info);
104 static int s3triofbcon_updatevar(int con, struct fb_info *info);
105 static void s3triofbcon_blank(int blank, struct fb_info *info);
106 #if 0
107 static int s3triofbcon_setcmap(struct fb_cmap *cmap, int con);
108 #endif
111 * Text console acceleration
114 #ifdef FBCON_HAS_CFB8
115 static struct display_switch fbcon_trio8;
116 #endif
119 * Accelerated Functions used by the low level console driver
122 static void Trio_WaitQueue(u_short fifo);
123 static void Trio_WaitBlit(void);
124 static void Trio_BitBLT(u_short curx, u_short cury, u_short destx,
125 u_short desty, u_short width, u_short height,
126 u_short mode);
127 static void Trio_RectFill(u_short x, u_short y, u_short width, u_short height,
128 u_short mode, u_short color);
129 static void Trio_MoveCursor(u_short x, u_short y);
133 * Internal routines
136 static int s3trio_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue,
137 u_int *transp, struct fb_info *info);
138 static int s3trio_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
139 u_int transp, struct fb_info *info);
140 static void do_install_cmap(int con, struct fb_info *info);
143 static struct fb_ops s3trio_ops = {
144 s3trio_open, s3trio_release, s3trio_get_fix, s3trio_get_var, s3trio_set_var,
145 s3trio_get_cmap, s3trio_set_cmap, s3trio_pan_display, s3trio_ioctl
150 * Open/Release the frame buffer device
153 static int s3trio_open(struct fb_info *info, int user)
156 * Nothing, only a usage count for the moment
159 MOD_INC_USE_COUNT;
160 return(0);
163 static int s3trio_release(struct fb_info *info, int user)
165 MOD_DEC_USE_COUNT;
166 return(0);
171 * Get the Fixed Part of the Display
174 static int s3trio_get_fix(struct fb_fix_screeninfo *fix, int con,
175 struct fb_info *info)
177 memcpy(fix, &fb_fix, sizeof(fb_fix));
178 return 0;
183 * Get the User Defined Part of the Display
186 static int s3trio_get_var(struct fb_var_screeninfo *var, int con,
187 struct fb_info *info)
189 memcpy(var, &fb_var, sizeof(fb_var));
190 return 0;
195 * Set the User Defined Part of the Display
198 static int s3trio_set_var(struct fb_var_screeninfo *var, int con,
199 struct fb_info *info)
201 if (var->xres > fb_var.xres || var->yres > fb_var.yres ||
202 var->bits_per_pixel > fb_var.bits_per_pixel )
203 /* || var->nonstd || var->vmode != FB_VMODE_NONINTERLACED) */
204 return -EINVAL;
205 if (var->xres_virtual > fb_var.xres_virtual) {
206 outw(IO_OUT16VAL((var->xres_virtual /8) & 0xff, 0x13), 0x3d4);
207 outw(IO_OUT16VAL(((var->xres_virtual /8 ) & 0x300) >> 3, 0x51), 0x3d4);
208 fb_var.xres_virtual = var->xres_virtual;
209 fb_fix.line_length = var->xres_virtual;
211 fb_var.yres_virtual = var->yres_virtual;
212 memcpy(var, &fb_var, sizeof(fb_var));
213 return 0;
218 * Pan or Wrap the Display
220 * This call looks only at xoffset, yoffset and the FB_VMODE_YWRAP flag
223 static int s3trio_pan_display(struct fb_var_screeninfo *var, int con,
224 struct fb_info *info)
226 unsigned int base;
228 if (var->xoffset > (var->xres_virtual - var->xres))
229 return -EINVAL;
230 if (var->yoffset > (var->yres_virtual - var->yres))
231 return -EINVAL;
233 fb_var.xoffset = var->xoffset;
234 fb_var.yoffset = var->yoffset;
236 base = var->yoffset * fb_fix.line_length + var->xoffset;
238 outw(IO_OUT16VAL((base >> 8) & 0xff, 0x0c),0x03D4);
239 outw(IO_OUT16VAL(base & 0xff, 0x0d),0x03D4);
240 outw(IO_OUT16VAL((base >> 16) & 0xf, 0x69),0x03D4);
241 return 0;
246 * Get the Colormap
249 static int s3trio_get_cmap(struct fb_cmap *cmap, int kspc, int con,
250 struct fb_info *info)
252 if (con == currcon) /* current console? */
253 return fb_get_cmap(cmap, kspc, s3trio_getcolreg, info);
254 else if (fb_display[con].cmap.len) /* non default colormap? */
255 fb_copy_cmap(&fb_display[con].cmap, cmap, kspc ? 0 : 2);
256 else
257 fb_copy_cmap(fb_default_cmap(1 << fb_display[con].var.bits_per_pixel),
258 cmap, kspc ? 0 : 2);
259 return 0;
263 * Set the Colormap
266 static int s3trio_set_cmap(struct fb_cmap *cmap, int kspc, int con,
267 struct fb_info *info)
269 int err;
272 if (!fb_display[con].cmap.len) { /* no colormap allocated? */
273 if ((err = fb_alloc_cmap(&fb_display[con].cmap,
274 1<<fb_display[con].var.bits_per_pixel, 0)))
275 return err;
277 if (con == currcon) /* current console? */
278 return fb_set_cmap(cmap, kspc, s3trio_setcolreg, info);
279 else
280 fb_copy_cmap(cmap, &fb_display[con].cmap, kspc ? 0 : 1);
281 return 0;
285 static int s3trio_ioctl(struct inode *inode, struct file *file, u_int cmd,
286 u_long arg, int con, struct fb_info *info)
288 return -EINVAL;
291 int __init s3triofb_init(void)
293 #ifdef __powerpc__
294 /* We don't want to be called like this. */
295 /* We rely on Open Firmware (offb) instead. */
296 #else /* !__powerpc__ */
297 /* To be merged with cybervision */
298 #endif /* !__powerpc__ */
299 return 0;
302 void __init s3trio_resetaccel(void){
305 #define EC01_ENH_ENB 0x0005
306 #define EC01_LAW_ENB 0x0010
307 #define EC01_MMIO_ENB 0x0020
309 #define EC00_RESET 0x8000
310 #define EC00_ENABLE 0x4000
311 #define MF_MULT_MISC 0xE000
312 #define SRC_FOREGROUND 0x0020
313 #define SRC_BACKGROUND 0x0000
314 #define MIX_SRC 0x0007
315 #define MF_T_CLIP 0x1000
316 #define MF_L_CLIP 0x2000
317 #define MF_B_CLIP 0x3000
318 #define MF_R_CLIP 0x4000
319 #define MF_PIX_CONTROL 0xA000
320 #define MFA_SRC_FOREGR_MIX 0x0000
321 #define MF_PIX_CONTROL 0xA000
323 outw(EC00_RESET, 0x42e8);
324 inw( 0x42e8);
325 outw(EC00_ENABLE, 0x42e8);
326 inw( 0x42e8);
327 outw(EC01_ENH_ENB | EC01_LAW_ENB,
328 0x4ae8);
329 outw(MF_MULT_MISC, 0xbee8); /* 16 bit I/O registers */
331 /* Now set some basic accelerator registers */
332 Trio_WaitQueue(0x0400);
333 outw(SRC_FOREGROUND | MIX_SRC, 0xbae8);
334 outw(SRC_BACKGROUND | MIX_SRC, 0xb6e8);/* direct color*/
335 outw(MF_T_CLIP | 0, 0xbee8 ); /* clip virtual area */
336 outw(MF_L_CLIP | 0, 0xbee8 );
337 outw(MF_R_CLIP | (640 - 1), 0xbee8);
338 outw(MF_B_CLIP | (480 - 1), 0xbee8);
339 Trio_WaitQueue(0x0400);
340 outw(0xffff, 0xaae8); /* Enable all planes */
341 outw(0xffff, 0xaae8); /* Enable all planes */
342 outw( MF_PIX_CONTROL | MFA_SRC_FOREGR_MIX, 0xbee8);
345 int __init s3trio_init(struct device_node *dp){
347 u_char bus, dev;
348 unsigned int t32;
349 unsigned short cmd;
351 pci_device_loc(dp,&bus,&dev);
352 pcibios_read_config_dword(bus, dev, PCI_VENDOR_ID, &t32);
353 if(t32 == (PCI_DEVICE_ID_S3_TRIO << 16) + PCI_VENDOR_ID_S3) {
354 pcibios_read_config_dword(bus, dev, PCI_BASE_ADDRESS_0, &t32);
355 pcibios_read_config_dword(bus, dev, PCI_BASE_ADDRESS_1, &t32);
356 pcibios_read_config_word(bus, dev, PCI_COMMAND,&cmd);
358 pcibios_write_config_word(bus, dev, PCI_COMMAND, PCI_COMMAND_IO | PCI_COMMAND_MEMORY);
360 pcibios_write_config_dword(bus, dev, PCI_BASE_ADDRESS_0,0xffffffff);
361 pcibios_read_config_dword(bus, dev, PCI_BASE_ADDRESS_0, &t32);
363 /* This is a gross hack as OF only maps enough memory for the framebuffer and
364 we want to use MMIO too. We should find out which chunk of address space
365 we can use here */
366 pcibios_write_config_dword(bus,dev,PCI_BASE_ADDRESS_0,0xc6000000);
368 /* unlock s3 */
370 outb(0x01, 0x3C3);
372 outb(inb(0x03CC) | 1, 0x3c2);
374 outw(IO_OUT16VAL(0x48, 0x38),0x03D4);
375 outw(IO_OUT16VAL(0xA0, 0x39),0x03D4);
376 outb(0x33,0x3d4);
377 outw(IO_OUT16VAL((inb(0x3d5) & ~(0x2 | 0x10 | 0x40)) |
378 0x20, 0x33), 0x3d4);
380 outw(IO_OUT16VAL(0x6, 0x8), 0x3c4);
382 /* switch to MMIO only mode */
384 outb(0x58, 0x3d4);
385 outw(IO_OUT16VAL(inb(0x3d5) | 3 | 0x10, 0x58), 0x3d4);
386 outw(IO_OUT16VAL(8, 0x53), 0x3d4);
388 /* switch off I/O accesses */
390 #if 0
391 pcibios_write_config_word(bus, dev, PCI_COMMAND,
392 PCI_COMMAND_IO | PCI_COMMAND_MEMORY);
393 #endif
394 return 1;
397 return 0;
402 * Initialisation
403 * We heavily rely on OF for the moment. This needs fixing.
406 void __init s3triofb_init_of(struct device_node *dp)
408 int i, *pp, len;
409 unsigned long address;
410 u_long *CursorBase;
412 strncat(s3trio_name, dp->name, sizeof(s3trio_name));
413 s3trio_name[sizeof(s3trio_name)-1] = '\0';
414 strcpy(fb_fix.id, s3trio_name);
416 if((pp = (int *)get_property(dp, "vendor-id", &len)) != NULL
417 && *pp!=PCI_VENDOR_ID_S3) {
418 printk("%s: can't find S3 Trio board\n", dp->full_name);
419 return;
422 if((pp = (int *)get_property(dp, "device-id", &len)) != NULL
423 && *pp!=PCI_DEVICE_ID_S3_TRIO) {
424 printk("%s: can't find S3 Trio board\n", dp->full_name);
425 return;
428 if ((pp = (int *)get_property(dp, "depth", &len)) != NULL
429 && len == sizeof(int) && *pp != 8) {
430 printk("%s: can't use depth = %d\n", dp->full_name, *pp);
431 return;
433 if ((pp = (int *)get_property(dp, "width", &len)) != NULL
434 && len == sizeof(int))
435 fb_var.xres = fb_var.xres_virtual = *pp;
436 if ((pp = (int *)get_property(dp, "height", &len)) != NULL
437 && len == sizeof(int))
438 fb_var.yres = fb_var.yres_virtual = *pp;
439 if ((pp = (int *)get_property(dp, "linebytes", &len)) != NULL
440 && len == sizeof(int))
441 fb_fix.line_length = *pp;
442 else
443 fb_fix.line_length = fb_var.xres_virtual;
444 fb_fix.smem_len = fb_fix.line_length*fb_var.yres;
446 s3trio_init(dp);
447 address = 0xc6000000;
448 s3trio_base = ioremap(address,64*1024*1024);
449 fb_fix.smem_start = address;
450 fb_fix.type = FB_TYPE_PACKED_PIXELS;
451 fb_fix.type_aux = 0;
452 fb_fix.accel = FB_ACCEL_S3_TRIO64;
453 fb_fix.mmio_start = address+0x1000000;
454 fb_fix.mmio_len = 0x1000000;
456 fb_fix.xpanstep = 1;
457 fb_fix.ypanstep = 1;
459 s3trio_resetaccel();
461 mem_out8(0x30, s3trio_base+0x1008000 + 0x03D4);
462 mem_out8(0x2d, s3trio_base+0x1008000 + 0x03D4);
463 mem_out8(0x2e, s3trio_base+0x1008000 + 0x03D4);
465 mem_out8(0x50, s3trio_base+0x1008000 + 0x03D4);
467 /* disable HW cursor */
469 mem_out8(0x39, s3trio_base+0x1008000 + 0x03D4);
470 mem_out8(0xa0, s3trio_base+0x1008000 + 0x03D5);
472 mem_out8(0x45, s3trio_base+0x1008000 + 0x03D4);
473 mem_out8(0, s3trio_base+0x1008000 + 0x03D5);
475 mem_out8(0x4e, s3trio_base+0x1008000 + 0x03D4);
476 mem_out8(0, s3trio_base+0x1008000 + 0x03D5);
478 mem_out8(0x4f, s3trio_base+0x1008000 + 0x03D4);
479 mem_out8(0, s3trio_base+0x1008000 + 0x03D5);
481 /* init HW cursor */
483 CursorBase = (u_long *)(s3trio_base + 2*1024*1024 - 0x400);
484 for (i = 0; i < 8; i++) {
485 *(CursorBase +(i*4)) = 0xffffff00;
486 *(CursorBase+1+(i*4)) = 0xffff0000;
487 *(CursorBase+2+(i*4)) = 0xffff0000;
488 *(CursorBase+3+(i*4)) = 0xffff0000;
490 for (i = 8; i < 64; i++) {
491 *(CursorBase +(i*4)) = 0xffff0000;
492 *(CursorBase+1+(i*4)) = 0xffff0000;
493 *(CursorBase+2+(i*4)) = 0xffff0000;
494 *(CursorBase+3+(i*4)) = 0xffff0000;
498 mem_out8(0x4c, s3trio_base+0x1008000 + 0x03D4);
499 mem_out8(((2*1024 - 1)&0xf00)>>8, s3trio_base+0x1008000 + 0x03D5);
501 mem_out8(0x4d, s3trio_base+0x1008000 + 0x03D4);
502 mem_out8((2*1024 - 1) & 0xff, s3trio_base+0x1008000 + 0x03D5);
504 mem_out8(0x45, s3trio_base+0x1008000 + 0x03D4);
505 mem_in8(s3trio_base+0x1008000 + 0x03D4);
507 mem_out8(0x4a, s3trio_base+0x1008000 + 0x03D4);
508 mem_out8(0x80, s3trio_base+0x1008000 + 0x03D5);
509 mem_out8(0x80, s3trio_base+0x1008000 + 0x03D5);
510 mem_out8(0x80, s3trio_base+0x1008000 + 0x03D5);
512 mem_out8(0x4b, s3trio_base+0x1008000 + 0x03D4);
513 mem_out8(0x00, s3trio_base+0x1008000 + 0x03D5);
514 mem_out8(0x00, s3trio_base+0x1008000 + 0x03D5);
515 mem_out8(0x00, s3trio_base+0x1008000 + 0x03D5);
517 mem_out8(0x45, s3trio_base+0x1008000 + 0x03D4);
518 mem_out8(0, s3trio_base+0x1008000 + 0x03D5);
520 /* setup default color table */
522 for(i = 0; i < 16; i++) {
523 int j = color_table[i];
524 palette[i].red=default_red[j];
525 palette[i].green=default_grn[j];
526 palette[i].blue=default_blu[j];
529 s3trio_setcolreg(255, 56, 100, 160, 0, NULL /* not used */);
530 s3trio_setcolreg(254, 0, 0, 0, 0, NULL /* not used */);
531 memset((char *)s3trio_base, 0, 640*480);
533 #if 0
534 Trio_RectFill(0, 0, 90, 90, 7, 1);
535 #endif
537 fb_fix.visual = FB_VISUAL_PSEUDOCOLOR ;
538 fb_var.xoffset = fb_var.yoffset = 0;
539 fb_var.bits_per_pixel = 8;
540 fb_var.grayscale = 0;
541 fb_var.red.offset = fb_var.green.offset = fb_var.blue.offset = 0;
542 fb_var.red.length = fb_var.green.length = fb_var.blue.length = 8;
543 fb_var.red.msb_right = fb_var.green.msb_right = fb_var.blue.msb_right = 0;
544 fb_var.transp.offset = fb_var.transp.length = fb_var.transp.msb_right = 0;
545 fb_var.nonstd = 0;
546 fb_var.activate = 0;
547 fb_var.height = fb_var.width = -1;
548 fb_var.accel_flags = FB_ACCELF_TEXT;
549 #warning FIXME: always obey fb_var.accel_flags
550 fb_var.pixclock = 1;
551 fb_var.left_margin = fb_var.right_margin = 0;
552 fb_var.upper_margin = fb_var.lower_margin = 0;
553 fb_var.hsync_len = fb_var.vsync_len = 0;
554 fb_var.sync = 0;
555 fb_var.vmode = FB_VMODE_NONINTERLACED;
557 disp.var = fb_var;
558 disp.cmap.start = 0;
559 disp.cmap.len = 0;
560 disp.cmap.red = disp.cmap.green = disp.cmap.blue = disp.cmap.transp = NULL;
561 disp.screen_base = s3trio_base;
562 disp.visual = fb_fix.visual;
563 disp.type = fb_fix.type;
564 disp.type_aux = fb_fix.type_aux;
565 disp.ypanstep = 0;
566 disp.ywrapstep = 0;
567 disp.line_length = fb_fix.line_length;
568 disp.can_soft_blank = 1;
569 disp.inverse = 0;
570 #ifdef FBCON_HAS_CFB8
571 if (fb_var.accel_flags & FB_ACCELF_TEXT)
572 disp.dispsw = &fbcon_trio8;
573 else
574 disp.dispsw = &fbcon_cfb8;
575 #else
576 disp.dispsw = &fbcon_dummy;
577 #endif
578 disp.scrollmode = fb_var.accel_flags & FB_ACCELF_TEXT ? 0 : SCROLL_YREDRAW;
580 strcpy(fb_info.modename, "Trio64 ");
581 strncat(fb_info.modename, dp->full_name, sizeof(fb_info.modename));
582 fb_info.node = -1;
583 fb_info.fbops = &s3trio_ops;
584 #if 0
585 fb_info.fbvar_num = 1;
586 fb_info.fbvar = &fb_var;
587 #endif
588 fb_info.disp = &disp;
589 fb_info.fontname[0] = '\0';
590 fb_info.changevar = NULL;
591 fb_info.switch_con = &s3triofbcon_switch;
592 fb_info.updatevar = &s3triofbcon_updatevar;
593 fb_info.blank = &s3triofbcon_blank;
594 #if 0
595 fb_info.setcmap = &s3triofbcon_setcmap;
596 #endif
598 #ifdef CONFIG_FB_COMPAT_XPMAC
599 if (!console_fb_info) {
600 display_info.height = fb_var.yres;
601 display_info.width = fb_var.xres;
602 display_info.depth = 8;
603 display_info.pitch = fb_fix.line_length;
604 display_info.mode = 0;
605 strncpy(display_info.name, dp->name, sizeof(display_info.name));
606 display_info.fb_address = (unsigned long)fb_fix.smem_start;
607 display_info.disp_reg_address = address + 0x1008000;
608 display_info.cmap_adr_address = address + 0x1008000 + 0x3c8;
609 display_info.cmap_data_address = address + 0x1008000 + 0x3c9;
610 console_fb_info = &fb_info;
612 #endif /* CONFIG_FB_COMPAT_XPMAC) */
614 fb_info.flags = FBINFO_FLAG_DEFAULT;
615 if (register_framebuffer(&fb_info) < 0)
616 return;
618 printk("fb%d: S3 Trio frame buffer device on %s\n",
619 GET_FB_IDX(fb_info.node), dp->full_name);
623 static int s3triofbcon_switch(int con, struct fb_info *info)
625 /* Do we have to save the colormap? */
626 if (fb_display[currcon].cmap.len)
627 fb_get_cmap(&fb_display[currcon].cmap, 1, s3trio_getcolreg, info);
629 currcon = con;
630 /* Install new colormap */
631 do_install_cmap(con,info);
632 return 0;
636 * Update the `var' structure (called by fbcon.c)
639 static int s3triofbcon_updatevar(int con, struct fb_info *info)
641 /* Nothing */
642 return 0;
646 * Blank the display.
649 static void s3triofbcon_blank(int blank, struct fb_info *info)
651 unsigned char x;
653 mem_out8(0x1, s3trio_base+0x1008000 + 0x03c4);
654 x = mem_in8(s3trio_base+0x1008000 + 0x03c5);
655 mem_out8((x & (~0x20)) | (blank << 5), s3trio_base+0x1008000 + 0x03c5);
659 * Set the colormap
662 #if 0
663 static int s3triofbcon_setcmap(struct fb_cmap *cmap, int con)
665 return(s3trio_set_cmap(cmap, 1, con, &fb_info));
667 #endif
671 * Read a single color register and split it into
672 * colors/transparent. Return != 0 for invalid regno.
675 static int s3trio_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue,
676 u_int *transp, struct fb_info *info)
678 if (regno > 255)
679 return 1;
680 *red = (palette[regno].red << 8) | palette[regno].red;
681 *green = (palette[regno].green << 8) | palette[regno].green;
682 *blue = (palette[regno].blue << 8) | palette[regno].blue;
683 *transp = 0;
684 return 0;
689 * Set a single color register. Return != 0 for invalid regno.
692 static int s3trio_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
693 u_int transp, struct fb_info *info)
695 if (regno > 255)
696 return 1;
698 red >>= 8;
699 green >>= 8;
700 blue >>= 8;
701 palette[regno].red = red;
702 palette[regno].green = green;
703 palette[regno].blue = blue;
705 mem_out8(regno,s3trio_base+0x1008000 + 0x3c8);
706 mem_out8((red & 0xff) >> 2,s3trio_base+0x1008000 + 0x3c9);
707 mem_out8((green & 0xff) >> 2,s3trio_base+0x1008000 + 0x3c9);
708 mem_out8((blue & 0xff) >> 2,s3trio_base+0x1008000 + 0x3c9);
710 return 0;
714 static void do_install_cmap(int con, struct fb_info *info)
716 if (con != currcon)
717 return;
718 if (fb_display[con].cmap.len)
719 fb_set_cmap(&fb_display[con].cmap, 1, s3trio_setcolreg, &fb_info);
720 else
721 fb_set_cmap(fb_default_cmap(fb_display[con].var.bits_per_pixel), 1,
722 s3trio_setcolreg, &fb_info);
725 int s3triofb_setup(char *options) {
727 return 0;
731 static void Trio_WaitQueue(u_short fifo) {
733 u_short status;
737 status = mem_in16(s3trio_base + 0x1000000 + 0x9AE8);
738 } while (!(status & fifo));
742 static void Trio_WaitBlit(void) {
744 u_short status;
748 status = mem_in16(s3trio_base + 0x1000000 + 0x9AE8);
749 } while (status & 0x200);
753 static void Trio_BitBLT(u_short curx, u_short cury, u_short destx,
754 u_short desty, u_short width, u_short height,
755 u_short mode) {
757 u_short blitcmd = 0xc011;
759 /* Set drawing direction */
760 /* -Y, X maj, -X (default) */
762 if (curx > destx)
763 blitcmd |= 0x0020; /* Drawing direction +X */
764 else {
765 curx += (width - 1);
766 destx += (width - 1);
769 if (cury > desty)
770 blitcmd |= 0x0080; /* Drawing direction +Y */
771 else {
772 cury += (height - 1);
773 desty += (height - 1);
776 Trio_WaitQueue(0x0400);
778 outw(0xa000, 0xBEE8);
779 outw(0x60 | mode, 0xBAE8);
781 outw(curx, 0x86E8);
782 outw(cury, 0x82E8);
784 outw(destx, 0x8EE8);
785 outw(desty, 0x8AE8);
787 outw(height - 1, 0xBEE8);
788 outw(width - 1, 0x96E8);
790 outw(blitcmd, 0x9AE8);
794 static void Trio_RectFill(u_short x, u_short y, u_short width, u_short height,
795 u_short mode, u_short color) {
797 u_short blitcmd = 0x40b1;
799 Trio_WaitQueue(0x0400);
801 outw(0xa000, 0xBEE8);
802 outw((0x20 | mode), 0xBAE8);
803 outw(0xe000, 0xBEE8);
804 outw(color, 0xA6E8);
805 outw(x, 0x86E8);
806 outw(y, 0x82E8);
807 outw((height - 1), 0xBEE8);
808 outw((width - 1), 0x96E8);
809 outw(blitcmd, 0x9AE8);
814 static void Trio_MoveCursor(u_short x, u_short y) {
816 mem_out8(0x39, s3trio_base + 0x1008000 + 0x3d4);
817 mem_out8(0xa0, s3trio_base + 0x1008000 + 0x3d5);
819 mem_out8(0x46, s3trio_base + 0x1008000 + 0x3d4);
820 mem_out8((x & 0x0700) >> 8, s3trio_base + 0x1008000 + 0x3d5);
821 mem_out8(0x47, s3trio_base + 0x1008000 + 0x3d4);
822 mem_out8(x & 0x00ff, s3trio_base + 0x1008000 + 0x3d5);
824 mem_out8(0x48, s3trio_base + 0x1008000 + 0x3d4);
825 mem_out8((y & 0x0700) >> 8, s3trio_base + 0x1008000 + 0x3d5);
826 mem_out8(0x49, s3trio_base + 0x1008000 + 0x3d4);
827 mem_out8(y & 0x00ff, s3trio_base + 0x1008000 + 0x3d5);
833 * Text console acceleration
836 #ifdef FBCON_HAS_CFB8
837 static void fbcon_trio8_bmove(struct display *p, int sy, int sx, int dy,
838 int dx, int height, int width)
840 sx *= 8; dx *= 8; width *= 8;
841 Trio_BitBLT((u_short)sx, (u_short)(sy*fontheight(p)), (u_short)dx,
842 (u_short)(dy*fontheight(p)), (u_short)width,
843 (u_short)(height*fontheight(p)), (u_short)S3_NEW);
846 static void fbcon_trio8_clear(struct vc_data *conp, struct display *p, int sy,
847 int sx, int height, int width)
849 unsigned char bg;
851 sx *= 8; width *= 8;
852 bg = attr_bgcol_ec(p,conp);
853 Trio_RectFill((u_short)sx,
854 (u_short)(sy*fontheight(p)),
855 (u_short)width,
856 (u_short)(height*fontheight(p)),
857 (u_short)S3_NEW,
858 (u_short)bg);
861 static void fbcon_trio8_putc(struct vc_data *conp, struct display *p, int c,
862 int yy, int xx)
864 Trio_WaitBlit();
865 fbcon_cfb8_putc(conp, p, c, yy, xx);
868 static void fbcon_trio8_putcs(struct vc_data *conp, struct display *p,
869 const unsigned short *s, int count, int yy, int xx)
871 Trio_WaitBlit();
872 fbcon_cfb8_putcs(conp, p, s, count, yy, xx);
875 static void fbcon_trio8_revc(struct display *p, int xx, int yy)
877 Trio_WaitBlit();
878 fbcon_cfb8_revc(p, xx, yy);
881 static struct display_switch fbcon_trio8 = {
882 fbcon_cfb8_setup, fbcon_trio8_bmove, fbcon_trio8_clear, fbcon_trio8_putc,
883 fbcon_trio8_putcs, fbcon_trio8_revc, NULL, NULL, fbcon_cfb8_clear_margins,
884 FONTWIDTH(8)
886 #endif