Resent-Date: Wed, 27 Jan 1999 23:40:07 +0100 (MET)
Date: Thu, 28 Jan 1999 09:10:22 +1100 (EST)
From: Ken Tyler <kent@werple.net.au>
Reply-To: Ken Tyler <kent@werple.net.au>
Subject: Patch for 16 bit on CV64-3D
To: linux-apus@sunsite.auc.dk
Cc: linux-m68k@lists.linux-m68k.org
Organization: Organization
Resent-From: linux-m68k@phil.uni-sb.de



The following patch for virgefb.c implements :

	a) 16 bit colour 

	b) blit_maybe_busy (as disscussed at length !)

	c) fixes various console corruptions on APUS

Supports 800x600x16, other 8, 16 bit modes possible by easy changes.

Tested on APUS ZorroIII.

Includes Christin's ZorroII changes but not tested on ZorroIII. 

Patch is relative to 2.1.131
 
Next to do is to make virgefb self initializing, would love someone to
explain some mysteries in the cyberfb and virgefb drivers, any offers ?

Ken.

--- linux-2.1.131/drivers/video/virgefb.c.save	Thu Jan 28 19:41:25 1999
+++ linux-2.1.131/drivers/video/virgefb.c	Thu Jan 28 18:41:18 1999
@@ -39,7 +39,6 @@
 #include <video/fbcon-cfb8.h>
 #include <video/fbcon-cfb16.h>
 
-
 #ifdef VIRGEFBDEBUG
 #define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __FUNCTION__ , ## args)
 #else
@@ -50,7 +49,15 @@
 
 #if 1
 #define vgawb_3d(reg,dat) \
-                (*((unsigned char *)(CyberVGARegs + (reg ^ 3))) = dat)
+	if (cv3d_on_zorro2) { \
+	*((unsigned char volatile *)((Cyber_vcode_switch_base) + 0x04)) = \
+	(0x01 & 0xffff); asm volatile ("nop"); \
+	} \
+	(*((unsigned char *)(CyberVGARegs + (reg ^ 3))) = dat); \
+	if (cv3d_on_zorro2) { \
+	*((unsigned char volatile *)((Cyber_vcode_switch_base) + 0x04)) = \
+	(0x02 & 0xffff); asm volatile ("nop"); \
+	}
 #define vgaww_3d(reg,dat) \
                 (*((unsigned word *)(CyberVGARegs + (reg ^ 2))) = swab16(dat))
 #define vgawl_3d(reg,dat) \
@@ -81,11 +88,6 @@
 #define rl_3d(reg) \
                 (*((unsigned long volatile *)(CyberRegs + reg)))
 
