diff options
author | marcel <marcel@FreeBSD.org> | 2012-07-03 00:06:14 +0000 |
---|---|---|
committer | marcel <marcel@FreeBSD.org> | 2012-07-03 00:06:14 +0000 |
commit | 307b767363e7c81ac24162a7dba152c50e9958df (patch) | |
tree | 4792b1b0a646e055b51bdcba7332129062e28093 /sys/powerpc | |
parent | 1b1a4a52a8872e6c695f0442d1e09846768aefa4 (diff) | |
download | FreeBSD-src-307b767363e7c81ac24162a7dba152c50e9958df.zip FreeBSD-src-307b767363e7c81ac24162a7dba152c50e9958df.tar.gz |
Support lbc interrupts:
o Save and clear the LTESR register in the interrupt handler.
o In lbc_read_reg(), return the saved LTESR register value if applicable
(i.e. when the saved value is not invalid (read: ~0U)).
o In lbc_write_reg(), clear the bits in the saved register when when it's
written to and when the asved value is not invalid.
o Also in lbc_write_reg(), the LTESR register is unlocked (in H/W) when
bit 1 of LTEATR is cleared. We use this to invalidate our saved LTESR
register value. Subsequent reads and write go to H/W directly.
While here:
o In lbc_read_reg() & lbc_write_reg(), add some belts and suspenders to
catch when register offsets are out of range.
o In lbc_attach(), initialize completely and don't leave something left
for lbc_banks_enable().
Diffstat (limited to 'sys/powerpc')
-rw-r--r-- | sys/powerpc/mpc85xx/lbc.c | 131 | ||||
-rw-r--r-- | sys/powerpc/mpc85xx/lbc.h | 11 |
2 files changed, 108 insertions, 34 deletions
diff --git a/sys/powerpc/mpc85xx/lbc.c b/sys/powerpc/mpc85xx/lbc.c index 9737215..cbcd9fc 100644 --- a/sys/powerpc/mpc85xx/lbc.c +++ b/sys/powerpc/mpc85xx/lbc.c @@ -273,13 +273,8 @@ lbc_banks_enable(struct lbc_softc *sc) for (i = 0; i < LBC_DEV_MAX; i++) { size = sc->sc_banks[i].size; - if (size == 0) { - bus_space_write_4(sc->sc_bst, sc->sc_bsh, - LBC85XX_BR(i), 0); - bus_space_write_4(sc->sc_bst, sc->sc_bsh, - LBC85XX_OR(i), 0); + if (size == 0) continue; - } /* * Compute and program BR value. @@ -331,23 +326,6 @@ lbc_banks_enable(struct lbc_softc *sc) LBC85XX_OR(i), regval); } - /* - * Initialize configuration register: - * - enable Local Bus - * - set data buffer control signal function - * - disable parity byte select - * - set ECC parity type - * - set bus monitor timing and timer prescale - */ - bus_space_write_4(sc->sc_bst, sc->sc_bsh, LBC85XX_LBCR, 0); - - /* - * Initialize clock ratio register: - * - disable PLL bypass mode - * - configure LCLK delay cycles for the assertion of LALE - * - set system clock divider - */ - bus_space_write_4(sc->sc_bst, sc->sc_bsh, LBC85XX_LCRR, 0x00030008); return (0); fail: @@ -426,6 +404,18 @@ out: return (rv); } +static void +lbc_intr(void *arg) +{ + struct lbc_softc *sc = arg; + uint32_t ltesr; + + ltesr = bus_space_read_4(sc->sc_bst, sc->sc_bsh, LBC85XX_LTESR); + sc->sc_ltesr = ltesr; + bus_space_write_4(sc->sc_bst, sc->sc_bsh, LBC85XX_LTESR, ltesr); + wakeup(sc->sc_dev); +} + static int lbc_probe(device_t dev) { @@ -455,14 +445,59 @@ lbc_attach(device_t dev) sc = device_get_softc(dev); sc->sc_dev = dev; - sc->sc_rid = 0; - sc->sc_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &sc->sc_rid, + sc->sc_mrid = 0; + sc->sc_mres = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &sc->sc_mrid, RF_ACTIVE); - if (sc->sc_res == NULL) + if (sc->sc_mres == NULL) return (ENXIO); - sc->sc_bst = rman_get_bustag(sc->sc_res); - sc->sc_bsh = rman_get_bushandle(sc->sc_res); + sc->sc_bst = rman_get_bustag(sc->sc_mres); + sc->sc_bsh = rman_get_bushandle(sc->sc_mres); + + for (bank = 0; bank < LBC_DEV_MAX; bank++) { + bus_space_write_4(sc->sc_bst, sc->sc_bsh, LBC85XX_BR(bank), 0); + bus_space_write_4(sc->sc_bst, sc->sc_bsh, LBC85XX_OR(bank), 0); + } + + /* + * Initialize configuration register: + * - enable Local Bus + * - set data buffer control signal function + * - disable parity byte select + * - set ECC parity type + * - set bus monitor timing and timer prescale + */ + bus_space_write_4(sc->sc_bst, sc->sc_bsh, LBC85XX_LBCR, 0); + + /* + * Initialize clock ratio register: + * - disable PLL bypass mode + * - configure LCLK delay cycles for the assertion of LALE + * - set system clock divider + */ + bus_space_write_4(sc->sc_bst, sc->sc_bsh, LBC85XX_LCRR, 0x00030008); + + bus_space_write_4(sc->sc_bst, sc->sc_bsh, LBC85XX_LTEDR, 0); + bus_space_write_4(sc->sc_bst, sc->sc_bsh, LBC85XX_LTESR, ~0); + bus_space_write_4(sc->sc_bst, sc->sc_bsh, LBC85XX_LTEIR, 0x64080001); + + sc->sc_irid = 0; + sc->sc_ires = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->sc_irid, + RF_ACTIVE | RF_SHAREABLE); + if (sc->sc_ires != NULL) { + error = bus_setup_intr(dev, sc->sc_ires, + INTR_TYPE_MISC | INTR_MPSAFE, NULL, lbc_intr, sc, + &sc->sc_icookie); + if (error) { + device_printf(dev, "could not activate interrupt\n"); + bus_release_resource(dev, SYS_RES_IRQ, sc->sc_irid, + sc->sc_ires); + sc->sc_ires = NULL; + } + } + + sc->sc_ltesr = ~0; + rangesptr = NULL; rm = &sc->sc_rman; @@ -614,7 +649,7 @@ lbc_attach(device_t dev) fail: free(rangesptr, M_OFWPROP); - bus_release_resource(dev, SYS_RES_MEMORY, sc->sc_rid, sc->sc_res); + bus_release_resource(dev, SYS_RES_MEMORY, sc->sc_mrid, sc->sc_mres); return (error); } @@ -742,17 +777,49 @@ lbc_get_devinfo(device_t bus, device_t child) void lbc_write_reg(device_t child, u_int off, uint32_t val) { + device_t dev; struct lbc_softc *sc; - sc = device_get_softc(device_get_parent(child)); + dev = device_get_parent(child); + + if (off >= 0x1000) { + device_printf(dev, "%s(%s): invalid offset %#x\n", + __func__, device_get_nameunit(child), off); + return; + } + + sc = device_get_softc(dev); + + if (off == LBC85XX_LTESR && sc->sc_ltesr != ~0u) { + sc->sc_ltesr ^= (val & sc->sc_ltesr); + return; + } + + if (off == LBC85XX_LTEATR && (val & 1) == 0) + sc->sc_ltesr = ~0u; bus_space_write_4(sc->sc_bst, sc->sc_bsh, off, val); } uint32_t lbc_read_reg(device_t child, u_int off) { + device_t dev; struct lbc_softc *sc; + uint32_t val; + + dev = device_get_parent(child); + + if (off >= 0x1000) { + device_printf(dev, "%s(%s): invalid offset %#x\n", + __func__, device_get_nameunit(child), off); + return (~0U); + } + + sc = device_get_softc(dev); - sc = device_get_softc(device_get_parent(child)); - return (bus_space_read_4(sc->sc_bst, sc->sc_bsh, off)); + if (off == LBC85XX_LTESR && sc->sc_ltesr != ~0U) + val = sc->sc_ltesr; + else + val = bus_space_read_4(sc->sc_bst, sc->sc_bsh, off); + return (val); } diff --git a/sys/powerpc/mpc85xx/lbc.h b/sys/powerpc/mpc85xx/lbc.h index 53d9e1c..9b3ad91 100644 --- a/sys/powerpc/mpc85xx/lbc.h +++ b/sys/powerpc/mpc85xx/lbc.h @@ -105,10 +105,15 @@ struct lbc_bank { struct lbc_softc { device_t sc_dev; - struct resource *sc_res; + + struct resource *sc_mres; bus_space_handle_t sc_bsh; bus_space_tag_t sc_bst; - int sc_rid; + int sc_mrid; + + int sc_irid; + struct resource *sc_ires; + void *sc_icookie; struct rman sc_rman; @@ -117,6 +122,8 @@ struct lbc_softc { struct lbc_memrange sc_range[LBC_DEV_MAX]; struct lbc_bank sc_banks[LBC_DEV_MAX]; + + uint32_t sc_ltesr; }; struct lbc_devinfo { |