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