blob: b3717c8f1bc2b474585b4c8afff35c6b7a2f1f2c [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * linux/drivers/video/S3Triofb.c -- Open Firmware based frame buffer device
3 *
4 * Copyright (C) 1997 Peter De Schrijver
5 *
6 * This driver is partly based on the PowerMac console driver:
7 *
8 * Copyright (C) 1996 Paul Mackerras
9 *
10 * and on the Open Firmware based frame buffer device:
11 *
12 * Copyright (C) 1997 Geert Uytterhoeven
13 *
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.
17 */
18
19/*
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.
23
24*/
25
Linus Torvalds1da177e2005-04-16 15:20:36 -070026#include <linux/kernel.h>
27#include <linux/module.h>
28#include <linux/errno.h>
29#include <linux/string.h>
30#include <linux/mm.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070031#include <linux/slab.h>
32#include <linux/vmalloc.h>
33#include <linux/delay.h>
34#include <linux/interrupt.h>
35#include <linux/fb.h>
36#include <linux/init.h>
37#include <linux/selection.h>
38#include <asm/io.h>
39#include <asm/prom.h>
40#include <asm/pci-bridge.h>
41#include <linux/pci.h>
42
43#include <video/fbcon.h>
44#include <video/fbcon-cfb8.h>
45#include <video/s3blit.h>
46
47
48#define mem_in8(addr) in_8((void *)(addr))
49#define mem_in16(addr) in_le16((void *)(addr))
50#define mem_in32(addr) in_le32((void *)(addr))
51
52#define mem_out8(val, addr) out_8((void *)(addr), val)
53#define mem_out16(val, addr) out_le16((void *)(addr), val)
54#define mem_out32(val, addr) out_le32((void *)(addr), val)
55
56#define IO_OUT16VAL(v, r) (((v) << 8) | (r))
57
58static struct display disp;
59static struct fb_info fb_info;
60static struct { u_char red, green, blue, pad; } palette[256];
61static char s3trio_name[16] = "S3Trio ";
62static char *s3trio_base;
63
64static struct fb_fix_screeninfo fb_fix;
65static struct fb_var_screeninfo fb_var = { 0, };
66
67
68 /*
69 * Interface used by the world
70 */
71
72static void __init s3triofb_of_init(struct device_node *dp);
73static int s3trio_get_fix(struct fb_fix_screeninfo *fix, int con,
74 struct fb_info *info);
75static int s3trio_get_var(struct fb_var_screeninfo *var, int con,
76 struct fb_info *info);
77static int s3trio_set_var(struct fb_var_screeninfo *var, int con,
78 struct fb_info *info);
79static int s3trio_get_cmap(struct fb_cmap *cmap, int kspc, int con,
80 struct fb_info *info);
81static int s3trio_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
82 u_int transp, struct fb_info *info);
83static int s3trio_pan_display(struct fb_var_screeninfo *var, int con,
84 struct fb_info *info);
85static void s3triofb_blank(int blank, struct fb_info *info);
86
87 /*
88 * Interface to the low level console driver
89 */
90
91int s3triofb_init(void);
92static int s3triofbcon_switch(int con, struct fb_info *info);
93static int s3triofbcon_updatevar(int con, struct fb_info *info);
94
95 /*
96 * Text console acceleration
97 */
98
99#ifdef FBCON_HAS_CFB8
100static struct display_switch fbcon_trio8;
101#endif
102
103 /*
104 * Accelerated Functions used by the low level console driver
105 */
106
107static void Trio_WaitQueue(u_short fifo);
108static void Trio_WaitBlit(void);
109static void Trio_BitBLT(u_short curx, u_short cury, u_short destx,
110 u_short desty, u_short width, u_short height,
111 u_short mode);
112static void Trio_RectFill(u_short x, u_short y, u_short width, u_short height,
113 u_short mode, u_short color);
114static void Trio_MoveCursor(u_short x, u_short y);
115
116
117 /*
118 * Internal routines
119 */
120
121static int s3trio_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue,
122 u_int *transp, struct fb_info *info);
123
124static struct fb_ops s3trio_ops = {
125 .owner = THIS_MODULE,
126 .fb_get_fix = s3trio_get_fix,
127 .fb_get_var = s3trio_get_var,
128 .fb_set_var = s3trio_set_var,
129 .fb_get_cmap = s3trio_get_cmap,
130 .fb_set_cmap = gen_set_cmap,
131 .fb_setcolreg = s3trio_setcolreg,
132 .fb_pan_display =s3trio_pan_display,
133 .fb_blank = s3triofb_blank,
134};
135
136 /*
137 * Get the Fixed Part of the Display
138 */
139
140static int s3trio_get_fix(struct fb_fix_screeninfo *fix, int con,
141 struct fb_info *info)
142{
143 memcpy(fix, &fb_fix, sizeof(fb_fix));
144 return 0;
145}
146
147
148 /*
149 * Get the User Defined Part of the Display
150 */
151
152static int s3trio_get_var(struct fb_var_screeninfo *var, int con,
153 struct fb_info *info)
154{
155 memcpy(var, &fb_var, sizeof(fb_var));
156 return 0;
157}
158
159
160 /*
161 * Set the User Defined Part of the Display
162 */
163
164static int s3trio_set_var(struct fb_var_screeninfo *var, int con,
165 struct fb_info *info)
166{
167 if (var->xres > fb_var.xres || var->yres > fb_var.yres ||
168 var->bits_per_pixel > fb_var.bits_per_pixel )
169 /* || var->nonstd || var->vmode != FB_VMODE_NONINTERLACED) */
170 return -EINVAL;
171 if (var->xres_virtual > fb_var.xres_virtual) {
172 outw(IO_OUT16VAL((var->xres_virtual /8) & 0xff, 0x13), 0x3d4);
173 outw(IO_OUT16VAL(((var->xres_virtual /8 ) & 0x300) >> 3, 0x51), 0x3d4);
174 fb_var.xres_virtual = var->xres_virtual;
175 fb_fix.line_length = var->xres_virtual;
176 }
177 fb_var.yres_virtual = var->yres_virtual;
178 memcpy(var, &fb_var, sizeof(fb_var));
179 return 0;
180}
181
182
183 /*
184 * Pan or Wrap the Display
185 *
186 * This call looks only at xoffset, yoffset and the FB_VMODE_YWRAP flag
187 */
188
189static int s3trio_pan_display(struct fb_var_screeninfo *var, int con,
190 struct fb_info *info)
191{
192 unsigned int base;
193
194 if (var->xoffset > (var->xres_virtual - var->xres))
195 return -EINVAL;
196 if (var->yoffset > (var->yres_virtual - var->yres))
197 return -EINVAL;
198
199 fb_var.xoffset = var->xoffset;
200 fb_var.yoffset = var->yoffset;
201
202 base = var->yoffset * fb_fix.line_length + var->xoffset;
203
204 outw(IO_OUT16VAL((base >> 8) & 0xff, 0x0c),0x03D4);
205 outw(IO_OUT16VAL(base & 0xff, 0x0d),0x03D4);
206 outw(IO_OUT16VAL((base >> 16) & 0xf, 0x69),0x03D4);
207 return 0;
208}
209
210
211 /*
212 * Get the Colormap
213 */
214
215static int s3trio_get_cmap(struct fb_cmap *cmap, int kspc, int con,
216 struct fb_info *info)
217{
218 if (con == info->currcon) /* current console? */
219 return fb_get_cmap(cmap, kspc, s3trio_getcolreg, info);
220 else if (fb_display[con].cmap.len) /* non default colormap? */
221 fb_copy_cmap(&fb_display[con].cmap, cmap, kspc ? 0 : 2);
222 else
223 fb_copy_cmap(fb_default_cmap(1 << fb_display[con].var.bits_per_pixel),
224 cmap, kspc ? 0 : 2);
225 return 0;
226}
227
228int __init s3triofb_init(void)
229{
230 struct device_node *dp;
231
232 dp = find_devices("S3Trio");
233 if (dp != 0)
234 s3triofb_of_init(dp);
235 return 0;
236}
237
238void __init s3trio_resetaccel(void){
239
240
241#define EC01_ENH_ENB 0x0005
242#define EC01_LAW_ENB 0x0010
243#define EC01_MMIO_ENB 0x0020
244
245#define EC00_RESET 0x8000
246#define EC00_ENABLE 0x4000
247#define MF_MULT_MISC 0xE000
248#define SRC_FOREGROUND 0x0020
249#define SRC_BACKGROUND 0x0000
250#define MIX_SRC 0x0007
251#define MF_T_CLIP 0x1000
252#define MF_L_CLIP 0x2000
253#define MF_B_CLIP 0x3000
254#define MF_R_CLIP 0x4000
255#define MF_PIX_CONTROL 0xA000
256#define MFA_SRC_FOREGR_MIX 0x0000
257#define MF_PIX_CONTROL 0xA000
258
259 outw(EC00_RESET, 0x42e8);
260 inw( 0x42e8);
261 outw(EC00_ENABLE, 0x42e8);
262 inw( 0x42e8);
263 outw(EC01_ENH_ENB | EC01_LAW_ENB,
264 0x4ae8);
265 outw(MF_MULT_MISC, 0xbee8); /* 16 bit I/O registers */
266
267 /* Now set some basic accelerator registers */
268 Trio_WaitQueue(0x0400);
269 outw(SRC_FOREGROUND | MIX_SRC, 0xbae8);
270 outw(SRC_BACKGROUND | MIX_SRC, 0xb6e8);/* direct color*/
271 outw(MF_T_CLIP | 0, 0xbee8 ); /* clip virtual area */
272 outw(MF_L_CLIP | 0, 0xbee8 );
273 outw(MF_R_CLIP | (640 - 1), 0xbee8);
274 outw(MF_B_CLIP | (480 - 1), 0xbee8);
275 Trio_WaitQueue(0x0400);
276 outw(0xffff, 0xaae8); /* Enable all planes */
277 outw(0xffff, 0xaae8); /* Enable all planes */
278 outw( MF_PIX_CONTROL | MFA_SRC_FOREGR_MIX, 0xbee8);
279}
280
281int __init s3trio_init(struct device_node *dp){
282
283 u_char bus, dev;
284 unsigned int t32;
285 unsigned short cmd;
286
287 pci_device_loc(dp,&bus,&dev);
288 pcibios_read_config_dword(bus, dev, PCI_VENDOR_ID, &t32);
289 if(t32 == (PCI_DEVICE_ID_S3_TRIO << 16) + PCI_VENDOR_ID_S3) {
290 pcibios_read_config_dword(bus, dev, PCI_BASE_ADDRESS_0, &t32);
291 pcibios_read_config_dword(bus, dev, PCI_BASE_ADDRESS_1, &t32);
292 pcibios_read_config_word(bus, dev, PCI_COMMAND,&cmd);
293
294 pcibios_write_config_word(bus, dev, PCI_COMMAND, PCI_COMMAND_IO | PCI_COMMAND_MEMORY);
295
296 pcibios_write_config_dword(bus, dev, PCI_BASE_ADDRESS_0,0xffffffff);
297 pcibios_read_config_dword(bus, dev, PCI_BASE_ADDRESS_0, &t32);
298
299/* This is a gross hack as OF only maps enough memory for the framebuffer and
300 we want to use MMIO too. We should find out which chunk of address space
301 we can use here */
302 pcibios_write_config_dword(bus,dev,PCI_BASE_ADDRESS_0,0xc6000000);
303
304 /* unlock s3 */
305
306 outb(0x01, 0x3C3);
307
308 outb(inb(0x03CC) | 1, 0x3c2);
309
310 outw(IO_OUT16VAL(0x48, 0x38),0x03D4);
311 outw(IO_OUT16VAL(0xA0, 0x39),0x03D4);
312 outb(0x33,0x3d4);
313 outw(IO_OUT16VAL((inb(0x3d5) & ~(0x2 | 0x10 | 0x40)) |
314 0x20, 0x33), 0x3d4);
315
316 outw(IO_OUT16VAL(0x6, 0x8), 0x3c4);
317
318 /* switch to MMIO only mode */
319
320 outb(0x58, 0x3d4);
321 outw(IO_OUT16VAL(inb(0x3d5) | 3 | 0x10, 0x58), 0x3d4);
322 outw(IO_OUT16VAL(8, 0x53), 0x3d4);
323
324 /* switch off I/O accesses */
325
326#if 0
327 pcibios_write_config_word(bus, dev, PCI_COMMAND,
328 PCI_COMMAND_IO | PCI_COMMAND_MEMORY);
329#endif
330 return 1;
331 }
332
333 return 0;
334}
335
336
337 /*
338 * Initialisation
339 * We heavily rely on OF for the moment. This needs fixing.
340 */
341
342static void __init s3triofb_of_init(struct device_node *dp)
343{
344 int i, *pp, len;
345 unsigned long address, size;
346 u_long *CursorBase;
347
348 strncat(s3trio_name, dp->name, sizeof(s3trio_name));
349 s3trio_name[sizeof(s3trio_name)-1] = '\0';
350 strcpy(fb_fix.id, s3trio_name);
351
Jeremy Kerrb04e3dd2006-07-12 15:40:40 +1000352 if((pp = get_property(dp, "vendor-id", &len)) != NULL
Linus Torvalds1da177e2005-04-16 15:20:36 -0700353 && *pp!=PCI_VENDOR_ID_S3) {
354 printk("%s: can't find S3 Trio board\n", dp->full_name);
355 return;
356 }
357
Jeremy Kerrb04e3dd2006-07-12 15:40:40 +1000358 if((pp = get_property(dp, "device-id", &len)) != NULL
Linus Torvalds1da177e2005-04-16 15:20:36 -0700359 && *pp!=PCI_DEVICE_ID_S3_TRIO) {
360 printk("%s: can't find S3 Trio board\n", dp->full_name);
361 return;
362 }
363
Jeremy Kerrb04e3dd2006-07-12 15:40:40 +1000364 if ((pp = get_property(dp, "depth", &len)) != NULL
Linus Torvalds1da177e2005-04-16 15:20:36 -0700365 && len == sizeof(int) && *pp != 8) {
366 printk("%s: can't use depth = %d\n", dp->full_name, *pp);
367 return;
368 }
Jeremy Kerrb04e3dd2006-07-12 15:40:40 +1000369 if ((pp = get_property(dp, "width", &len)) != NULL
Linus Torvalds1da177e2005-04-16 15:20:36 -0700370 && len == sizeof(int))
371 fb_var.xres = fb_var.xres_virtual = *pp;
Jeremy Kerrb04e3dd2006-07-12 15:40:40 +1000372 if ((pp = get_property(dp, "height", &len)) != NULL
Linus Torvalds1da177e2005-04-16 15:20:36 -0700373 && len == sizeof(int))
374 fb_var.yres = fb_var.yres_virtual = *pp;
Jeremy Kerrb04e3dd2006-07-12 15:40:40 +1000375 if ((pp = get_property(dp, "linebytes", &len)) != NULL
Linus Torvalds1da177e2005-04-16 15:20:36 -0700376 && len == sizeof(int))
377 fb_fix.line_length = *pp;
378 else
379 fb_fix.line_length = fb_var.xres_virtual;
380 fb_fix.smem_len = fb_fix.line_length*fb_var.yres;
381
382 address = 0xc6000000;
383 size = 64*1024*1024;
384 if (!request_mem_region(address, size, "S3triofb"))
385 return;
386
387 s3trio_init(dp);
388 s3trio_base = ioremap(address, size);
389 fb_fix.smem_start = address;
390 fb_fix.type = FB_TYPE_PACKED_PIXELS;
391 fb_fix.type_aux = 0;
392 fb_fix.accel = FB_ACCEL_S3_TRIO64;
393 fb_fix.mmio_start = address+0x1000000;
394 fb_fix.mmio_len = 0x1000000;
395
396 fb_fix.xpanstep = 1;
397 fb_fix.ypanstep = 1;
398
399 s3trio_resetaccel();
400
401 mem_out8(0x30, s3trio_base+0x1008000 + 0x03D4);
402 mem_out8(0x2d, s3trio_base+0x1008000 + 0x03D4);
403 mem_out8(0x2e, s3trio_base+0x1008000 + 0x03D4);
404
405 mem_out8(0x50, s3trio_base+0x1008000 + 0x03D4);
406
407 /* disable HW cursor */
408
409 mem_out8(0x39, s3trio_base+0x1008000 + 0x03D4);
410 mem_out8(0xa0, s3trio_base+0x1008000 + 0x03D5);
411
412 mem_out8(0x45, s3trio_base+0x1008000 + 0x03D4);
413 mem_out8(0, s3trio_base+0x1008000 + 0x03D5);
414
415 mem_out8(0x4e, s3trio_base+0x1008000 + 0x03D4);
416 mem_out8(0, s3trio_base+0x1008000 + 0x03D5);
417
418 mem_out8(0x4f, s3trio_base+0x1008000 + 0x03D4);
419 mem_out8(0, s3trio_base+0x1008000 + 0x03D5);
420
421 /* init HW cursor */
422
423 CursorBase = (u_long *)(s3trio_base + 2*1024*1024 - 0x400);
424 for (i = 0; i < 8; i++) {
425 *(CursorBase +(i*4)) = 0xffffff00;
426 *(CursorBase+1+(i*4)) = 0xffff0000;
427 *(CursorBase+2+(i*4)) = 0xffff0000;
428 *(CursorBase+3+(i*4)) = 0xffff0000;
429 }
430 for (i = 8; i < 64; i++) {
431 *(CursorBase +(i*4)) = 0xffff0000;
432 *(CursorBase+1+(i*4)) = 0xffff0000;
433 *(CursorBase+2+(i*4)) = 0xffff0000;
434 *(CursorBase+3+(i*4)) = 0xffff0000;
435 }
436
437
438 mem_out8(0x4c, s3trio_base+0x1008000 + 0x03D4);
439 mem_out8(((2*1024 - 1)&0xf00)>>8, s3trio_base+0x1008000 + 0x03D5);
440
441 mem_out8(0x4d, s3trio_base+0x1008000 + 0x03D4);
442 mem_out8((2*1024 - 1) & 0xff, s3trio_base+0x1008000 + 0x03D5);
443
444 mem_out8(0x45, s3trio_base+0x1008000 + 0x03D4);
445 mem_in8(s3trio_base+0x1008000 + 0x03D4);
446
447 mem_out8(0x4a, s3trio_base+0x1008000 + 0x03D4);
448 mem_out8(0x80, s3trio_base+0x1008000 + 0x03D5);
449 mem_out8(0x80, s3trio_base+0x1008000 + 0x03D5);
450 mem_out8(0x80, s3trio_base+0x1008000 + 0x03D5);
451
452 mem_out8(0x4b, s3trio_base+0x1008000 + 0x03D4);
453 mem_out8(0x00, s3trio_base+0x1008000 + 0x03D5);
454 mem_out8(0x00, s3trio_base+0x1008000 + 0x03D5);
455 mem_out8(0x00, s3trio_base+0x1008000 + 0x03D5);
456
457 mem_out8(0x45, s3trio_base+0x1008000 + 0x03D4);
458 mem_out8(0, s3trio_base+0x1008000 + 0x03D5);
459
460 /* setup default color table */
461
462 for(i = 0; i < 16; i++) {
463 int j = color_table[i];
464 palette[i].red=default_red[j];
465 palette[i].green=default_grn[j];
466 palette[i].blue=default_blu[j];
467 }
468
469 s3trio_setcolreg(255, 56, 100, 160, 0, NULL /* not used */);
470 s3trio_setcolreg(254, 0, 0, 0, 0, NULL /* not used */);
471 memset((char *)s3trio_base, 0, 640*480);
472
473#if 0
474 Trio_RectFill(0, 0, 90, 90, 7, 1);
475#endif
476
477 fb_fix.visual = FB_VISUAL_PSEUDOCOLOR ;
478 fb_var.xoffset = fb_var.yoffset = 0;
479 fb_var.bits_per_pixel = 8;
480 fb_var.grayscale = 0;
481 fb_var.red.offset = fb_var.green.offset = fb_var.blue.offset = 0;
482 fb_var.red.length = fb_var.green.length = fb_var.blue.length = 8;
483 fb_var.red.msb_right = fb_var.green.msb_right = fb_var.blue.msb_right = 0;
484 fb_var.transp.offset = fb_var.transp.length = fb_var.transp.msb_right = 0;
485 fb_var.nonstd = 0;
486 fb_var.activate = 0;
487 fb_var.height = fb_var.width = -1;
488 fb_var.accel_flags = FB_ACCELF_TEXT;
489#warning FIXME: always obey fb_var.accel_flags
490 fb_var.pixclock = 1;
491 fb_var.left_margin = fb_var.right_margin = 0;
492 fb_var.upper_margin = fb_var.lower_margin = 0;
493 fb_var.hsync_len = fb_var.vsync_len = 0;
494 fb_var.sync = 0;
495 fb_var.vmode = FB_VMODE_NONINTERLACED;
496
497 disp.var = fb_var;
498 disp.cmap.start = 0;
499 disp.cmap.len = 0;
500 disp.cmap.red = disp.cmap.green = disp.cmap.blue = disp.cmap.transp = NULL;
501 disp.visual = fb_fix.visual;
502 disp.type = fb_fix.type;
503 disp.type_aux = fb_fix.type_aux;
504 disp.ypanstep = 0;
505 disp.ywrapstep = 0;
506 disp.line_length = fb_fix.line_length;
507 disp.can_soft_blank = 1;
508 disp.inverse = 0;
509#ifdef FBCON_HAS_CFB8
510 if (fb_var.accel_flags & FB_ACCELF_TEXT)
511 disp.dispsw = &fbcon_trio8;
512 else
513 disp.dispsw = &fbcon_cfb8;
514#else
515 disp.dispsw = &fbcon_dummy;
516#endif
517 disp.scrollmode = fb_var.accel_flags & FB_ACCELF_TEXT ? 0 : SCROLL_YREDRAW;
518
519 strcpy(fb_info.modename, "Trio64 ");
520 strncat(fb_info.modename, dp->full_name, sizeof(fb_info.modename));
521 fb_info.currcon = -1;
522 fb_info.fbops = &s3trio_ops;
523 fb_info.screen_base = s3trio_base;
524#if 0
525 fb_info.fbvar_num = 1;
526 fb_info.fbvar = &fb_var;
527#endif
528 fb_info.disp = &disp;
529 fb_info.fontname[0] = '\0';
530 fb_info.changevar = NULL;
531 fb_info.switch_con = &s3triofbcon_switch;
532 fb_info.updatevar = &s3triofbcon_updatevar;
533#if 0
534 fb_info.setcmap = &s3triofbcon_setcmap;
535#endif
536
537 fb_info.flags = FBINFO_FLAG_DEFAULT;
Amol Lad945f0ee2006-12-08 02:40:16 -0800538 if (register_framebuffer(&fb_info) < 0) {
539 iounmap(fb_info.screen_base);
540 fb_info.screen_base = NULL;
541 return;
542 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700543
544 printk("fb%d: S3 Trio frame buffer device on %s\n",
545 fb_info.node, dp->full_name);
546}
547
548
549static int s3triofbcon_switch(int con, struct fb_info *info)
550{
551 /* Do we have to save the colormap? */
552 if (fb_display[info->currcon].cmap.len)
553 fb_get_cmap(&fb_display[info->currcon].cmap, 1, s3trio_getcolreg, info);
554
555 info->currcon = con;
556 /* Install new colormap */
557 do_install_cmap(con,info);
558 return 0;
559}
560
561 /*
562 * Update the `var' structure (called by fbcon.c)
563 */
564
565static int s3triofbcon_updatevar(int con, struct fb_info *info)
566{
567 /* Nothing */
568 return 0;
569}
570
571 /*
572 * Blank the display.
573 */
574
575static int s3triofb_blank(int blank, struct fb_info *info)
576{
577 unsigned char x;
578
579 mem_out8(0x1, s3trio_base+0x1008000 + 0x03c4);
580 x = mem_in8(s3trio_base+0x1008000 + 0x03c5);
581 mem_out8((x & (~0x20)) | (blank << 5), s3trio_base+0x1008000 + 0x03c5);
582 return 0;
583}
584
585 /*
586 * Read a single color register and split it into
587 * colors/transparent. Return != 0 for invalid regno.
588 */
589
590static int s3trio_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue,
591 u_int *transp, struct fb_info *info)
592{
593 if (regno > 255)
594 return 1;
595 *red = (palette[regno].red << 8) | palette[regno].red;
596 *green = (palette[regno].green << 8) | palette[regno].green;
597 *blue = (palette[regno].blue << 8) | palette[regno].blue;
598 *transp = 0;
599 return 0;
600}
601
602
603 /*
604 * Set a single color register. Return != 0 for invalid regno.
605 */
606
607static int s3trio_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
608 u_int transp, struct fb_info *info)
609{
610 if (regno > 255)
611 return 1;
612
613 red >>= 8;
614 green >>= 8;
615 blue >>= 8;
616 palette[regno].red = red;
617 palette[regno].green = green;
618 palette[regno].blue = blue;
619
620 mem_out8(regno,s3trio_base+0x1008000 + 0x3c8);
621 mem_out8((red & 0xff) >> 2,s3trio_base+0x1008000 + 0x3c9);
622 mem_out8((green & 0xff) >> 2,s3trio_base+0x1008000 + 0x3c9);
623 mem_out8((blue & 0xff) >> 2,s3trio_base+0x1008000 + 0x3c9);
624
625 return 0;
626}
627
628static void Trio_WaitQueue(u_short fifo) {
629
630 u_short status;
631
632 do
633 {
634 status = mem_in16(s3trio_base + 0x1000000 + 0x9AE8);
635 } while (!(status & fifo));
636
637}
638
639static void Trio_WaitBlit(void) {
640
641 u_short status;
642
643 do
644 {
645 status = mem_in16(s3trio_base + 0x1000000 + 0x9AE8);
646 } while (status & 0x200);
647
648}
649
650static void Trio_BitBLT(u_short curx, u_short cury, u_short destx,
651 u_short desty, u_short width, u_short height,
652 u_short mode) {
653
654 u_short blitcmd = 0xc011;
655
656 /* Set drawing direction */
657 /* -Y, X maj, -X (default) */
658
659 if (curx > destx)
660 blitcmd |= 0x0020; /* Drawing direction +X */
661 else {
662 curx += (width - 1);
663 destx += (width - 1);
664 }
665
666 if (cury > desty)
667 blitcmd |= 0x0080; /* Drawing direction +Y */
668 else {
669 cury += (height - 1);
670 desty += (height - 1);
671 }
672
673 Trio_WaitQueue(0x0400);
674
675 outw(0xa000, 0xBEE8);
676 outw(0x60 | mode, 0xBAE8);
677
678 outw(curx, 0x86E8);
679 outw(cury, 0x82E8);
680
681 outw(destx, 0x8EE8);
682 outw(desty, 0x8AE8);
683
684 outw(height - 1, 0xBEE8);
685 outw(width - 1, 0x96E8);
686
687 outw(blitcmd, 0x9AE8);
688
689}
690
691static void Trio_RectFill(u_short x, u_short y, u_short width, u_short height,
692 u_short mode, u_short color) {
693
694 u_short blitcmd = 0x40b1;
695
696 Trio_WaitQueue(0x0400);
697
698 outw(0xa000, 0xBEE8);
699 outw((0x20 | mode), 0xBAE8);
700 outw(0xe000, 0xBEE8);
701 outw(color, 0xA6E8);
702 outw(x, 0x86E8);
703 outw(y, 0x82E8);
704 outw((height - 1), 0xBEE8);
705 outw((width - 1), 0x96E8);
706 outw(blitcmd, 0x9AE8);
707
708}
709
710
711static void Trio_MoveCursor(u_short x, u_short y) {
712
713 mem_out8(0x39, s3trio_base + 0x1008000 + 0x3d4);
714 mem_out8(0xa0, s3trio_base + 0x1008000 + 0x3d5);
715
716 mem_out8(0x46, s3trio_base + 0x1008000 + 0x3d4);
717 mem_out8((x & 0x0700) >> 8, s3trio_base + 0x1008000 + 0x3d5);
718 mem_out8(0x47, s3trio_base + 0x1008000 + 0x3d4);
719 mem_out8(x & 0x00ff, s3trio_base + 0x1008000 + 0x3d5);
720
721 mem_out8(0x48, s3trio_base + 0x1008000 + 0x3d4);
722 mem_out8((y & 0x0700) >> 8, s3trio_base + 0x1008000 + 0x3d5);
723 mem_out8(0x49, s3trio_base + 0x1008000 + 0x3d4);
724 mem_out8(y & 0x00ff, s3trio_base + 0x1008000 + 0x3d5);
725
726}
727
728
729 /*
730 * Text console acceleration
731 */
732
733#ifdef FBCON_HAS_CFB8
734static void fbcon_trio8_bmove(struct display *p, int sy, int sx, int dy,
735 int dx, int height, int width)
736{
737 sx *= 8; dx *= 8; width *= 8;
738 Trio_BitBLT((u_short)sx, (u_short)(sy*fontheight(p)), (u_short)dx,
739 (u_short)(dy*fontheight(p)), (u_short)width,
740 (u_short)(height*fontheight(p)), (u_short)S3_NEW);
741}
742
743static void fbcon_trio8_clear(struct vc_data *conp, struct display *p, int sy,
744 int sx, int height, int width)
745{
746 unsigned char bg;
747
748 sx *= 8; width *= 8;
749 bg = attr_bgcol_ec(p,conp);
750 Trio_RectFill((u_short)sx,
751 (u_short)(sy*fontheight(p)),
752 (u_short)width,
753 (u_short)(height*fontheight(p)),
754 (u_short)S3_NEW,
755 (u_short)bg);
756}
757
758static void fbcon_trio8_putc(struct vc_data *conp, struct display *p, int c,
759 int yy, int xx)
760{
761 Trio_WaitBlit();
762 fbcon_cfb8_putc(conp, p, c, yy, xx);
763}
764
765static void fbcon_trio8_putcs(struct vc_data *conp, struct display *p,
766 const unsigned short *s, int count, int yy, int xx)
767{
768 Trio_WaitBlit();
769 fbcon_cfb8_putcs(conp, p, s, count, yy, xx);
770}
771
772static void fbcon_trio8_revc(struct display *p, int xx, int yy)
773{
774 Trio_WaitBlit();
775 fbcon_cfb8_revc(p, xx, yy);
776}
777
778static struct display_switch fbcon_trio8 = {
779 .setup = fbcon_cfb8_setup,
780 .bmove = fbcon_trio8_bmove,
781 .clear = fbcon_trio8_clear,
782 .putc = fbcon_trio8_putc,
783 .putcs = fbcon_trio8_putcs,
784 .revc = fbcon_trio8_revc,
785 .clear_margins = fbcon_cfb8_clear_margins,
786 .fontwidthmask = FONTWIDTH(8)
787};
788#endif
789
790MODULE_LICENSE("GPL");