patch-2.2.17 linux/drivers/video/offb.c

Next file: linux/drivers/video/pm2fb.c
Previous file: linux/drivers/video/matroxfb.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.2.16/drivers/video/offb.c linux/drivers/video/offb.c
@@ -42,6 +42,15 @@
 
 static int currcon = 0;
 
+/* Supported palette hacks */
+enum {
+	cmap_unknown,
+	cmap_m64,	/* ATI Mach64 */
+	cmap_r128,	/* ATI Rage128 */
+	cmap_M3A,	/* ATI Rage Mobility M3 Head A */
+	cmap_M3B	/* ATI Rage Mobility M3 Head B */
+};
+
 struct fb_info_offb {
     struct fb_info info;
     struct fb_fix_screeninfo fix;
@@ -50,6 +59,7 @@
     struct { u_char red, green, blue, pad; } palette[256];
     volatile unsigned char *cmap_adr;
     volatile unsigned char *cmap_data;
+    int cmap_type;
     union {
 #ifdef FBCON_HAS_CFB16
 	u16 cfb16[16];
@@ -106,7 +116,8 @@
 static int offb_init_driver(struct device_node *);
 static void offb_init_nodriver(struct device_node *);
 static void offb_init_fb(const char *name, const char *full_name, int width,
-		      int height, int depth, int pitch, unsigned long address);
+		      int height, int depth, int pitch, unsigned long address,
+		      struct device_node *dp);
 
     /*
      *  Interface to the low level console driver
@@ -293,6 +304,9 @@
 #ifdef CONFIG_FB_ATY
 extern void atyfb_of_init(struct device_node *dp);
 #endif /* CONFIG_FB_ATY */
+#if defined(CONFIG_FB_ATY128)
+extern void aty128fb_of_init(struct device_node *dp);
+#endif /* CONFIG_FB_ATY128 */
 #ifdef CONFIG_FB_S3TRIO
 extern void s3triofb_init_of(struct device_node *dp);
 #endif /* CONFIG_FB_S3TRIO */
@@ -362,6 +376,20 @@
 	    }
 
 	    /*
+	     * The M3 on the Pismo powerbook has no addresses
+	     * on the display nodes, they are on their parent.
+	     */
+	    if (dp->n_addrs == 0 && device_is_compatible(dp, "ATY,RageM3p")) {
+		int na;
+		unsigned int *ap = (unsigned int *)
+		    get_property(dp, "AAPL,address", &na);
+		if (ap != 0)
+		    for (na /= sizeof(unsigned int); na > 0; --na, ++ap)
+			if (*ap <= addr && addr < *ap + 0x1000000)
+			    goto foundit;
+	    }
+
+	    /*
 	     * See if the display address is in one of the address
 	     * ranges for this display.
 	     */
@@ -386,7 +414,7 @@
 			 boot_infos->dispDeviceRect[2],
 			 boot_infos->dispDeviceRect[3],
 			 boot_infos->dispDeviceDepth,
-			 boot_infos->dispDeviceRowBytes, addr);
+			 boot_infos->dispDeviceRowBytes, addr, 0);
 	}
     }
 
@@ -409,6 +437,15 @@
 
 __initfunc(static int offb_init_driver(struct device_node *dp))
 {
+#ifdef CONFIG_FB_ATY128
+    if (!strncmp(dp->name, "ATY,Rage128", 11) ||
+    	!strncmp(dp->name, "ATY,RageM3pA", 12)) {
+	aty128fb_of_init(dp);
+	return 1;
+    }
+    if (!strncmp(dp->name, "ATY,RageM3pB", 12))
+    	return 0;
+#endif /* CONFIG_FB_ATY128*/
 #ifdef CONFIG_FB_ATY
     if (!strncmp(dp->name, "ATY", 3)) {
 	atyfb_of_init(dp);
@@ -477,9 +514,11 @@
 	&& len == sizeof(int))
 	height = *pp;
     if ((pp = (int *)get_property(dp, "linebytes", &len)) != NULL
-	&& len == sizeof(int))
+	&& len == sizeof(int)) {
 	pitch = *pp;
-    else
+	if (pitch == 1)
+	    pitch = 0x1000;
+    } else
 	pitch = width;
     if ((up = (unsigned *)get_property(dp, "address", &len)) != NULL
 	&& len == sizeof(unsigned))
