Linux-2.6.12-rc2
[linux-2.6/next.git] / drivers / video / S3triofb.c
blob455fda990ff70472a895cfb36b346a1d2fe181d6
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/slab.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>
45 #include <video/fbcon.h>
46 #include <video/fbcon-cfb8.h>
47 #include <video/s3blit.h>
50 #define mem_in8(addr) in_8((void *)(addr))
51 #define mem_in16(addr) in_le16((void *)(addr))
52 #define mem_in32(addr) in_le32((void *)(addr))
54 #define mem_out8(val, addr) out_8((void *)(addr), val)
55 #define mem_out16(val, addr) out_le16((void *)(addr), val)
56 #define mem_out32(val, addr) out_le32((void *)(addr), val)
58 #define IO_OUT16VAL(v, r) (((v) << 8) | (r))
60 static struct display disp;
61 static struct fb_info fb_info;
62 static struct { u_char red, green, blue, pad; } palette[256];
63 static char s3trio_name[16] = "S3Trio ";
64 static char *s3trio_base;
66 static struct fb_fix_screeninfo fb_fix;
67 static struct fb_var_screeninfo fb_var = { 0, };
71 * Interface used by the world
74 static void __init s3triofb_of_init(struct device_node *dp);
75 static int s3trio_get_fix(struct fb_fix_screeninfo *fix, int con,
76 struct fb_info *info);
77 static int s3trio_get_var(struct fb_var_screeninfo *var, int con,
78 struct fb_info *info);
79 static int s3trio_set_var(struct fb_var_screeninfo *var, int con,
80 struct fb_info *info);
81 static int s3trio_get_cmap(struct fb_cmap *cmap, int kspc, int con,
82 struct fb_info *info);
83 static int s3trio_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
84 u_int transp, struct fb_info *info);
85 static int s3trio_pan_display(struct fb_var_screeninfo *var, int con,
86 struct fb_info *info);
87 static void s3triofb_blank(int blank, struct fb_info *info);
90 * Interface to the low level console driver
93 int s3triofb_init(void);
94 static int s3triofbcon_switch(int con, struct fb_info *info);
95 static int s3triofbcon_updatevar(int con, struct fb_info *info);
98 * Text console acceleration
101 #ifdef FBCON_HAS_CFB8
102 static struct display_switch fbcon_trio8;
103 #endif
106 * Accelerated Functions used by the low level console driver
109 static void Trio_WaitQueue(u_short fifo);
110 static void Trio_WaitBlit(void);
111 static void Trio_BitBLT(u_short curx, u_short cury, u_short destx,
112 u_short desty, u_short width, u_short height,
113 u_short mode);
114 static void Trio_RectFill(u_short x, u_short y, u_short width, u_short height,
115 u_short mode, u_short color);
116 static void Trio_MoveCursor(u_short x, u_short y);
120 * Internal routines
123 static int s3trio_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue,
124 u_int *transp, struct fb_info *info);
126 static struct fb_ops s3trio_ops = {
127 .owner = THIS_MODULE,
128 .fb_get_fix = s3trio_get_fix,
129 .fb_get_var = s3trio_get_var,
130 .fb_set_var = s3trio_set_var,
131 .fb_get_cmap = s3trio_get_cmap,
132 .fb_set_cmap = gen_set_cmap,
133 .fb_setcolreg = s3trio_setcolreg,
134 .fb_pan_display =s3trio_pan_display,
135 .fb_blank = s3triofb_blank,
139 * Get the Fixed Part of the Display
142 static int s3trio_get_fix(struct fb_fix_screeninfo *fix, int con,
143 struct fb_info *info)
145 memcpy(fix, &fb_fix, sizeof(fb_fix));
146 return 0;
151 * Get the User Defined Part of the Display
154 static int s3trio_get_var(struct fb_var_screeninfo *var, int con,
155 struct fb_info *info)
157 memcpy(var, &fb_var, sizeof(fb_var));
158 return 0;
163 * Set the User Defined Part of the Display
166 static int s3trio_set_var(struct fb_var_screeninfo *var, int con,
167 struct fb_info *info)
169 if (var->xres > fb_var.xres || var->yres > fb_var.yres ||
170 var->bits_per_pixel > fb_var.bits_per_pixel )
171 /* || var->nonstd || var->vmode != FB_VMODE_NONINTERLACED) */
172 return -EINVAL;
173 if (var->xres_virtual > fb_var.xres_virtual) {
174 outw(IO_OUT16VAL((var->xres_virtual /8) & 0xff, 0x13), 0x3d4);
175 outw(IO_OUT16VAL(((var->xres_virtual /8 ) & 0x300) >> 3, 0x51), 0x3d4);
176 fb_var.xres_virtual = var->xres_virtual;
177 fb_fix.line_length = var->xres_virtual;
179 fb_var.yres_virtual = var->yres_virtual;
180 memcpy(var, &fb_var, sizeof(fb_var));
181 return 0;
186 * Pan or Wrap the Display
188 * This call looks only at xoffset, yoffset and the FB_VMODE_YWRAP flag
191 static int s3trio_pan_display(struct fb_var_screeninfo *var, int con,
192 struct fb_info *info)
194 unsigned int base;
196 if (var->xoffset > (var->xres_virtual - var->xres))
197 return -EINVAL;
198 if (var->yoffset > (var->yres_virtual - var->yres))
199 return -EINVAL;
201 fb_var.xoffset = var->xoffset;
202 fb_var.yoffset = var->yoffset;
204 base = var->yoffset * fb_fix.line_length + var->xoffset;
206 outw(IO_OUT16VAL((base >> 8) & 0xff, 0x0c),0x03D4);
207 outw(IO_OUT16VAL(base & 0xff, 0x0d),0x03D4);
208 outw(IO_OUT16VAL((base >> 16) & 0xf, 0x69),0x03D4);
209 return 0;
214 * Get the Colormap
217 static int s3trio_get_cmap(struct fb_cmap *cmap, int kspc, int con,
218 struct fb_info *info)
220 if (con == info->currcon) /* current console? */
221 return fb_get_cmap(cmap, kspc, s3trio_getcolreg, info);
222 else if (fb_display[con].cmap.len) /* non default colormap? */
223 fb_copy_cmap(&fb_display[con].cmap, cmap, kspc ? 0 : 2);
224 else
225 fb_copy_cmap(fb_default_cmap(1 << fb_display[con].var.bits_per_pixel),
226 cmap, kspc ? 0 : 2);
227 return 0;
230 int __init s3triofb_init(void)
232 struct device_node *dp;
234 dp = find_devices("S3Trio");
235 if (dp != 0)
236 s3triofb_of_init(dp);
237 return 0;
240 void __init s3trio_resetaccel(void){
243 #define EC01_ENH_ENB 0x0005
244 #define EC01_LAW_ENB 0x0010
245 #define EC01_MMIO_ENB 0x0020
247 #define EC00_RESET 0x8000
248 #define EC00_ENABLE 0x4000
249 #define MF_MULT_MISC 0xE000
250 #define SRC_FOREGROUND 0x0020
251 #define SRC_BACKGROUND 0x0000
252 #define MIX_SRC 0x0007
253 #define MF_T_CLIP 0x1000
254 #define MF_L_CLIP 0x2000
255 #define MF_B_CLIP 0x3000
256 #define MF_R_CLIP 0x4000
257 #define MF_PIX_CONTROL 0xA000
258 #define MFA_SRC_FOREGR_MIX 0x0000
259 #define MF_PIX_CONTROL 0xA000
261 outw(EC00_RESET, 0x42e8);
262 inw( 0x42e8);
263 outw(EC00_ENABLE, 0x42e8);
264 inw( 0x42e8);
265 outw(EC01_ENH_ENB | EC01_LAW_ENB,
266 0x4ae8);
267 outw(MF_MULT_MISC, 0xbee8); /* 16 bit I/O registers */
269 /* Now set some basic accelerator registers */
270 Trio_WaitQueue(0x0400);
271 outw(SRC_FOREGROUND | MIX_SRC, 0xbae8);
272 outw(SRC_BACKGROUND | MIX_SRC, 0xb6e8);/* direct color*/
273 outw(MF_T_CLIP | 0, 0xbee8 ); /* clip virtual area */
274 outw(MF_L_CLIP | 0, 0xbee8 );
275 outw(MF_R_CLIP | (640 - 1), 0xbee8);
276 outw(MF_B_CLIP | (480 - 1), 0xbee8);
277 Trio_WaitQueue(0x0400);
278 outw(0xffff, 0xaae8); /* Enable all planes */
279 outw(0xffff, 0xaae8); /* Enable all planes */
280 outw( MF_PIX_CONTROL | MFA_SRC_FOREGR_MIX, 0xbee8);
283 int __init s3trio_init(struct device_node *dp){
285 u_char bus, dev;
286 unsigned int t32;
287 unsigned short cmd;
289 pci_device_loc(dp,&bus,&dev);
290 pcibios_read_config_dword(bus, dev, PCI_VENDOR_ID, &t32);
291 if(t32 == (PCI_DEVICE_ID_S3_TRIO << 16) + PCI_VENDOR_ID_S3) {
292 pcibios_read_config_dword(bus, dev, PCI_BASE_ADDRESS_0, &t32);
293 pcibios_read_config_dword(bus, dev, PCI_BASE_ADDRESS_1, &t32);
294 pcibios_read_config_word(bus, dev, PCI_COMMAND,&cmd);
296 pcibios_write_config_word(bus, dev, PCI_COMMAND, PCI_COMMAND_IO | PCI_COMMAND_MEMORY);
298 pcibios_write_config_dword(bus, dev, PCI_BASE_ADDRESS_0,0xffffffff);
299 pcibios_read_config_dword(bus, dev, PCI_BASE_ADDRESS_0, &t32);
301 /* This is a gross hack as OF only maps enough memory for the framebuffer and
302 we want to use MMIO too. We should find out which chunk of address space
303 we can use here */
304 pcibios_write_config_dword(bus,dev,PCI_BASE_ADDRESS_0,0xc6000000);
306 /* unlock s3 */
308 outb(0x01, 0x3C3);
310 outb(inb(0x03CC) | 1, 0x3c2);
312 outw(IO_OUT16VAL(0x48, 0x38),0x03D4);
313 outw(IO_OUT16VAL(0xA0, 0x39),0x03D4);
314 outb(0x33,0x3d4);
315 outw(IO_OUT16VAL((inb(0x3d5) & ~(0x2 | 0x10 | 0x40)) |
316 0x20, 0x33), 0x3d4);
318 outw(IO_OUT16VAL(0x6, 0x8), 0x3c4);
320 /* switch to MMIO only mode */
322 outb(0x58, 0x3d4);
323 outw(IO_OUT16VAL(inb(0x3d5) | 3 | 0x10, 0x58), 0x3d4);
324 outw(IO_OUT16VAL(8, 0x53), 0x3d4);
326 /* switch off I/O accesses */
328 #if 0
329 pcibios_write_config_word(bus, dev, PCI_COMMAND,
330 PCI_COMMAND_IO | PCI_COMMAND_MEMORY);
331 #endif
332 return 1;
335 return 0;
340 * Initialisation
341 * We heavily rely on OF for the moment. This needs fixing.
344 static void __init s3triofb_of_init(struct device_node *dp)
346 int i, *pp, len;
347 unsigned long address, size;
348 u_long *CursorBase;
350 strncat(s3trio_name, dp->name, sizeof(s3trio_name));
351 s3trio_name[sizeof(s3trio_name)-1] = '\0';
352 strcpy(fb_fix.id, s3trio_name);
354 if((pp = (int *)get_property(dp, "vendor-id", &len)) != NULL
355 && *pp!=PCI_VENDOR_ID_S3) {
356 printk("%s: can't find S3 Trio board\n", dp->full_name);
357 return;
360 if((pp = (int *)get_property(dp, "device-id", &len)) != NULL
361 && *pp!=PCI_DEVICE_ID_S3_TRIO) {
362 printk("%s: can't find S3 Trio board\n", dp->full_name);
363 return;
366 if ((pp = (int *)get_property(dp, "depth", &len)) != NULL
367 && len == sizeof(int) && *pp != 8) {
368 printk("%s: can't use depth = %d\n", dp->full_name, *pp);
369 return;
371 if ((pp = (int *)get_property(dp, "width", &len)) != NULL
372 && len == sizeof(int))
373 fb_var.xres = fb_var.xres_virtual = *pp;
374 if ((pp = (int *)get_property(dp, "height", &len)) != NULL
375 && len == sizeof(int))
376 fb_var.yres = fb_var.yres_virtual = *pp;
377 if ((pp = (int *)get_property(dp, "linebytes", &len)) != NULL
378 && len == sizeof(int))
379 fb_fix.line_length = *pp;
380 else
381 fb_fix.line_length = fb_var.xres_virtual;
382 fb_fix.smem_len = fb_fix.line_length*fb_var.yres;
384 address = 0xc6000000;
385 size = 64*1024*1024;
386 if (!request_mem_region(address, size, "S3triofb"))
387 return;
389 s3trio_init(dp);
390 s3trio_base = ioremap(address, size);
391 fb_fix.smem_start = address;
392 fb_fix.type = FB_TYPE_PACKED_PIXELS;
393 fb_fix.type_aux = 0;
394 fb_fix.accel = FB_ACCEL_S3_TRIO64;
395 fb_fix.mmio_start = address+0x1000000;
396 fb_fix.mmio_len = 0x1000000;
398 fb_fix.xpanstep = 1;
399 fb_fix.ypanstep = 1;
401 s3trio_resetaccel();
403 mem_out8(0x30, s3trio_base+0x1008000 + 0x03D4);
404 mem_out8(0x2d, s3trio_base+0x1008000 + 0x03D4);
405 mem_out8(0x2e, s3trio_base+0x1008000 + 0x03D4);
407 mem_out8(0x50, s3trio_base+0x1008000 + 0x03D4);
409 /* disable HW cursor */
411 mem_out8(0x39, s3trio_base+0x1008000 + 0x03D4);
412 mem_out8(0xa0, s3trio_base+0x1008000 + 0x03D5);
414 mem_out8(0x45, s3trio_base+0x1008000 + 0x03D4);
415 mem_out8(0, s3trio_base+0x1008000 + 0x03D5);
417 mem_out8(0x4e, s3trio_base+0x1008000 + 0x03D4);
418 mem_out8(0, s3trio_base+0x1008000 + 0x03D5);
420 mem_out8(0x4f, s3trio_base+0x1008000 + 0x03D4);
421 mem_out8(0, s3trio_base+0x1008000 + 0x03D5);
423 /* init HW cursor */
425 CursorBase = (u_long *)(s3trio_base + 2*1024*1024 - 0x400);
426 for (i = 0; i < 8; i++) {
427 *(CursorBase +(i*4)) = 0xffffff00;
428 *(CursorBase+1+(i*4)) = 0xffff0000;
429 *(CursorBase+2+(i*4)) = 0xffff0000;
430 *(CursorBase+3+(i*4)) = 0xffff0000;
432 for (i = 8; i < 64; i++) {
433 *(CursorBase +(i*4)) = 0xffff0000;
434 *(CursorBase+1+(i*4)) = 0xffff0000;
435 *(CursorBase+2+(i*4)) = 0xffff0000;
436 *(CursorBase+3+(i*4)) = 0xffff0000;
440 mem_out8(0x4c, s3trio_base+0x1008000 + 0x03D4);
441 mem_out8(((2*1024 - 1)&0xf00)>>8, s3trio_base+0x1008000 + 0x03D5);
443 mem_out8(0x4d, s3trio_base+0x1008000 + 0x03D4);
444 mem_out8((2*1024 - 1) & 0xff, s3trio_base+0x1008000 + 0x03D5);
446 mem_out8(0x45, s3trio_base+0x1008000 + 0x03D4);
447 mem_in8(s3trio_base+0x1008000 + 0x03D4);
449 mem_out8(0x4a, s3trio_base+0x1008000 + 0x03D4);
450 mem_out8(0x80, s3trio_base+0x1008000 + 0x03D5);
451 mem_out8(0x80, s3trio_base+0x1008000 + 0x03D5);
452 mem_out8(0x80, s3trio_base+0x1008000 + 0x03D5);
454 mem_out8(0x4b, s3trio_base+0x1008000 + 0x03D4);
455 mem_out8(0x00, s3trio_base+0x1008000 + 0x03D5);
456 mem_out8(0x00, s3trio_base+0x1008000 + 0x03D5);
457 mem_out8(0x00, s3trio_base+0x1008000 + 0x03D5);
459 mem_out8(0x45, s3trio_base+0x1008000 + 0x03D4);
460 mem_out8(0, s3trio_base+0x1008000 + 0x03D5);
462 /* setup default color table */
464 for(i = 0; i < 16; i++) {
465 int j = color_table[i];
466 palette[i].red=default_red[j];
467 palette[i].green=default_grn[j];
468 palette[i].blue=default_blu[j];
471 s3trio_setcolreg(255, 56, 100, 160, 0, NULL /* not used */);
472 s3trio_setcolreg(254, 0, 0, 0, 0, NULL /* not used */);
473 memset((char *)s3trio_base, 0, 640*480);
475 #if 0
476 Trio_RectFill(0, 0, 90, 90, 7, 1);
477 #endif
479 fb_fix.visual = FB_VISUAL_PSEUDOCOLOR ;
480 fb_var.xoffset = fb_var.yoffset = 0;
481 fb_var.bits_per_pixel = 8;
482 fb_var.grayscale = 0;
483 fb_var.red.offset = fb_var.green.offset = fb_var.blue.offset = 0;
484 fb_var.red.length = fb_var.green.length = fb_var.blue.length = 8;
485 fb_var.red.msb_right = fb_var.green.msb_right = fb_var.blue.msb_right = 0;
486 fb_var.transp.offset = fb_var.transp.length = fb_var.transp.msb_right = 0;
487 fb_var.nonstd = 0;
488 fb_var.activate = 0;
489 fb_var.height = fb_var.width = -1;
490 fb_var.accel_flags = FB_ACCELF_TEXT;
491 #warning FIXME: always obey fb_var.accel_flags
492 fb_var.pixclock = 1;
493 fb_var.left_margin = fb_var.right_margin = 0;
494 fb_var.upper_margin = fb_var.lower_margin = 0;
495 fb_var.hsync_len = fb_var.vsync_len = 0;
496 fb_var.sync = 0;
497 fb_var.vmode = FB_VMODE_NONINTERLACED;
499 disp.var = fb_var;
500 disp.cmap.start = 0;
501 disp.cmap.len = 0;
502 disp.cmap.red = disp.cmap.green = disp.cmap.blue = disp.cmap.transp = NULL;
503 disp.visual = fb_fix.visual;
504 disp.type = fb_fix.type;
505 disp.type_aux = fb_fix.type_aux;
506 disp.ypanstep = 0;
507 disp.ywrapstep = 0;
508 disp.line_length = fb_fix.line_length;
509 disp.can_soft_blank = 1;
510 disp.inverse = 0;
511 #ifdef FBCON_HAS_CFB8
512 if (fb_var.accel_flags & FB_ACCELF_TEXT)
513 disp.dispsw = &fbcon_trio8;
514 else
515 disp.dispsw = &fbcon_cfb8;
516 #else
517 disp.dispsw = &fbcon_dummy;
518 #endif
519 disp.scrollmode = fb_var.accel_flags & FB_ACCELF_TEXT ? 0 : SCROLL_YREDRAW;
521 strcpy(fb_info.modename, "Trio64 ");
522 strncat(fb_info.modename, dp->full_name, sizeof(fb_info.modename));
523 fb_info.currcon = -1;
524 fb_info.fbops = &s3trio_ops;
525 fb_info.screen_base = s3trio_base;
526 #if 0
527 fb_info.fbvar_num = 1;
528 fb_info.fbvar = &fb_var;
529 #endif
530 fb_info.disp = &disp;
531 fb_info.fontname[0] = '\0';
532 fb_info.changevar = NULL;
533 fb_info.switch_con = &s3triofbcon_switch;
534 fb_info.updatevar = &s3triofbcon_updatevar;
535 #if 0
536 fb_info.setcmap = &s3triofbcon_setcmap;
537 #endif
539 fb_info.flags = FBINFO_FLAG_DEFAULT;
540 if (register_framebuffer(&fb_info) < 0)
541 return;
543 printk("fb%d: S3 Trio frame buffer device on %s\n",
544 fb_info.node, dp->full_name);
548 static int s3triofbcon_switch(int con, struct fb_info *info)
550 /* Do we have to save the colormap? */
551 if (fb_display[info->currcon].cmap.len)
552 fb_get_cmap(&fb_display[info->currcon].cmap, 1, s3trio_getcolreg, info);
554 info->currcon = con;
555 /* Install new colormap */
556 do_install_cmap(con,info);
557 return 0;
561 * Update the `var' structure (called by fbcon.c)
564 static int s3triofbcon_updatevar(int con, struct fb_info *info)
566 /* Nothing */
567 return 0;
571 * Blank the display.
574 static int s3triofb_blank(int blank, struct fb_info *info)
576 unsigned char x;
578 mem_out8(0x1, s3trio_base+0x1008000 + 0x03c4);
579 x = mem_in8(s3trio_base+0x1008000 + 0x03c5);
580 mem_out8((x & (~0x20)) | (blank << 5), s3trio_base+0x1008000 + 0x03c5);
581 return 0;
585 * Read a single color register and split it into
586 * colors/transparent. Return != 0 for invalid regno.
589 static int s3trio_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue,
590 u_int *transp, struct fb_info *info)
592 if (regno > 255)
593 return 1;
594 *red = (palette[regno].red << 8) | palette[regno].red;
595 *green = (palette[regno].green << 8) | palette[regno].green;
596 *blue = (palette[regno].blue << 8) | palette[regno].blue;
597 *transp = 0;
598 return 0;
603 * Set a single color register. Return != 0 for invalid regno.
606 static int s3trio_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
607 u_int transp, struct fb_info *info)
609 if (regno > 255)
610 return 1;
612 red >>= 8;
613 green >>= 8;
614 blue >>= 8;
615 palette[regno].red = red;
616 palette[regno].green = green;
617 palette[regno].blue = blue;
619 mem_out8(regno,s3trio_base+0x1008000 + 0x3c8);
620 mem_out8((red & 0xff) >> 2,s3trio_base+0x1008000 + 0x3c9);
621 mem_out8((green & 0xff) >> 2,s3trio_base+0x1008000 + 0x3c9);
622 mem_out8((blue & 0xff) >> 2,s3trio_base+0x1008000 + 0x3c9);
624 return 0;
627 static void Trio_WaitQueue(u_short fifo) {
629 u_short status;
633 status = mem_in16(s3trio_base + 0x1000000 + 0x9AE8);
634 } while (!(status & fifo));
638 static void Trio_WaitBlit(void) {
640 u_short status;
644 status = mem_in16(s3trio_base + 0x1000000 + 0x9AE8);
645 } while (status & 0x200);
649 static void Trio_BitBLT(u_short curx, u_short cury, u_short destx,
650 u_short desty, u_short width, u_short height,
651 u_short mode) {
653 u_short blitcmd = 0xc011;
655 /* Set drawing direction */
656 /* -Y, X maj, -X (default) */
658 if (curx > destx)
659 blitcmd |= 0x0020; /* Drawing direction +X */
660 else {
661 curx += (width - 1);
662 destx += (width - 1);
665 if (cury > desty)
666 blitcmd |= 0x0080; /* Drawing direction +Y */
667 else {
668 cury += (height - 1);
669 desty += (height - 1);
672 Trio_WaitQueue(0x0400);
674 outw(0xa000, 0xBEE8);
675 outw(0x60 | mode, 0xBAE8);
677 outw(curx, 0x86E8);
678 outw(cury, 0x82E8);
680 outw(destx, 0x8EE8);
681 outw(desty, 0x8AE8);
683 outw(height - 1, 0xBEE8);
684 outw(width - 1, 0x96E8);
686 outw(blitcmd, 0x9AE8);
690 static void Trio_RectFill(u_short x, u_short y, u_short width, u_short height,
691 u_short mode, u_short color) {
693 u_short blitcmd = 0x40b1;
695 Trio_WaitQueue(0x0400);
697 outw(0xa000, 0xBEE8);
698 outw((0x20 | mode), 0xBAE8);
699 outw(0xe000, 0xBEE8);
700 outw(color, 0xA6E8);
701 outw(x, 0x86E8);
702 outw(y, 0x82E8);
703 outw((height - 1), 0xBEE8);
704 outw((width - 1), 0x96E8);
705 outw(blitcmd, 0x9AE8);
710 static void Trio_MoveCursor(u_short x, u_short y) {
712 mem_out8(0x39, s3trio_base + 0x1008000 + 0x3d4);
713 mem_out8(0xa0, s3trio_base + 0x1008000 + 0x3d5);
715 mem_out8(0x46, s3trio_base + 0x1008000 + 0x3d4);
716 mem_out8((x & 0x0700) >> 8, s3trio_base + 0x1008000 + 0x3d5);
717 mem_out8(0x47, s3trio_base + 0x1008000 + 0x3d4);
718 mem_out8(x & 0x00ff, s3trio_base + 0x1008000 + 0x3d5);
720 mem_out8(0x48, s3trio_base + 0x1008000 + 0x3d4);
721 mem_out8((y & 0x0700) >> 8, s3trio_base + 0x1008000 + 0x3d5);
722 mem_out8(0x49, s3trio_base + 0x1008000 + 0x3d4);
723 mem_out8(y & 0x00ff, s3trio_base + 0x1008000 + 0x3d5);
729 * Text console acceleration
732 #ifdef FBCON_HAS_CFB8
733 static void fbcon_trio8_bmove(struct display *p, int sy, int sx, int dy,
734 int dx, int height, int width)
736 sx *= 8; dx *= 8; width *= 8;
737 Trio_BitBLT((u_short)sx, (u_short)(sy*fontheight(p)), (u_short)dx,
738 (u_short)(dy*fontheight(p)), (u_short)width,
739 (u_short)(height*fontheight(p)), (u_short)S3_NEW);
742 static void fbcon_trio8_clear(struct vc_data *conp, struct display *p, int sy,
743 int sx, int height, int width)
745 unsigned char bg;
747 sx *= 8; width *= 8;
748 bg = attr_bgcol_ec(p,conp);
749 Trio_RectFill((u_short)sx,
750 (u_short)(sy*fontheight(p)),
751 (u_short)width,
752 (u_short)(height*fontheight(p)),
753 (u_short)S3_NEW,
754 (u_short)bg);
757 static void fbcon_trio8_putc(struct vc_data *conp, struct display *p, int c,
758 int yy, int xx)
760 Trio_WaitBlit();
761 fbcon_cfb8_putc(conp, p, c, yy, xx);
764 static void fbcon_trio8_putcs(struct vc_data *conp, struct display *p,
765 const unsigned short *s, int count, int yy, int xx)
767 Trio_WaitBlit();
768 fbcon_cfb8_putcs(conp, p, s, count, yy, xx);
771 static void fbcon_trio8_revc(struct display *p, int xx, int yy)
773 Trio_WaitBlit();
774 fbcon_cfb8_revc(p, xx, yy);
777 static struct display_switch fbcon_trio8 = {
778 .setup = fbcon_cfb8_setup,
779 .bmove = fbcon_trio8_bmove,
780 .clear = fbcon_trio8_clear,
781 .putc = fbcon_trio8_putc,
782 .putcs = fbcon_trio8_putcs,
783 .revc = fbcon_trio8_revc,
784 .clear_margins = fbcon_cfb8_clear_margins,
785 .fontwidthmask = FONTWIDTH(8)
787 #endif
789 MODULE_LICENSE("GPL");