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