2 * SPDX-License-Identifier: BSD-3-Clause
4 * Copyright 2006 by Juniper Networks.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
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.
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
31 #include <sys/cdefs.h>
32 __FBSDID("$FreeBSD$");
34 #include <sys/param.h>
35 #include <sys/systm.h>
38 #include <sys/endian.h>
39 #include <sys/kernel.h>
40 #include <sys/malloc.h>
41 #include <sys/queue.h>
42 #include <sys/serial.h>
44 #include <machine/bus.h>
45 #include <machine/resource.h>
48 #include <dev/ic/quicc.h>
50 #include <dev/quicc/quicc_bfe.h>
51 #include <dev/quicc/quicc_bus.h>
53 #define quicc_read2(r, o) \
54 bus_space_read_2((r)->r_bustag, (r)->r_bushandle, o)
55 #define quicc_read4(r, o) \
56 bus_space_read_4((r)->r_bustag, (r)->r_bushandle, o)
58 #define quicc_write2(r, o, v) \
59 bus_space_write_2((r)->r_bustag, (r)->r_bushandle, o, v)
60 #define quicc_write4(r, o, v) \
61 bus_space_write_4((r)->r_bustag, (r)->r_bushandle, o, v)
63 devclass_t quicc_devclass;
64 char quicc_driver_name[] = "quicc";
66 static MALLOC_DEFINE(M_QUICC, "QUICC", "QUICC driver");
70 struct resource_list qd_rlist;
74 driver_filter_t *qd_ih;
79 quicc_bfe_intr(void *arg)
81 struct quicc_device *qd;
82 struct quicc_softc *sc = arg;
85 sipnr = quicc_read4(sc->sc_rres, QUICC_REG_SIPNR_L);
86 if (sipnr & 0x00f00000)
91 if (qd == NULL || qd->qd_ih == NULL) {
92 device_printf(sc->sc_dev, "Stray interrupt %08x\n", sipnr);
93 return (FILTER_STRAY);
96 return ((*qd->qd_ih)(qd->qd_ih_arg));
100 quicc_bfe_attach(device_t dev)
102 struct quicc_device *qd;
103 struct quicc_softc *sc;
104 struct resource_list_entry *rle;
106 rman_res_t size, start;
109 sc = device_get_softc(dev);
112 * Re-allocate. We expect that the softc contains the information
113 * collected by quicc_bfe_probe() intact.
115 sc->sc_rres = bus_alloc_resource_any(dev, sc->sc_rtype, &sc->sc_rrid,
117 if (sc->sc_rres == NULL)
120 start = rman_get_start(sc->sc_rres);
121 size = rman_get_size(sc->sc_rres);
123 sc->sc_rman.rm_start = start;
124 sc->sc_rman.rm_end = start + size - 1;
125 sc->sc_rman.rm_type = RMAN_ARRAY;
126 sc->sc_rman.rm_descr = "QUICC resources";
127 error = rman_init(&sc->sc_rman);
129 error = rman_manage_region(&sc->sc_rman, start,
132 bus_release_resource(dev, sc->sc_rtype, sc->sc_rrid,
138 * Allocate interrupt resource.
141 sc->sc_ires = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->sc_irid,
142 RF_ACTIVE | RF_SHAREABLE);
144 if (sc->sc_ires != NULL) {
145 error = bus_setup_intr(dev, sc->sc_ires,
146 INTR_TYPE_TTY, quicc_bfe_intr, NULL, sc, &sc->sc_icookie);
148 error = bus_setup_intr(dev, sc->sc_ires,
149 INTR_TYPE_TTY | INTR_MPSAFE, NULL,
150 (driver_intr_t *)quicc_bfe_intr, sc,
155 device_printf(dev, "could not activate interrupt\n");
156 bus_release_resource(dev, SYS_RES_IRQ, sc->sc_irid,
162 if (sc->sc_ires == NULL)
165 if (bootverbose && (sc->sc_fastintr || sc->sc_polled)) {
167 device_print_prettyname(dev);
168 if (sc->sc_fastintr) {
169 printf("%sfast interrupt", sep);
173 printf("%spolled mode", sep);
179 sc->sc_device = qd = malloc(sizeof(struct quicc_device), M_QUICC,
182 qd->qd_devtype = QUICC_DEVTYPE_SCC;
183 qd->qd_rman = &sc->sc_rman;
184 resource_list_init(&qd->qd_rlist);
186 resource_list_add(&qd->qd_rlist, sc->sc_rtype, 0, start,
187 start + size - 1, size);
189 resource_list_add(&qd->qd_rlist, SYS_RES_IRQ, 0, 0xf00, 0xf00, 1);
190 rle = resource_list_find(&qd->qd_rlist, SYS_RES_IRQ, 0);
191 rle->res = sc->sc_ires;
193 qd->qd_dev = device_add_child(dev, NULL, -1);
194 device_set_ivars(qd->qd_dev, (void *)qd);
195 error = device_probe_and_attach(qd->qd_dev);
197 /* Enable all SCC interrupts. */
198 quicc_write4(sc->sc_rres, QUICC_REG_SIMR_L, 0x00f00000);
200 /* Clear all pending interrupts. */
201 quicc_write4(sc->sc_rres, QUICC_REG_SIPNR_H, ~0);
202 quicc_write4(sc->sc_rres, QUICC_REG_SIPNR_L, ~0);
207 quicc_bfe_detach(device_t dev)
209 struct quicc_softc *sc;
211 sc = device_get_softc(dev);
213 bus_teardown_intr(dev, sc->sc_ires, sc->sc_icookie);
214 bus_release_resource(dev, SYS_RES_IRQ, sc->sc_irid, sc->sc_ires);
215 bus_release_resource(dev, sc->sc_rtype, sc->sc_rrid, sc->sc_rres);
220 quicc_bfe_probe(device_t dev, u_int clock)
222 struct quicc_softc *sc;
225 sc = device_get_softc(dev);
227 if (device_get_desc(dev) == NULL)
229 "Quad integrated communications controller");
232 sc->sc_rtype = SYS_RES_MEMORY;
233 sc->sc_rres = bus_alloc_resource_any(dev, sc->sc_rtype, &sc->sc_rrid,
235 if (sc->sc_rres == NULL) {
237 sc->sc_rtype = SYS_RES_IOPORT;
238 sc->sc_rres = bus_alloc_resource_any(dev, sc->sc_rtype,
239 &sc->sc_rrid, RF_ACTIVE);
240 if (sc->sc_rres == NULL)
244 sc->sc_clock = clock;
247 * Check that the microcode revision is 0x00e8, as documented
248 * in the MPC8555E PowerQUICC III Integrated Processor Family
251 rev = quicc_read2(sc->sc_rres, QUICC_PRAM_REV_NUM);
253 bus_release_resource(dev, sc->sc_rtype, sc->sc_rrid, sc->sc_rres);
254 return ((rev == 0x00e8) ? BUS_PROBE_DEFAULT : ENXIO);
258 quicc_bus_alloc_resource(device_t dev, device_t child, int type, int *rid,
259 rman_res_t start, rman_res_t end, rman_res_t count, u_int flags)
261 struct quicc_device *qd;
262 struct resource_list_entry *rle;
264 if (device_get_parent(child) != dev)
267 /* We only support default allocations. */
268 if (!RMAN_IS_DEFAULT_RANGE(start, end))
271 qd = device_get_ivars(child);
272 rle = resource_list_find(&qd->qd_rlist, type, *rid);
276 if (rle->res == NULL) {
277 rle->res = rman_reserve_resource(qd->qd_rman, rle->start,
278 rle->start + rle->count - 1, rle->count, flags, child);
279 if (rle->res != NULL) {
280 rman_set_bustag(rle->res, &bs_be_tag);
281 rman_set_bushandle(rle->res, rle->start);
288 quicc_bus_get_resource(device_t dev, device_t child, int type, int rid,
289 rman_res_t *startp, rman_res_t *countp)
291 struct quicc_device *qd;
292 struct resource_list_entry *rle;
294 if (device_get_parent(child) != dev)
297 qd = device_get_ivars(child);
298 rle = resource_list_find(&qd->qd_rlist, type, rid);
303 *startp = rle->start;
305 *countp = rle->count;
310 quicc_bus_read_ivar(device_t dev, device_t child, int index, uintptr_t *result)
312 struct quicc_device *qd;
313 struct quicc_softc *sc;
316 if (device_get_parent(child) != dev)
319 sc = device_get_softc(dev);
320 qd = device_get_ivars(child);
323 case QUICC_IVAR_CLOCK:
324 *result = sc->sc_clock;
326 case QUICC_IVAR_BRGCLK:
327 sccr = quicc_read4(sc->sc_rres, QUICC_REG_SCCR) & 3;
328 *result = sc->sc_clock / ((1 << (sccr + 1)) << sccr);
330 case QUICC_IVAR_DEVTYPE:
331 *result = qd->qd_devtype;
340 quicc_bus_release_resource(device_t dev, device_t child, int type, int rid,
341 struct resource *res)
343 struct quicc_device *qd;
344 struct resource_list_entry *rle;
346 if (device_get_parent(child) != dev)
349 qd = device_get_ivars(child);
350 rle = resource_list_find(&qd->qd_rlist, type, rid);
351 return ((rle == NULL) ? EINVAL : 0);
355 quicc_bus_setup_intr(device_t dev, device_t child, struct resource *r,
356 int flags, driver_filter_t *filt, void (*ihand)(void *), void *arg,
359 struct quicc_device *qd;
360 struct quicc_softc *sc;
362 if (device_get_parent(child) != dev)
365 /* Interrupt handlers must be FAST or MPSAFE. */
366 if (filt == NULL && !(flags & INTR_MPSAFE))
369 sc = device_get_softc(dev);
373 if (sc->sc_fastintr && filt == NULL) {
375 bus_teardown_intr(dev, sc->sc_ires, sc->sc_icookie);
376 bus_setup_intr(dev, sc->sc_ires, INTR_TYPE_TTY | INTR_MPSAFE,
377 NULL, (driver_intr_t *)quicc_bfe_intr, sc, &sc->sc_icookie);
380 qd = device_get_ivars(child);
381 qd->qd_ih = (filt != NULL) ? filt : (driver_filter_t *)ihand;
388 quicc_bus_teardown_intr(device_t dev, device_t child, struct resource *r,
391 struct quicc_device *qd;
393 if (device_get_parent(child) != dev)
396 qd = device_get_ivars(child);
397 if (qd->qd_ih != cookie)
401 qd->qd_ih_arg = NULL;