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