1 /* $OpenBSD: lasi.c,v 1.23 2018/05/14 13:54:39 kettenis Exp $ */
2
3 /*
4 * Copyright (c) 1998-2003 Michael Shalayeff
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 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 * IN NO EVENT SHALL THE AUTHOR OR HIS RELATIVES BE LIABLE FOR ANY DIRECT,
20 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
22 * SERVICES; LOSS OF MIND, USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
24 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
25 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
26 * THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29 #undef LASIDEBUG
30
31 #include <sys/param.h>
32 #include <sys/systm.h>
33 #include <sys/device.h>
34 #include <sys/reboot.h>
35
36 #include <machine/bus.h>
37 #include <machine/iomod.h>
38 #include <machine/reg.h>
39 #include <machine/autoconf.h>
40
41 #include <hppa/dev/cpudevs.h>
42
43 #include <hppa/gsc/gscbusvar.h>
44
45 #define LASI_IOMASK 0xfff00000
46
47 struct lasi_hwr {
48 u_int32_t lasi_power;
49 #define LASI_BLINK 0x01
50 #define LASI_OFF 0x02
51 u_int32_t lasi_error;
52 u_int32_t lasi_version;
53 u_int32_t lasi_reset;
54 u_int32_t lasi_arbmask;
55 };
56
57 struct lasi_softc {
58 struct device sc_dev;
59
60 struct lasi_hwr volatile *sc_hw;
61 struct gsc_attach_args ga; /* for deferred attach */
62 };
63
64 int lasimatch(struct device *, void *, void *);
65 void lasiattach(struct device *, struct device *, void *);
66
67 const struct cfattach lasi_ca = {
68 sizeof(struct lasi_softc), lasimatch, lasiattach
69 };
70
71 struct cfdriver lasi_cd = {
72 NULL, "lasi", DV_DULL
73 };
74
75 void lasi_cold_hook(int on);
76 void lasi_gsc_attach(struct device *self);
77
78 int
lasimatch(parent,cfdata,aux)79 lasimatch(parent, cfdata, aux)
80 struct device *parent;
81 void *cfdata;
82 void *aux;
83 {
84 struct confargs *ca = aux;
85 /* struct cfdata *cf = cfdata; */
86
87 if (ca->ca_type.iodc_type != HPPA_TYPE_BHA ||
88 ca->ca_type.iodc_sv_model != HPPA_BHA_LASI)
89 return 0;
90
91 return 1;
92 }
93
94 void
lasiattach(parent,self,aux)95 lasiattach(parent, self, aux)
96 struct device *parent;
97 struct device *self;
98 void *aux;
99 {
100 struct lasi_softc *sc = (struct lasi_softc *)self;
101 struct confargs *ca = aux;
102 struct gscbus_ic *ic;
103 bus_space_handle_t ioh, ioh2;
104 int s;
105
106 if (bus_space_map(ca->ca_iot, ca->ca_hpa,
107 IOMOD_HPASIZE, 0, &ioh)) {
108 printf(": can't map TRS space\n");
109 return;
110 }
111
112 if (bus_space_map(ca->ca_iot, ca->ca_hpa + 0xc000,
113 IOMOD_HPASIZE, 0, &ioh2)) {
114 bus_space_unmap(ca->ca_iot, ioh, IOMOD_HPASIZE);
115 printf(": can't map IO space\n");
116 return;
117 }
118
119 sc->sc_hw = (struct lasi_hwr *)(ca->ca_hpa + 0xc000);
120 ic = (struct gscbus_ic *)ca->ca_hpa;
121
122 /* XXX should we reset the chip here? */
123
124 printf(": rev %d.%d\n", (sc->sc_hw->lasi_version & 0xf0) >> 4,
125 sc->sc_hw->lasi_version & 0xf);
126
127 /* interrupts guts */
128 s = splhigh();
129 ic->iar = 0; /* will be set up by gsc when attaching */
130 ic->icr = 0;
131 ic->imr = ~0U;
132 (void)ic->irr;
133 ic->imr = 0;
134 splx(s);
135
136 #ifdef USELEDS
137 /* figure out the leds address */
138 switch (cpu_hvers) {
139 case HPPA_BOARD_HP712_60:
140 case HPPA_BOARD_HP712_80:
141 case HPPA_BOARD_HP712_100:
142 case HPPA_BOARD_HP743I_64:
143 case HPPA_BOARD_HP743I_100:
144 case HPPA_BOARD_HP712_120:
145 break; /* only has one led. works different */
146
147 case HPPA_BOARD_HP715_64:
148 case HPPA_BOARD_HP715_80:
149 case HPPA_BOARD_HP715_100:
150 case HPPA_BOARD_HP715_100XC:
151 case HPPA_BOARD_HP725_100:
152 case HPPA_BOARD_HP725_120:
153 if (bus_space_map(ca->ca_iot, ca->ca_hpa - 0x20000,
154 4, 0, (bus_space_handle_t *)&machine_ledaddr))
155 machine_ledaddr = NULL;
156 machine_ledword = 1;
157 break;
158
159 case HPPA_BOARD_HP800_A180C:
160 case HPPA_BOARD_HP778_B132L:
161 case HPPA_BOARD_HP778_B132LP:
162 case HPPA_BOARD_HP778_B160L:
163 case HPPA_BOARD_HP778_B180L:
164 case HPPA_BOARD_HP780_C100:
165 case HPPA_BOARD_HP780_C110:
166 case HPPA_BOARD_HP779_C132L:
167 case HPPA_BOARD_HP779_C160L:
168 case HPPA_BOARD_HP779_C180L:
169 case HPPA_BOARD_HP779_C160L1:
170 if (bus_space_map(ca->ca_iot, 0xf0190000,
171 4, 0, (bus_space_handle_t *)&machine_ledaddr))
172 machine_ledaddr = NULL;
173 machine_ledword = 1;
174 break;
175
176 default:
177 machine_ledaddr = (u_int8_t *)sc->sc_hw;
178 machine_ledword = 1;
179 break;
180 }
181 #endif
182
183 sc->ga.ga_ca = *ca; /* clone from us */
184 if (!strcmp(parent->dv_xname, "mainbus0")) {
185 sc->ga.ga_dp.dp_bc[0] = sc->ga.ga_dp.dp_bc[1];
186 sc->ga.ga_dp.dp_bc[1] = sc->ga.ga_dp.dp_bc[2];
187 sc->ga.ga_dp.dp_bc[2] = sc->ga.ga_dp.dp_bc[3];
188 sc->ga.ga_dp.dp_bc[3] = sc->ga.ga_dp.dp_bc[4];
189 sc->ga.ga_dp.dp_bc[4] = sc->ga.ga_dp.dp_bc[5];
190 sc->ga.ga_dp.dp_bc[5] = sc->ga.ga_dp.dp_mod;
191 sc->ga.ga_dp.dp_mod = 0;
192 }
193 sc->ga.ga_name = "gsc";
194 sc->ga.ga_hpamask = LASI_IOMASK;
195 sc->ga.ga_parent = gsc_lasi;
196 sc->ga.ga_ic = ic;
197 if (sc->sc_dev.dv_unit)
198 config_defer(self, lasi_gsc_attach);
199 else {
200 extern void (*cold_hook)(int);
201
202 lasi_gsc_attach(self);
203 /* could be already set by power(4) */
204 if (!cold_hook)
205 cold_hook = lasi_cold_hook;
206 }
207 }
208
209 void
lasi_gsc_attach(self)210 lasi_gsc_attach(self)
211 struct device *self;
212 {
213 struct lasi_softc *sc = (struct lasi_softc *)self;
214
215 config_found(self, &sc->ga, gscprint);
216 }
217
218 void
lasi_cold_hook(on)219 lasi_cold_hook(on)
220 int on;
221 {
222 struct lasi_softc *sc = lasi_cd.cd_devs[0];
223
224 if (!sc)
225 return;
226
227 switch (on) {
228 case HPPA_COLD_COLD:
229 sc->sc_hw->lasi_power = LASI_BLINK;
230 break;
231 case HPPA_COLD_HOT:
232 sc->sc_hw->lasi_power = 0;
233 break;
234 case HPPA_COLD_OFF:
235 sc->sc_hw->lasi_power = LASI_OFF;
236 break;
237 }
238 }
239