1136301Syongari/*-
2136301Syongari * Copyright (c) 2004 Pyun YongHyeon
3136301Syongari * All rights reserved.
4136301Syongari *
5136301Syongari * Redistribution and use in source and binary forms, with or without
6136301Syongari * modification, are permitted provided that the following conditions
7136301Syongari * are met:
8136301Syongari * 1. Redistributions of source code must retain the above copyright
9136301Syongari *    notice, this list of conditions and the following disclaimer.
10136301Syongari * 2. Redistributions in binary form must reproduce the above copyright
11136301Syongari *    notice, this list of conditions and the following disclaimer in the
12136301Syongari *    documentation and/or other materials provided with the distribution.
13136301Syongari *
14136301Syongari * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15136301Syongari * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16136301Syongari * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17136301Syongari * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18136301Syongari * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19136301Syongari * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20136301Syongari * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21136301Syongari * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22136301Syongari * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23136301Syongari * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24136301Syongari * SUCH DAMAGE.
25136301Syongari *
26136301Syongari */
27136301Syongari
28136301Syongari/*	$NetBSD: auxio.c,v 1.11 2003/07/15 03:36:04 lukem Exp $	*/
29136301Syongari
30139749Simp/*-
31136301Syongari * Copyright (c) 2000, 2001 Matthew R. Green
32136301Syongari * All rights reserved.
33136301Syongari *
34136301Syongari * Redistribution and use in source and binary forms, with or without
35136301Syongari * modification, are permitted provided that the following conditions
36136301Syongari * are met:
37136301Syongari * 1. Redistributions of source code must retain the above copyright
38136301Syongari *    notice, this list of conditions and the following disclaimer.
39136301Syongari * 2. Redistributions in binary form must reproduce the above copyright
40136301Syongari *    notice, this list of conditions and the following disclaimer in the
41136301Syongari *    documentation and/or other materials provided with the distribution.
42136301Syongari * 3. The name of the author may not be used to endorse or promote products
43136301Syongari *    derived from this software without specific prior written permission.
44136301Syongari *
45136301Syongari * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
46136301Syongari * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
47136301Syongari * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
48136301Syongari * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
49136301Syongari * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
50136301Syongari * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
51136301Syongari * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
52136301Syongari * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
53136301Syongari * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
54136301Syongari * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
55136301Syongari * SUCH DAMAGE.
56136301Syongari */
57136301Syongari
58136301Syongari/*
59200815Smarius * AUXIO registers support on the SBus & EBus2, used for the floppy driver
60136301Syongari * and to control the system LED, for the BLINK option.
61136301Syongari */
62136301Syongari
63136301Syongari#include <sys/cdefs.h>
64136301Syongari__FBSDID("$FreeBSD$");
65136301Syongari
66136301Syongari#include <sys/param.h>
67136301Syongari#include <sys/systm.h>
68136301Syongari#include <sys/bus.h>
69136301Syongari#include <sys/kernel.h>
70136301Syongari#include <sys/lock.h>
71136301Syongari#include <sys/module.h>
72136301Syongari#include <sys/mutex.h>
73136301Syongari#include <sys/resource.h>
74136301Syongari#include <sys/rman.h>
75136301Syongari
76136301Syongari#include <dev/led/led.h>
77136301Syongari#include <dev/ofw/ofw_bus.h>
78136301Syongari#include <dev/ofw/openfirm.h>
79136301Syongari
80136301Syongari#include <machine/bus.h>
81136301Syongari#include <machine/ofw_machdep.h>
82136301Syongari#include <machine/resource.h>
83136301Syongari
84136301Syongari#include <sparc64/sbus/sbusvar.h>
85136301Syongari#include <dev/auxio/auxioreg.h>
86136301Syongari
87136301Syongari/*
88200815Smarius * On sun4u, auxio exists with one register (LED) on the SBus, and 5
89200815Smarius * registers on the EBus2 (pci) (LED, PCIMODE, FREQUENCY, SCSI
90136301Syongari * OSCILLATOR, and TEMP SENSE.
91136301Syongari */
92136301Syongari
93136301Syongari#define AUXIO_PCIO_LED	0
94136301Syongari#define AUXIO_PCIO_PCI	1
95136301Syongari#define AUXIO_PCIO_FREQ	2
96136301Syongari#define AUXIO_PCIO_OSC	3
97136301Syongari#define AUXIO_PCIO_TEMP	4
98147877Smarius#define AUXIO_PCIO_NREG	5
99136301Syongari
100136301Syongaristruct auxio_softc {
101136301Syongari	struct device		*sc_dev;
102136301Syongari
103136301Syongari	int			sc_nauxio;
104147877Smarius	struct resource		*sc_res[AUXIO_PCIO_NREG];
105147877Smarius	int			sc_rid[AUXIO_PCIO_NREG];
106147877Smarius	bus_space_tag_t		sc_regt[AUXIO_PCIO_NREG];
107147877Smarius	bus_space_handle_t	sc_regh[AUXIO_PCIO_NREG];
108136301Syongari	struct cdev		*sc_led_dev;
109136301Syongari	u_int32_t		sc_led_stat;
110136301Syongari
111136301Syongari	int			sc_flags;
112136301Syongari#define	AUXIO_LEDONLY		0x1
113136301Syongari#define	AUXIO_EBUS		0x2
114136301Syongari#define	AUXIO_SBUS		0x4
115136301Syongari
116136301Syongari	struct mtx		sc_lock;
117136301Syongari};
118136301Syongari
119136301Syongaristatic void	auxio_led_func(void *arg, int onoff);
120146965Smariusstatic int	auxio_attach_common(struct auxio_softc *);
121136301Syongaristatic int	auxio_bus_probe(device_t);
122136301Syongaristatic int	auxio_sbus_attach(device_t);
123136301Syongaristatic int	auxio_ebus_attach(device_t);
124136301Syongaristatic int	auxio_bus_detach(device_t);
125136301Syongaristatic void	auxio_free_resource(struct auxio_softc *);
126136301Syongaristatic __inline u_int32_t auxio_led_read(struct auxio_softc *);
127136301Syongaristatic __inline void auxio_led_write(struct auxio_softc *, u_int32_t);
128136301Syongari
129136301Syongari/* SBus */
130136301Syongaristatic device_method_t auxio_sbus_methods[] = {
131136301Syongari	DEVMETHOD(device_probe,		auxio_bus_probe),
132136301Syongari	DEVMETHOD(device_attach,	auxio_sbus_attach),
133136301Syongari	DEVMETHOD(device_detach,	auxio_bus_detach),
134246128Ssbz
135246128Ssbz	DEVMETHOD_END
136136301Syongari};
137136301Syongari
138136301Syongaristatic driver_t auxio_sbus_driver = {
139136301Syongari	"auxio",
140136301Syongari	auxio_sbus_methods,
141136301Syongari	sizeof(struct auxio_softc)
142136301Syongari};
143136301Syongari
144136301Syongaristatic devclass_t	auxio_devclass;
145200874Smarius/* The probe order is handled by sbus(4). */
146200874SmariusEARLY_DRIVER_MODULE(auxio, sbus, auxio_sbus_driver, auxio_devclass, 0, 0,
147200874Smarius    BUS_PASS_DEFAULT);
148200815SmariusMODULE_DEPEND(auxio, sbus, 1, 1, 1);
149136301Syongari
150136301Syongari/* EBus */
151136301Syongaristatic device_method_t auxio_ebus_methods[] = {
152136301Syongari	DEVMETHOD(device_probe,		auxio_bus_probe),
153136301Syongari	DEVMETHOD(device_attach,	auxio_ebus_attach),
154136301Syongari	DEVMETHOD(device_detach,	auxio_bus_detach),
155246128Ssbz
156246128Ssbz	DEVMETHOD_END
157136301Syongari};
158136301Syongari
159136301Syongaristatic driver_t auxio_ebus_driver = {
160136301Syongari	"auxio",
161136301Syongari	auxio_ebus_methods,
162136301Syongari	sizeof(struct auxio_softc)
163136301Syongari};
164136301Syongari
165200874SmariusEARLY_DRIVER_MODULE(auxio, ebus, auxio_ebus_driver, auxio_devclass, 0, 0,
166200874Smarius    BUS_PASS_DEFAULT);
167200815SmariusMODULE_DEPEND(auxio, ebus, 1, 1, 1);
168136301SyongariMODULE_VERSION(auxio, 1);
169136301Syongari
170136301Syongari#define AUXIO_LOCK_INIT(sc)	\
171136301Syongari	mtx_init(&sc->sc_lock, "auxio mtx", NULL, MTX_DEF)
172136301Syongari#define AUXIO_LOCK(sc)		mtx_lock(&sc->sc_lock)
173136301Syongari#define AUXIO_UNLOCK(sc)	mtx_unlock(&sc->sc_lock)
174136301Syongari#define AUXIO_LOCK_DESTROY(sc)	mtx_destroy(&sc->sc_lock)
175136301Syongari
176136301Syongaristatic __inline void
177136301Syongariauxio_led_write(struct auxio_softc *sc, u_int32_t v)
178136301Syongari{
179136301Syongari	if (sc->sc_flags & AUXIO_EBUS)
180136301Syongari		bus_space_write_4(sc->sc_regt[AUXIO_PCIO_LED],
181136301Syongari		    sc->sc_regh[AUXIO_PCIO_LED], 0, v);
182136301Syongari	else
183136301Syongari		bus_space_write_1(sc->sc_regt[AUXIO_PCIO_LED],
184136301Syongari		    sc->sc_regh[AUXIO_PCIO_LED], 0, v);
185136301Syongari}
186136301Syongari
187136301Syongaristatic __inline u_int32_t
188136301Syongariauxio_led_read(struct auxio_softc *sc)
189136301Syongari{
190136301Syongari	u_int32_t led;
191136301Syongari
192136301Syongari	if (sc->sc_flags & AUXIO_EBUS)
193136301Syongari		led = bus_space_read_4(sc->sc_regt[AUXIO_PCIO_LED],
194136301Syongari		    sc->sc_regh[AUXIO_PCIO_LED], 0);
195136301Syongari	else
196136301Syongari		led = bus_space_read_1(sc->sc_regt[AUXIO_PCIO_LED],
197136301Syongari		    sc->sc_regh[AUXIO_PCIO_LED], 0);
198136301Syongari
199136301Syongari	return (led);
200136301Syongari}
201136301Syongari
202136301Syongaristatic void
203136301Syongariauxio_led_func(void *arg, int onoff)
204136301Syongari{
205136301Syongari	struct auxio_softc *sc;
206136301Syongari	u_int32_t led;
207136301Syongari
208136301Syongari	sc = (struct auxio_softc *)arg;
209136301Syongari
210136301Syongari	AUXIO_LOCK(sc);
211154864Smarius	/*
212154864Smarius	 * NB: We must not touch the other bits of the SBus AUXIO reg.
213154864Smarius	 */
214154864Smarius	led = auxio_led_read(sc);
215154864Smarius	if (onoff)
216154864Smarius		led |= AUXIO_LED_LED;
217154864Smarius	else
218154864Smarius		led &= ~AUXIO_LED_LED;
219136301Syongari	auxio_led_write(sc, led);
220136301Syongari	AUXIO_UNLOCK(sc);
221136301Syongari}
222136301Syongari
223136301Syongaristatic int
224136301Syongariauxio_bus_probe(device_t dev)
225136301Syongari{
226136301Syongari	const char *name;
227136301Syongari
228136301Syongari	name = ofw_bus_get_name(dev);
229136301Syongari	if (strcmp("auxio", name) == 0) {
230136301Syongari		device_set_desc(dev, "Sun Auxiliary I/O");
231136301Syongari		return (0);
232136301Syongari	}
233136301Syongari
234136301Syongari	return (ENXIO);
235136301Syongari}
236136301Syongari
237136301Syongaristatic int
238136301Syongariauxio_ebus_attach(device_t dev)
239136301Syongari{
240136301Syongari	struct auxio_softc *sc;
241136301Syongari
242136301Syongari	sc = device_get_softc(dev);
243136301Syongari	sc->sc_dev = dev;
244136301Syongari
245136301Syongari	AUXIO_LOCK_INIT(sc);
246147877Smarius	sc->sc_nauxio = AUXIO_PCIO_NREG;
247146965Smarius	sc->sc_flags = AUXIO_LEDONLY | AUXIO_EBUS;
248146965Smarius
249146965Smarius	return(auxio_attach_common(sc));
250146965Smarius}
251146965Smarius
252146965Smariusstatic int
253146965Smariusauxio_attach_common(struct auxio_softc *sc)
254146965Smarius{
255146965Smarius	struct resource *res;
256146965Smarius	int i;
257146965Smarius
258146965Smarius	for (i = 0; i < sc->sc_nauxio; i++) {
259146965Smarius		sc->sc_rid[i] = i;
260146965Smarius		res = bus_alloc_resource_any(sc->sc_dev, SYS_RES_MEMORY,
261136301Syongari		    &sc->sc_rid[i], RF_ACTIVE);
262136301Syongari		if (res == NULL) {
263136301Syongari			device_printf(sc->sc_dev,
264136301Syongari			    "could not allocate resources\n");
265136301Syongari			goto attach_fail;
266136301Syongari		}
267136301Syongari		sc->sc_res[i] = res;
268136301Syongari		sc->sc_regt[i] = rman_get_bustag(res);
269136301Syongari		sc->sc_regh[i] = rman_get_bushandle(res);
270136301Syongari	}
271136301Syongari
272154864Smarius	sc->sc_led_stat = auxio_led_read(sc) & AUXIO_LED_LED;
273146965Smarius	sc->sc_led_dev = led_create(auxio_led_func, sc, "auxioled");
274146965Smarius	/* turn on the LED */
275146965Smarius	auxio_led_func(sc, 1);
276146965Smarius
277136301Syongari	return (0);
278136301Syongari
279136301Syongariattach_fail:
280136301Syongari	auxio_free_resource(sc);
281136301Syongari
282136301Syongari	return (ENXIO);
283136301Syongari}
284136301Syongari
285136301Syongaristatic int
286136301Syongariauxio_bus_detach(device_t dev)
287136301Syongari{
288136301Syongari	struct auxio_softc *sc;
289136301Syongari
290136301Syongari	sc = device_get_softc(dev);
291136301Syongari	led_destroy(sc->sc_led_dev);
292136301Syongari	auxio_led_func(sc, sc->sc_led_stat);
293136301Syongari	auxio_free_resource(sc);
294136301Syongari
295136301Syongari	return (0);
296136301Syongari}
297136301Syongari
298136301Syongaristatic void
299136301Syongariauxio_free_resource(struct auxio_softc *sc)
300136301Syongari{
301146965Smarius	int i;
302136301Syongari
303146965Smarius	for (i = 0; i < sc->sc_nauxio; i++)
304136301Syongari		if (sc->sc_res[i])
305146965Smarius			bus_release_resource(sc->sc_dev, SYS_RES_MEMORY,
306146965Smarius			    sc->sc_rid[i], sc->sc_res[i]);
307136301Syongari	AUXIO_LOCK_DESTROY(sc);
308136301Syongari}
309136301Syongari
310136301Syongaristatic int
311136301Syongariauxio_sbus_attach(device_t dev)
312136301Syongari{
313136301Syongari	struct auxio_softc *sc;
314136301Syongari
315136301Syongari	sc = device_get_softc(dev);
316136301Syongari	sc->sc_dev = dev;
317136301Syongari
318136301Syongari	AUXIO_LOCK_INIT(sc);
319136301Syongari	sc->sc_nauxio = 1;
320136301Syongari	sc->sc_flags = AUXIO_LEDONLY | AUXIO_SBUS;
321136301Syongari
322146965Smarius	return (auxio_attach_common(sc));
323136301Syongari}
324