-
-
-
-
-
 struct virgefb_par {
    int xres;
    int yres;
@@ -101,6 +103,11 @@
 static struct display disp;
 static struct fb_info fb_info;
 
+static union {
+#ifdef FBCON_HAS_CFB16
+    u16 cfb16[16];
+#endif
+} fbcon_cmap;
 
 /*
  *    Switch for Chipset Independency
@@ -124,6 +131,7 @@
    void (*blank)(int blank);
 } *fbhw;
 
+static int blit_maybe_busy = 0;
 
 /*
  *    Frame Buffer Name
@@ -140,7 +148,7 @@
 #define VIRGE8_HEIGHT 886
 #define VIRGE8_PIXCLOCK 12500    /* ++Geert: Just a guess */
 
-#if 0
+#if 1
 #define VIRGE16_WIDTH 800
 #define VIRGE16_HEIGHT 600
 #endif
@@ -151,11 +159,21 @@
 static unsigned char Cyber_colour_table [256][3];
 static unsigned long CyberMem;
 static unsigned long CyberSize;
+#ifndef CTS_FIX
 static volatile char *CyberRegs;
 static volatile unsigned long CyberVGARegs; /* ++Andre: for CV64/3D, see macros at the beginning */
+#else
+static volatile unsigned char *CyberRegs;
+static volatile unsigned long *CyberVGARegs; /* ++Andre: for CV64/3D, see macros at the beginning */
+#endif
 static unsigned long CyberMem_phys;
 static unsigned long CyberRegs_phys;
+static unsigned long Cyber_register_base;
+static unsigned long Cyber_vcode_switch_base;
+static unsigned char cv3d_on_zorro2;
  
+#define PHYS_OFFSET_8  0x800000 /* offsets from CyberMem_phys to virge aperture */ 
+#define PHYS_OFFSET_16 0x400000 
 
 /*
  *    Predefined Video Modes
@@ -208,7 +226,7 @@
 	"800x600-16", {		/* Cybervision 16 bpp */
 	    800, 600, 800, 600, 0, 0, 16, 0,
 	    {11, 5, 0}, {5, 6, 0}, {0, 5, 0}, {0, 0, 0},
-	    0, 0, -1, -1, 0, VIRGE16_PIXCLOCK, 64, 96, 35, 12, 112, 2,
+	    0, 0, -1, -1, FB_ACCELF_TEXT, VIRGE16_PIXCLOCK, 64, 96, 35, 12, 112, 2,
 	    FB_SYNC_COMP_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
 	}
     }, {
@@ -235,7 +253,7 @@
  *    Some default modes
  */
 
-#define VIRGE8_DEFMODE     (0)
+#define VIRGE8_DEFMODE     (1)
 #define VIRGE16_DEFMODE    (6)
 
 static struct fb_var_screeninfo virgefb_default;
@@ -283,6 +301,9 @@
 static struct display_switch fbcon_virge8;
 #endif
 
+#ifdef FBCON_HAS_CFB16
+static struct display_switch fbcon_virge16;
+#endif
 
 /*
  *   Hardware Specific Routines
@@ -342,10 +363,14 @@
 	 *                (the 3D penguin might need texture memory :-) )
 	 */
 
-	memset ((char*)CyberMem, 0, 1600 * 1200);
+	memset ((char*)CyberMem, 0, /*1024*1024*16*/ 1600 * 1200 );
 
 	/* Disable hardware cursor */
-	CyberSize = 0x00400000; /* 4 MB */
+	if (cv3d_on_zorro2) {
+		CyberSize = 0x00380000; /* 3.5 MB , we need some space for the registers? */
+	} else {
+		CyberSize = 0x00400000; /* 4 MB */
+	}
 
 	vgawb_3d(0x3c8, 255);
 	vgawb_3d(0x3c9, 56);
@@ -381,7 +406,14 @@
 {
 	memset(fix, 0, sizeof(struct fb_fix_screeninfo));
 	strcpy(fix->id, virgefb_name);
-	fix->smem_start = (char*) CyberMem_phys;
+	switch (par->bpp) {
+		case 8:
+			fix->smem_start = (char*) (CyberMem_phys + PHYS_OFFSET_8);
+			break;
+		case 16:
+			fix->smem_start = (char*) (CyberMem_phys + PHYS_OFFSET_16);
+			break;
+	}
 	fix->smem_len = CyberSize;
 	fix->mmio_start = (char*) CyberRegs_phys;
 	fix->mmio_len = 0x10000; /* TODO: verify this for the CV64/3D */
@@ -452,24 +484,27 @@
 	var->bits_per_pixel = par->bpp;
 	var->grayscale = 0;
 
-	if (par->bpp == 8) {
-		var->red.offset = 0;
-		var->red.length = 6;
-		var->red.msb_right = 0;
-		var->blue = var->green = var->red;
-	} else {
-		var->red.offset = 11;
-		var->red.length = 5;
-		var->red.msb_right = 0;
-		var->green.offset = 5;
-		var->green.length = 6;
-		var->green.msb_right = 0;
-		var->blue.offset = 0;
-		var->blue.length = 5;
-		var->blue.msb_right = 0;
-	}
-	var->transp.offset = 0;
-	var->transp.length = 0;
+	switch (var->bits_per_pixel) {
+		case 8:		/* CLUT */
+			var->red.offset = 0;
+			var->red.length = 6;
+			var->red.msb_right = 0;
+			var->blue = var->green = var->red;
+			break;
+		case 16:	/* RGB 565 */
+			var->red.offset = 11;
+			var->red.length = 5;
+			var->green.offset = 5;
+			var->green.length = 6;
+			var->blue.offset = 0;
+			var->blue.length = 5;
+			var->transp.offset = 0;
+			var->transp.length = 0;
+			break;
+	}
+	var->red.msb_right = 0;
+	var->green.msb_right = 0;
+	var->blue.msb_right = 0;
 	var->transp.msb_right = 0;
 
 	var->nonstd = 0;
@@ -478,8 +513,10 @@
 	var->height = -1;
 	var->width = -1;
 
-	var->accel_flags = (par->accel && par->bpp == 8) ? FB_ACCELF_TEXT : 0;
-	DPRINTK("accel CV64/3D\n");
+ 	var->accel_flags = (par->accel &&
+		((par->bpp == 8) || (par->bpp == 16))) ? FB_ACCELF_TEXT : 0;
+
+/*	printk("CV64/3D : %s\n",(var->accel_flags ? "accel" : "no accel")); */
 
 	var->vmode = FB_VMODE_NONINTERLACED;
 
@@ -510,32 +547,37 @@
 static int Cyber_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
 			   u_int transp, struct fb_info *info)
 {
-	if (regno > 255)
-	{
-		return (1);
-	}
+	if (((current_par.bpp==8) && (regno>255)) ||
+		((current_par.bpp!=8) && (regno>15)))
+			return (1);
 
-	/*
-	 * No colors on the CV3D yet.
-	 */
-
-	vgawb_3d(0x3c8, (unsigned char) regno);
-	red >>= 10;
-	green >>= 10;
-	blue >>= 10;
-
-	Cyber_colour_table [regno][0] = red;
-	Cyber_colour_table [regno][1] = green;
-	Cyber_colour_table [regno][2] = blue;
-
-	vgawb_3d(0x3c9, red);
-	vgawb_3d(0x3c9, green);
-	vgawb_3d(0x3c9, blue);
+	if (((current_par.bpp==8) && (regno<256)) || ((current_par.bpp==16) &&(regno<16))) {
+		Cyber_colour_table [regno][0] = red >> 10;
+		Cyber_colour_table [regno][1] = green >> 10;
+		Cyber_colour_table [regno][2] = blue >> 10;
+	}
 
+	switch (current_par.bpp) {
+#ifdef FBCON_HAS_CFB8
+		case 8:
+			vgawb_3d(0x3c8, (unsigned char) regno);
+			vgawb_3d(0x3c9, ((unsigned char) (red >> 10)));
+			vgawb_3d(0x3c9, ((unsigned char) (green >> 10)));
+			vgawb_3d(0x3c9, ((unsigned char) (blue >> 10)));
+			break;
+#endif
+#ifdef FBCON_HAS_CFB16
+		case 16:
+			fbcon_cmap.cfb16[regno] =
+				((red  & 0xf800) |
+				((green & 0xfc00) >> 5) |
+				((blue  & 0xf800) >> 11));
+			break;
+#endif
+	}
 	return (0);
 }
 
-
 /*
  *    Read a single color register and split it into
  *    colors/transparent. Return != 0 for invalid regno.
@@ -546,14 +588,18 @@
 {
 	int t;
 
-	if (regno >= 256)
+	if (regno > 255)
 		return (1);
-	t       = Cyber_colour_table [regno][0];
-	*red    = (t<<10) | (t<<4) | (t>>2);
-	t       = Cyber_colour_table [regno][1];
-	*green  = (t<<10) | (t<<4) | (t>>2);
-	t       = Cyber_colour_table [regno][2];
-	*blue   = (t<<10) | (t<<4) | (t>>2);
+
+	if (((current_par.bpp==8) && (regno<256)) || ((current_par.bpp==16) && (regno<16))) {
+
+		t = Cyber_colour_table [regno][0];
+		*red    = (t<<10) | (t<<4) | (t>>2);
+		t = Cyber_colour_table [regno][1];
+		*green  = (t<<10) | (t<<4) | (t>>2);
+		t = Cyber_colour_table [regno][2];
+		*blue   = (t<<10) | (t<<4) | (t>>2);
+	}
 	*transp = 0;
 	return (0);
 }
@@ -600,9 +646,10 @@
 unsigned long status;
 
 	do {
-		iobarrier_r();
+		mb();
 		status = rl_3d(0x8504);
 	} while (!(status & (1 << 13)));
+	blit_maybe_busy = 0;
 }
 
 #define S3V_BITBLT	(0x0 << 27)
@@ -652,7 +699,10 @@
 		desty += (height - 1);
 	}
 
-	Cyber3D_WaitBusy();
+	if (blit_maybe_busy)
+		Cyber3D_WaitBusy();
+
+	blit_maybe_busy = 1;
 
 	wl_3d(0xa4f4, 1); /* pattern fb color */
 
@@ -677,7 +727,10 @@
 	unsigned int blitcmd = S3V_RECTFILL | S3V_DRAW | S3V_DST_8BPP |
 		S3V_BLT_CLEAR | S3V_MONO_PAT | (1 << 26) | (1 << 25);
 
-	Cyber3D_WaitBusy();
+	if (blit_maybe_busy)
+		Cyber3D_WaitBusy();
+
+	blit_maybe_busy = 1;
 
 	tmp = color & 0xff;
 	wl_3d(0xa4f4, tmp);
@@ -692,12 +745,14 @@
 /**************************************************************
  * Move cursor to x, y
  */
+
+#if 0
 static void Cyber_MoveCursor (u_short x, u_short y)
 {
 	printk("Yuck .... MoveCursor on a 3D\n");
 	return;
 }
-
+#endif
 
 /* -------------------- Interfaces to hardware functions -------------------- */
 
@@ -855,7 +910,14 @@
 	virgefb_get_fix(&fix, con, info);
 	if (con == -1)
 		con = 0;
-	display->screen_base = (char*) CyberMem;
+        switch (display->var.bits_per_pixel) {
+		case 8:
+			display->screen_base = (char*) phys_to_virt(CyberMem_phys + PHYS_OFFSET_8);
+			break;
+		case 16:
+			display->screen_base = (char*) phys_to_virt(CyberMem_phys + PHYS_OFFSET_16);
+			break;
+	}
 	display->visual = fix.visual;
 	display->type = fix.type;
 	display->type_aux = fix.type_aux;
@@ -865,26 +927,31 @@
 	display->inverse = Cyberfb_inverse;
 	switch (display->var.bits_per_pixel) {
 #ifdef FBCON_HAS_CFB8
-	    case 8:
-		if (display->var.accel_flags & FB_ACCELF_TEXT) {
-		    display->dispsw = &fbcon_virge8;
+		case 8:
+			if (display->var.accel_flags & FB_ACCELF_TEXT) {
+		   		display->dispsw = &fbcon_virge8;
 #warning FIXME: We should reinit the graphics engine here
-		} else
-		    display->dispsw = &fbcon_virge8;
-		break;
+			} else
+				display->dispsw = &fbcon_cfb8;
+			break;
 #endif
 #ifdef FBCON_HAS_CFB16
-	    case 16:
-		display->dispsw = &fbcon_cfb16;
-		break;
+		case 16:
+			if (display->var.accel_flags & FB_ACCELF_TEXT) {
+				display->dispsw = &fbcon_virge16;
+			} else
+				display->dispsw = &fbcon_cfb16;
+			display->dispsw_data = &fbcon_cmap.cfb16;
+			break;
 #endif
-	    default:
-		display->dispsw = &fbcon_dummy;
-		break;
+		default:
+			display->dispsw = &fbcon_dummy;
+			break;
 	}
 }
 
 
