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