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