+
 /*
  *    Set the User Defined Part of the Display
  */
@@ -949,7 +1016,7 @@
 
 	if (!fb_display[con].cmap.len) {       /* no colormap allocated? */
 		if ((err = fb_alloc_cmap(&fb_display[con].cmap,
-				 1<<fb_display[con].var.bits_per_pixel, 0)))
+				1<<fb_display[con].var.bits_per_pixel, 0)))
 			return(err);
 	}
 	if (con == currcon)		 /* current console? */
@@ -974,8 +1041,8 @@
 
 
 /*
-    *	 Cybervision Frame Buffer Specific ioctls
-    */
+ *	 Cybervision Frame Buffer Specific ioctls
+ */
 
 static int virgefb_ioctl(struct inode *inode, struct file *file,
 			 u_int cmd, u_long arg, int con, struct fb_info *info)
@@ -1047,8 +1114,16 @@
 
 		CyberMem_phys = board_addr;
 		CyberMem = ZTWO_VADDR(CyberMem_phys);
-		printk("CV3D detected running in Z2 mode ... not yet supported!\n");
-		return;
+		CyberVGARegs = (unsigned long) \
+			ZTWO_VADDR(board_addr + 0x003c0000);
+		CyberRegs_phys = (unsigned long)(board_addr + 0x003e0000);
+		CyberRegs = (unsigned char *)ZTWO_VADDR(CyberRegs_phys);
+		Cyber_register_base = (unsigned long) \
+			ZTWO_VADDR(board_addr + 0x003c8000);
+		Cyber_vcode_switch_base = (unsigned long) \
+			ZTWO_VADDR(board_addr + 0x003a0000);
+		cv3d_on_zorro2 = 1;
+		printk("CV3D detected running in Z2 mode.\n");
 	}
 	else
 	{
@@ -1056,12 +1131,13 @@
 					       KERNELMAP_NOCACHE_SER, NULL);
 
 		CyberRegs_phys = board_addr + 0x05000000;
