This is pre8 ...
[linux-2.6/linux-mips.git] / drivers / video / S3triofb.c
blob19539318ab65395fdfc54aa82aa9d41d3d5e251c
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);
92 static int s3trio_ioctl(struct inode *inode, struct file *file, u_int cmd,
93 u_long arg, int con, struct fb_info *info);
97 * Interface to the low level console driver
100 int s3triofb_init(void);
101 static int s3triofbcon_switch(int con, struct fb_info *info);
102 static int s3triofbcon_updatevar(int con, struct fb_info *info);
103 static void s3triofbcon_blank(int blank, struct fb_info *info);
104 #if 0
105 static int s3triofbcon_setcmap(struct fb_cmap *cmap, int con);
106 #endif
109 * Text console acceleration
112 #ifdef FBCON_HAS_CFB8
113 static struct display_switch fbcon_trio8;
114 #endif
117 * Accelerated Functions used by the low level console driver
120 static void Trio_WaitQueue(u_short fifo);
121 static void Trio_WaitBlit(void);
122 static void Trio_BitBLT(u_short curx, u_short cury, u_short destx,
123 u_short desty, u_short width, u_short height,
124 u_short mode);
125 static void Trio_RectFill(u_short x, u_short y, u_short width, u_short height,
126 u_short mode, u_short color);
127 static void Trio_MoveCursor(u_short x, u_short y);
131 * Internal routines
134 static int s3trio_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue,
135 u_int *transp, struct fb_info *info);
136 static int s3trio_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
137 u_int transp, struct fb_info *info);
138 static void do_install_cmap(int con, struct fb_info *info);
141 static struct fb_ops s3trio_ops = {
142 owner: THIS_MODULE,
143 fb_get_fix: s3trio_get_fix,
144 fb_get_var: s3trio_get_var,
145 fb_set_var: s3trio_set_var,
146 fb_get_cmap: s3trio_get_cmap,
147 fb_set_cmap: s3trio_set_cmap,
148 fb_pan_display: s3trio_pan_display,
149 fb_ioctl: s3trio_ioctl,
153 * Get the Fixed Part of the Display
156 static int s3trio_get_fix(struct fb_fix_screeninfo *fix, int con,
157 struct fb_info *info)
159 memcpy(fix, &fb_fix, sizeof(fb_fix));
160 return 0;
165 * Get the User Defined Part of the Display
168 static int s3trio_get_var(struct fb_var_screeninfo *var, int con,
169 struct fb_info *info)
171 memcpy(var, &fb_var, sizeof(fb_var));
172 return 0;
177 * Set the User Defined Part of the Display
180 static int s3trio_set_var(struct fb_var_screeninfo *var, int con,
181 struct fb_info *info)
183 if (var->xres > fb_var.xres || var->yres > fb_var.yres ||
184 var->bits_per_pixel > fb_var.bits_per_pixel )
185 /* || var->nonstd || var->vmode != FB_VMODE_NONINTERLACED) */
186 return -EINVAL;
187 if (var->xres_virtual > fb_var.xres_virtual) {
188 outw(IO_OUT16VAL((var->xres_virtual /8) & 0xff, 0x13), 0x3d4);
189 outw(IO_OUT16VAL(((var->xres_virtual /8 ) & 0x300) >> 3, 0x51), 0x3d4);
190 fb_var.xres_virtual = var->xres_virtual;
191 fb_fix.line_length = var->xres_virtual;
193 fb_var.yres_virtual = var->yres_virtual;
194 memcpy(var, &fb_var, sizeof(fb_var));
195 return 0;
200 * Pan or Wrap the Display
202 * This call looks only at xoffset, yoffset and the FB_VMODE_YWRAP flag
205 static int s3trio_pan_display(struct fb_var_screeninfo *var, int con,
206 struct fb_info *info)
208 unsigned int base;
210 if (var->xoffset > (var->xres_virtual - var->xres))
211 return -EINVAL;
212 if (var->yoffset > (var->yres_virtual - var->yres))
213 return -EINVAL;
215 fb_var.xoffset = var->xoffset;
216 fb_var.yoffset = var->yoffset;
218 base = var->yoffset * fb_fix.line_length + var->xoffset;
220 outw(IO_OUT16VAL((base >> 8) & 0xff, 0x0c),0x03D4);
221 outw(IO_OUT16VAL(base & 0xff, 0x0d),0x03D4);
222 outw(IO_OUT16VAL((base >> 16) & 0xf, 0x69),0x03D4);
223 return 0;
228 * Get the Colormap
231 static int s3trio_get_cmap(struct fb_cmap *cmap, int kspc, int con,
232 struct fb_info *info)
234 if (con == currcon) /* current console? */
235 return fb_get_cmap(cmap, kspc, s3trio_getcolreg, info);
236 else if (fb_display[con].cmap.len) /* non default colormap? */
237 fb_copy_cmap(&fb_display[con].cmap, cmap, kspc ? 0 : 2);
238 else
239 fb_copy_cmap(fb_default_cmap(1 << fb_display[con].var.bits_per_pixel),
240 cmap, kspc ? 0 : 2);
241 return 0;
245 * Set the Colormap
248 static int s3trio_set_cmap(struct fb_cmap *cmap, int kspc, int con,
249 struct fb_info *info)
251 int err;
254 if (!fb_display[con].cmap.len) { /* no colormap allocated? */
255 if ((err = fb_alloc_cmap(&fb_display[con].cmap,
256 1<<fb_display[con].var.bits_per_pixel, 0)))
257 return err;
259 if (con == currcon) /* current console? */
260 return fb_set_cmap(cmap, kspc, s3trio_setcolreg, info);
261 else
262 fb_copy_cmap(cmap, &fb_display[con].cmap, kspc ? 0 : 1);
263 return 0;
267 static int s3trio_ioctl(struct inode *inode, struct file *file, u_int cmd,
268 u_long arg, int con, struct fb_info *info)
270 return -EINVAL;
273 int __init s3triofb_init(void)
275 #ifdef __powerpc__
276 /* We don't want to be called like this. */
277 /* We rely on Open Firmware (offb) instead. */
278 #else /* !__powerpc__ */
279 /* To be merged with cybervision */
280 #endif /* !__powerpc__ */
281 return 0;
284 void __init s3trio_resetaccel(void){
287 #define EC01_ENH_ENB 0x0005
288 #define EC01_LAW_ENB 0x0010
289 #define EC01_MMIO_ENB 0x0020
291 #define EC00_RESET 0x8000
292 #define EC00_ENABLE 0x4000
293 #define MF_MULT_MISC 0xE000
294 #define SRC_FOREGROUND 0x0020
295 #define SRC_BACKGROUND 0x0000
296 #define MIX_SRC 0x0007
297 #define MF_T_CLIP 0x1000
298 #define MF_L_CLIP 0x2000
299 #define MF_B_CLIP 0x3000
300 #define MF_R_CLIP 0x4000
301 #define MF_PIX_CONTROL 0xA000
302 #define MFA_SRC_FOREGR_MIX 0x0000
303 #define MF_PIX_CONTROL 0xA000
305 outw(EC00_RESET, 0x42e8);
306 inw( 0x42e8);
307 outw(EC00_ENABLE, 0x42e8);
308 inw( 0x42e8);
309 outw(EC01_ENH_ENB | EC01_LAW_ENB,
310 0x4ae8);
311 outw(MF_MULT_MISC, 0xbee8); /* 16 bit I/O registers */
313 /* Now set some basic accelerator registers */
314 Trio_WaitQueue(0x0400);
315 outw(SRC_FOREGROUND | MIX_SRC, 0xbae8);
316 outw(SRC_BACKGROUND | MIX_SRC, 0xb6e8);/* direct color*/
317 outw(MF_T_CLIP | 0, 0xbee8 ); /* clip virtual area */
318 outw(MF_L_CLIP | 0, 0xbee8 );
319 outw(MF_R_CLIP | (640 - 1), 0xbee8);
320 outw(MF_B_CLIP | (480 - 1), 0xbee8);
321 Trio_WaitQueue(0x0400);
322 outw(0xffff, 0xaae8); /* Enable all planes */
323 outw(0xffff, 0xaae8); /* Enable all planes */
324 outw( MF_PIX_CONTROL | MFA_SRC_FOREGR_MIX, 0xbee8);
327 int __init s3trio_init(struct device_node *dp){
329 u_char bus, dev;
330 unsigned int t32;
331 unsigned short cmd;
333 pci_device_loc(dp,&bus,&dev);
334 pcibios_read_config_dword(bus, dev, PCI_VENDOR_ID, &t32);
335 if(t32 == (PCI_DEVICE_ID_S3_TRIO << 16) + PCI_VENDOR_ID_S3) {
336 pcibios_read_config_dword(bus, dev, PCI_BASE_ADDRESS_0, &t32);
337 pcibios_read_config_dword(bus, dev, PCI_BASE_ADDRESS_1, &t32);
338 pcibios_read_config_word(bus, dev, PCI_COMMAND,&cmd);
340 pcibios_write_config_word(bus, dev, PCI_COMMAND, PCI_COMMAND_IO | PCI_COMMAND_MEMORY);
342 pcibios_write_config_dword(bus, dev, PCI_BASE_ADDRESS_0,0xffffffff);
343 pcibios_read_config_dword(bus, dev, PCI_BASE_ADDRESS_0, &t32);
345 /* This is a gross hack as OF only maps enough memory for the framebuffer and
346 we want to use MMIO too. We should find out which chunk of address space
347 we can use here */
348 pcibios_write_config_dword(bus,dev,PCI_BASE_ADDRESS_0,0xc6000000);
350 /* unlock s3 */
352 outb(0x01, 0x3C3);
354 outb(inb(0x03CC) | 1, 0x3c2);
356 outw(IO_OUT16VAL(0x48, 0x38),0x03D4);
357 outw(IO_OUT16VAL(0xA0, 0x39),0x03D4);
358 outb(0x33,0x3d4);
359 outw(IO_OUT16VAL((inb(0x3d5) & ~(0x2 | 0x10 | 0x40)) |
360 0x20, 0x33), 0x3d4);
362 outw(IO_OUT16VAL(0x6, 0x8), 0x3c4);
364 /* switch to MMIO only mode */
366 outb(0x58, 0x3d4);
367 outw(IO_OUT16VAL(inb(0x3d5) | 3 | 0x10, 0x58), 0x3d4);
368 outw(IO_OUT16VAL(8, 0x53), 0x3d4);
370 /* switch off I/O accesses */
372 #if 0
373 pcibios_write_config_word(bus, dev, PCI_COMMAND,
374 PCI_COMMAND_IO | PCI_COMMAND_MEMORY);
375 #endif
376 return 1;
379 return 0;
384 * Initialisation
385 * We heavily rely on OF for the moment. This needs fixing.
388 void __init s3triofb_init_of(struct device_node *dp)
390 int i, *pp, len;
391 unsigned long address;
392 u_long *CursorBase;
394 strncat(s3trio_name, dp->name, sizeof(s3trio_name));
395 s3trio_name[sizeof(s3trio_name)-1] = '\0';
396 strcpy(fb_fix.id, s3trio_name);
398 if((pp = (int *)get_property(dp, "vendor-id", &len)) != NULL
399 && *pp!=PCI_VENDOR_ID_S3) {
400 printk("%s: can't find S3 Trio board\n", dp->full_name);
401 return;
404 if((pp = (int *)get_property(dp, "device-id", &len)) != NULL
405 && *pp!=PCI_DEVICE_ID_S3_TRIO) {
406 printk("%s: can't find S3 Trio board\n", dp->full_name);
407 return;
410 if ((pp = (int *)get_property(dp, "depth", &len)) != NULL
411 && len == sizeof(int) && *pp != 8) {
412 printk("%s: can't use depth = %d\n", dp->full_name, *pp);
413 return;
415 if ((pp = (int *)get_property(dp, "width", &len)) != NULL
416 && len == sizeof(int))
417 fb_var.xres = fb_var.xres_virtual = *pp;
418 if ((pp = (int *)get_property(dp, "height", &len)) != NULL
419 && len == sizeof(int))
420 fb_var.yres = fb_var.yres_virtual = *pp;
421 if ((pp = (int *)get_property(dp, "linebytes", &len)) != NULL
422 && len == sizeof(int))
423 fb_fix.line_length = *pp;
424 else
425 fb_fix.line_length = fb_var.xres_virtual;
426 fb_fix.smem_len = fb_fix.line_length*fb_var.yres;
428 s3trio_init(dp);
429 address = 0xc6000000;
430 s3trio_base = ioremap(address,64*1024*1024);
431 fb_fix.smem_start = address;
432 fb_fix.type = FB_TYPE_PACKED_PIXELS;
433 fb_fix.type_aux = 0;
434 fb_fix.accel = FB_ACCEL_S3_TRIO64;
435 fb_fix.mmio_start = address+0x1000000;
436 fb_fix.mmio_len = 0x1000000;
438 fb_fix.xpanstep = 1;
439 fb_fix.ypanstep = 1;
441 s3trio_resetaccel();
443 mem_out8(0x30, s3trio_base+0x1008000 + 0x03D4);
444 mem_out8(0x2d, s3trio_base+0x1008000 + 0x03D4);
445 mem_out8(0x2e, s3trio_base+0x1008000 + 0x03D4);
447 mem_out8(0x50, s3trio_base+0x1008000 + 0x03D4);
449 /* disable HW cursor */
451 mem_out8(0x39, s3trio_base+0x1008000 + 0x03D4);
452 mem_out8(0xa0, s3trio_base+0x1008000 + 0x03D5);
454 mem_out8(0x45, s3trio_base+0x1008000 + 0x03D4);
455 mem_out8(0, s3trio_base+0x1008000 + 0x03D5);
457 mem_out8(0x4e, s3trio_base+0x1008000 + 0x03D4);
458 mem_out8(0, s3trio_base+0x1008000 + 0x03D5);
460 mem_out8(0x4f, s3trio_base+0x1008000 + 0x03D4);
461 mem_out8(0, s3trio_base+0x1008000 + 0x03D5);
463 /* init HW cursor */
465 CursorBase = (u_long *)(s3trio_base + 2*1024*1024 - 0x400);
466 for (i = 0; i < 8; i++) {
467 *(CursorBase +(i*4)) = 0xffffff00;
468 *(CursorBase+1+(i*4)) = 0xffff0000;
469 *(CursorBase+2+(i*4)) = 0xffff0000;
470 *(CursorBase+3+(i*4)) = 0xffff0000;
472 for (i = 8; i < 64; i++) {
473 *(CursorBase +(i*4)) = 0xffff0000;
474 *(CursorBase+1+(i*4)) = 0xffff0000;
475 *(CursorBase+2+(i*4)) = 0xffff0000;
476 *(CursorBase+3+(i*4)) = 0xffff0000;
480 mem_out8(0x4c, s3trio_base+0x1008000 + 0x03D4);
481 mem_out8(((2*1024 - 1)&0xf00)>>8, s3trio_base+0x1008000 + 0x03D5);
483 mem_out8(0x4d, s3trio_base+0x1008000 + 0x03D4);
484 mem_out8((2*1024 - 1) & 0xff, s3trio_base+0x1008000 + 0x03D5);
486 mem_out8(0x45, s3trio_base+0x1008000 + 0x03D4);
487 mem_in8(s3trio_base+0x1008000 + 0x03D4);
489 mem_out8(0x4a, s3trio_base+0x1008000 + 0x03D4);
490 mem_out8(0x80, s3trio_base+0x1008000 + 0x03D5);
491 mem_out8(0x80, s3trio_base+0x1008000 + 0x03D5);
492 mem_out8(0x80, s3trio_base+0x1008000 + 0x03D5);
494 mem_out8(0x4b, s3trio_base+0x1008000 + 0x03D4);
495 mem_out8(0x00, s3trio_base+0x1008000 + 0x03D5);
496 mem_out8(0x00, s3trio_base+0x1008000 + 0x03D5);
497 mem_out8(0x00, s3trio_base+0x1008000 + 0x03D5);
499 mem_out8(0x45, s3trio_base+0x1008000 + 0x03D4);
500 mem_out8(0, s3trio_base+0x1008000 + 0x03D5);
502 /* setup default color table */
504 for(i = 0; i < 16; i++) {
505 int j = color_table[i];
506 palette[i].red=default_red[j];
507 palette[i].green=default_grn[j];
508 palette[i].blue=default_blu[j];
511 s3trio_setcolreg(255, 56, 100, 160, 0, NULL /* not used */);
512 s3trio_setcolreg(254, 0, 0, 0, 0, NULL /* not used */);
513 memset((char *)s3trio_base, 0, 640*480);
515 #if 0
516 Trio_RectFill(0, 0, 90, 90, 7, 1);
517 #endif
519 fb_fix.visual = FB_VISUAL_PSEUDOCOLOR ;
520 fb_var.xoffset = fb_var.yoffset = 0;
521 fb_var.bits_per_pixel = 8;
522 fb_var.grayscale = 0;
523 fb_var.red.offset = fb_var.green.offset = fb_var.blue.offset = 0;
524 fb_var.red.length = fb_var.green.length = fb_var.blue.length = 8;
525 fb_var.red.msb_right = fb_var.green.msb_right = fb_var.blue.msb_right = 0;
526 fb_var.transp.offset = fb_var.transp.length = fb_var.transp.msb_right = 0;
527 fb_var.nonstd = 0;
528 fb_var.activate = 0;
529 fb_var.height = fb_var.width = -1;
530 fb_var.accel_flags = FB_ACCELF_TEXT;
531 #warning FIXME: always obey fb_var.accel_flags
532 fb_var.pixclock = 1;
533 fb_var.left_margin = fb_var.right_margin = 0;
534 fb_var.upper_margin = fb_var.lower_margin = 0;
535 fb_var.hsync_len = fb_var.vsync_len = 0;
536 fb_var.sync = 0;
537 fb_var.vmode = FB_VMODE_NONINTERLACED;
539 disp.var = fb_var;
540 disp.cmap.start = 0;
541 disp.cmap.len = 0;
542 disp.cmap.red = disp.cmap.green = disp.cmap.blue = disp.cmap.transp = NULL;
543 disp.screen_base = s3trio_base;
544 disp.visual = fb_fix.visual;
545 disp.type = fb_fix.type;
546 disp.type_aux = fb_fix.type_aux;
547 disp.ypanstep = 0;
548 disp.ywrapstep = 0;
549 disp.line_length = fb_fix.line_length;
550 disp.can_soft_blank = 1;
551 disp.inverse = 0;
552 #ifdef FBCON_HAS_CFB8
553 if (fb_var.accel_flags & FB_ACCELF_TEXT)
554 disp.dispsw = &fbcon_trio8;
555 else
556 disp.dispsw = &fbcon_cfb8;
557 #else
558 disp.dispsw = &fbcon_dummy;
559 #endif
560 disp.scrollmode = fb_var.accel_flags & FB_ACCELF_TEXT ? 0 : SCROLL_YREDRAW;
562 strcpy(fb_info.modename, "Trio64 ");
563 strncat(fb_info.modename, dp->full_name, sizeof(fb_info.modename));
564 fb_info.node = -1;
565 fb_info.fbops = &s3trio_ops;
566 #if 0
567 fb_info.fbvar_num = 1;
568 fb_info.fbvar = &fb_var;
569 #endif
570 fb_info.disp = &disp;
571 fb_info.fontname[0] = '\0';
572 fb_info.changevar = NULL;
573 fb_info.switch_con = &s3triofbcon_switch;
574 fb_info.updatevar = &s3triofbcon_updatevar;
575 fb_info.blank = &s3triofbcon_blank;
576 #if 0
577 fb_info.setcmap = &s3triofbcon_setcmap;
578 #endif
580 #ifdef CONFIG_FB_COMPAT_XPMAC
581 if (!console_fb_info) {
582 display_info.height = fb_var.yres;
583 display_info.width = fb_var.xres;
584 display_info.depth = 8;
585 display_info.pitch = fb_fix.line_length;
586 display_info.mode = 0;
587 strncpy(display_info.name, dp->name, sizeof(display_info.name));
588 display_info.fb_address = (unsigned long)fb_fix.smem_start;
589 display_info.disp_reg_address = address + 0x1008000;
590 display_info.cmap_adr_address = address + 0x1008000 + 0x3c8;
591 display_info.cmap_data_address = address + 0x1008000 + 0x3c9;
592 console_fb_info = &fb_info;
594 #endif /* CONFIG_FB_COMPAT_XPMAC) */
596 fb_info.flags = FBINFO_FLAG_DEFAULT;
597 if (register_framebuffer(&fb_info) < 0)
598 return;
600 printk("fb%d: S3 Trio frame buffer device on %s\n",
601 GET_FB_IDX(fb_info.node), dp->full_name);
605 static int s3triofbcon_switch(int con, struct fb_info *info)
607 /* Do we have to save the colormap? */
608 if (fb_display[currcon].cmap.len)
609 fb_get_cmap(&fb_display[currcon].cmap, 1, s3trio_getcolreg, info);
611 currcon = con;
612 /* Install new colormap */
613 do_install_cmap(con,info);
614 return 0;
618 * Update the `var' structure (called by fbcon.c)
621 static int s3triofbcon_updatevar(int con, struct fb_info *info)
623 /* Nothing */
624 return 0;
628 * Blank the display.
631 static void s3triofbcon_blank(int blank, struct fb_info *info)
633 unsigned char x;
635 mem_out8(0x1, s3trio_base+0x1008000 + 0x03c4);
636 x = mem_in8(s3trio_base+0x1008000 + 0x03c5);
637 mem_out8((x & (~0x20)) | (blank << 5), s3trio_base+0x1008000 + 0x03c5);
641 * Set the colormap
644 #if 0
645 static int s3triofbcon_setcmap(struct fb_cmap *cmap, int con)
647 return(s3trio_set_cmap(cmap, 1, con, &fb_info));
649 #endif
653 * Read a single color register and split it into
654 * colors/transparent. Return != 0 for invalid regno.
657 static int s3trio_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue,
658 u_int *transp, struct fb_info *info)
660 if (regno > 255)
661 return 1;
662 *red = (palette[regno].red << 8) | palette[regno].red;
663 *green = (palette[regno].green << 8) | palette[regno].green;
664 *blue = (palette[regno].blue << 8) | palette[regno].blue;
665 *transp = 0;
666 return 0;
671 * Set a single color register. Return != 0 for invalid regno.
674 static int s3trio_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
675 u_int transp, struct fb_info *info)
677 if (regno > 255)
678 return 1;
680 red >>= 8;
681 green >>= 8;
682 blue >>= 8;
683 palette[regno].red = red;
684 palette[regno].green = green;
685 palette[regno].blue = blue;
687 mem_out8(regno,s3trio_base+0x1008000 + 0x3c8);
688 mem_out8((red & 0xff) >> 2,s3trio_base+0x1008000 + 0x3c9);
689 mem_out8((green & 0xff) >> 2,s3trio_base+0x1008000 + 0x3c9);
690 mem_out8((blue & 0xff) >> 2,s3trio_base+0x1008000 + 0x3c9);
692 return 0;
696 static void do_install_cmap(int con, struct fb_info *info)
698 if (con != currcon)
699 return;
700 if (fb_display[con].cmap.len)
701 fb_set_cmap(&fb_display[con].cmap, 1, s3trio_setcolreg, &fb_info);
702 else
703 fb_set_cmap(fb_default_cmap(fb_display[con].var.bits_per_pixel), 1,
704 s3trio_setcolreg, &fb_info);
707 int s3triofb_setup(char *options) {
709 return 0;
713 static void Trio_WaitQueue(u_short fifo) {
715 u_short status;
719 status = mem_in16(s3trio_base + 0x1000000 + 0x9AE8);
720 } while (!(status & fifo));
724 static void Trio_WaitBlit(void) {
726 u_short status;
730 status = mem_in16(s3trio_base + 0x1000000 + 0x9AE8);
731 } while (status & 0x200);
735 static void Trio_BitBLT(u_short curx, u_short cury, u_short destx,
736 u_short desty, u_short width, u_short height,
737 u_short mode) {
739 u_short blitcmd = 0xc011;
741 /* Set drawing direction */
742 /* -Y, X maj, -X (default) */
744 if (curx > destx)
745 blitcmd |= 0x0020; /* Drawing direction +X */
746 else {
747 curx += (width - 1);
748 destx += (width - 1);
751 if (cury > desty)
752 blitcmd |= 0x0080; /* Drawing direction +Y */
753 else {
754 cury += (height - 1);
755 desty += (height - 1);
758 Trio_WaitQueue(0x0400);
760 outw(0xa000, 0xBEE8);
761 outw(0x60 | mode, 0xBAE8);
763 outw(curx, 0x86E8);
764 outw(cury, 0x82E8);
766 outw(destx, 0x8EE8);
767 outw(desty, 0x8AE8);
769 outw(height - 1, 0xBEE8);
770 outw(width - 1, 0x96E8);
772 outw(blitcmd, 0x9AE8);
776 static void Trio_RectFill(u_short x, u_short y, u_short width, u_short height,
777 u_short mode, u_short color) {
779 u_short blitcmd = 0x40b1;
781 Trio_WaitQueue(0x0400);
783 outw(0xa000, 0xBEE8);
784 outw((0x20 | mode), 0xBAE8);
785 outw(0xe000, 0xBEE8);
786 outw(color, 0xA6E8);
787 outw(x, 0x86E8);
788 outw(y, 0x82E8);
789 outw((height - 1), 0xBEE8);
790 outw((width - 1), 0x96E8);
791 outw(blitcmd, 0x9AE8);
796 static void Trio_MoveCursor(u_short x, u_short y) {
798 mem_out8(0x39, s3trio_base + 0x1008000 + 0x3d4);
799 mem_out8(0xa0, s3trio_base + 0x1008000 + 0x3d5);
801 mem_out8(0x46, s3trio_base + 0x1008000 + 0x3d4);
802 mem_out8((x & 0x0700) >> 8, s3trio_base + 0x1008000 + 0x3d5);
803 mem_out8(0x47, s3trio_base + 0x1008000 + 0x3d4);
804 mem_out8(x & 0x00ff, s3trio_base + 0x1008000 + 0x3d5);
806 mem_out8(0x48, s3trio_base + 0x1008000 + 0x3d4);
807 mem_out8((y & 0x0700) >> 8, s3trio_base + 0x1008000 + 0x3d5);
808 mem_out8(0x49, s3trio_base + 0x1008000 + 0x3d4);
809 mem_out8(y & 0x00ff, s3trio_base + 0x1008000 + 0x3d5);
815 * Text console acceleration
818 #ifdef FBCON_HAS_CFB8
819 static void fbcon_trio8_bmove(struct display *p, int sy, int sx, int dy,
820 int dx, int height, int width)
822 sx *= 8; dx *= 8; width *= 8;
823 Trio_BitBLT((u_short)sx, (u_short)(sy*fontheight(p)), (u_short)dx,
824 (u_short)(dy*fontheight(p)), (u_short)width,
825 (u_short)(height*fontheight(p)), (u_short)S3_NEW);
828 static void fbcon_trio8_clear(struct vc_data *conp, struct display *p, int sy,
829 int sx, int height, int width)
831 unsigned char bg;
833 sx *= 8; width *= 8;
834 bg = attr_bgcol_ec(p,conp);
835 Trio_RectFill((u_short)sx,
836 (u_short)(sy*fontheight(p)),
837 (u_short)width,
838 (u_short)(height*fontheight(p)),
839 (u_short)S3_NEW,
840 (u_short)bg);
843 static void fbcon_trio8_putc(struct vc_data *conp, struct display *p, int c,
844 int yy, int xx)
846 Trio_WaitBlit();
847 fbcon_cfb8_putc(conp, p, c, yy, xx);
850 static void fbcon_trio8_putcs(struct vc_data *conp, struct display *p,
851 const unsigned short *s, int count, int yy, int xx)
853 Trio_WaitBlit();
854 fbcon_cfb8_putcs(conp, p, s, count, yy, xx);
857 static void fbcon_trio8_revc(struct display *p, int xx, int yy)
859 Trio_WaitBlit();
860 fbcon_cfb8_revc(p, xx, yy);
863 static struct display_switch fbcon_trio8 = {
864 fbcon_cfb8_setup, fbcon_trio8_bmove, fbcon_trio8_clear, fbcon_trio8_putc,
865 fbcon_trio8_putcs, fbcon_trio8_revc, NULL, NULL, fbcon_cfb8_clear_margins,
866 FONTWIDTH(8)
868 #endif