1/* auxio.c: Probing for the Sparc AUXIO register at boot time. 2 * 3 * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) 4 */ 5 6#include <linux/stddef.h> 7#include <linux/init.h> 8#include <linux/spinlock.h> 9#include <asm/oplib.h> 10#include <asm/io.h> 11#include <asm/auxio.h> 12#include <asm/string.h> /* memset(), Linux has no bzero() */ 13 14/* Probe and map in the Auxiliary I/O register */ 15 16/* auxio_register is not static because it is referenced 17 * in entry.S::floppy_tdone 18 */ 19void __iomem *auxio_register = NULL; 20static DEFINE_SPINLOCK(auxio_lock); 21 22void __init auxio_probe(void) 23{ 24 int node, auxio_nd; 25 struct linux_prom_registers auxregs[1]; 26 struct resource r; 27 28 switch (sparc_cpu_model) { 29 case sun4d: 30 case sun4: 31 return; 32 default: 33 break; 34 } 35 node = prom_getchild(prom_root_node); 36 auxio_nd = prom_searchsiblings(node, "auxiliary-io"); 37 if(!auxio_nd) { 38 node = prom_searchsiblings(node, "obio"); 39 node = prom_getchild(node); 40 auxio_nd = prom_searchsiblings(node, "auxio"); 41 if(!auxio_nd) { 42#ifdef CONFIG_PCI 43 /* There may be auxio on Ebus */ 44 return; 45#else 46 if(prom_searchsiblings(node, "leds")) { 47 /* VME chassis sun4m machine, no auxio exists. */ 48 return; 49 } 50 prom_printf("Cannot find auxio node, cannot continue...\n"); 51 prom_halt(); 52#endif 53 } 54 } 55 if(prom_getproperty(auxio_nd, "reg", (char *) auxregs, sizeof(auxregs)) <= 0) 56 return; 57 prom_apply_obio_ranges(auxregs, 0x1); 58 /* Map the register both read and write */ 59 r.flags = auxregs[0].which_io & 0xF; 60 r.start = auxregs[0].phys_addr; 61 r.end = auxregs[0].phys_addr + auxregs[0].reg_size - 1; 62 auxio_register = sbus_ioremap(&r, 0, auxregs[0].reg_size, "auxio"); 63 /* Fix the address on sun4m and sun4c. */ 64 if((((unsigned long) auxregs[0].phys_addr) & 3) == 3 || 65 sparc_cpu_model == sun4c) 66 auxio_register += (3 - ((unsigned long)auxio_register & 3)); 67 68 set_auxio(AUXIO_LED, 0); 69} 70 71unsigned char get_auxio(void) 72{ 73 if(auxio_register) 74 return sbus_readb(auxio_register); 75 return 0; 76} 77 78void set_auxio(unsigned char bits_on, unsigned char bits_off) 79{ 80 unsigned char regval; 81 unsigned long flags; 82 spin_lock_irqsave(&auxio_lock, flags); 83 switch(sparc_cpu_model) { 84 case sun4c: 85 regval = sbus_readb(auxio_register); 86 sbus_writeb(((regval | bits_on) & ~bits_off) | AUXIO_ORMEIN, 87 auxio_register); 88 break; 89 case sun4m: 90 if(!auxio_register) 91 break; /* VME chassis sun4m, no auxio. */ 92 regval = sbus_readb(auxio_register); 93 sbus_writeb(((regval | bits_on) & ~bits_off) | AUXIO_ORMEIN4M, 94 auxio_register); 95 break; 96 case sun4d: 97 break; 98 default: 99 panic("Can't set AUXIO register on this machine."); 100 }; 101 spin_unlock_irqrestore(&auxio_lock, flags); 102} 103 104 105/* sun4m power control register (AUXIO2) */ 106 107volatile unsigned char * auxio_power_register = NULL; 108 109void __init auxio_power_probe(void) 110{ 111 struct linux_prom_registers regs; 112 int node; 113 struct resource r; 114 115 /* Attempt to find the sun4m power control node. */ 116 node = prom_getchild(prom_root_node); 117 node = prom_searchsiblings(node, "obio"); 118 node = prom_getchild(node); 119 node = prom_searchsiblings(node, "power"); 120 if (node == 0 || node == -1) 121 return; 122 123 /* Map the power control register. */ 124 if (prom_getproperty(node, "reg", (char *)®s, sizeof(regs)) <= 0) 125 return; 126 prom_apply_obio_ranges(®s, 1); 127 memset(&r, 0, sizeof(r)); 128 r.flags = regs.which_io & 0xF; 129 r.start = regs.phys_addr; 130 r.end = regs.phys_addr + regs.reg_size - 1; 131 auxio_power_register = (unsigned char *) sbus_ioremap(&r, 0, 132 regs.reg_size, "auxpower"); 133 134 /* Display a quick message on the console. */ 135 if (auxio_power_register) 136 printk(KERN_INFO "Power off control detected.\n"); 137} 138