1 /* $OpenBSD: auxio.c,v 1.10 2022/10/16 01:22:39 jsg Exp $ */
2 /* $NetBSD: auxio.c,v 1.1 2000/04/15 03:08:13 mrg Exp $ */
3
4 /*
5 * Copyright (c) 2000 Matthew R. Green
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
22 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
24 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
25 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 */
29
30 /*
31 * AUXIO registers support on the sbus & ebus2.
32 */
33
34 #include <sys/param.h>
35 #include <sys/systm.h>
36 #include <sys/errno.h>
37 #include <sys/device.h>
38 #include <sys/timeout.h>
39 #include <sys/kernel.h>
40
41 #include <machine/autoconf.h>
42 #include <machine/cpu.h>
43
44 #include <sparc64/dev/ebusreg.h>
45 #include <sparc64/dev/ebusvar.h>
46 #include <sparc64/dev/sbusvar.h>
47 #include <sparc64/dev/auxioreg.h>
48 #include <sparc64/dev/auxiovar.h>
49
50 #define AUXIO_ROM_NAME "auxio"
51
52 /*
53 * ebus code.
54 */
55 int auxio_ebus_match(struct device *, void *, void *);
56 void auxio_ebus_attach(struct device *, struct device *, void *);
57 int auxio_sbus_match(struct device *, void *, void *);
58 void auxio_sbus_attach(struct device *, struct device *, void *);
59 void auxio_attach_common(struct auxio_softc *);
60
61 const struct cfattach auxio_ebus_ca = {
62 sizeof(struct auxio_softc), auxio_ebus_match, auxio_ebus_attach
63 };
64
65 const struct cfattach auxio_sbus_ca = {
66 sizeof(struct auxio_softc), auxio_sbus_match, auxio_sbus_attach
67 };
68
69 struct cfdriver auxio_cd = {
70 NULL, "auxio", DV_DULL
71 };
72
73 void auxio_led_blink(void *, int);
74
75 int
auxio_ebus_match(struct device * parent,void * cf,void * aux)76 auxio_ebus_match(struct device *parent, void *cf, void *aux)
77 {
78 struct ebus_attach_args *ea = aux;
79
80 return (strcmp(AUXIO_ROM_NAME, ea->ea_name) == 0);
81 }
82
83 void
auxio_ebus_attach(struct device * parent,struct device * self,void * aux)84 auxio_ebus_attach(struct device *parent, struct device *self, void *aux)
85 {
86 struct auxio_softc *sc = (struct auxio_softc *)self;
87 struct ebus_attach_args *ea = aux;
88
89 if (ea->ea_nregs < 1 || ea->ea_nvaddrs < 1) {
90 printf(": no registers??\n");
91 return;
92 }
93
94 sc->sc_tag = ea->ea_memtag;
95
96 if (ea->ea_nregs != 5 || ea->ea_nvaddrs != 5) {
97 printf(": not 5 (%d) registers, only setting led",
98 ea->ea_nregs);
99 sc->sc_flags = AUXIO_LEDONLY|AUXIO_EBUS;
100 } else {
101 sc->sc_flags = AUXIO_EBUS;
102 if (bus_space_map(sc->sc_tag, ea->ea_vaddrs[2],
103 sizeof(u_int32_t), BUS_SPACE_MAP_PROMADDRESS,
104 &sc->sc_freq)) {
105 printf(": unable to map freq\n");
106 return;
107 }
108 if (bus_space_map(sc->sc_tag, ea->ea_vaddrs[3],
109 sizeof(u_int32_t), BUS_SPACE_MAP_PROMADDRESS,
110 &sc->sc_scsi)) {
111 printf(": unable to map SCSI\n");
112 return;
113 }
114 if (bus_space_map(sc->sc_tag, ea->ea_vaddrs[4],
115 sizeof(u_int32_t), BUS_SPACE_MAP_PROMADDRESS,
116 &sc->sc_temp)) {
117 printf(": unable to map temp\n");
118 return;
119 }
120 }
121
122 if (bus_space_map(sc->sc_tag, ea->ea_vaddrs[0], sizeof(u_int32_t),
123 BUS_SPACE_MAP_PROMADDRESS, &sc->sc_led)) {
124 printf(": unable to map LED\n");
125 return;
126 }
127
128 auxio_attach_common(sc);
129 }
130
131 int
auxio_sbus_match(struct device * parent,void * cf,void * aux)132 auxio_sbus_match(struct device *parent, void *cf, void *aux)
133 {
134 struct sbus_attach_args *sa = aux;
135
136 return (strcmp(AUXIO_ROM_NAME, sa->sa_name) == 0);
137 }
138
139 void
auxio_sbus_attach(struct device * parent,struct device * self,void * aux)140 auxio_sbus_attach(struct device *parent, struct device *self, void *aux)
141 {
142 struct auxio_softc *sc = (struct auxio_softc *)self;
143 struct sbus_attach_args *sa = aux;
144
145 sc->sc_tag = sa->sa_bustag;
146
147 if (sa->sa_nreg < 1 || sa->sa_npromvaddrs < 1) {
148 printf(": no registers??\n");
149 return;
150 }
151
152 if (sa->sa_nreg != 1 || sa->sa_npromvaddrs != 1) {
153 printf(": not 1 (%d/%d) registers??", sa->sa_nreg, sa->sa_npromvaddrs);
154 return;
155 }
156
157 /* sbus auxio only has one set of registers */
158 sc->sc_flags = AUXIO_LEDONLY|AUXIO_SBUS;
159 if (bus_space_map(sc->sc_tag, sa->sa_promvaddr, 1,
160 BUS_SPACE_MAP_PROMADDRESS, &sc->sc_led)) {
161 printf(": couldn't map registers\n");
162 return;
163 }
164
165 auxio_attach_common(sc);
166 }
167
168 void
auxio_attach_common(struct auxio_softc * sc)169 auxio_attach_common(struct auxio_softc *sc)
170 {
171 sc->sc_blink.bl_func = auxio_led_blink;
172 sc->sc_blink.bl_arg = sc;
173 blink_led_register(&sc->sc_blink);
174 printf("\n");
175 }
176
177 void
auxio_led_blink(void * vsc,int on)178 auxio_led_blink(void *vsc, int on)
179 {
180 struct auxio_softc *sc = vsc;
181 u_int32_t led;
182 int s;
183
184 s = splhigh();
185
186 if (sc->sc_flags & AUXIO_EBUS)
187 led = letoh32(bus_space_read_4(sc->sc_tag, sc->sc_led, 0));
188 else
189 led = bus_space_read_1(sc->sc_tag, sc->sc_led, 0);
190
191 if (on)
192 led |= AUXIO_LED_LED;
193 else
194 led &= ~AUXIO_LED_LED;
195
196 if (sc->sc_flags & AUXIO_EBUS)
197 bus_space_write_4(sc->sc_tag, sc->sc_led, 0, htole32(led));
198 else
199 bus_space_write_1(sc->sc_tag, sc->sc_led, 0, led);
200
201 splx(s);
202 }
203
204 int
auxio_fd_control(u_int32_t bits)205 auxio_fd_control(u_int32_t bits)
206 {
207 struct auxio_softc *sc;
208 u_int32_t led;
209
210 if (auxio_cd.cd_ndevs == 0) {
211 return ENXIO;
212 }
213
214 /*
215 * XXX This does not handle > 1 auxio correctly.
216 * We'll assume the floppy drive is tied to first auxio found.
217 */
218 sc = (struct auxio_softc *)auxio_cd.cd_devs[0];
219 if (sc->sc_flags & AUXIO_EBUS)
220 led = letoh32(bus_space_read_4(sc->sc_tag, sc->sc_led, 0));
221 else
222 led = bus_space_read_1(sc->sc_tag, sc->sc_led, 0);
223
224 led = (led & ~AUXIO_LED_FLOPPY_MASK) | bits;
225
226 if (sc->sc_flags & AUXIO_EBUS)
227 bus_space_write_4(sc->sc_tag, sc->sc_led, 0, htole32(led));
228 else
229 bus_space_write_1(sc->sc_tag, sc->sc_led, 0, led);
230
231 return 0;
232 }
233