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