macfb: fix 24-bit visual and stuff

Lots of changes. Remove volatile keywords. Take the advice in the comments
and change video_slot to slot_addr. Factor out fifteen or so "channel >>
8" shifts into three shifts higher up the call graph. Make
csc_setpalette() atomic, pass the correct color values. Check for
ioremap() failure. Add missing break statement, thus fixing 24 bit console
visual (blue background bug). Remove some uninformative printk() noise.
Add a description for powerbook 140/170 graphics.

Signed-off-by: Finn Thain <fthain@telegraphics.com.au>
Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org>
diff --git a/drivers/video/macfb.c b/drivers/video/macfb.c
index 8b246ee..43207cc 100644
--- a/drivers/video/macfb.c
+++ b/drivers/video/macfb.c
@@ -120,8 +120,6 @@
 
 #define PIXEL_TO_MM(a)	(((a)*10)/28)	/* width in mm at 72 dpi */
 
-static int  video_slot = 0;
-
 static struct fb_var_screeninfo macfb_defined = {
 	.bits_per_pixel	= 8,
 	.activate	= FB_ACTIVATE_NOW,
@@ -139,6 +137,7 @@
 	.accel	= FB_ACCEL_NONE,
 };
 
+static void *slot_addr;
 static struct fb_info fb_info;
 static u32 pseudo_palette[16];
 static int inverse;
