lbc.c (184250) | lbc.c (186288) |
---|---|
1/*- 2 * Copyright (c) 2006-2008, Juniper Networks, Inc. | 1/*- 2 * Copyright (c) 2006-2008, Juniper Networks, Inc. |
3 * Copyright (c) 2008 Semihalf, Rafal Czubak |
|
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 unchanged lines hidden (view full) --- 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> | 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> |
30__FBSDID("$FreeBSD: head/sys/powerpc/mpc85xx/lbc.c 184250 2008-10-25 06:03:40Z marcel $"); | 31__FBSDID("$FreeBSD: head/sys/powerpc/mpc85xx/lbc.c 186288 2008-12-18 18:27:12Z raj $"); |
31 32#include <sys/param.h> 33#include <sys/systm.h> 34#include <sys/ktr.h> 35#include <sys/kernel.h> 36#include <sys/malloc.h> 37#include <sys/module.h> 38#include <sys/bus.h> 39#include <sys/rman.h> 40#include <machine/bus.h> 41#include <machine/ocpbus.h> 42 43#include <vm/vm.h> 44#include <vm/pmap.h> 45 46#include <powerpc/mpc85xx/lbc.h> | 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> |
|
47 48struct lbc_softc { 49 device_t sc_dev; 50 51 struct resource *sc_res; 52 bus_space_handle_t sc_bsh; 53 bus_space_tag_t sc_bst; 54 int sc_rid; 55 56 struct rman sc_rman; | 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; |
57 uintptr_t sc_kva; | 60 vm_offset_t sc_kva[LBC_DEV_MAX]; |
58}; 59 60struct lbc_devinfo { 61 int lbc_devtype; | 61}; 62 63struct lbc_devinfo { 64 int lbc_devtype; |
62 int lbc_memtype; 63 /* Also the BAR number */ | 65 /* LBC child unit. It also represents resource table entry number */ |
64 int lbc_unit; 65}; 66 | 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 |
|
67static int lbc_probe(device_t); 68static int lbc_attach(device_t); 69static int lbc_shutdown(device_t); 70static int lbc_get_resource(device_t, device_t, int, int, u_long *, 71 u_long *); 72static struct resource *lbc_alloc_resource(device_t, device_t, int, int *, 73 u_long, u_long, u_long, u_int); 74static int lbc_print_child(device_t, device_t); --- 28 unchanged lines hidden (view full) --- 103static driver_t lbc_driver = { 104 "lbc", 105 lbc_methods, 106 sizeof(struct lbc_softc) 107}; 108devclass_t lbc_devclass; 109DRIVER_MODULE(lbc, ocpbus, lbc_driver, lbc_devclass, 0, 0); 110 | 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 |
|
111static device_t | 179static device_t |
112lbc_mk_child(device_t dev, int type, int mtype, int unit) | 180lbc_mk_child(device_t dev, const struct lbc_resource *lbcres) |
113{ 114 struct lbc_devinfo *dinfo; 115 device_t child; 116 | 181{ 182 struct lbc_devinfo *dinfo; 183 device_t child; 184 |
185 if (lbcres->lbr_unit > LBC_DEV_MAX - 1) 186 return (NULL); 187 |
|
117 child = device_add_child(dev, NULL, -1); 118 if (child == NULL) { | 188 child = device_add_child(dev, NULL, -1); 189 if (child == NULL) { |
119 device_printf(dev, "could not add child device\n"); | 190 device_printf(dev, "could not add LBC child device\n"); |
120 return (NULL); 121 } 122 dinfo = malloc(sizeof(struct lbc_devinfo), M_DEVBUF, M_WAITOK | M_ZERO); | 191 return (NULL); 192 } 193 dinfo = malloc(sizeof(struct lbc_devinfo), M_DEVBUF, M_WAITOK | M_ZERO); |
123 dinfo->lbc_devtype = type; 124 dinfo->lbc_memtype = mtype; 125 dinfo->lbc_unit = unit; | 194 dinfo->lbc_devtype = lbcres->lbr_devtype; 195 dinfo->lbc_unit = lbcres->lbr_unit; |
126 device_set_ivars(child, dinfo); 127 return (child); 128} 129 130static int | 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 |
|
131lbc_probe(device_t dev) 132{ 133 device_t parent; 134 uintptr_t devtype; 135 int error; 136 137 parent = device_get_parent(dev); 138 error = BUS_READ_IVAR(parent, dev, OCPBUS_IVAR_DEVTYPE, &devtype); --- 6 unchanged lines hidden (view full) --- 145 return (BUS_PROBE_DEFAULT); 146} 147 148static int 149lbc_attach(device_t dev) 150{ 151 struct lbc_softc *sc; 152 struct rman *rm; | 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; |
153 u_long start, size; | 325 const struct lbc_resource *lbcres; |
154 int error; 155 156 sc = device_get_softc(dev); 157 sc->sc_dev = dev; 158 159 sc->sc_rid = 0; 160 sc->sc_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &sc->sc_rid, 161 RF_ACTIVE); 162 if (sc->sc_res == NULL) 163 return (ENXIO); 164 165 sc->sc_bst = rman_get_bustag(sc->sc_res); 166 sc->sc_bsh = rman_get_bushandle(sc->sc_res); 167 | 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 |
168 error = bus_get_resource(dev, SYS_RES_MEMORY, 1, &start, &size); 169 if (error) 170 goto fail; 171 | |
172 rm = &sc->sc_rman; 173 rm->rm_type = RMAN_ARRAY; 174 rm->rm_descr = "MPC85XX Local Bus Space"; | 340 rm = &sc->sc_rman; 341 rm->rm_type = RMAN_ARRAY; 342 rm->rm_descr = "MPC85XX Local Bus Space"; |
175 rm->rm_start = start; 176 rm->rm_end = start + size - 1; | 343 rm->rm_start = 0UL; 344 rm->rm_end = ~0UL; |
177 error = rman_init(rm); 178 if (error) 179 goto fail; 180 181 error = rman_manage_region(rm, rm->rm_start, rm->rm_end); 182 if (error) { 183 rman_fini(rm); 184 goto fail; 185 } 186 | 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 |
187 sc->sc_kva = (uintptr_t)pmap_mapdev(start, size); | 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); |
188 | 364 |
189 lbc_mk_child(dev, LBC_DEVTYPE_CFI, 0, 0); | 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); |
190 | 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 |
|
191 return (bus_generic_attach(dev)); 192 | 381 return (bus_generic_attach(dev)); 382 |
193 fail: | 383fail: |
194 bus_release_resource(dev, SYS_RES_MEMORY, sc->sc_rid, sc->sc_res); 195 return (error); 196} 197 198static int 199lbc_shutdown(device_t dev) 200{ 201 202 /* TODO */ 203 return(0); 204} 205 206static struct resource * 207lbc_alloc_resource(device_t dev, device_t child, int type, int *rid, 208 u_long start, u_long end, u_long count, u_int flags) 209{ 210 struct lbc_softc *sc; | 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; |
|
211 struct resource *rv; 212 struct rman *rm; 213 int error; 214 215 sc = device_get_softc(dev); | 402 struct resource *rv; 403 struct rman *rm; 404 int error; 405 406 sc = device_get_softc(dev); |
407 dinfo = device_get_ivars(child); |
|
216 217 if (type != SYS_RES_MEMORY && type != SYS_RES_IRQ) 218 return (NULL); 219 220 /* We only support default allocations. */ 221 if (start != 0ul || end != ~0ul) 222 return (NULL); 223 224 if (type == SYS_RES_IRQ) 225 return (bus_alloc_resource(dev, type, rid, start, end, count, 226 flags)); 227 | 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 |
|
228 error = lbc_get_resource(dev, child, type, *rid, &start, &count); 229 if (error) 230 return (NULL); 231 232 rm = &sc->sc_rman; 233 end = start + count - 1; 234 rv = rman_reserve_resource(rm, start, end, count, flags, child); 235 if (rv != NULL) { 236 rman_set_bustag(rv, &bs_be_tag); | 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); |
237 rman_set_bushandle(rv, sc->sc_kva + rman_get_start(rv) - 238 rm->rm_start); | 435 rman_set_bushandle(rv, rman_get_start(rv)); |
239 } 240 return (rv); 241} 242 243static int 244lbc_print_child(device_t dev, device_t child) 245{ 246 u_long size, start; --- 27 unchanged lines hidden (view full) --- 274 return (EINVAL); 275 276 dinfo = device_get_ivars(child); 277 278 switch (index) { 279 case LBC_IVAR_DEVTYPE: 280 *result = dinfo->lbc_devtype; 281 return (0); | 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); |
282 case LBC_IVAR_CLOCK: 283 *result = 1843200; 284 return (0); 285 case LBC_IVAR_REGSHIFT: 286 *result = 0; 287 return (0); | |
288 default: 289 break; 290 } 291 return (EINVAL); 292} 293 294static int 295lbc_release_resource(device_t dev, device_t child, int type, int rid, --- 4 unchanged lines hidden (view full) --- 300} 301 302static int 303lbc_get_resource(device_t dev, device_t child, int type, int rid, 304 u_long *startp, u_long *countp) 305{ 306 struct lbc_softc *sc; 307 struct lbc_devinfo *dinfo; | 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; |
|
308 309 if (type != SYS_RES_MEMORY) 310 return (ENOENT); 311 | 500 501 if (type != SYS_RES_MEMORY) 502 return (ENOENT); 503 |
312 /* Currently all devices have a single RID per type. */ | 504 /* Currently all LBC devices have a single RID per type. */ |
313 if (rid != 0) 314 return (ENOENT); 315 316 sc = device_get_softc(dev); 317 dinfo = device_get_ivars(child); 318 | 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 |
|
319 switch (dinfo->lbc_devtype) { 320 case LBC_DEVTYPE_CFI: | 516 switch (dinfo->lbc_devtype) { 517 case LBC_DEVTYPE_CFI: |
321 *startp = sc->sc_rman.rm_start; 322 *countp = sc->sc_rman.rm_end - sc->sc_rman.rm_start + 1; 323 break; | 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 } |
324 default: | 526 default: |
325 return(EDOOFUS); | 527 return (EDOOFUS); |
326 } | 528 } |
327 return(0); | 529 return (0); |
328} | 530} |