auxio.c revision 139749
1219820Sjeff/*-
2219820Sjeff * Copyright (c) 2004 Pyun YongHyeon
3219820Sjeff * All rights reserved.
4219820Sjeff *
5219820Sjeff * Redistribution and use in source and binary forms, with or without
6219820Sjeff * modification, are permitted provided that the following conditions
7219820Sjeff * are met:
8219820Sjeff * 1. Redistributions of source code must retain the above copyright
9219820Sjeff *    notice, this list of conditions and the following disclaimer.
10219820Sjeff * 2. Redistributions in binary form must reproduce the above copyright
11219820Sjeff *    notice, this list of conditions and the following disclaimer in the
12219820Sjeff *    documentation and/or other materials provided with the distribution.
13219820Sjeff *
14219820Sjeff * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15219820Sjeff * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16219820Sjeff * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17219820Sjeff * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18219820Sjeff * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19219820Sjeff * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20219820Sjeff * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21219820Sjeff * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22219820Sjeff * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23219820Sjeff * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24219820Sjeff * SUCH DAMAGE.
25219820Sjeff *
26219820Sjeff */
27219820Sjeff
28219820Sjeff/*	$NetBSD: auxio.c,v 1.11 2003/07/15 03:36:04 lukem Exp $	*/
29219820Sjeff
30219820Sjeff/*-
31219820Sjeff * Copyright (c) 2000, 2001 Matthew R. Green
32219820Sjeff * All rights reserved.
33219820Sjeff *
34219820Sjeff * Redistribution and use in source and binary forms, with or without
35219820Sjeff * modification, are permitted provided that the following conditions
36219820Sjeff * are met:
37219820Sjeff * 1. Redistributions of source code must retain the above copyright
38219820Sjeff *    notice, this list of conditions and the following disclaimer.
39219820Sjeff * 2. Redistributions in binary form must reproduce the above copyright
40219820Sjeff *    notice, this list of conditions and the following disclaimer in the
41219820Sjeff *    documentation and/or other materials provided with the distribution.
42219820Sjeff * 3. The name of the author may not be used to endorse or promote products
43219820Sjeff *    derived from this software without specific prior written permission.
44219820Sjeff *
45219820Sjeff * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
46219820Sjeff * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
47219820Sjeff * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
48219820Sjeff * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
49219820Sjeff * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
50219820Sjeff * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
51219820Sjeff * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
52219820Sjeff * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
53219820Sjeff * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
54219820Sjeff * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
55219820Sjeff * SUCH DAMAGE.
56219820Sjeff */
57219820Sjeff
58219820Sjeff/*
59219820Sjeff * AUXIO registers support on the sbus & ebus2, used for the floppy driver
60219820Sjeff * and to control the system LED, for the BLINK option.
61219820Sjeff */
62219820Sjeff
63219820Sjeff#include <sys/cdefs.h>
64219820Sjeff__FBSDID("$FreeBSD: head/sys/dev/auxio/auxio.c 139749 2005-01-06 01:43:34Z imp $");
65219820Sjeff
66219820Sjeff#include <sys/param.h>
67219820Sjeff#include <sys/systm.h>
68219820Sjeff#include <sys/bus.h>
69219820Sjeff#include <sys/kernel.h>
70219820Sjeff#include <sys/lock.h>
71219820Sjeff#include <sys/module.h>
72219820Sjeff#include <sys/mutex.h>
73219820Sjeff#include <sys/resource.h>
74219820Sjeff#include <sys/rman.h>
75219820Sjeff
76219820Sjeff#include <dev/led/led.h>
77219820Sjeff#include <dev/ofw/ofw_bus.h>
78219820Sjeff#include <dev/ofw/openfirm.h>
79219820Sjeff
80219820Sjeff#include <machine/bus.h>
81219820Sjeff#include <machine/ofw_machdep.h>
82219820Sjeff#include <machine/resource.h>
83219820Sjeff
84219820Sjeff#include <sparc64/sbus/sbusvar.h>
85219820Sjeff#include <dev/auxio/auxioreg.h>
86219820Sjeff
87219820Sjeff/*
88219820Sjeff * on sun4u, auxio exists with one register (LED) on the sbus, and 5
89219820Sjeff * registers on the ebus2 (pci) (LED, PCIMODE, FREQUENCY, SCSI
90219820Sjeff * OSCILLATOR, and TEMP SENSE.
91219820Sjeff */
92219820Sjeff
93219820Sjeff#define AUXIO_PCIO_LED	0
94219820Sjeff#define AUXIO_PCIO_PCI	1
95219820Sjeff#define AUXIO_PCIO_FREQ	2
96219820Sjeff#define AUXIO_PCIO_OSC	3
97219820Sjeff#define AUXIO_PCIO_TEMP	4
98219820Sjeff#define AUXIO_PCIO_MAX	8
99219820Sjeff
100219820Sjeffstruct auxio_softc {
101219820Sjeff	struct device		*sc_dev;
102219820Sjeff
103219820Sjeff	int			sc_nauxio;
104219820Sjeff	struct resource		*sc_res[AUXIO_PCIO_MAX];
105219820Sjeff	int			sc_rid[AUXIO_PCIO_MAX];
106219820Sjeff	bus_space_tag_t		sc_regt[AUXIO_PCIO_MAX];
107219820Sjeff	bus_space_handle_t	sc_regh[AUXIO_PCIO_MAX];
108219820Sjeff	struct cdev		*sc_led_dev;
109219820Sjeff	u_int32_t		sc_led_stat;
110219820Sjeff
111219820Sjeff	int			sc_flags;
112219820Sjeff#define	AUXIO_LEDONLY		0x1
113219820Sjeff#define	AUXIO_EBUS		0x2
114219820Sjeff#define	AUXIO_SBUS		0x4
115219820Sjeff
116219820Sjeff	struct mtx		sc_lock;
117219820Sjeff};
118219820Sjeff
119219820Sjeffstatic void	auxio_led_func(void *arg, int onoff);
120219820Sjeffstatic void	auxio_attach_common(struct auxio_softc *);
121219820Sjeffstatic int	auxio_bus_probe(device_t);
122219820Sjeffstatic int	auxio_sbus_attach(device_t);
123219820Sjeffstatic int	auxio_ebus_attach(device_t);
124219820Sjeffstatic int	auxio_bus_detach(device_t);
125219820Sjeffstatic void	auxio_free_resource(struct auxio_softc *);
126219820Sjeffstatic __inline u_int32_t auxio_led_read(struct auxio_softc *);
127219820Sjeffstatic __inline void auxio_led_write(struct auxio_softc *, u_int32_t);
128219820Sjeff
129219820Sjeff/* SBus */
130219820Sjeffstatic device_method_t auxio_sbus_methods[] = {
131219820Sjeff	DEVMETHOD(device_probe,		auxio_bus_probe),
132219820Sjeff	DEVMETHOD(device_attach,	auxio_sbus_attach),
133219820Sjeff	DEVMETHOD(device_detach,	auxio_bus_detach),
134219820Sjeff	{0, 0}
135219820Sjeff};
136219820Sjeff
137219820Sjeffstatic driver_t auxio_sbus_driver = {
138219820Sjeff	"auxio",
139219820Sjeff	auxio_sbus_methods,
140219820Sjeff	sizeof(struct auxio_softc)
141219820Sjeff};
142219820Sjeff
143219820Sjeffstatic devclass_t	auxio_devclass;
144219820SjeffDRIVER_MODULE(auxio, sbus, auxio_sbus_driver, auxio_devclass, 0, 0);
145219820Sjeff
146219820Sjeff/* EBus */
147219820Sjeffstatic device_method_t auxio_ebus_methods[] = {
148219820Sjeff	DEVMETHOD(device_probe,		auxio_bus_probe),
149219820Sjeff	DEVMETHOD(device_attach,	auxio_ebus_attach),
150219820Sjeff	DEVMETHOD(device_detach,	auxio_bus_detach),
151219820Sjeff	{0, 0}
152219820Sjeff};
153219820Sjeff
154219820Sjeffstatic driver_t auxio_ebus_driver = {
155219820Sjeff	"auxio",
156219820Sjeff	auxio_ebus_methods,
157219820Sjeff	sizeof(struct auxio_softc)
158219820Sjeff};
159219820Sjeff
160219820SjeffDRIVER_MODULE(auxio, ebus, auxio_ebus_driver, auxio_devclass, 0, 0);
161219820SjeffMODULE_VERSION(auxio, 1);
162219820Sjeff
163219820Sjeff#define AUXIO_LOCK_INIT(sc)	\
164219820Sjeff	mtx_init(&sc->sc_lock, "auxio mtx", NULL, MTX_DEF)
165219820Sjeff#define AUXIO_LOCK(sc)		mtx_lock(&sc->sc_lock)
166219820Sjeff#define AUXIO_UNLOCK(sc)	mtx_unlock(&sc->sc_lock)
167219820Sjeff#define AUXIO_LOCK_DESTROY(sc)	mtx_destroy(&sc->sc_lock)
168219820Sjeff
169219820Sjeffstatic __inline void
170219820Sjeffauxio_led_write(struct auxio_softc *sc, u_int32_t v)
171219820Sjeff{
172219820Sjeff	if (sc->sc_flags & AUXIO_EBUS)
173219820Sjeff		bus_space_write_4(sc->sc_regt[AUXIO_PCIO_LED],
174219820Sjeff		    sc->sc_regh[AUXIO_PCIO_LED], 0, v);
175219820Sjeff	else
176219820Sjeff		bus_space_write_1(sc->sc_regt[AUXIO_PCIO_LED],
177219820Sjeff		    sc->sc_regh[AUXIO_PCIO_LED], 0, v);
178219820Sjeff}
179219820Sjeff
180219820Sjeffstatic __inline u_int32_t
181219820Sjeffauxio_led_read(struct auxio_softc *sc)
182219820Sjeff{
183219820Sjeff	u_int32_t led;
184219820Sjeff
185219820Sjeff	if (sc->sc_flags & AUXIO_EBUS)
186219820Sjeff		led = bus_space_read_4(sc->sc_regt[AUXIO_PCIO_LED],
187219820Sjeff		    sc->sc_regh[AUXIO_PCIO_LED], 0);
188219820Sjeff	else
189219820Sjeff		led = bus_space_read_1(sc->sc_regt[AUXIO_PCIO_LED],
190219820Sjeff		    sc->sc_regh[AUXIO_PCIO_LED], 0);
191219820Sjeff
192219820Sjeff	return (led);
193219820Sjeff}
194219820Sjeff
195219820Sjeffstatic void
196219820Sjeffauxio_led_func(void *arg, int onoff)
197219820Sjeff{
198219820Sjeff	struct auxio_softc *sc;
199219820Sjeff	u_int32_t led;
200219820Sjeff
201219820Sjeff	sc = (struct auxio_softc *)arg;
202219820Sjeff
203219820Sjeff	led = onoff ? AUXIO_LED_LED : 0;
204219820Sjeff	AUXIO_LOCK(sc);
205219820Sjeff	auxio_led_write(sc, led);
206219820Sjeff	AUXIO_UNLOCK(sc);
207219820Sjeff}
208219820Sjeff
209219820Sjeffstatic int
210219820Sjeffauxio_bus_probe(device_t dev)
211219820Sjeff{
212219820Sjeff	const char *name;
213219820Sjeff
214219820Sjeff	name = ofw_bus_get_name(dev);
215219820Sjeff	if (strcmp("auxio", name) == 0) {
216219820Sjeff		device_set_desc(dev, "Sun Auxiliary I/O");
217219820Sjeff		return (0);
218219820Sjeff	}
219219820Sjeff
220219820Sjeff	return (ENXIO);
221219820Sjeff}
222219820Sjeff
223219820Sjeffstatic int
224219820Sjeffauxio_ebus_attach(device_t dev)
225219820Sjeff{
226219820Sjeff	struct auxio_softc *sc;
227219820Sjeff	struct resource *res;
228219820Sjeff	u_long start, count;
229219820Sjeff	int i;
230219820Sjeff
231219820Sjeff	sc = device_get_softc(dev);
232219820Sjeff	bzero(sc, sizeof(*sc));
233219820Sjeff	sc->sc_dev = dev;
234219820Sjeff
235219820Sjeff	AUXIO_LOCK_INIT(sc);
236219820Sjeff	sc->sc_nauxio = AUXIO_PCIO_MAX;
237219820Sjeff	sc->sc_flags = AUXIO_LEDONLY | AUXIO_EBUS;
238219820Sjeff	for (i = 0;
239219820Sjeff	    i < AUXIO_PCIO_MAX &&
240219820Sjeff	    bus_get_resource(dev, SYS_RES_IOPORT, i, &start, &count) == 0;
241219820Sjeff             i++) {
242219820Sjeff		sc->sc_rid[i] = i;
243219820Sjeff		if (bootverbose)
244219820Sjeff			device_printf(sc->sc_dev,
245219820Sjeff			    "Got rid %d, start %#lx, count %#lx\n",
246219820Sjeff			    i, start, count);
247219820Sjeff		res = bus_alloc_resource_any(dev, SYS_RES_IOPORT,
248219820Sjeff		    &sc->sc_rid[i], RF_ACTIVE);
249219820Sjeff		if (res == NULL) {
250219820Sjeff			device_printf(sc->sc_dev,
251219820Sjeff			    "could not allocate resources\n");
252219820Sjeff			goto attach_fail;
253219820Sjeff		}
254219820Sjeff		sc->sc_res[i] = res;
255219820Sjeff		sc->sc_regt[i] = rman_get_bustag(res);
256219820Sjeff		sc->sc_regh[i] = rman_get_bushandle(res);
257219820Sjeff	}
258219820Sjeff	sc->sc_nauxio = i;
259219820Sjeff	auxio_attach_common(sc);
260219820Sjeff
261219820Sjeff	return (0);
262219820Sjeff
263219820Sjeffattach_fail:
264219820Sjeff	auxio_free_resource(sc);
265219820Sjeff
266219820Sjeff	return (ENXIO);
267219820Sjeff}
268219820Sjeff
269219820Sjeffstatic void
270219820Sjeffauxio_attach_common(struct auxio_softc *sc)
271219820Sjeff{
272219820Sjeff	sc->sc_led_stat = auxio_led_read(sc);
273219820Sjeff	sc->sc_led_dev = led_create(auxio_led_func, sc, "auxioled");
274219820Sjeff	/* turn on the LED */
275219820Sjeff	auxio_led_func(sc, 1);
276219820Sjeff}
277219820Sjeff
278219820Sjeffstatic int
279219820Sjeffauxio_bus_detach(device_t dev)
280219820Sjeff{
281219820Sjeff	struct auxio_softc *sc;
282219820Sjeff
283219820Sjeff	sc = device_get_softc(dev);
284219820Sjeff	led_destroy(sc->sc_led_dev);
285219820Sjeff	auxio_led_func(sc, sc->sc_led_stat);
286219820Sjeff	auxio_free_resource(sc);
287219820Sjeff
288219820Sjeff	return (0);
289219820Sjeff}
290219820Sjeff
291219820Sjeffstatic void
292219820Sjeffauxio_free_resource(struct auxio_softc *sc)
293219820Sjeff{
294219820Sjeff	int i, n;
295219820Sjeff
296219820Sjeff	n = sc->sc_nauxio;
297219820Sjeff	for (i = 0; i < n; i++)
298219820Sjeff		if (sc->sc_res[i])
299219820Sjeff			bus_release_resource(sc->sc_dev,
300219820Sjeff			    (sc->sc_flags & AUXIO_SBUS) ? SYS_RES_MEMORY :
301219820Sjeff			    SYS_RES_IOPORT, sc->sc_rid[i], sc->sc_res[i]);
302219820Sjeff	AUXIO_LOCK_DESTROY(sc);
303219820Sjeff}
304219820Sjeff
305219820Sjeffstatic int
306219820Sjeffauxio_sbus_attach(device_t dev)
307219820Sjeff{
308219820Sjeff	struct auxio_softc *sc;
309219820Sjeff	struct resource *res;
310219820Sjeff
311219820Sjeff	sc = device_get_softc(dev);
312219820Sjeff	bzero(sc, sizeof(*sc));
313219820Sjeff	sc->sc_dev = dev;
314219820Sjeff
315219820Sjeff	AUXIO_LOCK_INIT(sc);
316219820Sjeff	sc->sc_nauxio = 1;
317219820Sjeff	sc->sc_flags = AUXIO_LEDONLY | AUXIO_SBUS;
318219820Sjeff	sc->sc_rid[AUXIO_PCIO_LED] = 0;
319219820Sjeff	res = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
320219820Sjeff	    &sc->sc_rid[AUXIO_PCIO_LED], RF_ACTIVE);
321219820Sjeff	if (res == NULL) {
322219820Sjeff		device_printf(sc->sc_dev, "could not allocate resources\n");
323219820Sjeff		goto attach_fail;
324219820Sjeff	}
325219820Sjeff	sc->sc_res[AUXIO_PCIO_LED] = res;
326219820Sjeff	sc->sc_regt[AUXIO_PCIO_LED] = rman_get_bustag(res);
327	sc->sc_regh[AUXIO_PCIO_LED] = rman_get_bushandle(res);
328	auxio_attach_common(sc);
329	return (0);
330
331attach_fail:
332	auxio_free_resource(sc);
333
334	return (ENXIO);
335}
336