Resent-Date: Fri, 29 Jan 1999 09:36:18 +0100 (MET)
Date: Fri, 29 Jan 1999 09:38:05 +0100 (CET)
From: "Christian T. Steigies" <cts@ap031.experimentalphysik.uni-kiel.de>
Reply-To: "Christian T. Steigies" <steigies@physik.uni-kiel.de>
To: Ken Tyler <kent@werple.net.au>
cc: linux-apus@sunsite.auc.dk, linux-m68k <linux-m68k@lists.linux-m68k.org>
Subject: Re: Patch for 16 bit on CV64-3D
In-Reply-To: <Pine.AMI.3.96.990128084911.138832584A-100000@werple.net.au>
Resent-From: linux-m68k@phil.uni-sb.de

Hi Ken, hi all, 
I applied your patch to the 2.2.0pre7 tree, since this is the current devel
tree(?). The Zorro2 patches were allready in the tree and I think you have
forgotten some lines in the patch. Anyway, I edited it and now I have your
patch against a (hopefully) fresh 2.2.0pre7 tree, please double check.

The 16bit patch will not work like this on Zorro2. Thus I used the
cv3d_on_zorro2 flag to preserve the old behaviour for Zorro2 systems.
AFAIK we can not access video memory for 16 bit modes at another address,
there is not that much space available on Zorro2. I guess it has to be done
by some switching, similar to the Cyberwb_3d patch, but I don't know what to
switch... till we know, I propose we stick to the old behaviour for Z2.
I append the patch for 2.2.0pre7 with these changes, please test.

Note to Roman H.: Ken's patch was relative to 2.1.131, please move it :-)

PS Ignore the time stamp on the patch. If somebody has a spare accu/clock
for my A2k, I need to fix that soon...

Ciao,
Christian.

--- drivers/video/virgefb.c.orig	Thu Jan 28 20:18:18 1999
+++ drivers/video/virgefb.c	Tue Mar 16 01:48:48 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
@@ -89,11 +88,6 @@
 #define rl_3d(reg) \
                 (*((unsigned long volatile *)(CyberRegs + reg)))
 
-
-
-
-
-
 struct virgefb_par {
    int xres;
    int yres;
@@ -109,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
@@ -132,6 +131,7 @@
    void (*blank)(int blank);
 } *fbhw;
 
+static int blit_maybe_busy = 0;
 
 /*
  *    Frame Buffer Name
@@ -148,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
@@ -167,6 +167,8 @@
 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 /* ++CTS: this will not work on Z2 !!! */
 
 /*
  *    Predefined Video Modes
@@ -219,7 +221,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
 	}
     }, {
@@ -246,7 +248,7 @@
  *    Some default modes
  */
 
-#define VIRGE8_DEFMODE     (0)
+#define VIRGE8_DEFMODE     (1)
 #define VIRGE16_DEFMODE    (6)
 
 static struct fb_var_screeninfo virgefb_default;
@@ -291,9 +293,14 @@
  */
 
 #ifdef FBCON_HAS_CFB8
+#warning FBCON_HAS_CFB8
 static struct display_switch fbcon_virge8;
 #endif
 
+#ifdef FBCON_HAS_CFB16
+#warning FBCON_HAS_CFB16
+static struct display_switch fbcon_virge16;
+#endif
 
 /*
  *   Hardware Specific Routines
@@ -353,7 +360,7 @@
 	 *                (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 */
 	if (cv3d_on_zorro2) {
@@ -396,7 +403,25 @@
 {
 	memset(fix, 0, sizeof(struct fb_fix_screeninfo));
 	strcpy(fix->id, virgefb_name);
-	fix->smem_start = (char*) CyberMem_phys;
+	if (cv3d_on_zorro2) {
+/*
+ *	++CTS: address space on Z2 is somewhat limited, we need another way
+ *	to acces the memory for the 16 bits modes, probably with the
+ *  	Cyber_vcode_switch_base register. Until we know how, we prefer to
+ *	stick with 8 bit modes only on Z2. 8 is better than 0, isnt it? 
+ * 	Please note that you can boot in a 16 bit mode, but you shouldn't...
+ */	
+		fix->smem_start = (char*) CyberMem_phys;
+	} else {
+		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 */
@@ -467,24 +492,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;
@@ -493,8 +521,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;
 
@@ -525,32 +555,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);
-	}
-
-	/*
-	 * No colors on the CV3D yet.
-	 */
+	if (((current_par.bpp==8) && (regno>255)) ||
+		((current_par.bpp!=8) && (regno>15)))
+			return (1);
 
-	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.
@@ -561,14 +596,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);
 }
