2 * linux/drivers/video/virgefb.c -- CyberVision64/3D frame buffer device
4 * Copyright (C) 1997 André Heynatz
7 * This file is based on the CyberVision frame buffer device (cyberfb.c):
9 * Copyright (C) 1996 Martin Apel
12 * This file is subject to the terms and conditions of the GNU General Public
13 * License. See the file COPYING in the main directory of this archive
19 #include <linux/module.h>
20 #include <linux/kernel.h>
21 #include <linux/errno.h>
22 #include <linux/string.h>
24 #include <linux/tty.h>
25 #include <linux/malloc.h>
26 #include <linux/delay.h>
27 #include <linux/zorro.h>
29 #include <linux/init.h>
30 #include <asm/uaccess.h>
31 #include <asm/system.h>
33 #include <asm/pgtable.h>
34 #include <asm/amigahw.h>
37 #include <video/s3blit.h>
38 #include <video/fbcon.h>
39 #include <video/fbcon-cfb8.h>
40 #include <video/fbcon-cfb16.h>
44 #define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __FUNCTION__ , ## args)
46 #define DPRINTK(fmt, args...)
49 #define arraysize(x) (sizeof(x)/sizeof(*(x)))
52 #define vgawb_3d(reg,dat) \
53 if (cv3d_on_zorro2) { \
54 *((unsigned char volatile *)((Cyber_vcode_switch_base) + 0x04)) = \
55 (0x01 & 0xffff); asm volatile ("nop"); \
57 (*((unsigned char *)(CyberVGARegs + (reg ^ 3))) = dat); \
58 if (cv3d_on_zorro2) { \
59 *((unsigned char volatile *)((Cyber_vcode_switch_base) + 0x04)) = \
60 (0x02 & 0xffff); asm volatile ("nop"); \
62 #define vgaww_3d(reg,dat) \
63 (*((unsigned word *)(CyberVGARegs + (reg ^ 2))) = swab16(dat))
64 #define vgawl_3d(reg,dat) \
65 (*((unsigned long *)(CyberVGARegs + reg)) = swab32(dat))
68 * Dunno why this doesn't work at the moment - we'll have to look at
71 #define vgawb_3d(reg,dat) \
72 (*((unsigned char *)(CyberRegs + 0x8000 + reg)) = dat)
73 #define vgaww_3d(reg,dat) \
74 (*((unsigned word *)(CyberRegs + 0x8000 + reg)) = dat)
75 #define vgawl_3d(reg,dat) \
76 (*((unsigned long *)(CyberRegs + 0x8000 + reg)) = dat)
80 * We asume P5 mapped the big-endian version of these registers.
82 #define wb_3d(reg,dat) \
83 (*((unsigned char volatile *)(CyberRegs + reg)) = dat)
84 #define ww_3d(reg,dat) \
85 (*((unsigned word volatile *)(CyberRegs + reg)) = dat)
86 #define wl_3d(reg,dat) \
87 (*((unsigned long volatile *)(CyberRegs + reg)) = dat)
89 (*((unsigned long volatile *)(CyberRegs + reg)))
91 #define Select_Zorro2_FrameBuffer(flag) \
93 *((unsigned char volatile *)((Cyber_vcode_switch_base) + 0x08)) = \
94 ((flag * 0x40) & 0xffff); asm volatile ("nop"); \
97 * may be needed when we initialize the board?
98 * 8bit: flag = 2, 16 bit: flag = 1, 24/32bit: flag = 0
99 * _when_ the board is initialized, depth doesnt matter, we allways write
100 * to the same address, aperture seems not to matter on Z2.
110 static struct virgefb_par current_par
;
112 static int current_par_valid
= 0;
113 static int currcon
= 0;
115 static struct display disp
;
116 static struct fb_info fb_info
;
119 #ifdef FBCON_HAS_CFB16
125 * Switch for Chipset Independency
128 static struct fb_hwswitch
{
134 /* Display Control */
136 int (*encode_fix
)(struct fb_fix_screeninfo
*fix
, struct virgefb_par
*par
);
137 int (*decode_var
)(struct fb_var_screeninfo
*var
, struct virgefb_par
*par
);
138 int (*encode_var
)(struct fb_var_screeninfo
*var
, struct virgefb_par
*par
);
139 int (*getcolreg
)(u_int regno
, u_int
*red
, u_int
*green
, u_int
*blue
,
140 u_int
*transp
, struct fb_info
*info
);
141 int (*setcolreg
)(u_int regno
, u_int red
, u_int green
, u_int blue
,
142 u_int transp
, struct fb_info
*info
);
143 void (*blank
)(int blank
);
146 static int blit_maybe_busy
= 0;
152 static char virgefb_name
[16] = "Cybervision/3D";
156 * Cybervision Graphics Board
159 #define VIRGE8_WIDTH 1152
160 #define VIRGE8_HEIGHT 886
161 #define VIRGE8_PIXCLOCK 12500 /* ++Geert: Just a guess */
164 #define VIRGE16_WIDTH 800
165 #define VIRGE16_HEIGHT 600
167 #define VIRGE16_PIXCLOCK 25000 /* ++Geert: Just a guess */
170 static unsigned char Cyber_colour_table
[256][3];
171 static unsigned long CyberMem
;
172 static unsigned long CyberSize
;
173 static volatile char *CyberRegs
;
174 static volatile unsigned long CyberVGARegs
; /* ++Andre: for CV64/3D, see macros at the beginning */
175 static unsigned long CyberMem_phys
;
176 static unsigned long CyberRegs_phys
;
177 static unsigned long Cyber_register_base
;
178 static unsigned long Cyber_vcode_switch_base
;
179 static unsigned char cv3d_on_zorro2
;
181 #define CYBMEM_OFFSET_8 0x800000 /* offsets from start of video - */
182 #define CYBMEM_OFFSET_16 0x400000 /* ram to appropriate aperture */
185 * Predefined Video Modes
190 struct fb_var_screeninfo var
;
191 } virgefb_predefined
[] __initdata
= {
193 "640x480-8", { /* Cybervision 8 bpp */
194 640, 480, 640, 480, 0, 0, 8, 0,
195 {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
196 0, 0, -1, -1, FB_ACCELF_TEXT
, VIRGE8_PIXCLOCK
, 64, 96, 35, 12, 112, 2,
197 FB_SYNC_COMP_HIGH_ACT
|FB_SYNC_VERT_HIGH_ACT
, FB_VMODE_NONINTERLACED
200 "800x600-8", { /* Cybervision 8 bpp */
201 800, 600, 800, 600, 0, 0, 8, 0,
202 {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
203 0, 0, -1, -1, FB_ACCELF_TEXT
, VIRGE8_PIXCLOCK
, 64, 96, 35, 12, 112, 2,
204 FB_SYNC_COMP_HIGH_ACT
|FB_SYNC_VERT_HIGH_ACT
, FB_VMODE_NONINTERLACED
207 "1024x768-8", { /* Cybervision 8 bpp */
208 1024, 768, 1024, 768, 0, 0, 8, 0,
209 {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
210 0, 0, -1, -1, FB_ACCELF_TEXT
, VIRGE8_PIXCLOCK
, 64, 96, 35, 12, 112, 2,
211 FB_SYNC_COMP_HIGH_ACT
|FB_SYNC_VERT_HIGH_ACT
, FB_VMODE_NONINTERLACED
214 "1152x886-8", { /* Cybervision 8 bpp */
215 1152, 886, 1152, 886, 0, 0, 8, 0,
216 {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
217 0, 0, -1, -1, FB_ACCELF_TEXT
, VIRGE8_PIXCLOCK
, 64, 96, 35, 12, 112, 2,
218 FB_SYNC_COMP_HIGH_ACT
|FB_SYNC_VERT_HIGH_ACT
, FB_VMODE_NONINTERLACED
221 "1280x1024-8", { /* Cybervision 8 bpp */
222 1280, 1024, 1280, 1024, 0, 0, 8, 0,
223 {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
224 0, 0, -1, -1, FB_ACCELF_TEXT
, VIRGE8_PIXCLOCK
, 64, 96, 35, 12, 112, 2,
225 FB_SYNC_COMP_HIGH_ACT
|FB_SYNC_VERT_HIGH_ACT
, FB_VMODE_NONINTERLACED
228 "1600x1200-8", { /* Cybervision 8 bpp */
229 1600, 1200, 1600, 1200, 0, 0, 8, 0,
230 {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
231 0, 0, -1, -1, FB_ACCELF_TEXT
, VIRGE8_PIXCLOCK
, 64, 96, 35, 12, 112, 2,
232 FB_SYNC_COMP_HIGH_ACT
|FB_SYNC_VERT_HIGH_ACT
, FB_VMODE_NONINTERLACED
235 "640x480-16", { /* Cybervision 16 bpp */
236 640, 480, 640, 480, 0, 0, 16, 0,
237 {11, 5, 0}, {5, 6, 0}, {0, 5, 0}, {0, 0, 0},
238 0, 0, -1, -1, FB_ACCELF_TEXT
, VIRGE16_PIXCLOCK
, 64, 96, 35, 12, 112, 2,
239 FB_SYNC_COMP_HIGH_ACT
|FB_SYNC_VERT_HIGH_ACT
, FB_VMODE_NONINTERLACED
242 "800x600-16", { /* Cybervision 16 bpp */
243 800, 600, 800, 600, 0, 0, 16, 0,
244 {11, 5, 0}, {5, 6, 0}, {0, 5, 0}, {0, 0, 0},
245 0, 0, -1, -1, FB_ACCELF_TEXT
, VIRGE16_PIXCLOCK
, 64, 96, 35, 12, 112, 2,
246 FB_SYNC_COMP_HIGH_ACT
|FB_SYNC_VERT_HIGH_ACT
, FB_VMODE_NONINTERLACED
249 "1024x768-16", { /* Cybervision 16 bpp */
250 1024, 768, 1024, 768, 0, 0, 16, 0,
251 {11, 5, 0}, {5, 6, 0}, {0, 5, 0}, {0, 0, 0},
252 0, 0, -1, -1, FB_ACCELF_TEXT
, VIRGE16_PIXCLOCK
, 64, 96, 35, 12, 112, 2,
253 FB_SYNC_COMP_HIGH_ACT
|FB_SYNC_VERT_HIGH_ACT
, FB_VMODE_NONINTERLACED
256 "1152x886-16", { /* Cybervision 16 bpp */
257 1152, 886, 1152, 886, 0, 0, 16, 0,
258 {11, 5, 0}, {5, 6, 0}, {0, 5, 0}, {0, 0, 0},
259 0, 0, -1, -1, FB_ACCELF_TEXT
, VIRGE16_PIXCLOCK
, 64, 96, 35, 12, 112, 2,
260 FB_SYNC_COMP_HIGH_ACT
|FB_SYNC_VERT_HIGH_ACT
, FB_VMODE_NONINTERLACED
263 "1280x1024-16", { /* Cybervision 16 bpp */
264 1280, 1024, 1280, 1024, 0, 0, 16, 0,
265 {11, 5, 0}, {5, 6, 0}, {0, 5, 0}, {0, 0, 0},
266 0, 0, -1, -1, FB_ACCELF_TEXT
, VIRGE16_PIXCLOCK
, 64, 96, 35, 12, 112, 2,
267 FB_SYNC_COMP_HIGH_ACT
|FB_SYNC_VERT_HIGH_ACT
, FB_VMODE_NONINTERLACED
270 "1600x1200-16", { /* Cybervision 16 bpp */
271 1600, 1200, 1600, 1200, 0, 0, 16, 0,
272 {11, 5, 0}, {5, 6, 0}, {0, 5, 0}, {0, 0, 0},
273 0, 0, -1, -1, FB_ACCELF_TEXT
, VIRGE16_PIXCLOCK
, 64, 96, 35, 12, 112, 2,
274 FB_SYNC_COMP_HIGH_ACT
|FB_SYNC_VERT_HIGH_ACT
, FB_VMODE_NONINTERLACED
280 #define NUM_TOTAL_MODES arraysize(virgefb_predefined)
283 static int Cyberfb_inverse
= 0;
289 #define VIRGE8_DEFMODE (1)
290 #define VIRGE16_DEFMODE (7)
292 static struct fb_var_screeninfo virgefb_default
;
296 * Interface used by the world
299 int virgefb_setup(char*);
301 static int virgefb_get_fix(struct fb_fix_screeninfo
*fix
, int con
, struct
303 static int virgefb_get_var(struct fb_var_screeninfo
*var
, int con
, struct
305 static int virgefb_set_var(struct fb_var_screeninfo
*var
, int con
, struct
307 static int virgefb_get_cmap(struct fb_cmap
*cmap
, int kspc
, int con
,
308 struct fb_info
*info
);
309 static int virgefb_set_cmap(struct fb_cmap
*cmap
, int kspc
, int con
,
310 struct fb_info
*info
);
314 * Interface to the low level console driver
317 int virgefb_init(void);
318 static int Cyberfb_switch(int con
, struct fb_info
*info
);
319 static int Cyberfb_updatevar(int con
, struct fb_info
*info
);
320 static void Cyberfb_blank(int blank
, struct fb_info
*info
);
324 * Text console acceleration
327 #ifdef FBCON_HAS_CFB8
328 static struct display_switch fbcon_virge8
;
331 #ifdef FBCON_HAS_CFB16
332 static struct display_switch fbcon_virge16
;
336 * Hardware Specific Routines
339 static int Cyber_init(void);
340 static int Cyber_encode_fix(struct fb_fix_screeninfo
*fix
,
341 struct virgefb_par
*par
);
342 static int Cyber_decode_var(struct fb_var_screeninfo
*var
,
343 struct virgefb_par
*par
);
344 static int Cyber_encode_var(struct fb_var_screeninfo
*var
,
345 struct virgefb_par
*par
);
346 static int Cyber_getcolreg(u_int regno
, u_int
*red
, u_int
*green
, u_int
*blue
,
347 u_int
*transp
, struct fb_info
*info
);
348 static int Cyber_setcolreg(u_int regno
, u_int red
, u_int green
, u_int blue
,
349 u_int transp
, struct fb_info
*info
);
350 static void Cyber_blank(int blank
);
357 static void virgefb_get_par(struct virgefb_par
*par
);
358 static void virgefb_set_par(struct virgefb_par
*par
);
359 static int do_fb_set_var(struct fb_var_screeninfo
*var
, int isactive
);
360 static void do_install_cmap(int con
, struct fb_info
*info
);
361 static void virgefb_set_disp(int con
, struct fb_info
*info
);
362 static int get_video_mode(const char *name
);
365 /* -------------------- Hardware specific routines ------------------------- */
371 * Set the default video mode for this chipset. If a video mode was
372 * specified on the command line, it will override the default mode.
375 static int Cyber_init(void)
379 for (i
= 0; i
< 256; i
++)
381 Cyber_colour_table
[i
][0] = i
;
382 Cyber_colour_table
[i
][1] = i
;
383 Cyber_colour_table
[i
][2] = i
;
387 * Just clear the thing for the biggest mode.
389 * ++Andre, TODO: determine size first, then clear all memory
390 * (the 3D penguin might need texture memory :-) )
393 if (cv3d_on_zorro2
) {
394 CyberSize
= 0x00380000; /* 3.5 MB , we need some space for the registers? */
396 CyberSize
= 0x00400000; /* 4 MB */
399 memset ((char*)CyberMem
, 0, CyberSize
);
401 /* Disable hardware cursor */
402 vgawb_3d(0x3c8, 255);
404 vgawb_3d(0x3c9, 100);
405 vgawb_3d(0x3c9, 160);
407 vgawb_3d(0x3c8, 254);
412 /* Disable hardware cursor */
413 vgawb_3d(S3_CRTC_ADR
, S3_REG_LOCK2
);
414 vgawb_3d(S3_CRTC_DATA
, 0xa0);
415 vgawb_3d(S3_CRTC_ADR
, S3_HGC_MODE
);
416 vgawb_3d(S3_CRTC_DATA
, 0x00);
417 vgawb_3d(S3_CRTC_ADR
, S3_HWGC_DX
);
418 vgawb_3d(S3_CRTC_DATA
, 0x00);
419 vgawb_3d(S3_CRTC_ADR
, S3_HWGC_DY
);
420 vgawb_3d(S3_CRTC_DATA
, 0x00);
422 return 0; /* TODO: hardware cursor for CV64/3D */
427 * This function should fill in the `fix' structure based on the
428 * values in the `par' structure.
431 static int Cyber_encode_fix(struct fb_fix_screeninfo
*fix
,
432 struct virgefb_par
*par
)
434 memset(fix
, 0, sizeof(struct fb_fix_screeninfo
));
435 strcpy(fix
->id
, virgefb_name
);
436 if (cv3d_on_zorro2
) {
437 fix
->smem_start
= CyberMem_phys
;
441 fix
->smem_start
= (CyberMem_phys
+ CYBMEM_OFFSET_8
);
444 fix
->smem_start
= (CyberMem_phys
+ CYBMEM_OFFSET_16
);
448 fix
->smem_len
= CyberSize
;
449 fix
->mmio_start
= CyberRegs_phys
;
450 fix
->mmio_len
= 0x10000; /* TODO: verify this for the CV64/3D */
452 fix
->type
= FB_TYPE_PACKED_PIXELS
;
455 fix
->visual
= FB_VISUAL_PSEUDOCOLOR
;
457 fix
->visual
= FB_VISUAL_TRUECOLOR
;
462 fix
->line_length
= 0;
463 fix
->accel
= FB_ACCEL_S3_VIRGE
;
469 * Get the video params out of `var'. If a value doesn't fit, round
470 * it up, if it's too big, return -EINVAL.
473 static int Cyber_decode_var(struct fb_var_screeninfo
*var
,
474 struct virgefb_par
*par
)
477 par
->xres
= var
->xres
;
478 par
->yres
= var
->yres
;
479 par
->bpp
= var
->bits_per_pixel
;
480 if (var
->accel_flags
& FB_ACCELF_TEXT
)
481 par
->accel
= FB_ACCELF_TEXT
;
485 if (Cyberfb_Cyber8
) {
486 par
->xres
= VIRGE8_WIDTH
;
487 par
->yres
= VIRGE8_HEIGHT
;
490 par
->xres
= VIRGE16_WIDTH
;
491 par
->yres
= VIRGE16_HEIGHT
;
500 * Fill the `var' structure based on the values in `par' and maybe
501 * other values read out of the hardware.
504 static int Cyber_encode_var(struct fb_var_screeninfo
*var
,
505 struct virgefb_par
*par
)
507 memset(var
, 0, sizeof(struct fb_var_screeninfo
));
508 var
->xres
= par
->xres
;
509 var
->yres
= par
->yres
;
510 var
->xres_virtual
= par
->xres
;
511 var
->yres_virtual
= par
->yres
;
515 var
->bits_per_pixel
= par
->bpp
;
518 switch (var
->bits_per_pixel
) {
522 var
->red
.msb_right
= 0;
523 var
->blue
= var
->green
= var
->red
;
525 case 16: /* RGB 565 */
526 var
->red
.offset
= 11;
528 var
->green
.offset
= 5;
529 var
->green
.length
= 6;
530 var
->blue
.offset
= 0;
531 var
->blue
.length
= 5;
532 var
->transp
.offset
= 0;
533 var
->transp
.length
= 0;
536 var
->red
.msb_right
= 0;
537 var
->green
.msb_right
= 0;
538 var
->blue
.msb_right
= 0;
539 var
->transp
.msb_right
= 0;
547 var
->accel_flags
= (par
->accel
&&
548 ((par
->bpp
== 8) || (par
->bpp
== 16))) ? FB_ACCELF_TEXT
: 0;
550 /* printk("CV64/3D : %s\n",(var->accel_flags ? "accel" : "no accel")); */
552 var
->vmode
= FB_VMODE_NONINTERLACED
;
557 var
->pixclock
= VIRGE8_PIXCLOCK
;
559 var
->pixclock
= VIRGE16_PIXCLOCK
;
561 var
->left_margin
= 64;
562 var
->right_margin
= 96;
563 var
->upper_margin
= 35;
564 var
->lower_margin
= 12;
565 var
->hsync_len
= 112;
573 * Set a single color register. The values supplied are already
574 * rounded down to the hardware's capabilities (according to the
575 * entries in the var structure). Return != 0 for invalid regno.
578 static int Cyber_setcolreg(u_int regno
, u_int red
, u_int green
, u_int blue
,
579 u_int transp
, struct fb_info
*info
)
581 if (((current_par
.bpp
==8) && (regno
>255)) ||
582 ((current_par
.bpp
!=8) && (regno
>15)))
585 if (((current_par
.bpp
==8) && (regno
<256)) || ((current_par
.bpp
==16) &&(regno
<16))) {
586 Cyber_colour_table
[regno
][0] = red
>> 10;
587 Cyber_colour_table
[regno
][1] = green
>> 10;
588 Cyber_colour_table
[regno
][2] = blue
>> 10;
591 switch (current_par
.bpp
) {
592 #ifdef FBCON_HAS_CFB8
594 vgawb_3d(0x3c8, (unsigned char) regno
);
595 vgawb_3d(0x3c9, ((unsigned char) (red
>> 10)));
596 vgawb_3d(0x3c9, ((unsigned char) (green
>> 10)));
597 vgawb_3d(0x3c9, ((unsigned char) (blue
>> 10)));
600 #ifdef FBCON_HAS_CFB16
602 fbcon_cmap
.cfb16
[regno
] =
604 ((green
& 0xfc00) >> 5) |
605 ((blue
& 0xf800) >> 11));
614 * Read a single color register and split it into
615 * colors/transparent. Return != 0 for invalid regno.
618 static int Cyber_getcolreg(u_int regno
, u_int
*red
, u_int
*green
, u_int
*blue
,
619 u_int
*transp
, struct fb_info
*info
)
626 if (((current_par
.bpp
==8) && (regno
<256)) || ((current_par
.bpp
==16) && (regno
<16))) {
628 t
= Cyber_colour_table
[regno
][0];
629 *red
= (t
<<10) | (t
<<4) | (t
>>2);
630 t
= Cyber_colour_table
[regno
][1];
631 *green
= (t
<<10) | (t
<<4) | (t
>>2);
632 t
= Cyber_colour_table
[regno
][2];
633 *blue
= (t
<<10) | (t
<<4) | (t
>>2);
641 * (Un)Blank the screen
644 void Cyber_blank(int blank
)
650 for (i
= 0; i
< 256; i
++)
652 vgawb_3d(0x3c8, (unsigned char) i
);
660 for (i
= 0; i
< 256; i
++)
662 vgawb_3d(0x3c8, (unsigned char) i
);
663 vgawb_3d(0x3c9, Cyber_colour_table
[i
][0]);
664 vgawb_3d(0x3c9, Cyber_colour_table
[i
][1]);
665 vgawb_3d(0x3c9, Cyber_colour_table
[i
][2]);
671 * CV3D low-level support
674 #define Cyber3D_WaitQueue(v) \
677 while ((rl_3d(0x8504) & 0x1f00) < (((v)+2) << 8)); \
682 static inline void Cyber3D_WaitBusy(void)
684 unsigned long status
;
688 status
= rl_3d(0x8504);
689 } while (!(status
& (1 << 13)));
693 #define S3V_BITBLT (0x0 << 27)
694 #define S3V_RECTFILL (0x2 << 27)
695 #define S3V_AUTOEXE 0x01
696 #define S3V_HWCLIP 0x02
697 #define S3V_DRAW 0x20
698 #define S3V_DST_8BPP 0x00
699 #define S3V_DST_16BPP 0x04
700 #define S3V_DST_24BPP 0x08
701 #define S3V_MONO_PAT 0x100
703 #define S3V_BLT_COPY (0xcc<<17)
704 #define S3V_BLT_CLEAR (0x00<<17)
705 #define S3V_BLT_SET (0xff<<17)
708 * BitBLT - Through the Plane
711 static void Cyber3D_BitBLT(u_short curx
, u_short cury
, u_short destx
,
712 u_short desty
, u_short width
, u_short height
, u_short depth
)
714 unsigned int blitcmd
= S3V_BITBLT
| S3V_DRAW
| S3V_BLT_COPY
;
717 #ifdef FBCON_HAS_CFB8
719 blitcmd
|= S3V_DST_8BPP
;
722 #ifdef FBCON_HAS_CFB16
724 blitcmd
|= S3V_DST_16BPP
;
729 /* Set drawing direction */
730 /* -Y, X maj, -X (default) */
733 blitcmd
|= (1 << 25); /* Drawing direction +X */
738 destx
+= (width
- 1);
743 blitcmd
|= (1 << 26); /* Drawing direction +Y */
747 cury
+= (height
- 1);
748 desty
+= (height
- 1);
755 wl_3d(0xa4f4, 1); /* pattern fb color */
757 wl_3d(0xa4e8, ~0); /* mono pat 0 */
758 wl_3d(0xa4ec, ~0); /* mono pat 1 */
760 wl_3d(0xa504, ((width
<< 16) | height
)); /* rwidth_height */
761 wl_3d(0xa508, ((curx
<< 16) | cury
)); /* rsrc_xy */
762 wl_3d(0xa50c, ((destx
<< 16) | desty
)); /* rdest_xy */
764 wl_3d(0xa500, blitcmd
); /* GO! */
768 * Rectangle Fill Solid
771 static void Cyber3D_RectFill(u_short x
, u_short y
, u_short width
,
772 u_short height
, u_short color
, u_short depth
)
775 unsigned int blitcmd
= S3V_RECTFILL
| S3V_DRAW
|
776 S3V_BLT_CLEAR
| S3V_MONO_PAT
| (1 << 26) | (1 << 25);
783 #ifdef FBCON_HAS_CFB8
785 blitcmd
|= S3V_DST_8BPP
;
788 #ifdef FBCON_HAS_CFB16
790 blitcmd
|= S3V_DST_16BPP
;
798 wl_3d(0xa504, ((width
<< 16) | height
)); /* rwidth_height */
799 wl_3d(0xa50c, ((x
<< 16) | y
)); /* rdest_xy */
801 wl_3d(0xa500, blitcmd
); /* GO! */
805 /**************************************************************
806 * Move cursor to x, y
810 static void Cyber_MoveCursor (u_short x
, u_short y
)
812 printk(KERN_DEBUG
"Yuck .... MoveCursor on a 3D\n");
817 /* -------------------- Interfaces to hardware functions -------------------- */
820 static struct fb_hwswitch Cyber_switch
= {
821 Cyber_init
, Cyber_encode_fix
, Cyber_decode_var
, Cyber_encode_var
,
822 Cyber_getcolreg
, Cyber_setcolreg
, Cyber_blank
826 /* -------------------- Generic routines ------------------------------------ */
830 * Fill the hardware's `par' structure.
833 static void virgefb_get_par(struct virgefb_par
*par
)
835 if (current_par_valid
)
841 fbhw
->decode_var(&virgefb_default
, par
);
846 static void virgefb_set_par(struct virgefb_par
*par
)
849 current_par_valid
= 1;
853 static void virge_set_video(struct fb_var_screeninfo
*var
)
855 /* Set clipping rectangle to current screen size */
859 clip
= ((0 << 16) | (var
->xres
- 1));
861 clip
= ((0 << 16) | (var
->yres
- 1));
866 static int do_fb_set_var(struct fb_var_screeninfo
*var
, int isactive
)
869 struct virgefb_par par
;
871 if ((err
= fbhw
->decode_var(var
, &par
)))
873 activate
= var
->activate
;
874 if ((var
->activate
& FB_ACTIVATE_MASK
) == FB_ACTIVATE_NOW
&& isactive
)
875 virgefb_set_par(&par
);
876 fbhw
->encode_var(var
, &par
);
877 var
->activate
= activate
;
879 virge_set_video(var
);
884 static void do_install_cmap(int con
, struct fb_info
*info
)
888 if (fb_display
[con
].cmap
.len
)
889 fb_set_cmap(&fb_display
[con
].cmap
, 1, fbhw
->setcolreg
, info
);
891 fb_set_cmap(fb_default_cmap(1<<fb_display
[con
].var
.bits_per_pixel
),
892 1, fbhw
->setcolreg
, info
);
896 * Get the Fixed Part of the Display
899 static int virgefb_get_fix(struct fb_fix_screeninfo
*fix
, int con
,
900 struct fb_info
*info
)
902 struct virgefb_par par
;
906 virgefb_get_par(&par
);
908 error
= fbhw
->decode_var(&fb_display
[con
].var
, &par
);
909 return(error
? error
: fbhw
->encode_fix(fix
, &par
));
914 * Get the User Defined Part of the Display
917 static int virgefb_get_var(struct fb_var_screeninfo
*var
, int con
,
918 struct fb_info
*info
)
920 struct virgefb_par par
;
925 virgefb_get_par(&par
);
926 error
= fbhw
->encode_var(var
, &par
);
927 disp
.var
= *var
; /* ++Andre: don't know if this is the right place */
931 *var
= fb_display
[con
].var
;
938 static void virgefb_set_disp(int con
, struct fb_info
*info
)
940 struct fb_fix_screeninfo fix
;
941 struct display
*display
;
944 display
= &fb_display
[con
];
946 display
= &disp
; /* used during initialization */
948 virgefb_get_fix(&fix
, con
, info
);
951 if (cv3d_on_zorro2
) {
952 display
->screen_base
= (char*) CyberMem
;
954 switch (display
->var
.bits_per_pixel
) {
956 display
->screen_base
= (char*) (CyberMem
+ CYBMEM_OFFSET_8
);
959 display
->screen_base
= (char*) (CyberMem
+ CYBMEM_OFFSET_16
);
963 display
->visual
= fix
.visual
;
964 display
->type
= fix
.type
;
965 display
->type_aux
= fix
.type_aux
;
966 display
->ypanstep
= fix
.ypanstep
;
967 display
->ywrapstep
= fix
.ywrapstep
;
968 display
->can_soft_blank
= 1;
969 display
->inverse
= Cyberfb_inverse
;
970 switch (display
->var
.bits_per_pixel
) {
971 #ifdef FBCON_HAS_CFB8
973 if (display
->var
.accel_flags
& FB_ACCELF_TEXT
) {
974 display
->dispsw
= &fbcon_virge8
;
975 #warning FIXME: We should reinit the graphics engine here
977 display
->dispsw
= &fbcon_cfb8
;
980 #ifdef FBCON_HAS_CFB16
982 if (display
->var
.accel_flags
& FB_ACCELF_TEXT
) {
983 display
->dispsw
= &fbcon_virge16
;
985 display
->dispsw
= &fbcon_cfb16
;
986 display
->dispsw_data
= &fbcon_cmap
.cfb16
;
990 display
->dispsw
= &fbcon_dummy
;
997 * Set the User Defined Part of the Display
1000 static int virgefb_set_var(struct fb_var_screeninfo
*var
, int con
,
1001 struct fb_info
*info
)
1003 int err
, oldxres
, oldyres
, oldvxres
, oldvyres
, oldbpp
, oldaccel
;
1005 if ((err
= do_fb_set_var(var
, con
== currcon
)))
1007 if ((var
->activate
& FB_ACTIVATE_MASK
) == FB_ACTIVATE_NOW
) {
1008 oldxres
= fb_display
[con
].var
.xres
;
1009 oldyres
= fb_display
[con
].var
.yres
;
1010 oldvxres
= fb_display
[con
].var
.xres_virtual
;
1011 oldvyres
= fb_display
[con
].var
.yres_virtual
;
1012 oldbpp
= fb_display
[con
].var
.bits_per_pixel
;
1013 oldaccel
= fb_display
[con
].var
.accel_flags
;
1014 fb_display
[con
].var
= *var
;
1015 if (oldxres
!= var
->xres
|| oldyres
!= var
->yres
||
1016 oldvxres
!= var
->xres_virtual
||
1017 oldvyres
!= var
->yres_virtual
||
1018 oldbpp
!= var
->bits_per_pixel
||
1019 oldaccel
!= var
->accel_flags
) {
1020 virgefb_set_disp(con
, info
);
1021 (*fb_info
.changevar
)(con
);
1022 fb_alloc_cmap(&fb_display
[con
].cmap
, 0, 0);
1023 do_install_cmap(con
, info
);
1035 static int virgefb_get_cmap(struct fb_cmap
*cmap
, int kspc
, int con
,
1036 struct fb_info
*info
)
1038 if (con
== currcon
) /* current console? */
1039 return(fb_get_cmap(cmap
, kspc
, fbhw
->getcolreg
, info
));
1040 else if (fb_display
[con
].cmap
.len
) /* non default colormap? */
1041 fb_copy_cmap(&fb_display
[con
].cmap
, cmap
, kspc
? 0 : 2);
1043 fb_copy_cmap(fb_default_cmap(1<<fb_display
[con
].var
.bits_per_pixel
),
1044 cmap
, kspc
? 0 : 2);
1053 static int virgefb_set_cmap(struct fb_cmap
*cmap
, int kspc
, int con
,
1054 struct fb_info
*info
)
1058 if (!fb_display
[con
].cmap
.len
) { /* no colormap allocated? */
1059 if ((err
= fb_alloc_cmap(&fb_display
[con
].cmap
,
1060 1<<fb_display
[con
].var
.bits_per_pixel
, 0)))
1063 if (con
== currcon
) /* current console? */
1064 return(fb_set_cmap(cmap
, kspc
, fbhw
->setcolreg
, info
));
1066 fb_copy_cmap(cmap
, &fb_display
[con
].cmap
, kspc
? 0 : 1);
1071 static struct fb_ops virgefb_ops
= {
1073 fb_get_fix
: virgefb_get_fix
,
1074 fb_get_var
: virgefb_get_var
,
1075 fb_set_var
: virgefb_set_var
,
1076 fb_get_cmap
: virgefb_get_cmap
,
1077 fb_set_cmap
: virgefb_set_cmap
,
1081 int __init
virgefb_setup(char *options
)
1085 fb_info
.fontname
[0] = '\0';
1087 if (!options
|| !*options
)
1090 for (this_opt
= strtok(options
, ","); this_opt
; this_opt
= strtok(NULL
, ","))
1091 if (!strcmp(this_opt
, "inverse")) {
1092 Cyberfb_inverse
= 1;
1094 } else if (!strncmp(this_opt
, "font:", 5))
1095 strcpy(fb_info
.fontname
, this_opt
+5);
1096 else if (!strcmp (this_opt
, "virge8")){
1097 virgefb_default
= virgefb_predefined
[VIRGE8_DEFMODE
].var
;
1099 else if (!strcmp (this_opt
, "virge16")){
1100 virgefb_default
= virgefb_predefined
[VIRGE16_DEFMODE
].var
;
1103 get_video_mode(this_opt
);
1105 DPRINTK("default mode: xres=%d, yres=%d, bpp=%d\n",virgefb_default
.xres
,
1106 virgefb_default
.yres
,
1107 virgefb_default
.bits_per_pixel
);
1116 int __init
virgefb_init(void)
1118 struct virgefb_par par
;
1119 unsigned long board_addr
, ramsize
;
1120 struct zorro_dev
*z
= NULL
;
1122 while ((z
= zorro_find_device(ZORRO_PROD_PHASE5_CYBERVISION64_3D
, z
))) {
1123 board_addr
= z
->resource
.start
;
1124 if (board_addr
< 0x01000000) {
1126 * Ok we got the board running in Z2 space.
1128 CyberRegs_phys
= (unsigned long)(board_addr
+ 0x003e0000);
1129 CyberMem_phys
= board_addr
;
1130 ramsize
= 0x00380000;
1132 CyberRegs_phys
= board_addr
+ 0x05000000;
1133 CyberMem_phys
= board_addr
+ 0x04000000; /* was 0x04800000 */
1134 ramsize
= 0x00400000;
1136 if (!request_mem_region(CyberRegs_phys
, 0x10000, "S3 ViRGE"))
1138 if (!request_mem_region(CyberMem_phys
, ramsize
, "RAM")) {
1139 release_mem_region(CyberRegs_phys
, 0x10000);
1143 if (board_addr
< 0x01000000) {
1145 * Ok we got the board running in Z2 space.
1148 CyberMem
= ZTWO_VADDR(CyberMem_phys
);
1149 CyberVGARegs
= (unsigned long) \
1150 ZTWO_VADDR(board_addr
+ 0x003c0000);
1151 CyberRegs
= (unsigned char *)ZTWO_VADDR(CyberRegs_phys
);
1152 Cyber_register_base
= (unsigned long) \
1153 ZTWO_VADDR(board_addr
+ 0x003c8000);
1154 Cyber_vcode_switch_base
= (unsigned long) \
1155 ZTWO_VADDR(board_addr
+ 0x003a0000);
1157 printk(KERN_INFO
"CV3D detected running in Z2 mode.\n");
1159 CyberVGARegs
= (unsigned long)ioremap(board_addr
+0x0c000000, 0x00010000);
1160 CyberRegs
= ioremap(CyberRegs_phys
, 0x00010000);
1161 CyberMem
= (unsigned long)ioremap(CyberMem_phys
, 0x01000000); /* was 0x00400000 */
1163 printk(KERN_INFO
"CV3D detected running in Z3 mode.\n");
1166 fbhw
= &Cyber_switch
;
1168 strcpy(fb_info
.modename
, virgefb_name
);
1169 fb_info
.changevar
= NULL
;
1171 fb_info
.fbops
= &virgefb_ops
;
1172 fb_info
.disp
= &disp
;
1173 fb_info
.switch_con
= &Cyberfb_switch
;
1174 fb_info
.updatevar
= &Cyberfb_updatevar
;
1175 fb_info
.blank
= &Cyberfb_blank
;
1176 fb_info
.flags
= FBINFO_FLAG_DEFAULT
;
1179 fbhw
->decode_var(&virgefb_default
, &par
);
1180 fbhw
->encode_var(&virgefb_default
, &par
);
1182 do_fb_set_var(&virgefb_default
, 1);
1183 virgefb_get_var(&fb_display
[0].var
, -1, &fb_info
);
1184 virgefb_set_disp(-1, &fb_info
);
1185 do_install_cmap(0, &fb_info
);
1187 if (register_framebuffer(&fb_info
) < 0) {
1188 printk(KERN_ERR
"virgefb.c: register_framebuffer failed\n");
1192 printk(KERN_INFO
"fb%d: %s frame buffer device, using %ldK of "
1193 "video memory\n", GET_FB_IDX(fb_info
.node
),
1194 fb_info
.modename
, CyberSize
>>10);
1196 /* TODO: This driver cannot be unloaded yet */
1204 static int Cyberfb_switch(int con
, struct fb_info
*info
)
1206 /* Do we have to save the colormap? */
1207 if (fb_display
[currcon
].cmap
.len
)
1208 fb_get_cmap(&fb_display
[currcon
].cmap
, 1, fbhw
->getcolreg
,
1211 do_fb_set_var(&fb_display
[con
].var
, 1);
1213 /* Install new colormap */
1214 do_install_cmap(con
, info
);
1220 * Update the `var' structure (called by fbcon.c)
1222 * This call looks only at yoffset and the FB_VMODE_YWRAP flag in `var'.
1223 * Since it's called by a kernel driver, no range checking is done.
1226 static int Cyberfb_updatevar(int con
, struct fb_info
*info
)
1233 * Blank the display.
1236 static void Cyberfb_blank(int blank
, struct fb_info
*info
)
1246 static int __init
get_video_mode(const char *name
)
1250 for (i
= 0; i
< NUM_TOTAL_MODES
; i
++) {
1251 if (!strcmp(name
, virgefb_predefined
[i
].name
)) {
1252 virgefb_default
= virgefb_predefined
[i
].var
;
1256 /* ++Andre: set virgefb default mode */
1257 virgefb_default
= virgefb_predefined
[VIRGE8_DEFMODE
].var
;
1263 * Text console acceleration
1266 #ifdef FBCON_HAS_CFB8
1267 static void fbcon_virge8_bmove(struct display
*p
, int sy
, int sx
, int dy
,
1268 int dx
, int height
, int width
)
1270 sx
*= 8; dx
*= 8; width
*= 8;
1271 Cyber3D_BitBLT((u_short
)sx
, (u_short
)(sy
*fontheight(p
)), (u_short
)dx
,
1272 (u_short
)(dy
*fontheight(p
)), (u_short
)width
,
1273 (u_short
)(height
*fontheight(p
)), 8);
1276 static void fbcon_virge8_clear(struct vc_data
*conp
, struct display
*p
, int sy
,
1277 int sx
, int height
, int width
)
1281 sx
*= 8; width
*= 8;
1282 bg
= attr_bgcol_ec(p
,conp
);
1283 Cyber3D_RectFill((u_short
)sx
, (u_short
)(sy
*fontheight(p
)),
1284 (u_short
)width
, (u_short
)(height
*fontheight(p
)),
1288 static void fbcon_virge8_putc(struct vc_data
*conp
, struct display
*p
, int c
, int yy
,
1291 if (blit_maybe_busy
)
1293 fbcon_cfb8_putc(conp
, p
, c
, yy
, xx
);
1296 static void fbcon_virge8_putcs(struct vc_data
*conp
, struct display
*p
,
1297 const unsigned short *s
, int count
, int yy
, int xx
)
1299 if (blit_maybe_busy
)
1301 fbcon_cfb8_putcs(conp
, p
, s
, count
, yy
, xx
);
1304 static void fbcon_virge8_revc(struct display
*p
, int xx
, int yy
)
1306 if (blit_maybe_busy
)
1308 fbcon_cfb8_revc(p
, xx
, yy
);
1311 static void fbcon_virge8_clear_margins(struct vc_data
*conp
, struct display
*p
,
1314 if (blit_maybe_busy
)
1316 fbcon_cfb8_clear_margins(conp
, p
, bottom_only
);
1319 static struct display_switch fbcon_virge8
= {
1320 setup
: fbcon_cfb8_setup
,
1321 bmove
: fbcon_virge8_bmove
,
1322 clear
: fbcon_virge8_clear
,
1323 putc
: fbcon_virge8_putc
,
1324 putcs
: fbcon_virge8_putcs
,
1325 revc
: fbcon_virge8_revc
,
1326 clear_margins
: fbcon_virge8_clear_margins
,
1327 fontwidthmask
: FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16)
1331 #ifdef FBCON_HAS_CFB16
1332 static void fbcon_virge16_bmove(struct display
*p
, int sy
, int sx
, int dy
,
1333 int dx
, int height
, int width
)
1335 sx
*= 8; dx
*= 8; width
*= 8;
1336 Cyber3D_BitBLT((u_short
)sx
, (u_short
)(sy
*fontheight(p
)), (u_short
)dx
,
1337 (u_short
)(dy
*fontheight(p
)), (u_short
)width
,
1338 (u_short
)(height
*fontheight(p
)), 16);
1341 static void fbcon_virge16_clear(struct vc_data
*conp
, struct display
*p
, int sy
,
1342 int sx
, int height
, int width
)
1346 sx
*= 8; width
*= 8;
1347 bg
= attr_bgcol_ec(p
,conp
);
1348 Cyber3D_RectFill((u_short
)sx
, (u_short
)(sy
*fontheight(p
)),
1349 (u_short
)width
, (u_short
)(height
*fontheight(p
)),
1353 static void fbcon_virge16_putc(struct vc_data
*conp
, struct display
*p
, int c
, int yy
,
1356 if (blit_maybe_busy
)
1358 fbcon_cfb16_putc(conp
, p
, c
, yy
, xx
);
1361 static void fbcon_virge16_putcs(struct vc_data
*conp
, struct display
*p
,
1362 const unsigned short *s
, int count
, int yy
, int xx
)
1364 if (blit_maybe_busy
)
1366 fbcon_cfb16_putcs(conp
, p
, s
, count
, yy
, xx
);
1369 static void fbcon_virge16_revc(struct display
*p
, int xx
, int yy
)
1371 if (blit_maybe_busy
)
1373 fbcon_cfb16_revc(p
, xx
, yy
);
1376 static void fbcon_virge16_clear_margins(struct vc_data
*conp
, struct display
*p
,
1379 if (blit_maybe_busy
)
1381 fbcon_cfb16_clear_margins(conp
, p
, bottom_only
);
1384 static struct display_switch fbcon_virge16
= {
1385 setup
: fbcon_cfb16_setup
,
1386 bmove
: fbcon_virge16_bmove
,
1387 clear
: fbcon_virge16_clear
,
1388 putc
: fbcon_virge16_putc
,
1389 putcs
: fbcon_virge16_putcs
,
1390 revc
: fbcon_virge16_revc
,
1391 clear_margins
: fbcon_virge16_clear_margins
,
1392 fontwidthmask
: FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16)
1397 int init_module(void)
1399 return virgefb_init();
1402 void cleanup_module(void)
1404 /* Not reached because the usecount will never be
1405 decremented to zero */
1406 unregister_framebuffer(&fb_info
);
1407 /* TODO: clean up ... */