1 /*- 2 * Copyright (c) 2006-2008, Juniper Networks, Inc. 3 * Copyright (c) 2008 Semihalf, Rafal Czubak 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 3. The name of the author may not be used to endorse or promote products 15 * derived from this software without specific prior written permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 22 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 23 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 24 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 25 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 */ 29 30 #include <sys/cdefs.h> 31 __FBSDID("$FreeBSD$"); 32 33 #include <sys/param.h> 34 #include <sys/systm.h> 35 #include <sys/ktr.h> 36 #include <sys/kernel.h> 37 #include <sys/malloc.h> 38 #include <sys/module.h> 39 #include <sys/bus.h> 40 #include <sys/rman.h> 41 #include <machine/bus.h> 42 #include <machine/ocpbus.h> 43 44 #include <vm/vm.h> 45 #include <vm/pmap.h> 46 47 #include <powerpc/mpc85xx/lbc.h> 48 #include <powerpc/mpc85xx/mpc85xx.h> 49 #include <powerpc/mpc85xx/ocpbus.h> 50 51 struct lbc_softc { 52 device_t sc_dev; 53 54 struct resource *sc_res; 55 bus_space_handle_t sc_bsh; 56 bus_space_tag_t sc_bst; 57 int sc_rid; 58 59 struct rman sc_rman; 60 vm_offset_t sc_kva[LBC_DEV_MAX]; 61 }; 62 63 struct lbc_devinfo { 64 int lbc_devtype; 65 /* LBC child unit. It also represents resource table entry number */ 66 int lbc_unit; 67 }; 68 69 /* Resources for MPC8555CDS system */ 70 const struct lbc_resource mpc85xx_lbc_resources[] = { 71 /* Boot flash bank */ 72 { 73 LBC_DEVTYPE_CFI, 0, 0xff800000, 0x00800000, 16, 74 LBCRES_MSEL_GPCM, LBCRES_DECC_DISABLED, 75 LBCRES_ATOM_DISABLED, 0 76 }, 77 78 /* Second flash bank */ 79 { 80 LBC_DEVTYPE_CFI, 1, 0xff000000, 0x00800000, 16, 81 LBCRES_MSEL_GPCM, LBCRES_DECC_DISABLED, 82 LBCRES_ATOM_DISABLED, 0 83 }, 84 85 /* DS1553 RTC/NVRAM */ 86 { 87 LBC_DEVTYPE_RTC, 2, 0xf8000000, 0x8000, 8, 88 LBCRES_MSEL_GPCM, LBCRES_DECC_DISABLED, 89 LBCRES_ATOM_DISABLED, 0 90 }, 91 92 {0} 93 }; 94 95 static int lbc_probe(device_t); 96 static int lbc_attach(device_t); 97 static int lbc_shutdown(device_t); 98 static int lbc_get_resource(device_t, device_t, int, int, u_long *, 99 u_long *); 100 static struct resource *lbc_alloc_resource(device_t, device_t, int, int *, 101 u_long, u_long, u_long, u_int); 102 static int lbc_print_child(device_t, device_t); 103 static int lbc_release_resource(device_t, device_t, int, int, 104 struct resource *); 105 static int lbc_read_ivar(device_t, device_t, int, uintptr_t *); 106 107 /* 108 * Bus interface definition 109 */ 110 static device_method_t lbc_methods[] = { 111 /* Device interface */ 112 DEVMETHOD(device_probe, lbc_probe), 113 DEVMETHOD(device_attach, lbc_attach), 114 DEVMETHOD(device_shutdown, lbc_shutdown), 115 116 /* Bus interface */ 117 DEVMETHOD(bus_print_child, lbc_print_child), 118 DEVMETHOD(bus_read_ivar, lbc_read_ivar), 119 DEVMETHOD(bus_setup_intr, bus_generic_setup_intr), 120 DEVMETHOD(bus_teardown_intr, NULL), 121 122 DEVMETHOD(bus_get_resource, NULL), 123 DEVMETHOD(bus_alloc_resource, lbc_alloc_resource), 124 DEVMETHOD(bus_release_resource, lbc_release_resource), 125 DEVMETHOD(bus_activate_resource, bus_generic_activate_resource), 126 DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), 127 128 { 0, 0 } 129 }; 130 131 static driver_t lbc_driver = { 132 "lbc", 133 lbc_methods, 134 sizeof(struct lbc_softc) 135 }; 136 devclass_t lbc_devclass; 137 DRIVER_MODULE(lbc, ocpbus, lbc_driver, lbc_devclass, 0, 0); 138 139 static __inline void 140 lbc_write_reg(struct lbc_softc *sc, bus_size_t off, uint32_t val) 141 { 142 143 bus_space_write_4(sc->sc_bst, sc->sc_bsh, off, val); 144 } 145 146 static __inline uint32_t 147 lbc_read_reg(struct lbc_softc *sc, bus_size_t off) 148 { 149 150 return (bus_space_read_4(sc->sc_bst, sc->sc_bsh, off)); 151 } 152 153 /* 154 * Calculate address mask used by OR(n) registers. Use memory region size to 155 * determine mask value. The size must be a power of two and within the range 156 * of 32KB - 4GB. Otherwise error code is returned. Value representing 157 * 4GB size can be passed as 0xffffffff. 158 */ 159 static uint32_t 160 lbc_address_mask(uint32_t size) 161 { 162 int n = 15; 163 164 if (size == ~0UL) 165 return (0); 166 167 while (n < 32) { 168 if (size == (1UL << n)) 169 break; 170 n++; 171 } 172 173 if (n == 32) 174 return (EINVAL); 175 176 return (0xffff8000 << (n - 15)); 177 } 178 179 static device_t 180 lbc_mk_child(device_t dev, const struct lbc_resource *lbcres) 181 { 182 struct lbc_devinfo *dinfo; 183 device_t child; 184 185 if (lbcres->lbr_unit > LBC_DEV_MAX - 1) 186 return (NULL); 187 188 child = device_add_child(dev, NULL, -1); 189 if (child == NULL) { 190 device_printf(dev, "could not add LBC child device\n"); 191 return (NULL); 192 } 193 dinfo = malloc(sizeof(struct lbc_devinfo), M_DEVBUF, M_WAITOK | M_ZERO); 194 dinfo->lbc_devtype = lbcres->lbr_devtype; 195 dinfo->lbc_unit = lbcres->lbr_unit; 196 device_set_ivars(child, dinfo); 197 return (child); 198 } 199 200 static int 201 lbc_init_child(device_t dev, device_t child) 202 { 203 struct lbc_softc *sc; 204 struct lbc_devinfo *dinfo; 205 const struct lbc_resource *res; 206 u_long start, size; 207 uint32_t regbuff; 208 int error, unit; 209 210 sc = device_get_softc(dev); 211 dinfo = device_get_ivars(child); 212 213 res = mpc85xx_lbc_resources; 214 215 regbuff = 0; 216 unit = -1; 217 for (; res->lbr_devtype; res++) { 218 if (res->lbr_unit != dinfo->lbc_unit) 219 continue; 220 221 start = res->lbr_base_addr; 222 size = res->lbr_size; 223 unit = res->lbr_unit; 224 225 /* 226 * Configure LAW for this LBC device and map its physical 227 * memory region into KVA 228 */ 229 error = law_enable(OCP85XX_TGTIF_LBC, start, size); 230 if (error) 231 return (error); 232 233 sc->sc_kva[unit] = (vm_offset_t)pmap_mapdev(start, size); 234 if (sc->sc_kva[unit] == 0) { 235 law_disable(OCP85XX_TGTIF_LBC, start, size); 236 return (ENOSPC); 237 } 238 239 /* 240 * Compute and program BR value 241 */ 242 regbuff |= start; 243 244 switch (res->lbr_port_size) { 245 case 8: 246 regbuff |= (1 << 11); 247 break; 248 case 16: 249 regbuff |= (2 << 11); 250 break; 251 case 32: 252 regbuff |= (3 << 11); 253 break; 254 default: 255 error = EINVAL; 256 goto fail; 257 } 258 regbuff |= (res->lbr_decc << 9); 259 regbuff |= (res->lbr_wp << 8); 260 regbuff |= (res->lbr_msel << 5); 261 regbuff |= (res->lbr_atom << 2); 262 regbuff |= 1; 263 264 lbc_write_reg(sc, LBC85XX_BR(unit), regbuff); 265 266 /* 267 * Compute and program OR value 268 */ 269 regbuff = 0; 270 regbuff |= lbc_address_mask(size); 271 272 switch (res->lbr_msel) { 273 case LBCRES_MSEL_GPCM: 274 /* TODO Add flag support for option registers */ 275 regbuff |= 0x00000ff7; 276 break; 277 case LBCRES_MSEL_FCM: 278 printf("FCM mode not supported yet!"); 279 error = ENOSYS; 280 goto fail; 281 case LBCRES_MSEL_UPMA: 282 case LBCRES_MSEL_UPMB: 283 case LBCRES_MSEL_UPMC: 284 printf("UPM mode not supported yet!"); 285 error = ENOSYS; 286 goto fail; 287 } 288 289 lbc_write_reg(sc, LBC85XX_OR(unit), regbuff); 290 291 return (0); 292 } 293 fail: 294 if (unit != -1) { 295 law_disable(OCP85XX_TGTIF_LBC, start, size); 296 pmap_unmapdev(sc->sc_kva[unit], size); 297 return (error); 298 } else 299 return (ENOENT); 300 } 301 302 static int 303 lbc_probe(device_t dev) 304 { 305 device_t parent; 306 uintptr_t devtype; 307 int error; 308 309 parent = device_get_parent(dev); 310 error = BUS_READ_IVAR(parent, dev, OCPBUS_IVAR_DEVTYPE, &devtype); 311 if (error) 312 return (error); 313 if (devtype != OCPBUS_DEVTYPE_LBC) 314 return (ENXIO); 315 316 device_set_desc(dev, "Freescale MPC85xx Local Bus Controller"); 317 return (BUS_PROBE_DEFAULT); 318 } 319 320 static int 321 lbc_attach(device_t dev) 322 { 323 struct lbc_softc *sc; 324 struct rman *rm; 325 const struct lbc_resource *lbcres; 326 int error; 327 328 sc = device_get_softc(dev); 329 sc->sc_dev = dev; 330 331 sc->sc_rid = 0; 332 sc->sc_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &sc->sc_rid, 333 RF_ACTIVE); 334 if (sc->sc_res == NULL) 335 return (ENXIO); 336 337 sc->sc_bst = rman_get_bustag(sc->sc_res); 338 sc->sc_bsh = rman_get_bushandle(sc->sc_res); 339 340 rm = &sc->sc_rman; 341 rm->rm_type = RMAN_ARRAY; 342 rm->rm_descr = "MPC85XX Local Bus Space"; 343 rm->rm_start = 0UL; 344 rm->rm_end = ~0UL; 345 error = rman_init(rm); 346 if (error) 347 goto fail; 348 349 error = rman_manage_region(rm, rm->rm_start, rm->rm_end); 350 if (error) { 351 rman_fini(rm); 352 goto fail; 353 } 354 355 /* 356 * Initialize configuration register: 357 * - enable Local Bus 358 * - set data buffer control signal function 359 * - disable parity byte select 360 * - set ECC parity type 361 * - set bus monitor timing and timer prescale 362 */ 363 lbc_write_reg(sc, LBC85XX_LBCR, 0x00000000); 364 365 /* 366 * Initialize clock ratio register: 367 * - disable PLL bypass mode 368 * - configure LCLK delay cycles for the assertion of LALE 369 * - set system clock divider 370 */ 371 lbc_write_reg(sc, LBC85XX_LCRR, 0x00030008); 372 373 lbcres = mpc85xx_lbc_resources; 374 375 for (; lbcres->lbr_devtype; lbcres++) 376 if (!lbc_mk_child(dev, lbcres)) { 377 error = ENXIO; 378 goto fail; 379 } 380 381 return (bus_generic_attach(dev)); 382 383 fail: 384 bus_release_resource(dev, SYS_RES_MEMORY, sc->sc_rid, sc->sc_res); 385 return (error); 386 } 387 388 static int 389 lbc_shutdown(device_t dev) 390 { 391 392 /* TODO */ 393 return(0); 394 } 395 396 static struct resource * 397 lbc_alloc_resource(device_t dev, device_t child, int type, int *rid, 398 u_long start, u_long end, u_long count, u_int flags) 399 { 400 struct lbc_softc *sc; 401 struct lbc_devinfo *dinfo; 402 struct resource *rv; 403 struct rman *rm; 404 int error; 405 406 sc = device_get_softc(dev); 407 dinfo = device_get_ivars(child); 408 409 if (type != SYS_RES_MEMORY && type != SYS_RES_IRQ) 410 return (NULL); 411 412 /* We only support default allocations. */ 413 if (start != 0ul || end != ~0ul) 414 return (NULL); 415 416 if (type == SYS_RES_IRQ) 417 return (bus_alloc_resource(dev, type, rid, start, end, count, 418 flags)); 419 420 if (!sc->sc_kva[dinfo->lbc_unit]) { 421 error = lbc_init_child(dev, child); 422 if (error) 423 return (NULL); 424 } 425 426 error = lbc_get_resource(dev, child, type, *rid, &start, &count); 427 if (error) 428 return (NULL); 429 430 rm = &sc->sc_rman; 431 end = start + count - 1; 432 rv = rman_reserve_resource(rm, start, end, count, flags, child); 433 if (rv != NULL) { 434 rman_set_bustag(rv, &bs_be_tag); 435 rman_set_bushandle(rv, rman_get_start(rv)); 436 } 437 return (rv); 438 } 439 440 static int 441 lbc_print_child(device_t dev, device_t child) 442 { 443 u_long size, start; 444 int error, retval, rid; 445 446 retval = bus_print_child_header(dev, child); 447 448 rid = 0; 449 while (1) { 450 error = lbc_get_resource(dev, child, SYS_RES_MEMORY, rid, 451 &start, &size); 452 if (error) 453 break; 454 retval += (rid == 0) ? printf(" iomem ") : printf(","); 455 retval += printf("%#lx", start); 456 if (size > 1) 457 retval += printf("-%#lx", start + size - 1); 458 rid++; 459 } 460 461 retval += bus_print_child_footer(dev, child); 462 return (retval); 463 } 464 465 static int 466 lbc_read_ivar(device_t dev, device_t child, int index, uintptr_t *result) 467 { 468 struct lbc_devinfo *dinfo; 469 470 if (device_get_parent(child) != dev) 471 return (EINVAL); 472 473 dinfo = device_get_ivars(child); 474 475 switch (index) { 476 case LBC_IVAR_DEVTYPE: 477 *result = dinfo->lbc_devtype; 478 return (0); 479 default: 480 break; 481 } 482 return (EINVAL); 483 } 484 485 static int 486 lbc_release_resource(device_t dev, device_t child, int type, int rid, 487 struct resource *res) 488 { 489 490 return (rman_release_resource(res)); 491 } 492 493 static int 494 lbc_get_resource(device_t dev, device_t child, int type, int rid, 495 u_long *startp, u_long *countp) 496 { 497 struct lbc_softc *sc; 498 struct lbc_devinfo *dinfo; 499 const struct lbc_resource *lbcres; 500 501 if (type != SYS_RES_MEMORY) 502 return (ENOENT); 503 504 /* Currently all LBC devices have a single RID per type. */ 505 if (rid != 0) 506 return (ENOENT); 507 508 sc = device_get_softc(dev); 509 dinfo = device_get_ivars(child); 510 511 if ((dinfo->lbc_unit < 0) || (dinfo->lbc_unit > (LBC_DEV_MAX - 1))) 512 return (EINVAL); 513 514 lbcres = mpc85xx_lbc_resources; 515 516 switch (dinfo->lbc_devtype) { 517 case LBC_DEVTYPE_CFI: 518 case LBC_DEVTYPE_RTC: 519 for (; lbcres->lbr_devtype; lbcres++) { 520 if (dinfo->lbc_unit == lbcres->lbr_unit) { 521 *startp = sc->sc_kva[lbcres->lbr_unit]; 522 *countp = lbcres->lbr_size; 523 return (0); 524 } 525 } 526 default: 527 return (EDOOFUS); 528 } 529 return (0); 530 } 531