@@ -500,13 +539,14 @@
 	    address += 0x1000;
     }
     offb_init_fb(dp->name, dp->full_name, width, height, depth,
-		 pitch, address);
+		 pitch, address, dp);
     
 }
 
 __initfunc(static void offb_init_fb(const char *name, const char *full_name,
 				    int width, int height, int depth,
-				    int pitch, unsigned long address))
+				    int pitch, unsigned long address,
+				    struct device_node *dp))
 {
     int i;
     struct fb_fix_screeninfo *fix;
@@ -543,13 +583,27 @@
     fix->type = FB_TYPE_PACKED_PIXELS;
     fix->type_aux = 0;
 
+    info->cmap_type = cmap_unknown;
     if (depth == 8)
     {
     	/* XXX kludge for ati */
-    	if (strncmp(name, "ATY,", 4) == 0) {
+	if (dp && !strncmp(name, "ATY,Rage128", 11)) {
+		unsigned long regbase = dp->addrs[2].address;
+		info->cmap_adr = ioremap(regbase, 0x1FFF);
+		info->cmap_type = cmap_r128;
+	} else if (dp && !strncmp(name, "ATY,RageM3pA", 12)) {
+		unsigned long regbase = dp->parent->addrs[2].address;
+		info->cmap_adr = ioremap(regbase, 0x1FFF);
+		info->cmap_type = cmap_M3A;
+	} else if (dp && !strncmp(name, "ATY,RageM3pB", 12)) {
+		unsigned long regbase = dp->parent->addrs[2].address;
+		info->cmap_adr = ioremap(regbase, 0x1FFF);
+		info->cmap_type = cmap_M3B;
+	} else if (!strncmp(name, "ATY,", 4)) {
 		unsigned long base = address & 0xff000000UL;
 		info->cmap_adr = ioremap(base + 0x7ff000, 0x1000) + 0xcc0;
 		info->cmap_data = info->cmap_adr + 1;
+		info->cmap_type = cmap_m64;
 	}
         fix->visual = info->cmap_adr ? FB_VISUAL_PSEUDOCOLOR
 				     : FB_VISUAL_STATIC_PSEUDOCOLOR;
@@ -706,7 +760,7 @@
 	display_info.cmap_data_address = 0;
 	display_info.disp_reg_address = 0;
 	/* XXX kludge for ati */
-	if (strncmp(name, "ATY,", 4) == 0) {
+	if (info->cmap_type == cmap_m64) {
 	    unsigned long base = address & 0xff000000UL;
 	    display_info.disp_reg_address = base + 0x7ffc00;
 	    display_info.cmap_adr_address = base + 0x7ffcc0;
@@ -767,12 +821,33 @@
 	return;
 
     if (blank)
-	for (i = 0; i < 256; i++) {
-	    *info2->cmap_adr = i;
-	    mach_eieio();
-	    for (j = 0; j < 3; j++) {
-		*info2->cmap_data = 0;
-		mach_eieio();
+        for (i = 0; i < 256; i++) {
+	    switch(info2->cmap_type) {
+	    case cmap_m64:
+	        *info2->cmap_adr = i;
+	  	mach_eieio();
+	  	for (j = 0; j < 3; j++) {
+		    *info2->cmap_data = 0;
+		    mach_eieio();
+	    	}
+	    	break;
+	    case cmap_M3A:
+	        /* Clear PALETTE_ACCESS_CNTL in DAC_CNTL */
+	    	out_le32((unsigned *)(info2->cmap_adr + 0x58),
+	    		in_le32((unsigned *)(info2->cmap_adr + 0x58)) & ~0x20);
+	    case cmap_r128:
+	    	/* Set palette index & data */
+    	        out_8(info2->cmap_adr + 0xb0, i);
+	    	out_le32((unsigned *)(info2->cmap_adr + 0xb4), 0);
+	    	break;
+	    case cmap_M3B:
+	        /* Set PALETTE_ACCESS_CNTL in DAC_CNTL */
+	    	out_le32((unsigned *)(info2->cmap_adr + 0x58),
+	    		in_le32((unsigned *)(info2->cmap_adr + 0x58)) | 0x20);
+	    	/* Set palette index & data */
+	    	out_8(info2->cmap_adr + 0xb0, i);
+	    	out_le32((unsigned *)(info2->cmap_adr + 0xb4), 0);
+	    	break;
 	    }
 	}
     else
@@ -823,14 +898,37 @@
     info2->palette[regno].green = green;
     info2->palette[regno].blue = blue;
 
-    *info2->cmap_adr = regno;/* On some chipsets, add << 3 in 15 bits */
-    mach_eieio();
-    *info2->cmap_data = red;
-    mach_eieio();
-    *info2->cmap_data = green;
-    mach_eieio();
-    *info2->cmap_data = blue;
-    mach_eieio();
+    switch(info2->cmap_type) {
+    case cmap_m64:
+        *info2->cmap_adr = regno;
+	mach_eieio();
+	*info2->cmap_data = red;
+	mach_eieio();
+	*info2->cmap_data = green;
+	mach_eieio();
+	*info2->cmap_data = blue;
+	mach_eieio();
+	break;
+    case cmap_M3A:
+	/* Clear PALETTE_ACCESS_CNTL in DAC_CNTL */
+	out_le32((unsigned *)(info2->cmap_adr + 0x58),
+		in_le32((unsigned *)(info2->cmap_adr + 0x58)) & ~0x20);
+    case cmap_r128:
+	/* Set palette index & data */
+	out_8(info2->cmap_adr + 0xb0, regno);
+	out_le32((unsigned *)(info2->cmap_adr + 0xb4),
+		(red << 16 | green << 8 | blue));
+	break;
+    case cmap_M3B:
+        /* Set PALETTE_ACCESS_CNTL in DAC_CNTL */
+    	out_le32((unsigned *)(info2->cmap_adr + 0x58),
+    		in_le32((unsigned *)(info2->cmap_adr + 0x58)) | 0x20);
+    	/* Set palette index & data */
+    	out_8(info2->cmap_adr + 0xb0, regno);
+  	out_le32((unsigned *)(info2->cmap_adr + 0xb4),
+    		(red << 16 | green << 8 | blue));
+    	break;
+    }
 
     if (regno < 16)
 	switch (info2->var.bits_per_pixel) {

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)