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

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

diff -u --recursive --new-file v2.1.123/linux/drivers/video/offb.c linux/drivers/video/offb.c
@@ -31,10 +31,11 @@
 #endif
 #include <asm/io.h>
 #include <asm/prom.h>
+#include <asm/bootx.h>
 
-#include "fbcon.h"
-#include "fbcon-cfb8.h"
-#include "macmodes.h"
+#include <video/fbcon.h>
+#include <video/fbcon-cfb8.h>
+#include <video/macmodes.h>
 
 
 static int currcon = 0;
@@ -91,6 +92,12 @@
 struct vc_mode display_info;
 #endif /* CONFIG_FB_COMPAT_XPMAC */
 
+extern boot_infos_t *boot_infos;
+
+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);
 
     /*
      *  Interface to the low level console driver
@@ -175,7 +182,8 @@
 			struct fb_info *info)
 {
     struct display *display;
-    int oldbpp = -1, err;
+    unsigned int oldbpp = 0;
+    int err;
     int activate = var->activate;
     struct fb_info_offb *info2 = (struct fb_info_offb *)info;
 
@@ -229,8 +237,7 @@
 			 struct fb_info *info)
 {
     if (con == currcon) /* current console? */
-	return fb_get_cmap(cmap, &fb_display[con].var, kspc, offb_getcolreg,
-			   info);
+	return fb_get_cmap(cmap, kspc, offb_getcolreg, info);
     else if (fb_display[con].cmap.len) /* non default colormap? */
 	fb_copy_cmap(&fb_display[con].cmap, cmap, kspc ? 0 : 2);
     else
@@ -258,8 +265,7 @@
 	    return err;
     }
     if (con == currcon)			/* current console? */
-	return fb_set_cmap(cmap, &fb_display[con].var, kspc, offb_setcolreg,
-			   info);
+	return fb_set_cmap(cmap, kspc, offb_setcolreg, info);
     else
 	fb_copy_cmap(cmap, &fb_display[con].cmap, kspc ? 0 : 1);
     return 0;
@@ -279,12 +285,18 @@
 #ifdef CONFIG_FB_S3TRIO
 extern void s3triofb_init_of(struct device_node *dp);
 #endif /* CONFIG_FB_S3TRIO */
+#ifdef CONFIG_FB_IMSTT
+extern void imsttfb_of_init(struct device_node *dp);
+#endif
 #ifdef CONFIG_FB_CT65550
 extern void chips_of_init(struct device_node *dp);
 #endif /* CONFIG_FB_CT65550 */
 #ifdef CONFIG_FB_CONTROL
 extern void control_of_init(struct device_node *dp);
 #endif /* CONFIG_FB_CONTROL */
+#ifdef CONFIG_FB_VALKYRIE
+extern void valkyrie_of_init(struct device_node *dp);
+#endif /* CONFIG_FB_VALKYRIE */
 #ifdef CONFIG_FB_PLATINUM
 extern void platinum_of_init(struct device_node *dp);
 #endif /* CONFIG_FB_PLATINUM */
