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