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