2 * Copyright 2006 by Juniper Networks.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. The name of the author may not be used to endorse or promote products
14 * derived from this software without specific prior written permission.
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 BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
21 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
23 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 #include <sys/cdefs.h>
30 __FBSDID("$FreeBSD$");
32 #include <sys/param.h>
33 #include <sys/systm.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>
42 #include <machine/bus.h>
43 #include <machine/resource.h>
46 #include <dev/ic/quicc.h>
48 #include <dev/quicc/quicc_bfe.h>
49 #include <dev/quicc/quicc_bus.h>
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)
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)
61 devclass_t quicc_devclass
;
62 char quicc_driver_name
[] = "quicc";
64 static MALLOC_DEFINE(M_QUICC
, "QUICC", "QUICC driver");
68 struct resource_list qd_rlist
;
72 driver_filter_t
*qd_ih
;
77 quicc_bfe_intr(void *arg
)
79 struct quicc_device
*qd
;
80 struct quicc_softc
*sc
= arg
;
83 sipnr
= quicc_read4(sc
->sc_rres
, QUICC_REG_SIPNR_L
);
84 if (sipnr
& 0x00f00000)
89 if (qd
== NULL
|| qd
->qd_ih
== NULL
) {
90 device_printf(sc
->sc_dev
, "Stray interrupt %08x\n", sipnr
);
91 return (FILTER_STRAY
);
94 return ((*qd
->qd_ih
)(qd
->qd_ih_arg
));
98 quicc_bfe_attach(device_t dev
)
100 struct quicc_device
*qd
;
101 struct quicc_softc
*sc
;
102 struct resource_list_entry
*rle
;
104 rman_res_t size
, start
;
107 sc
= device_get_softc(dev
);
110 * Re-allocate. We expect that the softc contains the information
111 * collected by quicc_bfe_probe() intact.
113 sc
->sc_rres
= bus_alloc_resource_any(dev
, sc
->sc_rtype
, &sc
->sc_rrid
,
115 if (sc
->sc_rres
== NULL
)
118 start
= rman_get_start(sc
->sc_rres
);
119 size
= rman_get_size(sc
->sc_rres
);
121 sc
->sc_rman
.rm_start
= start
;
122 sc
->sc_rman
.rm_end
= start
+ size
- 1;
123 sc
->sc_rman
.rm_type
= RMAN_ARRAY
;
124 sc
->sc_rman
.rm_descr
= "QUICC resources";
125 error
= rman_init(&sc
->sc_rman
);
127 error
= rman_manage_region(&sc
->sc_rman
, start
,
130 bus_release_resource(dev
, sc
->sc_rtype
, sc
->sc_rrid
,
136 * Allocate interrupt resource.
139 sc
->sc_ires
= bus_alloc_resource_any(dev
, SYS_RES_IRQ
, &sc
->sc_irid
,
140 RF_ACTIVE
| RF_SHAREABLE
);
142 if (sc
->sc_ires
!= NULL
) {
143 error
= bus_setup_intr(dev
, sc
->sc_ires
,
144 INTR_TYPE_TTY
, quicc_bfe_intr
, NULL
, sc
, &sc
->sc_icookie
);
146 error
= bus_setup_intr(dev
, sc
->sc_ires
,
147 INTR_TYPE_TTY
| INTR_MPSAFE
, NULL
,
148 (driver_intr_t
*)quicc_bfe_intr
, sc
,
153 device_printf(dev
, "could not activate interrupt\n");
154 bus_release_resource(dev
, SYS_RES_IRQ
, sc
->sc_irid
,
160 if (sc
->sc_ires
== NULL
)
163 if (bootverbose
&& (sc
->sc_fastintr
|| sc
->sc_polled
)) {
165 device_print_prettyname(dev
);
166 if (sc
->sc_fastintr
) {
167 printf("%sfast interrupt", sep
);
171 printf("%spolled mode", sep
);
177 sc
->sc_device
= qd
= malloc(sizeof(struct quicc_device
), M_QUICC
,
180 qd
->qd_devtype
= QUICC_DEVTYPE_SCC
;
181 qd
->qd_rman
= &sc
->sc_rman
;
182 resource_list_init(&qd
->qd_rlist
);
184 resource_list_add(&qd
->qd_rlist
, sc
->sc_rtype
, 0, start
,
185 start
+ size
- 1, size
);
187 resource_list_add(&qd
->qd_rlist
, SYS_RES_IRQ
, 0, 0xf00, 0xf00, 1);
188 rle
= resource_list_find(&qd
->qd_rlist
, SYS_RES_IRQ
, 0);
189 rle
->res
= sc
->sc_ires
;
191 qd
->qd_dev
= device_add_child(dev
, NULL
, -1);
192 device_set_ivars(qd
->qd_dev
, (void *)qd
);
193 error
= device_probe_and_attach(qd
->qd_dev
);
195 /* Enable all SCC interrupts. */
196 quicc_write4(sc
->sc_rres
, QUICC_REG_SIMR_L
, 0x00f00000);
198 /* Clear all pending interrupts. */
199 quicc_write4(sc
->sc_rres
, QUICC_REG_SIPNR_H
, ~0);
200 quicc_write4(sc
->sc_rres
, QUICC_REG_SIPNR_L
, ~0);
205 quicc_bfe_detach(device_t dev
)
207 struct quicc_softc
*sc
;
209 sc
= device_get_softc(dev
);
211 bus_teardown_intr(dev
, sc
->sc_ires
, sc
->sc_icookie
);
212 bus_release_resource(dev
, SYS_RES_IRQ
, sc
->sc_irid
, sc
->sc_ires
);
213 bus_release_resource(dev
, sc
->sc_rtype
, sc
->sc_rrid
, sc
->sc_rres
);
218 quicc_bfe_probe(device_t dev
, u_int clock
)
220 struct quicc_softc
*sc
;
223 sc
= device_get_softc(dev
);
225 if (device_get_desc(dev
) == NULL
)
227 "Quad integrated communications controller");
230 sc
->sc_rtype
= SYS_RES_MEMORY
;
231 sc
->sc_rres
= bus_alloc_resource_any(dev
, sc
->sc_rtype
, &sc
->sc_rrid
,
233 if (sc
->sc_rres
== NULL
) {
235 sc
->sc_rtype
= SYS_RES_IOPORT
;
236 sc
->sc_rres
= bus_alloc_resource_any(dev
, sc
->sc_rtype
,
237 &sc
->sc_rrid
, RF_ACTIVE
);
238 if (sc
->sc_rres
== NULL
)
242 sc
->sc_clock
= clock
;
245 * Check that the microcode revision is 0x00e8, as documented
246 * in the MPC8555E PowerQUICC III Integrated Processor Family
249 rev
= quicc_read2(sc
->sc_rres
, QUICC_PRAM_REV_NUM
);
251 bus_release_resource(dev
, sc
->sc_rtype
, sc
->sc_rrid
, sc
->sc_rres
);
252 return ((rev
== 0x00e8) ? BUS_PROBE_DEFAULT
: ENXIO
);
256 quicc_bus_alloc_resource(device_t dev
, device_t child
, int type
, int *rid
,
257 rman_res_t start
, rman_res_t end
, rman_res_t count
, u_int flags
)
259 struct quicc_device
*qd
;
260 struct resource_list_entry
*rle
;
262 if (device_get_parent(child
) != dev
)
265 /* We only support default allocations. */
266 if (!RMAN_IS_DEFAULT_RANGE(start
, end
))
269 qd
= device_get_ivars(child
);
270 rle
= resource_list_find(&qd
->qd_rlist
, type
, *rid
);
274 if (rle
->res
== NULL
) {
275 rle
->res
= rman_reserve_resource(qd
->qd_rman
, rle
->start
,
276 rle
->start
+ rle
->count
- 1, rle
->count
, flags
, child
);
277 if (rle
->res
!= NULL
) {
278 rman_set_bustag(rle
->res
, &bs_be_tag
);
279 rman_set_bushandle(rle
->res
, rle
->start
);
286 quicc_bus_get_resource(device_t dev
, device_t child
, int type
, int rid
,
287 rman_res_t
*startp
, rman_res_t
*countp
)
289 struct quicc_device
*qd
;
290 struct resource_list_entry
*rle
;
292 if (device_get_parent(child
) != dev
)
295 qd
= device_get_ivars(child
);
296 rle
= resource_list_find(&qd
->qd_rlist
, type
, rid
);
301 *startp
= rle
->start
;
303 *countp
= rle
->count
;
308 quicc_bus_read_ivar(device_t dev
, device_t child
, int index
, uintptr_t *result
)
310 struct quicc_device
*qd
;
311 struct quicc_softc
*sc
;
314 if (device_get_parent(child
) != dev
)
317 sc
= device_get_softc(dev
);
318 qd
= device_get_ivars(child
);
321 case QUICC_IVAR_CLOCK
:
322 *result
= sc
->sc_clock
;
324 case QUICC_IVAR_BRGCLK
:
325 sccr
= quicc_read4(sc
->sc_rres
, QUICC_REG_SCCR
) & 3;
326 *result
= sc
->sc_clock
/ ((1 << (sccr
+ 1)) << sccr
);
328 case QUICC_IVAR_DEVTYPE
:
329 *result
= qd
->qd_devtype
;
338 quicc_bus_release_resource(device_t dev
, device_t child
, int type
, int rid
,
339 struct resource
*res
)
341 struct quicc_device
*qd
;
342 struct resource_list_entry
*rle
;
344 if (device_get_parent(child
) != dev
)
347 qd
= device_get_ivars(child
);
348 rle
= resource_list_find(&qd
->qd_rlist
, type
, rid
);
349 return ((rle
== NULL
) ? EINVAL
: 0);
353 quicc_bus_setup_intr(device_t dev
, device_t child
, struct resource
*r
,
354 int flags
, driver_filter_t
*filt
, void (*ihand
)(void *), void *arg
,
357 struct quicc_device
*qd
;
358 struct quicc_softc
*sc
;
360 if (device_get_parent(child
) != dev
)
363 /* Interrupt handlers must be FAST or MPSAFE. */
364 if (filt
== NULL
&& !(flags
& INTR_MPSAFE
))
367 sc
= device_get_softc(dev
);
371 if (sc
->sc_fastintr
&& filt
== NULL
) {
373 bus_teardown_intr(dev
, sc
->sc_ires
, sc
->sc_icookie
);
374 bus_setup_intr(dev
, sc
->sc_ires
, INTR_TYPE_TTY
| INTR_MPSAFE
,
375 NULL
, (driver_intr_t
*)quicc_bfe_intr
, sc
, &sc
->sc_icookie
);
378 qd
= device_get_ivars(child
);
379 qd
->qd_ih
= (filt
!= NULL
) ? filt
: (driver_filter_t
*)ihand
;
386 quicc_bus_teardown_intr(device_t dev
, device_t child
, struct resource
*r
,
389 struct quicc_device
*qd
;
391 if (device_get_parent(child
) != dev
)
394 qd
= device_get_ivars(child
);
395 if (qd
->qd_ih
!= cookie
)
399 qd
->qd_ih_arg
= NULL
;