1*5de18cdeSSam Ravnborg /* 2*5de18cdeSSam Ravnborg * p1275.c: Sun IEEE 1275 PROM low level interface routines 3*5de18cdeSSam Ravnborg * 4*5de18cdeSSam Ravnborg * Copyright (C) 1996,1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) 5*5de18cdeSSam Ravnborg */ 6*5de18cdeSSam Ravnborg 7*5de18cdeSSam Ravnborg #include <linux/kernel.h> 8*5de18cdeSSam Ravnborg #include <linux/init.h> 9*5de18cdeSSam Ravnborg #include <linux/sched.h> 10*5de18cdeSSam Ravnborg #include <linux/smp.h> 11*5de18cdeSSam Ravnborg #include <linux/string.h> 12*5de18cdeSSam Ravnborg #include <linux/spinlock.h> 13*5de18cdeSSam Ravnborg 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/spitfire.h> 18*5de18cdeSSam Ravnborg #include <asm/pstate.h> 19*5de18cdeSSam Ravnborg #include <asm/ldc.h> 20*5de18cdeSSam Ravnborg 21*5de18cdeSSam Ravnborg struct { 22*5de18cdeSSam Ravnborg long prom_callback; /* 0x00 */ 23*5de18cdeSSam Ravnborg void (*prom_cif_handler)(long *); /* 0x08 */ 24*5de18cdeSSam Ravnborg unsigned long prom_cif_stack; /* 0x10 */ 25*5de18cdeSSam Ravnborg unsigned long prom_args [23]; /* 0x18 */ 26*5de18cdeSSam Ravnborg char prom_buffer [3000]; 27*5de18cdeSSam Ravnborg } p1275buf; 28*5de18cdeSSam Ravnborg 29*5de18cdeSSam Ravnborg extern void prom_world(int); 30*5de18cdeSSam Ravnborg 31*5de18cdeSSam Ravnborg extern void prom_cif_interface(void); 32*5de18cdeSSam Ravnborg extern void prom_cif_callback(void); 33*5de18cdeSSam Ravnborg 34*5de18cdeSSam Ravnborg /* 35*5de18cdeSSam Ravnborg * This provides SMP safety on the p1275buf. prom_callback() drops this lock 36*5de18cdeSSam Ravnborg * to allow recursuve acquisition. 37*5de18cdeSSam Ravnborg */ 38*5de18cdeSSam Ravnborg DEFINE_SPINLOCK(prom_entry_lock); 39*5de18cdeSSam Ravnborg 40*5de18cdeSSam Ravnborg long p1275_cmd(const char *service, long fmt, ...) 41*5de18cdeSSam Ravnborg { 42*5de18cdeSSam Ravnborg char *p, *q; 43*5de18cdeSSam Ravnborg unsigned long flags; 44*5de18cdeSSam Ravnborg int nargs, nrets, i; 45*5de18cdeSSam Ravnborg va_list list; 46*5de18cdeSSam Ravnborg long attrs, x; 47*5de18cdeSSam Ravnborg 48*5de18cdeSSam Ravnborg p = p1275buf.prom_buffer; 49*5de18cdeSSam Ravnborg 50*5de18cdeSSam Ravnborg spin_lock_irqsave(&prom_entry_lock, flags); 51*5de18cdeSSam Ravnborg 52*5de18cdeSSam Ravnborg p1275buf.prom_args[0] = (unsigned long)p; /* service */ 53*5de18cdeSSam Ravnborg strcpy (p, service); 54*5de18cdeSSam Ravnborg p = (char *)(((long)(strchr (p, 0) + 8)) & ~7); 55*5de18cdeSSam Ravnborg p1275buf.prom_args[1] = nargs = (fmt & 0x0f); /* nargs */ 56*5de18cdeSSam Ravnborg p1275buf.prom_args[2] = nrets = ((fmt & 0xf0) >> 4); /* nrets */ 57*5de18cdeSSam Ravnborg attrs = fmt >> 8; 58*5de18cdeSSam Ravnborg va_start(list, fmt); 59*5de18cdeSSam Ravnborg for (i = 0; i < nargs; i++, attrs >>= 3) { 60*5de18cdeSSam Ravnborg switch (attrs & 0x7) { 61*5de18cdeSSam Ravnborg case P1275_ARG_NUMBER: 62*5de18cdeSSam Ravnborg p1275buf.prom_args[i + 3] = 63*5de18cdeSSam Ravnborg (unsigned)va_arg(list, long); 64*5de18cdeSSam Ravnborg break; 65*5de18cdeSSam Ravnborg case P1275_ARG_IN_64B: 66*5de18cdeSSam Ravnborg p1275buf.prom_args[i + 3] = 67*5de18cdeSSam Ravnborg va_arg(list, unsigned long); 68*5de18cdeSSam Ravnborg break; 69*5de18cdeSSam Ravnborg case P1275_ARG_IN_STRING: 70*5de18cdeSSam Ravnborg strcpy (p, va_arg(list, char *)); 71*5de18cdeSSam Ravnborg p1275buf.prom_args[i + 3] = (unsigned long)p; 72*5de18cdeSSam Ravnborg p = (char *)(((long)(strchr (p, 0) + 8)) & ~7); 73*5de18cdeSSam Ravnborg break; 74*5de18cdeSSam Ravnborg case P1275_ARG_OUT_BUF: 75*5de18cdeSSam Ravnborg (void) va_arg(list, char *); 76*5de18cdeSSam Ravnborg p1275buf.prom_args[i + 3] = (unsigned long)p; 77*5de18cdeSSam Ravnborg x = va_arg(list, long); 78*5de18cdeSSam Ravnborg i++; attrs >>= 3; 79*5de18cdeSSam Ravnborg p = (char *)(((long)(p + (int)x + 7)) & ~7); 80*5de18cdeSSam Ravnborg p1275buf.prom_args[i + 3] = x; 81*5de18cdeSSam Ravnborg break; 82*5de18cdeSSam Ravnborg case P1275_ARG_IN_BUF: 83*5de18cdeSSam Ravnborg q = va_arg(list, char *); 84*5de18cdeSSam Ravnborg p1275buf.prom_args[i + 3] = (unsigned long)p; 85*5de18cdeSSam Ravnborg x = va_arg(list, long); 86*5de18cdeSSam Ravnborg i++; attrs >>= 3; 87*5de18cdeSSam Ravnborg memcpy (p, q, (int)x); 88*5de18cdeSSam Ravnborg p = (char *)(((long)(p + (int)x + 7)) & ~7); 89*5de18cdeSSam Ravnborg p1275buf.prom_args[i + 3] = x; 90*5de18cdeSSam Ravnborg break; 91*5de18cdeSSam Ravnborg case P1275_ARG_OUT_32B: 92*5de18cdeSSam Ravnborg (void) va_arg(list, char *); 93*5de18cdeSSam Ravnborg p1275buf.prom_args[i + 3] = (unsigned long)p; 94*5de18cdeSSam Ravnborg p += 32; 95*5de18cdeSSam Ravnborg break; 96*5de18cdeSSam Ravnborg case P1275_ARG_IN_FUNCTION: 97*5de18cdeSSam Ravnborg p1275buf.prom_args[i + 3] = 98*5de18cdeSSam Ravnborg (unsigned long)prom_cif_callback; 99*5de18cdeSSam Ravnborg p1275buf.prom_callback = va_arg(list, long); 100*5de18cdeSSam Ravnborg break; 101*5de18cdeSSam Ravnborg } 102*5de18cdeSSam Ravnborg } 103*5de18cdeSSam Ravnborg va_end(list); 104*5de18cdeSSam Ravnborg 105*5de18cdeSSam Ravnborg prom_world(1); 106*5de18cdeSSam Ravnborg prom_cif_interface(); 107*5de18cdeSSam Ravnborg prom_world(0); 108*5de18cdeSSam Ravnborg 109*5de18cdeSSam Ravnborg attrs = fmt >> 8; 110*5de18cdeSSam Ravnborg va_start(list, fmt); 111*5de18cdeSSam Ravnborg for (i = 0; i < nargs; i++, attrs >>= 3) { 112*5de18cdeSSam Ravnborg switch (attrs & 0x7) { 113*5de18cdeSSam Ravnborg case P1275_ARG_NUMBER: 114*5de18cdeSSam Ravnborg (void) va_arg(list, long); 115*5de18cdeSSam Ravnborg break; 116*5de18cdeSSam Ravnborg case P1275_ARG_IN_STRING: 117*5de18cdeSSam Ravnborg (void) va_arg(list, char *); 118*5de18cdeSSam Ravnborg break; 119*5de18cdeSSam Ravnborg case P1275_ARG_IN_FUNCTION: 120*5de18cdeSSam Ravnborg (void) va_arg(list, long); 121*5de18cdeSSam Ravnborg break; 122*5de18cdeSSam Ravnborg case P1275_ARG_IN_BUF: 123*5de18cdeSSam Ravnborg (void) va_arg(list, char *); 124*5de18cdeSSam Ravnborg (void) va_arg(list, long); 125*5de18cdeSSam Ravnborg i++; attrs >>= 3; 126*5de18cdeSSam Ravnborg break; 127*5de18cdeSSam Ravnborg case P1275_ARG_OUT_BUF: 128*5de18cdeSSam Ravnborg p = va_arg(list, char *); 129*5de18cdeSSam Ravnborg x = va_arg(list, long); 130*5de18cdeSSam Ravnborg memcpy (p, (char *)(p1275buf.prom_args[i + 3]), (int)x); 131*5de18cdeSSam Ravnborg i++; attrs >>= 3; 132*5de18cdeSSam Ravnborg break; 133*5de18cdeSSam Ravnborg case P1275_ARG_OUT_32B: 134*5de18cdeSSam Ravnborg p = va_arg(list, char *); 135*5de18cdeSSam Ravnborg memcpy (p, (char *)(p1275buf.prom_args[i + 3]), 32); 136*5de18cdeSSam Ravnborg break; 137*5de18cdeSSam Ravnborg } 138*5de18cdeSSam Ravnborg } 139*5de18cdeSSam Ravnborg va_end(list); 140*5de18cdeSSam Ravnborg x = p1275buf.prom_args [nargs + 3]; 141*5de18cdeSSam Ravnborg 142*5de18cdeSSam Ravnborg spin_unlock_irqrestore(&prom_entry_lock, flags); 143*5de18cdeSSam Ravnborg 144*5de18cdeSSam Ravnborg return x; 145*5de18cdeSSam Ravnborg } 146*5de18cdeSSam Ravnborg 147*5de18cdeSSam Ravnborg void prom_cif_init(void *cif_handler, void *cif_stack) 148*5de18cdeSSam Ravnborg { 149*5de18cdeSSam Ravnborg p1275buf.prom_cif_handler = (void (*)(long *))cif_handler; 150*5de18cdeSSam Ravnborg p1275buf.prom_cif_stack = (unsigned long)cif_stack; 151*5de18cdeSSam Ravnborg } 152