1 /* $NetBSD: auxio.c,v 1.19 2008/05/29 14:51:26 mrg Exp $ */
4 * Copyright (c) 2000, 2001 Matthew R. Green
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
21 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
23 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * AUXIO registers support on the sbus & ebus2, used for the floppy driver
31 * and to control the system LED, for the BLINK option.
34 #include <sys/cdefs.h>
35 __KERNEL_RCSID(0, "$NetBSD: auxio.c,v 1.19 2008/05/29 14:51:26 mrg Exp $");
37 #include "opt_auxio.h"
39 #include <sys/param.h>
40 #include <sys/systm.h>
41 #include <sys/kernel.h>
42 #include <sys/callout.h>
43 #include <sys/errno.h>
44 #include <sys/device.h>
45 #include <sys/malloc.h>
47 #include <machine/autoconf.h>
48 #include <machine/cpu.h>
50 #include <dev/ebus/ebusreg.h>
51 #include <dev/ebus/ebusvar.h>
52 #include <sparc64/dev/sbusvar.h>
53 #include <sparc64/dev/auxioreg.h>
54 #include <sparc64/dev/auxiovar.h>
57 * on sun4u, auxio exists with one register (LED) on the sbus, and 5
58 * registers on the ebus2 (pci) (LED, PCIMODE, FREQUENCY, SCSI
59 * OSCILLATOR, and TEMP SENSE.
66 bus_space_tag_t sc_tag
;
68 /* handles to the various auxio regsiter sets */
69 bus_space_handle_t sc_led
;
70 bus_space_handle_t sc_pci
;
71 bus_space_handle_t sc_freq
;
72 bus_space_handle_t sc_scsi
;
73 bus_space_handle_t sc_temp
;
76 #define AUXIO_LEDONLY 0x1
77 #define AUXIO_EBUS 0x2
78 #define AUXIO_SBUS 0x4
81 #define AUXIO_ROM_NAME "auxio"
83 void auxio_attach_common(struct auxio_softc
*);
84 int auxio_ebus_match(struct device
*, struct cfdata
*, void *);
85 void auxio_ebus_attach(struct device
*, struct device
*, void *);
86 int auxio_sbus_match(struct device
*, struct cfdata
*, void *);
87 void auxio_sbus_attach(struct device
*, struct device
*, void *);
89 CFATTACH_DECL(auxio_ebus
, sizeof(struct auxio_softc
),
90 auxio_ebus_match
, auxio_ebus_attach
, NULL
, NULL
);
92 CFATTACH_DECL(auxio_sbus
, sizeof(struct auxio_softc
),
93 auxio_sbus_match
, auxio_sbus_attach
, NULL
, NULL
);
95 extern struct cfdriver auxio_cd
;
98 static callout_t blink_ch
;
99 static void auxio_blink(void *);
101 /* let someone disable it if it's already turned on; XXX sysctl? */
107 struct auxio_softc
*sc
= x
;
115 if (sc
->sc_flags
& AUXIO_EBUS
)
116 led
= le32toh(bus_space_read_4(sc
->sc_tag
, sc
->sc_led
, 0));
118 led
= bus_space_read_1(sc
->sc_tag
, sc
->sc_led
, 0);
120 led
= led
^ AUXIO_LED_LED
;
121 if (sc
->sc_flags
& AUXIO_EBUS
)
122 bus_space_write_4(sc
->sc_tag
, sc
->sc_led
, 0, htole32(led
));
124 bus_space_write_1(sc
->sc_tag
, sc
->sc_led
, 0, led
);
129 * full cycle every second if completely idle (loadav = 0)
130 * full cycle every 2 seconds if loadav = 1
131 * full cycle every 3 seconds if loadav = 2
134 s
= (((averunnable
.ldavg
[0] + FSCALE
) * hz
) >> (FSHIFT
+ 1));
135 callout_reset(&blink_ch
, s
, auxio_blink
, sc
);
140 auxio_attach_common(struct auxio_softc
*sc
)
143 static int do_once
= 1;
145 /* only start one blinker */
147 callout_init(&blink_ch
, 0);
156 auxio_ebus_match(struct device
*parent
, struct cfdata
*cf
, void *aux
)
158 struct ebus_attach_args
*ea
= aux
;
160 return (strcmp(AUXIO_ROM_NAME
, ea
->ea_name
) == 0);
164 auxio_ebus_attach(struct device
*parent
, struct device
*self
, void *aux
)
166 struct auxio_softc
*sc
= (struct auxio_softc
*)self
;
167 struct ebus_attach_args
*ea
= aux
;
169 sc
->sc_tag
= ea
->ea_bustag
;
171 if (ea
->ea_nreg
< 1) {
172 printf(": no registers??\n");
176 if (ea
->ea_nreg
!= 5) {
177 printf(": not 5 (%d) registers, only setting led",
179 sc
->sc_flags
= AUXIO_LEDONLY
|AUXIO_EBUS
;
180 } else if (ea
->ea_nvaddr
== 5) {
181 sc
->sc_flags
= AUXIO_EBUS
;
183 sparc_promaddr_to_handle(sc
->sc_tag
,
184 ea
->ea_vaddr
[1], &sc
->sc_pci
);
185 sparc_promaddr_to_handle(sc
->sc_tag
,
186 ea
->ea_vaddr
[2], &sc
->sc_freq
);
187 sparc_promaddr_to_handle(sc
->sc_tag
,
188 ea
->ea_vaddr
[3], &sc
->sc_scsi
);
189 sparc_promaddr_to_handle(sc
->sc_tag
,
190 ea
->ea_vaddr
[4], &sc
->sc_temp
);
192 sc
->sc_flags
= AUXIO_EBUS
;
193 bus_space_map(sc
->sc_tag
, EBUS_ADDR_FROM_REG(&ea
->ea_reg
[1]),
194 ea
->ea_reg
[1].size
, 0, &sc
->sc_pci
);
195 bus_space_map(sc
->sc_tag
, EBUS_ADDR_FROM_REG(&ea
->ea_reg
[2]),
196 ea
->ea_reg
[2].size
, 0, &sc
->sc_freq
);
197 bus_space_map(sc
->sc_tag
, EBUS_ADDR_FROM_REG(&ea
->ea_reg
[3]),
198 ea
->ea_reg
[3].size
, 0, &sc
->sc_scsi
);
199 bus_space_map(sc
->sc_tag
, EBUS_ADDR_FROM_REG(&ea
->ea_reg
[4]),
200 ea
->ea_reg
[4].size
, 0, &sc
->sc_temp
);
203 if (ea
->ea_nvaddr
> 0) {
204 sparc_promaddr_to_handle(sc
->sc_tag
,
205 ea
->ea_vaddr
[0], &sc
->sc_led
);
207 bus_space_map(sc
->sc_tag
, EBUS_ADDR_FROM_REG(&ea
->ea_reg
[0]),
208 ea
->ea_reg
[0].size
, 0, &sc
->sc_led
);
211 auxio_attach_common(sc
);
215 auxio_sbus_match(struct device
*parent
, struct cfdata
*cf
, void *aux
)
217 struct sbus_attach_args
*sa
= aux
;
219 return (strcmp(AUXIO_ROM_NAME
, sa
->sa_name
) == 0);
223 auxio_sbus_attach(struct device
*parent
, struct device
*self
, void *aux
)
225 struct auxio_softc
*sc
= (struct auxio_softc
*)self
;
226 struct sbus_attach_args
*sa
= aux
;
228 sc
->sc_tag
= sa
->sa_bustag
;
230 if (sa
->sa_nreg
< 1) {
231 printf(": no registers??\n");
235 if (sa
->sa_nreg
!= 1) {
236 printf(": not 1 (%d/%d) registers??", sa
->sa_nreg
,
241 /* sbus auxio only has one set of registers */
242 sc
->sc_flags
= AUXIO_LEDONLY
|AUXIO_SBUS
;
243 if (sa
->sa_npromvaddrs
> 0) {
244 sbus_promaddr_to_handle(sc
->sc_tag
,
245 sa
->sa_promvaddr
, &sc
->sc_led
);
247 sbus_bus_map(sc
->sc_tag
, sa
->sa_slot
, sa
->sa_offset
,
248 sa
->sa_size
, 0, &sc
->sc_led
);
251 auxio_attach_common(sc
);
255 auxio_fd_control(u_int32_t bits
)
257 struct auxio_softc
*sc
;
260 if (auxio_cd
.cd_ndevs
== 0) {
265 * XXX This does not handle > 1 auxio correctly.
266 * We'll assume the floppy drive is tied to first auxio found.
268 sc
= device_lookup_private(&auxio_cd
, 0);
269 if (sc
->sc_flags
& AUXIO_EBUS
)
270 led
= le32toh(bus_space_read_4(sc
->sc_tag
, sc
->sc_led
, 0));
272 led
= bus_space_read_1(sc
->sc_tag
, sc
->sc_led
, 0);
274 led
= (led
& ~AUXIO_LED_FLOPPY_MASK
) | bits
;
276 if (sc
->sc_flags
& AUXIO_EBUS
)
277 bus_space_write_4(sc
->sc_tag
, sc
->sc_led
, 0, htole32(led
));
279 bus_space_write_1(sc
->sc_tag
, sc
->sc_led
, 0, led
);