Commit ab134466 authored by Benjamin Herrenschmidt's avatar Benjamin Herrenschmidt Committed by Paul Mackerras

[POWERPC] Fix various offb and BootX-related issues

This patch fixes various issues with offb (the default fbdev used on
powerpc when no proper fbdev is supported). It was broken when using
BootX under some circumstances and would fail to properly get the
framebuffer base address in others.
Signed-off-by: default avatarBenjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: default avatarPaul Mackerras <paulus@samba.org>
parent 4ce631e7
...@@ -111,7 +111,7 @@ void __init btext_setup_display(int width, int height, int depth, int pitch, ...@@ -111,7 +111,7 @@ void __init btext_setup_display(int width, int height, int depth, int pitch,
logicalDisplayBase = (unsigned char *)address; logicalDisplayBase = (unsigned char *)address;
dispDeviceBase = (unsigned char *)address; dispDeviceBase = (unsigned char *)address;
dispDeviceRowBytes = pitch; dispDeviceRowBytes = pitch;
dispDeviceDepth = depth; dispDeviceDepth = depth == 15 ? 16 : depth;
dispDeviceRect[0] = dispDeviceRect[1] = 0; dispDeviceRect[0] = dispDeviceRect[1] = 0;
dispDeviceRect[2] = width; dispDeviceRect[2] = width;
dispDeviceRect[3] = height; dispDeviceRect[3] = height;
...@@ -160,20 +160,28 @@ int btext_initialize(struct device_node *np) ...@@ -160,20 +160,28 @@ int btext_initialize(struct device_node *np)
unsigned long address = 0; unsigned long address = 0;
u32 *prop; u32 *prop;
prop = (u32 *)get_property(np, "width", NULL); prop = (u32 *)get_property(np, "linux,bootx-width", NULL);
if (prop == NULL)
prop = (u32 *)get_property(np, "width", NULL);
if (prop == NULL) if (prop == NULL)
return -EINVAL; return -EINVAL;
width = *prop; width = *prop;
prop = (u32 *)get_property(np, "height", NULL); prop = (u32 *)get_property(np, "linux,bootx-height", NULL);
if (prop == NULL)
prop = (u32 *)get_property(np, "height", NULL);
if (prop == NULL) if (prop == NULL)
return -EINVAL; return -EINVAL;
height = *prop; height = *prop;
prop = (u32 *)get_property(np, "depth", NULL); prop = (u32 *)get_property(np, "linux,bootx-depth", NULL);
if (prop == NULL)
prop = (u32 *)get_property(np, "depth", NULL);
if (prop == NULL) if (prop == NULL)
return -EINVAL; return -EINVAL;
depth = *prop; depth = *prop;
pitch = width * ((depth + 7) / 8); pitch = width * ((depth + 7) / 8);
prop = (u32 *)get_property(np, "linebytes", NULL); prop = (u32 *)get_property(np, "linux,bootx-linebytes", NULL);
if (prop == NULL)
prop = (u32 *)get_property(np, "linebytes", NULL);
if (prop) if (prop)
pitch = *prop; pitch = *prop;
if (pitch == 1) if (pitch == 1)
...@@ -194,7 +202,7 @@ int btext_initialize(struct device_node *np) ...@@ -194,7 +202,7 @@ int btext_initialize(struct device_node *np)
g_max_loc_Y = height / 16; g_max_loc_Y = height / 16;
dispDeviceBase = (unsigned char *)address; dispDeviceBase = (unsigned char *)address;
dispDeviceRowBytes = pitch; dispDeviceRowBytes = pitch;
dispDeviceDepth = depth; dispDeviceDepth = depth == 15 ? 16 : depth;
dispDeviceRect[0] = dispDeviceRect[1] = 0; dispDeviceRect[0] = dispDeviceRect[1] = 0;
dispDeviceRect[2] = width; dispDeviceRect[2] = width;
dispDeviceRect[3] = height; dispDeviceRect[3] = height;
......
...@@ -51,7 +51,6 @@ ...@@ -51,7 +51,6 @@
extern void bootx_init(unsigned long r4, unsigned long phys); extern void bootx_init(unsigned long r4, unsigned long phys);
boot_infos_t *boot_infos;
struct ide_machdep_calls ppc_ide_md; struct ide_machdep_calls ppc_ide_md;
int boot_cpuid; int boot_cpuid;
......
...@@ -181,8 +181,25 @@ static void __init bootx_add_chosen_props(unsigned long base, ...@@ -181,8 +181,25 @@ static void __init bootx_add_chosen_props(unsigned long base,
static void __init bootx_add_display_props(unsigned long base, static void __init bootx_add_display_props(unsigned long base,
unsigned long *mem_end) unsigned long *mem_end)
{ {
boot_infos_t *bi = bootx_info;
u32 tmp;
bootx_dt_add_prop("linux,boot-display", NULL, 0, mem_end); bootx_dt_add_prop("linux,boot-display", NULL, 0, mem_end);
bootx_dt_add_prop("linux,opened", NULL, 0, mem_end); bootx_dt_add_prop("linux,opened", NULL, 0, mem_end);
tmp = bi->dispDeviceDepth;
bootx_dt_add_prop("linux,bootx-depth", &tmp, 4, mem_end);
tmp = bi->dispDeviceRect[2] - bi->dispDeviceRect[0];
bootx_dt_add_prop("linux,bootx-width", &tmp, 4, mem_end);
tmp = bi->dispDeviceRect[3] - bi->dispDeviceRect[1];
bootx_dt_add_prop("linux,bootx-height", &tmp, 4, mem_end);
tmp = bi->dispDeviceRowBytes;
bootx_dt_add_prop("linux,bootx-linebytes", &tmp, 4, mem_end);
tmp = (u32)bi->dispDeviceBase;
if (tmp == 0)
tmp = (u32)bi->logicalDisplayBase;
tmp += bi->dispDeviceRect[1] * bi->dispDeviceRowBytes;
tmp += bi->dispDeviceRect[0] * ((bi->dispDeviceDepth + 7) / 8);
bootx_dt_add_prop("linux,bootx-addr", &tmp, 4, mem_end);
} }
static void __init bootx_dt_add_string(char *s, unsigned long *mem_end) static void __init bootx_dt_add_string(char *s, unsigned long *mem_end)
...@@ -222,6 +239,11 @@ static void __init bootx_scan_dt_build_strings(unsigned long base, ...@@ -222,6 +239,11 @@ static void __init bootx_scan_dt_build_strings(unsigned long base,
DBG(" detected display ! adding properties names !\n"); DBG(" detected display ! adding properties names !\n");
bootx_dt_add_string("linux,boot-display", mem_end); bootx_dt_add_string("linux,boot-display", mem_end);
bootx_dt_add_string("linux,opened", mem_end); bootx_dt_add_string("linux,opened", mem_end);
bootx_dt_add_string("linux,bootx-depth", mem_end);
bootx_dt_add_string("linux,bootx-width", mem_end);
bootx_dt_add_string("linux,bootx-height", mem_end);
bootx_dt_add_string("linux,bootx-linebytes", mem_end);
bootx_dt_add_string("linux,bootx-addr", mem_end);
strncpy(bootx_disp_path, namep, 255); strncpy(bootx_disp_path, namep, 255);
} }
...@@ -443,7 +465,14 @@ void __init bootx_init(unsigned long r3, unsigned long r4) ...@@ -443,7 +465,14 @@ void __init bootx_init(unsigned long r3, unsigned long r4)
if (!BOOT_INFO_IS_V2_COMPATIBLE(bi)) if (!BOOT_INFO_IS_V2_COMPATIBLE(bi))
bi->logicalDisplayBase = bi->dispDeviceBase; bi->logicalDisplayBase = bi->dispDeviceBase;
/* Fixup depth 16 -> 15 as that's what MacOS calls 16bpp */
if (bi->dispDeviceDepth == 16)
bi->dispDeviceDepth = 15;
#ifdef CONFIG_BOOTX_TEXT #ifdef CONFIG_BOOTX_TEXT
ptr = (unsigned long)bi->logicalDisplayBase;
ptr += bi->dispDeviceRect[1] * bi->dispDeviceRowBytes;
ptr += bi->dispDeviceRect[0] * ((bi->dispDeviceDepth + 7) / 8);
btext_setup_display(bi->dispDeviceRect[2] - bi->dispDeviceRect[0], btext_setup_display(bi->dispDeviceRect[2] - bi->dispDeviceRect[0],
bi->dispDeviceRect[3] - bi->dispDeviceRect[1], bi->dispDeviceRect[3] - bi->dispDeviceRect[1],
bi->dispDeviceDepth, bi->dispDeviceRowBytes, bi->dispDeviceDepth, bi->dispDeviceRowBytes,
......
...@@ -97,14 +97,43 @@ static int offb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, ...@@ -97,14 +97,43 @@ static int offb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
u_int transp, struct fb_info *info) u_int transp, struct fb_info *info)
{ {
struct offb_par *par = (struct offb_par *) info->par; struct offb_par *par = (struct offb_par *) info->par;
int i, depth;
u32 *pal = info->pseudo_palette;
if (!par->cmap_adr || regno > 255) depth = info->var.bits_per_pixel;
if (depth == 16)
depth = (info->var.green.length == 5) ? 15 : 16;
if (regno > 255 ||
(depth == 16 && regno > 63) ||
(depth == 15 && regno > 31))
return 1; return 1;
if (regno < 16) {
switch (depth) {
case 15:
pal[regno] = (regno << 10) | (regno << 5) | regno;
break;
case 16:
pal[regno] = (regno << 11) | (regno << 5) | regno;
break;
case 24:
pal[regno] = (regno << 16) | (regno << 8) | regno;
break;
case 32:
i = (regno << 8) | regno;
pal[regno] = (i << 16) | i;
break;
}
}
red >>= 8; red >>= 8;
green >>= 8; green >>= 8;
blue >>= 8; blue >>= 8;
if (!par->cmap_adr)
return 0;
switch (par->cmap_type) { switch (par->cmap_type) {
case cmap_m64: case cmap_m64:
writeb(regno, par->cmap_adr); writeb(regno, par->cmap_adr);
...@@ -141,20 +170,6 @@ static int offb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, ...@@ -141,20 +170,6 @@ static int offb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
break; break;
} }
if (regno < 16)
switch (info->var.bits_per_pixel) {
case 16:
((u16 *) (info->pseudo_palette))[regno] =
(regno << 10) | (regno << 5) | regno;
break;
case 32:
{
int i = (regno << 8) | regno;
((u32 *) (info->pseudo_palette))[regno] =
(i << 16) | i;
break;
}
}
return 0; return 0;
} }
...@@ -223,81 +238,9 @@ int __init offb_init(void) ...@@ -223,81 +238,9 @@ int __init offb_init(void)
{ {
struct device_node *dp = NULL, *boot_disp = NULL; struct device_node *dp = NULL, *boot_disp = NULL;
#if defined(CONFIG_BOOTX_TEXT) && defined(CONFIG_PPC32)
struct device_node *macos_display = NULL;
#endif
if (fb_get_options("offb", NULL)) if (fb_get_options("offb", NULL))
return -ENODEV; return -ENODEV;
#if defined(CONFIG_BOOTX_TEXT) && defined(CONFIG_PPC32)
/* If we're booted from BootX... */
if (boot_infos != 0) {
unsigned long addr =
(unsigned long) boot_infos->dispDeviceBase;
u32 *addrp;
u64 daddr, dsize;
unsigned int flags;
/* find the device node corresponding to the macos display */
while ((dp = of_find_node_by_type(dp, "display"))) {
int i;
/*
* Look for an AAPL,address property first.
*/
unsigned 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) {
macos_display = dp;
goto foundit;
}
}
/*
* See if the display address is in one of the address
* ranges for this display.
*/
i = 0;
for (;;) {
addrp = of_get_address(dp, i++, &dsize, &flags);
if (addrp == NULL)
break;
if (!(flags & IORESOURCE_MEM))
continue;
daddr = of_translate_address(dp, addrp);
if (daddr == OF_BAD_ADDR)
continue;
if (daddr <= addr && addr < (daddr + dsize)) {
macos_display = dp;
goto foundit;
}
}
foundit:
if (macos_display) {
printk(KERN_INFO "MacOS display is %s\n",
dp->full_name);
break;
}
}
/* initialize it */
offb_init_fb(macos_display ? macos_display->
name : "MacOS display",
macos_display ? macos_display->
full_name : "MacOS display",
boot_infos->dispDeviceRect[2],
boot_infos->dispDeviceRect[3],
boot_infos->dispDeviceDepth,
boot_infos->dispDeviceRowBytes, addr, NULL);
}
#endif /* defined(CONFIG_BOOTX_TEXT) && defined(CONFIG_PPC32) */
for (dp = NULL; (dp = of_find_node_by_type(dp, "display"));) { for (dp = NULL; (dp = of_find_node_by_type(dp, "display"));) {
if (get_property(dp, "linux,opened", NULL) && if (get_property(dp, "linux,opened", NULL) &&
get_property(dp, "linux,boot-display", NULL)) { get_property(dp, "linux,boot-display", NULL)) {
...@@ -317,94 +260,93 @@ int __init offb_init(void) ...@@ -317,94 +260,93 @@ int __init offb_init(void)
static void __init offb_init_nodriver(struct device_node *dp) static void __init offb_init_nodriver(struct device_node *dp)
{ {
int *pp, i;
unsigned int len; unsigned int len;
int width = 640, height = 480, depth = 8, pitch; int i, width = 640, height = 480, depth = 8, pitch = 640;
unsigned int flags, rsize, *up; unsigned int flags, rsize, addr_prop = 0;
u64 address = OF_BAD_ADDR; unsigned long max_size = 0;
u32 *addrp; u64 rstart, address = OF_BAD_ADDR;
u32 *pp, *addrp, *up;
u64 asize; u64 asize;
if ((pp = (int *) get_property(dp, "depth", &len)) != NULL pp = (u32 *)get_property(dp, "linux,bootx-depth", &len);
&& len == sizeof(int)) if (pp == NULL)
pp = (u32 *)get_property(dp, "depth", &len);
if (pp && len == sizeof(u32))
depth = *pp; depth = *pp;
if ((pp = (int *) get_property(dp, "width", &len)) != NULL
&& len == sizeof(int)) pp = (u32 *)get_property(dp, "linux,bootx-width", &len);
if (pp == NULL)
pp = (u32 *)get_property(dp, "width", &len);
if (pp && len == sizeof(u32))
width = *pp; width = *pp;
if ((pp = (int *) get_property(dp, "height", &len)) != NULL
&& len == sizeof(int)) pp = (u32 *)get_property(dp, "linux,bootx-height", &len);
if (pp == NULL)
pp = (u32 *)get_property(dp, "height", &len);
if (pp && len == sizeof(u32))
height = *pp; height = *pp;
if ((pp = (int *) get_property(dp, "linebytes", &len)) != NULL
&& len == sizeof(int)) { pp = (u32 *)get_property(dp, "linux,bootx-linebytes", &len);
if (pp == NULL)
pp = (u32 *)get_property(dp, "linebytes", &len);
if (pp && len == sizeof(u32))
pitch = *pp; pitch = *pp;
if (pitch == 1) else
pitch = 0x1000; pitch = width * ((depth + 7) / 8);
} else
pitch = width; rsize = (unsigned long)pitch * (unsigned long)height;
rsize = (unsigned long)pitch * (unsigned long)height * /* Ok, now we try to figure out the address of the framebuffer.
(unsigned long)(depth / 8); *
* Unfortunately, Open Firmware doesn't provide a standard way to do
/* Try to match device to a PCI device in order to get a properly * so. All we can do is a dodgy heuristic that happens to work in
* translated address rather then trying to decode the open firmware * practice. On most machines, the "address" property contains what
* stuff in various incorrect ways * we need, though not on Matrox cards found in IBM machines. What I've
*/ * found that appears to give good results is to go through the PCI
#ifdef CONFIG_PCI * ranges and pick one that is both big enough and if possible encloses
/* First try to locate the PCI device if any */ * the "address" property. If none match, we pick the biggest
{ */
struct pci_dev *pdev = NULL; up = (u32 *)get_property(dp, "linux,bootx-addr", &len);
if (up == NULL)
for_each_pci_dev(pdev) { up = (u32 *)get_property(dp, "address", &len);
if (dp == pci_device_to_OF_node(pdev)) if (up && len == sizeof(u32))
break; addr_prop = *up;
}
if (pdev) { for (i = 0; (addrp = of_get_address(dp, i, &asize, &flags))
for (i = 0; i < 6 && address == OF_BAD_ADDR; i++) { != NULL; i++) {
if ((pci_resource_flags(pdev, i) & int match_addrp = 0;
IORESOURCE_MEM) &&
(pci_resource_len(pdev, i) >= rsize)) if (!(flags & IORESOURCE_MEM))
address = pci_resource_start(pdev, i); continue;
} if (asize < rsize)
pci_dev_put(pdev); continue;
} rstart = of_translate_address(dp, addrp);
} if (rstart == OF_BAD_ADDR)
#endif /* CONFIG_PCI */ continue;
if (addr_prop && (rstart <= addr_prop) &&
/* This one is dodgy, we may drop it ... */ ((rstart + asize) >= (addr_prop + rsize)))
if (address == OF_BAD_ADDR && match_addrp = 1;
(up = (unsigned *) get_property(dp, "address", &len)) != NULL && if (match_addrp) {
len == sizeof(unsigned int)) address = addr_prop;
address = (u64) * up; break;
if (address == OF_BAD_ADDR) {
for (i = 0; (addrp = of_get_address(dp, i, &asize, &flags))
!= NULL; i++) {
if (!(flags & IORESOURCE_MEM))
continue;
if (asize >= pitch * height * depth / 8)
break;
}
if (addrp == NULL) {
printk(KERN_ERR
"no framebuffer address found for %s\n",
dp->full_name);
return;
}
address = of_translate_address(dp, addrp);
if (address == OF_BAD_ADDR) {
printk(KERN_ERR
"can't translate framebuffer address for %s\n",
dp->full_name);
return;
} }
if (rsize > max_size) {
max_size = rsize;
address = OF_BAD_ADDR;
}
if (address == OF_BAD_ADDR)
address = rstart;
}
if (address == OF_BAD_ADDR && addr_prop)
address = (u64)addr_prop;
if (address != OF_BAD_ADDR) {
/* kludge for valkyrie */ /* kludge for valkyrie */
if (strcmp(dp->name, "valkyrie") == 0) if (strcmp(dp->name, "valkyrie") == 0)
address += 0x1000; address += 0x1000;
offb_init_fb(dp->name, dp->full_name, width, height, depth,
pitch, address, dp);
} }
offb_init_fb(dp->name, dp->full_name, width, height, depth,
pitch, address, dp);
} }
static void __init offb_init_fb(const char *name, const char *full_name, static void __init offb_init_fb(const char *name, const char *full_name,
...@@ -412,7 +354,7 @@ static void __init offb_init_fb(const char *name, const char *full_name, ...@@ -412,7 +354,7 @@ static void __init offb_init_fb(const char *name, const char *full_name,
int pitch, unsigned long address, int pitch, unsigned long address,
struct device_node *dp) struct device_node *dp)
{ {
unsigned long res_size = pitch * height * depth / 8; unsigned long res_size = pitch * height * (depth + 7) / 8;
struct offb_par *par = &default_par; struct offb_par *par = &default_par;
unsigned long res_start = address; unsigned long res_start = address;
struct fb_fix_screeninfo *fix; struct fb_fix_screeninfo *fix;
...@@ -426,7 +368,7 @@ static void __init offb_init_fb(const char *name, const char *full_name, ...@@ -426,7 +368,7 @@ static void __init offb_init_fb(const char *name, const char *full_name,
printk(KERN_INFO printk(KERN_INFO
"Using unsupported %dx%d %s at %lx, depth=%d, pitch=%d\n", "Using unsupported %dx%d %s at %lx, depth=%d, pitch=%d\n",
width, height, name, address, depth, pitch); width, height, name, address, depth, pitch);
if (depth != 8 && depth != 16 && depth != 32) { if (depth != 8 && depth != 15 && depth != 16 && depth != 32) {
printk(KERN_ERR "%s: can't use depth = %d\n", full_name, printk(KERN_ERR "%s: can't use depth = %d\n", full_name,
depth); depth);
release_mem_region(res_start, res_size); release_mem_region(res_start, res_size);
...@@ -502,7 +444,6 @@ static void __init offb_init_fb(const char *name, const char *full_name, ...@@ -502,7 +444,6 @@ static void __init offb_init_fb(const char *name, const char *full_name,
: */ FB_VISUAL_TRUECOLOR; : */ FB_VISUAL_TRUECOLOR;
var->xoffset = var->yoffset = 0; var->xoffset = var->yoffset = 0;
var->bits_per_pixel = depth;
switch (depth) { switch (depth) {
case 8: case 8:
var->bits_per_pixel = 8; var->bits_per_pixel = 8;
...@@ -515,7 +456,7 @@ static void __init offb_init_fb(const char *name, const char *full_name, ...@@ -515,7 +456,7 @@ static void __init offb_init_fb(const char *name, const char *full_name,
var->transp.offset = 0; var->transp.offset = 0;
var->transp.length = 0; var->transp.length = 0;
break; break;
case 16: /* RGB 555 */ case 15: /* RGB 555 */
var->bits_per_pixel = 16; var->bits_per_pixel = 16;
var->red.offset = 10; var->red.offset = 10;
var->red.length = 5; var->red.length = 5;
...@@ -526,6 +467,17 @@ static void __init offb_init_fb(const char *name, const char *full_name, ...@@ -526,6 +467,17 @@ static void __init offb_init_fb(const char *name, const char *full_name,
var->transp.offset = 0; var->transp.offset = 0;
var->transp.length = 0; var->transp.length = 0;
break; break;
case 16: /* RGB 565 */
var->bits_per_pixel = 16;
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;
case 32: /* RGB 888 */ case 32: /* RGB 888 */
var->bits_per_pixel = 32; var->bits_per_pixel = 32;
var->red.offset = 16; var->red.offset = 16;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment