1 /*
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
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
47
48 #include <video/fbcon.h>
49 #include <video/fbcon-cfb8.h>
50 #include <video/s3blit.h>
51
52
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))
56
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)
60
61 #define IO_OUT16VAL(v, r) (((v) << 8) | (r))
62
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;
69
70 static struct fb_fix_screeninfo fb_fix;
71 static struct fb_var_screeninfo fb_var = { 0, };
72
73
74 /*
75 * Interface used by the world
76 */
77
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);
91
92
93 /*
94 * Interface to the low level console driver
95 */
96
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
104
105 /*
106 * Text console acceleration
107 */
108
109 #ifdef FBCON_HAS_CFB8
110 static struct display_switch fbcon_trio8;
111 #endif
112
113 /*
114 * Accelerated Functions used by the low level console driver
115 */
116
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);
125
126
127 /*
128 * Internal routines
129 */
130
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);
136
137
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,
146 };
147
148 /*
149 * Get the Fixed Part of the Display
150 */
151
152 static int s3trio_get_fix(struct fb_fix_screeninfo *fix, int con,
153 struct fb_info *info)
154 {
155 memcpy(fix, &fb_fix, sizeof(fb_fix));
156 return 0;
157 }
158
159
160 /*
161 * Get the User Defined Part of the Display
162 */
163
164 static int s3trio_get_var(struct fb_var_screeninfo *var, int con,
165 struct fb_info *info)
166 {
167 memcpy(var, &fb_var, sizeof(fb_var));
168 return 0;
169 }
170
171
172 /*
173 * Set the User Defined Part of the Display
174 */
175
176 static int s3trio_set_var(struct fb_var_screeninfo *var, int con,
177 struct fb_info *info)
178 {
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;
188 }
189 fb_var.yres_virtual = var->yres_virtual;
190 memcpy(var, &fb_var, sizeof(fb_var));
191 return 0;
192 }
193
194
195 /*
196 * Pan or Wrap the Display
197 *
198 * This call looks only at xoffset, yoffset and the FB_VMODE_YWRAP flag
199 */
200
201 static int s3trio_pan_display(struct fb_var_screeninfo *var, int con,
202 struct fb_info *info)
203 {
204 unsigned int base;
205
206 if (var->xoffset > (var->xres_virtual - var->xres))
207 return -EINVAL;
208 if (var->yoffset > (var->yres_virtual - var->yres))
209 return -EINVAL;
210
211 fb_var.xoffset = var->xoffset;
212 fb_var.yoffset = var->yoffset;
213
214 base = var->yoffset * fb_fix.line_length + var->xoffset;
215
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;
220 }
221
222
223 /*
224 * Get the Colormap
225 */
226
227 static int s3trio_get_cmap(struct fb_cmap *cmap, int kspc, int con,
228 struct fb_info *info)
229 {
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;
238 }
239
240 /*
241 * Set the Colormap
242 */
243
244 static int s3trio_set_cmap(struct fb_cmap *cmap, int kspc, int con,
245 struct fb_info *info)
246 {
247 int err;
248
249
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;
254 }
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;
260 }
261
262
263 int __init s3triofb_init(void)
264 {
265 struct device_node *dp;
266
267 dp = find_devices("S3Trio");
268 if (dp != 0)
269 s3triofb_of_init(dp);
270 return 0;
271 }
272
273 void __init s3trio_resetaccel(void){
274
275
276 #define EC01_ENH_ENB 0x0005
277 #define EC01_LAW_ENB 0x0010
278 #define EC01_MMIO_ENB 0x0020
279
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
293
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 */
301
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);
314 }
315
316 int __init s3trio_init(struct device_node *dp){
317
318 u_char bus, dev;
319 unsigned int t32;
320 unsigned short cmd;
321
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);
328
329 pcibios_write_config_word(bus, dev, PCI_COMMAND, PCI_COMMAND_IO | PCI_COMMAND_MEMORY);
330
331 pcibios_write_config_dword(bus, dev, PCI_BASE_ADDRESS_0,0xffffffff);
332 pcibios_read_config_dword(bus, dev, PCI_BASE_ADDRESS_0, &t32);
333
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);
338
339 /* unlock s3 */
340
341 outb(0x01, 0x3C3);
342
343 outb(inb(0x03CC) | 1, 0x3c2);
344
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);
350
351 outw(IO_OUT16VAL(0x6, 0x8), 0x3c4);
352
353 /* switch to MMIO only mode */
354
355 outb(0x58, 0x3d4);
356 outw(IO_OUT16VAL(inb(0x3d5) | 3 | 0x10, 0x58), 0x3d4);
357 outw(IO_OUT16VAL(8, 0x53), 0x3d4);
358
359 /* switch off I/O accesses */
360
361 #if 0
362 pcibios_write_config_word(bus, dev, PCI_COMMAND,
363 PCI_COMMAND_IO | PCI_COMMAND_MEMORY);
364 #endif
365 return 1;
366 }
367
368 return 0;
369 }
370
371
372 /*
373 * Initialisation
374 * We heavily rely on OF for the moment. This needs fixing.
375 */
376
377 static void __init s3triofb_of_init(struct device_node *dp)
378 {
379 int i, *pp, len;
380 unsigned long address, size;
381 u_long *CursorBase;
382
383 strncat(s3trio_name, dp->name, sizeof(s3trio_name));
384 s3trio_name[sizeof(s3trio_name)-1] = '\0';
385 strcpy(fb_fix.id, s3trio_name);
386
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;
391 }
392
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;
397 }
398
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;
403 }
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;
416
417 address = 0xc6000000;
418 size = 64*1024*1024;
419 if (!request_mem_region(address, size, "S3triofb"))
420 return;
421
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;
430
431 fb_fix.xpanstep = 1;
432 fb_fix.ypanstep = 1;
433
434 s3trio_resetaccel();
435
436 mem_out8(0x30, s3trio_base+0x1008000 + 0x03D4);
437 mem_out8(0x2d, s3trio_base+0x1008000 + 0x03D4);
438 mem_out8(0x2e, s3trio_base+0x1008000 + 0x03D4);
439
440 mem_out8(0x50, s3trio_base+0x1008000 + 0x03D4);
441
442 /* disable HW cursor */
443
444 mem_out8(0x39, s3trio_base+0x1008000 + 0x03D4);
445 mem_out8(0xa0, s3trio_base+0x1008000 + 0x03D5);
446
447 mem_out8(0x45, s3trio_base+0x1008000 + 0x03D4);
448 mem_out8(0, s3trio_base+0x1008000 + 0x03D5);
449
450 mem_out8(0x4e, s3trio_base+0x1008000 + 0x03D4);
451 mem_out8(0, s3trio_base+0x1008000 + 0x03D5);
452
453 mem_out8(0x4f, s3trio_base+0x1008000 + 0x03D4);
454 mem_out8(0, s3trio_base+0x1008000 + 0x03D5);
455
456 /* init HW cursor */
457
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;
464 }
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;
470 }
471
472
473 mem_out8(0x4c, s3trio_base+0x1008000 + 0x03D4);
474 mem_out8(((2*1024 - 1)&0xf00)>>8, s3trio_base+0x1008000 + 0x03D5);
475
476 mem_out8(0x4d, s3trio_base+0x1008000 + 0x03D4);
477 mem_out8((2*1024 - 1) & 0xff, s3trio_base+0x1008000 + 0x03D5);
478
479 mem_out8(0x45, s3trio_base+0x1008000 + 0x03D4);
480 mem_in8(s3trio_base+0x1008000 + 0x03D4);
481
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);
486
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);
491
492 mem_out8(0x45, s3trio_base+0x1008000 + 0x03D4);
493 mem_out8(0, s3trio_base+0x1008000 + 0x03D5);
494
495 /* setup default color table */
496
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];
502 }
503
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);
507
508 #if 0
509 Trio_RectFill(0, 0, 90, 90, 7, 1);
510 #endif
511
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;
531
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;
554
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
572
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;
586 }
587 #endif /* CONFIG_FB_COMPAT_XPMAC) */
588
589 fb_info.flags = FBINFO_FLAG_DEFAULT;
590 if (register_framebuffer(&fb_info) < 0)
591 return;
592
593 printk("fb%d: S3 Trio frame buffer device on %s\n",
594 GET_FB_IDX(fb_info.node), dp->full_name);
595 }
596
597
598 static int s3triofbcon_switch(int con, struct fb_info *info)
599 {
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);
603
604 currcon = con;
605 /* Install new colormap */
606 do_install_cmap(con,info);
607 return 0;
608 }
609
610 /*
611 * Update the `var' structure (called by fbcon.c)
612 */
613
614 static int s3triofbcon_updatevar(int con, struct fb_info *info)
615 {
616 /* Nothing */
617 return 0;
618 }
619
620 /*
621 * Blank the display.
622 */
623
624 static void s3triofbcon_blank(int blank, struct fb_info *info)
625 {
626 unsigned char x;
627
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);
631 }
632
633 /*
634 * Set the colormap
635 */
636
637 #if 0
638 static int s3triofbcon_setcmap(struct fb_cmap *cmap, int con)
639 {
640 return(s3trio_set_cmap(cmap, 1, con, &fb_info));
641 }
642 #endif
643
644
645 /*
646 * Read a single color register and split it into
647 * colors/transparent. Return != 0 for invalid regno.
648 */
649
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)
652 {
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;
660 }
661
662
663 /*
664 * Set a single color register. Return != 0 for invalid regno.
665 */
666
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)
669 {
670 if (regno > 255)
671 return 1;
672
673 red >>= 8;
674 green >>= 8;
675 blue >>= 8;
676 palette[regno].red = red;
677 palette[regno].green = green;
678 palette[regno].blue = blue;
679
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);
684
685 return 0;
686 }
687
688
689 static void do_install_cmap(int con, struct fb_info *info)
690 {
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);
698 }
699
700 static void Trio_WaitQueue(u_short fifo) {
701
702 u_short status;
703
704 do
705 {
706 status = mem_in16(s3trio_base + 0x1000000 + 0x9AE8);
707 } while (!(status & fifo));
708
709 }
710
711 static void Trio_WaitBlit(void) {
712
713 u_short status;
714
715 do
716 {
717 status = mem_in16(s3trio_base + 0x1000000 + 0x9AE8);
718 } while (status & 0x200);
719
720 }
721
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) {
725
726 u_short blitcmd = 0xc011;
727
728 /* Set drawing direction */
729 /* -Y, X maj, -X (default) */
730
731 if (curx > destx)
732 blitcmd |= 0x0020; /* Drawing direction +X */
733 else {
734 curx += (width - 1);
735 destx += (width - 1);
736 }
737
738 if (cury > desty)
739 blitcmd |= 0x0080; /* Drawing direction +Y */
740 else {
741 cury += (height - 1);
742 desty += (height - 1);
743 }
744
745 Trio_WaitQueue(0x0400);
746
747 outw(0xa000, 0xBEE8);
748 outw(0x60 | mode, 0xBAE8);
749
750 outw(curx, 0x86E8);
751 outw(cury, 0x82E8);
752
753 outw(destx, 0x8EE8);
754 outw(desty, 0x8AE8);
755
756 outw(height - 1, 0xBEE8);
757 outw(width - 1, 0x96E8);
758
759 outw(blitcmd, 0x9AE8);
760
761 }
762
763 static void Trio_RectFill(u_short x, u_short y, u_short width, u_short height,
764 u_short mode, u_short color) {
765
766 u_short blitcmd = 0x40b1;
767
768 Trio_WaitQueue(0x0400);
769
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);
779
780 }
781
782
783 static void Trio_MoveCursor(u_short x, u_short y) {
784
785 mem_out8(0x39, s3trio_base + 0x1008000 + 0x3d4);
786 mem_out8(0xa0, s3trio_base + 0x1008000 + 0x3d5);
787
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);
792
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);
797
798 }
799
800
801 /*
802 * Text console acceleration
803 */
804
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)
808 {
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);
813 }
814
815 static void fbcon_trio8_clear(struct vc_data *conp, struct display *p, int sy,
816 int sx, int height, int width)
817 {
818 unsigned char bg;
819
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);
828 }
829
830 static void fbcon_trio8_putc(struct vc_data *conp, struct display *p, int c,
831 int yy, int xx)
832 {
833 Trio_WaitBlit();
834 fbcon_cfb8_putc(conp, p, c, yy, xx);
835 }
836
837 static void fbcon_trio8_putcs(struct vc_data *conp, struct display *p,
838 const unsigned short *s, int count, int yy, int xx)
839 {
840 Trio_WaitBlit();
841 fbcon_cfb8_putcs(conp, p, s, count, yy, xx);
842 }
843
844 static void fbcon_trio8_revc(struct display *p, int xx, int yy)
845 {
846 Trio_WaitBlit();
847 fbcon_cfb8_revc(p, xx, yy);
848 }
849
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)
859 };
860 #endif
861
This page was automatically generated by the
LXR engine.
Visit the LXR main site for more
information.