1 /* $NetBSD: auxio.c,v 1.10 2003/06/16 19:24:51 heas Exp $ */ 2 3 /* 4 * Copyright (c) 2000, 2001 Matthew R. Green 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 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. 15 * 3. The name of the author may not be used to endorse or promote products 16 * derived from this software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 23 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 24 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 25 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 26 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28 * SUCH DAMAGE. 29 */ 30 31 /* 32 * AUXIO registers support on the sbus & ebus2, used for the floppy driver 33 * and to control the system LED, for the BLINK option. 34 */ 35 36 #include "opt_auxio.h" 37 38 #include <sys/param.h> 39 #include <sys/systm.h> 40 #include <sys/kernel.h> 41 #include <sys/callout.h> 42 #include <sys/errno.h> 43 #include <sys/device.h> 44 #include <sys/malloc.h> 45 46 #include <machine/autoconf.h> 47 #include <machine/cpu.h> 48 49 #include <dev/ebus/ebusreg.h> 50 #include <dev/ebus/ebusvar.h> 51 #include <sparc64/dev/sbusvar.h> 52 #include <sparc64/dev/auxioreg.h> 53 54 /* 55 * on sun4u, auxio exists with one register (LED) on the sbus, and 5 56 * registers on the ebus2 (pci) (LED, PCIMODE, FREQUENCY, SCSI 57 * OSCILLATOR, and TEMP SENSE. 58 */ 59 60 struct auxio_softc { 61 struct device sc_dev; 62 63 /* parent's tag */ 64 bus_space_tag_t sc_tag; 65 66 /* handles to the various auxio regsiter sets */ 67 bus_space_handle_t sc_led; 68 bus_space_handle_t sc_pci; 69 bus_space_handle_t sc_freq; 70 bus_space_handle_t sc_scsi; 71 bus_space_handle_t sc_temp; 72 73 int sc_flags; 74 #define AUXIO_LEDONLY 0x1 75 #define AUXIO_EBUS 0x2 76 #define AUXIO_SBUS 0x4 77 }; 78 79 #define AUXIO_ROM_NAME "auxio" 80 81 void auxio_attach_common(struct auxio_softc *); 82 int auxio_ebus_match(struct device *, struct cfdata *, void *); 83 void auxio_ebus_attach(struct device *, struct device *, void *); 84 int auxio_sbus_match(struct device *, struct cfdata *, void *); 85 void auxio_sbus_attach(struct device *, struct device *, void *); 86 87 CFATTACH_DECL(auxio_ebus, sizeof(struct auxio_softc), 88 auxio_ebus_match, auxio_ebus_attach, NULL, NULL); 89 90 CFATTACH_DECL(auxio_sbus, sizeof(struct auxio_softc), 91 auxio_sbus_match, auxio_sbus_attach, NULL, NULL); 92 93 #ifdef BLINK 94 static struct callout blink_ch = CALLOUT_INITIALIZER; 95 96 static void auxio_blink(void *); 97 98 static void 99 auxio_blink(x) 100 void *x; 101 { 102 struct auxio_softc *sc = x; 103 int s; 104 u_int32_t led; 105 106 s = splhigh(); 107 if (sc->sc_flags & AUXIO_EBUS) 108 led = le32toh(bus_space_read_4(sc->sc_tag, sc->sc_led, 0)); 109 else 110 led = bus_space_read_1(sc->sc_tag, sc->sc_led, 0); 111 if (led & AUXIO_LED_LED) 112 led = 0; 113 else 114 led = AUXIO_LED_LED; 115 if (sc->sc_flags & AUXIO_EBUS) 116 bus_space_write_4(sc->sc_tag, sc->sc_led, 0, htole32(led)); 117 else 118 bus_space_write_1(sc->sc_tag, sc->sc_led, 0, led); 119 splx(s); 120 121 /* 122 * Blink rate is: 123 * full cycle every second if completely idle (loadav = 0) 124 * full cycle every 2 seconds if loadav = 1 125 * full cycle every 3 seconds if loadav = 2 126 * etc. 127 */ 128 s = (((averunnable.ldavg[0] + FSCALE) * hz) >> (FSHIFT + 1)); 129 callout_reset(&blink_ch, s, auxio_blink, sc); 130 } 131 #endif 132 133 void 134 auxio_attach_common(sc) 135 struct auxio_softc *sc; 136 { 137 #ifdef BLINK 138 static int do_once = 1; 139 140 /* only start one blinker */ 141 if (do_once) { 142 auxio_blink(sc); 143 do_once = 0; 144 } 145 #endif 146 printf("\n"); 147 } 148 149 int 150 auxio_ebus_match(parent, cf, aux) 151 struct device *parent; 152 struct cfdata *cf; 153 void *aux; 154 { 155 struct ebus_attach_args *ea = aux; 156 157 return (strcmp(AUXIO_ROM_NAME, ea->ea_name) == 0); 158 } 159 160 void 161 auxio_ebus_attach(parent, self, aux) 162 struct device *parent, *self; 163 void *aux; 164 { 165 struct auxio_softc *sc = (struct auxio_softc *)self; 166 struct ebus_attach_args *ea = aux; 167 168 sc->sc_tag = ea->ea_bustag; 169 170 if (ea->ea_nreg < 1) { 171 printf(": no registers??\n"); 172 return; 173 } 174 175 if (ea->ea_nreg != 5) { 176 printf(": not 5 (%d) registers, only setting led", 177 ea->ea_nreg); 178 sc->sc_flags = AUXIO_LEDONLY|AUXIO_EBUS; 179 } else if (ea->ea_nvaddr == 5) { 180 sc->sc_flags = AUXIO_EBUS; 181 182 sparc_promaddr_to_handle(sc->sc_tag, 183 ea->ea_vaddr[1], &sc->sc_pci); 184 sparc_promaddr_to_handle(sc->sc_tag, 185 ea->ea_vaddr[2], &sc->sc_freq); 186 sparc_promaddr_to_handle(sc->sc_tag, 187 ea->ea_vaddr[3], &sc->sc_scsi); 188 sparc_promaddr_to_handle(sc->sc_tag, 189 ea->ea_vaddr[4], &sc->sc_temp); 190 } else { 191 sc->sc_flags = AUXIO_EBUS; 192 bus_space_map(sc->sc_tag, EBUS_ADDR_FROM_REG(&ea->ea_reg[1]), 193 ea->ea_reg[1].size, 0, &sc->sc_pci); 194 bus_space_map(sc->sc_tag, EBUS_ADDR_FROM_REG(&ea->ea_reg[2]), 195 ea->ea_reg[2].size, 0, &sc->sc_freq); 196 bus_space_map(sc->sc_tag, EBUS_ADDR_FROM_REG(&ea->ea_reg[3]), 197 ea->ea_reg[3].size, 0, &sc->sc_scsi); 198 bus_space_map(sc->sc_tag, EBUS_ADDR_FROM_REG(&ea->ea_reg[4]), 199 ea->ea_reg[4].size, 0, &sc->sc_temp); 200 } 201 202 if (ea->ea_nvaddr > 0) { 203 sparc_promaddr_to_handle(sc->sc_tag, 204 ea->ea_vaddr[0], &sc->sc_led); 205 } else { 206 bus_space_map(sc->sc_tag, EBUS_ADDR_FROM_REG(&ea->ea_reg[0]), 207 ea->ea_reg[0].size, 0, &sc->sc_led); 208 } 209 210 auxio_attach_common(sc); 211 } 212 213 int 214 auxio_sbus_match(parent, cf, aux) 215 struct device *parent; 216 struct cfdata *cf; 217 void *aux; 218 { 219 struct sbus_attach_args *sa = aux; 220 221 return (strcmp(AUXIO_ROM_NAME, sa->sa_name) == 0); 222 } 223 224 void 225 auxio_sbus_attach(parent, self, aux) 226 struct device *parent, *self; 227 void *aux; 228 { 229 struct auxio_softc *sc = (struct auxio_softc *)self; 230 struct sbus_attach_args *sa = aux; 231 232 sc->sc_tag = sa->sa_bustag; 233 234 if (sa->sa_nreg < 1) { 235 printf(": no registers??\n"); 236 return; 237 } 238 239 if (sa->sa_nreg != 1) { 240 printf(": not 1 (%d/%d) registers??", sa->sa_nreg, 241 sa->sa_npromvaddrs); 242 return; 243 } 244 245 /* sbus auxio only has one set of registers */ 246 sc->sc_flags = AUXIO_LEDONLY|AUXIO_SBUS; 247 if (sa->sa_npromvaddrs > 0) { 248 sbus_promaddr_to_handle(sc->sc_tag, 249 sa->sa_promvaddr, &sc->sc_led); 250 } else { 251 sbus_bus_map(sc->sc_tag, sa->sa_slot, sa->sa_offset, 252 sa->sa_size, 0, &sc->sc_led); 253 } 254 255 auxio_attach_common(sc); 256 } 257