-		CyberMem_phys  = board_addr + 0x04800000;
+		CyberMem_phys  = board_addr + 0x04000000;
 		CyberRegs = (char *)kernel_map(CyberRegs_phys,
 					       0x00010000,
 					       KERNELMAP_NOCACHE_SER, NULL);
-		CyberMem = kernel_map(CyberMem_phys, 0x00400000,
-				      KERNELMAP_NOCACHE_SER, NULL);
+		CyberMem = kernel_map(CyberMem_phys, 0x01000000,
+				      KERNELMAP_NOCACHE_SER, NULL); /* 16 Meg of video ram */
+		cv3d_on_zorro2 = 0;
 		printk("CV3D detected running in Z3 mode\n");
 	}
 
@@ -1086,8 +1162,10 @@
 	virgefb_set_disp(-1, &fb_info);
 	do_install_cmap(0, &fb_info);
 
-	if (register_framebuffer(&fb_info) < 0)
+	if (register_framebuffer(&fb_info) < 0) {
+		printk("virgefb.c: register_framebuffer failed\n");
 		return;
+	}
 
 	printk("fb%d: %s frame buffer device, using %ldK of video memory\n",
 	       GET_FB_IDX(fb_info.node), fb_info.modename, CyberSize>>10);
@@ -1126,8 +1204,8 @@
 
 
 /*
-    *    Blank the display.
-    */
+ *    Blank the display.
+ */
 
 static void Cyberfb_blank(int blank, struct fb_info *info)
 {
@@ -1184,37 +1262,100 @@
 static void fbcon_virge8_putc(struct vc_data *conp, struct display *p, int c, int yy,
                               int xx)
 {
-        Cyber3D_WaitBusy();
-        fbcon_cfb8_putc(conp, p, c, yy, xx);
+	if (blit_maybe_busy)
+		Cyber3D_WaitBusy();
+	fbcon_cfb8_putc(conp, p, c, yy, xx);
 }
 
 static void fbcon_virge8_putcs(struct vc_data *conp, struct display *p,
                       const unsigned short *s, int count, int yy, int xx)
 {
-        Cyber3D_WaitBusy();
-        fbcon_cfb8_putcs(conp, p, s, count, yy, xx);
+	if (blit_maybe_busy)
+		Cyber3D_WaitBusy();
+	fbcon_cfb8_putcs(conp, p, s, count, yy, xx);
 }
 
 static void fbcon_virge8_revc(struct display *p, int xx, int yy)
 {
-        Cyber3D_WaitBusy();
-        fbcon_cfb8_revc(p, xx, yy);
+	if (blit_maybe_busy)
+		Cyber3D_WaitBusy();
+	fbcon_cfb8_revc(p, xx, yy);
 }
 
 static void fbcon_virge8_clear_margins(struct vc_data *conp, struct display *p,
                               int bottom_only)
 {
-        Cyber3D_WaitBusy();
-        fbcon_cfb8_clear_margins(conp, p, bottom_only);
+	if (blit_maybe_busy)
+		Cyber3D_WaitBusy();
+	fbcon_cfb8_clear_margins(conp, p, bottom_only);
 }
 
 static struct display_switch fbcon_virge8 = {
    fbcon_cfb8_setup, fbcon_virge8_bmove, fbcon_virge8_clear, fbcon_virge8_putc,
    fbcon_virge8_putcs, fbcon_virge8_revc, NULL, NULL, fbcon_virge8_clear_margins,
-   FONTWIDTH(8)
+   FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16)
 };
 #endif
 
