qec.c revision 1.2 1 /* $NetBSD: qec.c,v 1.2 1998/07/28 00:44:39 pk Exp $ */
2
3 /*-
4 * Copyright (c) 1998 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Paul Kranenburg.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. All advertising materials mentioning features or use of this software
19 * must display the following acknowledgement:
20 * This product includes software developed by the NetBSD
21 * Foundation, Inc. and its contributors.
22 * 4. Neither the name of The NetBSD Foundation nor the names of its
23 * contributors may be used to endorse or promote products derived
24 * from this software without specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36 * POSSIBILITY OF SUCH DAMAGE.
37 */
38
39 #include <sys/types.h>
40 #include <sys/param.h>
41 #include <sys/systm.h>
42 #include <sys/kernel.h>
43 #include <sys/errno.h>
44 #include <sys/ioctl.h>
45 #include <sys/device.h>
46 #include <sys/malloc.h>
47 #include <sys/buf.h>
48 #include <sys/proc.h>
49 #include <sys/user.h>
50
51 #include <machine/bus.h>
52 #include <machine/autoconf.h>
53
54 #include <dev/sbus/sbusvar.h>
55 #include <dev/sbus/qecreg.h>
56 #include <dev/sbus/qecvar.h>
57
58 static int qecprint __P((void *, const char *));
59 static int qecmatch __P((struct device *, struct cfdata *, void *));
60 static void qecattach __P((struct device *, struct device *, void *));
61
62 static int qec_bus_map __P((
63 bus_space_tag_t,
64 bus_type_t, /*slot*/
65 bus_addr_t, /*offset*/
66 bus_size_t, /*size*/
67 int, /*flags*/
68 vm_offset_t, /*preferred virtual address */
69 bus_space_handle_t *));
70
71 struct cfattach qec_ca = {
72 sizeof(struct qec_softc), qecmatch, qecattach
73 };
74
75 int
76 qecprint(aux, busname)
77 void *aux;
78 const char *busname;
79 {
80 struct sbus_attach_args *sa = aux;
81 bus_space_tag_t t = sa->sa_bustag;
82 struct qec_softc *sc = t->cookie;
83
84 sa->sa_bustag = sc->sc_bustag; /* XXX */
85 sbus_print(aux, busname); /* XXX */
86 sa->sa_bustag = t; /* XXX */
87 return (UNCONF);
88 }
89
90 int
91 qecmatch(parent, cf, aux)
92 struct device *parent;
93 struct cfdata *cf;
94 void *aux;
95 {
96 struct sbus_attach_args *sa = aux;
97
98 return (strcmp(cf->cf_driver->cd_name, sa->sa_name) == 0);
99 }
100
101 /*
102 * Attach all the sub-devices we can find
103 */
104 void
105 qecattach(parent, self, aux)
106 struct device *parent, *self;
107 void *aux;
108 {
109 struct sbus_attach_args *sa = aux;
110 struct qec_softc *sc = (void *)self;
111 int node;
112 int sbusburst;
113 bus_space_tag_t sbt;
114 bus_space_handle_t bh;
115 struct bootpath *bp;
116 int error;
117 int nreg;
118 struct rom_reg *rr;
119
120 sc->sc_bustag = sa->sa_bustag;
121 sc->sc_dmatag = sa->sa_dmatag;
122 node = sa->sa_node;
123
124 rr = NULL;
125 if (getpropA(node, "reg", sizeof(struct rom_reg),
126 &nreg, (void **)&rr) != 0) {
127 printf("%s: cannot get register property\n", self->dv_xname);
128 return;
129 }
130 if (nreg < 2) {
131 printf("%s: only %d register sets\n", self->dv_xname, nreg);
132 return;
133 }
134
135 if (sbus_bus_map(sa->sa_bustag,
136 (bus_type_t)rr[0].rr_iospace,
137 (bus_addr_t)rr[0].rr_paddr,
138 (bus_size_t)rr[0].rr_len,
139 BUS_SPACE_MAP_LINEAR, 0, &bh) != 0) {
140 printf("%s: attach: cannot map registers\n", self->dv_xname);
141 return;
142 }
143 sc->sc_regs = (void *)bh;
144
145 /*
146 * This device's "register space 1" is just a buffer where the
147 * Lance ring-buffers can be stored. Note the buffer's location
148 * and size, so the child driver can pick them up.
149 */
150 if (sbus_bus_map(sa->sa_bustag,
151 (bus_type_t)rr[1].rr_iospace,
152 (bus_addr_t)rr[1].rr_paddr,
153 (bus_size_t)rr[1].rr_len,
154 BUS_SPACE_MAP_LINEAR, 0, &bh) != 0) {
155 printf("%s: attach: cannot map registers\n", self->dv_xname);
156 return;
157 }
158 sc->sc_buffer = (caddr_t)bh;
159 sc->sc_bufsiz = (bus_size_t)rr[1].rr_len;
160
161 /*
162 * Get transfer burst size from PROM
163 */
164 sbusburst = ((struct sbus_softc *)parent)->sc_burst;
165 if (sbusburst == 0)
166 sbusburst = SBUS_BURST_32 - 1; /* 1->16 */
167
168 sc->sc_burst = getpropint(node, "burst-sizes", -1);
169 if (sc->sc_burst == -1)
170 /* take SBus burst sizes */
171 sc->sc_burst = sbusburst;
172
173 /* Clamp at parent's burst sizes */
174 sc->sc_burst &= sbusburst;
175
176 sbus_establish(&sc->sc_sd, &sc->sc_dev);
177
178
179 /*
180 * Collect address translations from the OBP.
181 */
182 error = getpropA(node, "ranges", sizeof(struct rom_range),
183 &sc->sc_nrange, (void **)&sc->sc_range);
184 switch (error) {
185 case 0:
186 break;
187 case ENOENT:
188 default:
189 panic("%s: error getting ranges property", self->dv_xname);
190 }
191
192 /* Propagate bootpath */
193 if (sa->sa_bp != NULL)
194 bp = sa->sa_bp + 1;
195 else
196 bp = NULL;
197
198 /* Allocate a bus tag */
199 sbt = (bus_space_tag_t)
200 malloc(sizeof(struct sparc_bus_space_tag), M_DEVBUF, M_NOWAIT);
201 if (sbt == NULL) {
202 printf("%s: attach: out of memory\n", self->dv_xname);
203 return;
204 }
205
206 bzero(sbt, sizeof *sbt);
207 sbt->cookie = sc;
208 sbt->parent = sc->sc_bustag;
209 sbt->sparc_bus_map = qec_bus_map;
210
211 printf(": %dK memory\n", sc->sc_bufsiz / 1024);
212
213 /* search through children */
214 for (node = firstchild(node); node; node = nextsibling(node)) {
215 struct sbus_attach_args sa;
216 sbus_setup_attach_args((struct sbus_softc *)parent,
217 sbt, sc->sc_dmatag, node, bp, &sa);
218 (void)config_found(&sc->sc_dev, (void *)&sa, qecprint);
219 }
220 free(rr, M_DEVBUF);
221 }
222
223 int
224 qec_bus_map(t, btype, offset, size, flags, vaddr, hp)
225 bus_space_tag_t t;
226 bus_type_t btype;
227 bus_addr_t offset;
228 bus_size_t size;
229 int flags;
230 vm_offset_t vaddr;
231 bus_space_handle_t *hp;
232 {
233 struct qec_softc *sc = t->cookie;
234 int slot = btype;
235 int i;
236
237 for (i = 0; i < sc->sc_nrange; i++) {
238 bus_addr_t paddr;
239 bus_type_t iospace;
240
241 if (sc->sc_range[i].cspace != slot)
242 continue;
243
244 /* We've found the connection to the parent bus */
245 paddr = sc->sc_range[i].poffset + offset;
246 iospace = sc->sc_range[i].pspace;
247 return (bus_space_map2(sc->sc_bustag, iospace, paddr,
248 size, flags, vaddr, hp));
249 }
250
251 return (EINVAL);
252 }
253