@@ -297,193 +309,298 @@
 __initfunc(void offb_init(void))
 {
     struct device_node *dp;
-    int dpy, i, *pp, len;
-    unsigned *up, address;
-    struct fb_fix_screeninfo *fix;
-    struct fb_var_screeninfo *var;
-    struct display *disp;
-    struct fb_info_offb *info;
+    unsigned int dpy;
+    struct device_node *displays = find_type_devices("display");
+    struct device_node *macos_display = NULL;
+
+    /* If we're booted from BootX... */
+    if (prom_num_displays == 0 && boot_infos != 0) {
+	unsigned long addr = (unsigned long) boot_infos->dispDeviceBase;
+	if (!ofonly) {
+	    /* find the device node corresponding to the macos display */
+	    for (dp = displays; dp != NULL; dp = dp->next) {
+		int i;
+		/*
+		 * Grrr...  It looks like the MacOS ATI driver
+		 * munges the assigned-addresses property (but
+		 * the AAPL,address value is OK).
+		 */
+		if (strncmp(dp->name, "ATY,", 4) == 0 && dp->n_addrs == 1) {
+		    unsigned int *ap = (unsigned int *)
+			get_property(dp, "AAPL,address", NULL);
+		    if (ap != NULL) {
+			dp->addrs[0].address = *ap;
+			dp->addrs[0].size = 0x01000000;
+		    }
+		}
+		/*
+		 * See if the display address is in one of the address
+		 * ranges for this display.
+		 */
+		for (i = 0; i < dp->n_addrs; ++i) {
+		    if (dp->addrs[i].address <= addr
+			&& addr < dp->addrs[i].address + dp->addrs[i].size)
+			break;
+		}
+		if (i < dp->n_addrs) {
+		    printk(KERN_INFO "MacOS display is %s\n", dp->full_name);
+		    macos_display = dp;
+		    break;
+		}
+	    }
+	}
+
+	/* initialize it */
+	if (macos_display == NULL || !offb_init_driver(macos_display)) {
+	    offb_init_fb("MacOS display", "MacOS display",
+			 boot_infos->dispDeviceRect[2],
+			 boot_infos->dispDeviceRect[3],
+			 boot_infos->dispDeviceDepth,
+			 boot_infos->dispDeviceRowBytes, addr);
+	}
+    }
 
     for (dpy = 0; dpy < prom_num_displays; dpy++) {
-	if (!(dp = find_path_device(prom_display_paths[dpy])))
-	    continue;
+	if ((dp = find_path_device(prom_display_paths[dpy])))
+	    if (ofonly || !offb_init_driver(dp))
+		offb_init_nodriver(dp);
+    }
 
-	if (!ofonly) {
+    if (!ofonly) {
+	for (dp = find_type_devices("display"); dp != NULL; dp = dp->next) {
+	    for (dpy = 0; dpy < prom_num_displays; dpy++)
+		if (strcmp(dp->full_name, prom_display_paths[dpy]) == 0)
+		    break;
+	    if (dpy >= prom_num_displays && dp != macos_display)
+		offb_init_driver(dp);
+	}
+    }
+}
+
+__initfunc(static int offb_init_driver(struct device_node *dp))
+{
 #ifdef CONFIG_FB_ATY
-	    if (!strncmp(dp->name, "ATY", 3)) {
-		atyfb_of_init(dp);
-		continue;
-	    }
+    if (!strncmp(dp->name, "ATY", 3)) {
+	atyfb_of_init(dp);
+	return 1;
+    }
 #endif /* CONFIG_FB_ATY */
 #ifdef CONFIG_FB_S3TRIO
-            if (s3triofb_init_of(dp))
-                continue;
+    if (s3triofb_init_of(dp))
+	return 1;
 #endif /* CONFIG_FB_S3TRIO */
+#ifdef CONFIG_FB_IMSTT
+    if (!strncmp(dp->name, "IMS,tt128mb", 11)) {
+	imsttfb_of_init(dp);
+	return 1;
+    }
+#endif
 #ifdef CONFIG_FB_CT65550
-	    if (!strcmp(dp->name, "chips65550")) {
-		chips_of_init(dp);
-		continue;
-	    }
+    if (!strcmp(dp->name, "chips65550")) {
+	chips_of_init(dp);
+	return 1;
+    }
 #endif /* CONFIG_FB_CT65550 */
 #ifdef CONFIG_FB_CONTROL
-		if(!strcmp(dp->name, "control")) {
-			control_of_init(dp);
-			continue;
-		}
+    if(!strcmp(dp->name, "control")) {
+	control_of_init(dp);
+	return 1;
+    }
 #endif /* CONFIG_FB_CONTROL */
+#ifdef CONFIG_FB_VALKYRIE
+    if(!strcmp(dp->name, "valkyrie")) {
+	valkyrie_of_init(dp);
+	return 1;
+    }
+#endif /* CONFIG_FB_VALKYRIE */
 #ifdef CONFIG_FB_PLATINUM
-	    if (!strncmp(dp->name, "platinum",8)) {
-	    	printk("jonh: offb_init sees device node %s\n", dp->name);
-		platinum_of_init(dp);
-		continue;
-	    }
+    if (!strncmp(dp->name, "platinum",8)) {
+	platinum_of_init(dp);
+	return 1;
+    }
 #endif /* CONFIG_FB_PLATINUM */
-	}
+    return 0;
+}
 
