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