📄 prom_init.c
字号:
*mem_start = _ALIGN(*mem_start, 4); } /* Add a "linux,phandle" property. */ soff = dt_find_string(RELOC("linux,phandle")); if (soff == 0) prom_printf("WARNING: Can't find string index for" " <linux-phandle> node %s\n", path); else { dt_push_token(OF_DT_PROP, mem_start, mem_end); dt_push_token(4, mem_start, mem_end); dt_push_token(soff, mem_start, mem_end); valp = make_room(mem_start, mem_end, 4, 4); *(u32 *)valp = node; } /* do all our children */ child = call_prom("child", 1, 1, node); while (child != 0) { scan_dt_build_struct(child, mem_start, mem_end); child = call_prom("peer", 1, 1, child); } dt_push_token(OF_DT_END_NODE, mem_start, mem_end);}static void __init flatten_device_tree(void){ phandle root; unsigned long mem_start, mem_end, room; struct boot_param_header *hdr; struct prom_t *_prom = &RELOC(prom); char *namep; u64 *rsvmap; /* * Check how much room we have between alloc top & bottom (+/- a * few pages), crop to 4Mb, as this is our "chuck" size */ room = RELOC(alloc_top) - RELOC(alloc_bottom) - 0x4000; if (room > DEVTREE_CHUNK_SIZE) room = DEVTREE_CHUNK_SIZE; prom_debug("starting device tree allocs at %x\n", RELOC(alloc_bottom)); /* Now try to claim that */ mem_start = (unsigned long)alloc_up(room, PAGE_SIZE); if (mem_start == 0) prom_panic("Can't allocate initial device-tree chunk\n"); mem_end = RELOC(alloc_top); /* Get root of tree */ root = call_prom("peer", 1, 1, (phandle)0); if (root == (phandle)0) prom_panic ("couldn't get device tree root\n"); /* Build header and make room for mem rsv map */ mem_start = _ALIGN(mem_start, 4); hdr = make_room(&mem_start, &mem_end, sizeof(struct boot_param_header), 4); RELOC(dt_header_start) = (unsigned long)hdr; rsvmap = make_room(&mem_start, &mem_end, sizeof(mem_reserve_map), 8); /* Start of strings */ mem_start = PAGE_ALIGN(mem_start); RELOC(dt_string_start) = mem_start; mem_start += 4; /* hole */ /* Add "linux,phandle" in there, we'll need it */ namep = make_room(&mem_start, &mem_end, 16, 1); strcpy(namep, RELOC("linux,phandle")); mem_start = (unsigned long)namep + strlen(namep) + 1; /* Build string array */ prom_printf("Building dt strings...\n"); scan_dt_build_strings(root, &mem_start, &mem_end); RELOC(dt_string_end) = mem_start; /* Build structure */ mem_start = PAGE_ALIGN(mem_start); RELOC(dt_struct_start) = mem_start; prom_printf("Building dt structure...\n"); scan_dt_build_struct(root, &mem_start, &mem_end); dt_push_token(OF_DT_END, &mem_start, &mem_end); RELOC(dt_struct_end) = PAGE_ALIGN(mem_start); /* Finish header */ hdr->boot_cpuid_phys = _prom->cpu; hdr->magic = OF_DT_HEADER; hdr->totalsize = RELOC(dt_struct_end) - RELOC(dt_header_start); hdr->off_dt_struct = RELOC(dt_struct_start) - RELOC(dt_header_start); hdr->off_dt_strings = RELOC(dt_string_start) - RELOC(dt_header_start); hdr->dt_strings_size = RELOC(dt_string_end) - RELOC(dt_string_start); hdr->off_mem_rsvmap = ((unsigned long)rsvmap) - RELOC(dt_header_start); hdr->version = OF_DT_VERSION; /* Version 16 is not backward compatible */ hdr->last_comp_version = 0x10; /* Copy the reserve map in */ memcpy(rsvmap, RELOC(mem_reserve_map), sizeof(mem_reserve_map));#ifdef DEBUG_PROM { int i; prom_printf("reserved memory map:\n"); for (i = 0; i < RELOC(mem_reserve_cnt); i++) prom_printf(" %x - %x\n", RELOC(mem_reserve_map)[i].base, RELOC(mem_reserve_map)[i].size); }#endif /* Bump mem_reserve_cnt to cause further reservations to fail * since it's too late. */ RELOC(mem_reserve_cnt) = MEM_RESERVE_MAP_SIZE; prom_printf("Device tree strings 0x%x -> 0x%x\n", RELOC(dt_string_start), RELOC(dt_string_end)); prom_printf("Device tree struct 0x%x -> 0x%x\n", RELOC(dt_struct_start), RELOC(dt_struct_end));}#ifdef CONFIG_PPC_MAPLE/* PIBS Version 1.05.0000 04/26/2005 has an incorrect /ht/isa/ranges property. * The values are bad, and it doesn't even have the right number of cells. */static void __init fixup_device_tree_maple(void){ phandle isa; u32 rloc = 0x01002000; /* IO space; PCI device = 4 */ u32 isa_ranges[6]; char *name; name = "/ht@0/isa@4"; isa = call_prom("finddevice", 1, 1, ADDR(name)); if (!PHANDLE_VALID(isa)) { name = "/ht@0/isa@6"; isa = call_prom("finddevice", 1, 1, ADDR(name)); rloc = 0x01003000; /* IO space; PCI device = 6 */ } if (!PHANDLE_VALID(isa)) return; if (prom_getproplen(isa, "ranges") != 12) return; if (prom_getprop(isa, "ranges", isa_ranges, sizeof(isa_ranges)) == PROM_ERROR) return; if (isa_ranges[0] != 0x1 || isa_ranges[1] != 0xf4000000 || isa_ranges[2] != 0x00010000) return; prom_printf("Fixing up bogus ISA range on Maple/Apache...\n"); isa_ranges[0] = 0x1; isa_ranges[1] = 0x0; isa_ranges[2] = rloc; isa_ranges[3] = 0x0; isa_ranges[4] = 0x0; isa_ranges[5] = 0x00010000; prom_setprop(isa, name, "ranges", isa_ranges, sizeof(isa_ranges));}#else#define fixup_device_tree_maple()#endif#ifdef CONFIG_PPC_CHRP/* * Pegasos and BriQ lacks the "ranges" property in the isa node * Pegasos needs decimal IRQ 14/15, not hexadecimal * Pegasos has the IDE configured in legacy mode, but advertised as native */static void __init fixup_device_tree_chrp(void){ phandle ph; u32 prop[6]; u32 rloc = 0x01006000; /* IO space; PCI device = 12 */ char *name; int rc; name = "/pci@80000000/isa@c"; ph = call_prom("finddevice", 1, 1, ADDR(name)); if (!PHANDLE_VALID(ph)) { name = "/pci@ff500000/isa@6"; ph = call_prom("finddevice", 1, 1, ADDR(name)); rloc = 0x01003000; /* IO space; PCI device = 6 */ } if (PHANDLE_VALID(ph)) { rc = prom_getproplen(ph, "ranges"); if (rc == 0 || rc == PROM_ERROR) { prom_printf("Fixing up missing ISA range on Pegasos...\n"); prop[0] = 0x1; prop[1] = 0x0; prop[2] = rloc; prop[3] = 0x0; prop[4] = 0x0; prop[5] = 0x00010000; prom_setprop(ph, name, "ranges", prop, sizeof(prop)); } } name = "/pci@80000000/ide@C,1"; ph = call_prom("finddevice", 1, 1, ADDR(name)); if (PHANDLE_VALID(ph)) { prom_printf("Fixing up IDE interrupt on Pegasos...\n"); prop[0] = 14; prop[1] = 0x0; prom_setprop(ph, name, "interrupts", prop, 2*sizeof(u32)); prom_printf("Fixing up IDE class-code on Pegasos...\n"); rc = prom_getprop(ph, "class-code", prop, sizeof(u32)); if (rc == sizeof(u32)) { prop[0] &= ~0x5; prom_setprop(ph, name, "class-code", prop, sizeof(u32)); } }}#else#define fixup_device_tree_chrp()#endif#if defined(CONFIG_PPC64) && defined(CONFIG_PPC_PMAC)static void __init fixup_device_tree_pmac(void){ phandle u3, i2c, mpic; u32 u3_rev; u32 interrupts[2]; u32 parent; /* Some G5s have a missing interrupt definition, fix it up here */ u3 = call_prom("finddevice", 1, 1, ADDR("/u3@0,f8000000")); if (!PHANDLE_VALID(u3)) return; i2c = call_prom("finddevice", 1, 1, ADDR("/u3@0,f8000000/i2c@f8001000")); if (!PHANDLE_VALID(i2c)) return; mpic = call_prom("finddevice", 1, 1, ADDR("/u3@0,f8000000/mpic@f8040000")); if (!PHANDLE_VALID(mpic)) return; /* check if proper rev of u3 */ if (prom_getprop(u3, "device-rev", &u3_rev, sizeof(u3_rev)) == PROM_ERROR) return; if (u3_rev < 0x35 || u3_rev > 0x39) return; /* does it need fixup ? */ if (prom_getproplen(i2c, "interrupts") > 0) return; prom_printf("fixing up bogus interrupts for u3 i2c...\n"); /* interrupt on this revision of u3 is number 0 and level */ interrupts[0] = 0; interrupts[1] = 1; prom_setprop(i2c, "/u3@0,f8000000/i2c@f8001000", "interrupts", &interrupts, sizeof(interrupts)); parent = (u32)mpic; prom_setprop(i2c, "/u3@0,f8000000/i2c@f8001000", "interrupt-parent", &parent, sizeof(parent));}#else#define fixup_device_tree_pmac()#endif#ifdef CONFIG_PPC_EFIKA/* The current fw of the Efika has a device tree needs quite a few * fixups to be compliant with the mpc52xx bindings. It's currently * unknown if it will ever be compliant (come on bPlan ...) so we do fixups. * NOTE that we (barely) tolerate it because the EFIKA was out before * the bindings were finished, for any new boards -> RTFM ! */struct subst_entry { char *path; char *property; void *value; int value_len;};static void __init fixup_device_tree_efika(void){ /* Substitution table */ #define prop_cstr(x) x, sizeof(x) int prop_sound_irq[3] = { 2, 2, 0 }; int prop_bcomm_irq[3*16] = { 3,0,0, 3,1,0, 3,2,0, 3,3,0, 3,4,0, 3,5,0, 3,6,0, 3,7,0, 3,8,0, 3,9,0, 3,10,0, 3,11,0, 3,12,0, 3,13,0, 3,14,0, 3,15,0 }; struct subst_entry efika_subst_table[] = { { "/", "device_type", prop_cstr("efika") }, { "/builtin", "device_type", prop_cstr("soc") }, { "/builtin/ata", "compatible", prop_cstr("mpc5200b-ata\0mpc5200-ata"), }, { "/builtin/bestcomm", "compatible", prop_cstr("mpc5200b-bestcomm\0mpc5200-bestcomm") }, { "/builtin/bestcomm", "interrupts", prop_bcomm_irq, sizeof(prop_bcomm_irq) }, { "/builtin/ethernet", "compatible", prop_cstr("mpc5200b-fec\0mpc5200-fec") }, { "/builtin/pic", "compatible", prop_cstr("mpc5200b-pic\0mpc5200-pic") }, { "/builtin/serial", "compatible", prop_cstr("mpc5200b-psc-uart\0mpc5200-psc-uart") }, { "/builtin/sound", "compatible", prop_cstr("mpc5200b-psc-ac97\0mpc5200-psc-ac97") }, { "/builtin/sound", "interrupts", prop_sound_irq, sizeof(prop_sound_irq) }, { "/builtin/sram", "compatible", prop_cstr("mpc5200b-sram\0mpc5200-sram") }, { "/builtin/sram", "device_type", prop_cstr("sram") }, {} }; #undef prop_cstr /* Vars */ u32 node; char prop[64]; int rv, i; /* Check if we're really running on a EFIKA */ node = call_prom("finddevice", 1, 1, ADDR("/")); if (!PHANDLE_VALID(node)) return; rv = prom_getprop(node, "model", prop, sizeof(prop)); if (rv == PROM_ERROR) return; if (strcmp(prop, "EFIKA5K2")) return; prom_printf("Applying EFIKA device tree fixups\n"); /* Process substitution table */ for (i=0; efika_subst_table[i].path; i++) { struct subst_entry *se = &efika_subst_table[i]; node = call_prom("finddevice", 1, 1, ADDR(se->path)); if (!PHANDLE_VALID(node)) { prom_printf("fixup_device_tree_efika: ", "skipped entry %x - not found\n", i); continue; } rv = prom_setprop(node, se->path, se->property, se->value, se->value_len ); if (rv == PROM_ERROR) prom_printf("fixup_device_tree_efika: ", "skipped entry %x - setprop error\n", i); } /* Make sure ethernet mdio bus node exists */ node = call_prom("finddevice", 1, 1, ADDR("/builtin/mdio")); if (!PHANDLE_VALID(node)) { prom_printf("Adding Ethernet MDIO node\n"); call_prom("interpret", 1, 1, " s\" /builtin\" find-device" " new-device" " 1 encode-int s\" #address-cells\" property" " 0 encode-int s\" #size-cells\" property" " s\" mdio\" 2dup device-name device-type" " s\" mpc5200b-fec-phy\" encode-string" " s\" compatible\" property" " 0xf0003000 0x400 reg" " 0x2 encode-int" " 0x5 encode-int encode+" " 0x3 encode-int encode+" " s\" interrupts\" property" " finish-device"); }; /* Make sure ethernet phy device node exist */ node = call_prom("finddevice", 1, 1, ADDR("/builtin/mdio/ethernet-phy")); if (!PHANDLE_VALID(node)) { prom_printf("Adding Ethernet PHY node\n"); call_prom("interpret", 1, 1, " s\" /builtin/mdio\" find-device" " new-device" " s\" ethernet-phy\" device-name" " 0x10 encode-int s\" reg\" property" " my-self" " ihandle>phandle" " finish-device" " s\" /builtin/ethernet\" find-device" " encode-int" " s\" phy-handle\" property" " device-end"); }}#else#define fixup_device_tree_efika()#endifstatic void __init fixup_device_tree(void){ fixup_device_tree_maple(); fixup_device_tree_chrp(); fixup_device_tree_pmac(); fixup_device_tree_efika();}static void __init prom_find_boot_cpu(void){ struct prom_t *_prom = &RELOC(prom); u32 getprop_rval; ihandle prom_cpu; phandle cpu_pkg; _prom->cpu = 0; if (prom_getprop(_prom->chosen, "cpu", &prom_cpu, sizeof(prom_cpu)) <= 0) return; cpu_pkg = call_prom("instance-to-package", 1, 1, prom_cpu); prom_getprop(cpu_pkg, "reg", &getprop_rval, sizeof(getprop_rval)); _prom->cpu = getprop_rval; prom_debug("Booting CPU hw index = 0x%x\n", _prom->cpu);}static void __init prom_check_initrd(unsigned long r3, unsigned long r4){#ifdef CONFIG_BLK_DEV_INITRD struct prom_t *_prom = &RELOC(prom); if (r3 && r4 && r4 != 0xdeadbeef) { unsigned long val; RELOC(prom_initrd_start) = is_kernel_addr(r3) ? __pa(r3) : r3; RELOC(prom_initrd_end) = RELOC(prom_initrd_start) + r4; val = RELOC(prom_initrd_start); prom_setprop(_prom->chosen, "/chosen", "linux,initrd-start", &val, sizeof(val)); val = RELOC(prom_initrd_end); prom_setprop(_prom->chosen, "/chosen", "linux,initrd-end", &val, sizeof(val)); reserve_mem(RELOC(prom_initrd_start), RELOC(prom_initrd_end) - RELOC(prom_initrd_start)); prom_debug("initrd_start=0x%x\n", RELOC(prom_initrd_start)); prom_debug("initrd_end=0x%x\n", RELOC(prom_initrd_end)); }#endif /* CONFIG_BLK_DEV_INITRD */}/* * We enter here early on, when the Open Firmware prom is still * handling exceptions and the MMU hash table for us. */unsigned long __init prom_init(unsigned long r3, unsigned long r4, unsigned long pp, unsigned long r6, unsigned long r7){ struct prom_t *_prom; unsigned long hdr; unsigned long offset = reloc_offset();#ifdef CONFIG_PPC32 reloc_got2(offset);#endif _prom = &RELOC(prom); /* * First zero the BSS */ memset(&RELOC(__bss_start), 0, __bss_stop - __bss_start); /* * Init interface to Open Firmware, get some node references
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -