1*9b6b563cSPaul Mackerras /* 2*9b6b563cSPaul Mackerras * Procedures for interfacing to Open Firmware. 3*9b6b563cSPaul Mackerras * 4*9b6b563cSPaul Mackerras * Paul Mackerras August 1996. 5*9b6b563cSPaul Mackerras * Copyright (C) 1996-2005 Paul Mackerras. 6*9b6b563cSPaul Mackerras * 7*9b6b563cSPaul Mackerras * Adapted for 64bit PowerPC by Dave Engebretsen and Peter Bergner. 8*9b6b563cSPaul Mackerras * {engebret|bergner}@us.ibm.com 9*9b6b563cSPaul Mackerras * 10*9b6b563cSPaul Mackerras * This program is free software; you can redistribute it and/or 11*9b6b563cSPaul Mackerras * modify it under the terms of the GNU General Public License 12*9b6b563cSPaul Mackerras * as published by the Free Software Foundation; either version 13*9b6b563cSPaul Mackerras * 2 of the License, or (at your option) any later version. 14*9b6b563cSPaul Mackerras */ 15*9b6b563cSPaul Mackerras 16*9b6b563cSPaul Mackerras #undef DEBUG_PROM 17*9b6b563cSPaul Mackerras 18*9b6b563cSPaul Mackerras #include <stdarg.h> 19*9b6b563cSPaul Mackerras #include <linux/config.h> 20*9b6b563cSPaul Mackerras #include <linux/kernel.h> 21*9b6b563cSPaul Mackerras #include <linux/string.h> 22*9b6b563cSPaul Mackerras #include <linux/init.h> 23*9b6b563cSPaul Mackerras #include <linux/threads.h> 24*9b6b563cSPaul Mackerras #include <linux/spinlock.h> 25*9b6b563cSPaul Mackerras #include <linux/types.h> 26*9b6b563cSPaul Mackerras #include <linux/pci.h> 27*9b6b563cSPaul Mackerras #include <linux/proc_fs.h> 28*9b6b563cSPaul Mackerras #include <linux/stringify.h> 29*9b6b563cSPaul Mackerras #include <linux/delay.h> 30*9b6b563cSPaul Mackerras #include <linux/initrd.h> 31*9b6b563cSPaul Mackerras #include <linux/bitops.h> 32*9b6b563cSPaul Mackerras #include <asm/prom.h> 33*9b6b563cSPaul Mackerras #include <asm/rtas.h> 34*9b6b563cSPaul Mackerras #include <asm/page.h> 35*9b6b563cSPaul Mackerras #include <asm/processor.h> 36*9b6b563cSPaul Mackerras #include <asm/irq.h> 37*9b6b563cSPaul Mackerras #include <asm/io.h> 38*9b6b563cSPaul Mackerras #include <asm/smp.h> 39*9b6b563cSPaul Mackerras #include <asm/system.h> 40*9b6b563cSPaul Mackerras #include <asm/mmu.h> 41*9b6b563cSPaul Mackerras #include <asm/pgtable.h> 42*9b6b563cSPaul Mackerras #include <asm/pci.h> 43*9b6b563cSPaul Mackerras #include <asm/iommu.h> 44*9b6b563cSPaul Mackerras #include <asm/bootinfo.h> 45*9b6b563cSPaul Mackerras #include <asm/btext.h> 46*9b6b563cSPaul Mackerras #include <asm/sections.h> 47*9b6b563cSPaul Mackerras #include <asm/machdep.h> 48*9b6b563cSPaul Mackerras 49*9b6b563cSPaul Mackerras #ifdef CONFIG_LOGO_LINUX_CLUT224 50*9b6b563cSPaul Mackerras #include <linux/linux_logo.h> 51*9b6b563cSPaul Mackerras extern const struct linux_logo logo_linux_clut224; 52*9b6b563cSPaul Mackerras #endif 53*9b6b563cSPaul Mackerras 54*9b6b563cSPaul Mackerras /* 55*9b6b563cSPaul Mackerras * Properties whose value is longer than this get excluded from our 56*9b6b563cSPaul Mackerras * copy of the device tree. This value does need to be big enough to 57*9b6b563cSPaul Mackerras * ensure that we don't lose things like the interrupt-map property 58*9b6b563cSPaul Mackerras * on a PCI-PCI bridge. 59*9b6b563cSPaul Mackerras */ 60*9b6b563cSPaul Mackerras #define MAX_PROPERTY_LENGTH (1UL * 1024 * 1024) 61*9b6b563cSPaul Mackerras 62*9b6b563cSPaul Mackerras /* 63*9b6b563cSPaul Mackerras * Eventually bump that one up 64*9b6b563cSPaul Mackerras */ 65*9b6b563cSPaul Mackerras #define DEVTREE_CHUNK_SIZE 0x100000 66*9b6b563cSPaul Mackerras 67*9b6b563cSPaul Mackerras /* 68*9b6b563cSPaul Mackerras * This is the size of the local memory reserve map that gets copied 69*9b6b563cSPaul Mackerras * into the boot params passed to the kernel. That size is totally 70*9b6b563cSPaul Mackerras * flexible as the kernel just reads the list until it encounters an 71*9b6b563cSPaul Mackerras * entry with size 0, so it can be changed without breaking binary 72*9b6b563cSPaul Mackerras * compatibility 73*9b6b563cSPaul Mackerras */ 74*9b6b563cSPaul Mackerras #define MEM_RESERVE_MAP_SIZE 8 75*9b6b563cSPaul Mackerras 76*9b6b563cSPaul Mackerras /* 77*9b6b563cSPaul Mackerras * prom_init() is called very early on, before the kernel text 78*9b6b563cSPaul Mackerras * and data have been mapped to KERNELBASE. At this point the code 79*9b6b563cSPaul Mackerras * is running at whatever address it has been loaded at. 80*9b6b563cSPaul Mackerras * On ppc32 we compile with -mrelocatable, which means that references 81*9b6b563cSPaul Mackerras * to extern and static variables get relocated automatically. 82*9b6b563cSPaul Mackerras * On ppc64 we have to relocate the references explicitly with 83*9b6b563cSPaul Mackerras * RELOC. (Note that strings count as static variables.) 84*9b6b563cSPaul Mackerras * 85*9b6b563cSPaul Mackerras * Because OF may have mapped I/O devices into the area starting at 86*9b6b563cSPaul Mackerras * KERNELBASE, particularly on CHRP machines, we can't safely call 87*9b6b563cSPaul Mackerras * OF once the kernel has been mapped to KERNELBASE. Therefore all 88*9b6b563cSPaul Mackerras * OF calls must be done within prom_init(). 89*9b6b563cSPaul Mackerras * 90*9b6b563cSPaul Mackerras * ADDR is used in calls to call_prom. The 4th and following 91*9b6b563cSPaul Mackerras * arguments to call_prom should be 32-bit values. 92*9b6b563cSPaul Mackerras * On ppc64, 64 bit values are truncated to 32 bits (and 93*9b6b563cSPaul Mackerras * fortunately don't get interpreted as two arguments). 94*9b6b563cSPaul Mackerras */ 95*9b6b563cSPaul Mackerras #ifdef CONFIG_PPC64 96*9b6b563cSPaul Mackerras #define RELOC(x) (*PTRRELOC(&(x))) 97*9b6b563cSPaul Mackerras #define ADDR(x) (u32) add_reloc_offset((unsigned long)(x)) 98*9b6b563cSPaul Mackerras #else 99*9b6b563cSPaul Mackerras #define RELOC(x) (x) 100*9b6b563cSPaul Mackerras #define ADDR(x) (u32) (x) 101*9b6b563cSPaul Mackerras #endif 102*9b6b563cSPaul Mackerras 103*9b6b563cSPaul Mackerras #define PROM_BUG() do { \ 104*9b6b563cSPaul Mackerras prom_printf("kernel BUG at %s line 0x%x!\n", \ 105*9b6b563cSPaul Mackerras RELOC(__FILE__), __LINE__); \ 106*9b6b563cSPaul Mackerras __asm__ __volatile__(".long " BUG_ILLEGAL_INSTR); \ 107*9b6b563cSPaul Mackerras } while (0) 108*9b6b563cSPaul Mackerras 109*9b6b563cSPaul Mackerras #ifdef DEBUG_PROM 110*9b6b563cSPaul Mackerras #define prom_debug(x...) prom_printf(x) 111*9b6b563cSPaul Mackerras #else 112*9b6b563cSPaul Mackerras #define prom_debug(x...) 113*9b6b563cSPaul Mackerras #endif 114*9b6b563cSPaul Mackerras 115*9b6b563cSPaul Mackerras #ifdef CONFIG_PPC32 116*9b6b563cSPaul Mackerras #define PLATFORM_POWERMAC _MACH_Pmac 117*9b6b563cSPaul Mackerras #define PLATFORM_CHRP _MACH_chrp 118*9b6b563cSPaul Mackerras #endif 119*9b6b563cSPaul Mackerras 120*9b6b563cSPaul Mackerras 121*9b6b563cSPaul Mackerras typedef u32 prom_arg_t; 122*9b6b563cSPaul Mackerras 123*9b6b563cSPaul Mackerras struct prom_args { 124*9b6b563cSPaul Mackerras u32 service; 125*9b6b563cSPaul Mackerras u32 nargs; 126*9b6b563cSPaul Mackerras u32 nret; 127*9b6b563cSPaul Mackerras prom_arg_t args[10]; 128*9b6b563cSPaul Mackerras }; 129*9b6b563cSPaul Mackerras 130*9b6b563cSPaul Mackerras struct prom_t { 131*9b6b563cSPaul Mackerras ihandle root; 132*9b6b563cSPaul Mackerras ihandle chosen; 133*9b6b563cSPaul Mackerras int cpu; 134*9b6b563cSPaul Mackerras ihandle stdout; 135*9b6b563cSPaul Mackerras }; 136*9b6b563cSPaul Mackerras 137*9b6b563cSPaul Mackerras struct mem_map_entry { 138*9b6b563cSPaul Mackerras unsigned long base; 139*9b6b563cSPaul Mackerras unsigned long size; 140*9b6b563cSPaul Mackerras }; 141*9b6b563cSPaul Mackerras 142*9b6b563cSPaul Mackerras typedef u32 cell_t; 143*9b6b563cSPaul Mackerras 144*9b6b563cSPaul Mackerras extern void __start(unsigned long r3, unsigned long r4, unsigned long r5); 145*9b6b563cSPaul Mackerras 146*9b6b563cSPaul Mackerras #ifdef CONFIG_PPC64 147*9b6b563cSPaul Mackerras extern void enter_prom(struct prom_args *args, unsigned long entry); 148*9b6b563cSPaul Mackerras #else 149*9b6b563cSPaul Mackerras static inline void enter_prom(struct prom_args *args, unsigned long entry) 150*9b6b563cSPaul Mackerras { 151*9b6b563cSPaul Mackerras ((void (*)(struct prom_args *))entry)(args); 152*9b6b563cSPaul Mackerras } 153*9b6b563cSPaul Mackerras #endif 154*9b6b563cSPaul Mackerras 155*9b6b563cSPaul Mackerras extern void copy_and_flush(unsigned long dest, unsigned long src, 156*9b6b563cSPaul Mackerras unsigned long size, unsigned long offset); 157*9b6b563cSPaul Mackerras 158*9b6b563cSPaul Mackerras /* prom structure */ 159*9b6b563cSPaul Mackerras static struct prom_t __initdata prom; 160*9b6b563cSPaul Mackerras 161*9b6b563cSPaul Mackerras static unsigned long prom_entry __initdata; 162*9b6b563cSPaul Mackerras 163*9b6b563cSPaul Mackerras #define PROM_SCRATCH_SIZE 256 164*9b6b563cSPaul Mackerras 165*9b6b563cSPaul Mackerras static char __initdata of_stdout_device[256]; 166*9b6b563cSPaul Mackerras static char __initdata prom_scratch[PROM_SCRATCH_SIZE]; 167*9b6b563cSPaul Mackerras 168*9b6b563cSPaul Mackerras static unsigned long __initdata dt_header_start; 169*9b6b563cSPaul Mackerras static unsigned long __initdata dt_struct_start, dt_struct_end; 170*9b6b563cSPaul Mackerras static unsigned long __initdata dt_string_start, dt_string_end; 171*9b6b563cSPaul Mackerras 172*9b6b563cSPaul Mackerras static unsigned long __initdata prom_initrd_start, prom_initrd_end; 173*9b6b563cSPaul Mackerras 174*9b6b563cSPaul Mackerras #ifdef CONFIG_PPC64 175*9b6b563cSPaul Mackerras static int __initdata iommu_force_on; 176*9b6b563cSPaul Mackerras static int __initdata ppc64_iommu_off; 177*9b6b563cSPaul Mackerras static unsigned long __initdata prom_tce_alloc_start; 178*9b6b563cSPaul Mackerras static unsigned long __initdata prom_tce_alloc_end; 179*9b6b563cSPaul Mackerras #endif 180*9b6b563cSPaul Mackerras 181*9b6b563cSPaul Mackerras static int __initdata of_platform; 182*9b6b563cSPaul Mackerras 183*9b6b563cSPaul Mackerras static char __initdata prom_cmd_line[COMMAND_LINE_SIZE]; 184*9b6b563cSPaul Mackerras 185*9b6b563cSPaul Mackerras static unsigned long __initdata prom_memory_limit; 186*9b6b563cSPaul Mackerras 187*9b6b563cSPaul Mackerras static unsigned long __initdata alloc_top; 188*9b6b563cSPaul Mackerras static unsigned long __initdata alloc_top_high; 189*9b6b563cSPaul Mackerras static unsigned long __initdata alloc_bottom; 190*9b6b563cSPaul Mackerras static unsigned long __initdata rmo_top; 191*9b6b563cSPaul Mackerras static unsigned long __initdata ram_top; 192*9b6b563cSPaul Mackerras 193*9b6b563cSPaul Mackerras static struct mem_map_entry __initdata mem_reserve_map[MEM_RESERVE_MAP_SIZE]; 194*9b6b563cSPaul Mackerras static int __initdata mem_reserve_cnt; 195*9b6b563cSPaul Mackerras 196*9b6b563cSPaul Mackerras static cell_t __initdata regbuf[1024]; 197*9b6b563cSPaul Mackerras 198*9b6b563cSPaul Mackerras 199*9b6b563cSPaul Mackerras #define MAX_CPU_THREADS 2 200*9b6b563cSPaul Mackerras 201*9b6b563cSPaul Mackerras /* TO GO */ 202*9b6b563cSPaul Mackerras #ifdef CONFIG_HMT 203*9b6b563cSPaul Mackerras struct { 204*9b6b563cSPaul Mackerras unsigned int pir; 205*9b6b563cSPaul Mackerras unsigned int threadid; 206*9b6b563cSPaul Mackerras } hmt_thread_data[NR_CPUS]; 207*9b6b563cSPaul Mackerras #endif /* CONFIG_HMT */ 208*9b6b563cSPaul Mackerras 209*9b6b563cSPaul Mackerras /* 210*9b6b563cSPaul Mackerras * Error results ... some OF calls will return "-1" on error, some 211*9b6b563cSPaul Mackerras * will return 0, some will return either. To simplify, here are 212*9b6b563cSPaul Mackerras * macros to use with any ihandle or phandle return value to check if 213*9b6b563cSPaul Mackerras * it is valid 214*9b6b563cSPaul Mackerras */ 215*9b6b563cSPaul Mackerras 216*9b6b563cSPaul Mackerras #define PROM_ERROR (-1u) 217*9b6b563cSPaul Mackerras #define PHANDLE_VALID(p) ((p) != 0 && (p) != PROM_ERROR) 218*9b6b563cSPaul Mackerras #define IHANDLE_VALID(i) ((i) != 0 && (i) != PROM_ERROR) 219*9b6b563cSPaul Mackerras 220*9b6b563cSPaul Mackerras 221*9b6b563cSPaul Mackerras /* This is the one and *ONLY* place where we actually call open 222*9b6b563cSPaul Mackerras * firmware. 223*9b6b563cSPaul Mackerras */ 224*9b6b563cSPaul Mackerras 225*9b6b563cSPaul Mackerras static int __init call_prom(const char *service, int nargs, int nret, ...) 226*9b6b563cSPaul Mackerras { 227*9b6b563cSPaul Mackerras int i; 228*9b6b563cSPaul Mackerras struct prom_args args; 229*9b6b563cSPaul Mackerras va_list list; 230*9b6b563cSPaul Mackerras 231*9b6b563cSPaul Mackerras args.service = ADDR(service); 232*9b6b563cSPaul Mackerras args.nargs = nargs; 233*9b6b563cSPaul Mackerras args.nret = nret; 234*9b6b563cSPaul Mackerras 235*9b6b563cSPaul Mackerras va_start(list, nret); 236*9b6b563cSPaul Mackerras for (i = 0; i < nargs; i++) 237*9b6b563cSPaul Mackerras args.args[i] = va_arg(list, prom_arg_t); 238*9b6b563cSPaul Mackerras va_end(list); 239*9b6b563cSPaul Mackerras 240*9b6b563cSPaul Mackerras for (i = 0; i < nret; i++) 241*9b6b563cSPaul Mackerras args.args[nargs+i] = 0; 242*9b6b563cSPaul Mackerras 243*9b6b563cSPaul Mackerras enter_prom(&args, RELOC(prom_entry)); 244*9b6b563cSPaul Mackerras 245*9b6b563cSPaul Mackerras return (nret > 0) ? args.args[nargs] : 0; 246*9b6b563cSPaul Mackerras } 247*9b6b563cSPaul Mackerras 248*9b6b563cSPaul Mackerras static int __init call_prom_ret(const char *service, int nargs, int nret, 249*9b6b563cSPaul Mackerras prom_arg_t *rets, ...) 250*9b6b563cSPaul Mackerras { 251*9b6b563cSPaul Mackerras int i; 252*9b6b563cSPaul Mackerras struct prom_args args; 253*9b6b563cSPaul Mackerras va_list list; 254*9b6b563cSPaul Mackerras 255*9b6b563cSPaul Mackerras args.service = ADDR(service); 256*9b6b563cSPaul Mackerras args.nargs = nargs; 257*9b6b563cSPaul Mackerras args.nret = nret; 258*9b6b563cSPaul Mackerras 259*9b6b563cSPaul Mackerras va_start(list, rets); 260*9b6b563cSPaul Mackerras for (i = 0; i < nargs; i++) 261*9b6b563cSPaul Mackerras args.args[i] = va_arg(list, prom_arg_t); 262*9b6b563cSPaul Mackerras va_end(list); 263*9b6b563cSPaul Mackerras 264*9b6b563cSPaul Mackerras for (i = 0; i < nret; i++) 265*9b6b563cSPaul Mackerras rets[nargs+i] = 0; 266*9b6b563cSPaul Mackerras 267*9b6b563cSPaul Mackerras enter_prom(&args, RELOC(prom_entry)); 268*9b6b563cSPaul Mackerras 269*9b6b563cSPaul Mackerras if (rets != NULL) 270*9b6b563cSPaul Mackerras for (i = 1; i < nret; ++i) 271*9b6b563cSPaul Mackerras rets[i] = args.args[nargs+i]; 272*9b6b563cSPaul Mackerras 273*9b6b563cSPaul Mackerras return (nret > 0) ? args.args[nargs] : 0; 274*9b6b563cSPaul Mackerras } 275*9b6b563cSPaul Mackerras 276*9b6b563cSPaul Mackerras 277*9b6b563cSPaul Mackerras static unsigned int __init prom_claim(unsigned long virt, unsigned long size, 278*9b6b563cSPaul Mackerras unsigned long align) 279*9b6b563cSPaul Mackerras { 280*9b6b563cSPaul Mackerras return (unsigned int)call_prom("claim", 3, 1, 281*9b6b563cSPaul Mackerras (prom_arg_t)virt, (prom_arg_t)size, 282*9b6b563cSPaul Mackerras (prom_arg_t)align); 283*9b6b563cSPaul Mackerras } 284*9b6b563cSPaul Mackerras 285*9b6b563cSPaul Mackerras static void __init prom_print(const char *msg) 286*9b6b563cSPaul Mackerras { 287*9b6b563cSPaul Mackerras const char *p, *q; 288*9b6b563cSPaul Mackerras struct prom_t *_prom = &RELOC(prom); 289*9b6b563cSPaul Mackerras 290*9b6b563cSPaul Mackerras if (_prom->stdout == 0) 291*9b6b563cSPaul Mackerras return; 292*9b6b563cSPaul Mackerras 293*9b6b563cSPaul Mackerras for (p = msg; *p != 0; p = q) { 294*9b6b563cSPaul Mackerras for (q = p; *q != 0 && *q != '\n'; ++q) 295*9b6b563cSPaul Mackerras ; 296*9b6b563cSPaul Mackerras if (q > p) 297*9b6b563cSPaul Mackerras call_prom("write", 3, 1, _prom->stdout, p, q - p); 298*9b6b563cSPaul Mackerras if (*q == 0) 299*9b6b563cSPaul Mackerras break; 300*9b6b563cSPaul Mackerras ++q; 301*9b6b563cSPaul Mackerras call_prom("write", 3, 1, _prom->stdout, ADDR("\r\n"), 2); 302*9b6b563cSPaul Mackerras } 303*9b6b563cSPaul Mackerras } 304*9b6b563cSPaul Mackerras 305*9b6b563cSPaul Mackerras 306*9b6b563cSPaul Mackerras static void __init prom_print_hex(unsigned long val) 307*9b6b563cSPaul Mackerras { 308*9b6b563cSPaul Mackerras int i, nibbles = sizeof(val)*2; 309*9b6b563cSPaul Mackerras char buf[sizeof(val)*2+1]; 310*9b6b563cSPaul Mackerras struct prom_t *_prom = &RELOC(prom); 311*9b6b563cSPaul Mackerras 312*9b6b563cSPaul Mackerras for (i = nibbles-1; i >= 0; i--) { 313*9b6b563cSPaul Mackerras buf[i] = (val & 0xf) + '0'; 314*9b6b563cSPaul Mackerras if (buf[i] > '9') 315*9b6b563cSPaul Mackerras buf[i] += ('a'-'0'-10); 316*9b6b563cSPaul Mackerras val >>= 4; 317*9b6b563cSPaul Mackerras } 318*9b6b563cSPaul Mackerras buf[nibbles] = '\0'; 319*9b6b563cSPaul Mackerras call_prom("write", 3, 1, _prom->stdout, buf, nibbles); 320*9b6b563cSPaul Mackerras } 321*9b6b563cSPaul Mackerras 322*9b6b563cSPaul Mackerras 323*9b6b563cSPaul Mackerras static void __init prom_printf(const char *format, ...) 324*9b6b563cSPaul Mackerras { 325*9b6b563cSPaul Mackerras const char *p, *q, *s; 326*9b6b563cSPaul Mackerras va_list args; 327*9b6b563cSPaul Mackerras unsigned long v; 328*9b6b563cSPaul Mackerras struct prom_t *_prom = &RELOC(prom); 329*9b6b563cSPaul Mackerras 330*9b6b563cSPaul Mackerras va_start(args, format); 331*9b6b563cSPaul Mackerras #ifdef CONFIG_PPC64 332*9b6b563cSPaul Mackerras format = PTRRELOC(format); 333*9b6b563cSPaul Mackerras #endif 334*9b6b563cSPaul Mackerras for (p = format; *p != 0; p = q) { 335*9b6b563cSPaul Mackerras for (q = p; *q != 0 && *q != '\n' && *q != '%'; ++q) 336*9b6b563cSPaul Mackerras ; 337*9b6b563cSPaul Mackerras if (q > p) 338*9b6b563cSPaul Mackerras call_prom("write", 3, 1, _prom->stdout, p, q - p); 339*9b6b563cSPaul Mackerras if (*q == 0) 340*9b6b563cSPaul Mackerras break; 341*9b6b563cSPaul Mackerras if (*q == '\n') { 342*9b6b563cSPaul Mackerras ++q; 343*9b6b563cSPaul Mackerras call_prom("write", 3, 1, _prom->stdout, 344*9b6b563cSPaul Mackerras ADDR("\r\n"), 2); 345*9b6b563cSPaul Mackerras continue; 346*9b6b563cSPaul Mackerras } 347*9b6b563cSPaul Mackerras ++q; 348*9b6b563cSPaul Mackerras if (*q == 0) 349*9b6b563cSPaul Mackerras break; 350*9b6b563cSPaul Mackerras switch (*q) { 351*9b6b563cSPaul Mackerras case 's': 352*9b6b563cSPaul Mackerras ++q; 353*9b6b563cSPaul Mackerras s = va_arg(args, const char *); 354*9b6b563cSPaul Mackerras prom_print(s); 355*9b6b563cSPaul Mackerras break; 356*9b6b563cSPaul Mackerras case 'x': 357*9b6b563cSPaul Mackerras ++q; 358*9b6b563cSPaul Mackerras v = va_arg(args, unsigned long); 359*9b6b563cSPaul Mackerras prom_print_hex(v); 360*9b6b563cSPaul Mackerras break; 361*9b6b563cSPaul Mackerras } 362*9b6b563cSPaul Mackerras } 363*9b6b563cSPaul Mackerras } 364*9b6b563cSPaul Mackerras 365*9b6b563cSPaul Mackerras 366*9b6b563cSPaul Mackerras static void __init __attribute__((noreturn)) prom_panic(const char *reason) 367*9b6b563cSPaul Mackerras { 368*9b6b563cSPaul Mackerras #ifdef CONFIG_PPC64 369*9b6b563cSPaul Mackerras reason = PTRRELOC(reason); 370*9b6b563cSPaul Mackerras #endif 371*9b6b563cSPaul Mackerras prom_print(reason); 372*9b6b563cSPaul Mackerras /* ToDo: should put up an SRC here on p/iSeries */ 373*9b6b563cSPaul Mackerras call_prom("exit", 0, 0); 374*9b6b563cSPaul Mackerras 375*9b6b563cSPaul Mackerras for (;;) /* should never get here */ 376*9b6b563cSPaul Mackerras ; 377*9b6b563cSPaul Mackerras } 378*9b6b563cSPaul Mackerras 379*9b6b563cSPaul Mackerras 380*9b6b563cSPaul Mackerras static int __init prom_next_node(phandle *nodep) 381*9b6b563cSPaul Mackerras { 382*9b6b563cSPaul Mackerras phandle node; 383*9b6b563cSPaul Mackerras 384*9b6b563cSPaul Mackerras if ((node = *nodep) != 0 385*9b6b563cSPaul Mackerras && (*nodep = call_prom("child", 1, 1, node)) != 0) 386*9b6b563cSPaul Mackerras return 1; 387*9b6b563cSPaul Mackerras if ((*nodep = call_prom("peer", 1, 1, node)) != 0) 388*9b6b563cSPaul Mackerras return 1; 389*9b6b563cSPaul Mackerras for (;;) { 390*9b6b563cSPaul Mackerras if ((node = call_prom("parent", 1, 1, node)) == 0) 391*9b6b563cSPaul Mackerras return 0; 392*9b6b563cSPaul Mackerras if ((*nodep = call_prom("peer", 1, 1, node)) != 0) 393*9b6b563cSPaul Mackerras return 1; 394*9b6b563cSPaul Mackerras } 395*9b6b563cSPaul Mackerras } 396*9b6b563cSPaul Mackerras 397*9b6b563cSPaul Mackerras static int __init prom_getprop(phandle node, const char *pname, 398*9b6b563cSPaul Mackerras void *value, size_t valuelen) 399*9b6b563cSPaul Mackerras { 400*9b6b563cSPaul Mackerras return call_prom("getprop", 4, 1, node, ADDR(pname), 401*9b6b563cSPaul Mackerras (u32)(unsigned long) value, (u32) valuelen); 402*9b6b563cSPaul Mackerras } 403*9b6b563cSPaul Mackerras 404*9b6b563cSPaul Mackerras static int __init prom_getproplen(phandle node, const char *pname) 405*9b6b563cSPaul Mackerras { 406*9b6b563cSPaul Mackerras return call_prom("getproplen", 2, 1, node, ADDR(pname)); 407*9b6b563cSPaul Mackerras } 408*9b6b563cSPaul Mackerras 409*9b6b563cSPaul Mackerras static int __init prom_setprop(phandle node, const char *pname, 410*9b6b563cSPaul Mackerras void *value, size_t valuelen) 411*9b6b563cSPaul Mackerras { 412*9b6b563cSPaul Mackerras return call_prom("setprop", 4, 1, node, ADDR(pname), 413*9b6b563cSPaul Mackerras (u32)(unsigned long) value, (u32) valuelen); 414*9b6b563cSPaul Mackerras } 415*9b6b563cSPaul Mackerras 416*9b6b563cSPaul Mackerras /* We can't use the standard versions because of RELOC headaches. */ 417*9b6b563cSPaul Mackerras #define isxdigit(c) (('0' <= (c) && (c) <= '9') \ 418*9b6b563cSPaul Mackerras || ('a' <= (c) && (c) <= 'f') \ 419*9b6b563cSPaul Mackerras || ('A' <= (c) && (c) <= 'F')) 420*9b6b563cSPaul Mackerras 421*9b6b563cSPaul Mackerras #define isdigit(c) ('0' <= (c) && (c) <= '9') 422*9b6b563cSPaul Mackerras #define islower(c) ('a' <= (c) && (c) <= 'z') 423*9b6b563cSPaul Mackerras #define toupper(c) (islower(c) ? ((c) - 'a' + 'A') : (c)) 424*9b6b563cSPaul Mackerras 425*9b6b563cSPaul Mackerras unsigned long prom_strtoul(const char *cp, const char **endp) 426*9b6b563cSPaul Mackerras { 427*9b6b563cSPaul Mackerras unsigned long result = 0, base = 10, value; 428*9b6b563cSPaul Mackerras 429*9b6b563cSPaul Mackerras if (*cp == '0') { 430*9b6b563cSPaul Mackerras base = 8; 431*9b6b563cSPaul Mackerras cp++; 432*9b6b563cSPaul Mackerras if (toupper(*cp) == 'X') { 433*9b6b563cSPaul Mackerras cp++; 434*9b6b563cSPaul Mackerras base = 16; 435*9b6b563cSPaul Mackerras } 436*9b6b563cSPaul Mackerras } 437*9b6b563cSPaul Mackerras 438*9b6b563cSPaul Mackerras while (isxdigit(*cp) && 439*9b6b563cSPaul Mackerras (value = isdigit(*cp) ? *cp - '0' : toupper(*cp) - 'A' + 10) < base) { 440*9b6b563cSPaul Mackerras result = result * base + value; 441*9b6b563cSPaul Mackerras cp++; 442*9b6b563cSPaul Mackerras } 443*9b6b563cSPaul Mackerras 444*9b6b563cSPaul Mackerras if (endp) 445*9b6b563cSPaul Mackerras *endp = cp; 446*9b6b563cSPaul Mackerras 447*9b6b563cSPaul Mackerras return result; 448*9b6b563cSPaul Mackerras } 449*9b6b563cSPaul Mackerras 450*9b6b563cSPaul Mackerras unsigned long prom_memparse(const char *ptr, const char **retptr) 451*9b6b563cSPaul Mackerras { 452*9b6b563cSPaul Mackerras unsigned long ret = prom_strtoul(ptr, retptr); 453*9b6b563cSPaul Mackerras int shift = 0; 454*9b6b563cSPaul Mackerras 455*9b6b563cSPaul Mackerras /* 456*9b6b563cSPaul Mackerras * We can't use a switch here because GCC *may* generate a 457*9b6b563cSPaul Mackerras * jump table which won't work, because we're not running at 458*9b6b563cSPaul Mackerras * the address we're linked at. 459*9b6b563cSPaul Mackerras */ 460*9b6b563cSPaul Mackerras if ('G' == **retptr || 'g' == **retptr) 461*9b6b563cSPaul Mackerras shift = 30; 462*9b6b563cSPaul Mackerras 463*9b6b563cSPaul Mackerras if ('M' == **retptr || 'm' == **retptr) 464*9b6b563cSPaul Mackerras shift = 20; 465*9b6b563cSPaul Mackerras 466*9b6b563cSPaul Mackerras if ('K' == **retptr || 'k' == **retptr) 467*9b6b563cSPaul Mackerras shift = 10; 468*9b6b563cSPaul Mackerras 469*9b6b563cSPaul Mackerras if (shift) { 470*9b6b563cSPaul Mackerras ret <<= shift; 471*9b6b563cSPaul Mackerras (*retptr)++; 472*9b6b563cSPaul Mackerras } 473*9b6b563cSPaul Mackerras 474*9b6b563cSPaul Mackerras return ret; 475*9b6b563cSPaul Mackerras } 476*9b6b563cSPaul Mackerras 477*9b6b563cSPaul Mackerras /* 478*9b6b563cSPaul Mackerras * Early parsing of the command line passed to the kernel, used for 479*9b6b563cSPaul Mackerras * "mem=x" and the options that affect the iommu 480*9b6b563cSPaul Mackerras */ 481*9b6b563cSPaul Mackerras static void __init early_cmdline_parse(void) 482*9b6b563cSPaul Mackerras { 483*9b6b563cSPaul Mackerras struct prom_t *_prom = &RELOC(prom); 484*9b6b563cSPaul Mackerras char *opt, *p; 485*9b6b563cSPaul Mackerras int l = 0; 486*9b6b563cSPaul Mackerras 487*9b6b563cSPaul Mackerras RELOC(prom_cmd_line[0]) = 0; 488*9b6b563cSPaul Mackerras p = RELOC(prom_cmd_line); 489*9b6b563cSPaul Mackerras if ((long)_prom->chosen > 0) 490*9b6b563cSPaul Mackerras l = prom_getprop(_prom->chosen, "bootargs", p, COMMAND_LINE_SIZE-1); 491*9b6b563cSPaul Mackerras #ifdef CONFIG_CMDLINE 492*9b6b563cSPaul Mackerras if (l == 0) /* dbl check */ 493*9b6b563cSPaul Mackerras strlcpy(RELOC(prom_cmd_line), 494*9b6b563cSPaul Mackerras RELOC(CONFIG_CMDLINE), sizeof(prom_cmd_line)); 495*9b6b563cSPaul Mackerras #endif /* CONFIG_CMDLINE */ 496*9b6b563cSPaul Mackerras prom_printf("command line: %s\n", RELOC(prom_cmd_line)); 497*9b6b563cSPaul Mackerras 498*9b6b563cSPaul Mackerras #ifdef CONFIG_PPC64 499*9b6b563cSPaul Mackerras opt = strstr(RELOC(prom_cmd_line), RELOC("iommu=")); 500*9b6b563cSPaul Mackerras if (opt) { 501*9b6b563cSPaul Mackerras prom_printf("iommu opt is: %s\n", opt); 502*9b6b563cSPaul Mackerras opt += 6; 503*9b6b563cSPaul Mackerras while (*opt && *opt == ' ') 504*9b6b563cSPaul Mackerras opt++; 505*9b6b563cSPaul Mackerras if (!strncmp(opt, RELOC("off"), 3)) 506*9b6b563cSPaul Mackerras RELOC(ppc64_iommu_off) = 1; 507*9b6b563cSPaul Mackerras else if (!strncmp(opt, RELOC("force"), 5)) 508*9b6b563cSPaul Mackerras RELOC(iommu_force_on) = 1; 509*9b6b563cSPaul Mackerras } 510*9b6b563cSPaul Mackerras #endif 511*9b6b563cSPaul Mackerras 512*9b6b563cSPaul Mackerras opt = strstr(RELOC(prom_cmd_line), RELOC("mem=")); 513*9b6b563cSPaul Mackerras if (opt) { 514*9b6b563cSPaul Mackerras opt += 4; 515*9b6b563cSPaul Mackerras RELOC(prom_memory_limit) = prom_memparse(opt, (const char **)&opt); 516*9b6b563cSPaul Mackerras #ifdef CONFIG_PPC64 517*9b6b563cSPaul Mackerras /* Align to 16 MB == size of ppc64 large page */ 518*9b6b563cSPaul Mackerras RELOC(prom_memory_limit) = ALIGN(RELOC(prom_memory_limit), 0x1000000); 519*9b6b563cSPaul Mackerras #endif 520*9b6b563cSPaul Mackerras } 521*9b6b563cSPaul Mackerras } 522*9b6b563cSPaul Mackerras 523*9b6b563cSPaul Mackerras #ifdef CONFIG_PPC_PSERIES 524*9b6b563cSPaul Mackerras /* 525*9b6b563cSPaul Mackerras * To tell the firmware what our capabilities are, we have to pass 526*9b6b563cSPaul Mackerras * it a fake 32-bit ELF header containing a couple of PT_NOTE sections 527*9b6b563cSPaul Mackerras * that contain structures that contain the actual values. 528*9b6b563cSPaul Mackerras */ 529*9b6b563cSPaul Mackerras static struct fake_elf { 530*9b6b563cSPaul Mackerras Elf32_Ehdr elfhdr; 531*9b6b563cSPaul Mackerras Elf32_Phdr phdr[2]; 532*9b6b563cSPaul Mackerras struct chrpnote { 533*9b6b563cSPaul Mackerras u32 namesz; 534*9b6b563cSPaul Mackerras u32 descsz; 535*9b6b563cSPaul Mackerras u32 type; 536*9b6b563cSPaul Mackerras char name[8]; /* "PowerPC" */ 537*9b6b563cSPaul Mackerras struct chrpdesc { 538*9b6b563cSPaul Mackerras u32 real_mode; 539*9b6b563cSPaul Mackerras u32 real_base; 540*9b6b563cSPaul Mackerras u32 real_size; 541*9b6b563cSPaul Mackerras u32 virt_base; 542*9b6b563cSPaul Mackerras u32 virt_size; 543*9b6b563cSPaul Mackerras u32 load_base; 544*9b6b563cSPaul Mackerras } chrpdesc; 545*9b6b563cSPaul Mackerras } chrpnote; 546*9b6b563cSPaul Mackerras struct rpanote { 547*9b6b563cSPaul Mackerras u32 namesz; 548*9b6b563cSPaul Mackerras u32 descsz; 549*9b6b563cSPaul Mackerras u32 type; 550*9b6b563cSPaul Mackerras char name[24]; /* "IBM,RPA-Client-Config" */ 551*9b6b563cSPaul Mackerras struct rpadesc { 552*9b6b563cSPaul Mackerras u32 lpar_affinity; 553*9b6b563cSPaul Mackerras u32 min_rmo_size; 554*9b6b563cSPaul Mackerras u32 min_rmo_percent; 555*9b6b563cSPaul Mackerras u32 max_pft_size; 556*9b6b563cSPaul Mackerras u32 splpar; 557*9b6b563cSPaul Mackerras u32 min_load; 558*9b6b563cSPaul Mackerras u32 new_mem_def; 559*9b6b563cSPaul Mackerras u32 ignore_me; 560*9b6b563cSPaul Mackerras } rpadesc; 561*9b6b563cSPaul Mackerras } rpanote; 562*9b6b563cSPaul Mackerras } fake_elf = { 563*9b6b563cSPaul Mackerras .elfhdr = { 564*9b6b563cSPaul Mackerras .e_ident = { 0x7f, 'E', 'L', 'F', 565*9b6b563cSPaul Mackerras ELFCLASS32, ELFDATA2MSB, EV_CURRENT }, 566*9b6b563cSPaul Mackerras .e_type = ET_EXEC, /* yeah right */ 567*9b6b563cSPaul Mackerras .e_machine = EM_PPC, 568*9b6b563cSPaul Mackerras .e_version = EV_CURRENT, 569*9b6b563cSPaul Mackerras .e_phoff = offsetof(struct fake_elf, phdr), 570*9b6b563cSPaul Mackerras .e_phentsize = sizeof(Elf32_Phdr), 571*9b6b563cSPaul Mackerras .e_phnum = 2 572*9b6b563cSPaul Mackerras }, 573*9b6b563cSPaul Mackerras .phdr = { 574*9b6b563cSPaul Mackerras [0] = { 575*9b6b563cSPaul Mackerras .p_type = PT_NOTE, 576*9b6b563cSPaul Mackerras .p_offset = offsetof(struct fake_elf, chrpnote), 577*9b6b563cSPaul Mackerras .p_filesz = sizeof(struct chrpnote) 578*9b6b563cSPaul Mackerras }, [1] = { 579*9b6b563cSPaul Mackerras .p_type = PT_NOTE, 580*9b6b563cSPaul Mackerras .p_offset = offsetof(struct fake_elf, rpanote), 581*9b6b563cSPaul Mackerras .p_filesz = sizeof(struct rpanote) 582*9b6b563cSPaul Mackerras } 583*9b6b563cSPaul Mackerras }, 584*9b6b563cSPaul Mackerras .chrpnote = { 585*9b6b563cSPaul Mackerras .namesz = sizeof("PowerPC"), 586*9b6b563cSPaul Mackerras .descsz = sizeof(struct chrpdesc), 587*9b6b563cSPaul Mackerras .type = 0x1275, 588*9b6b563cSPaul Mackerras .name = "PowerPC", 589*9b6b563cSPaul Mackerras .chrpdesc = { 590*9b6b563cSPaul Mackerras .real_mode = ~0U, /* ~0 means "don't care" */ 591*9b6b563cSPaul Mackerras .real_base = ~0U, 592*9b6b563cSPaul Mackerras .real_size = ~0U, 593*9b6b563cSPaul Mackerras .virt_base = ~0U, 594*9b6b563cSPaul Mackerras .virt_size = ~0U, 595*9b6b563cSPaul Mackerras .load_base = ~0U 596*9b6b563cSPaul Mackerras }, 597*9b6b563cSPaul Mackerras }, 598*9b6b563cSPaul Mackerras .rpanote = { 599*9b6b563cSPaul Mackerras .namesz = sizeof("IBM,RPA-Client-Config"), 600*9b6b563cSPaul Mackerras .descsz = sizeof(struct rpadesc), 601*9b6b563cSPaul Mackerras .type = 0x12759999, 602*9b6b563cSPaul Mackerras .name = "IBM,RPA-Client-Config", 603*9b6b563cSPaul Mackerras .rpadesc = { 604*9b6b563cSPaul Mackerras .lpar_affinity = 0, 605*9b6b563cSPaul Mackerras .min_rmo_size = 64, /* in megabytes */ 606*9b6b563cSPaul Mackerras .min_rmo_percent = 0, 607*9b6b563cSPaul Mackerras .max_pft_size = 48, /* 2^48 bytes max PFT size */ 608*9b6b563cSPaul Mackerras .splpar = 1, 609*9b6b563cSPaul Mackerras .min_load = ~0U, 610*9b6b563cSPaul Mackerras .new_mem_def = 0 611*9b6b563cSPaul Mackerras } 612*9b6b563cSPaul Mackerras } 613*9b6b563cSPaul Mackerras }; 614*9b6b563cSPaul Mackerras 615*9b6b563cSPaul Mackerras static void __init prom_send_capabilities(void) 616*9b6b563cSPaul Mackerras { 617*9b6b563cSPaul Mackerras ihandle elfloader; 618*9b6b563cSPaul Mackerras 619*9b6b563cSPaul Mackerras elfloader = call_prom("open", 1, 1, ADDR("/packages/elf-loader")); 620*9b6b563cSPaul Mackerras if (elfloader == 0) { 621*9b6b563cSPaul Mackerras prom_printf("couldn't open /packages/elf-loader\n"); 622*9b6b563cSPaul Mackerras return; 623*9b6b563cSPaul Mackerras } 624*9b6b563cSPaul Mackerras call_prom("call-method", 3, 1, ADDR("process-elf-header"), 625*9b6b563cSPaul Mackerras elfloader, ADDR(&fake_elf)); 626*9b6b563cSPaul Mackerras call_prom("close", 1, 0, elfloader); 627*9b6b563cSPaul Mackerras } 628*9b6b563cSPaul Mackerras #endif 629*9b6b563cSPaul Mackerras 630*9b6b563cSPaul Mackerras /* 631*9b6b563cSPaul Mackerras * Memory allocation strategy... our layout is normally: 632*9b6b563cSPaul Mackerras * 633*9b6b563cSPaul Mackerras * at 14Mb or more we have vmlinux, then a gap and initrd. In some 634*9b6b563cSPaul Mackerras * rare cases, initrd might end up being before the kernel though. 635*9b6b563cSPaul Mackerras * We assume this won't override the final kernel at 0, we have no 636*9b6b563cSPaul Mackerras * provision to handle that in this version, but it should hopefully 637*9b6b563cSPaul Mackerras * never happen. 638*9b6b563cSPaul Mackerras * 639*9b6b563cSPaul Mackerras * alloc_top is set to the top of RMO, eventually shrink down if the 640*9b6b563cSPaul Mackerras * TCEs overlap 641*9b6b563cSPaul Mackerras * 642*9b6b563cSPaul Mackerras * alloc_bottom is set to the top of kernel/initrd 643*9b6b563cSPaul Mackerras * 644*9b6b563cSPaul Mackerras * from there, allocations are done this way : rtas is allocated 645*9b6b563cSPaul Mackerras * topmost, and the device-tree is allocated from the bottom. We try 646*9b6b563cSPaul Mackerras * to grow the device-tree allocation as we progress. If we can't, 647*9b6b563cSPaul Mackerras * then we fail, we don't currently have a facility to restart 648*9b6b563cSPaul Mackerras * elsewhere, but that shouldn't be necessary. 649*9b6b563cSPaul Mackerras * 650*9b6b563cSPaul Mackerras * Note that calls to reserve_mem have to be done explicitly, memory 651*9b6b563cSPaul Mackerras * allocated with either alloc_up or alloc_down isn't automatically 652*9b6b563cSPaul Mackerras * reserved. 653*9b6b563cSPaul Mackerras */ 654*9b6b563cSPaul Mackerras 655*9b6b563cSPaul Mackerras 656*9b6b563cSPaul Mackerras /* 657*9b6b563cSPaul Mackerras * Allocates memory in the RMO upward from the kernel/initrd 658*9b6b563cSPaul Mackerras * 659*9b6b563cSPaul Mackerras * When align is 0, this is a special case, it means to allocate in place 660*9b6b563cSPaul Mackerras * at the current location of alloc_bottom or fail (that is basically 661*9b6b563cSPaul Mackerras * extending the previous allocation). Used for the device-tree flattening 662*9b6b563cSPaul Mackerras */ 663*9b6b563cSPaul Mackerras static unsigned long __init alloc_up(unsigned long size, unsigned long align) 664*9b6b563cSPaul Mackerras { 665*9b6b563cSPaul Mackerras unsigned long base = _ALIGN_UP(RELOC(alloc_bottom), align); 666*9b6b563cSPaul Mackerras unsigned long addr = 0; 667*9b6b563cSPaul Mackerras 668*9b6b563cSPaul Mackerras prom_debug("alloc_up(%x, %x)\n", size, align); 669*9b6b563cSPaul Mackerras if (RELOC(ram_top) == 0) 670*9b6b563cSPaul Mackerras prom_panic("alloc_up() called with mem not initialized\n"); 671*9b6b563cSPaul Mackerras 672*9b6b563cSPaul Mackerras if (align) 673*9b6b563cSPaul Mackerras base = _ALIGN_UP(RELOC(alloc_bottom), align); 674*9b6b563cSPaul Mackerras else 675*9b6b563cSPaul Mackerras base = RELOC(alloc_bottom); 676*9b6b563cSPaul Mackerras 677*9b6b563cSPaul Mackerras for(; (base + size) <= RELOC(alloc_top); 678*9b6b563cSPaul Mackerras base = _ALIGN_UP(base + 0x100000, align)) { 679*9b6b563cSPaul Mackerras prom_debug(" trying: 0x%x\n\r", base); 680*9b6b563cSPaul Mackerras addr = (unsigned long)prom_claim(base, size, 0); 681*9b6b563cSPaul Mackerras if (addr != PROM_ERROR) 682*9b6b563cSPaul Mackerras break; 683*9b6b563cSPaul Mackerras addr = 0; 684*9b6b563cSPaul Mackerras if (align == 0) 685*9b6b563cSPaul Mackerras break; 686*9b6b563cSPaul Mackerras } 687*9b6b563cSPaul Mackerras if (addr == 0) 688*9b6b563cSPaul Mackerras return 0; 689*9b6b563cSPaul Mackerras RELOC(alloc_bottom) = addr; 690*9b6b563cSPaul Mackerras 691*9b6b563cSPaul Mackerras prom_debug(" -> %x\n", addr); 692*9b6b563cSPaul Mackerras prom_debug(" alloc_bottom : %x\n", RELOC(alloc_bottom)); 693*9b6b563cSPaul Mackerras prom_debug(" alloc_top : %x\n", RELOC(alloc_top)); 694*9b6b563cSPaul Mackerras prom_debug(" alloc_top_hi : %x\n", RELOC(alloc_top_high)); 695*9b6b563cSPaul Mackerras prom_debug(" rmo_top : %x\n", RELOC(rmo_top)); 696*9b6b563cSPaul Mackerras prom_debug(" ram_top : %x\n", RELOC(ram_top)); 697*9b6b563cSPaul Mackerras 698*9b6b563cSPaul Mackerras return addr; 699*9b6b563cSPaul Mackerras } 700*9b6b563cSPaul Mackerras 701*9b6b563cSPaul Mackerras /* 702*9b6b563cSPaul Mackerras * Allocates memory downward, either from top of RMO, or if highmem 703*9b6b563cSPaul Mackerras * is set, from the top of RAM. Note that this one doesn't handle 704*9b6b563cSPaul Mackerras * failures. It does claim memory if highmem is not set. 705*9b6b563cSPaul Mackerras */ 706*9b6b563cSPaul Mackerras static unsigned long __init alloc_down(unsigned long size, unsigned long align, 707*9b6b563cSPaul Mackerras int highmem) 708*9b6b563cSPaul Mackerras { 709*9b6b563cSPaul Mackerras unsigned long base, addr = 0; 710*9b6b563cSPaul Mackerras 711*9b6b563cSPaul Mackerras prom_debug("alloc_down(%x, %x, %s)\n", size, align, 712*9b6b563cSPaul Mackerras highmem ? RELOC("(high)") : RELOC("(low)")); 713*9b6b563cSPaul Mackerras if (RELOC(ram_top) == 0) 714*9b6b563cSPaul Mackerras prom_panic("alloc_down() called with mem not initialized\n"); 715*9b6b563cSPaul Mackerras 716*9b6b563cSPaul Mackerras if (highmem) { 717*9b6b563cSPaul Mackerras /* Carve out storage for the TCE table. */ 718*9b6b563cSPaul Mackerras addr = _ALIGN_DOWN(RELOC(alloc_top_high) - size, align); 719*9b6b563cSPaul Mackerras if (addr <= RELOC(alloc_bottom)) 720*9b6b563cSPaul Mackerras return 0; 721*9b6b563cSPaul Mackerras /* Will we bump into the RMO ? If yes, check out that we 722*9b6b563cSPaul Mackerras * didn't overlap existing allocations there, if we did, 723*9b6b563cSPaul Mackerras * we are dead, we must be the first in town ! 724*9b6b563cSPaul Mackerras */ 725*9b6b563cSPaul Mackerras if (addr < RELOC(rmo_top)) { 726*9b6b563cSPaul Mackerras /* Good, we are first */ 727*9b6b563cSPaul Mackerras if (RELOC(alloc_top) == RELOC(rmo_top)) 728*9b6b563cSPaul Mackerras RELOC(alloc_top) = RELOC(rmo_top) = addr; 729*9b6b563cSPaul Mackerras else 730*9b6b563cSPaul Mackerras return 0; 731*9b6b563cSPaul Mackerras } 732*9b6b563cSPaul Mackerras RELOC(alloc_top_high) = addr; 733*9b6b563cSPaul Mackerras goto bail; 734*9b6b563cSPaul Mackerras } 735*9b6b563cSPaul Mackerras 736*9b6b563cSPaul Mackerras base = _ALIGN_DOWN(RELOC(alloc_top) - size, align); 737*9b6b563cSPaul Mackerras for (; base > RELOC(alloc_bottom); 738*9b6b563cSPaul Mackerras base = _ALIGN_DOWN(base - 0x100000, align)) { 739*9b6b563cSPaul Mackerras prom_debug(" trying: 0x%x\n\r", base); 740*9b6b563cSPaul Mackerras addr = (unsigned long)prom_claim(base, size, 0); 741*9b6b563cSPaul Mackerras if (addr != PROM_ERROR) 742*9b6b563cSPaul Mackerras break; 743*9b6b563cSPaul Mackerras addr = 0; 744*9b6b563cSPaul Mackerras } 745*9b6b563cSPaul Mackerras if (addr == 0) 746*9b6b563cSPaul Mackerras return 0; 747*9b6b563cSPaul Mackerras RELOC(alloc_top) = addr; 748*9b6b563cSPaul Mackerras 749*9b6b563cSPaul Mackerras bail: 750*9b6b563cSPaul Mackerras prom_debug(" -> %x\n", addr); 751*9b6b563cSPaul Mackerras prom_debug(" alloc_bottom : %x\n", RELOC(alloc_bottom)); 752*9b6b563cSPaul Mackerras prom_debug(" alloc_top : %x\n", RELOC(alloc_top)); 753*9b6b563cSPaul Mackerras prom_debug(" alloc_top_hi : %x\n", RELOC(alloc_top_high)); 754*9b6b563cSPaul Mackerras prom_debug(" rmo_top : %x\n", RELOC(rmo_top)); 755*9b6b563cSPaul Mackerras prom_debug(" ram_top : %x\n", RELOC(ram_top)); 756*9b6b563cSPaul Mackerras 757*9b6b563cSPaul Mackerras return addr; 758*9b6b563cSPaul Mackerras } 759*9b6b563cSPaul Mackerras 760*9b6b563cSPaul Mackerras /* 761*9b6b563cSPaul Mackerras * Parse a "reg" cell 762*9b6b563cSPaul Mackerras */ 763*9b6b563cSPaul Mackerras static unsigned long __init prom_next_cell(int s, cell_t **cellp) 764*9b6b563cSPaul Mackerras { 765*9b6b563cSPaul Mackerras cell_t *p = *cellp; 766*9b6b563cSPaul Mackerras unsigned long r = 0; 767*9b6b563cSPaul Mackerras 768*9b6b563cSPaul Mackerras /* Ignore more than 2 cells */ 769*9b6b563cSPaul Mackerras while (s > sizeof(unsigned long) / 4) { 770*9b6b563cSPaul Mackerras p++; 771*9b6b563cSPaul Mackerras s--; 772*9b6b563cSPaul Mackerras } 773*9b6b563cSPaul Mackerras r = *p++; 774*9b6b563cSPaul Mackerras #ifdef CONFIG_PPC64 775*9b6b563cSPaul Mackerras if (s) { 776*9b6b563cSPaul Mackerras r <<= 32; 777*9b6b563cSPaul Mackerras r |= *(p++); 778*9b6b563cSPaul Mackerras } 779*9b6b563cSPaul Mackerras #endif 780*9b6b563cSPaul Mackerras *cellp = p; 781*9b6b563cSPaul Mackerras return r; 782*9b6b563cSPaul Mackerras } 783*9b6b563cSPaul Mackerras 784*9b6b563cSPaul Mackerras /* 785*9b6b563cSPaul Mackerras * Very dumb function for adding to the memory reserve list, but 786*9b6b563cSPaul Mackerras * we don't need anything smarter at this point 787*9b6b563cSPaul Mackerras * 788*9b6b563cSPaul Mackerras * XXX Eventually check for collisions. They should NEVER happen. 789*9b6b563cSPaul Mackerras * If problems seem to show up, it would be a good start to track 790*9b6b563cSPaul Mackerras * them down. 791*9b6b563cSPaul Mackerras */ 792*9b6b563cSPaul Mackerras static void reserve_mem(unsigned long base, unsigned long size) 793*9b6b563cSPaul Mackerras { 794*9b6b563cSPaul Mackerras unsigned long top = base + size; 795*9b6b563cSPaul Mackerras unsigned long cnt = RELOC(mem_reserve_cnt); 796*9b6b563cSPaul Mackerras 797*9b6b563cSPaul Mackerras if (size == 0) 798*9b6b563cSPaul Mackerras return; 799*9b6b563cSPaul Mackerras 800*9b6b563cSPaul Mackerras /* We need to always keep one empty entry so that we 801*9b6b563cSPaul Mackerras * have our terminator with "size" set to 0 since we are 802*9b6b563cSPaul Mackerras * dumb and just copy this entire array to the boot params 803*9b6b563cSPaul Mackerras */ 804*9b6b563cSPaul Mackerras base = _ALIGN_DOWN(base, PAGE_SIZE); 805*9b6b563cSPaul Mackerras top = _ALIGN_UP(top, PAGE_SIZE); 806*9b6b563cSPaul Mackerras size = top - base; 807*9b6b563cSPaul Mackerras 808*9b6b563cSPaul Mackerras if (cnt >= (MEM_RESERVE_MAP_SIZE - 1)) 809*9b6b563cSPaul Mackerras prom_panic("Memory reserve map exhausted !\n"); 810*9b6b563cSPaul Mackerras RELOC(mem_reserve_map)[cnt].base = base; 811*9b6b563cSPaul Mackerras RELOC(mem_reserve_map)[cnt].size = size; 812*9b6b563cSPaul Mackerras RELOC(mem_reserve_cnt) = cnt + 1; 813*9b6b563cSPaul Mackerras } 814*9b6b563cSPaul Mackerras 815*9b6b563cSPaul Mackerras /* 816*9b6b563cSPaul Mackerras * Initialize memory allocation mecanism, parse "memory" nodes and 817*9b6b563cSPaul Mackerras * obtain that way the top of memory and RMO to setup out local allocator 818*9b6b563cSPaul Mackerras */ 819*9b6b563cSPaul Mackerras static void __init prom_init_mem(void) 820*9b6b563cSPaul Mackerras { 821*9b6b563cSPaul Mackerras phandle node; 822*9b6b563cSPaul Mackerras char *path, type[64]; 823*9b6b563cSPaul Mackerras unsigned int plen; 824*9b6b563cSPaul Mackerras cell_t *p, *endp; 825*9b6b563cSPaul Mackerras struct prom_t *_prom = &RELOC(prom); 826*9b6b563cSPaul Mackerras u32 rac, rsc; 827*9b6b563cSPaul Mackerras 828*9b6b563cSPaul Mackerras /* 829*9b6b563cSPaul Mackerras * We iterate the memory nodes to find 830*9b6b563cSPaul Mackerras * 1) top of RMO (first node) 831*9b6b563cSPaul Mackerras * 2) top of memory 832*9b6b563cSPaul Mackerras */ 833*9b6b563cSPaul Mackerras rac = 2; 834*9b6b563cSPaul Mackerras prom_getprop(_prom->root, "#address-cells", &rac, sizeof(rac)); 835*9b6b563cSPaul Mackerras rsc = 1; 836*9b6b563cSPaul Mackerras prom_getprop(_prom->root, "#size-cells", &rsc, sizeof(rsc)); 837*9b6b563cSPaul Mackerras prom_debug("root_addr_cells: %x\n", (unsigned long) rac); 838*9b6b563cSPaul Mackerras prom_debug("root_size_cells: %x\n", (unsigned long) rsc); 839*9b6b563cSPaul Mackerras 840*9b6b563cSPaul Mackerras prom_debug("scanning memory:\n"); 841*9b6b563cSPaul Mackerras path = RELOC(prom_scratch); 842*9b6b563cSPaul Mackerras 843*9b6b563cSPaul Mackerras for (node = 0; prom_next_node(&node); ) { 844*9b6b563cSPaul Mackerras type[0] = 0; 845*9b6b563cSPaul Mackerras prom_getprop(node, "device_type", type, sizeof(type)); 846*9b6b563cSPaul Mackerras 847*9b6b563cSPaul Mackerras if (strcmp(type, RELOC("memory"))) 848*9b6b563cSPaul Mackerras continue; 849*9b6b563cSPaul Mackerras 850*9b6b563cSPaul Mackerras plen = prom_getprop(node, "reg", RELOC(regbuf), sizeof(regbuf)); 851*9b6b563cSPaul Mackerras if (plen > sizeof(regbuf)) { 852*9b6b563cSPaul Mackerras prom_printf("memory node too large for buffer !\n"); 853*9b6b563cSPaul Mackerras plen = sizeof(regbuf); 854*9b6b563cSPaul Mackerras } 855*9b6b563cSPaul Mackerras p = RELOC(regbuf); 856*9b6b563cSPaul Mackerras endp = p + (plen / sizeof(cell_t)); 857*9b6b563cSPaul Mackerras 858*9b6b563cSPaul Mackerras #ifdef DEBUG_PROM 859*9b6b563cSPaul Mackerras memset(path, 0, PROM_SCRATCH_SIZE); 860*9b6b563cSPaul Mackerras call_prom("package-to-path", 3, 1, node, path, PROM_SCRATCH_SIZE-1); 861*9b6b563cSPaul Mackerras prom_debug(" node %s :\n", path); 862*9b6b563cSPaul Mackerras #endif /* DEBUG_PROM */ 863*9b6b563cSPaul Mackerras 864*9b6b563cSPaul Mackerras while ((endp - p) >= (rac + rsc)) { 865*9b6b563cSPaul Mackerras unsigned long base, size; 866*9b6b563cSPaul Mackerras 867*9b6b563cSPaul Mackerras base = prom_next_cell(rac, &p); 868*9b6b563cSPaul Mackerras size = prom_next_cell(rsc, &p); 869*9b6b563cSPaul Mackerras 870*9b6b563cSPaul Mackerras if (size == 0) 871*9b6b563cSPaul Mackerras continue; 872*9b6b563cSPaul Mackerras prom_debug(" %x %x\n", base, size); 873*9b6b563cSPaul Mackerras if (base == 0) 874*9b6b563cSPaul Mackerras RELOC(rmo_top) = size; 875*9b6b563cSPaul Mackerras if ((base + size) > RELOC(ram_top)) 876*9b6b563cSPaul Mackerras RELOC(ram_top) = base + size; 877*9b6b563cSPaul Mackerras } 878*9b6b563cSPaul Mackerras } 879*9b6b563cSPaul Mackerras 880*9b6b563cSPaul Mackerras RELOC(alloc_bottom) = PAGE_ALIGN((unsigned long)&RELOC(_end) + 0x4000); 881*9b6b563cSPaul Mackerras 882*9b6b563cSPaul Mackerras /* Check if we have an initrd after the kernel, if we do move our bottom 883*9b6b563cSPaul Mackerras * point to after it 884*9b6b563cSPaul Mackerras */ 885*9b6b563cSPaul Mackerras if (RELOC(prom_initrd_start)) { 886*9b6b563cSPaul Mackerras if (RELOC(prom_initrd_end) > RELOC(alloc_bottom)) 887*9b6b563cSPaul Mackerras RELOC(alloc_bottom) = PAGE_ALIGN(RELOC(prom_initrd_end)); 888*9b6b563cSPaul Mackerras } 889*9b6b563cSPaul Mackerras 890*9b6b563cSPaul Mackerras /* 891*9b6b563cSPaul Mackerras * If prom_memory_limit is set we reduce the upper limits *except* for 892*9b6b563cSPaul Mackerras * alloc_top_high. This must be the real top of RAM so we can put 893*9b6b563cSPaul Mackerras * TCE's up there. 894*9b6b563cSPaul Mackerras */ 895*9b6b563cSPaul Mackerras 896*9b6b563cSPaul Mackerras RELOC(alloc_top_high) = RELOC(ram_top); 897*9b6b563cSPaul Mackerras 898*9b6b563cSPaul Mackerras if (RELOC(prom_memory_limit)) { 899*9b6b563cSPaul Mackerras if (RELOC(prom_memory_limit) <= RELOC(alloc_bottom)) { 900*9b6b563cSPaul Mackerras prom_printf("Ignoring mem=%x <= alloc_bottom.\n", 901*9b6b563cSPaul Mackerras RELOC(prom_memory_limit)); 902*9b6b563cSPaul Mackerras RELOC(prom_memory_limit) = 0; 903*9b6b563cSPaul Mackerras } else if (RELOC(prom_memory_limit) >= RELOC(ram_top)) { 904*9b6b563cSPaul Mackerras prom_printf("Ignoring mem=%x >= ram_top.\n", 905*9b6b563cSPaul Mackerras RELOC(prom_memory_limit)); 906*9b6b563cSPaul Mackerras RELOC(prom_memory_limit) = 0; 907*9b6b563cSPaul Mackerras } else { 908*9b6b563cSPaul Mackerras RELOC(ram_top) = RELOC(prom_memory_limit); 909*9b6b563cSPaul Mackerras RELOC(rmo_top) = min(RELOC(rmo_top), RELOC(prom_memory_limit)); 910*9b6b563cSPaul Mackerras } 911*9b6b563cSPaul Mackerras } 912*9b6b563cSPaul Mackerras 913*9b6b563cSPaul Mackerras /* 914*9b6b563cSPaul Mackerras * Setup our top alloc point, that is top of RMO or top of 915*9b6b563cSPaul Mackerras * segment 0 when running non-LPAR. 916*9b6b563cSPaul Mackerras * Some RS64 machines have buggy firmware where claims up at 917*9b6b563cSPaul Mackerras * 1GB fail. Cap at 768MB as a workaround. 918*9b6b563cSPaul Mackerras * Since 768MB is plenty of room, and we need to cap to something 919*9b6b563cSPaul Mackerras * reasonable on 32-bit, cap at 768MB on all machines. 920*9b6b563cSPaul Mackerras */ 921*9b6b563cSPaul Mackerras if (!RELOC(rmo_top)) 922*9b6b563cSPaul Mackerras RELOC(rmo_top) = RELOC(ram_top); 923*9b6b563cSPaul Mackerras RELOC(rmo_top) = min(0x30000000ul, RELOC(rmo_top)); 924*9b6b563cSPaul Mackerras RELOC(alloc_top) = RELOC(rmo_top); 925*9b6b563cSPaul Mackerras 926*9b6b563cSPaul Mackerras prom_printf("memory layout at init:\n"); 927*9b6b563cSPaul Mackerras prom_printf(" memory_limit : %x (16 MB aligned)\n", RELOC(prom_memory_limit)); 928*9b6b563cSPaul Mackerras prom_printf(" alloc_bottom : %x\n", RELOC(alloc_bottom)); 929*9b6b563cSPaul Mackerras prom_printf(" alloc_top : %x\n", RELOC(alloc_top)); 930*9b6b563cSPaul Mackerras prom_printf(" alloc_top_hi : %x\n", RELOC(alloc_top_high)); 931*9b6b563cSPaul Mackerras prom_printf(" rmo_top : %x\n", RELOC(rmo_top)); 932*9b6b563cSPaul Mackerras prom_printf(" ram_top : %x\n", RELOC(ram_top)); 933*9b6b563cSPaul Mackerras } 934*9b6b563cSPaul Mackerras 935*9b6b563cSPaul Mackerras 936*9b6b563cSPaul Mackerras /* 937*9b6b563cSPaul Mackerras * Allocate room for and instantiate RTAS 938*9b6b563cSPaul Mackerras */ 939*9b6b563cSPaul Mackerras static void __init prom_instantiate_rtas(void) 940*9b6b563cSPaul Mackerras { 941*9b6b563cSPaul Mackerras phandle rtas_node; 942*9b6b563cSPaul Mackerras ihandle rtas_inst; 943*9b6b563cSPaul Mackerras u32 base, entry = 0; 944*9b6b563cSPaul Mackerras u32 size = 0; 945*9b6b563cSPaul Mackerras 946*9b6b563cSPaul Mackerras prom_debug("prom_instantiate_rtas: start...\n"); 947*9b6b563cSPaul Mackerras 948*9b6b563cSPaul Mackerras rtas_node = call_prom("finddevice", 1, 1, ADDR("/rtas")); 949*9b6b563cSPaul Mackerras prom_debug("rtas_node: %x\n", rtas_node); 950*9b6b563cSPaul Mackerras if (!PHANDLE_VALID(rtas_node)) 951*9b6b563cSPaul Mackerras return; 952*9b6b563cSPaul Mackerras 953*9b6b563cSPaul Mackerras prom_getprop(rtas_node, "rtas-size", &size, sizeof(size)); 954*9b6b563cSPaul Mackerras if (size == 0) 955*9b6b563cSPaul Mackerras return; 956*9b6b563cSPaul Mackerras 957*9b6b563cSPaul Mackerras base = alloc_down(size, PAGE_SIZE, 0); 958*9b6b563cSPaul Mackerras if (base == 0) { 959*9b6b563cSPaul Mackerras prom_printf("RTAS allocation failed !\n"); 960*9b6b563cSPaul Mackerras return; 961*9b6b563cSPaul Mackerras } 962*9b6b563cSPaul Mackerras 963*9b6b563cSPaul Mackerras rtas_inst = call_prom("open", 1, 1, ADDR("/rtas")); 964*9b6b563cSPaul Mackerras if (!IHANDLE_VALID(rtas_inst)) { 965*9b6b563cSPaul Mackerras prom_printf("opening rtas package failed"); 966*9b6b563cSPaul Mackerras return; 967*9b6b563cSPaul Mackerras } 968*9b6b563cSPaul Mackerras 969*9b6b563cSPaul Mackerras prom_printf("instantiating rtas at 0x%x ...", base); 970*9b6b563cSPaul Mackerras 971*9b6b563cSPaul Mackerras if (call_prom_ret("call-method", 3, 2, &entry, 972*9b6b563cSPaul Mackerras ADDR("instantiate-rtas"), 973*9b6b563cSPaul Mackerras rtas_inst, base) == PROM_ERROR 974*9b6b563cSPaul Mackerras || entry == 0) { 975*9b6b563cSPaul Mackerras prom_printf(" failed\n"); 976*9b6b563cSPaul Mackerras return; 977*9b6b563cSPaul Mackerras } 978*9b6b563cSPaul Mackerras prom_printf(" done\n"); 979*9b6b563cSPaul Mackerras 980*9b6b563cSPaul Mackerras reserve_mem(base, size); 981*9b6b563cSPaul Mackerras 982*9b6b563cSPaul Mackerras prom_setprop(rtas_node, "linux,rtas-base", &base, sizeof(base)); 983*9b6b563cSPaul Mackerras prom_setprop(rtas_node, "linux,rtas-entry", &entry, sizeof(entry)); 984*9b6b563cSPaul Mackerras 985*9b6b563cSPaul Mackerras prom_debug("rtas base = 0x%x\n", base); 986*9b6b563cSPaul Mackerras prom_debug("rtas entry = 0x%x\n", entry); 987*9b6b563cSPaul Mackerras prom_debug("rtas size = 0x%x\n", (long)size); 988*9b6b563cSPaul Mackerras 989*9b6b563cSPaul Mackerras prom_debug("prom_instantiate_rtas: end...\n"); 990*9b6b563cSPaul Mackerras } 991*9b6b563cSPaul Mackerras 992*9b6b563cSPaul Mackerras #ifdef CONFIG_PPC64 993*9b6b563cSPaul Mackerras /* 994*9b6b563cSPaul Mackerras * Allocate room for and initialize TCE tables 995*9b6b563cSPaul Mackerras */ 996*9b6b563cSPaul Mackerras static void __init prom_initialize_tce_table(void) 997*9b6b563cSPaul Mackerras { 998*9b6b563cSPaul Mackerras phandle node; 999*9b6b563cSPaul Mackerras ihandle phb_node; 1000*9b6b563cSPaul Mackerras char compatible[64], type[64], model[64]; 1001*9b6b563cSPaul Mackerras char *path = RELOC(prom_scratch); 1002*9b6b563cSPaul Mackerras u64 base, align; 1003*9b6b563cSPaul Mackerras u32 minalign, minsize; 1004*9b6b563cSPaul Mackerras u64 tce_entry, *tce_entryp; 1005*9b6b563cSPaul Mackerras u64 local_alloc_top, local_alloc_bottom; 1006*9b6b563cSPaul Mackerras u64 i; 1007*9b6b563cSPaul Mackerras 1008*9b6b563cSPaul Mackerras if (RELOC(ppc64_iommu_off)) 1009*9b6b563cSPaul Mackerras return; 1010*9b6b563cSPaul Mackerras 1011*9b6b563cSPaul Mackerras prom_debug("starting prom_initialize_tce_table\n"); 1012*9b6b563cSPaul Mackerras 1013*9b6b563cSPaul Mackerras /* Cache current top of allocs so we reserve a single block */ 1014*9b6b563cSPaul Mackerras local_alloc_top = RELOC(alloc_top_high); 1015*9b6b563cSPaul Mackerras local_alloc_bottom = local_alloc_top; 1016*9b6b563cSPaul Mackerras 1017*9b6b563cSPaul Mackerras /* Search all nodes looking for PHBs. */ 1018*9b6b563cSPaul Mackerras for (node = 0; prom_next_node(&node); ) { 1019*9b6b563cSPaul Mackerras compatible[0] = 0; 1020*9b6b563cSPaul Mackerras type[0] = 0; 1021*9b6b563cSPaul Mackerras model[0] = 0; 1022*9b6b563cSPaul Mackerras prom_getprop(node, "compatible", 1023*9b6b563cSPaul Mackerras compatible, sizeof(compatible)); 1024*9b6b563cSPaul Mackerras prom_getprop(node, "device_type", type, sizeof(type)); 1025*9b6b563cSPaul Mackerras prom_getprop(node, "model", model, sizeof(model)); 1026*9b6b563cSPaul Mackerras 1027*9b6b563cSPaul Mackerras if ((type[0] == 0) || (strstr(type, RELOC("pci")) == NULL)) 1028*9b6b563cSPaul Mackerras continue; 1029*9b6b563cSPaul Mackerras 1030*9b6b563cSPaul Mackerras /* Keep the old logic in tack to avoid regression. */ 1031*9b6b563cSPaul Mackerras if (compatible[0] != 0) { 1032*9b6b563cSPaul Mackerras if ((strstr(compatible, RELOC("python")) == NULL) && 1033*9b6b563cSPaul Mackerras (strstr(compatible, RELOC("Speedwagon")) == NULL) && 1034*9b6b563cSPaul Mackerras (strstr(compatible, RELOC("Winnipeg")) == NULL)) 1035*9b6b563cSPaul Mackerras continue; 1036*9b6b563cSPaul Mackerras } else if (model[0] != 0) { 1037*9b6b563cSPaul Mackerras if ((strstr(model, RELOC("ython")) == NULL) && 1038*9b6b563cSPaul Mackerras (strstr(model, RELOC("peedwagon")) == NULL) && 1039*9b6b563cSPaul Mackerras (strstr(model, RELOC("innipeg")) == NULL)) 1040*9b6b563cSPaul Mackerras continue; 1041*9b6b563cSPaul Mackerras } 1042*9b6b563cSPaul Mackerras 1043*9b6b563cSPaul Mackerras if (prom_getprop(node, "tce-table-minalign", &minalign, 1044*9b6b563cSPaul Mackerras sizeof(minalign)) == PROM_ERROR) 1045*9b6b563cSPaul Mackerras minalign = 0; 1046*9b6b563cSPaul Mackerras if (prom_getprop(node, "tce-table-minsize", &minsize, 1047*9b6b563cSPaul Mackerras sizeof(minsize)) == PROM_ERROR) 1048*9b6b563cSPaul Mackerras minsize = 4UL << 20; 1049*9b6b563cSPaul Mackerras 1050*9b6b563cSPaul Mackerras /* 1051*9b6b563cSPaul Mackerras * Even though we read what OF wants, we just set the table 1052*9b6b563cSPaul Mackerras * size to 4 MB. This is enough to map 2GB of PCI DMA space. 1053*9b6b563cSPaul Mackerras * By doing this, we avoid the pitfalls of trying to DMA to 1054*9b6b563cSPaul Mackerras * MMIO space and the DMA alias hole. 1055*9b6b563cSPaul Mackerras * 1056*9b6b563cSPaul Mackerras * On POWER4, firmware sets the TCE region by assuming 1057*9b6b563cSPaul Mackerras * each TCE table is 8MB. Using this memory for anything 1058*9b6b563cSPaul Mackerras * else will impact performance, so we always allocate 8MB. 1059*9b6b563cSPaul Mackerras * Anton 1060*9b6b563cSPaul Mackerras */ 1061*9b6b563cSPaul Mackerras if (__is_processor(PV_POWER4) || __is_processor(PV_POWER4p)) 1062*9b6b563cSPaul Mackerras minsize = 8UL << 20; 1063*9b6b563cSPaul Mackerras else 1064*9b6b563cSPaul Mackerras minsize = 4UL << 20; 1065*9b6b563cSPaul Mackerras 1066*9b6b563cSPaul Mackerras /* Align to the greater of the align or size */ 1067*9b6b563cSPaul Mackerras align = max(minalign, minsize); 1068*9b6b563cSPaul Mackerras base = alloc_down(minsize, align, 1); 1069*9b6b563cSPaul Mackerras if (base == 0) 1070*9b6b563cSPaul Mackerras prom_panic("ERROR, cannot find space for TCE table.\n"); 1071*9b6b563cSPaul Mackerras if (base < local_alloc_bottom) 1072*9b6b563cSPaul Mackerras local_alloc_bottom = base; 1073*9b6b563cSPaul Mackerras 1074*9b6b563cSPaul Mackerras /* Save away the TCE table attributes for later use. */ 1075*9b6b563cSPaul Mackerras prom_setprop(node, "linux,tce-base", &base, sizeof(base)); 1076*9b6b563cSPaul Mackerras prom_setprop(node, "linux,tce-size", &minsize, sizeof(minsize)); 1077*9b6b563cSPaul Mackerras 1078*9b6b563cSPaul Mackerras /* It seems OF doesn't null-terminate the path :-( */ 1079*9b6b563cSPaul Mackerras memset(path, 0, sizeof(path)); 1080*9b6b563cSPaul Mackerras /* Call OF to setup the TCE hardware */ 1081*9b6b563cSPaul Mackerras if (call_prom("package-to-path", 3, 1, node, 1082*9b6b563cSPaul Mackerras path, PROM_SCRATCH_SIZE-1) == PROM_ERROR) { 1083*9b6b563cSPaul Mackerras prom_printf("package-to-path failed\n"); 1084*9b6b563cSPaul Mackerras } 1085*9b6b563cSPaul Mackerras 1086*9b6b563cSPaul Mackerras prom_debug("TCE table: %s\n", path); 1087*9b6b563cSPaul Mackerras prom_debug("\tnode = 0x%x\n", node); 1088*9b6b563cSPaul Mackerras prom_debug("\tbase = 0x%x\n", base); 1089*9b6b563cSPaul Mackerras prom_debug("\tsize = 0x%x\n", minsize); 1090*9b6b563cSPaul Mackerras 1091*9b6b563cSPaul Mackerras /* Initialize the table to have a one-to-one mapping 1092*9b6b563cSPaul Mackerras * over the allocated size. 1093*9b6b563cSPaul Mackerras */ 1094*9b6b563cSPaul Mackerras tce_entryp = (unsigned long *)base; 1095*9b6b563cSPaul Mackerras for (i = 0; i < (minsize >> 3) ;tce_entryp++, i++) { 1096*9b6b563cSPaul Mackerras tce_entry = (i << PAGE_SHIFT); 1097*9b6b563cSPaul Mackerras tce_entry |= 0x3; 1098*9b6b563cSPaul Mackerras *tce_entryp = tce_entry; 1099*9b6b563cSPaul Mackerras } 1100*9b6b563cSPaul Mackerras 1101*9b6b563cSPaul Mackerras prom_printf("opening PHB %s", path); 1102*9b6b563cSPaul Mackerras phb_node = call_prom("open", 1, 1, path); 1103*9b6b563cSPaul Mackerras if (phb_node == 0) 1104*9b6b563cSPaul Mackerras prom_printf("... failed\n"); 1105*9b6b563cSPaul Mackerras else 1106*9b6b563cSPaul Mackerras prom_printf("... done\n"); 1107*9b6b563cSPaul Mackerras 1108*9b6b563cSPaul Mackerras call_prom("call-method", 6, 0, ADDR("set-64-bit-addressing"), 1109*9b6b563cSPaul Mackerras phb_node, -1, minsize, 1110*9b6b563cSPaul Mackerras (u32) base, (u32) (base >> 32)); 1111*9b6b563cSPaul Mackerras call_prom("close", 1, 0, phb_node); 1112*9b6b563cSPaul Mackerras } 1113*9b6b563cSPaul Mackerras 1114*9b6b563cSPaul Mackerras reserve_mem(local_alloc_bottom, local_alloc_top - local_alloc_bottom); 1115*9b6b563cSPaul Mackerras 1116*9b6b563cSPaul Mackerras if (RELOC(prom_memory_limit)) { 1117*9b6b563cSPaul Mackerras /* 1118*9b6b563cSPaul Mackerras * We align the start to a 16MB boundary so we can map 1119*9b6b563cSPaul Mackerras * the TCE area using large pages if possible. 1120*9b6b563cSPaul Mackerras * The end should be the top of RAM so no need to align it. 1121*9b6b563cSPaul Mackerras */ 1122*9b6b563cSPaul Mackerras RELOC(prom_tce_alloc_start) = _ALIGN_DOWN(local_alloc_bottom, 1123*9b6b563cSPaul Mackerras 0x1000000); 1124*9b6b563cSPaul Mackerras RELOC(prom_tce_alloc_end) = local_alloc_top; 1125*9b6b563cSPaul Mackerras } 1126*9b6b563cSPaul Mackerras 1127*9b6b563cSPaul Mackerras /* Flag the first invalid entry */ 1128*9b6b563cSPaul Mackerras prom_debug("ending prom_initialize_tce_table\n"); 1129*9b6b563cSPaul Mackerras } 1130*9b6b563cSPaul Mackerras #endif 1131*9b6b563cSPaul Mackerras 1132*9b6b563cSPaul Mackerras /* 1133*9b6b563cSPaul Mackerras * With CHRP SMP we need to use the OF to start the other processors. 1134*9b6b563cSPaul Mackerras * We can't wait until smp_boot_cpus (the OF is trashed by then) 1135*9b6b563cSPaul Mackerras * so we have to put the processors into a holding pattern controlled 1136*9b6b563cSPaul Mackerras * by the kernel (not OF) before we destroy the OF. 1137*9b6b563cSPaul Mackerras * 1138*9b6b563cSPaul Mackerras * This uses a chunk of low memory, puts some holding pattern 1139*9b6b563cSPaul Mackerras * code there and sends the other processors off to there until 1140*9b6b563cSPaul Mackerras * smp_boot_cpus tells them to do something. The holding pattern 1141*9b6b563cSPaul Mackerras * checks that address until its cpu # is there, when it is that 1142*9b6b563cSPaul Mackerras * cpu jumps to __secondary_start(). smp_boot_cpus() takes care 1143*9b6b563cSPaul Mackerras * of setting those values. 1144*9b6b563cSPaul Mackerras * 1145*9b6b563cSPaul Mackerras * We also use physical address 0x4 here to tell when a cpu 1146*9b6b563cSPaul Mackerras * is in its holding pattern code. 1147*9b6b563cSPaul Mackerras * 1148*9b6b563cSPaul Mackerras * -- Cort 1149*9b6b563cSPaul Mackerras */ 1150*9b6b563cSPaul Mackerras static void __init prom_hold_cpus(void) 1151*9b6b563cSPaul Mackerras { 1152*9b6b563cSPaul Mackerras #ifdef CONFIG_PPC64 1153*9b6b563cSPaul Mackerras unsigned long i; 1154*9b6b563cSPaul Mackerras unsigned int reg; 1155*9b6b563cSPaul Mackerras phandle node; 1156*9b6b563cSPaul Mackerras char type[64]; 1157*9b6b563cSPaul Mackerras int cpuid = 0; 1158*9b6b563cSPaul Mackerras unsigned int interrupt_server[MAX_CPU_THREADS]; 1159*9b6b563cSPaul Mackerras unsigned int cpu_threads, hw_cpu_num; 1160*9b6b563cSPaul Mackerras int propsize; 1161*9b6b563cSPaul Mackerras extern void __secondary_hold(void); 1162*9b6b563cSPaul Mackerras extern unsigned long __secondary_hold_spinloop; 1163*9b6b563cSPaul Mackerras extern unsigned long __secondary_hold_acknowledge; 1164*9b6b563cSPaul Mackerras unsigned long *spinloop 1165*9b6b563cSPaul Mackerras = (void *) __pa(&__secondary_hold_spinloop); 1166*9b6b563cSPaul Mackerras unsigned long *acknowledge 1167*9b6b563cSPaul Mackerras = (void *) __pa(&__secondary_hold_acknowledge); 1168*9b6b563cSPaul Mackerras #ifdef CONFIG_PPC64 1169*9b6b563cSPaul Mackerras unsigned long secondary_hold 1170*9b6b563cSPaul Mackerras = __pa(*PTRRELOC((unsigned long *)__secondary_hold)); 1171*9b6b563cSPaul Mackerras #else 1172*9b6b563cSPaul Mackerras unsigned long secondary_hold = __pa(&__secondary_hold); 1173*9b6b563cSPaul Mackerras #endif 1174*9b6b563cSPaul Mackerras struct prom_t *_prom = &RELOC(prom); 1175*9b6b563cSPaul Mackerras 1176*9b6b563cSPaul Mackerras prom_debug("prom_hold_cpus: start...\n"); 1177*9b6b563cSPaul Mackerras prom_debug(" 1) spinloop = 0x%x\n", (unsigned long)spinloop); 1178*9b6b563cSPaul Mackerras prom_debug(" 1) *spinloop = 0x%x\n", *spinloop); 1179*9b6b563cSPaul Mackerras prom_debug(" 1) acknowledge = 0x%x\n", 1180*9b6b563cSPaul Mackerras (unsigned long)acknowledge); 1181*9b6b563cSPaul Mackerras prom_debug(" 1) *acknowledge = 0x%x\n", *acknowledge); 1182*9b6b563cSPaul Mackerras prom_debug(" 1) secondary_hold = 0x%x\n", secondary_hold); 1183*9b6b563cSPaul Mackerras 1184*9b6b563cSPaul Mackerras /* Set the common spinloop variable, so all of the secondary cpus 1185*9b6b563cSPaul Mackerras * will block when they are awakened from their OF spinloop. 1186*9b6b563cSPaul Mackerras * This must occur for both SMP and non SMP kernels, since OF will 1187*9b6b563cSPaul Mackerras * be trashed when we move the kernel. 1188*9b6b563cSPaul Mackerras */ 1189*9b6b563cSPaul Mackerras *spinloop = 0; 1190*9b6b563cSPaul Mackerras 1191*9b6b563cSPaul Mackerras #ifdef CONFIG_HMT 1192*9b6b563cSPaul Mackerras for (i = 0; i < NR_CPUS; i++) { 1193*9b6b563cSPaul Mackerras RELOC(hmt_thread_data)[i].pir = 0xdeadbeef; 1194*9b6b563cSPaul Mackerras } 1195*9b6b563cSPaul Mackerras #endif 1196*9b6b563cSPaul Mackerras /* look for cpus */ 1197*9b6b563cSPaul Mackerras for (node = 0; prom_next_node(&node); ) { 1198*9b6b563cSPaul Mackerras type[0] = 0; 1199*9b6b563cSPaul Mackerras prom_getprop(node, "device_type", type, sizeof(type)); 1200*9b6b563cSPaul Mackerras if (strcmp(type, RELOC("cpu")) != 0) 1201*9b6b563cSPaul Mackerras continue; 1202*9b6b563cSPaul Mackerras 1203*9b6b563cSPaul Mackerras /* Skip non-configured cpus. */ 1204*9b6b563cSPaul Mackerras if (prom_getprop(node, "status", type, sizeof(type)) > 0) 1205*9b6b563cSPaul Mackerras if (strcmp(type, RELOC("okay")) != 0) 1206*9b6b563cSPaul Mackerras continue; 1207*9b6b563cSPaul Mackerras 1208*9b6b563cSPaul Mackerras reg = -1; 1209*9b6b563cSPaul Mackerras prom_getprop(node, "reg", ®, sizeof(reg)); 1210*9b6b563cSPaul Mackerras 1211*9b6b563cSPaul Mackerras prom_debug("\ncpuid = 0x%x\n", cpuid); 1212*9b6b563cSPaul Mackerras prom_debug("cpu hw idx = 0x%x\n", reg); 1213*9b6b563cSPaul Mackerras 1214*9b6b563cSPaul Mackerras /* Init the acknowledge var which will be reset by 1215*9b6b563cSPaul Mackerras * the secondary cpu when it awakens from its OF 1216*9b6b563cSPaul Mackerras * spinloop. 1217*9b6b563cSPaul Mackerras */ 1218*9b6b563cSPaul Mackerras *acknowledge = (unsigned long)-1; 1219*9b6b563cSPaul Mackerras 1220*9b6b563cSPaul Mackerras propsize = prom_getprop(node, "ibm,ppc-interrupt-server#s", 1221*9b6b563cSPaul Mackerras &interrupt_server, 1222*9b6b563cSPaul Mackerras sizeof(interrupt_server)); 1223*9b6b563cSPaul Mackerras if (propsize < 0) { 1224*9b6b563cSPaul Mackerras /* no property. old hardware has no SMT */ 1225*9b6b563cSPaul Mackerras cpu_threads = 1; 1226*9b6b563cSPaul Mackerras interrupt_server[0] = reg; /* fake it with phys id */ 1227*9b6b563cSPaul Mackerras } else { 1228*9b6b563cSPaul Mackerras /* We have a threaded processor */ 1229*9b6b563cSPaul Mackerras cpu_threads = propsize / sizeof(u32); 1230*9b6b563cSPaul Mackerras if (cpu_threads > MAX_CPU_THREADS) { 1231*9b6b563cSPaul Mackerras prom_printf("SMT: too many threads!\n" 1232*9b6b563cSPaul Mackerras "SMT: found %x, max is %x\n", 1233*9b6b563cSPaul Mackerras cpu_threads, MAX_CPU_THREADS); 1234*9b6b563cSPaul Mackerras cpu_threads = 1; /* ToDo: panic? */ 1235*9b6b563cSPaul Mackerras } 1236*9b6b563cSPaul Mackerras } 1237*9b6b563cSPaul Mackerras 1238*9b6b563cSPaul Mackerras hw_cpu_num = interrupt_server[0]; 1239*9b6b563cSPaul Mackerras if (hw_cpu_num != _prom->cpu) { 1240*9b6b563cSPaul Mackerras /* Primary Thread of non-boot cpu */ 1241*9b6b563cSPaul Mackerras prom_printf("%x : starting cpu hw idx %x... ", cpuid, reg); 1242*9b6b563cSPaul Mackerras call_prom("start-cpu", 3, 0, node, 1243*9b6b563cSPaul Mackerras secondary_hold, reg); 1244*9b6b563cSPaul Mackerras 1245*9b6b563cSPaul Mackerras for ( i = 0 ; (i < 100000000) && 1246*9b6b563cSPaul Mackerras (*acknowledge == ((unsigned long)-1)); i++ ) 1247*9b6b563cSPaul Mackerras mb(); 1248*9b6b563cSPaul Mackerras 1249*9b6b563cSPaul Mackerras if (*acknowledge == reg) { 1250*9b6b563cSPaul Mackerras prom_printf("done\n"); 1251*9b6b563cSPaul Mackerras /* We have to get every CPU out of OF, 1252*9b6b563cSPaul Mackerras * even if we never start it. */ 1253*9b6b563cSPaul Mackerras if (cpuid >= NR_CPUS) 1254*9b6b563cSPaul Mackerras goto next; 1255*9b6b563cSPaul Mackerras } else { 1256*9b6b563cSPaul Mackerras prom_printf("failed: %x\n", *acknowledge); 1257*9b6b563cSPaul Mackerras } 1258*9b6b563cSPaul Mackerras } 1259*9b6b563cSPaul Mackerras #ifdef CONFIG_SMP 1260*9b6b563cSPaul Mackerras else 1261*9b6b563cSPaul Mackerras prom_printf("%x : boot cpu %x\n", cpuid, reg); 1262*9b6b563cSPaul Mackerras #endif 1263*9b6b563cSPaul Mackerras next: 1264*9b6b563cSPaul Mackerras #ifdef CONFIG_SMP 1265*9b6b563cSPaul Mackerras /* Init paca for secondary threads. They start later. */ 1266*9b6b563cSPaul Mackerras for (i=1; i < cpu_threads; i++) { 1267*9b6b563cSPaul Mackerras cpuid++; 1268*9b6b563cSPaul Mackerras if (cpuid >= NR_CPUS) 1269*9b6b563cSPaul Mackerras continue; 1270*9b6b563cSPaul Mackerras } 1271*9b6b563cSPaul Mackerras #endif /* CONFIG_SMP */ 1272*9b6b563cSPaul Mackerras cpuid++; 1273*9b6b563cSPaul Mackerras } 1274*9b6b563cSPaul Mackerras #ifdef CONFIG_HMT 1275*9b6b563cSPaul Mackerras /* Only enable HMT on processors that provide support. */ 1276*9b6b563cSPaul Mackerras if (__is_processor(PV_PULSAR) || 1277*9b6b563cSPaul Mackerras __is_processor(PV_ICESTAR) || 1278*9b6b563cSPaul Mackerras __is_processor(PV_SSTAR)) { 1279*9b6b563cSPaul Mackerras prom_printf(" starting secondary threads\n"); 1280*9b6b563cSPaul Mackerras 1281*9b6b563cSPaul Mackerras for (i = 0; i < NR_CPUS; i += 2) { 1282*9b6b563cSPaul Mackerras if (!cpu_online(i)) 1283*9b6b563cSPaul Mackerras continue; 1284*9b6b563cSPaul Mackerras 1285*9b6b563cSPaul Mackerras if (i == 0) { 1286*9b6b563cSPaul Mackerras unsigned long pir = mfspr(SPRN_PIR); 1287*9b6b563cSPaul Mackerras if (__is_processor(PV_PULSAR)) { 1288*9b6b563cSPaul Mackerras RELOC(hmt_thread_data)[i].pir = 1289*9b6b563cSPaul Mackerras pir & 0x1f; 1290*9b6b563cSPaul Mackerras } else { 1291*9b6b563cSPaul Mackerras RELOC(hmt_thread_data)[i].pir = 1292*9b6b563cSPaul Mackerras pir & 0x3ff; 1293*9b6b563cSPaul Mackerras } 1294*9b6b563cSPaul Mackerras } 1295*9b6b563cSPaul Mackerras } 1296*9b6b563cSPaul Mackerras } else { 1297*9b6b563cSPaul Mackerras prom_printf("Processor is not HMT capable\n"); 1298*9b6b563cSPaul Mackerras } 1299*9b6b563cSPaul Mackerras #endif 1300*9b6b563cSPaul Mackerras 1301*9b6b563cSPaul Mackerras if (cpuid > NR_CPUS) 1302*9b6b563cSPaul Mackerras prom_printf("WARNING: maximum CPUs (" __stringify(NR_CPUS) 1303*9b6b563cSPaul Mackerras ") exceeded: ignoring extras\n"); 1304*9b6b563cSPaul Mackerras 1305*9b6b563cSPaul Mackerras prom_debug("prom_hold_cpus: end...\n"); 1306*9b6b563cSPaul Mackerras #endif 1307*9b6b563cSPaul Mackerras } 1308*9b6b563cSPaul Mackerras 1309*9b6b563cSPaul Mackerras 1310*9b6b563cSPaul Mackerras static void __init prom_init_client_services(unsigned long pp) 1311*9b6b563cSPaul Mackerras { 1312*9b6b563cSPaul Mackerras struct prom_t *_prom = &RELOC(prom); 1313*9b6b563cSPaul Mackerras 1314*9b6b563cSPaul Mackerras /* Get a handle to the prom entry point before anything else */ 1315*9b6b563cSPaul Mackerras RELOC(prom_entry) = pp; 1316*9b6b563cSPaul Mackerras 1317*9b6b563cSPaul Mackerras /* get a handle for the stdout device */ 1318*9b6b563cSPaul Mackerras _prom->chosen = call_prom("finddevice", 1, 1, ADDR("/chosen")); 1319*9b6b563cSPaul Mackerras if (!PHANDLE_VALID(_prom->chosen)) 1320*9b6b563cSPaul Mackerras prom_panic("cannot find chosen"); /* msg won't be printed :( */ 1321*9b6b563cSPaul Mackerras 1322*9b6b563cSPaul Mackerras /* get device tree root */ 1323*9b6b563cSPaul Mackerras _prom->root = call_prom("finddevice", 1, 1, ADDR("/")); 1324*9b6b563cSPaul Mackerras if (!PHANDLE_VALID(_prom->root)) 1325*9b6b563cSPaul Mackerras prom_panic("cannot find device tree root"); /* msg won't be printed :( */ 1326*9b6b563cSPaul Mackerras } 1327*9b6b563cSPaul Mackerras 1328*9b6b563cSPaul Mackerras static void __init prom_init_stdout(void) 1329*9b6b563cSPaul Mackerras { 1330*9b6b563cSPaul Mackerras struct prom_t *_prom = &RELOC(prom); 1331*9b6b563cSPaul Mackerras char *path = RELOC(of_stdout_device); 1332*9b6b563cSPaul Mackerras char type[16]; 1333*9b6b563cSPaul Mackerras u32 val; 1334*9b6b563cSPaul Mackerras 1335*9b6b563cSPaul Mackerras if (prom_getprop(_prom->chosen, "stdout", &val, sizeof(val)) <= 0) 1336*9b6b563cSPaul Mackerras prom_panic("cannot find stdout"); 1337*9b6b563cSPaul Mackerras 1338*9b6b563cSPaul Mackerras _prom->stdout = val; 1339*9b6b563cSPaul Mackerras 1340*9b6b563cSPaul Mackerras /* Get the full OF pathname of the stdout device */ 1341*9b6b563cSPaul Mackerras memset(path, 0, 256); 1342*9b6b563cSPaul Mackerras call_prom("instance-to-path", 3, 1, _prom->stdout, path, 255); 1343*9b6b563cSPaul Mackerras val = call_prom("instance-to-package", 1, 1, _prom->stdout); 1344*9b6b563cSPaul Mackerras prom_setprop(_prom->chosen, "linux,stdout-package", &val, sizeof(val)); 1345*9b6b563cSPaul Mackerras prom_printf("OF stdout device is: %s\n", RELOC(of_stdout_device)); 1346*9b6b563cSPaul Mackerras prom_setprop(_prom->chosen, "linux,stdout-path", 1347*9b6b563cSPaul Mackerras RELOC(of_stdout_device), strlen(RELOC(of_stdout_device))+1); 1348*9b6b563cSPaul Mackerras 1349*9b6b563cSPaul Mackerras /* If it's a display, note it */ 1350*9b6b563cSPaul Mackerras memset(type, 0, sizeof(type)); 1351*9b6b563cSPaul Mackerras prom_getprop(val, "device_type", type, sizeof(type)); 1352*9b6b563cSPaul Mackerras if (strcmp(type, RELOC("display")) == 0) 1353*9b6b563cSPaul Mackerras prom_setprop(val, "linux,boot-display", NULL, 0); 1354*9b6b563cSPaul Mackerras } 1355*9b6b563cSPaul Mackerras 1356*9b6b563cSPaul Mackerras static void __init prom_close_stdin(void) 1357*9b6b563cSPaul Mackerras { 1358*9b6b563cSPaul Mackerras struct prom_t *_prom = &RELOC(prom); 1359*9b6b563cSPaul Mackerras ihandle val; 1360*9b6b563cSPaul Mackerras 1361*9b6b563cSPaul Mackerras if (prom_getprop(_prom->chosen, "stdin", &val, sizeof(val)) > 0) 1362*9b6b563cSPaul Mackerras call_prom("close", 1, 0, val); 1363*9b6b563cSPaul Mackerras } 1364*9b6b563cSPaul Mackerras 1365*9b6b563cSPaul Mackerras static int __init prom_find_machine_type(void) 1366*9b6b563cSPaul Mackerras { 1367*9b6b563cSPaul Mackerras struct prom_t *_prom = &RELOC(prom); 1368*9b6b563cSPaul Mackerras char compat[256]; 1369*9b6b563cSPaul Mackerras int len, i = 0; 1370*9b6b563cSPaul Mackerras phandle rtas; 1371*9b6b563cSPaul Mackerras 1372*9b6b563cSPaul Mackerras len = prom_getprop(_prom->root, "compatible", 1373*9b6b563cSPaul Mackerras compat, sizeof(compat)-1); 1374*9b6b563cSPaul Mackerras if (len > 0) { 1375*9b6b563cSPaul Mackerras compat[len] = 0; 1376*9b6b563cSPaul Mackerras while (i < len) { 1377*9b6b563cSPaul Mackerras char *p = &compat[i]; 1378*9b6b563cSPaul Mackerras int sl = strlen(p); 1379*9b6b563cSPaul Mackerras if (sl == 0) 1380*9b6b563cSPaul Mackerras break; 1381*9b6b563cSPaul Mackerras if (strstr(p, RELOC("Power Macintosh")) || 1382*9b6b563cSPaul Mackerras strstr(p, RELOC("MacRISC4"))) 1383*9b6b563cSPaul Mackerras return PLATFORM_POWERMAC; 1384*9b6b563cSPaul Mackerras #ifdef CONFIG_PPC64 1385*9b6b563cSPaul Mackerras if (strstr(p, RELOC("Momentum,Maple"))) 1386*9b6b563cSPaul Mackerras return PLATFORM_MAPLE; 1387*9b6b563cSPaul Mackerras #endif 1388*9b6b563cSPaul Mackerras i += sl + 1; 1389*9b6b563cSPaul Mackerras } 1390*9b6b563cSPaul Mackerras } 1391*9b6b563cSPaul Mackerras #ifdef CONFIG_PPC64 1392*9b6b563cSPaul Mackerras /* Default to pSeries. We need to know if we are running LPAR */ 1393*9b6b563cSPaul Mackerras rtas = call_prom("finddevice", 1, 1, ADDR("/rtas")); 1394*9b6b563cSPaul Mackerras if (PHANDLE_VALID(rtas)) { 1395*9b6b563cSPaul Mackerras int x = prom_getproplen(rtas, "ibm,hypertas-functions"); 1396*9b6b563cSPaul Mackerras if (x != PROM_ERROR) { 1397*9b6b563cSPaul Mackerras prom_printf("Hypertas detected, assuming LPAR !\n"); 1398*9b6b563cSPaul Mackerras return PLATFORM_PSERIES_LPAR; 1399*9b6b563cSPaul Mackerras } 1400*9b6b563cSPaul Mackerras } 1401*9b6b563cSPaul Mackerras return PLATFORM_PSERIES; 1402*9b6b563cSPaul Mackerras #else 1403*9b6b563cSPaul Mackerras return PLATFORM_CHRP; 1404*9b6b563cSPaul Mackerras #endif 1405*9b6b563cSPaul Mackerras } 1406*9b6b563cSPaul Mackerras 1407*9b6b563cSPaul Mackerras static int __init setup_disp(phandle dp) 1408*9b6b563cSPaul Mackerras { 1409*9b6b563cSPaul Mackerras #if defined(CONFIG_BOOTX_TEXT) && defined(CONFIG_PPC32) 1410*9b6b563cSPaul Mackerras int width = 640, height = 480, depth = 8, pitch; 1411*9b6b563cSPaul Mackerras unsigned address; 1412*9b6b563cSPaul Mackerras u32 addrs[8][5]; 1413*9b6b563cSPaul Mackerras int i, naddrs; 1414*9b6b563cSPaul Mackerras char name[32]; 1415*9b6b563cSPaul Mackerras char *getprop = "getprop"; 1416*9b6b563cSPaul Mackerras 1417*9b6b563cSPaul Mackerras prom_printf("Initializing screen: "); 1418*9b6b563cSPaul Mackerras 1419*9b6b563cSPaul Mackerras memset(name, 0, sizeof(name)); 1420*9b6b563cSPaul Mackerras call_prom(getprop, 4, 1, dp, "name", name, sizeof(name)); 1421*9b6b563cSPaul Mackerras name[sizeof(name)-1] = 0; 1422*9b6b563cSPaul Mackerras prom_print(name); 1423*9b6b563cSPaul Mackerras prom_print("\n"); 1424*9b6b563cSPaul Mackerras call_prom(getprop, 4, 1, dp, "width", &width, sizeof(width)); 1425*9b6b563cSPaul Mackerras call_prom(getprop, 4, 1, dp, "height", &height, sizeof(height)); 1426*9b6b563cSPaul Mackerras call_prom(getprop, 4, 1, dp, "depth", &depth, sizeof(depth)); 1427*9b6b563cSPaul Mackerras pitch = width * ((depth + 7) / 8); 1428*9b6b563cSPaul Mackerras call_prom(getprop, 4, 1, dp, "linebytes", 1429*9b6b563cSPaul Mackerras &pitch, sizeof(pitch)); 1430*9b6b563cSPaul Mackerras if (pitch == 1) 1431*9b6b563cSPaul Mackerras pitch = 0x1000; /* for strange IBM display */ 1432*9b6b563cSPaul Mackerras address = 0; 1433*9b6b563cSPaul Mackerras call_prom(getprop, 4, 1, dp, "address", &address, sizeof(address)); 1434*9b6b563cSPaul Mackerras if (address == 0) { 1435*9b6b563cSPaul Mackerras /* look for an assigned address with a size of >= 1MB */ 1436*9b6b563cSPaul Mackerras naddrs = call_prom(getprop, 4, 1, dp, "assigned-addresses", 1437*9b6b563cSPaul Mackerras addrs, sizeof(addrs)); 1438*9b6b563cSPaul Mackerras naddrs /= 20; 1439*9b6b563cSPaul Mackerras for (i = 0; i < naddrs; ++i) { 1440*9b6b563cSPaul Mackerras if (addrs[i][4] >= (1 << 20)) { 1441*9b6b563cSPaul Mackerras address = addrs[i][2]; 1442*9b6b563cSPaul Mackerras /* use the BE aperture if possible */ 1443*9b6b563cSPaul Mackerras if (addrs[i][4] >= (16 << 20)) 1444*9b6b563cSPaul Mackerras address += (8 << 20); 1445*9b6b563cSPaul Mackerras break; 1446*9b6b563cSPaul Mackerras } 1447*9b6b563cSPaul Mackerras } 1448*9b6b563cSPaul Mackerras if (address == 0) { 1449*9b6b563cSPaul Mackerras prom_print("Failed to get address\n"); 1450*9b6b563cSPaul Mackerras return 0; 1451*9b6b563cSPaul Mackerras } 1452*9b6b563cSPaul Mackerras } 1453*9b6b563cSPaul Mackerras /* kludge for valkyrie */ 1454*9b6b563cSPaul Mackerras if (strcmp(name, "valkyrie") == 0) 1455*9b6b563cSPaul Mackerras address += 0x1000; 1456*9b6b563cSPaul Mackerras 1457*9b6b563cSPaul Mackerras prom_printf("\n\n\n\naddress = %x\n", address); 1458*9b6b563cSPaul Mackerras btext_setup_display(width, height, depth, pitch, address); 1459*9b6b563cSPaul Mackerras #endif /* CONFIG_BOOTX_TEXT && CONFIG_PPC32 */ 1460*9b6b563cSPaul Mackerras return 1; 1461*9b6b563cSPaul Mackerras } 1462*9b6b563cSPaul Mackerras 1463*9b6b563cSPaul Mackerras static int __init prom_set_color(ihandle ih, int i, int r, int g, int b) 1464*9b6b563cSPaul Mackerras { 1465*9b6b563cSPaul Mackerras return call_prom("call-method", 6, 1, ADDR("color!"), ih, i, b, g, r); 1466*9b6b563cSPaul Mackerras } 1467*9b6b563cSPaul Mackerras 1468*9b6b563cSPaul Mackerras /* 1469*9b6b563cSPaul Mackerras * If we have a display that we don't know how to drive, 1470*9b6b563cSPaul Mackerras * we will want to try to execute OF's open method for it 1471*9b6b563cSPaul Mackerras * later. However, OF will probably fall over if we do that 1472*9b6b563cSPaul Mackerras * we've taken over the MMU. 1473*9b6b563cSPaul Mackerras * So we check whether we will need to open the display, 1474*9b6b563cSPaul Mackerras * and if so, open it now. 1475*9b6b563cSPaul Mackerras */ 1476*9b6b563cSPaul Mackerras static void __init prom_check_displays(void) 1477*9b6b563cSPaul Mackerras { 1478*9b6b563cSPaul Mackerras char type[16], *path; 1479*9b6b563cSPaul Mackerras phandle node; 1480*9b6b563cSPaul Mackerras ihandle ih; 1481*9b6b563cSPaul Mackerras int i; 1482*9b6b563cSPaul Mackerras int got_display = 0; 1483*9b6b563cSPaul Mackerras 1484*9b6b563cSPaul Mackerras static unsigned char default_colors[] = { 1485*9b6b563cSPaul Mackerras 0x00, 0x00, 0x00, 1486*9b6b563cSPaul Mackerras 0x00, 0x00, 0xaa, 1487*9b6b563cSPaul Mackerras 0x00, 0xaa, 0x00, 1488*9b6b563cSPaul Mackerras 0x00, 0xaa, 0xaa, 1489*9b6b563cSPaul Mackerras 0xaa, 0x00, 0x00, 1490*9b6b563cSPaul Mackerras 0xaa, 0x00, 0xaa, 1491*9b6b563cSPaul Mackerras 0xaa, 0xaa, 0x00, 1492*9b6b563cSPaul Mackerras 0xaa, 0xaa, 0xaa, 1493*9b6b563cSPaul Mackerras 0x55, 0x55, 0x55, 1494*9b6b563cSPaul Mackerras 0x55, 0x55, 0xff, 1495*9b6b563cSPaul Mackerras 0x55, 0xff, 0x55, 1496*9b6b563cSPaul Mackerras 0x55, 0xff, 0xff, 1497*9b6b563cSPaul Mackerras 0xff, 0x55, 0x55, 1498*9b6b563cSPaul Mackerras 0xff, 0x55, 0xff, 1499*9b6b563cSPaul Mackerras 0xff, 0xff, 0x55, 1500*9b6b563cSPaul Mackerras 0xff, 0xff, 0xff 1501*9b6b563cSPaul Mackerras }; 1502*9b6b563cSPaul Mackerras const unsigned char *clut; 1503*9b6b563cSPaul Mackerras 1504*9b6b563cSPaul Mackerras prom_printf("Looking for displays\n"); 1505*9b6b563cSPaul Mackerras for (node = 0; prom_next_node(&node); ) { 1506*9b6b563cSPaul Mackerras memset(type, 0, sizeof(type)); 1507*9b6b563cSPaul Mackerras prom_getprop(node, "device_type", type, sizeof(type)); 1508*9b6b563cSPaul Mackerras if (strcmp(type, RELOC("display")) != 0) 1509*9b6b563cSPaul Mackerras continue; 1510*9b6b563cSPaul Mackerras 1511*9b6b563cSPaul Mackerras /* It seems OF doesn't null-terminate the path :-( */ 1512*9b6b563cSPaul Mackerras path = RELOC(prom_scratch); 1513*9b6b563cSPaul Mackerras memset(path, 0, PROM_SCRATCH_SIZE); 1514*9b6b563cSPaul Mackerras 1515*9b6b563cSPaul Mackerras /* 1516*9b6b563cSPaul Mackerras * leave some room at the end of the path for appending extra 1517*9b6b563cSPaul Mackerras * arguments 1518*9b6b563cSPaul Mackerras */ 1519*9b6b563cSPaul Mackerras if (call_prom("package-to-path", 3, 1, node, path, 1520*9b6b563cSPaul Mackerras PROM_SCRATCH_SIZE-10) == PROM_ERROR) 1521*9b6b563cSPaul Mackerras continue; 1522*9b6b563cSPaul Mackerras prom_printf("found display : %s, opening ... ", path); 1523*9b6b563cSPaul Mackerras 1524*9b6b563cSPaul Mackerras ih = call_prom("open", 1, 1, path); 1525*9b6b563cSPaul Mackerras if (ih == 0) { 1526*9b6b563cSPaul Mackerras prom_printf("failed\n"); 1527*9b6b563cSPaul Mackerras continue; 1528*9b6b563cSPaul Mackerras } 1529*9b6b563cSPaul Mackerras 1530*9b6b563cSPaul Mackerras /* Success */ 1531*9b6b563cSPaul Mackerras prom_printf("done\n"); 1532*9b6b563cSPaul Mackerras prom_setprop(node, "linux,opened", NULL, 0); 1533*9b6b563cSPaul Mackerras 1534*9b6b563cSPaul Mackerras /* Setup a usable color table when the appropriate 1535*9b6b563cSPaul Mackerras * method is available. Should update this to set-colors */ 1536*9b6b563cSPaul Mackerras clut = RELOC(default_colors); 1537*9b6b563cSPaul Mackerras for (i = 0; i < 32; i++, clut += 3) 1538*9b6b563cSPaul Mackerras if (prom_set_color(ih, i, clut[0], clut[1], 1539*9b6b563cSPaul Mackerras clut[2]) != 0) 1540*9b6b563cSPaul Mackerras break; 1541*9b6b563cSPaul Mackerras 1542*9b6b563cSPaul Mackerras #ifdef CONFIG_LOGO_LINUX_CLUT224 1543*9b6b563cSPaul Mackerras clut = PTRRELOC(RELOC(logo_linux_clut224.clut)); 1544*9b6b563cSPaul Mackerras for (i = 0; i < RELOC(logo_linux_clut224.clutsize); i++, clut += 3) 1545*9b6b563cSPaul Mackerras if (prom_set_color(ih, i + 32, clut[0], clut[1], 1546*9b6b563cSPaul Mackerras clut[2]) != 0) 1547*9b6b563cSPaul Mackerras break; 1548*9b6b563cSPaul Mackerras #endif /* CONFIG_LOGO_LINUX_CLUT224 */ 1549*9b6b563cSPaul Mackerras if (!got_display) 1550*9b6b563cSPaul Mackerras got_display = setup_disp(node); 1551*9b6b563cSPaul Mackerras } 1552*9b6b563cSPaul Mackerras } 1553*9b6b563cSPaul Mackerras 1554*9b6b563cSPaul Mackerras 1555*9b6b563cSPaul Mackerras /* Return (relocated) pointer to this much memory: moves initrd if reqd. */ 1556*9b6b563cSPaul Mackerras static void __init *make_room(unsigned long *mem_start, unsigned long *mem_end, 1557*9b6b563cSPaul Mackerras unsigned long needed, unsigned long align) 1558*9b6b563cSPaul Mackerras { 1559*9b6b563cSPaul Mackerras void *ret; 1560*9b6b563cSPaul Mackerras 1561*9b6b563cSPaul Mackerras *mem_start = _ALIGN(*mem_start, align); 1562*9b6b563cSPaul Mackerras while ((*mem_start + needed) > *mem_end) { 1563*9b6b563cSPaul Mackerras unsigned long room, chunk; 1564*9b6b563cSPaul Mackerras 1565*9b6b563cSPaul Mackerras prom_debug("Chunk exhausted, claiming more at %x...\n", 1566*9b6b563cSPaul Mackerras RELOC(alloc_bottom)); 1567*9b6b563cSPaul Mackerras room = RELOC(alloc_top) - RELOC(alloc_bottom); 1568*9b6b563cSPaul Mackerras if (room > DEVTREE_CHUNK_SIZE) 1569*9b6b563cSPaul Mackerras room = DEVTREE_CHUNK_SIZE; 1570*9b6b563cSPaul Mackerras if (room < PAGE_SIZE) 1571*9b6b563cSPaul Mackerras prom_panic("No memory for flatten_device_tree (no room)"); 1572*9b6b563cSPaul Mackerras chunk = alloc_up(room, 0); 1573*9b6b563cSPaul Mackerras if (chunk == 0) 1574*9b6b563cSPaul Mackerras prom_panic("No memory for flatten_device_tree (claim failed)"); 1575*9b6b563cSPaul Mackerras *mem_end = RELOC(alloc_top); 1576*9b6b563cSPaul Mackerras } 1577*9b6b563cSPaul Mackerras 1578*9b6b563cSPaul Mackerras ret = (void *)*mem_start; 1579*9b6b563cSPaul Mackerras *mem_start += needed; 1580*9b6b563cSPaul Mackerras 1581*9b6b563cSPaul Mackerras return ret; 1582*9b6b563cSPaul Mackerras } 1583*9b6b563cSPaul Mackerras 1584*9b6b563cSPaul Mackerras #define dt_push_token(token, mem_start, mem_end) \ 1585*9b6b563cSPaul Mackerras do { *((u32 *)make_room(mem_start, mem_end, 4, 4)) = token; } while(0) 1586*9b6b563cSPaul Mackerras 1587*9b6b563cSPaul Mackerras static unsigned long __init dt_find_string(char *str) 1588*9b6b563cSPaul Mackerras { 1589*9b6b563cSPaul Mackerras char *s, *os; 1590*9b6b563cSPaul Mackerras 1591*9b6b563cSPaul Mackerras s = os = (char *)RELOC(dt_string_start); 1592*9b6b563cSPaul Mackerras s += 4; 1593*9b6b563cSPaul Mackerras while (s < (char *)RELOC(dt_string_end)) { 1594*9b6b563cSPaul Mackerras if (strcmp(s, str) == 0) 1595*9b6b563cSPaul Mackerras return s - os; 1596*9b6b563cSPaul Mackerras s += strlen(s) + 1; 1597*9b6b563cSPaul Mackerras } 1598*9b6b563cSPaul Mackerras return 0; 1599*9b6b563cSPaul Mackerras } 1600*9b6b563cSPaul Mackerras 1601*9b6b563cSPaul Mackerras /* 1602*9b6b563cSPaul Mackerras * The Open Firmware 1275 specification states properties must be 31 bytes or 1603*9b6b563cSPaul Mackerras * less, however not all firmwares obey this. Make it 64 bytes to be safe. 1604*9b6b563cSPaul Mackerras */ 1605*9b6b563cSPaul Mackerras #define MAX_PROPERTY_NAME 64 1606*9b6b563cSPaul Mackerras 1607*9b6b563cSPaul Mackerras static void __init scan_dt_build_strings(phandle node, 1608*9b6b563cSPaul Mackerras unsigned long *mem_start, 1609*9b6b563cSPaul Mackerras unsigned long *mem_end) 1610*9b6b563cSPaul Mackerras { 1611*9b6b563cSPaul Mackerras char *prev_name, *namep, *sstart; 1612*9b6b563cSPaul Mackerras unsigned long soff; 1613*9b6b563cSPaul Mackerras phandle child; 1614*9b6b563cSPaul Mackerras 1615*9b6b563cSPaul Mackerras sstart = (char *)RELOC(dt_string_start); 1616*9b6b563cSPaul Mackerras 1617*9b6b563cSPaul Mackerras /* get and store all property names */ 1618*9b6b563cSPaul Mackerras prev_name = RELOC(""); 1619*9b6b563cSPaul Mackerras for (;;) { 1620*9b6b563cSPaul Mackerras /* 64 is max len of name including nul. */ 1621*9b6b563cSPaul Mackerras namep = make_room(mem_start, mem_end, MAX_PROPERTY_NAME, 1); 1622*9b6b563cSPaul Mackerras if (call_prom("nextprop", 3, 1, node, prev_name, namep) != 1) { 1623*9b6b563cSPaul Mackerras /* No more nodes: unwind alloc */ 1624*9b6b563cSPaul Mackerras *mem_start = (unsigned long)namep; 1625*9b6b563cSPaul Mackerras break; 1626*9b6b563cSPaul Mackerras } 1627*9b6b563cSPaul Mackerras 1628*9b6b563cSPaul Mackerras /* skip "name" */ 1629*9b6b563cSPaul Mackerras if (strcmp(namep, RELOC("name")) == 0) { 1630*9b6b563cSPaul Mackerras *mem_start = (unsigned long)namep; 1631*9b6b563cSPaul Mackerras prev_name = RELOC("name"); 1632*9b6b563cSPaul Mackerras continue; 1633*9b6b563cSPaul Mackerras } 1634*9b6b563cSPaul Mackerras /* get/create string entry */ 1635*9b6b563cSPaul Mackerras soff = dt_find_string(namep); 1636*9b6b563cSPaul Mackerras if (soff != 0) { 1637*9b6b563cSPaul Mackerras *mem_start = (unsigned long)namep; 1638*9b6b563cSPaul Mackerras namep = sstart + soff; 1639*9b6b563cSPaul Mackerras } else { 1640*9b6b563cSPaul Mackerras /* Trim off some if we can */ 1641*9b6b563cSPaul Mackerras *mem_start = (unsigned long)namep + strlen(namep) + 1; 1642*9b6b563cSPaul Mackerras RELOC(dt_string_end) = *mem_start; 1643*9b6b563cSPaul Mackerras } 1644*9b6b563cSPaul Mackerras prev_name = namep; 1645*9b6b563cSPaul Mackerras } 1646*9b6b563cSPaul Mackerras 1647*9b6b563cSPaul Mackerras /* do all our children */ 1648*9b6b563cSPaul Mackerras child = call_prom("child", 1, 1, node); 1649*9b6b563cSPaul Mackerras while (child != 0) { 1650*9b6b563cSPaul Mackerras scan_dt_build_strings(child, mem_start, mem_end); 1651*9b6b563cSPaul Mackerras child = call_prom("peer", 1, 1, child); 1652*9b6b563cSPaul Mackerras } 1653*9b6b563cSPaul Mackerras } 1654*9b6b563cSPaul Mackerras 1655*9b6b563cSPaul Mackerras static void __init scan_dt_build_struct(phandle node, unsigned long *mem_start, 1656*9b6b563cSPaul Mackerras unsigned long *mem_end) 1657*9b6b563cSPaul Mackerras { 1658*9b6b563cSPaul Mackerras phandle child; 1659*9b6b563cSPaul Mackerras char *namep, *prev_name, *sstart, *p, *ep, *lp, *path; 1660*9b6b563cSPaul Mackerras unsigned long soff; 1661*9b6b563cSPaul Mackerras unsigned char *valp; 1662*9b6b563cSPaul Mackerras static char pname[MAX_PROPERTY_NAME]; 1663*9b6b563cSPaul Mackerras int l; 1664*9b6b563cSPaul Mackerras 1665*9b6b563cSPaul Mackerras dt_push_token(OF_DT_BEGIN_NODE, mem_start, mem_end); 1666*9b6b563cSPaul Mackerras 1667*9b6b563cSPaul Mackerras /* get the node's full name */ 1668*9b6b563cSPaul Mackerras namep = (char *)*mem_start; 1669*9b6b563cSPaul Mackerras l = call_prom("package-to-path", 3, 1, node, 1670*9b6b563cSPaul Mackerras namep, *mem_end - *mem_start); 1671*9b6b563cSPaul Mackerras if (l >= 0) { 1672*9b6b563cSPaul Mackerras /* Didn't fit? Get more room. */ 1673*9b6b563cSPaul Mackerras if ((l+1) > (*mem_end - *mem_start)) { 1674*9b6b563cSPaul Mackerras namep = make_room(mem_start, mem_end, l+1, 1); 1675*9b6b563cSPaul Mackerras call_prom("package-to-path", 3, 1, node, namep, l); 1676*9b6b563cSPaul Mackerras } 1677*9b6b563cSPaul Mackerras namep[l] = '\0'; 1678*9b6b563cSPaul Mackerras 1679*9b6b563cSPaul Mackerras /* Fixup an Apple bug where they have bogus \0 chars in the 1680*9b6b563cSPaul Mackerras * middle of the path in some properties 1681*9b6b563cSPaul Mackerras */ 1682*9b6b563cSPaul Mackerras for (p = namep, ep = namep + l; p < ep; p++) 1683*9b6b563cSPaul Mackerras if (*p == '\0') { 1684*9b6b563cSPaul Mackerras memmove(p, p+1, ep - p); 1685*9b6b563cSPaul Mackerras ep--; l--; p--; 1686*9b6b563cSPaul Mackerras } 1687*9b6b563cSPaul Mackerras 1688*9b6b563cSPaul Mackerras /* now try to extract the unit name in that mess */ 1689*9b6b563cSPaul Mackerras for (p = namep, lp = NULL; *p; p++) 1690*9b6b563cSPaul Mackerras if (*p == '/') 1691*9b6b563cSPaul Mackerras lp = p + 1; 1692*9b6b563cSPaul Mackerras if (lp != NULL) 1693*9b6b563cSPaul Mackerras memmove(namep, lp, strlen(lp) + 1); 1694*9b6b563cSPaul Mackerras *mem_start = _ALIGN(((unsigned long) namep) + 1695*9b6b563cSPaul Mackerras strlen(namep) + 1, 4); 1696*9b6b563cSPaul Mackerras } 1697*9b6b563cSPaul Mackerras 1698*9b6b563cSPaul Mackerras /* get it again for debugging */ 1699*9b6b563cSPaul Mackerras path = RELOC(prom_scratch); 1700*9b6b563cSPaul Mackerras memset(path, 0, PROM_SCRATCH_SIZE); 1701*9b6b563cSPaul Mackerras call_prom("package-to-path", 3, 1, node, path, PROM_SCRATCH_SIZE-1); 1702*9b6b563cSPaul Mackerras 1703*9b6b563cSPaul Mackerras /* get and store all properties */ 1704*9b6b563cSPaul Mackerras prev_name = RELOC(""); 1705*9b6b563cSPaul Mackerras sstart = (char *)RELOC(dt_string_start); 1706*9b6b563cSPaul Mackerras for (;;) { 1707*9b6b563cSPaul Mackerras if (call_prom("nextprop", 3, 1, node, prev_name, 1708*9b6b563cSPaul Mackerras RELOC(pname)) != 1) 1709*9b6b563cSPaul Mackerras break; 1710*9b6b563cSPaul Mackerras 1711*9b6b563cSPaul Mackerras /* skip "name" */ 1712*9b6b563cSPaul Mackerras if (strcmp(RELOC(pname), RELOC("name")) == 0) { 1713*9b6b563cSPaul Mackerras prev_name = RELOC("name"); 1714*9b6b563cSPaul Mackerras continue; 1715*9b6b563cSPaul Mackerras } 1716*9b6b563cSPaul Mackerras 1717*9b6b563cSPaul Mackerras /* find string offset */ 1718*9b6b563cSPaul Mackerras soff = dt_find_string(RELOC(pname)); 1719*9b6b563cSPaul Mackerras if (soff == 0) { 1720*9b6b563cSPaul Mackerras prom_printf("WARNING: Can't find string index for" 1721*9b6b563cSPaul Mackerras " <%s>, node %s\n", RELOC(pname), path); 1722*9b6b563cSPaul Mackerras break; 1723*9b6b563cSPaul Mackerras } 1724*9b6b563cSPaul Mackerras prev_name = sstart + soff; 1725*9b6b563cSPaul Mackerras 1726*9b6b563cSPaul Mackerras /* get length */ 1727*9b6b563cSPaul Mackerras l = call_prom("getproplen", 2, 1, node, RELOC(pname)); 1728*9b6b563cSPaul Mackerras 1729*9b6b563cSPaul Mackerras /* sanity checks */ 1730*9b6b563cSPaul Mackerras if (l == PROM_ERROR) 1731*9b6b563cSPaul Mackerras continue; 1732*9b6b563cSPaul Mackerras if (l > MAX_PROPERTY_LENGTH) { 1733*9b6b563cSPaul Mackerras prom_printf("WARNING: ignoring large property "); 1734*9b6b563cSPaul Mackerras /* It seems OF doesn't null-terminate the path :-( */ 1735*9b6b563cSPaul Mackerras prom_printf("[%s] ", path); 1736*9b6b563cSPaul Mackerras prom_printf("%s length 0x%x\n", RELOC(pname), l); 1737*9b6b563cSPaul Mackerras continue; 1738*9b6b563cSPaul Mackerras } 1739*9b6b563cSPaul Mackerras 1740*9b6b563cSPaul Mackerras /* push property head */ 1741*9b6b563cSPaul Mackerras dt_push_token(OF_DT_PROP, mem_start, mem_end); 1742*9b6b563cSPaul Mackerras dt_push_token(l, mem_start, mem_end); 1743*9b6b563cSPaul Mackerras dt_push_token(soff, mem_start, mem_end); 1744*9b6b563cSPaul Mackerras 1745*9b6b563cSPaul Mackerras /* push property content */ 1746*9b6b563cSPaul Mackerras valp = make_room(mem_start, mem_end, l, 4); 1747*9b6b563cSPaul Mackerras call_prom("getprop", 4, 1, node, RELOC(pname), valp, l); 1748*9b6b563cSPaul Mackerras *mem_start = _ALIGN(*mem_start, 4); 1749*9b6b563cSPaul Mackerras } 1750*9b6b563cSPaul Mackerras 1751*9b6b563cSPaul Mackerras /* Add a "linux,phandle" property. */ 1752*9b6b563cSPaul Mackerras soff = dt_find_string(RELOC("linux,phandle")); 1753*9b6b563cSPaul Mackerras if (soff == 0) 1754*9b6b563cSPaul Mackerras prom_printf("WARNING: Can't find string index for" 1755*9b6b563cSPaul Mackerras " <linux-phandle> node %s\n", path); 1756*9b6b563cSPaul Mackerras else { 1757*9b6b563cSPaul Mackerras dt_push_token(OF_DT_PROP, mem_start, mem_end); 1758*9b6b563cSPaul Mackerras dt_push_token(4, mem_start, mem_end); 1759*9b6b563cSPaul Mackerras dt_push_token(soff, mem_start, mem_end); 1760*9b6b563cSPaul Mackerras valp = make_room(mem_start, mem_end, 4, 4); 1761*9b6b563cSPaul Mackerras *(u32 *)valp = node; 1762*9b6b563cSPaul Mackerras } 1763*9b6b563cSPaul Mackerras 1764*9b6b563cSPaul Mackerras /* do all our children */ 1765*9b6b563cSPaul Mackerras child = call_prom("child", 1, 1, node); 1766*9b6b563cSPaul Mackerras while (child != 0) { 1767*9b6b563cSPaul Mackerras scan_dt_build_struct(child, mem_start, mem_end); 1768*9b6b563cSPaul Mackerras child = call_prom("peer", 1, 1, child); 1769*9b6b563cSPaul Mackerras } 1770*9b6b563cSPaul Mackerras 1771*9b6b563cSPaul Mackerras dt_push_token(OF_DT_END_NODE, mem_start, mem_end); 1772*9b6b563cSPaul Mackerras } 1773*9b6b563cSPaul Mackerras 1774*9b6b563cSPaul Mackerras static void __init flatten_device_tree(void) 1775*9b6b563cSPaul Mackerras { 1776*9b6b563cSPaul Mackerras phandle root; 1777*9b6b563cSPaul Mackerras unsigned long mem_start, mem_end, room; 1778*9b6b563cSPaul Mackerras struct boot_param_header *hdr; 1779*9b6b563cSPaul Mackerras struct prom_t *_prom = &RELOC(prom); 1780*9b6b563cSPaul Mackerras char *namep; 1781*9b6b563cSPaul Mackerras u64 *rsvmap; 1782*9b6b563cSPaul Mackerras 1783*9b6b563cSPaul Mackerras /* 1784*9b6b563cSPaul Mackerras * Check how much room we have between alloc top & bottom (+/- a 1785*9b6b563cSPaul Mackerras * few pages), crop to 4Mb, as this is our "chuck" size 1786*9b6b563cSPaul Mackerras */ 1787*9b6b563cSPaul Mackerras room = RELOC(alloc_top) - RELOC(alloc_bottom) - 0x4000; 1788*9b6b563cSPaul Mackerras if (room > DEVTREE_CHUNK_SIZE) 1789*9b6b563cSPaul Mackerras room = DEVTREE_CHUNK_SIZE; 1790*9b6b563cSPaul Mackerras prom_debug("starting device tree allocs at %x\n", RELOC(alloc_bottom)); 1791*9b6b563cSPaul Mackerras 1792*9b6b563cSPaul Mackerras /* Now try to claim that */ 1793*9b6b563cSPaul Mackerras mem_start = (unsigned long)alloc_up(room, PAGE_SIZE); 1794*9b6b563cSPaul Mackerras if (mem_start == 0) 1795*9b6b563cSPaul Mackerras prom_panic("Can't allocate initial device-tree chunk\n"); 1796*9b6b563cSPaul Mackerras mem_end = RELOC(alloc_top); 1797*9b6b563cSPaul Mackerras 1798*9b6b563cSPaul Mackerras /* Get root of tree */ 1799*9b6b563cSPaul Mackerras root = call_prom("peer", 1, 1, (phandle)0); 1800*9b6b563cSPaul Mackerras if (root == (phandle)0) 1801*9b6b563cSPaul Mackerras prom_panic ("couldn't get device tree root\n"); 1802*9b6b563cSPaul Mackerras 1803*9b6b563cSPaul Mackerras /* Build header and make room for mem rsv map */ 1804*9b6b563cSPaul Mackerras mem_start = _ALIGN(mem_start, 4); 1805*9b6b563cSPaul Mackerras hdr = make_room(&mem_start, &mem_end, 1806*9b6b563cSPaul Mackerras sizeof(struct boot_param_header), 4); 1807*9b6b563cSPaul Mackerras RELOC(dt_header_start) = (unsigned long)hdr; 1808*9b6b563cSPaul Mackerras rsvmap = make_room(&mem_start, &mem_end, sizeof(mem_reserve_map), 8); 1809*9b6b563cSPaul Mackerras 1810*9b6b563cSPaul Mackerras /* Start of strings */ 1811*9b6b563cSPaul Mackerras mem_start = PAGE_ALIGN(mem_start); 1812*9b6b563cSPaul Mackerras RELOC(dt_string_start) = mem_start; 1813*9b6b563cSPaul Mackerras mem_start += 4; /* hole */ 1814*9b6b563cSPaul Mackerras 1815*9b6b563cSPaul Mackerras /* Add "linux,phandle" in there, we'll need it */ 1816*9b6b563cSPaul Mackerras namep = make_room(&mem_start, &mem_end, 16, 1); 1817*9b6b563cSPaul Mackerras strcpy(namep, RELOC("linux,phandle")); 1818*9b6b563cSPaul Mackerras mem_start = (unsigned long)namep + strlen(namep) + 1; 1819*9b6b563cSPaul Mackerras 1820*9b6b563cSPaul Mackerras /* Build string array */ 1821*9b6b563cSPaul Mackerras prom_printf("Building dt strings...\n"); 1822*9b6b563cSPaul Mackerras scan_dt_build_strings(root, &mem_start, &mem_end); 1823*9b6b563cSPaul Mackerras RELOC(dt_string_end) = mem_start; 1824*9b6b563cSPaul Mackerras 1825*9b6b563cSPaul Mackerras /* Build structure */ 1826*9b6b563cSPaul Mackerras mem_start = PAGE_ALIGN(mem_start); 1827*9b6b563cSPaul Mackerras RELOC(dt_struct_start) = mem_start; 1828*9b6b563cSPaul Mackerras prom_printf("Building dt structure...\n"); 1829*9b6b563cSPaul Mackerras scan_dt_build_struct(root, &mem_start, &mem_end); 1830*9b6b563cSPaul Mackerras dt_push_token(OF_DT_END, &mem_start, &mem_end); 1831*9b6b563cSPaul Mackerras RELOC(dt_struct_end) = PAGE_ALIGN(mem_start); 1832*9b6b563cSPaul Mackerras 1833*9b6b563cSPaul Mackerras /* Finish header */ 1834*9b6b563cSPaul Mackerras hdr->boot_cpuid_phys = _prom->cpu; 1835*9b6b563cSPaul Mackerras hdr->magic = OF_DT_HEADER; 1836*9b6b563cSPaul Mackerras hdr->totalsize = RELOC(dt_struct_end) - RELOC(dt_header_start); 1837*9b6b563cSPaul Mackerras hdr->off_dt_struct = RELOC(dt_struct_start) - RELOC(dt_header_start); 1838*9b6b563cSPaul Mackerras hdr->off_dt_strings = RELOC(dt_string_start) - RELOC(dt_header_start); 1839*9b6b563cSPaul Mackerras hdr->dt_strings_size = RELOC(dt_string_end) - RELOC(dt_string_start); 1840*9b6b563cSPaul Mackerras hdr->off_mem_rsvmap = ((unsigned long)rsvmap) - RELOC(dt_header_start); 1841*9b6b563cSPaul Mackerras hdr->version = OF_DT_VERSION; 1842*9b6b563cSPaul Mackerras /* Version 16 is not backward compatible */ 1843*9b6b563cSPaul Mackerras hdr->last_comp_version = 0x10; 1844*9b6b563cSPaul Mackerras 1845*9b6b563cSPaul Mackerras /* Reserve the whole thing and copy the reserve map in, we 1846*9b6b563cSPaul Mackerras * also bump mem_reserve_cnt to cause further reservations to 1847*9b6b563cSPaul Mackerras * fail since it's too late. 1848*9b6b563cSPaul Mackerras */ 1849*9b6b563cSPaul Mackerras reserve_mem(RELOC(dt_header_start), hdr->totalsize); 1850*9b6b563cSPaul Mackerras memcpy(rsvmap, RELOC(mem_reserve_map), sizeof(mem_reserve_map)); 1851*9b6b563cSPaul Mackerras 1852*9b6b563cSPaul Mackerras #ifdef DEBUG_PROM 1853*9b6b563cSPaul Mackerras { 1854*9b6b563cSPaul Mackerras int i; 1855*9b6b563cSPaul Mackerras prom_printf("reserved memory map:\n"); 1856*9b6b563cSPaul Mackerras for (i = 0; i < RELOC(mem_reserve_cnt); i++) 1857*9b6b563cSPaul Mackerras prom_printf(" %x - %x\n", 1858*9b6b563cSPaul Mackerras RELOC(mem_reserve_map)[i].base, 1859*9b6b563cSPaul Mackerras RELOC(mem_reserve_map)[i].size); 1860*9b6b563cSPaul Mackerras } 1861*9b6b563cSPaul Mackerras #endif 1862*9b6b563cSPaul Mackerras RELOC(mem_reserve_cnt) = MEM_RESERVE_MAP_SIZE; 1863*9b6b563cSPaul Mackerras 1864*9b6b563cSPaul Mackerras prom_printf("Device tree strings 0x%x -> 0x%x\n", 1865*9b6b563cSPaul Mackerras RELOC(dt_string_start), RELOC(dt_string_end)); 1866*9b6b563cSPaul Mackerras prom_printf("Device tree struct 0x%x -> 0x%x\n", 1867*9b6b563cSPaul Mackerras RELOC(dt_struct_start), RELOC(dt_struct_end)); 1868*9b6b563cSPaul Mackerras 1869*9b6b563cSPaul Mackerras } 1870*9b6b563cSPaul Mackerras 1871*9b6b563cSPaul Mackerras 1872*9b6b563cSPaul Mackerras static void __init fixup_device_tree(void) 1873*9b6b563cSPaul Mackerras { 1874*9b6b563cSPaul Mackerras #if defined(CONFIG_PPC64) && defined(CONFIG_PPC_PMAC) 1875*9b6b563cSPaul Mackerras phandle u3, i2c, mpic; 1876*9b6b563cSPaul Mackerras u32 u3_rev; 1877*9b6b563cSPaul Mackerras u32 interrupts[2]; 1878*9b6b563cSPaul Mackerras u32 parent; 1879*9b6b563cSPaul Mackerras 1880*9b6b563cSPaul Mackerras /* Some G5s have a missing interrupt definition, fix it up here */ 1881*9b6b563cSPaul Mackerras u3 = call_prom("finddevice", 1, 1, ADDR("/u3@0,f8000000")); 1882*9b6b563cSPaul Mackerras if (!PHANDLE_VALID(u3)) 1883*9b6b563cSPaul Mackerras return; 1884*9b6b563cSPaul Mackerras i2c = call_prom("finddevice", 1, 1, ADDR("/u3@0,f8000000/i2c@f8001000")); 1885*9b6b563cSPaul Mackerras if (!PHANDLE_VALID(i2c)) 1886*9b6b563cSPaul Mackerras return; 1887*9b6b563cSPaul Mackerras mpic = call_prom("finddevice", 1, 1, ADDR("/u3@0,f8000000/mpic@f8040000")); 1888*9b6b563cSPaul Mackerras if (!PHANDLE_VALID(mpic)) 1889*9b6b563cSPaul Mackerras return; 1890*9b6b563cSPaul Mackerras 1891*9b6b563cSPaul Mackerras /* check if proper rev of u3 */ 1892*9b6b563cSPaul Mackerras if (prom_getprop(u3, "device-rev", &u3_rev, sizeof(u3_rev)) 1893*9b6b563cSPaul Mackerras == PROM_ERROR) 1894*9b6b563cSPaul Mackerras return; 1895*9b6b563cSPaul Mackerras if (u3_rev != 0x35 && u3_rev != 0x37) 1896*9b6b563cSPaul Mackerras return; 1897*9b6b563cSPaul Mackerras /* does it need fixup ? */ 1898*9b6b563cSPaul Mackerras if (prom_getproplen(i2c, "interrupts") > 0) 1899*9b6b563cSPaul Mackerras return; 1900*9b6b563cSPaul Mackerras 1901*9b6b563cSPaul Mackerras prom_printf("fixing up bogus interrupts for u3 i2c...\n"); 1902*9b6b563cSPaul Mackerras 1903*9b6b563cSPaul Mackerras /* interrupt on this revision of u3 is number 0 and level */ 1904*9b6b563cSPaul Mackerras interrupts[0] = 0; 1905*9b6b563cSPaul Mackerras interrupts[1] = 1; 1906*9b6b563cSPaul Mackerras prom_setprop(i2c, "interrupts", &interrupts, sizeof(interrupts)); 1907*9b6b563cSPaul Mackerras parent = (u32)mpic; 1908*9b6b563cSPaul Mackerras prom_setprop(i2c, "interrupt-parent", &parent, sizeof(parent)); 1909*9b6b563cSPaul Mackerras #endif 1910*9b6b563cSPaul Mackerras } 1911*9b6b563cSPaul Mackerras 1912*9b6b563cSPaul Mackerras 1913*9b6b563cSPaul Mackerras static void __init prom_find_boot_cpu(void) 1914*9b6b563cSPaul Mackerras { 1915*9b6b563cSPaul Mackerras struct prom_t *_prom = &RELOC(prom); 1916*9b6b563cSPaul Mackerras u32 getprop_rval; 1917*9b6b563cSPaul Mackerras ihandle prom_cpu; 1918*9b6b563cSPaul Mackerras phandle cpu_pkg; 1919*9b6b563cSPaul Mackerras 1920*9b6b563cSPaul Mackerras if (prom_getprop(_prom->chosen, "cpu", &prom_cpu, sizeof(prom_cpu)) <= 0) 1921*9b6b563cSPaul Mackerras prom_panic("cannot find boot cpu"); 1922*9b6b563cSPaul Mackerras 1923*9b6b563cSPaul Mackerras cpu_pkg = call_prom("instance-to-package", 1, 1, prom_cpu); 1924*9b6b563cSPaul Mackerras 1925*9b6b563cSPaul Mackerras prom_getprop(cpu_pkg, "reg", &getprop_rval, sizeof(getprop_rval)); 1926*9b6b563cSPaul Mackerras _prom->cpu = getprop_rval; 1927*9b6b563cSPaul Mackerras 1928*9b6b563cSPaul Mackerras prom_debug("Booting CPU hw index = 0x%x\n", _prom->cpu); 1929*9b6b563cSPaul Mackerras } 1930*9b6b563cSPaul Mackerras 1931*9b6b563cSPaul Mackerras static void __init prom_check_initrd(unsigned long r3, unsigned long r4) 1932*9b6b563cSPaul Mackerras { 1933*9b6b563cSPaul Mackerras #ifdef CONFIG_BLK_DEV_INITRD 1934*9b6b563cSPaul Mackerras struct prom_t *_prom = &RELOC(prom); 1935*9b6b563cSPaul Mackerras 1936*9b6b563cSPaul Mackerras if (r3 && r4 && r4 != 0xdeadbeef) { 1937*9b6b563cSPaul Mackerras unsigned long val; 1938*9b6b563cSPaul Mackerras 1939*9b6b563cSPaul Mackerras RELOC(prom_initrd_start) = (r3 >= KERNELBASE) ? __pa(r3) : r3; 1940*9b6b563cSPaul Mackerras RELOC(prom_initrd_end) = RELOC(prom_initrd_start) + r4; 1941*9b6b563cSPaul Mackerras 1942*9b6b563cSPaul Mackerras val = RELOC(prom_initrd_start); 1943*9b6b563cSPaul Mackerras prom_setprop(_prom->chosen, "linux,initrd-start", &val, 1944*9b6b563cSPaul Mackerras sizeof(val)); 1945*9b6b563cSPaul Mackerras val = RELOC(prom_initrd_end); 1946*9b6b563cSPaul Mackerras prom_setprop(_prom->chosen, "linux,initrd-end", &val, 1947*9b6b563cSPaul Mackerras sizeof(val)); 1948*9b6b563cSPaul Mackerras 1949*9b6b563cSPaul Mackerras reserve_mem(RELOC(prom_initrd_start), 1950*9b6b563cSPaul Mackerras RELOC(prom_initrd_end) - RELOC(prom_initrd_start)); 1951*9b6b563cSPaul Mackerras 1952*9b6b563cSPaul Mackerras prom_debug("initrd_start=0x%x\n", RELOC(prom_initrd_start)); 1953*9b6b563cSPaul Mackerras prom_debug("initrd_end=0x%x\n", RELOC(prom_initrd_end)); 1954*9b6b563cSPaul Mackerras } 1955*9b6b563cSPaul Mackerras #endif /* CONFIG_BLK_DEV_INITRD */ 1956*9b6b563cSPaul Mackerras } 1957*9b6b563cSPaul Mackerras 1958*9b6b563cSPaul Mackerras /* 1959*9b6b563cSPaul Mackerras * We enter here early on, when the Open Firmware prom is still 1960*9b6b563cSPaul Mackerras * handling exceptions and the MMU hash table for us. 1961*9b6b563cSPaul Mackerras */ 1962*9b6b563cSPaul Mackerras 1963*9b6b563cSPaul Mackerras unsigned long __init prom_init(unsigned long r3, unsigned long r4, 1964*9b6b563cSPaul Mackerras unsigned long pp, 1965*9b6b563cSPaul Mackerras unsigned long r6, unsigned long r7) 1966*9b6b563cSPaul Mackerras { 1967*9b6b563cSPaul Mackerras struct prom_t *_prom; 1968*9b6b563cSPaul Mackerras extern char _stext[]; 1969*9b6b563cSPaul Mackerras unsigned long hdr; 1970*9b6b563cSPaul Mackerras u32 getprop_rval; 1971*9b6b563cSPaul Mackerras 1972*9b6b563cSPaul Mackerras #ifdef CONFIG_PPC32 1973*9b6b563cSPaul Mackerras unsigned long offset = reloc_offset(); 1974*9b6b563cSPaul Mackerras reloc_got2(offset); 1975*9b6b563cSPaul Mackerras #endif 1976*9b6b563cSPaul Mackerras 1977*9b6b563cSPaul Mackerras _prom = &RELOC(prom); 1978*9b6b563cSPaul Mackerras 1979*9b6b563cSPaul Mackerras /* 1980*9b6b563cSPaul Mackerras * First zero the BSS 1981*9b6b563cSPaul Mackerras */ 1982*9b6b563cSPaul Mackerras memset(&RELOC(__bss_start), 0, __bss_stop - __bss_start); 1983*9b6b563cSPaul Mackerras 1984*9b6b563cSPaul Mackerras /* 1985*9b6b563cSPaul Mackerras * Init interface to Open Firmware, get some node references, 1986*9b6b563cSPaul Mackerras * like /chosen 1987*9b6b563cSPaul Mackerras */ 1988*9b6b563cSPaul Mackerras prom_init_client_services(pp); 1989*9b6b563cSPaul Mackerras 1990*9b6b563cSPaul Mackerras /* 1991*9b6b563cSPaul Mackerras * Init prom stdout device 1992*9b6b563cSPaul Mackerras */ 1993*9b6b563cSPaul Mackerras prom_init_stdout(); 1994*9b6b563cSPaul Mackerras 1995*9b6b563cSPaul Mackerras /* 1996*9b6b563cSPaul Mackerras * Check for an initrd 1997*9b6b563cSPaul Mackerras */ 1998*9b6b563cSPaul Mackerras prom_check_initrd(r3, r4); 1999*9b6b563cSPaul Mackerras 2000*9b6b563cSPaul Mackerras /* 2001*9b6b563cSPaul Mackerras * Get default machine type. At this point, we do not differentiate 2002*9b6b563cSPaul Mackerras * between pSeries SMP and pSeries LPAR 2003*9b6b563cSPaul Mackerras */ 2004*9b6b563cSPaul Mackerras RELOC(of_platform) = prom_find_machine_type(); 2005*9b6b563cSPaul Mackerras getprop_rval = RELOC(of_platform); 2006*9b6b563cSPaul Mackerras prom_setprop(_prom->chosen, "linux,platform", 2007*9b6b563cSPaul Mackerras &getprop_rval, sizeof(getprop_rval)); 2008*9b6b563cSPaul Mackerras 2009*9b6b563cSPaul Mackerras #ifdef CONFIG_PPC_PSERIES 2010*9b6b563cSPaul Mackerras /* 2011*9b6b563cSPaul Mackerras * On pSeries, inform the firmware about our capabilities 2012*9b6b563cSPaul Mackerras */ 2013*9b6b563cSPaul Mackerras if (RELOC(of_platform) & PLATFORM_PSERIES) 2014*9b6b563cSPaul Mackerras prom_send_capabilities(); 2015*9b6b563cSPaul Mackerras #endif 2016*9b6b563cSPaul Mackerras 2017*9b6b563cSPaul Mackerras #if defined(CONFIG_PPC_PSERIES) || defined(CONFIG_PPC_BPA) 2018*9b6b563cSPaul Mackerras /* 2019*9b6b563cSPaul Mackerras * On pSeries and BPA, copy the CPU hold code 2020*9b6b563cSPaul Mackerras */ 2021*9b6b563cSPaul Mackerras if (RELOC(of_platform) & (PLATFORM_PSERIES | PLATFORM_BPA)) 2022*9b6b563cSPaul Mackerras copy_and_flush(0, KERNELBASE - offset, 0x100, 0); 2023*9b6b563cSPaul Mackerras #endif 2024*9b6b563cSPaul Mackerras 2025*9b6b563cSPaul Mackerras /* 2026*9b6b563cSPaul Mackerras * Do early parsing of command line 2027*9b6b563cSPaul Mackerras */ 2028*9b6b563cSPaul Mackerras early_cmdline_parse(); 2029*9b6b563cSPaul Mackerras 2030*9b6b563cSPaul Mackerras /* 2031*9b6b563cSPaul Mackerras * Initialize memory management within prom_init 2032*9b6b563cSPaul Mackerras */ 2033*9b6b563cSPaul Mackerras prom_init_mem(); 2034*9b6b563cSPaul Mackerras 2035*9b6b563cSPaul Mackerras /* 2036*9b6b563cSPaul Mackerras * Determine which cpu is actually running right _now_ 2037*9b6b563cSPaul Mackerras */ 2038*9b6b563cSPaul Mackerras prom_find_boot_cpu(); 2039*9b6b563cSPaul Mackerras 2040*9b6b563cSPaul Mackerras /* 2041*9b6b563cSPaul Mackerras * Initialize display devices 2042*9b6b563cSPaul Mackerras */ 2043*9b6b563cSPaul Mackerras prom_check_displays(); 2044*9b6b563cSPaul Mackerras 2045*9b6b563cSPaul Mackerras #ifdef CONFIG_PPC64 2046*9b6b563cSPaul Mackerras /* 2047*9b6b563cSPaul Mackerras * Initialize IOMMU (TCE tables) on pSeries. Do that before anything else 2048*9b6b563cSPaul Mackerras * that uses the allocator, we need to make sure we get the top of memory 2049*9b6b563cSPaul Mackerras * available for us here... 2050*9b6b563cSPaul Mackerras */ 2051*9b6b563cSPaul Mackerras if (RELOC(of_platform) == PLATFORM_PSERIES) 2052*9b6b563cSPaul Mackerras prom_initialize_tce_table(); 2053*9b6b563cSPaul Mackerras #endif 2054*9b6b563cSPaul Mackerras 2055*9b6b563cSPaul Mackerras /* 2056*9b6b563cSPaul Mackerras * On non-powermacs, try to instantiate RTAS and puts all CPUs 2057*9b6b563cSPaul Mackerras * in spin-loops. PowerMacs don't have a working RTAS and use 2058*9b6b563cSPaul Mackerras * a different way to spin CPUs 2059*9b6b563cSPaul Mackerras */ 2060*9b6b563cSPaul Mackerras if (RELOC(of_platform) != PLATFORM_POWERMAC) { 2061*9b6b563cSPaul Mackerras prom_instantiate_rtas(); 2062*9b6b563cSPaul Mackerras prom_hold_cpus(); 2063*9b6b563cSPaul Mackerras } 2064*9b6b563cSPaul Mackerras 2065*9b6b563cSPaul Mackerras /* 2066*9b6b563cSPaul Mackerras * Fill in some infos for use by the kernel later on 2067*9b6b563cSPaul Mackerras */ 2068*9b6b563cSPaul Mackerras if (RELOC(prom_memory_limit)) 2069*9b6b563cSPaul Mackerras prom_setprop(_prom->chosen, "linux,memory-limit", 2070*9b6b563cSPaul Mackerras &RELOC(prom_memory_limit), 2071*9b6b563cSPaul Mackerras sizeof(prom_memory_limit)); 2072*9b6b563cSPaul Mackerras #ifdef CONFIG_PPC64 2073*9b6b563cSPaul Mackerras if (RELOC(ppc64_iommu_off)) 2074*9b6b563cSPaul Mackerras prom_setprop(_prom->chosen, "linux,iommu-off", NULL, 0); 2075*9b6b563cSPaul Mackerras 2076*9b6b563cSPaul Mackerras if (RELOC(iommu_force_on)) 2077*9b6b563cSPaul Mackerras prom_setprop(_prom->chosen, "linux,iommu-force-on", NULL, 0); 2078*9b6b563cSPaul Mackerras 2079*9b6b563cSPaul Mackerras if (RELOC(prom_tce_alloc_start)) { 2080*9b6b563cSPaul Mackerras prom_setprop(_prom->chosen, "linux,tce-alloc-start", 2081*9b6b563cSPaul Mackerras &RELOC(prom_tce_alloc_start), 2082*9b6b563cSPaul Mackerras sizeof(prom_tce_alloc_start)); 2083*9b6b563cSPaul Mackerras prom_setprop(_prom->chosen, "linux,tce-alloc-end", 2084*9b6b563cSPaul Mackerras &RELOC(prom_tce_alloc_end), 2085*9b6b563cSPaul Mackerras sizeof(prom_tce_alloc_end)); 2086*9b6b563cSPaul Mackerras } 2087*9b6b563cSPaul Mackerras #endif 2088*9b6b563cSPaul Mackerras 2089*9b6b563cSPaul Mackerras /* 2090*9b6b563cSPaul Mackerras * Fixup any known bugs in the device-tree 2091*9b6b563cSPaul Mackerras */ 2092*9b6b563cSPaul Mackerras fixup_device_tree(); 2093*9b6b563cSPaul Mackerras 2094*9b6b563cSPaul Mackerras /* 2095*9b6b563cSPaul Mackerras * Now finally create the flattened device-tree 2096*9b6b563cSPaul Mackerras */ 2097*9b6b563cSPaul Mackerras prom_printf("copying OF device tree ...\n"); 2098*9b6b563cSPaul Mackerras flatten_device_tree(); 2099*9b6b563cSPaul Mackerras 2100*9b6b563cSPaul Mackerras /* in case stdin is USB and still active on IBM machines... */ 2101*9b6b563cSPaul Mackerras prom_close_stdin(); 2102*9b6b563cSPaul Mackerras 2103*9b6b563cSPaul Mackerras /* 2104*9b6b563cSPaul Mackerras * Call OF "quiesce" method to shut down pending DMA's from 2105*9b6b563cSPaul Mackerras * devices etc... 2106*9b6b563cSPaul Mackerras */ 2107*9b6b563cSPaul Mackerras prom_printf("Calling quiesce ...\n"); 2108*9b6b563cSPaul Mackerras call_prom("quiesce", 0, 0); 2109*9b6b563cSPaul Mackerras 2110*9b6b563cSPaul Mackerras /* 2111*9b6b563cSPaul Mackerras * And finally, call the kernel passing it the flattened device 2112*9b6b563cSPaul Mackerras * tree and NULL as r5, thus triggering the new entry point which 2113*9b6b563cSPaul Mackerras * is common to us and kexec 2114*9b6b563cSPaul Mackerras */ 2115*9b6b563cSPaul Mackerras hdr = RELOC(dt_header_start); 2116*9b6b563cSPaul Mackerras prom_printf("returning from prom_init\n"); 2117*9b6b563cSPaul Mackerras prom_debug("->dt_header_start=0x%x\n", hdr); 2118*9b6b563cSPaul Mackerras 2119*9b6b563cSPaul Mackerras #ifdef CONFIG_PPC32 2120*9b6b563cSPaul Mackerras reloc_got2(-offset); 2121*9b6b563cSPaul Mackerras #endif 2122*9b6b563cSPaul Mackerras 2123*9b6b563cSPaul Mackerras __start(hdr, 0, 0); 2124*9b6b563cSPaul Mackerras 2125*9b6b563cSPaul Mackerras return 0; 2126*9b6b563cSPaul Mackerras } 2127