@@ -615,8 +654,10 @@
 unsigned long status;
 
 	do {
+		mb();
 		status = rl_3d(0x8504);
 	} while (!(status & (1 << 13)));
+	blit_maybe_busy = 0;	
 }
 
 #define S3V_BITBLT	(0x0 << 27)
@@ -677,7 +718,13 @@
 
 	wl_3d(0xa500, blitcmd);				/* GO! */
 
-	Cyber3D_WaitBusy();
+	if (blit_maybe_busy)
+		Cyber3D_WaitBusy();
+	
+	blit_maybe_busy = 1;
+	
+	
+#endif
 }
 
 /*
@@ -698,19 +745,28 @@
 	wl_3d(0xa50c, ((x << 16) | y));			/* rdest_xy */
 
 	wl_3d(0xa500, blitcmd);				/* GO! */
-	Cyber3D_WaitBusy();
+
+	if (blit_maybe_busy)
+		Cyber3D_WaitBusy();
+
+	blit_maybe_busy = 1;
+#endif
+
 }
 
 
 /**************************************************************
  * 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;
+/* ++CTS: we can switch the cursor off, shouldn't be hard to move it? */
 }
-
+#endif
 
 /* -------------------- Interfaces to hardware functions -------------------- */
 
@@ -868,7 +924,22 @@
 	virgefb_get_fix(&fix, con, info);
 	if (con == -1)
 		con = 0;
-	display->screen_base = (char*) CyberMem;
+	if(cv3d_on_zorro2) {
+/*
+ *	++CTS: See above. Right know we can handle only 8 bit modes on Z2
+ */	
+		display->screen_base = (char*) CyberMem;
+	} else {
+	
+        	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;
@@ -878,26 +949,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
  */
@@ -962,7 +1038,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? */
@@ -987,8 +1063,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)
@@ -1076,9 +1152,9 @@
 		CyberVGARegs = ioremap(board_addr +0x0c000000, 0x00010000);
 
 		CyberRegs_phys = board_addr + 0x05000000;
-		CyberMem_phys  = board_addr + 0x04800000;
+		CyberMem_phys  = board_addr + 0x04000000;
 		CyberRegs = ioremap(CyberRegs_phys, 0x00010000);
-		CyberMem = ioremap(CyberMem_phys, 0x00400000);
+		CyberMem = ioremap(CyberMem_phys, 0x01000000); /* 16 Meg of video ram */		
 		cv3d_on_zorro2 = 0;
 		printk("CV3D detected running in Z3 mode\n");
 	}
@@ -1146,8 +1222,8 @@
 
 
 /*
-    *    Blank the display.
-    */
+ *    Blank the display.
+ */
 
 static void Cyberfb_blank(int blank, struct fb_info *info)
 {
@@ -1200,14 +1276,105 @@
                          (u_short)width, (u_short)(height*fontheight(p)),
                          (u_short)bg);
 }
+static void fbcon_virge8_putc(struct vc_data *conp, struct display *p, int c, int yy, 
+	int 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)
+{
+	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)
+{
+	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)
+{
+	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_cfb8_putc,
    fbcon_cfb8_putcs, fbcon_cfb8_revc, NULL, NULL, fbcon_cfb8_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)