@@ -156,10 +155,6 @@
 {
 	static int lastreg = -1;
 	unsigned long flags;
-	
-	red >>= 8;
-	green >>= 8;
-	blue >>= 8;
 
 	local_irq_save(flags);
 
@@ -205,10 +200,6 @@
 				struct fb_info *info)
 {
 	unsigned int bpp = info->var.bits_per_pixel;
-	unsigned char _red  =red>>8;
-	unsigned char _green=green>>8;
-	unsigned char _blue =blue>>8;
-	unsigned char _regno;
 	unsigned long flags;
 
 	if (bpp > 8)
@@ -222,16 +213,16 @@
 	 * In 4bpp, the regnos are 0x0f, 0x1f, 0x2f, etc, etc
 	 * In 2bpp, the regnos are 0x3f, 0x7f, 0xbf, 0xff
 	 */
-	_regno = (regno << (8 - bpp)) | (0xFF >> bpp);
-	nubus_writeb(_regno, &v8_brazil_cmap_regs->addr);
+	regno = (regno << (8 - bpp)) | (0xFF >> bpp);
+	nubus_writeb(regno, &v8_brazil_cmap_regs->addr);
 	nop();
 
 	/* send one color channel at a time */
-	nubus_writeb(_red, &v8_brazil_cmap_regs->lut);
+	nubus_writeb(red, &v8_brazil_cmap_regs->lut);
 	nop();
-	nubus_writeb(_green, &v8_brazil_cmap_regs->lut);
+	nubus_writeb(green, &v8_brazil_cmap_regs->lut);
 	nop();
-	nubus_writeb(_blue, &v8_brazil_cmap_regs->lut);
+	nubus_writeb(blue, &v8_brazil_cmap_regs->lut);
 
 	local_irq_restore(flags);
 	return 0;
@@ -242,11 +233,6 @@
 			  unsigned int green, unsigned int blue,
 			  struct fb_info *info)
 {
-	/* use MSBs */
-	unsigned char _red  =red>>8;
-	unsigned char _green=green>>8;
-	unsigned char _blue =blue>>8;
-	unsigned char _regno;
 	unsigned long flags;
 
 	if (info->var.bits_per_pixel > 8)
@@ -258,22 +244,22 @@
 	 * regno #254 and #255 are the important ones for 1-bit color,
 	 * regno #252-255 are the important ones for 2-bit color, etc.
 	 */
-	_regno = regno + (256-(1 << info->var.bits_per_pixel));
+	regno += 256 - (1 << info->var.bits_per_pixel);
 
 	/* reset clut? (VideoToolbox sez "not necessary") */
 	nubus_writeb(0xFF, &rbv_cmap_regs->cntl);
 	nop();
 
 	/* tell clut which address to use. */
-	nubus_writeb(_regno, &rbv_cmap_regs->addr);
+	nubus_writeb(regno, &rbv_cmap_regs->addr);
 	nop();
 
 	/* send one color channel at a time. */
-	nubus_writeb(_red, &rbv_cmap_regs->lut);
+	nubus_writeb(red, &rbv_cmap_regs->lut);
 	nop();
-	nubus_writeb(_green, &rbv_cmap_regs->lut);
+	nubus_writeb(green, &rbv_cmap_regs->lut);
 	nop();
-	nubus_writeb(_blue, &rbv_cmap_regs->lut);
+	nubus_writeb(blue, &rbv_cmap_regs->lut);
 
 	local_irq_restore(flags);
 	return 0;
@@ -284,25 +270,19 @@
 			  unsigned int green, unsigned int blue,
 			  struct fb_info *info)
 {
-	volatile struct mdc_cmap_regs *cmap_regs =
-		nubus_slot_addr(video_slot);
-	/* use MSBs */
-	unsigned char _red  =red>>8;
-	unsigned char _green=green>>8;
-	unsigned char _blue =blue>>8;
-	unsigned char _regno=regno;
+	struct mdc_cmap_regs *cmap_regs = slot_addr;
 	unsigned long flags;
 
 	local_irq_save(flags);
 
 	/* the nop's are there to order writes. */
-	nubus_writeb(_regno, &cmap_regs->addr);
+	nubus_writeb(regno, &cmap_regs->addr);
 	nop();
-	nubus_writeb(_red, &cmap_regs->lut);
+	nubus_writeb(red, &cmap_regs->lut);
 	nop();
-	nubus_writeb(_green, &cmap_regs->lut);
+	nubus_writeb(green, &cmap_regs->lut);
 	nop();
-	nubus_writeb(_blue, &cmap_regs->lut);
+	nubus_writeb(blue, &cmap_regs->lut);
 
 	local_irq_restore(flags);
 	return 0;
@@ -313,25 +293,24 @@
 			   unsigned int green, unsigned int blue,
 			   struct fb_info *info)
 {
-	volatile struct toby_cmap_regs *cmap_regs =
-		nubus_slot_addr(video_slot);
+	struct toby_cmap_regs *cmap_regs = slot_addr;
 	unsigned int bpp = info->var.bits_per_pixel;
-	/* use MSBs */
-	unsigned char _red  =~(red>>8);
-	unsigned char _green=~(green>>8);
-	unsigned char _blue =~(blue>>8);
-	unsigned char _regno = (regno << (8 - bpp)) | (0xFF >> bpp);
 	unsigned long flags;
 
+	red = ~red;
+	green = ~green;
+	blue = ~blue;
+	regno = (regno << (8 - bpp)) | (0xFF >> bpp);
+
 	local_irq_save(flags);
 
-	nubus_writeb(_regno, &cmap_regs->addr);
+	nubus_writeb(regno, &cmap_regs->addr);
 	nop();
-	nubus_writeb(_red, &cmap_regs->lut);
+	nubus_writeb(red, &cmap_regs->lut);
 	nop();
-	nubus_writeb(_green, &cmap_regs->lut);
+	nubus_writeb(green, &cmap_regs->lut);
 	nop();
-	nubus_writeb(_blue, &cmap_regs->lut);
+	nubus_writeb(blue, &cmap_regs->lut);
 
 	local_irq_restore(flags);
 	return 0;
@@ -342,23 +321,18 @@
 			  unsigned int green, unsigned int blue,
 			  struct fb_info *info)
 {
-	volatile struct jet_cmap_regs *cmap_regs =
-		nubus_slot_addr(video_slot);
-	/* use MSBs */
-	unsigned char _red   = (red>>8);
-	unsigned char _green = (green>>8);
-	unsigned char _blue  = (blue>>8);
+	struct jet_cmap_regs *cmap_regs = slot_addr;
 	unsigned long flags;
 
 	local_irq_save(flags);
 
 	nubus_writeb(regno, &cmap_regs->addr);
 	nop();
-	nubus_writeb(_red, &cmap_regs->lut);
+	nubus_writeb(red, &cmap_regs->lut);
 	nop();
-	nubus_writeb(_green, &cmap_regs->lut);
+	nubus_writeb(green, &cmap_regs->lut);
 	nop();
-	nubus_writeb(_blue, &cmap_regs->lut);
+	nubus_writeb(blue, &cmap_regs->lut);
 
 	local_irq_restore(flags);
 	return 0;
@@ -383,10 +357,6 @@
 	if (info->var.bits_per_pixel > 8)
 		return 1; /* failsafe */
 
-	red   >>= 8;
-	green >>= 8;
-	blue  >>= 8;
-
 	local_irq_save(flags);
 
 	/* Set the register address */
@@ -462,11 +432,17 @@
 			  unsigned int green, unsigned int blue,
 			  struct fb_info *info)
 {
-	mdelay(1);
+	unsigned long flags;
+
+	local_irq_save(flags);
+
+	udelay(1); /* mklinux on PB 5300 waits for 260 ns */
 	nubus_writeb(regno, &csc_cmap_regs->clut_waddr);
-	nubus_writeb(red,   &csc_cmap_regs->clut_data);
+	nubus_writeb(red, &csc_cmap_regs->clut_data);
 	nubus_writeb(green, &csc_cmap_regs->clut_data);
-	nubus_writeb(blue,  &csc_cmap_regs->clut_data);
+	nubus_writeb(blue, &csc_cmap_regs->clut_data);
+
+	local_irq_restore(flags);
 	return 0;
 }
 
