Linux-2.6.12-rc2
[GitHub/mt8127/android_kernel_alcatel_ttab.git] / drivers / video / S3triofb.c
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/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>
44
45 #include <video/fbcon.h>
46 #include <video/fbcon-cfb8.h>
47 #include <video/s3blit.h>
48
49
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))
53
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)
57
58 #define IO_OUT16VAL(v, r) (((v) << 8) | (r))
59
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;
65
66 static struct fb_fix_screeninfo fb_fix;
67 static struct fb_var_screeninfo fb_var = { 0, };
68
69
70 /*
71 * Interface used by the world
72 */
73
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);
88
89 /*
90 * Interface to the low level console driver
91 */
92
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);
96
97 /*
98 * Text console acceleration
99 */
100
101 #ifdef FBCON_HAS_CFB8
102 static struct display_switch fbcon_trio8;
103 #endif
104
105 /*
106 * Accelerated Functions used by the low level console driver
107 */
108
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);
117
118
119 /*
120 * Internal routines
121 */
122
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);
125
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,
136 };
137
138 /*
139 * Get the Fixed Part of the Display
140 */
141
142 static int s3trio_get_fix(struct fb_fix_screeninfo *fix, int con,
143 struct fb_info *info)
144 {
145 memcpy(fix, &fb_fix, sizeof(fb_fix));
146 return 0;
147 }
148
149
150 /*
151 * Get the User Defined Part of the Display
152 */
153
154 static int s3trio_get_var(struct fb_var_screeninfo *var, int con,
155 struct fb_info *info)
156 {
157 memcpy(var, &fb_var, sizeof(fb_var));
158 return 0;
159 }
160
161
162 /*
163 * Set the User Defined Part of the Display
164 */
165
166 static int s3trio_set_var(struct fb_var_screeninfo *var, int con,
167 struct fb_info *info)
168 {
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;
178 }
179 fb_var.yres_virtual = var->yres_virtual;
180 memcpy(var, &fb_var, sizeof(fb_var));
181 return 0;
182 }
183
184
185 /*
186 * Pan or Wrap the Display
187 *
188 * This call looks only at xoffset, yoffset and the FB_VMODE_YWRAP flag
189 */
190
191 static int s3trio_pan_display(struct fb_var_screeninfo *var, int con,
192 struct fb_info *info)
193 {
194 unsigned int base;
195
196 if (var->xoffset > (var->xres_virtual - var->xres))
197 return -EINVAL;
198 if (var->yoffset > (var->yres_virtual - var->yres))
199 return -EINVAL;
200
201 fb_var.xoffset = var->xoffset;
202 fb_var.yoffset = var->yoffset;
203
204 base = var->yoffset * fb_fix.line_length + var->xoffset;
205
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;
210 }
211
212
213 /*
214 * Get the Colormap
215 */
216
217 static int s3trio_get_cmap(struct fb_cmap *cmap, int kspc, int con,
218 struct fb_info *info)
219 {
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;
228 }
229
230 int __init s3triofb_init(void)
231 {
232 struct device_node *dp;
233
234 dp = find_devices("S3Trio");
235 if (dp != 0)
236 s3triofb_of_init(dp);
237 return 0;
238 }
239
240 void __init s3trio_resetaccel(void){
241
242
243 #define EC01_ENH_ENB 0x0005
244 #define EC01_LAW_ENB 0x0010
245 #define EC01_MMIO_ENB 0x0020
246
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
260
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 */
268
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);
281 }
282
283 int __init s3trio_init(struct device_node *dp){
284
285 u_char bus, dev;
286 unsigned int t32;
287 unsigned short cmd;
288
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);
295
296 pcibios_write_config_word(bus, dev, PCI_COMMAND, PCI_COMMAND_IO | PCI_COMMAND_MEMORY);
297
298 pcibios_write_config_dword(bus, dev, PCI_BASE_ADDRESS_0,0xffffffff);
299 pcibios_read_config_dword(bus, dev, PCI_BASE_ADDRESS_0, &t32);
300
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);
305
306 /* unlock s3 */
307
308 outb(0x01, 0x3C3);
309
310 outb(inb(0x03CC) | 1, 0x3c2);
311
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);
317
318 outw(IO_OUT16VAL(0x6, 0x8), 0x3c4);
319
320 /* switch to MMIO only mode */
321
322 outb(0x58, 0x3d4);
323 outw(IO_OUT16VAL(inb(0x3d5) | 3 | 0x10, 0x58), 0x3d4);
324 outw(IO_OUT16VAL(8, 0x53), 0x3d4);
325
326 /* switch off I/O accesses */
327
328 #if 0
329 pcibios_write_config_word(bus, dev, PCI_COMMAND,
330 PCI_COMMAND_IO | PCI_COMMAND_MEMORY);
331 #endif
332 return 1;
333 }
334
335 return 0;
336 }
337
338
339 /*
340 * Initialisation
341 * We heavily rely on OF for the moment. This needs fixing.
342 */
343
344 static void __init s3triofb_of_init(struct device_node *dp)
345 {
346 int i, *pp, len;
347 unsigned long address, size;
348 u_long *CursorBase;
349
350 strncat(s3trio_name, dp->name, sizeof(s3trio_name));
351 s3trio_name[sizeof(s3trio_name)-1] = '\0';
352 strcpy(fb_fix.id, s3trio_name);
353
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;
358 }
359
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;
364 }
365
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;
370 }
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;
383
384 address = 0xc6000000;
385 size = 64*1024*1024;
386 if (!request_mem_region(address, size, "S3triofb"))
387 return;
388
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;
397
398 fb_fix.xpanstep = 1;
399 fb_fix.ypanstep = 1;
400
401 s3trio_resetaccel();
402
403 mem_out8(0x30, s3trio_base+0x1008000 + 0x03D4);
404 mem_out8(0x2d, s3trio_base+0x1008000 + 0x03D4);
405 mem_out8(0x2e, s3trio_base+0x1008000 + 0x03D4);
406
407 mem_out8(0x50, s3trio_base+0x1008000 + 0x03D4);
408
409 /* disable HW cursor */
410
411 mem_out8(0x39, s3trio_base+0x1008000 + 0x03D4);
412 mem_out8(0xa0, s3trio_base+0x1008000 + 0x03D5);
413
414 mem_out8(0x45, s3trio_base+0x1008000 + 0x03D4);
415 mem_out8(0, s3trio_base+0x1008000 + 0x03D5);
416
417 mem_out8(0x4e, s3trio_base+0x1008000 + 0x03D4);
418 mem_out8(0, s3trio_base+0x1008000 + 0x03D5);
419
420 mem_out8(0x4f, s3trio_base+0x1008000 + 0x03D4);
421 mem_out8(0, s3trio_base+0x1008000 + 0x03D5);
422
423 /* init HW cursor */
424
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;
431 }
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;
437 }
438
439
440 mem_out8(0x4c, s3trio_base+0x1008000 + 0x03D4);
441 mem_out8(((2*1024 - 1)&0xf00)>>8, s3trio_base+0x1008000 + 0x03D5);
442
443 mem_out8(0x4d, s3trio_base+0x1008000 + 0x03D4);
444 mem_out8((2*1024 - 1) & 0xff, s3trio_base+0x1008000 + 0x03D5);
445
446 mem_out8(0x45, s3trio_base+0x1008000 + 0x03D4);
447 mem_in8(s3trio_base+0x1008000 + 0x03D4);
448
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);
453
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);
458
459 mem_out8(0x45, s3trio_base+0x1008000 + 0x03D4);
460 mem_out8(0, s3trio_base+0x1008000 + 0x03D5);
461
462 /* setup default color table */
463
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];
469 }
470
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);
474
475 #if 0
476 Trio_RectFill(0, 0, 90, 90, 7, 1);
477 #endif
478
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;
498
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;
520
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
538
539 fb_info.flags = FBINFO_FLAG_DEFAULT;
540 if (register_framebuffer(&fb_info) < 0)
541 return;
542
543 printk("fb%d: S3 Trio frame buffer device on %s\n",
544 fb_info.node, dp->full_name);
545 }
546
547
548 static int s3triofbcon_switch(int con, struct fb_info *info)
549 {
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);
553
554 info->currcon = con;
555 /* Install new colormap */
556 do_install_cmap(con,info);
557 return 0;
558 }
559
560 /*
561 * Update the `var' structure (called by fbcon.c)
562 */
563
564 static int s3triofbcon_updatevar(int con, struct fb_info *info)
565 {
566 /* Nothing */
567 return 0;
568 }
569
570 /*
571 * Blank the display.
572 */
573
574 static int s3triofb_blank(int blank, struct fb_info *info)
575 {
576 unsigned char x;
577
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;
582 }
583
584 /*
585 * Read a single color register and split it into
586 * colors/transparent. Return != 0 for invalid regno.
587 */
588
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)
591 {
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;
599 }
600
601
602 /*
603 * Set a single color register. Return != 0 for invalid regno.
604 */
605
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)
608 {
609 if (regno > 255)
610 return 1;
611
612 red >>= 8;
613 green >>= 8;
614 blue >>= 8;
615 palette[regno].red = red;
616 palette[regno].green = green;
617 palette[regno].blue = blue;
618
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);
623
624 return 0;
625 }
626
627 static void Trio_WaitQueue(u_short fifo) {
628
629 u_short status;
630
631 do
632 {
633 status = mem_in16(s3trio_base + 0x1000000 + 0x9AE8);
634 } while (!(status & fifo));
635
636 }
637
638 static void Trio_WaitBlit(void) {
639
640 u_short status;
641
642 do
643 {
644 status = mem_in16(s3trio_base + 0x1000000 + 0x9AE8);
645 } while (status & 0x200);
646
647 }
648
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) {
652
653 u_short blitcmd = 0xc011;
654
655 /* Set drawing direction */
656 /* -Y, X maj, -X (default) */
657
658 if (curx > destx)
659 blitcmd |= 0x0020; /* Drawing direction +X */
660 else {
661 curx += (width - 1);
662 destx += (width - 1);
663 }
664
665 if (cury > desty)
666 blitcmd |= 0x0080; /* Drawing direction +Y */
667 else {
668 cury += (height - 1);
669 desty += (height - 1);
670 }
671
672 Trio_WaitQueue(0x0400);
673
674 outw(0xa000, 0xBEE8);
675 outw(0x60 | mode, 0xBAE8);
676
677 outw(curx, 0x86E8);
678 outw(cury, 0x82E8);
679
680 outw(destx, 0x8EE8);
681 outw(desty, 0x8AE8);
682
683 outw(height - 1, 0xBEE8);
684 outw(width - 1, 0x96E8);
685
686 outw(blitcmd, 0x9AE8);
687
688 }
689
690 static void Trio_RectFill(u_short x, u_short y, u_short width, u_short height,
691 u_short mode, u_short color) {
692
693 u_short blitcmd = 0x40b1;
694
695 Trio_WaitQueue(0x0400);
696
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);
706
707 }
708
709
710 static void Trio_MoveCursor(u_short x, u_short y) {
711
712 mem_out8(0x39, s3trio_base + 0x1008000 + 0x3d4);
713 mem_out8(0xa0, s3trio_base + 0x1008000 + 0x3d5);
714
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);
719
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);
724
725 }
726
727
728 /*
729 * Text console acceleration
730 */
731
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)
735 {
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);
740 }
741
742 static void fbcon_trio8_clear(struct vc_data *conp, struct display *p, int sy,
743 int sx, int height, int width)
744 {
745 unsigned char bg;
746
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);
755 }
756
757 static void fbcon_trio8_putc(struct vc_data *conp, struct display *p, int c,
758 int yy, int xx)
759 {
760 Trio_WaitBlit();
761 fbcon_cfb8_putc(conp, p, c, yy, xx);
762 }
763
764 static void fbcon_trio8_putcs(struct vc_data *conp, struct display *p,
765 const unsigned short *s, int count, int yy, int xx)
766 {
767 Trio_WaitBlit();
768 fbcon_cfb8_putcs(conp, p, s, count, yy, xx);
769 }
770
771 static void fbcon_trio8_revc(struct display *p, int xx, int yy)
772 {
773 Trio_WaitBlit();
774 fbcon_cfb8_revc(p, xx, yy);
775 }
776
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)
786 };
787 #endif
788
789 MODULE_LICENSE("GPL");