-	info = kmalloc(sizeof(struct fb_info_offb), GFP_ATOMIC);
-	fix = &info->fix;
-	var = &info->var;
-	disp = &info->disp;
-
-	strcpy(fix->id, "OFfb ");
-	strncat(fix->id, dp->name, sizeof(fix->id));
-	fix->id[sizeof(fix->id)-1] = '\0';
-
-	if ((pp = (int *)get_property(dp, "depth", &len)) != NULL
-	    && len == sizeof(int) && *pp != 8) {
-	    printk("%s: can't use depth = %d\n", dp->full_name, *pp);
-	    kfree(info);
-	    continue;
-	}
-	if ((pp = (int *)get_property(dp, "width", &len)) != NULL
-	    && len == sizeof(int))
-	    var->xres = var->xres_virtual = *pp;
-	if ((pp = (int *)get_property(dp, "height", &len)) != NULL
-	    && len == sizeof(int))
-	    var->yres = var->yres_virtual = *pp;
-	if ((pp = (int *)get_property(dp, "linebytes", &len)) != NULL
-	    && len == sizeof(int))
-	    fix->line_length = *pp;
-	else
-	    fix->line_length = var->xres_virtual;
-	fix->smem_len = fix->line_length*var->yres;
-	if ((up = (unsigned *)get_property(dp, "address", &len)) != NULL
-	    && len == sizeof(unsigned))
-	    address = (u_long)*up;
-	else {
-	    for (i = 0; i < dp->n_addrs; ++i)
-		if (dp->addrs[i].size >= len)
-		    break;
-	    if (i >= dp->n_addrs) {
-		printk("no framebuffer address found for %s\n", dp->full_name);
-		kfree(info);
-		continue;
-	    }
-	    address = (u_long)dp->addrs[i].address;
+__initfunc(static void offb_init_nodriver(struct device_node *dp))
+{
+    int *pp, i;
+    unsigned int len;
+    int width = 640, height = 480, depth = 8, pitch;
+    unsigned *up, address;
+
+    if ((pp = (int *)get_property(dp, "depth", &len)) != NULL
+	&& len == sizeof(int))
+	depth = *pp;
+    if ((pp = (int *)get_property(dp, "width", &len)) != NULL
+	&& len == sizeof(int))
+	width = *pp;
+    if ((pp = (int *)get_property(dp, "height", &len)) != NULL
+	&& len == sizeof(int))
+	height = *pp;
+    if ((pp = (int *)get_property(dp, "linebytes", &len)) != NULL
+	&& len == sizeof(int))
+	pitch = *pp;
+    else
+	pitch = width;
+    if ((up = (unsigned *)get_property(dp, "address", &len)) != NULL
+	&& len == sizeof(unsigned))
+	address = (u_long)*up;
+    else {
+	for (i = 0; i < dp->n_addrs; ++i)
+	    if (dp->addrs[i].size >= len)
+		break;
+	if (i >= dp->n_addrs) {
+	    printk("no framebuffer address found for %s\n", dp->full_name);
+	    return;
 	}
-	fix->smem_start = (char *)address;
-	fix->type = FB_TYPE_PACKED_PIXELS;
-	fix->type_aux = 0;
+	address = (u_long)dp->addrs[i].address;
+
+	/* kludge for valkyrie */
+	if (strcmp(dp->name, "valkyrie") == 0) 
+	    address += 0x1000;
+    }
+    offb_init_fb(dp->name, dp->full_name, width, height, depth,
+		 pitch, address);
+}
+
+__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 i;
+    struct fb_fix_screeninfo *fix;
+    struct fb_var_screeninfo *var;
+    struct display *disp;
+    struct fb_info_offb *info;
+
+    printk(KERN_INFO "Using unsupported %dx%d %s at %lx, depth=%d, pitch=%d\n",
+	   width, height, name, address, depth, pitch);
+    if (depth != 8) {
+	printk("%s: can't use depth = %d\n", full_name, depth);
+	return;
+    }
+
+    info = kmalloc(sizeof(struct fb_info_offb), GFP_ATOMIC);
+    if (info == 0)
+	return;
+    memset(info, 0, sizeof(*info));
+
+    fix = &info->fix;
+    var = &info->var;
+    disp = &info->disp;
+
+    strcpy(fix->id, "OFfb ");
+    strncat(fix->id, name, sizeof(fix->id));
+    fix->id[sizeof(fix->id)-1] = '\0';
+
+    var->xres = var->xres_virtual = width;
+    var->yres = var->yres_virtual = height;
+    fix->line_length = pitch;
+
+    fix->smem_start = (char *)address;
+    fix->smem_len = pitch * height;
+    fix->type = FB_TYPE_PACKED_PIXELS;
+    fix->type_aux = 0;
 
 	/* XXX kludge for ati */
-	if (strncmp(dp->name, "ATY,", 4) == 0) {
-	    info->cmap_adr = ioremap(address + 0x7ff000, 0x1000) + 0xcc0;
-	    info->cmap_data = info->cmap_adr + 1;
-	}
+    if (strncmp(name, "ATY,", 4) == 0) {
+	info->cmap_adr = ioremap(address + 0x7ff000, 0x1000) + 0xcc0;
+	info->cmap_data = info->cmap_adr + 1;
+    }
 
-	fix->visual = info->cmap_adr ? FB_VISUAL_PSEUDOCOLOR :
-				       FB_VISUAL_STATIC_PSEUDOCOLOR;
+    fix->visual = info->cmap_adr ? FB_VISUAL_PSEUDOCOLOR :
+	FB_VISUAL_STATIC_PSEUDOCOLOR;
 
-	var->xoffset = var->yoffset = 0;
-	var->bits_per_pixel = 8;
-	var->grayscale = 0;
-	var->red.offset = var->green.offset = var->blue.offset = 0;
-	var->red.length = var->green.length = var->blue.length = 8;
-	var->red.msb_right = var->green.msb_right = var->blue.msb_right = 0;
-	var->transp.offset = var->transp.length = var->transp.msb_right = 0;
-	var->nonstd = 0;
-	var->activate = 0;
-	var->height = var->width = -1;
-	var->pixclock = 10000;
-	var->left_margin = var->right_margin = 16;
-	var->upper_margin = var->lower_margin = 16;
-	var->hsync_len = var->vsync_len = 8;
-	var->sync = 0;
-	var->vmode = FB_VMODE_NONINTERLACED;
-
-	disp->var = *var;
-	disp->cmap.start = 0;
-	disp->cmap.len = 0;
-	disp->cmap.red = NULL;
-	disp->cmap.green = NULL;
-	disp->cmap.blue = NULL;
-	disp->cmap.transp = NULL;
-	disp->screen_base = ioremap(address, fix->smem_len);
-	disp->visual = fix->visual;
-	disp->type = fix->type;
-	disp->type_aux = fix->type_aux;
-	disp->ypanstep = 0;
-	disp->ywrapstep = 0;
-	disp->line_length = fix->line_length;
-	disp->can_soft_blank = info->cmap_adr ? 1 : 0;
-	disp->inverse = 0;
+    var->xoffset = var->yoffset = 0;
+    var->bits_per_pixel = 8;
+    var->grayscale = 0;
+    var->red.offset = var->green.offset = var->blue.offset = 0;
+    var->red.length = var->green.length = var->blue.length = 8;
+    var->red.msb_right = var->green.msb_right = var->blue.msb_right = 0;
+    var->transp.offset = var->transp.length = var->transp.msb_right = 0;
+    var->nonstd = 0;
+    var->activate = 0;
+    var->height = var->width = -1;
+    var->pixclock = 10000;
+    var->left_margin = var->right_margin = 16;
+    var->upper_margin = var->lower_margin = 16;
+    var->hsync_len = var->vsync_len = 8;
+    var->sync = 0;
+    var->vmode = FB_VMODE_NONINTERLACED;
+
+    disp->var = *var;
+    disp->cmap.start = 0;
+    disp->cmap.len = 0;
+    disp->cmap.red = NULL;
+    disp->cmap.green = NULL;
+    disp->cmap.blue = NULL;
+    disp->cmap.transp = NULL;
+    disp->screen_base = ioremap(address, fix->smem_len);
+    disp->visual = fix->visual;
+    disp->type = fix->type;
+    disp->type_aux = fix->type_aux;
+    disp->ypanstep = 0;
+    disp->ywrapstep = 0;
+    disp->line_length = fix->line_length;
+    disp->can_soft_blank = info->cmap_adr ? 1 : 0;
+    disp->inverse = 0;
 #ifdef FBCON_HAS_CFB8
-	disp->dispsw = &fbcon_cfb8;
+    disp->dispsw = &fbcon_cfb8;
 #else
-	disp->dispsw = NULL;
+    disp->dispsw = &fbcon_dummy;
 #endif
-	disp->scrollmode = SCROLL_YREDRAW;
+    disp->scrollmode = SCROLL_YREDRAW;
 
-	strcpy(info->info.modename, "OFfb ");
-	strncat(info->info.modename, dp->full_name,
-		sizeof(info->info.modename));
-	info->info.node = -1;
-	info->info.fbops = &offb_ops;
-	info->info.disp = disp;
-	info->info.fontname[0] = '\0';
-	info->info.changevar = NULL;
-	info->info.switch_con = &offbcon_switch;
-	info->info.updatevar = &offbcon_updatevar;
-	info->info.blank = &offbcon_blank;
-
-	for (i = 0; i < 16; i++) {
-	    int j = color_table[i];
-	    info->palette[i].red = default_red[j];
-	    info->palette[i].green = default_grn[j];
-	    info->palette[i].blue = default_blu[j];
-	}
-	offb_set_var(var, -1, &info->info);
+    strcpy(info->info.modename, "OFfb ");
+    strncat(info->info.modename, full_name, sizeof(info->info.modename));
+    info->info.node = -1;
+    info->info.fbops = &offb_ops;
+    info->info.disp = disp;
+    info->info.fontname[0] = '\0';
+    info->info.changevar = NULL;
+    info->info.switch_con = &offbcon_switch;
+    info->info.updatevar = &offbcon_updatevar;
+    info->info.blank = &offbcon_blank;
+    info->info.flags = FBINFO_FLAG_DEFAULT;
+
+    for (i = 0; i < 16; i++) {
+	int j = color_table[i];
+	info->palette[i].red = default_red[j];
+	info->palette[i].green = default_grn[j];
+	info->palette[i].blue = default_blu[j];
+    }
+    offb_set_var(var, -1, &info->info);
 
-	if (register_framebuffer(&info->info) < 0) {
-	    kfree(info);
-	    return;
-	}
+    if (register_framebuffer(&info->info) < 0) {
+	kfree(info);
+	return;
+    }
 
-	printk("fb%d: Open Firmware frame buffer device on %s\n",
-	       GET_FB_IDX(info->info.node), dp->full_name);
+    printk("fb%d: Open Firmware frame buffer device on %s\n",
+	   GET_FB_IDX(info->info.node), full_name);
 
 #ifdef CONFIG_FB_COMPAT_XPMAC
-	if (!console_fb_info) {
-	    display_info.height = var->yres;
-	    display_info.width = var->xres;
-	    display_info.depth = 8;
-	    display_info.pitch = fix->line_length;
-	    display_info.mode = 0;
-	    strncpy(display_info.name, dp->name, sizeof(display_info.name));
-	    display_info.fb_address = address;
-	    display_info.cmap_adr_address = 0;
-	    display_info.cmap_data_address = 0;
-	    display_info.disp_reg_address = 0;
-	    /* XXX kludge for ati */
-	    if (strncmp(dp->name, "ATY,", 4) == 0) {
-		    display_info.disp_reg_address = address + 0x7ffc00;
-		    display_info.cmap_adr_address = address + 0x7ffcc0;
-		    display_info.cmap_data_address = address + 0x7ffcc1;
-	    }
-	    console_fb_info = &info->info;
+    if (!console_fb_info) {
+	display_info.height = var->yres;
+	display_info.width = var->xres;
+	display_info.depth = 8;
+	display_info.pitch = fix->line_length;
+	display_info.mode = 0;
+	strncpy(display_info.name, name, sizeof(display_info.name));
+	display_info.fb_address = address;
+	display_info.cmap_adr_address = 0;
+	display_info.cmap_data_address = 0;
+	display_info.disp_reg_address = 0;
+	/* XXX kludge for ati */
+	if (strncmp(name, "ATY,", 4) == 0) {
+	    display_info.disp_reg_address = address + 0x7ffc00;
+	    display_info.cmap_adr_address = address + 0x7ffcc0;
+	    display_info.cmap_data_address = address + 0x7ffcc1;
 	}
-#endif /* CONFIG_FB_COMPAT_XPMAC) */
+	console_fb_info = &info->info;
     }
+#endif /* CONFIG_FB_COMPAT_XPMAC) */
 }
 
 
@@ -505,8 +622,7 @@
 {
     /* Do we have to save the colormap? */
     if (fb_display[currcon].cmap.len)
-	fb_get_cmap(&fb_display[currcon].cmap, &fb_display[currcon].var, 1,
-		    offb_getcolreg, info);
+	fb_get_cmap(&fb_display[currcon].cmap, 1, offb_getcolreg, info);
 
     currcon = con;
     /* Install new colormap */
@@ -561,9 +677,11 @@
 
     if (!info2->cmap_adr || regno > 255)
 	return 1;
-    *red = info2->palette[regno].red;
-    *green = info2->palette[regno].green;
-    *blue = info2->palette[regno].blue;
+    
+    *red = (info2->palette[regno].red<<8) | info2->palette[regno].red;
+    *green = (info2->palette[regno].green<<8) | info2->palette[regno].green;
+    *blue = (info2->palette[regno].blue<<8) | info2->palette[regno].blue;
+    *transp = 0;
     return 0;
 }
 
@@ -581,6 +699,10 @@
 
     if (!info2->cmap_adr || regno > 255)
 	return 1;
+    red >>= 8;
+    green >>= 8;
+    blue >>= 8;
+
     info2->palette[regno].red = red;
     info2->palette[regno].green = green;
     info2->palette[regno].blue = blue;
@@ -601,12 +723,10 @@
     if (con != currcon)
 	return;
     if (fb_display[con].cmap.len)
-	fb_set_cmap(&fb_display[con].cmap, &fb_display[con].var, 1,
-		    offb_setcolreg, info);
+	fb_set_cmap(&fb_display[con].cmap, 1, offb_setcolreg, info);
     else
 	fb_set_cmap(fb_default_cmap(1<<fb_display[con].var.bits_per_pixel),
-				    &fb_display[con].var, 1, offb_setcolreg,
-				    info);
+				    1, offb_setcolreg, info);
 }
 
 

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov