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 --- 11 unchanged lines hidden (view full) --- 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: head/sys/powerpc/mpc85xx/lbc.c 186288 2008-12-18 18:27:12Z raj $"); |
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 51struct 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 63struct 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 */ 70const 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 |
95static int lbc_probe(device_t); 96static int lbc_attach(device_t); 97static int lbc_shutdown(device_t); 98static int lbc_get_resource(device_t, device_t, int, int, u_long *, 99 u_long *); 100static struct resource *lbc_alloc_resource(device_t, device_t, int, int *, 101 u_long, u_long, u_long, u_int); 102static int lbc_print_child(device_t, device_t); --- 28 unchanged lines hidden (view full) --- 131static driver_t lbc_driver = { 132 "lbc", 133 lbc_methods, 134 sizeof(struct lbc_softc) 135}; 136devclass_t lbc_devclass; 137DRIVER_MODULE(lbc, ocpbus, lbc_driver, lbc_devclass, 0, 0); 138 |
139static __inline void 140lbc_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 146static __inline uint32_t 147lbc_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 */ 159static uint32_t 160lbc_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 |
179static device_t |
180lbc_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 200static int |
201lbc_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 } 293fail: 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 302static int |
303lbc_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); --- 6 unchanged lines hidden (view full) --- 317 return (BUS_PROBE_DEFAULT); 318} 319 320static int 321lbc_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 |
383fail: |
384 bus_release_resource(dev, SYS_RES_MEMORY, sc->sc_rid, sc->sc_res); 385 return (error); 386} 387 388static int 389lbc_shutdown(device_t dev) 390{ 391 392 /* TODO */ 393 return(0); 394} 395 396static struct resource * 397lbc_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 440static int 441lbc_print_child(device_t dev, device_t child) 442{ 443 u_long size, start; --- 27 unchanged lines hidden (view full) --- 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 485static int 486lbc_release_resource(device_t dev, device_t child, int type, int rid, --- 4 unchanged lines hidden (view full) --- 491} 492 493static int 494lbc_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} |