1 /*-
2 * SPDX-License-Identifier: BSD-3-Clause
3 *
4 * Copyright 2006 by Juniper Networks.
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 #include <sys/param.h>
32 #include <sys/systm.h>
33 #include <sys/bus.h>
34 #include <sys/conf.h>
35 #include <sys/endian.h>
36 #include <sys/kernel.h>
37 #include <sys/malloc.h>
38 #include <sys/queue.h>
39 #include <sys/serial.h>
40
41 #include <machine/bus.h>
42 #include <machine/resource.h>
43 #include <sys/rman.h>
44
45 #include <dev/ic/quicc.h>
46
47 #include <dev/quicc/quicc_bfe.h>
48 #include <dev/quicc/quicc_bus.h>
49
50 #define quicc_read2(r, o) \
51 bus_space_read_2((r)->r_bustag, (r)->r_bushandle, o)
52 #define quicc_read4(r, o) \
53 bus_space_read_4((r)->r_bustag, (r)->r_bushandle, o)
54
55 #define quicc_write2(r, o, v) \
56 bus_space_write_2((r)->r_bustag, (r)->r_bushandle, o, v)
57 #define quicc_write4(r, o, v) \
58 bus_space_write_4((r)->r_bustag, (r)->r_bushandle, o, v)
59
60 char quicc_driver_name[] = "quicc";
61
62 static MALLOC_DEFINE(M_QUICC, "QUICC", "QUICC driver");
63
64 struct quicc_device {
65 struct rman *qd_rman;
66 struct resource_list qd_rlist;
67 device_t qd_dev;
68 int qd_devtype;
69
70 driver_filter_t *qd_ih;
71 void *qd_ih_arg;
72 };
73
74 static int
quicc_bfe_intr(void * arg)75 quicc_bfe_intr(void *arg)
76 {
77 struct quicc_device *qd;
78 struct quicc_softc *sc = arg;
79 uint32_t sipnr;
80
81 sipnr = quicc_read4(sc->sc_rres, QUICC_REG_SIPNR_L);
82 if (sipnr & 0x00f00000)
83 qd = sc->sc_device;
84 else
85 qd = NULL;
86
87 if (qd == NULL || qd->qd_ih == NULL) {
88 device_printf(sc->sc_dev, "Stray interrupt %08x\n", sipnr);
89 return (FILTER_STRAY);
90 }
91
92 return ((*qd->qd_ih)(qd->qd_ih_arg));
93 }
94
95 int
quicc_bfe_attach(device_t dev)96 quicc_bfe_attach(device_t dev)
97 {
98 struct quicc_device *qd;
99 struct quicc_softc *sc;
100 struct resource_list_entry *rle;
101 const char *sep;
102 rman_res_t size, start;
103 int error;
104
105 sc = device_get_softc(dev);
106
107 /*
108 * Re-allocate. We expect that the softc contains the information
109 * collected by quicc_bfe_probe() intact.
110 */
111 sc->sc_rres = bus_alloc_resource_any(dev, sc->sc_rtype, &sc->sc_rrid,
112 RF_ACTIVE);
113 if (sc->sc_rres == NULL)
114 return (ENXIO);
115
116 start = rman_get_start(sc->sc_rres);
117 size = rman_get_size(sc->sc_rres);
118
119 sc->sc_rman.rm_start = start;
120 sc->sc_rman.rm_end = start + size - 1;
121 sc->sc_rman.rm_type = RMAN_ARRAY;
122 sc->sc_rman.rm_descr = "QUICC resources";
123 error = rman_init(&sc->sc_rman);
124 if (!error)
125 error = rman_manage_region(&sc->sc_rman, start,
126 start + size - 1);
127 if (error) {
128 bus_release_resource(dev, sc->sc_rtype, sc->sc_rrid,
129 sc->sc_rres);
130 return (error);
131 }
132
133 /*
134 * Allocate interrupt resource.
135 */
136 sc->sc_irid = 0;
137 sc->sc_ires = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->sc_irid,
138 RF_ACTIVE | RF_SHAREABLE);
139
140 if (sc->sc_ires != NULL) {
141 error = bus_setup_intr(dev, sc->sc_ires,
142 INTR_TYPE_TTY, quicc_bfe_intr, NULL, sc, &sc->sc_icookie);
143 if (error) {
144 error = bus_setup_intr(dev, sc->sc_ires,
145 INTR_TYPE_TTY | INTR_MPSAFE, NULL,
146 (driver_intr_t *)quicc_bfe_intr, sc,
147 &sc->sc_icookie);
148 } else
149 sc->sc_fastintr = 1;
150 if (error) {
151 device_printf(dev, "could not activate interrupt\n");
152 bus_release_resource(dev, SYS_RES_IRQ, sc->sc_irid,
153 sc->sc_ires);
154 sc->sc_ires = NULL;
155 }
156 }
157
158 if (sc->sc_ires == NULL)
159 sc->sc_polled = 1;
160
161 if (bootverbose && (sc->sc_fastintr || sc->sc_polled)) {
162 sep = "";
163 device_print_prettyname(dev);
164 if (sc->sc_fastintr) {
165 printf("%sfast interrupt", sep);
166 sep = ", ";
167 }
168 if (sc->sc_polled) {
169 printf("%spolled mode", sep);
170 sep = ", ";
171 }
172 printf("\n");
173 }
174
175 sc->sc_device = qd = malloc(sizeof(struct quicc_device), M_QUICC,
176 M_WAITOK | M_ZERO);
177
178 qd->qd_devtype = QUICC_DEVTYPE_SCC;
179 qd->qd_rman = &sc->sc_rman;
180 resource_list_init(&qd->qd_rlist);
181
182 resource_list_add(&qd->qd_rlist, sc->sc_rtype, 0, start,
183 start + size - 1, size);
184
185 resource_list_add(&qd->qd_rlist, SYS_RES_IRQ, 0, 0xf00, 0xf00, 1);
186 rle = resource_list_find(&qd->qd_rlist, SYS_RES_IRQ, 0);
187 rle->res = sc->sc_ires;
188
189 qd->qd_dev = device_add_child(dev, NULL, -1);
190 device_set_ivars(qd->qd_dev, (void *)qd);
191 error = device_probe_and_attach(qd->qd_dev);
192
193 /* Enable all SCC interrupts. */
194 quicc_write4(sc->sc_rres, QUICC_REG_SIMR_L, 0x00f00000);
195
196 /* Clear all pending interrupts. */
197 quicc_write4(sc->sc_rres, QUICC_REG_SIPNR_H, ~0);
198 quicc_write4(sc->sc_rres, QUICC_REG_SIPNR_L, ~0);
199 return (error);
200 }
201
202 int
quicc_bfe_detach(device_t dev)203 quicc_bfe_detach(device_t dev)
204 {
205 struct quicc_softc *sc;
206
207 sc = device_get_softc(dev);
208
209 bus_teardown_intr(dev, sc->sc_ires, sc->sc_icookie);
210 bus_release_resource(dev, SYS_RES_IRQ, sc->sc_irid, sc->sc_ires);
211 bus_release_resource(dev, sc->sc_rtype, sc->sc_rrid, sc->sc_rres);
212 return (0);
213 }
214
215 int
quicc_bfe_probe(device_t dev,u_int clock)216 quicc_bfe_probe(device_t dev, u_int clock)
217 {
218 struct quicc_softc *sc;
219 uint16_t rev;
220
221 sc = device_get_softc(dev);
222 sc->sc_dev = dev;
223 if (device_get_desc(dev) == NULL)
224 device_set_desc(dev,
225 "Quad integrated communications controller");
226
227 sc->sc_rrid = 0;
228 sc->sc_rtype = SYS_RES_MEMORY;
229 sc->sc_rres = bus_alloc_resource_any(dev, sc->sc_rtype, &sc->sc_rrid,
230 RF_ACTIVE);
231 if (sc->sc_rres == NULL) {
232 sc->sc_rrid = 0;
233 sc->sc_rtype = SYS_RES_IOPORT;
234 sc->sc_rres = bus_alloc_resource_any(dev, sc->sc_rtype,
235 &sc->sc_rrid, RF_ACTIVE);
236 if (sc->sc_rres == NULL)
237 return (ENXIO);
238 }
239
240 sc->sc_clock = clock;
241
242 /*
243 * Check that the microcode revision is 0x00e8, as documented
244 * in the MPC8555E PowerQUICC III Integrated Processor Family
245 * Reference Manual.
246 */
247 rev = quicc_read2(sc->sc_rres, QUICC_PRAM_REV_NUM);
248
249 bus_release_resource(dev, sc->sc_rtype, sc->sc_rrid, sc->sc_rres);
250 return ((rev == 0x00e8) ? BUS_PROBE_DEFAULT : ENXIO);
251 }
252
253 struct resource *
quicc_bus_alloc_resource(device_t dev,device_t child,int type,int * rid,rman_res_t start,rman_res_t end,rman_res_t count,u_int flags)254 quicc_bus_alloc_resource(device_t dev, device_t child, int type, int *rid,
255 rman_res_t start, rman_res_t end, rman_res_t count, u_int flags)
256 {
257 struct quicc_device *qd;
258 struct resource_list_entry *rle;
259
260 if (device_get_parent(child) != dev)
261 return (NULL);
262
263 /* We only support default allocations. */
264 if (!RMAN_IS_DEFAULT_RANGE(start, end))
265 return (NULL);
266
267 qd = device_get_ivars(child);
268 rle = resource_list_find(&qd->qd_rlist, type, *rid);
269 if (rle == NULL)
270 return (NULL);
271
272 if (rle->res == NULL) {
273 rle->res = rman_reserve_resource(qd->qd_rman, rle->start,
274 rle->start + rle->count - 1, rle->count, flags, child);
275 if (rle->res != NULL) {
276 rman_set_bustag(rle->res, &bs_be_tag);
277 rman_set_bushandle(rle->res, rle->start);
278 }
279 }
280 return (rle->res);
281 }
282
283 int
quicc_bus_get_resource(device_t dev,device_t child,int type,int rid,rman_res_t * startp,rman_res_t * countp)284 quicc_bus_get_resource(device_t dev, device_t child, int type, int rid,
285 rman_res_t *startp, rman_res_t *countp)
286 {
287 struct quicc_device *qd;
288 struct resource_list_entry *rle;
289
290 if (device_get_parent(child) != dev)
291 return (EINVAL);
292
293 qd = device_get_ivars(child);
294 rle = resource_list_find(&qd->qd_rlist, type, rid);
295 if (rle == NULL)
296 return (EINVAL);
297
298 if (startp != NULL)
299 *startp = rle->start;
300 if (countp != NULL)
301 *countp = rle->count;
302 return (0);
303 }
304
305 int
quicc_bus_read_ivar(device_t dev,device_t child,int index,uintptr_t * result)306 quicc_bus_read_ivar(device_t dev, device_t child, int index, uintptr_t *result)
307 {
308 struct quicc_device *qd;
309 struct quicc_softc *sc;
310 uint32_t sccr;
311
312 if (device_get_parent(child) != dev)
313 return (EINVAL);
314
315 sc = device_get_softc(dev);
316 qd = device_get_ivars(child);
317
318 switch (index) {
319 case QUICC_IVAR_CLOCK:
320 *result = sc->sc_clock;
321 break;
322 case QUICC_IVAR_BRGCLK:
323 sccr = quicc_read4(sc->sc_rres, QUICC_REG_SCCR) & 3;
324 *result = sc->sc_clock / ((1 << (sccr + 1)) << sccr);
325 break;
326 case QUICC_IVAR_DEVTYPE:
327 *result = qd->qd_devtype;
328 break;
329 default:
330 return (EINVAL);
331 }
332 return (0);
333 }
334
335 int
quicc_bus_release_resource(device_t dev,device_t child,struct resource * res)336 quicc_bus_release_resource(device_t dev, device_t child, struct resource *res)
337 {
338 struct quicc_device *qd;
339 struct resource_list_entry *rle;
340
341 if (device_get_parent(child) != dev)
342 return (EINVAL);
343
344 qd = device_get_ivars(child);
345 rle = resource_list_find(&qd->qd_rlist, rman_get_type(res),
346 rman_get_rid(res));
347 return ((rle == NULL) ? EINVAL : 0);
348 }
349
350 int
quicc_bus_setup_intr(device_t dev,device_t child,struct resource * r,int flags,driver_filter_t * filt,void (* ihand)(void *),void * arg,void ** cookiep)351 quicc_bus_setup_intr(device_t dev, device_t child, struct resource *r,
352 int flags, driver_filter_t *filt, void (*ihand)(void *), void *arg,
353 void **cookiep)
354 {
355 struct quicc_device *qd;
356 struct quicc_softc *sc;
357
358 if (device_get_parent(child) != dev)
359 return (EINVAL);
360
361 /* Interrupt handlers must be FAST or MPSAFE. */
362 if (filt == NULL && !(flags & INTR_MPSAFE))
363 return (EINVAL);
364
365 sc = device_get_softc(dev);
366 if (sc->sc_polled)
367 return (ENXIO);
368
369 if (sc->sc_fastintr && filt == NULL) {
370 sc->sc_fastintr = 0;
371 bus_teardown_intr(dev, sc->sc_ires, sc->sc_icookie);
372 bus_setup_intr(dev, sc->sc_ires, INTR_TYPE_TTY | INTR_MPSAFE,
373 NULL, (driver_intr_t *)quicc_bfe_intr, sc, &sc->sc_icookie);
374 }
375
376 qd = device_get_ivars(child);
377 qd->qd_ih = (filt != NULL) ? filt : (driver_filter_t *)ihand;
378 qd->qd_ih_arg = arg;
379 *cookiep = ihand;
380 return (0);
381 }
382
383 int
quicc_bus_teardown_intr(device_t dev,device_t child,struct resource * r,void * cookie)384 quicc_bus_teardown_intr(device_t dev, device_t child, struct resource *r,
385 void *cookie)
386 {
387 struct quicc_device *qd;
388
389 if (device_get_parent(child) != dev)
390 return (EINVAL);
391
392 qd = device_get_ivars(child);
393 if (qd->qd_ih != cookie)
394 return (EINVAL);
395
396 qd->qd_ih = NULL;
397 qd->qd_ih_arg = NULL;
398 return (0);
399 }
400