1*5de18cdeSSam Ravnborg /* 2*5de18cdeSSam Ravnborg * misc.c: Miscellaneous prom functions that don't belong 3*5de18cdeSSam Ravnborg * anywhere else. 4*5de18cdeSSam Ravnborg * 5*5de18cdeSSam Ravnborg * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) 6*5de18cdeSSam Ravnborg * Copyright (C) 1996,1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) 7*5de18cdeSSam Ravnborg */ 8*5de18cdeSSam Ravnborg 9*5de18cdeSSam Ravnborg #include <linux/types.h> 10*5de18cdeSSam Ravnborg #include <linux/kernel.h> 11*5de18cdeSSam Ravnborg #include <linux/sched.h> 12*5de18cdeSSam Ravnborg #include <linux/interrupt.h> 13*5de18cdeSSam Ravnborg #include <linux/delay.h> 14*5de18cdeSSam Ravnborg #include <asm/openprom.h> 15*5de18cdeSSam Ravnborg #include <asm/oplib.h> 16*5de18cdeSSam Ravnborg #include <asm/system.h> 17*5de18cdeSSam Ravnborg #include <asm/ldc.h> 18*5de18cdeSSam Ravnborg 19*5de18cdeSSam Ravnborg int prom_service_exists(const char *service_name) 20*5de18cdeSSam Ravnborg { 21*5de18cdeSSam Ravnborg int err = p1275_cmd("test", P1275_ARG(0, P1275_ARG_IN_STRING) | 22*5de18cdeSSam Ravnborg P1275_INOUT(1, 1), service_name); 23*5de18cdeSSam Ravnborg 24*5de18cdeSSam Ravnborg if (err) 25*5de18cdeSSam Ravnborg return 0; 26*5de18cdeSSam Ravnborg return 1; 27*5de18cdeSSam Ravnborg } 28*5de18cdeSSam Ravnborg 29*5de18cdeSSam Ravnborg void prom_sun4v_guest_soft_state(void) 30*5de18cdeSSam Ravnborg { 31*5de18cdeSSam Ravnborg const char *svc = "SUNW,soft-state-supported"; 32*5de18cdeSSam Ravnborg 33*5de18cdeSSam Ravnborg if (!prom_service_exists(svc)) 34*5de18cdeSSam Ravnborg return; 35*5de18cdeSSam Ravnborg p1275_cmd(svc, P1275_INOUT(0, 0)); 36*5de18cdeSSam Ravnborg } 37*5de18cdeSSam Ravnborg 38*5de18cdeSSam Ravnborg /* Reset and reboot the machine with the command 'bcommand'. */ 39*5de18cdeSSam Ravnborg void prom_reboot(const char *bcommand) 40*5de18cdeSSam Ravnborg { 41*5de18cdeSSam Ravnborg #ifdef CONFIG_SUN_LDOMS 42*5de18cdeSSam Ravnborg if (ldom_domaining_enabled) 43*5de18cdeSSam Ravnborg ldom_reboot(bcommand); 44*5de18cdeSSam Ravnborg #endif 45*5de18cdeSSam Ravnborg p1275_cmd("boot", P1275_ARG(0, P1275_ARG_IN_STRING) | 46*5de18cdeSSam Ravnborg P1275_INOUT(1, 0), bcommand); 47*5de18cdeSSam Ravnborg } 48*5de18cdeSSam Ravnborg 49*5de18cdeSSam Ravnborg /* Forth evaluate the expression contained in 'fstring'. */ 50*5de18cdeSSam Ravnborg void prom_feval(const char *fstring) 51*5de18cdeSSam Ravnborg { 52*5de18cdeSSam Ravnborg if (!fstring || fstring[0] == 0) 53*5de18cdeSSam Ravnborg return; 54*5de18cdeSSam Ravnborg p1275_cmd("interpret", P1275_ARG(0, P1275_ARG_IN_STRING) | 55*5de18cdeSSam Ravnborg P1275_INOUT(1, 1), fstring); 56*5de18cdeSSam Ravnborg } 57*5de18cdeSSam Ravnborg 58*5de18cdeSSam Ravnborg #ifdef CONFIG_SMP 59*5de18cdeSSam Ravnborg extern void smp_capture(void); 60*5de18cdeSSam Ravnborg extern void smp_release(void); 61*5de18cdeSSam Ravnborg #endif 62*5de18cdeSSam Ravnborg 63*5de18cdeSSam Ravnborg /* Drop into the prom, with the chance to continue with the 'go' 64*5de18cdeSSam Ravnborg * prom command. 65*5de18cdeSSam Ravnborg */ 66*5de18cdeSSam Ravnborg void prom_cmdline(void) 67*5de18cdeSSam Ravnborg { 68*5de18cdeSSam Ravnborg unsigned long flags; 69*5de18cdeSSam Ravnborg 70*5de18cdeSSam Ravnborg local_irq_save(flags); 71*5de18cdeSSam Ravnborg 72*5de18cdeSSam Ravnborg #ifdef CONFIG_SMP 73*5de18cdeSSam Ravnborg smp_capture(); 74*5de18cdeSSam Ravnborg #endif 75*5de18cdeSSam Ravnborg 76*5de18cdeSSam Ravnborg p1275_cmd("enter", P1275_INOUT(0, 0)); 77*5de18cdeSSam Ravnborg 78*5de18cdeSSam Ravnborg #ifdef CONFIG_SMP 79*5de18cdeSSam Ravnborg smp_release(); 80*5de18cdeSSam Ravnborg #endif 81*5de18cdeSSam Ravnborg 82*5de18cdeSSam Ravnborg local_irq_restore(flags); 83*5de18cdeSSam Ravnborg } 84*5de18cdeSSam Ravnborg 85*5de18cdeSSam Ravnborg /* Drop into the prom, but completely terminate the program. 86*5de18cdeSSam Ravnborg * No chance of continuing. 87*5de18cdeSSam Ravnborg */ 88*5de18cdeSSam Ravnborg void prom_halt(void) 89*5de18cdeSSam Ravnborg { 90*5de18cdeSSam Ravnborg #ifdef CONFIG_SUN_LDOMS 91*5de18cdeSSam Ravnborg if (ldom_domaining_enabled) 92*5de18cdeSSam Ravnborg ldom_power_off(); 93*5de18cdeSSam Ravnborg #endif 94*5de18cdeSSam Ravnborg again: 95*5de18cdeSSam Ravnborg p1275_cmd("exit", P1275_INOUT(0, 0)); 96*5de18cdeSSam Ravnborg goto again; /* PROM is out to get me -DaveM */ 97*5de18cdeSSam Ravnborg } 98*5de18cdeSSam Ravnborg 99*5de18cdeSSam Ravnborg void prom_halt_power_off(void) 100*5de18cdeSSam Ravnborg { 101*5de18cdeSSam Ravnborg #ifdef CONFIG_SUN_LDOMS 102*5de18cdeSSam Ravnborg if (ldom_domaining_enabled) 103*5de18cdeSSam Ravnborg ldom_power_off(); 104*5de18cdeSSam Ravnborg #endif 105*5de18cdeSSam Ravnborg p1275_cmd("SUNW,power-off", P1275_INOUT(0, 0)); 106*5de18cdeSSam Ravnborg 107*5de18cdeSSam Ravnborg /* if nothing else helps, we just halt */ 108*5de18cdeSSam Ravnborg prom_halt(); 109*5de18cdeSSam Ravnborg } 110*5de18cdeSSam Ravnborg 111*5de18cdeSSam Ravnborg /* Set prom sync handler to call function 'funcp'. */ 112*5de18cdeSSam Ravnborg void prom_setcallback(callback_func_t funcp) 113*5de18cdeSSam Ravnborg { 114*5de18cdeSSam Ravnborg if (!funcp) 115*5de18cdeSSam Ravnborg return; 116*5de18cdeSSam Ravnborg p1275_cmd("set-callback", P1275_ARG(0, P1275_ARG_IN_FUNCTION) | 117*5de18cdeSSam Ravnborg P1275_INOUT(1, 1), funcp); 118*5de18cdeSSam Ravnborg } 119*5de18cdeSSam Ravnborg 120*5de18cdeSSam Ravnborg /* Get the idprom and stuff it into buffer 'idbuf'. Returns the 121*5de18cdeSSam Ravnborg * format type. 'num_bytes' is the number of bytes that your idbuf 122*5de18cdeSSam Ravnborg * has space for. Returns 0xff on error. 123*5de18cdeSSam Ravnborg */ 124*5de18cdeSSam Ravnborg unsigned char prom_get_idprom(char *idbuf, int num_bytes) 125*5de18cdeSSam Ravnborg { 126*5de18cdeSSam Ravnborg int len; 127*5de18cdeSSam Ravnborg 128*5de18cdeSSam Ravnborg len = prom_getproplen(prom_root_node, "idprom"); 129*5de18cdeSSam Ravnborg if ((len >num_bytes) || (len == -1)) 130*5de18cdeSSam Ravnborg return 0xff; 131*5de18cdeSSam Ravnborg if (!prom_getproperty(prom_root_node, "idprom", idbuf, num_bytes)) 132*5de18cdeSSam Ravnborg return idbuf[0]; 133*5de18cdeSSam Ravnborg 134*5de18cdeSSam Ravnborg return 0xff; 135*5de18cdeSSam Ravnborg } 136*5de18cdeSSam Ravnborg 137*5de18cdeSSam Ravnborg int prom_get_mmu_ihandle(void) 138*5de18cdeSSam Ravnborg { 139*5de18cdeSSam Ravnborg int node, ret; 140*5de18cdeSSam Ravnborg 141*5de18cdeSSam Ravnborg if (prom_mmu_ihandle_cache != 0) 142*5de18cdeSSam Ravnborg return prom_mmu_ihandle_cache; 143*5de18cdeSSam Ravnborg 144*5de18cdeSSam Ravnborg node = prom_finddevice(prom_chosen_path); 145*5de18cdeSSam Ravnborg ret = prom_getint(node, prom_mmu_name); 146*5de18cdeSSam Ravnborg if (ret == -1 || ret == 0) 147*5de18cdeSSam Ravnborg prom_mmu_ihandle_cache = -1; 148*5de18cdeSSam Ravnborg else 149*5de18cdeSSam Ravnborg prom_mmu_ihandle_cache = ret; 150*5de18cdeSSam Ravnborg 151*5de18cdeSSam Ravnborg return ret; 152*5de18cdeSSam Ravnborg } 153*5de18cdeSSam Ravnborg 154*5de18cdeSSam Ravnborg static int prom_get_memory_ihandle(void) 155*5de18cdeSSam Ravnborg { 156*5de18cdeSSam Ravnborg static int memory_ihandle_cache; 157*5de18cdeSSam Ravnborg int node, ret; 158*5de18cdeSSam Ravnborg 159*5de18cdeSSam Ravnborg if (memory_ihandle_cache != 0) 160*5de18cdeSSam Ravnborg return memory_ihandle_cache; 161*5de18cdeSSam Ravnborg 162*5de18cdeSSam Ravnborg node = prom_finddevice("/chosen"); 163*5de18cdeSSam Ravnborg ret = prom_getint(node, "memory"); 164*5de18cdeSSam Ravnborg if (ret == -1 || ret == 0) 165*5de18cdeSSam Ravnborg memory_ihandle_cache = -1; 166*5de18cdeSSam Ravnborg else 167*5de18cdeSSam Ravnborg memory_ihandle_cache = ret; 168*5de18cdeSSam Ravnborg 169*5de18cdeSSam Ravnborg return ret; 170*5de18cdeSSam Ravnborg } 171*5de18cdeSSam Ravnborg 172*5de18cdeSSam Ravnborg /* Load explicit I/D TLB entries. */ 173*5de18cdeSSam Ravnborg long prom_itlb_load(unsigned long index, 174*5de18cdeSSam Ravnborg unsigned long tte_data, 175*5de18cdeSSam Ravnborg unsigned long vaddr) 176*5de18cdeSSam Ravnborg { 177*5de18cdeSSam Ravnborg return p1275_cmd(prom_callmethod_name, 178*5de18cdeSSam Ravnborg (P1275_ARG(0, P1275_ARG_IN_STRING) | 179*5de18cdeSSam Ravnborg P1275_ARG(2, P1275_ARG_IN_64B) | 180*5de18cdeSSam Ravnborg P1275_ARG(3, P1275_ARG_IN_64B) | 181*5de18cdeSSam Ravnborg P1275_INOUT(5, 1)), 182*5de18cdeSSam Ravnborg "SUNW,itlb-load", 183*5de18cdeSSam Ravnborg prom_get_mmu_ihandle(), 184*5de18cdeSSam Ravnborg /* And then our actual args are pushed backwards. */ 185*5de18cdeSSam Ravnborg vaddr, 186*5de18cdeSSam Ravnborg tte_data, 187*5de18cdeSSam Ravnborg index); 188*5de18cdeSSam Ravnborg } 189*5de18cdeSSam Ravnborg 190*5de18cdeSSam Ravnborg long prom_dtlb_load(unsigned long index, 191*5de18cdeSSam Ravnborg unsigned long tte_data, 192*5de18cdeSSam Ravnborg unsigned long vaddr) 193*5de18cdeSSam Ravnborg { 194*5de18cdeSSam Ravnborg return p1275_cmd(prom_callmethod_name, 195*5de18cdeSSam Ravnborg (P1275_ARG(0, P1275_ARG_IN_STRING) | 196*5de18cdeSSam Ravnborg P1275_ARG(2, P1275_ARG_IN_64B) | 197*5de18cdeSSam Ravnborg P1275_ARG(3, P1275_ARG_IN_64B) | 198*5de18cdeSSam Ravnborg P1275_INOUT(5, 1)), 199*5de18cdeSSam Ravnborg "SUNW,dtlb-load", 200*5de18cdeSSam Ravnborg prom_get_mmu_ihandle(), 201*5de18cdeSSam Ravnborg /* And then our actual args are pushed backwards. */ 202*5de18cdeSSam Ravnborg vaddr, 203*5de18cdeSSam Ravnborg tte_data, 204*5de18cdeSSam Ravnborg index); 205*5de18cdeSSam Ravnborg } 206*5de18cdeSSam Ravnborg 207*5de18cdeSSam Ravnborg int prom_map(int mode, unsigned long size, 208*5de18cdeSSam Ravnborg unsigned long vaddr, unsigned long paddr) 209*5de18cdeSSam Ravnborg { 210*5de18cdeSSam Ravnborg int ret = p1275_cmd(prom_callmethod_name, 211*5de18cdeSSam Ravnborg (P1275_ARG(0, P1275_ARG_IN_STRING) | 212*5de18cdeSSam Ravnborg P1275_ARG(3, P1275_ARG_IN_64B) | 213*5de18cdeSSam Ravnborg P1275_ARG(4, P1275_ARG_IN_64B) | 214*5de18cdeSSam Ravnborg P1275_ARG(6, P1275_ARG_IN_64B) | 215*5de18cdeSSam Ravnborg P1275_INOUT(7, 1)), 216*5de18cdeSSam Ravnborg prom_map_name, 217*5de18cdeSSam Ravnborg prom_get_mmu_ihandle(), 218*5de18cdeSSam Ravnborg mode, 219*5de18cdeSSam Ravnborg size, 220*5de18cdeSSam Ravnborg vaddr, 221*5de18cdeSSam Ravnborg 0, 222*5de18cdeSSam Ravnborg paddr); 223*5de18cdeSSam Ravnborg 224*5de18cdeSSam Ravnborg if (ret == 0) 225*5de18cdeSSam Ravnborg ret = -1; 226*5de18cdeSSam Ravnborg return ret; 227*5de18cdeSSam Ravnborg } 228*5de18cdeSSam Ravnborg 229*5de18cdeSSam Ravnborg void prom_unmap(unsigned long size, unsigned long vaddr) 230*5de18cdeSSam Ravnborg { 231*5de18cdeSSam Ravnborg p1275_cmd(prom_callmethod_name, 232*5de18cdeSSam Ravnborg (P1275_ARG(0, P1275_ARG_IN_STRING) | 233*5de18cdeSSam Ravnborg P1275_ARG(2, P1275_ARG_IN_64B) | 234*5de18cdeSSam Ravnborg P1275_ARG(3, P1275_ARG_IN_64B) | 235*5de18cdeSSam Ravnborg P1275_INOUT(4, 0)), 236*5de18cdeSSam Ravnborg prom_unmap_name, 237*5de18cdeSSam Ravnborg prom_get_mmu_ihandle(), 238*5de18cdeSSam Ravnborg size, 239*5de18cdeSSam Ravnborg vaddr); 240*5de18cdeSSam Ravnborg } 241*5de18cdeSSam Ravnborg 242*5de18cdeSSam Ravnborg /* Set aside physical memory which is not touched or modified 243*5de18cdeSSam Ravnborg * across soft resets. 244*5de18cdeSSam Ravnborg */ 245*5de18cdeSSam Ravnborg unsigned long prom_retain(const char *name, 246*5de18cdeSSam Ravnborg unsigned long pa_low, unsigned long pa_high, 247*5de18cdeSSam Ravnborg long size, long align) 248*5de18cdeSSam Ravnborg { 249*5de18cdeSSam Ravnborg /* XXX I don't think we return multiple values correctly. 250*5de18cdeSSam Ravnborg * XXX OBP supposedly returns pa_low/pa_high here, how does 251*5de18cdeSSam Ravnborg * XXX it work? 252*5de18cdeSSam Ravnborg */ 253*5de18cdeSSam Ravnborg 254*5de18cdeSSam Ravnborg /* If align is zero, the pa_low/pa_high args are passed, 255*5de18cdeSSam Ravnborg * else they are not. 256*5de18cdeSSam Ravnborg */ 257*5de18cdeSSam Ravnborg if (align == 0) 258*5de18cdeSSam Ravnborg return p1275_cmd("SUNW,retain", 259*5de18cdeSSam Ravnborg (P1275_ARG(0, P1275_ARG_IN_BUF) | P1275_INOUT(5, 2)), 260*5de18cdeSSam Ravnborg name, pa_low, pa_high, size, align); 261*5de18cdeSSam Ravnborg else 262*5de18cdeSSam Ravnborg return p1275_cmd("SUNW,retain", 263*5de18cdeSSam Ravnborg (P1275_ARG(0, P1275_ARG_IN_BUF) | P1275_INOUT(3, 2)), 264*5de18cdeSSam Ravnborg name, size, align); 265*5de18cdeSSam Ravnborg } 266*5de18cdeSSam Ravnborg 267*5de18cdeSSam Ravnborg /* Get "Unumber" string for the SIMM at the given 268*5de18cdeSSam Ravnborg * memory address. Usually this will be of the form 269*5de18cdeSSam Ravnborg * "Uxxxx" where xxxx is a decimal number which is 270*5de18cdeSSam Ravnborg * etched into the motherboard next to the SIMM slot 271*5de18cdeSSam Ravnborg * in question. 272*5de18cdeSSam Ravnborg */ 273*5de18cdeSSam Ravnborg int prom_getunumber(int syndrome_code, 274*5de18cdeSSam Ravnborg unsigned long phys_addr, 275*5de18cdeSSam Ravnborg char *buf, int buflen) 276*5de18cdeSSam Ravnborg { 277*5de18cdeSSam Ravnborg return p1275_cmd(prom_callmethod_name, 278*5de18cdeSSam Ravnborg (P1275_ARG(0, P1275_ARG_IN_STRING) | 279*5de18cdeSSam Ravnborg P1275_ARG(3, P1275_ARG_OUT_BUF) | 280*5de18cdeSSam Ravnborg P1275_ARG(6, P1275_ARG_IN_64B) | 281*5de18cdeSSam Ravnborg P1275_INOUT(8, 2)), 282*5de18cdeSSam Ravnborg "SUNW,get-unumber", prom_get_memory_ihandle(), 283*5de18cdeSSam Ravnborg buflen, buf, P1275_SIZE(buflen), 284*5de18cdeSSam Ravnborg 0, phys_addr, syndrome_code); 285*5de18cdeSSam Ravnborg } 286*5de18cdeSSam Ravnborg 287*5de18cdeSSam Ravnborg /* Power management extensions. */ 288*5de18cdeSSam Ravnborg void prom_sleepself(void) 289*5de18cdeSSam Ravnborg { 290*5de18cdeSSam Ravnborg p1275_cmd("SUNW,sleep-self", P1275_INOUT(0, 0)); 291*5de18cdeSSam Ravnborg } 292*5de18cdeSSam Ravnborg 293*5de18cdeSSam Ravnborg int prom_sleepsystem(void) 294*5de18cdeSSam Ravnborg { 295*5de18cdeSSam Ravnborg return p1275_cmd("SUNW,sleep-system", P1275_INOUT(0, 1)); 296*5de18cdeSSam Ravnborg } 297*5de18cdeSSam Ravnborg 298*5de18cdeSSam Ravnborg int prom_wakeupsystem(void) 299*5de18cdeSSam Ravnborg { 300*5de18cdeSSam Ravnborg return p1275_cmd("SUNW,wakeup-system", P1275_INOUT(0, 1)); 301*5de18cdeSSam Ravnborg } 302*5de18cdeSSam Ravnborg 303*5de18cdeSSam Ravnborg #ifdef CONFIG_SMP 304*5de18cdeSSam Ravnborg void prom_startcpu(int cpunode, unsigned long pc, unsigned long arg) 305*5de18cdeSSam Ravnborg { 306*5de18cdeSSam Ravnborg p1275_cmd("SUNW,start-cpu", P1275_INOUT(3, 0), cpunode, pc, arg); 307*5de18cdeSSam Ravnborg } 308*5de18cdeSSam Ravnborg 309*5de18cdeSSam Ravnborg void prom_startcpu_cpuid(int cpuid, unsigned long pc, unsigned long arg) 310*5de18cdeSSam Ravnborg { 311*5de18cdeSSam Ravnborg p1275_cmd("SUNW,start-cpu-by-cpuid", P1275_INOUT(3, 0), 312*5de18cdeSSam Ravnborg cpuid, pc, arg); 313*5de18cdeSSam Ravnborg } 314*5de18cdeSSam Ravnborg 315*5de18cdeSSam Ravnborg void prom_stopcpu_cpuid(int cpuid) 316*5de18cdeSSam Ravnborg { 317*5de18cdeSSam Ravnborg p1275_cmd("SUNW,stop-cpu-by-cpuid", P1275_INOUT(1, 0), 318*5de18cdeSSam Ravnborg cpuid); 319*5de18cdeSSam Ravnborg } 320*5de18cdeSSam Ravnborg 321*5de18cdeSSam Ravnborg void prom_stopself(void) 322*5de18cdeSSam Ravnborg { 323*5de18cdeSSam Ravnborg p1275_cmd("SUNW,stop-self", P1275_INOUT(0, 0)); 324*5de18cdeSSam Ravnborg } 325*5de18cdeSSam Ravnborg 326*5de18cdeSSam Ravnborg void prom_idleself(void) 327*5de18cdeSSam Ravnborg { 328*5de18cdeSSam Ravnborg p1275_cmd("SUNW,idle-self", P1275_INOUT(0, 0)); 329*5de18cdeSSam Ravnborg } 330*5de18cdeSSam Ravnborg 331*5de18cdeSSam Ravnborg void prom_resumecpu(int cpunode) 332*5de18cdeSSam Ravnborg { 333*5de18cdeSSam Ravnborg p1275_cmd("SUNW,resume-cpu", P1275_INOUT(1, 0), cpunode); 334*5de18cdeSSam Ravnborg } 335*5de18cdeSSam Ravnborg #endif 336