📄 prom.c
字号:
}/* This function will enable the early boot text when doing OF booting. This * way, xmon output should work too */#ifdef CONFIG_BOOTX_TEXT__initstatic voidsetup_disp_fake_bi(ihandle dp){ int width = 640, height = 480, depth = 8, pitch; unsigned address; boot_infos_t* bi; unsigned long offset = reloc_offset(); struct pci_reg_property addrs[8]; int i, naddrs; char name[32]; char *getprop = RELOC("getprop"); prom_print(RELOC("Initializing fake screen: ")); memset(name, 0, sizeof(name)); call_prom(getprop, 4, 1, dp, RELOC("name"), name, sizeof(name)); name[sizeof(name)-1] = 0; prom_print(name); prom_print(RELOC("\n")); call_prom(getprop, 4, 1, dp, RELOC("width"), &width, sizeof(width)); call_prom(getprop, 4, 1, dp, RELOC("height"), &height, sizeof(height)); call_prom(getprop, 4, 1, dp, RELOC("depth"), &depth, sizeof(depth)); pitch = width * ((depth + 7) / 8); call_prom(getprop, 4, 1, dp, RELOC("linebytes"), &pitch, sizeof(pitch)); if (pitch == 1) pitch = 0x1000; /* for strange IBM display */ address = 0; call_prom(getprop, 4, 1, dp, RELOC("address"), &address, sizeof(address)); if (address == 0) { /* look for an assigned address with a size of >= 1MB */ naddrs = (int) call_prom(getprop, 4, 1, dp, RELOC("assigned-addresses"), addrs, sizeof(addrs)); naddrs /= sizeof(struct pci_reg_property); for (i = 0; i < naddrs; ++i) { if (addrs[i].size_lo >= (1 << 20)) { address = addrs[i].addr.a_lo; /* use the BE aperture if possible */ if (addrs[i].size_lo >= (16 << 20)) address += (8 << 20); break; } } if (address == 0) { prom_print(RELOC("Failed to get address\n")); return; } } /* kludge for valkyrie */ if (strcmp(name, RELOC("valkyrie")) == 0) address += 0x1000; 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__initstatic intprom_next_node(phandle *nodep){ phandle node; unsigned long offset = reloc_offset(); if ((node = *nodep) != 0 && (*nodep = call_prom(RELOC("child"), 1, 1, node)) != 0) return 1; if ((*nodep = call_prom(RELOC("peer"), 1, 1, node)) != 0) return 1; for (;;) { if ((node = call_prom(RELOC("parent"), 1, 1, node)) == 0) return 0; if ((*nodep = call_prom(RELOC("peer"), 1, 1, node)) != 0) return 1; }}/* * Make a copy of the device tree from the PROM. */__initstatic unsigned longcopy_device_tree(unsigned long mem_start, unsigned long mem_end){ phandle root; unsigned long new_start; struct device_node **allnextp; unsigned long offset = reloc_offset(); root = call_prom(RELOC("peer"), 1, 1, (phandle)0); if (root == (phandle)0) { prom_print(RELOC("couldn't get device tree root\n")); prom_exit(); } allnextp = &RELOC(allnodes); mem_start = ALIGN(mem_start); new_start = inspect_node(root, 0, mem_start, mem_end, &allnextp); *allnextp = 0; return new_start;}__initstatic unsigned longinspect_node(phandle node, struct device_node *dad, unsigned long mem_start, unsigned long mem_end, struct device_node ***allnextpp){ int l; phandle child; struct device_node *np; struct property *pp, **prev_propp; char *prev_name, *namep; unsigned char *valp; unsigned long offset = reloc_offset(); np = (struct device_node *) mem_start; mem_start += sizeof(struct device_node); memset(np, 0, sizeof(*np)); np->node = node; **allnextpp = PTRUNRELOC(np); *allnextpp = &np->allnext; if (dad != 0) { np->parent = PTRUNRELOC(dad); /* we temporarily use the `next' field as `last_child'. */ if (dad->next == 0) dad->child = PTRUNRELOC(np); else dad->next->sibling = PTRUNRELOC(np); dad->next = np; } /* get and store all properties */ prev_propp = &np->properties; prev_name = RELOC(""); for (;;) { pp = (struct property *) mem_start; namep = (char *) (pp + 1); pp->name = PTRUNRELOC(namep); if ((int) call_prom(RELOC("nextprop"), 3, 1, node, prev_name, namep) <= 0) break; mem_start = ALIGN((unsigned long)namep + strlen(namep) + 1); prev_name = namep; valp = (unsigned char *) mem_start; pp->value = PTRUNRELOC(valp); pp->length = (int) call_prom(RELOC("getprop"), 4, 1, node, namep, valp, mem_end - mem_start); if (pp->length < 0) continue;#ifdef MAX_PROPERTY_LENGTH if (pp->length > MAX_PROPERTY_LENGTH) continue; /* ignore this property */#endif mem_start = ALIGN(mem_start + pp->length); *prev_propp = PTRUNRELOC(pp); prev_propp = &pp->next; } *prev_propp = 0; /* get the node's full name */ l = (int) call_prom(RELOC("package-to-path"), 3, 1, node, (char *) mem_start, mem_end - mem_start); if (l >= 0) { np->full_name = PTRUNRELOC((char *) mem_start); *(char *)(mem_start + l) = 0; mem_start = ALIGN(mem_start + l + 1); } /* do all our children */ child = call_prom(RELOC("child"), 1, 1, node); while (child != (void *)0) { mem_start = inspect_node(child, np, mem_start, mem_end, allnextpp); child = call_prom(RELOC("peer"), 1, 1, child); } return mem_start;}/* * finish_device_tree is called once things are running normally * (i.e. with text and data mapped to the address they were linked at). * It traverses the device tree and fills in the name, type, * {n_}addrs and {n_}intrs fields of each node. */__initvoidfinish_device_tree(void){ unsigned long mem = (unsigned long) klimit; /* All newworld machines now use the interrupt tree */ struct device_node *np = allnodes; while(np && (_machine == _MACH_Pmac)) { if (get_property(np, "interrupt-parent", 0)) { pmac_newworld = 1; break; } np = np->allnext; } if ((_machine == _MACH_chrp) || (boot_infos == 0 && pmac_newworld)) use_of_interrupt_tree = 1; mem = finish_node(allnodes, mem, NULL, 0, 0); dev_tree_size = mem - (unsigned long) allnodes; klimit = (char *) mem;}/* * early_get_property is used to access the device tree image prepared * by BootX very early on, before the pointers in it have been relocated. */__init void *early_get_property(unsigned long base, unsigned long node, char *prop){ struct device_node *np = (struct device_node *)(base + node); struct property *pp; for (pp = np->properties; pp != 0; pp = pp->next) { pp = (struct property *) (base + (unsigned long)pp); if (strcmp((char *)((unsigned long)pp->name + base), prop) == 0) { return (void *)((unsigned long)pp->value + base); } } return 0;}__initstatic unsigned longfinish_node(struct device_node *np, unsigned long mem_start, interpret_func *ifunc, int naddrc, int nsizec){ struct device_node *child; int *ip; np->name = get_property(np, "name", 0); np->type = get_property(np, "device_type", 0); /* get the device addresses and interrupts */ if (ifunc != NULL) { mem_start = ifunc(np, mem_start, naddrc, nsizec); } if (use_of_interrupt_tree) { mem_start = finish_node_interrupts(np, mem_start); } /* Look for #address-cells and #size-cells properties. */ ip = (int *) get_property(np, "#address-cells", 0); if (ip != NULL) naddrc = *ip; ip = (int *) get_property(np, "#size-cells", 0); if (ip != NULL) nsizec = *ip; /* the f50 sets the name to 'display' and 'compatible' to what we * expect for the name -- Cort */ if (!strcmp(np->name, "display")) np->name = get_property(np, "compatible", 0); if (!strcmp(np->name, "device-tree")) ifunc = interpret_root_props; else if (np->type == 0) ifunc = NULL; else if (!strcmp(np->type, "pci") || !strcmp(np->type, "vci")) ifunc = interpret_pci_props; else if (!strcmp(np->type, "dbdma")) ifunc = interpret_dbdma_props; else if (!strcmp(np->type, "mac-io") || ifunc == interpret_macio_props) ifunc = interpret_macio_props; else if (!strcmp(np->type, "isa")) ifunc = interpret_isa_props; else if (!((ifunc == interpret_dbdma_props || ifunc == interpret_macio_props) && (!strcmp(np->type, "escc") || !strcmp(np->type, "media-bay")))) ifunc = NULL; /* if we were booted from BootX, convert the full name */ if (boot_infos && strncmp(np->full_name, "Devices:device-tree", 19) == 0) { if (np->full_name[19] == 0) { strcpy(np->full_name, "/"); } else if (np->full_name[19] == ':') { char *p = np->full_name + 19; np->full_name = p; for (; *p; ++p) if (*p == ':') *p = '/'; } } for (child = np->child; child != NULL; child = child->sibling) mem_start = finish_node(child, mem_start, ifunc, naddrc, nsizec); 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. */__initstatic unsigned longfinish_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; int cvt_irq; /* XXX on chrp, offset interrupt numbers for the 8259 by 0, those for the openpic by 16 */ cvt_irq = _machine == _MACH_chrp && get_property(node, "interrupt-parent", NULL) == 0; 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++; if (cvt_irq) np->intrs[i].line = openpic_to_irq(np->intrs[i].line); 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 * are offsets from the start of the tree. * This procedure updates the pointers. */__initvoid relocate_nodes(void){ unsigned long base; struct device_node *np; struct property *pp;#define ADDBASE(x) (x = (x)? ((typeof (x))((unsigned long)(x) + base)): 0) base = (unsigned long) boot_infos + boot_infos->deviceTreeOffset; allnodes = (struct device_node *)(base + 4); for (np = allnodes; np != 0; np = np->allnext) { ADDBASE(np->full_name); ADDBASE(np->properties); ADDBASE(np->parent); ADDBASE(np->child); ADDBASE(np->sibling); ADDBASE(np->allnext); for (pp = np->properties; pp != 0; pp = pp->next) { ADDBASE(pp->name); ADDBASE(pp->value); ADDBASE(pp->next); } }}__initstatic unsigned longinterpret_pci_props(struct device_node *np, unsigned long mem_start, int naddrc, int nsizec){ struct address_range *adr; struct pci_reg_property *pci_addrs; int i, l, *ip, ml;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -