Ok. I didn't make 2.4.0 in 2000. Tough. I tried, but we had some
[davej-history.git] / drivers / video / S3triofb.c
blobe8c0c97daeb245e8772ec31e03c89464d2a60870
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 static int currcon = 0;
64 static struct display disp;
65 static struct fb_info fb_info;
66 static struct { u_char red, green, blue, pad; } palette[256];
67 static char s3trio_name[16] = "S3Trio ";
68 static char *s3trio_base;
70 static struct fb_fix_screeninfo fb_fix;
71 static struct fb_var_screeninfo fb_var = { 0, };
75 * Interface used by the world
78 static void __init s3triofb_of_init(struct device_node *dp);
79 static int s3trio_get_fix(struct fb_fix_screeninfo *fix, int con,
80 struct fb_info *info);
81 static int s3trio_get_var(struct fb_var_screeninfo *var, int con,
82 struct fb_info *info);
83 static int s3trio_set_var(struct fb_var_screeninfo *var, int con,
84 struct fb_info *info);
85 static int s3trio_get_cmap(struct fb_cmap *cmap, int kspc, int con,
86 struct fb_info *info);
87 static int s3trio_set_cmap(struct fb_cmap *cmap, int kspc, int con,
88 struct fb_info *info);
89 static int s3trio_pan_display(struct fb_var_screeninfo *var, int con,
90 struct fb_info *info);
94 * Interface to the low level console driver
97 int s3triofb_init(void);
98 static int s3triofbcon_switch(int con, struct fb_info *info);
99 static int s3triofbcon_updatevar(int con, struct fb_info *info);
100 static void s3triofbcon_blank(int blank, struct fb_info *info);
101 #if 0
102 static int s3triofbcon_setcmap(struct fb_cmap *cmap, int con);
103 #endif
106 * Text console acceleration
109 #ifdef FBCON_HAS_CFB8
110 static struct display_switch fbcon_trio8;
111 #endif
114 * Accelerated Functions used by the low level console driver
117 static void Trio_WaitQueue(u_short fifo);
118 static void Trio_WaitBlit(void);
119 static void Trio_BitBLT(u_short curx, u_short cury, u_short destx,
120 u_short desty, u_short width, u_short height,
121 u_short mode);
122 static void Trio_RectFill(u_short x, u_short y, u_short width, u_short height,
123 u_short mode, u_short color);
124 static void Trio_MoveCursor(u_short x, u_short y);
128 * Internal routines
131 static int s3trio_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue,
132 u_int *transp, struct fb_info *info);
133 static int s3trio_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
134 u_int transp, struct fb_info *info);
135 static void do_install_cmap(int con, struct fb_info *info);
138 static struct fb_ops s3trio_ops = {
139 owner: THIS_MODULE,
140 fb_get_fix: s3trio_get_fix,
141 fb_get_var: s3trio_get_var,
142 fb_set_var: s3trio_set_var,
143 fb_get_cmap: s3trio_get_cmap,
144 fb_set_cmap: s3trio_set_cmap,
145 fb_pan_display: s3trio_pan_display,
149 * Get the Fixed Part of the Display
152 static int s3trio_get_fix(struct fb_fix_screeninfo *fix, int con,
153 struct fb_info *info)
155 memcpy(fix, &fb_fix, sizeof(fb_fix));
156 return 0;
161 * Get the User Defined Part of the Display
164 static int s3trio_get_var(struct fb_var_screeninfo *var, int con,
165 struct fb_info *info)
167 memcpy(var, &fb_var, sizeof(fb_var));
168 return 0;
173 * Set the User Defined Part of the Display
176 static int s3trio_set_var(struct fb_var_screeninfo *var, int con,
177 struct fb_info *info)
179 if (var->xres > fb_var.xres || var->yres > fb_var.yres ||
180 var->bits_per_pixel > fb_var.bits_per_pixel )
181 /* || var->nonstd || var->vmode != FB_VMODE_NONINTERLACED) */
182 return -EINVAL;
183 if (var->xres_virtual > fb_var.xres_virtual) {
184 outw(IO_OUT16VAL((var->xres_virtual /8) & 0xff, 0x13), 0x3d4);
185 outw(IO_OUT16VAL(((var->xres_virtual /8 ) & 0x300) >> 3, 0x51), 0x3d4);
186 fb_var.xres_virtual = var->xres_virtual;
187 fb_fix.line_length = var->xres_virtual;
189 fb_var.yres_virtual = var->yres_virtual;
190 memcpy(var, &fb_var, sizeof(fb_var));
191 return 0;
196 * Pan or Wrap the Display
198 * This call looks only at xoffset, yoffset and the FB_VMODE_YWRAP flag
201 static int s3trio_pan_display(struct fb_var_screeninfo *var, int con,
202 struct fb_info *info)
204 unsigned int base;
206 if (var->xoffset > (var->xres_virtual - var->xres))
207 return -EINVAL;
208 if (var->yoffset > (var->yres_virtual - var->yres))
209 return -EINVAL;
211 fb_var.xoffset = var->xoffset;
212 fb_var.yoffset = var->yoffset;
214 base = var->yoffset * fb_fix.line_length + var->xoffset;
216 outw(IO_OUT16VAL((base >> 8) & 0xff, 0x0c),0x03D4);
217 outw(IO_OUT16VAL(base & 0xff, 0x0d),0x03D4);
218 outw(IO_OUT16VAL((base >> 16) & 0xf, 0x69),0x03D4);
219 return 0;
224 * Get the Colormap
227 static int s3trio_get_cmap(struct fb_cmap *cmap, int kspc, int con,
228 struct fb_info *info)
230 if (con == currcon) /* current console? */
231 return fb_get_cmap(cmap, kspc, s3trio_getcolreg, info);
232 else if (fb_display[con].cmap.len) /* non default colormap? */
233 fb_copy_cmap(&fb_display[con].cmap, cmap, kspc ? 0 : 2);
234 else
235 fb_copy_cmap(fb_default_cmap(1 << fb_display[con].var.bits_per_pixel),
236 cmap, kspc ? 0 : 2);
237 return 0;
241 * Set the Colormap
244 static int s3trio_set_cmap(struct fb_cmap *cmap, int kspc, int con,
245 struct fb_info *info)
247 int err;
250 if (!fb_display[con].cmap.len) { /* no colormap allocated? */
251 if ((err = fb_alloc_cmap(&fb_display[con].cmap,
252 1<<fb_display[con].var.bits_per_pixel, 0)))
253 return err;
255 if (con == currcon) /* current console? */
256 return fb_set_cmap(cmap, kspc, s3trio_setcolreg, info);
257 else
258 fb_copy_cmap(cmap, &fb_display[con].cmap, kspc ? 0 : 1);
259 return 0;
263 int __init s3triofb_init(void)
265 struct device_node *dp;
267 dp = find_devices("S3Trio");
268 if (dp != 0)
269 s3triofb_of_init(dp);
270 return 0;
273 void __init s3trio_resetaccel(void){
276 #define EC01_ENH_ENB 0x0005
277 #define EC01_LAW_ENB 0x0010
278 #define EC01_MMIO_ENB 0x0020
280 #define EC00_RESET 0x8000
281 #define EC00_ENABLE 0x4000
282 #define MF_MULT_MISC 0xE000
283 #define SRC_FOREGROUND 0x0020
284 #define SRC_BACKGROUND 0x0000
285 #define MIX_SRC 0x0007
286 #define MF_T_CLIP 0x1000
287 #define MF_L_CLIP 0x2000
288 #define MF_B_CLIP 0x3000
289 #define MF_R_CLIP 0x4000
290 #define MF_PIX_CONTROL 0xA000
291 #define MFA_SRC_FOREGR_MIX 0x0000
292 #define MF_PIX_CONTROL 0xA000
294 outw(EC00_RESET, 0x42e8);
295 inw( 0x42e8);
296 outw(EC00_ENABLE, 0x42e8);
297 inw( 0x42e8);
298 outw(EC01_ENH_ENB | EC01_LAW_ENB,
299 0x4ae8);
300 outw(MF_MULT_MISC, 0xbee8); /* 16 bit I/O registers */
302 /* Now set some basic accelerator registers */
303 Trio_WaitQueue(0x0400);
304 outw(SRC_FOREGROUND | MIX_SRC, 0xbae8);
305 outw(SRC_BACKGROUND | MIX_SRC, 0xb6e8);/* direct color*/
306 outw(MF_T_CLIP | 0, 0xbee8 ); /* clip virtual area */
307 outw(MF_L_CLIP | 0, 0xbee8 );
308 outw(MF_R_CLIP | (640 - 1), 0xbee8);
309 outw(MF_B_CLIP | (480 - 1), 0xbee8);
310 Trio_WaitQueue(0x0400);
311 outw(0xffff, 0xaae8); /* Enable all planes */
312 outw(0xffff, 0xaae8); /* Enable all planes */
313 outw( MF_PIX_CONTROL | MFA_SRC_FOREGR_MIX, 0xbee8);
316 int __init s3trio_init(struct device_node *dp){
318 u_char bus, dev;
319 unsigned int t32;
320 unsigned short cmd;
322 pci_device_loc(dp,&bus,&dev);
323 pcibios_read_config_dword(bus, dev, PCI_VENDOR_ID, &t32);
324 if(t32 == (PCI_DEVICE_ID_S3_TRIO << 16) + PCI_VENDOR_ID_S3) {
325 pcibios_read_config_dword(bus, dev, PCI_BASE_ADDRESS_0, &t32);
326 pcibios_read_config_dword(bus, dev, PCI_BASE_ADDRESS_1, &t32);
327 pcibios_read_config_word(bus, dev, PCI_COMMAND,&cmd);
329 pcibios_write_config_word(bus, dev, PCI_COMMAND, PCI_COMMAND_IO | PCI_COMMAND_MEMORY);
331 pcibios_write_config_dword(bus, dev, PCI_BASE_ADDRESS_0,0xffffffff);
332 pcibios_read_config_dword(bus, dev, PCI_BASE_ADDRESS_0, &t32);
334 /* This is a gross hack as OF only maps enough memory for the framebuffer and
335 we want to use MMIO too. We should find out which chunk of address space
336 we can use here */
337 pcibios_write_config_dword(bus,dev,PCI_BASE_ADDRESS_0,0xc6000000);
339 /* unlock s3 */
341 outb(0x01, 0x3C3);
343 outb(inb(0x03CC) | 1, 0x3c2);
345 outw(IO_OUT16VAL(0x48, 0x38),0x03D4);
346 outw(IO_OUT16VAL(0xA0, 0x39),0x03D4);
347 outb(0x33,0x3d4);
348 outw(IO_OUT16VAL((inb(0x3d5) & ~(0x2 | 0x10 | 0x40)) |
349 0x20, 0x33), 0x3d4);
351 outw(IO_OUT16VAL(0x6, 0x8), 0x3c4);
353 /* switch to MMIO only mode */
355 outb(0x58, 0x3d4);
356 outw(IO_OUT16VAL(inb(0x3d5) | 3 | 0x10, 0x58), 0x3d4);
357 outw(IO_OUT16VAL(8, 0x53), 0x3d4);
359 /* switch off I/O accesses */
361 #if 0
362 pcibios_write_config_word(bus, dev, PCI_COMMAND,
363 PCI_COMMAND_IO | PCI_COMMAND_MEMORY);
364 #endif
365 return 1;
368 return 0;
373 * Initialisation
374 * We heavily rely on OF for the moment. This needs fixing.
377 static void __init s3triofb_of_init(struct device_node *dp)
379 int i, *pp, len;
380 unsigned long address, size;
381 u_long *CursorBase;
383 strncat(s3trio_name, dp->name, sizeof(s3trio_name));
384 s3trio_name[sizeof(s3trio_name)-1] = '\0';
385 strcpy(fb_fix.id, s3trio_name);
387 if((pp = (int *)get_property(dp, "vendor-id", &len)) != NULL
388 && *pp!=PCI_VENDOR_ID_S3) {
389 printk("%s: can't find S3 Trio board\n", dp->full_name);
390 return;
393 if((pp = (int *)get_property(dp, "device-id", &len)) != NULL
394 && *pp!=PCI_DEVICE_ID_S3_TRIO) {
395 printk("%s: can't find S3 Trio board\n", dp->full_name);
396 return;
399 if ((pp = (int *)get_property(dp, "depth", &len)) != NULL
400 && len == sizeof(int) && *pp != 8) {
401 printk("%s: can't use depth = %d\n", dp->full_name, *pp);
402 return;
404 if ((pp = (int *)get_property(dp, "width", &len)) != NULL
405 && len == sizeof(int))
406 fb_var.xres = fb_var.xres_virtual = *pp;
407 if ((pp = (int *)get_property(dp, "height", &len)) != NULL
408 && len == sizeof(int))
409 fb_var.yres = fb_var.yres_virtual = *pp;
410 if ((pp = (int *)get_property(dp, "linebytes", &len)) != NULL
411 && len == sizeof(int))
412 fb_fix.line_length = *pp;
413 else
414 fb_fix.line_length = fb_var.xres_virtual;
415 fb_fix.smem_len = fb_fix.line_length*fb_var.yres;
417 address = 0xc6000000;
418 size = 64*1024*1024;
419 if (!request_mem_region(address, size, "S3triofb"))
420 return;
422 s3trio_init(dp);
423 s3trio_base = ioremap(address, size);
424 fb_fix.smem_start = address;
425 fb_fix.type = FB_TYPE_PACKED_PIXELS;
426 fb_fix.type_aux = 0;
427 fb_fix.accel = FB_ACCEL_S3_TRIO64;
428 fb_fix.mmio_start = address+0x1000000;
429 fb_fix.mmio_len = 0x1000000;
431 fb_fix.xpanstep = 1;
432 fb_fix.ypanstep = 1;
434 s3trio_resetaccel();
436 mem_out8(0x30, s3trio_base+0x1008000 + 0x03D4);
437 mem_out8(0x2d, s3trio_base+0x1008000 + 0x03D4);
438 mem_out8(0x2e, s3trio_base+0x1008000 + 0x03D4);
440 mem_out8(0x50, s3trio_base+0x1008000 + 0x03D4);
442 /* disable HW cursor */
444 mem_out8(0x39, s3trio_base+0x1008000 + 0x03D4);
445 mem_out8(0xa0, s3trio_base+0x1008000 + 0x03D5);
447 mem_out8(0x45, s3trio_base+0x1008000 + 0x03D4);
448 mem_out8(0, s3trio_base+0x1008000 + 0x03D5);
450 mem_out8(0x4e, s3trio_base+0x1008000 + 0x03D4);
451 mem_out8(0, s3trio_base+0x1008000 + 0x03D5);
453 mem_out8(0x4f, s3trio_base+0x1008000 + 0x03D4);
454 mem_out8(0, s3trio_base+0x1008000 + 0x03D5);
456 /* init HW cursor */
458 CursorBase = (u_long *)(s3trio_base + 2*1024*1024 - 0x400);
459 for (i = 0; i < 8; i++) {
460 *(CursorBase +(i*4)) = 0xffffff00;
461 *(CursorBase+1+(i*4)) = 0xffff0000;
462 *(CursorBase+2+(i*4)) = 0xffff0000;
463 *(CursorBase+3+(i*4)) = 0xffff0000;
465 for (i = 8; i < 64; i++) {
466 *(CursorBase +(i*4)) = 0xffff0000;
467 *(CursorBase+1+(i*4)) = 0xffff0000;
468 *(CursorBase+2+(i*4)) = 0xffff0000;
469 *(CursorBase+3+(i*4)) = 0xffff0000;
473 mem_out8(0x4c, s3trio_base+0x1008000 + 0x03D4);
474 mem_out8(((2*1024 - 1)&0xf00)>>8, s3trio_base+0x1008000 + 0x03D5);
476 mem_out8(0x4d, s3trio_base+0x1008000 + 0x03D4);
477 mem_out8((2*1024 - 1) & 0xff, s3trio_base+0x1008000 + 0x03D5);
479 mem_out8(0x45, s3trio_base+0x1008000 + 0x03D4);
480 mem_in8(s3trio_base+0x1008000 + 0x03D4);
482 mem_out8(0x4a, s3trio_base+0x1008000 + 0x03D4);
483 mem_out8(0x80, s3trio_base+0x1008000 + 0x03D5);
484 mem_out8(0x80, s3trio_base+0x1008000 + 0x03D5);
485 mem_out8(0x80, s3trio_base+0x1008000 + 0x03D5);
487 mem_out8(0x4b, s3trio_base+0x1008000 + 0x03D4);
488 mem_out8(0x00, s3trio_base+0x1008000 + 0x03D5);
489 mem_out8(0x00, s3trio_base+0x1008000 + 0x03D5);
490 mem_out8(0x00, s3trio_base+0x1008000 + 0x03D5);
492 mem_out8(0x45, s3trio_base+0x1008000 + 0x03D4);
493 mem_out8(0, s3trio_base+0x1008000 + 0x03D5);
495 /* setup default color table */
497 for(i = 0; i < 16; i++) {
498 int j = color_table[i];
499 palette[i].red=default_red[j];
500 palette[i].green=default_grn[j];
501 palette[i].blue=default_blu[j];
504 s3trio_setcolreg(255, 56, 100, 160, 0, NULL /* not used */);
505 s3trio_setcolreg(254, 0, 0, 0, 0, NULL /* not used */);
506 memset((char *)s3trio_base, 0, 640*480);
508 #if 0
509 Trio_RectFill(0, 0, 90, 90, 7, 1);
510 #endif
512 fb_fix.visual = FB_VISUAL_PSEUDOCOLOR ;
513 fb_var.xoffset = fb_var.yoffset = 0;
514 fb_var.bits_per_pixel = 8;
515 fb_var.grayscale = 0;
516 fb_var.red.offset = fb_var.green.offset = fb_var.blue.offset = 0;
517 fb_var.red.length = fb_var.green.length = fb_var.blue.length = 8;
518 fb_var.red.msb_right = fb_var.green.msb_right = fb_var.blue.msb_right = 0;
519 fb_var.transp.offset = fb_var.transp.length = fb_var.transp.msb_right = 0;
520 fb_var.nonstd = 0;
521 fb_var.activate = 0;
522 fb_var.height = fb_var.width = -1;
523 fb_var.accel_flags = FB_ACCELF_TEXT;
524 #warning FIXME: always obey fb_var.accel_flags
525 fb_var.pixclock = 1;
526 fb_var.left_margin = fb_var.right_margin = 0;
527 fb_var.upper_margin = fb_var.lower_margin = 0;
528 fb_var.hsync_len = fb_var.vsync_len = 0;
529 fb_var.sync = 0;
530 fb_var.vmode = FB_VMODE_NONINTERLACED;
532 disp.var = fb_var;
533 disp.cmap.start = 0;
534 disp.cmap.len = 0;
535 disp.cmap.red = disp.cmap.green = disp.cmap.blue = disp.cmap.transp = NULL;
536 disp.screen_base = s3trio_base;
537 disp.visual = fb_fix.visual;
538 disp.type = fb_fix.type;
539 disp.type_aux = fb_fix.type_aux;
540 disp.ypanstep = 0;
541 disp.ywrapstep = 0;
542 disp.line_length = fb_fix.line_length;
543 disp.can_soft_blank = 1;
544 disp.inverse = 0;
545 #ifdef FBCON_HAS_CFB8
546 if (fb_var.accel_flags & FB_ACCELF_TEXT)
547 disp.dispsw = &fbcon_trio8;
548 else
549 disp.dispsw = &fbcon_cfb8;
550 #else
551 disp.dispsw = &fbcon_dummy;
552 #endif
553 disp.scrollmode = fb_var.accel_flags & FB_ACCELF_TEXT ? 0 : SCROLL_YREDRAW;
555 strcpy(fb_info.modename, "Trio64 ");
556 strncat(fb_info.modename, dp->full_name, sizeof(fb_info.modename));
557 fb_info.node = -1;
558 fb_info.fbops = &s3trio_ops;
559 #if 0
560 fb_info.fbvar_num = 1;
561 fb_info.fbvar = &fb_var;
562 #endif
563 fb_info.disp = &disp;
564 fb_info.fontname[0] = '\0';
565 fb_info.changevar = NULL;
566 fb_info.switch_con = &s3triofbcon_switch;
567 fb_info.updatevar = &s3triofbcon_updatevar;
568 fb_info.blank = &s3triofbcon_blank;
569 #if 0
570 fb_info.setcmap = &s3triofbcon_setcmap;
571 #endif
573 #ifdef CONFIG_FB_COMPAT_XPMAC
574 if (!console_fb_info) {
575 display_info.height = fb_var.yres;
576 display_info.width = fb_var.xres;
577 display_info.depth = 8;
578 display_info.pitch = fb_fix.line_length;
579 display_info.mode = 0;
580 strncpy(display_info.name, dp->name, sizeof(display_info.name));
581 display_info.fb_address = (unsigned long)fb_fix.smem_start;
582 display_info.disp_reg_address = address + 0x1008000;
583 display_info.cmap_adr_address = address + 0x1008000 + 0x3c8;
584 display_info.cmap_data_address = address + 0x1008000 + 0x3c9;
585 console_fb_info = &fb_info;
587 #endif /* CONFIG_FB_COMPAT_XPMAC) */
589 fb_info.flags = FBINFO_FLAG_DEFAULT;
590 if (register_framebuffer(&fb_info) < 0)
591 return;
593 printk("fb%d: S3 Trio frame buffer device on %s\n",
594 GET_FB_IDX(fb_info.node), dp->full_name);
598 static int s3triofbcon_switch(int con, struct fb_info *info)
600 /* Do we have to save the colormap? */
601 if (fb_display[currcon].cmap.len)
602 fb_get_cmap(&fb_display[currcon].cmap, 1, s3trio_getcolreg, info);
604 currcon = con;
605 /* Install new colormap */
606 do_install_cmap(con,info);
607 return 0;
611 * Update the `var' structure (called by fbcon.c)
614 static int s3triofbcon_updatevar(int con, struct fb_info *info)
616 /* Nothing */
617 return 0;
621 * Blank the display.
624 static void s3triofbcon_blank(int blank, struct fb_info *info)
626 unsigned char x;
628 mem_out8(0x1, s3trio_base+0x1008000 + 0x03c4);
629 x = mem_in8(s3trio_base+0x1008000 + 0x03c5);
630 mem_out8((x & (~0x20)) | (blank << 5), s3trio_base+0x1008000 + 0x03c5);
634 * Set the colormap
637 #if 0
638 static int s3triofbcon_setcmap(struct fb_cmap *cmap, int con)
640 return(s3trio_set_cmap(cmap, 1, con, &fb_info));
642 #endif
646 * Read a single color register and split it into
647 * colors/transparent. Return != 0 for invalid regno.
650 static int s3trio_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue,
651 u_int *transp, struct fb_info *info)
653 if (regno > 255)
654 return 1;
655 *red = (palette[regno].red << 8) | palette[regno].red;
656 *green = (palette[regno].green << 8) | palette[regno].green;
657 *blue = (palette[regno].blue << 8) | palette[regno].blue;
658 *transp = 0;
659 return 0;
664 * Set a single color register. Return != 0 for invalid regno.
667 static int s3trio_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
668 u_int transp, struct fb_info *info)
670 if (regno > 255)
671 return 1;
673 red >>= 8;
674 green >>= 8;
675 blue >>= 8;
676 palette[regno].red = red;
677 palette[regno].green = green;
678 palette[regno].blue = blue;
680 mem_out8(regno,s3trio_base+0x1008000 + 0x3c8);
681 mem_out8((red & 0xff) >> 2,s3trio_base+0x1008000 + 0x3c9);
682 mem_out8((green & 0xff) >> 2,s3trio_base+0x1008000 + 0x3c9);
683 mem_out8((blue & 0xff) >> 2,s3trio_base+0x1008000 + 0x3c9);
685 return 0;
689 static void do_install_cmap(int con, struct fb_info *info)
691 if (con != currcon)
692 return;
693 if (fb_display[con].cmap.len)
694 fb_set_cmap(&fb_display[con].cmap, 1, s3trio_setcolreg, &fb_info);
695 else
696 fb_set_cmap(fb_default_cmap(fb_display[con].var.bits_per_pixel), 1,
697 s3trio_setcolreg, &fb_info);
700 static void Trio_WaitQueue(u_short fifo) {
702 u_short status;
706 status = mem_in16(s3trio_base + 0x1000000 + 0x9AE8);
707 } while (!(status & fifo));
711 static void Trio_WaitBlit(void) {
713 u_short status;
717 status = mem_in16(s3trio_base + 0x1000000 + 0x9AE8);
718 } while (status & 0x200);
722 static void Trio_BitBLT(u_short curx, u_short cury, u_short destx,
723 u_short desty, u_short width, u_short height,
724 u_short mode) {
726 u_short blitcmd = 0xc011;
728 /* Set drawing direction */
729 /* -Y, X maj, -X (default) */
731 if (curx > destx)
732 blitcmd |= 0x0020; /* Drawing direction +X */
733 else {
734 curx += (width - 1);
735 destx += (width - 1);
738 if (cury > desty)
739 blitcmd |= 0x0080; /* Drawing direction +Y */
740 else {
741 cury += (height - 1);
742 desty += (height - 1);
745 Trio_WaitQueue(0x0400);
747 outw(0xa000, 0xBEE8);
748 outw(0x60 | mode, 0xBAE8);
750 outw(curx, 0x86E8);
751 outw(cury, 0x82E8);
753 outw(destx, 0x8EE8);
754 outw(desty, 0x8AE8);
756 outw(height - 1, 0xBEE8);
757 outw(width - 1, 0x96E8);
759 outw(blitcmd, 0x9AE8);
763 static void Trio_RectFill(u_short x, u_short y, u_short width, u_short height,
764 u_short mode, u_short color) {
766 u_short blitcmd = 0x40b1;
768 Trio_WaitQueue(0x0400);
770 outw(0xa000, 0xBEE8);
771 outw((0x20 | mode), 0xBAE8);
772 outw(0xe000, 0xBEE8);
773 outw(color, 0xA6E8);
774 outw(x, 0x86E8);
775 outw(y, 0x82E8);
776 outw((height - 1), 0xBEE8);
777 outw((width - 1), 0x96E8);
778 outw(blitcmd, 0x9AE8);
783 static void Trio_MoveCursor(u_short x, u_short y) {
785 mem_out8(0x39, s3trio_base + 0x1008000 + 0x3d4);
786 mem_out8(0xa0, s3trio_base + 0x1008000 + 0x3d5);
788 mem_out8(0x46, s3trio_base + 0x1008000 + 0x3d4);
789 mem_out8((x & 0x0700) >> 8, s3trio_base + 0x1008000 + 0x3d5);
790 mem_out8(0x47, s3trio_base + 0x1008000 + 0x3d4);
791 mem_out8(x & 0x00ff, s3trio_base + 0x1008000 + 0x3d5);
793 mem_out8(0x48, s3trio_base + 0x1008000 + 0x3d4);
794 mem_out8((y & 0x0700) >> 8, s3trio_base + 0x1008000 + 0x3d5);
795 mem_out8(0x49, s3trio_base + 0x1008000 + 0x3d4);
796 mem_out8(y & 0x00ff, s3trio_base + 0x1008000 + 0x3d5);
802 * Text console acceleration
805 #ifdef FBCON_HAS_CFB8
806 static void fbcon_trio8_bmove(struct display *p, int sy, int sx, int dy,
807 int dx, int height, int width)
809 sx *= 8; dx *= 8; width *= 8;
810 Trio_BitBLT((u_short)sx, (u_short)(sy*fontheight(p)), (u_short)dx,
811 (u_short)(dy*fontheight(p)), (u_short)width,
812 (u_short)(height*fontheight(p)), (u_short)S3_NEW);
815 static void fbcon_trio8_clear(struct vc_data *conp, struct display *p, int sy,
816 int sx, int height, int width)
818 unsigned char bg;
820 sx *= 8; width *= 8;
821 bg = attr_bgcol_ec(p,conp);
822 Trio_RectFill((u_short)sx,
823 (u_short)(sy*fontheight(p)),
824 (u_short)width,
825 (u_short)(height*fontheight(p)),
826 (u_short)S3_NEW,
827 (u_short)bg);
830 static void fbcon_trio8_putc(struct vc_data *conp, struct display *p, int c,
831 int yy, int xx)
833 Trio_WaitBlit();
834 fbcon_cfb8_putc(conp, p, c, yy, xx);
837 static void fbcon_trio8_putcs(struct vc_data *conp, struct display *p,
838 const unsigned short *s, int count, int yy, int xx)
840 Trio_WaitBlit();
841 fbcon_cfb8_putcs(conp, p, s, count, yy, xx);
844 static void fbcon_trio8_revc(struct display *p, int xx, int yy)
846 Trio_WaitBlit();
847 fbcon_cfb8_revc(p, xx, yy);
850 static struct display_switch fbcon_trio8 = {
851 setup: fbcon_cfb8_setup,
852 bmove: fbcon_trio8_bmove,
853 clear: fbcon_trio8_clear,
854 putc: fbcon_trio8_putc,
855 putcs: fbcon_trio8_putcs,
856 revc: fbcon_trio8_revc,
857 clear_margins: fbcon_cfb8_clear_margins,
858 fontwidthmask: FONTWIDTH(8)
860 #endif