+#ifdef FBCON_HAS_CFB16
+static void fbcon_virge16_bmove(struct display *p, int sy, int sx, int dy,
+                               int dx, int height, int width)
+{
+        sx *= 16; dx *= 16; width *= 16;
+        Cyber3D_BitBLT((u_short)sx, (u_short)(sy*fontheight(p)), (u_short)dx,
+                       (u_short)(dy*fontheight(p)), (u_short)width,
+                       (u_short)(height*fontheight(p)));
+}
+                
+static void fbcon_virge16_clear(struct vc_data *conp, struct display *p, int sy,
+                               int sx, int height, int width)
+{
+        unsigned char bg;   
+                
+        sx *= 16; width *= 16;
+        bg = attr_bgcol_ec(p,conp);
+        Cyber3D_RectFill((u_short)sx, (u_short)(sy*fontheight(p)),
+                         (u_short)width, (u_short)(height*fontheight(p)),
+                         (u_short)bg);
+}
+   
+static void fbcon_virge16_putc(struct vc_data *conp, struct display *p, int c, int yy,
+                              int xx)
+{
+	if (blit_maybe_busy)
+		Cyber3D_WaitBusy();
+	fbcon_cfb16_putc(conp, p, c, yy, xx);
+}
+
+static void fbcon_virge16_putcs(struct vc_data *conp, struct display *p,
+                      const unsigned short *s, int count, int yy, int xx)
+{
+	if (blit_maybe_busy)
+		Cyber3D_WaitBusy();
+	fbcon_cfb16_putcs(conp, p, s, count, yy, xx);
+}
+
+static void fbcon_virge16_revc(struct display *p, int xx, int yy)
+{
+	if (blit_maybe_busy)
+		Cyber3D_WaitBusy();
+	fbcon_cfb16_revc(p, xx, yy);
+}
+
+static void fbcon_virge16_clear_margins(struct vc_data *conp, struct display *p,
+                              int bottom_only)
+{
+	if (blit_maybe_busy)
+		Cyber3D_WaitBusy();
+	fbcon_cfb16_clear_margins(conp, p, bottom_only);
+}
+
+static struct display_switch fbcon_virge16 = {
+   fbcon_cfb16_setup, fbcon_virge16_bmove, fbcon_virge16_clear, fbcon_virge16_putc,
+   fbcon_virge16_putcs, fbcon_virge16_revc, NULL, NULL, fbcon_virge16_clear_margins,
+   FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16)
+};
+#endif
 
 #ifdef MODULE
 int init_module(void)


----------------


