2 * Copyright (c) 2006-2008, Juniper Networks, Inc.
3 * Copyright (c) 2008 Semihalf, Rafal Czubak
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
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.
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
30 #include <sys/cdefs.h>
31 __FBSDID("$FreeBSD$");
33 #include <sys/param.h>
34 #include <sys/systm.h>
36 #include <sys/kernel.h>
37 #include <sys/malloc.h>
38 #include <sys/module.h>
41 #include <machine/bus.h>
42 #include <machine/ocpbus.h>
47 #include <powerpc/mpc85xx/lbc.h>
48 #include <powerpc/mpc85xx/mpc85xx.h>
49 #include <powerpc/mpc85xx/ocpbus.h>
54 struct resource *sc_res;
55 bus_space_handle_t sc_bsh;
56 bus_space_tag_t sc_bst;
60 vm_offset_t sc_kva[LBC_DEV_MAX];
65 /* LBC child unit. It also represents resource table entry number */
69 /* Resources for MPC8555CDS system */
70 const struct lbc_resource mpc85xx_lbc_resources[] = {
73 LBC_DEVTYPE_CFI, 0, 0xff800000, 0x00800000, 16,
74 LBCRES_MSEL_GPCM, LBCRES_DECC_DISABLED,
75 LBCRES_ATOM_DISABLED, 0
78 /* Second flash bank */
80 LBC_DEVTYPE_CFI, 1, 0xff000000, 0x00800000, 16,
81 LBCRES_MSEL_GPCM, LBCRES_DECC_DISABLED,
82 LBCRES_ATOM_DISABLED, 0
85 /* DS1553 RTC/NVRAM */
87 LBC_DEVTYPE_RTC, 2, 0xf8000000, 0x8000, 8,
88 LBCRES_MSEL_GPCM, LBCRES_DECC_DISABLED,
89 LBCRES_ATOM_DISABLED, 0
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 *,
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,
105 static int lbc_read_ivar(device_t, device_t, int, uintptr_t *);
108 * Bus interface definition
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),
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),
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),
131 static driver_t lbc_driver = {
134 sizeof(struct lbc_softc)
136 devclass_t lbc_devclass;
137 DRIVER_MODULE(lbc, ocpbus, lbc_driver, lbc_devclass, 0, 0);
140 lbc_write_reg(struct lbc_softc *sc, bus_size_t off, uint32_t val)
143 bus_space_write_4(sc->sc_bst, sc->sc_bsh, off, val);
146 static __inline uint32_t
147 lbc_read_reg(struct lbc_softc *sc, bus_size_t off)
150 return (bus_space_read_4(sc->sc_bst, sc->sc_bsh, off));
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.
160 lbc_address_mask(uint32_t size)
168 if (size == (1UL << n))
176 return (0xffff8000 << (n - 15));
180 lbc_mk_child(device_t dev, const struct lbc_resource *lbcres)
182 struct lbc_devinfo *dinfo;
185 if (lbcres->lbr_unit > LBC_DEV_MAX - 1)
188 child = device_add_child(dev, NULL, -1);
190 device_printf(dev, "could not add LBC child device\n");
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);
201 lbc_init_child(device_t dev, device_t child)
203 struct lbc_softc *sc;
204 struct lbc_devinfo *dinfo;
205 const struct lbc_resource *res;
210 sc = device_get_softc(dev);
211 dinfo = device_get_ivars(child);
213 res = mpc85xx_lbc_resources;
217 for (; res->lbr_devtype; res++) {
218 if (res->lbr_unit != dinfo->lbc_unit)
221 start = res->lbr_base_addr;
222 size = res->lbr_size;
223 unit = res->lbr_unit;
226 * Configure LAW for this LBC device and map its physical
227 * memory region into KVA
229 error = law_enable(OCP85XX_TGTIF_LBC, start, size);
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);
240 * Compute and program BR value
244 switch (res->lbr_port_size) {
246 regbuff |= (1 << 11);
249 regbuff |= (2 << 11);
252 regbuff |= (3 << 11);
258 regbuff |= (res->lbr_decc << 9);
259 regbuff |= (res->lbr_wp << 8);
260 regbuff |= (res->lbr_msel << 5);
261 regbuff |= (res->lbr_atom << 2);
264 lbc_write_reg(sc, LBC85XX_BR(unit), regbuff);
267 * Compute and program OR value
270 regbuff |= lbc_address_mask(size);
272 switch (res->lbr_msel) {
273 case LBCRES_MSEL_GPCM:
274 /* TODO Add flag support for option registers */
275 regbuff |= 0x00000ff7;
277 case LBCRES_MSEL_FCM:
278 printf("FCM mode not supported yet!");
281 case LBCRES_MSEL_UPMA:
282 case LBCRES_MSEL_UPMB:
283 case LBCRES_MSEL_UPMC:
284 printf("UPM mode not supported yet!");
289 lbc_write_reg(sc, LBC85XX_OR(unit), regbuff);
295 law_disable(OCP85XX_TGTIF_LBC, start, size);
296 pmap_unmapdev(sc->sc_kva[unit], size);
303 lbc_probe(device_t dev)
309 parent = device_get_parent(dev);
310 error = BUS_READ_IVAR(parent, dev, OCPBUS_IVAR_DEVTYPE, &devtype);
313 if (devtype != OCPBUS_DEVTYPE_LBC)
316 device_set_desc(dev, "Freescale MPC85xx Local Bus Controller");
317 return (BUS_PROBE_DEFAULT);
321 lbc_attach(device_t dev)
323 struct lbc_softc *sc;
325 const struct lbc_resource *lbcres;
328 sc = device_get_softc(dev);
332 sc->sc_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &sc->sc_rid,
334 if (sc->sc_res == NULL)
337 sc->sc_bst = rman_get_bustag(sc->sc_res);
338 sc->sc_bsh = rman_get_bushandle(sc->sc_res);
341 rm->rm_type = RMAN_ARRAY;
342 rm->rm_descr = "MPC85XX Local Bus Space";
345 error = rman_init(rm);
349 error = rman_manage_region(rm, rm->rm_start, rm->rm_end);
356 * Initialize configuration register:
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
363 lbc_write_reg(sc, LBC85XX_LBCR, 0x00000000);
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
371 lbc_write_reg(sc, LBC85XX_LCRR, 0x00030008);
373 lbcres = mpc85xx_lbc_resources;
375 for (; lbcres->lbr_devtype; lbcres++)
376 if (!lbc_mk_child(dev, lbcres)) {
381 return (bus_generic_attach(dev));
384 bus_release_resource(dev, SYS_RES_MEMORY, sc->sc_rid, sc->sc_res);
389 lbc_shutdown(device_t dev)
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)
400 struct lbc_softc *sc;
401 struct lbc_devinfo *dinfo;
406 sc = device_get_softc(dev);
407 dinfo = device_get_ivars(child);
409 if (type != SYS_RES_MEMORY && type != SYS_RES_IRQ)
412 /* We only support default allocations. */
413 if (start != 0ul || end != ~0ul)
416 if (type == SYS_RES_IRQ)
417 return (bus_alloc_resource(dev, type, rid, start, end, count,
420 if (!sc->sc_kva[dinfo->lbc_unit]) {
421 error = lbc_init_child(dev, child);
426 error = lbc_get_resource(dev, child, type, *rid, &start, &count);
431 end = start + count - 1;
432 rv = rman_reserve_resource(rm, start, end, count, flags, child);
434 rman_set_bustag(rv, &bs_be_tag);
435 rman_set_bushandle(rv, rman_get_start(rv));
441 lbc_print_child(device_t dev, device_t child)
444 int error, retval, rid;
446 retval = bus_print_child_header(dev, child);
450 error = lbc_get_resource(dev, child, SYS_RES_MEMORY, rid,
454 retval += (rid == 0) ? printf(" iomem ") : printf(",");
455 retval += printf("%#lx", start);
457 retval += printf("-%#lx", start + size - 1);
461 retval += bus_print_child_footer(dev, child);
466 lbc_read_ivar(device_t dev, device_t child, int index, uintptr_t *result)
468 struct lbc_devinfo *dinfo;
470 if (device_get_parent(child) != dev)
473 dinfo = device_get_ivars(child);
476 case LBC_IVAR_DEVTYPE:
477 *result = dinfo->lbc_devtype;
486 lbc_release_resource(device_t dev, device_t child, int type, int rid,
487 struct resource *res)
490 return (rman_release_resource(res));
494 lbc_get_resource(device_t dev, device_t child, int type, int rid,
495 u_long *startp, u_long *countp)
497 struct lbc_softc *sc;
498 struct lbc_devinfo *dinfo;
499 const struct lbc_resource *lbcres;
501 if (type != SYS_RES_MEMORY)
504 /* Currently all LBC devices have a single RID per type. */
508 sc = device_get_softc(dev);
509 dinfo = device_get_ivars(child);
511 if ((dinfo->lbc_unit < 0) || (dinfo->lbc_unit > (LBC_DEV_MAX - 1)))
514 lbcres = mpc85xx_lbc_resources;
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;