@@ -493,8 +469,8 @@
 		case 4:
 		case 8:
 			if (macfb_setpalette)
-				macfb_setpalette(regno, red, green, blue,
-						 fb_info);
+				macfb_setpalette(regno, red >> 8, green >> 8,
+						 blue >> 8, fb_info);
 			else
 				return 1;
 			break;
@@ -611,8 +587,11 @@
 	 * those mappings are set up, so this is in fact the safest
 	 * way to ensure that this driver will work on every possible Mac
 	 */
-	fb_info.screen_base = ioremap(mac_bi_data.videoaddr, macfb_fix.smem_len);
-	
+	fb_info.screen_base = ioremap(mac_bi_data.videoaddr,
+				      macfb_fix.smem_len);
+	if (!fb_info.screen_base)
+		return -ENODEV;
+
 	printk("macfb: framebuffer at 0x%08lx, mapped to 0x%p, size %dk\n",
 	       macfb_fix.smem_start, fb_info.screen_base,
 	       macfb_fix.smem_len / 1024);
@@ -620,17 +599,13 @@
 	       macfb_defined.xres, macfb_defined.yres,
 	       macfb_defined.bits_per_pixel, macfb_fix.line_length);
 
-	/*
-	 * Fill in the available video resolution
-	 */
+	/* Fill in the available video resolution */
 	macfb_defined.xres_virtual = macfb_defined.xres;
 	macfb_defined.yres_virtual = macfb_defined.yres;
 	macfb_defined.height       = PIXEL_TO_MM(macfb_defined.yres);
 	macfb_defined.width        = PIXEL_TO_MM(macfb_defined.xres);
 
-	printk("macfb: scrolling: redraw\n");
-
-	/* some dummy values for timing to make fbset happy */
+	/* Some dummy values for timing to make fbset happy */
 	macfb_defined.pixclock     = 10000000 / macfb_defined.xres *
 				     1000 / macfb_defined.yres;
 	macfb_defined.left_margin  = (macfb_defined.xres / 8) & 0xf8;
@@ -666,8 +641,6 @@
 		macfb_defined.green.length = 5;
 		macfb_defined.blue.offset = 0;
 		macfb_defined.blue.length = 5;
-		printk("macfb: directcolor: "
-		       "size=1:5:5:5, shift=15:10:5:0\n");
 		video_cmap_len = 16;
 		/*
 		 * Should actually be FB_VISUAL_DIRECTCOLOR, but this
@@ -683,10 +656,9 @@
 		macfb_defined.green.length = 8;
 		macfb_defined.blue.offset = 0;
 		macfb_defined.blue.length = 8;
-		printk("macfb: truecolor: "
-		       "size=0:8:8:8, shift=0:16:8:0\n");
 		video_cmap_len = 16;
 		macfb_fix.visual = FB_VISUAL_TRUECOLOR;
+		break;
 	default:
 		video_cmap_len = 0;
 		macfb_fix.visual = FB_VISUAL_MONO01;
@@ -704,16 +676,17 @@
 	 * code is really broken :-)
 	 */
 
-	while ((ndev = nubus_find_type(NUBUS_CAT_DISPLAY, NUBUS_TYPE_VIDEO, ndev))
-		!= NULL)
+	while ((ndev = nubus_find_type(NUBUS_CAT_DISPLAY,
+				       NUBUS_TYPE_VIDEO, ndev)))
 	{
-		if (!(mac_bi_data.videoaddr >= ndev->board->slot_addr
-		      && (mac_bi_data.videoaddr <
-			  (unsigned long)nubus_slot_addr(ndev->board->slot+1))))
+		unsigned long base = ndev->board->slot_addr;
+
+		if (mac_bi_data.videoaddr < base ||
+		    mac_bi_data.videoaddr - base > 0xFFFFFF)
 			continue;
+
 		video_is_nubus = 1;
-		/* We should probably just use the slot address... */
-		video_slot = ndev->board->slot;
+		slot_addr = (unsigned char *)base;
 
 		switch(ndev->dr_hw) {
 		case NUBUS_DRHW_APPLE_MDC:
@@ -882,6 +855,9 @@
 		 * really support that.
 		 */
 
+		/*
+		 * Slot 0 ROM says TIM. No external video. B&W.
+		 */
 		case MAC_MODEL_PB140:
 		case MAC_MODEL_PB145:
 		case MAC_MODEL_PB170: