diff options
author | Ralf Baechle <ralf@linux-mips.org> | 2000-02-23 00:40:54 +0000 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2000-02-23 00:40:54 +0000 |
commit | 529c593ece216e4aaffd36bd940cb94f1fa63129 (patch) | |
tree | 78f1c0b805f5656aa7b0417a043c5346f700a2cf /arch/ppc/kernel/prom.c | |
parent | 0bd079751d25808d1972baee5c4eaa1db2227257 (diff) |
Merge with 2.3.43. I did ignore all modifications to the qlogicisp.c
driver due to the Origin A64 hacks.
Diffstat (limited to 'arch/ppc/kernel/prom.c')
-rw-r--r-- | arch/ppc/kernel/prom.c | 625 |
1 files changed, 550 insertions, 75 deletions
diff --git a/arch/ppc/kernel/prom.c b/arch/ppc/kernel/prom.c index 049cde10f..a52bdd804 100644 --- a/arch/ppc/kernel/prom.c +++ b/arch/ppc/kernel/prom.c @@ -30,6 +30,10 @@ #include <asm/system.h> #include <asm/gemini.h> +#ifdef CONFIG_FB +#include <asm/linux_logo.h> +#endif + /* * Properties whose value is longer than this get excluded from our * copy of the device tree. This way we don't waste space storing @@ -91,7 +95,7 @@ unsigned int prom_num_displays = 0; char *of_stdout_device = 0; prom_entry prom = 0; -ihandle prom_chosen = 0, prom_stdout = 0; +ihandle prom_chosen = 0, prom_stdout = 0, prom_disp_node = 0; extern char *klimit; char *bootpath = 0; @@ -102,33 +106,35 @@ unsigned int rtas_entry = 0; /* physical pointer */ unsigned int rtas_size = 0; unsigned int old_rtas = 0; +int use_of_interrupt_tree = 0; static struct device_node *allnodes = 0; +#ifdef CONFIG_BOOTX_TEXT + static void clearscreen(void); static void flushscreen(void); -#ifdef CONFIG_BOOTX_TEXT - void drawchar(char c); void drawstring(const char *c); static void drawhex(unsigned long v); static void scrollscreen(void); static void draw_byte(unsigned char c, long locX, long locY); -static void draw_byte_32(unsigned char *bits, unsigned long *base); -static void draw_byte_16(unsigned char *bits, unsigned long *base); -static void draw_byte_8(unsigned char *bits, unsigned long *base); +static void draw_byte_32(unsigned char *bits, unsigned long *base, int rb); +static void draw_byte_16(unsigned char *bits, unsigned long *base, int rb); +static void draw_byte_8(unsigned char *bits, unsigned long *base, int rb); -static long g_loc_X; -static long g_loc_Y; -static long g_max_loc_X; -static long g_max_loc_Y; +/* We want those in data, not BSS */ +static long g_loc_X = 0; +static long g_loc_Y = 0; +static long g_max_loc_X = 0; +static long g_max_loc_Y = 0; #define cmapsz (16*256) static unsigned char vga_font[cmapsz]; -#endif +#endif /* CONFIG_BOOTX_TEXT */ static void *call_prom(const char *service, int nargs, int nret, ...); @@ -138,15 +144,25 @@ static unsigned long inspect_node(phandle, struct device_node *, unsigned long, unsigned long, struct device_node ***); static unsigned long finish_node(struct device_node *, unsigned long, interpret_func *); +static unsigned long finish_node_interrupts(struct device_node *, unsigned long); static unsigned long check_display(unsigned long); static int prom_next_node(phandle *); static void *early_get_property(unsigned long, unsigned long, char *); +#ifdef CONFIG_BOOTX_TEXT +static void setup_disp_fake_bi(ihandle dp); +static void prom_welcome(boot_infos_t* bi, unsigned long phys); +#endif + extern void enter_rtas(void *); extern unsigned long reloc_offset(void); extern char cmd_line[512]; /* XXX */ boot_infos_t *boot_infos = 0; /* init it so it's in data segment not bss */ +#ifdef CONFIG_BOOTX_TEXT +boot_infos_t *disp_bi = 0; +boot_infos_t fake_bi = {0,}; +#endif unsigned long dev_tree_size; /* @@ -240,7 +256,7 @@ prom_print(const char *msg) if (RELOC(prom_stdout) == 0) { #ifdef CONFIG_BOOTX_TEXT - if (RELOC(boot_infos) != 0) + if (RELOC(disp_bi) != 0) drawstring(msg); #endif return; @@ -261,7 +277,6 @@ prom_print(const char *msg) } } -unsigned long smp_ibm_chrp_hack __initdata = 0; unsigned long smp_chrp_cpu_nr __initdata = 1; /* @@ -269,23 +284,29 @@ unsigned long smp_chrp_cpu_nr __initdata = 1; * handling exceptions and the MMU hash table for us. */ __init -void +unsigned long prom_init(int r3, int r4, prom_entry pp) { #ifdef CONFIG_SMP int i; phandle node; char type[16], *path; -#endif +#endif + int chrp = 0; unsigned long mem; - ihandle prom_rtas; + ihandle prom_rtas, prom_mmu, prom_op; unsigned long offset = reloc_offset(); int l; char *p, *d; + int prom_version = 0; + unsigned long phys; + + /* Default */ + phys = offset + KERNELBASE; /* check if we're apus, return if we are */ if ( r3 == 0x61707573 ) - return; + return phys; /* If we came here from BootX, clear the screen, * set up some pointers and return. */ @@ -294,22 +315,20 @@ prom_init(int r3, int r4, prom_entry pp) unsigned long space; unsigned long ptr, x; char *model; -#ifdef CONFIG_BOOTX_TEXT - unsigned long flags; -#endif RELOC(boot_infos) = PTRUNRELOC(bi); if (!BOOT_INFO_IS_V2_COMPATIBLE(bi)) bi->logicalDisplayBase = 0; - clearscreen(); - #ifdef CONFIG_BOOTX_TEXT RELOC(g_loc_X) = 0; RELOC(g_loc_Y) = 0; RELOC(g_max_loc_X) = (bi->dispDeviceRect[2] - bi->dispDeviceRect[0]) / 8; RELOC(g_max_loc_Y) = (bi->dispDeviceRect[3] - bi->dispDeviceRect[1]) / 16; + RELOC(disp_bi) = PTRUNRELOC(bi); + clearscreen(); + /* Test if boot-info is compatible. Done only in config CONFIG_BOOTX_TEXT since there is nothing much we can do with an incompatible version, except display a message and eventually hang the processor... @@ -320,23 +339,9 @@ prom_init(int r3, int r4, prom_entry pp) if (!BOOT_INFO_IS_COMPATIBLE(bi)) prom_print(RELOC(" !!! WARNING - Incompatible version of BootX !!!\n\n\n")); - prom_print(RELOC("Welcome to Linux, kernel " UTS_RELEASE "\n")); - prom_print(RELOC("\nstarted at : 0x")); - drawhex(reloc_offset() + KERNELBASE); - prom_print(RELOC("\nlinked at : 0x")); - drawhex(KERNELBASE); - prom_print(RELOC("\nframe buffer at : 0x")); - drawhex((unsigned long)bi->dispDeviceBase); - prom_print(RELOC(" (phys), 0x")); - drawhex((unsigned long)bi->logicalDisplayBase); - prom_print(RELOC(" (log)")); - prom_print(RELOC("\nMSR : 0x")); - __asm__ __volatile__ ("mfmsr %0" : "=r" ((flags)) : : "memory"); - drawhex(flags); - prom_print(RELOC("\n\n")); -#endif - /* Out of the #if/#endif since it flushes the clearscreen too */ + prom_welcome(bi, phys); flushscreen(); +#endif /* CONFIG_BOOTX_TEXT */ /* New BootX enters kernel with MMU off, i/os are not allowed here. This hack will have been done by the boostrap anyway. @@ -381,12 +386,12 @@ prom_init(int r3, int r4, prom_entry pp) prom_print(RELOC("booting...\n")); flushscreen(); #endif - return; + return phys; } /* check if we're prep, return if we are */ if ( *(unsigned long *)(0) == 0xdeadc0de ) - return; + return phys; /* First get a handle for the stdout device */ RELOC(prom) = pp; @@ -407,6 +412,30 @@ prom_init(int r3, int r4, prom_entry pp) RELOC(of_stdout_device) = PTRUNRELOC(p); mem += strlen(p) + 1; + /* Find the OF version */ + prom_op = call_prom(RELOC("finddevice"), 1, 1, RELOC("/openprom")); + prom_version = 0; + if (prom_op != (void*)-1) { + char model[64]; + int sz; + sz = (int)call_prom(RELOC("getprop"), 4, 1, prom_op, RELOC("model"), model, 64); + if (sz > 0) { + char *c; + /* hack to skip the ibm chrp firmware # */ + if ( strncmp(model,RELOC("IBM"),3) ) { + for (c = model; *c; c++) + if (*c >= '0' && *c <= '9') { + prom_version = *c - '0'; + break; + } + } + else + chrp = 1; + } + } + if (prom_version >= 3) + prom_print(RELOC("OF Version 3 detected.\n")); + /* Get the boot device and translate it to a full OF pathname. */ p = (char *) mem; l = (int) call_prom(RELOC("getprop"), 4, 1, RELOC(prom_chosen), @@ -478,6 +507,42 @@ prom_init(int r3, int r4, prom_entry pp) prom_print(RELOC(" done\n")); } + /* If we are already running at 0xc0000000, we assume we were loaded by + * an OF bootloader which did set a BAT for us. This breaks OF translate + * so we force phys to be 0 + */ + if (offset == 0) + phys = 0; + else { + if ((int) call_prom(RELOC("getprop"), 4, 1, RELOC(prom_chosen), + RELOC("mmu"), &prom_mmu, sizeof(prom_mmu)) <= 0) { + prom_print(RELOC(" no MMU found\n")); + } else { + int nargs; + struct prom_args prom_args; + nargs = 4; + prom_args.service = RELOC("call-method"); + prom_args.nargs = nargs; + prom_args.nret = 4; + prom_args.args[0] = RELOC("translate"); + prom_args.args[1] = prom_mmu; + prom_args.args[2] = (void *)(offset + KERNELBASE); + prom_args.args[3] = (void *)1; + RELOC(prom)(&prom_args); + + /* We assume the phys. address size is 3 cells */ + if (prom_args.args[nargs] != 0) + prom_print(RELOC(" (translate failed) ")); + else + phys = (unsigned long)prom_args.args[nargs+3]; + } + } + +#ifdef CONFIG_BOOTX_TEXT + if (!chrp && RELOC(prom_disp_node) != 0) + setup_disp_fake_bi(RELOC(prom_disp_node)); +#endif + #ifdef CONFIG_SMP /* * With CHRP SMP we need to use the OF to start the other @@ -512,7 +577,7 @@ prom_init(int r3, int r4, prom_entry pp) node = call_prom(RELOC("finddevice"), 1, 1, RELOC("/")); if ( (int)call_prom(RELOC("getprop"), 4, 1, node, RELOC("device_type"),type, sizeof(type)) <= 0) - return; + return phys; /* copy the holding pattern code to someplace safe (8M) */ memcpy( (void *)(8<<20), RELOC(__secondary_hold), 0x100 ); @@ -554,6 +619,79 @@ prom_init(int r3, int r4, prom_entry pp) prom_print(RELOC("...failed\n")); } #endif + /* If OpenFirmware version >= 3, then use quiesce call */ + if (prom_version >= 3) { + prom_print(RELOC("Calling quiesce ...\n")); + call_prom(RELOC("quiesce"), 0, 0); + offset = reloc_offset(); + phys = offset + KERNELBASE; + } + +#ifdef CONFIG_BOOTX_TEXT + if (!chrp && RELOC(disp_bi)) { + RELOC(prom_stdout) = 0; + clearscreen(); + prom_welcome(PTRRELOC(RELOC(disp_bi)), phys); + prom_print(RELOC("booting...\n")); + } +#endif + + return phys; +} + +#ifdef CONFIG_BOOTX_TEXT +__init static void +prom_welcome(boot_infos_t* bi, unsigned long phys) +{ + unsigned long offset = reloc_offset(); + unsigned long flags; + unsigned long pvr; + + prom_print(RELOC("Welcome to Linux, kernel " UTS_RELEASE "\n")); + prom_print(RELOC("\nstarted at : 0x")); + drawhex(phys); + prom_print(RELOC("\nlinked at : 0x")); + drawhex(KERNELBASE); + prom_print(RELOC("\nframe buffer at : 0x")); + drawhex((unsigned long)bi->dispDeviceBase); + prom_print(RELOC(" (phys), 0x")); + drawhex((unsigned long)bi->logicalDisplayBase); + prom_print(RELOC(" (log)")); + prom_print(RELOC("\nMSR : 0x")); + __asm__ __volatile__ ("mfmsr %0" : "=r" (flags)); + drawhex(flags); + __asm__ __volatile__ ("mfspr %0, 287" : "=r" (pvr)); + pvr >>= 16; + if (pvr > 1) { + prom_print(RELOC("\nHID0 : 0x")); + __asm__ __volatile__ ("mfspr %0, 1008" : "=r" (flags)); + drawhex(flags); + } + if (pvr == 8 || pvr == 12) { + prom_print(RELOC("\nICTC : 0x")); + __asm__ __volatile__ ("mfspr %0, 1019" : "=r" (flags)); + drawhex(flags); + } + prom_print(RELOC("\n\n")); +} +#endif + +static int prom_set_color(ihandle ih, int i, int r, int g, int b) +{ + struct prom_args prom_args; + unsigned long offset = reloc_offset(); + + prom_args.service = RELOC("call-method"); + prom_args.nargs = 6; + prom_args.nret = 1; + prom_args.args[0] = RELOC("color!"); + prom_args.args[1] = ih; + prom_args.args[2] = (void *) i; + prom_args.args[3] = (void *) b; + prom_args.args[4] = (void *) g; + prom_args.args[5] = (void *) r; + RELOC(prom)(&prom_args); + return (int) prom_args.args[6]; } /* @@ -573,6 +711,26 @@ check_display(unsigned long mem) int i; unsigned long offset = reloc_offset(); char type[16], *path; + static unsigned char default_colors[] = { + 0x00, 0x00, 0x00, + 0x00, 0x00, 0xaa, + 0x00, 0xaa, 0x00, + 0x00, 0xaa, 0xaa, + 0xaa, 0x00, 0x00, + 0xaa, 0x00, 0xaa, + 0xaa, 0xaa, 0x00, + 0xaa, 0xaa, 0xaa, + 0x55, 0x55, 0x55, + 0x55, 0x55, 0xff, + 0x55, 0xff, 0x55, + 0x55, 0xff, 0xff, + 0xff, 0x55, 0x55, + 0xff, 0x55, 0xff, + 0xff, 0xff, 0x55, + 0xff, 0xff, 0xff + }; + + RELOC(prom_disp_node) = 0; for (node = 0; prom_next_node(&node); ) { type[0] = 0; @@ -595,6 +753,26 @@ check_display(unsigned long mem) } prom_print(RELOC("... ok\n")); + if (RELOC(prom_disp_node) == 0) + RELOC(prom_disp_node) = node; + + /* Setup a useable color table when the appropriate + * method is available. Should update this to set-colors */ + for (i = 0; i < 32; i++) + if (prom_set_color(ih, i, RELOC(default_colors)[i*3], + RELOC(default_colors)[i*3+1], + RELOC(default_colors)[i*3+2]) != 0) + break; + +#ifdef CONFIG_FB + for (i = 0; i < LINUX_LOGO_COLORS; i++) + if (prom_set_color(ih, i + 32, + RELOC(linux_logo_red)[i], + RELOC(linux_logo_green)[i], + RELOC(linux_logo_blue)[i]) != 0) + break; +#endif /* CONFIG_FB */ + /* * If this display is the device that OF is using for stdout, * move it to the front of the list. @@ -614,6 +792,79 @@ check_display(unsigned long mem) return ALIGN(mem); } +/* This function will enable the early boot text when doing OF booting. This + * way, xmon output should work too + */ +#ifdef CONFIG_BOOTX_TEXT +__init +static void +setup_disp_fake_bi(ihandle dp) +{ + unsigned int len; + int width = 640, height = 480, depth = 8, pitch; + unsigned address; + boot_infos_t* bi; + unsigned long offset = reloc_offset(); + + prom_print(RELOC("Initing fake screen\n")); + + len = 0; + call_prom(RELOC("getprop"), 4, 1, dp, RELOC("depth"), &len, sizeof(len)); + if (len == 0) + prom_print(RELOC("Warning: assuming display depth = 8\n")); + else + depth = len; + width = len = 0; + call_prom(RELOC("getprop"), 4, 1, dp, RELOC("width"), &len, sizeof(len)); + width = len; + if (width == 0) { + prom_print(RELOC("Failed to get width\n")); + return; + } + height = len = 0; + call_prom(RELOC("getprop"), 4, 1, dp, RELOC("height"), &len, sizeof(len)); + height = len; + if (height == 0) { + prom_print(RELOC("Failed to get height\n")); + return; + } + pitch = len = 0; + call_prom(RELOC("getprop"), 4, 1, dp, RELOC("linebytes"), &len, sizeof(len)); + pitch = len; + if (pitch == 0) { + prom_print(RELOC("Failed to get pitch\n")); + return; + } + address = len = 0; + call_prom(RELOC("getprop"), 4, 1, dp, RELOC("address"), &len, sizeof(len)); + address = len; + if (address == 0) { + prom_print(RELOC("Failed to get address\n")); + return; + } +#if 0 + /* kludge for valkyrie */ + if (strcmp(dp->name, "valkyrie") == 0) + address += 0x1000; + } +#endif + + RELOC(disp_bi) = &fake_bi; + bi = PTRRELOC((&fake_bi)); + RELOC(g_loc_X) = 0; + RELOC(g_loc_Y) = 0; + RELOC(g_max_loc_X) = width / 8; + RELOC(g_max_loc_Y) = height / 16; + bi->logicalDisplayBase = (unsigned char *)address; + bi->dispDeviceBase = (unsigned char *)address; + bi->dispDeviceRowBytes = pitch; + bi->dispDeviceDepth = depth; + bi->dispDeviceRect[0] = bi->dispDeviceRect[1] = 0; + bi->dispDeviceRect[2] = width; + bi->dispDeviceRect[3] = height; +} +#endif + __init static int prom_next_node(phandle *nodep) @@ -748,6 +999,16 @@ void finish_device_tree(void) { unsigned long mem = (unsigned long) klimit; + char* model; + + /* Here, we decide if we'll use the interrupt-tree (new Core99 code) or not. + * This code was only tested with Core99 machines so far, but should be easily + * adapted to older newworld machines (iMac, B&W G3, Lombard). + */ + model = get_property(allnodes, "model", 0); + if ((boot_infos == 0) && model && (strcmp(model, "PowerBook2,1") == 0 + || strcmp(model, "PowerMac2,1") == 0 || strcmp(model, "PowerMac3,1") == 0)) + use_of_interrupt_tree = 1; mem = finish_node(allnodes, mem, NULL); dev_tree_size = mem - (unsigned long) allnodes; @@ -788,6 +1049,9 @@ finish_node(struct device_node *np, unsigned long mem_start, if (ifunc != NULL) { mem_start = ifunc(np, mem_start); } + if (use_of_interrupt_tree) { + mem_start = finish_node_interrupts(np, mem_start); + } /* the f50 sets the name to 'display' and 'compatible' to what we * expect for the name -- Cort @@ -834,6 +1098,133 @@ finish_node(struct device_node *np, unsigned long mem_start, return mem_start; } +/* This routine walks the interrupt tree for a given device node and gather + * all necessary informations according to the draft interrupt mapping + * for CHRP. The current version was only tested on Apple "Core99" machines + * and may not handle cascaded controllers correctly. + */ +__init +static unsigned long +finish_node_interrupts(struct device_node *np, unsigned long mem_start) +{ + /* Finish this node */ + unsigned int *isizep, *asizep, *interrupts, *map, *map_mask, *reg; + phandle *parent; + struct device_node *node, *parent_node; + int l, isize, ipsize, asize, map_size, regpsize; + + /* Currently, we don't look at all nodes with no "interrupts" property */ + interrupts = (unsigned int *)get_property(np, "interrupts", &l); + if (interrupts == NULL) + return mem_start; + ipsize = l>>2; + + reg = (unsigned int *)get_property(np, "reg", &l); + regpsize = l>>2; + + /* We assume default interrupt cell size is 1 (bugus ?) */ + isize = 1; + node = np; + + do { + /* We adjust the cell size if the current parent contains an #interrupt-cells + * property */ + isizep = (unsigned int *)get_property(node, "#interrupt-cells", &l); + if (isizep) + isize = *isizep; + + /* We don't do interrupt cascade (ISA) for now, we stop on the first + * controller found + */ + if (get_property(node, "interrupt-controller", &l)) { + int i,j; + np->intrs = (struct interrupt_info *) mem_start; + np->n_intrs = ipsize / isize; + mem_start += np->n_intrs * sizeof(struct interrupt_info); + for (i = 0; i < np->n_intrs; ++i) { + np->intrs[i].line = *interrupts++; + np->intrs[i].sense = 0; + if (isize > 1) + np->intrs[i].sense = *interrupts++; + for (j=2; j<isize; j++) + interrupts++; + } + return mem_start; + } + /* We lookup for an interrupt-map. This code can only handle one interrupt + * per device in the map. We also don't handle #address-cells in the parent + * I skip the pci node itself here, may not be necessary but I don't like it's + * reg property. + */ + if (np != node) + map = (unsigned int *)get_property(node, "interrupt-map", &l); + else + map = NULL; + if (map && l) { + int i, found, temp_isize; + map_size = l>>2; + map_mask = (unsigned int *)get_property(node, "interrupt-map-mask", &l); + asizep = (unsigned int *)get_property(node, "#address-cells", &l); + if (asizep && l == sizeof(unsigned int)) + asize = *asizep; + else + asize = 0; + found = 0; + while(map_size>0 && !found) { + found = 1; + for (i=0; i<asize; i++) { + unsigned int mask = map_mask ? map_mask[i] : 0xffffffff; + if (!reg || (i>=regpsize) || ((mask & *map) != (mask & reg[i]))) + found = 0; + map++; + map_size--; + } + for (i=0; i<isize; i++) { + unsigned int mask = map_mask ? map_mask[i+asize] : 0xffffffff; + if ((mask & *map) != (mask & interrupts[i])) + found = 0; + map++; + map_size--; + } + parent = *((phandle *)(map)); + map+=1; map_size-=1; + parent_node = find_phandle(parent); + temp_isize = isize; + if (parent_node) { + isizep = (unsigned int *)get_property(parent_node, "#interrupt-cells", &l); + if (isizep) + temp_isize = *isizep; + } + if (!found) { + map += temp_isize; + map_size-=temp_isize; + } + } + if (found) { + node = parent_node; + reg = NULL; + regpsize = 0; + interrupts = (unsigned int *)map; + ipsize = temp_isize*1; + continue; + } + } + /* We look for an explicit interrupt-parent. + */ + parent = (phandle *)get_property(node, "interrupt-parent", &l); + if (parent && (l == sizeof(phandle)) && + (parent_node = find_phandle(*parent))) { + node = parent_node; + continue; + } + /* Default, get real parent */ + node = node->parent; + } while(node); + + return mem_start; +} + + /* * When BootX makes a copy of the device tree from the MacOS * Name Registry, it is in the format we use but all of the pointers @@ -892,6 +1283,9 @@ interpret_pci_props(struct device_node *np, unsigned long mem_start) mem_start += i * sizeof(struct address_range); } + if (use_of_interrupt_tree) + return mem_start; + /* * If the pci host bridge has an interrupt-map property, * look for our node in it. @@ -901,14 +1295,28 @@ interpret_pci_props(struct device_node *np, unsigned long mem_start) get_property(np->parent, "interrupt-map", &ml)) != 0 && (ip = (int *) get_property(np, "interrupts", &l)) != 0) { unsigned int devfn = pci_addrs[0].addr.a_hi & 0xff00; + unsigned int cell_size; + struct device_node* np2; + /* This is hackish, but is only used for BootX booting */ + cell_size = sizeof(struct pci_intr_map); + np2 = np->parent; + while(np2) { + if (device_is_compatible(np2, "uni-north")) { + cell_size += 4; + break; + } + np2 = np2->parent; + } np->n_intrs = 0; np->intrs = (struct interrupt_info *) mem_start; - for (i = 0; (ml -= sizeof(struct pci_intr_map)) >= 0; ++i) { - if (imp[i].addr.a_hi == devfn) { - np->intrs[np->n_intrs].line = imp[i].intr; - np->intrs[np->n_intrs].sense = 0; + for (i = 0; (ml -= cell_size) >= 0; ++i) { + if (imp->addr.a_hi == devfn) { + np->intrs[np->n_intrs].line = imp->intr; + np->intrs[np->n_intrs].sense = 0; /* FIXME */ ++np->n_intrs; } + imp = (struct pci_intr_map *)(((unsigned int)imp) + + cell_size); } if (np->n_intrs == 0) np->intrs = 0; @@ -965,6 +1373,9 @@ interpret_dbdma_props(struct device_node *np, unsigned long mem_start) mem_start += i * sizeof(struct address_range); } + if (use_of_interrupt_tree) + return mem_start; + ip = (int *) get_property(np, "AAPL,interrupts", &l); if (ip == 0) ip = (int *) get_property(np, "interrupts", &l); @@ -988,13 +1399,14 @@ interpret_macio_props(struct device_node *np, unsigned long mem_start) struct reg_property *rp; struct address_range *adr; unsigned long base_address; - int i, l, *ip; + int i, l, keylargo, *ip; struct device_node *db; base_address = 0; for (db = np->parent; db != NULL; db = db->parent) { if (!strcmp(db->type, "mac-io") && db->n_addrs != 0) { base_address = db->addrs[0].address; + keylargo = device_is_compatible(db, "Keylargo"); break; } } @@ -1014,6 +1426,9 @@ interpret_macio_props(struct device_node *np, unsigned long mem_start) mem_start += i * sizeof(struct address_range); } + if (use_of_interrupt_tree) + return mem_start; + ip = (int *) get_property(np, "interrupts", &l); if (ip == 0) ip = (int *) get_property(np, "AAPL,interrupts", &l); @@ -1022,9 +1437,15 @@ interpret_macio_props(struct device_node *np, unsigned long mem_start) if (_machine == _MACH_Pmac) { /* for the iMac */ np->n_intrs = l / sizeof(int); + /* Hack for BootX on Core99 */ + if (keylargo) + np->n_intrs = np->n_intrs/2; for (i = 0; i < np->n_intrs; ++i) { np->intrs[i].line = *ip++; - np->intrs[i].sense = 0; + if (keylargo) + np->intrs[i].sense = *ip++; + else + np->intrs[i].sense = 0; } } else { /* CHRP machines */ @@ -1064,6 +1485,9 @@ interpret_isa_props(struct device_node *np, unsigned long mem_start) mem_start += i * sizeof(struct address_range); } + if (use_of_interrupt_tree) + return mem_start; + ip = (int *) get_property(np, "interrupts", &l); if (ip != 0) { np->intrs = (struct interrupt_info *) mem_start; @@ -1101,6 +1525,9 @@ interpret_root_props(struct device_node *np, unsigned long mem_start) mem_start += i * sizeof(struct address_range); } + if (use_of_interrupt_tree) + return mem_start; + ip = (int *) get_property(np, "AAPL,interrupts", &l); if (ip == 0) ip = (int *) get_property(np, "interrupts", &l); @@ -1157,6 +1584,49 @@ find_type_devices(const char *type) return head; } +/* Finds a device node given its PCI bus number, device number + * and function number + */ +__openfirmware +struct device_node * +find_pci_device_OFnode(unsigned char bus, unsigned char dev_fn) +{ + struct device_node* np; + unsigned int *reg; + int l; + + for (np = allnodes; np != 0; np = np->allnext) { + char *pname = np->parent ? + (char *)get_property(np->parent, "name", &l) : 0; + if (pname && strcmp(pname, "mac-io") == 0) + continue; + reg = (unsigned int *) get_property(np, "reg", &l); + if (reg == 0 || l < sizeof(struct reg_property)) + continue; + if (((reg[0] >> 8) & 0xff) == dev_fn && ((reg[0] >> 16) & 0xff) == bus) + break; + } + return np; +} + +/* + * Returns all nodes linked together + */ +__openfirmware +struct device_node * +find_all_nodes(void) +{ + struct device_node *head, **prevp, *np; + + prevp = &head; + for (np = allnodes; np != 0; np = np->allnext) { + *prevp = np; + prevp = &np->next; + } + *prevp = 0; + return head; +} + /* Checks if the given "compat" string matches one of the strings in * the device's "compatible" property */ @@ -1377,18 +1847,28 @@ abort() prom_exit(); } -#ifdef CONFIG_XMON +#ifdef CONFIG_BOOTX_TEXT + +/* Here's a small text engine to use during early boot or for debugging purposes + * + * todo: + * + * - build some kind of vgacon with it to enable early printk + * - move to a separate file + * - add a few video driver hooks to keep in sync with display + * changes. + */ + __init void map_bootx_text(void) { - if (boot_infos == 0) + if (disp_bi == 0) return; - boot_infos->logicalDisplayBase = - ioremap((unsigned long) boot_infos->dispDeviceBase, - boot_infos->dispDeviceRowBytes * boot_infos->dispDeviceRect[3]); + disp_bi->logicalDisplayBase = + ioremap((unsigned long) disp_bi->dispDeviceBase, + disp_bi->dispDeviceRowBytes * disp_bi->dispDeviceRect[3]); } -#endif /* CONFIG_XMON */ /* Calc the base address of a given point (x,y) */ __pmac @@ -1410,7 +1890,7 @@ static void clearscreen(void) { unsigned long offset = reloc_offset(); - boot_infos_t* bi = PTRRELOC(RELOC(boot_infos)); + boot_infos_t* bi = PTRRELOC(RELOC(disp_bi)); unsigned long *base = (unsigned long *)calc_base(bi, 0, 0); unsigned long width = ((bi->dispDeviceRect[2] - bi->dispDeviceRect[0]) * (bi->dispDeviceDepth >> 3)) >> 2; @@ -1435,7 +1915,7 @@ static void flushscreen(void) { unsigned long offset = reloc_offset(); - boot_infos_t* bi = PTRRELOC(RELOC(boot_infos)); + boot_infos_t* bi = PTRRELOC(RELOC(disp_bi)); unsigned long *base = (unsigned long *)calc_base(bi, 0, 0); unsigned long width = ((bi->dispDeviceRect[2] - bi->dispDeviceRect[0]) * (bi->dispDeviceDepth >> 3)) >> 2; @@ -1452,14 +1932,12 @@ flushscreen(void) } } -#ifdef CONFIG_BOOTX_TEXT - __pmac static void scrollscreen(void) { unsigned long offset = reloc_offset(); - boot_infos_t* bi = PTRRELOC(RELOC(boot_infos)); + boot_infos_t* bi = PTRRELOC(RELOC(disp_bi)); unsigned long *src = (unsigned long *)calc_base(bi,0,16); unsigned long *dst = (unsigned long *)calc_base(bi,0,0); unsigned long width = ((bi->dispDeviceRect[2] - bi->dispDeviceRect[0]) * @@ -1563,19 +2041,20 @@ static void draw_byte(unsigned char c, long locX, long locY) { unsigned long offset = reloc_offset(); - boot_infos_t* bi = PTRRELOC(RELOC(boot_infos)); + boot_infos_t* bi = PTRRELOC(RELOC(disp_bi)); unsigned char *base = calc_base(bi, locX << 3, locY << 4); unsigned char *font = &RELOC(vga_font)[((unsigned long)c) * 16]; + int rb = bi->dispDeviceRowBytes; switch(bi->dispDeviceDepth) { case 32: - draw_byte_32(font, (unsigned long *)base); + draw_byte_32(font, (unsigned long *)base, rb); break; case 16: - draw_byte_16(font, (unsigned long *)base); + draw_byte_16(font, (unsigned long *)base, rb); break; case 8: - draw_byte_8(font, (unsigned long *)base); + draw_byte_8(font, (unsigned long *)base, rb); break; default: break; @@ -1613,15 +2092,12 @@ static unsigned long expand_bits_16[4] = { __pmac static void -draw_byte_32(unsigned char *font, unsigned long *base) +draw_byte_32(unsigned char *font, unsigned long *base, int rb) { - unsigned long offset = reloc_offset(); - boot_infos_t* bi = PTRRELOC(RELOC(boot_infos)); int l, bits; int fg = 0xFFFFFFFFUL; int bg = 0x00000000UL; - for (l = 0; l < 16; ++l) { bits = *font++; @@ -1633,19 +2109,18 @@ draw_byte_32(unsigned char *font, unsigned long *base) base[5] = (-((bits >> 2) & 1) & fg) ^ bg; base[6] = (-((bits >> 1) & 1) & fg) ^ bg; base[7] = (-(bits & 1) & fg) ^ bg; - base = (unsigned long *) ((char *)base + bi->dispDeviceRowBytes); + base = (unsigned long *) ((char *)base + rb); } } __pmac static void -draw_byte_16(unsigned char *font, unsigned long *base) +draw_byte_16(unsigned char *font, unsigned long *base, int rb) { - unsigned long offset = reloc_offset(); - boot_infos_t* bi = PTRRELOC(RELOC(boot_infos)); int l, bits; int fg = 0xFFFFFFFFUL; int bg = 0x00000000UL; + unsigned long offset = reloc_offset(); unsigned long *eb = RELOC(expand_bits_16); for (l = 0; l < 16; ++l) @@ -1655,19 +2130,18 @@ draw_byte_16(unsigned char *font, unsigned long *base) base[1] = (eb[(bits >> 4) & 3] & fg) ^ bg; base[2] = (eb[(bits >> 2) & 3] & fg) ^ bg; base[3] = (eb[bits & 3] & fg) ^ bg; - base = (unsigned long *) ((char *)base + bi->dispDeviceRowBytes); + base = (unsigned long *) ((char *)base + rb); } } __pmac static void -draw_byte_8(unsigned char *font, unsigned long *base) +draw_byte_8(unsigned char *font, unsigned long *base, int rb) { - unsigned long offset = reloc_offset(); - boot_infos_t* bi = PTRRELOC(RELOC(boot_infos)); int l, bits; int fg = 0x0F0F0F0FUL; int bg = 0x00000000UL; + unsigned long offset = reloc_offset(); unsigned long *eb = RELOC(expand_bits_8); for (l = 0; l < 16; ++l) @@ -1675,7 +2149,7 @@ draw_byte_8(unsigned char *font, unsigned long *base) bits = *font++; base[0] = (eb[bits >> 4] & fg) ^ bg; base[1] = (eb[bits & 0xf] & fg) ^ bg; - base = (unsigned long *) ((char *)base + bi->dispDeviceRowBytes); + base = (unsigned long *) ((char *)base + rb); } } @@ -2026,3 +2500,4 @@ static unsigned char vga_font[cmapsz] = { }; #endif /* CONFIG_BOOTX_TEXT */ + |