diff --git a/sys/powerpc/mpc85xx/lbc.c b/sys/powerpc/mpc85xx/lbc.c index e993bced9ae..9737215e787 100644 --- a/sys/powerpc/mpc85xx/lbc.c +++ b/sys/powerpc/mpc85xx/lbc.c @@ -56,9 +56,6 @@ __FBSDID("$FreeBSD$"); #include "ofw_bus_if.h" #include "lbc.h" -#define DEBUG -#undef DEBUG - #ifdef DEBUG #define debugf(fmt, args...) do { printf("%s(): ", __func__); \ printf(fmt,##args); } while (0) @@ -66,20 +63,6 @@ __FBSDID("$FreeBSD$"); #define debugf(fmt, args...) #endif -static __inline void -lbc_write_reg(struct lbc_softc *sc, bus_size_t off, uint32_t val) -{ - - bus_space_write_4(sc->sc_bst, sc->sc_bsh, off, val); -} - -static __inline uint32_t -lbc_read_reg(struct lbc_softc *sc, bus_size_t off) -{ - - return (bus_space_read_4(sc->sc_bst, sc->sc_bsh, off)); -} - static MALLOC_DEFINE(M_LBC, "localbus", "localbus devices information"); static int lbc_probe(device_t); @@ -161,46 +144,123 @@ lbc_address_mask(uint32_t size) static void lbc_banks_unmap(struct lbc_softc *sc) { - int i; + int r; - for (i = 0; i < LBC_DEV_MAX; i++) { - if (sc->sc_banks[i].size == 0) - continue; + r = 0; + while (r < LBC_DEV_MAX) { + if (sc->sc_range[r].size == 0) + return; - law_disable(OCP85XX_TGTIF_LBC, sc->sc_banks[i].pa, - sc->sc_banks[i].size); - pmap_unmapdev(sc->sc_banks[i].va, sc->sc_banks[i].size); + pmap_unmapdev(sc->sc_range[r].kva, sc->sc_range[r].size); + law_disable(OCP85XX_TGTIF_LBC, sc->sc_range[r].addr, + sc->sc_range[r].size); + r++; } } static int lbc_banks_map(struct lbc_softc *sc) { - u_long start, size; - int error, i; + vm_paddr_t end, start; + vm_size_t size; + u_int i, r, ranges, s; + int error; + bzero(sc->sc_range, sizeof(sc->sc_range)); + + /* + * Determine number of discontiguous address ranges to program. + */ + ranges = 0; for (i = 0; i < LBC_DEV_MAX; i++) { - if (sc->sc_banks[i].size == 0) + size = sc->sc_banks[i].size; + if (size == 0) continue; - /* Physical address start/size. */ - start = sc->sc_banks[i].pa; - size = sc->sc_banks[i].size; + start = sc->sc_banks[i].addr; + for (r = 0; r < ranges; r++) { + /* Avoid wrap-around bugs. */ + end = sc->sc_range[r].addr - 1 + sc->sc_range[r].size; + if (start > 0 && end == start - 1) { + sc->sc_range[r].size += size; + break; + } + /* Avoid wrap-around bugs. */ + end = start - 1 + size; + if (sc->sc_range[r].addr > 0 && + end == sc->sc_range[r].addr - 1) { + sc->sc_range[r].addr = start; + sc->sc_range[r].size += size; + break; + } + } + if (r == ranges) { + /* New range; add using insertion sort */ + r = 0; + while (r < ranges && sc->sc_range[r].addr < start) + r++; + for (s = ranges; s > r; s--) + sc->sc_range[s] = sc->sc_range[s-1]; + sc->sc_range[r].addr = start; + sc->sc_range[r].size = size; + ranges++; + } + } - /* - * Configure LAW for this LBC bank (CS) and map its physical - * memory region into KVA. - */ + /* + * Ranges are sorted so quickly go over the list to merge ranges + * that grew toward each other while building the ranges. + */ + r = 0; + while (r < ranges - 1) { + end = sc->sc_range[r].addr + sc->sc_range[r].size; + if (end != sc->sc_range[r+1].addr) { + r++; + continue; + } + sc->sc_range[r].size += sc->sc_range[r+1].size; + for (s = r + 1; s < ranges - 1; s++) + sc->sc_range[s] = sc->sc_range[s+1]; + bzero(&sc->sc_range[s], sizeof(sc->sc_range[s])); + ranges--; + } + + /* + * Configure LAW for the LBC ranges and map the physical memory + * range into KVA. + */ + for (r = 0; r < ranges; r++) { + start = sc->sc_range[r].addr; + size = sc->sc_range[r].size; error = law_enable(OCP85XX_TGTIF_LBC, start, size); if (error) return (error); + sc->sc_range[r].kva = (vm_offset_t)pmap_mapdev(start, size); + } - sc->sc_banks[i].va = (vm_offset_t)pmap_mapdev(start, size); - if (sc->sc_banks[i].va == 0) { - lbc_banks_unmap(sc); - return (ENOSPC); + /* XXX: need something better here? */ + if (ranges == 0) + return (EINVAL); + + /* Assign KVA to banks based on the enclosing range. */ + for (i = 0; i < LBC_DEV_MAX; i++) { + size = sc->sc_banks[i].size; + if (size == 0) + continue; + + start = sc->sc_banks[i].addr; + for (r = 0; r < ranges; r++) { + end = sc->sc_range[r].addr - 1 + sc->sc_range[r].size; + if (start >= sc->sc_range[r].addr && + start - 1 + size <= end) + break; + } + if (r < ranges) { + sc->sc_banks[i].kva = sc->sc_range[r].kva + + (start - sc->sc_range[r].addr); } } + return (0); } @@ -213,14 +273,18 @@ lbc_banks_enable(struct lbc_softc *sc) for (i = 0; i < LBC_DEV_MAX; i++) { size = sc->sc_banks[i].size; - if (size == 0) + 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); continue; + } + /* * Compute and program BR value. */ - regval = 0; - regval |= sc->sc_banks[i].pa; - + regval = sc->sc_banks[i].addr; switch (sc->sc_banks[i].width) { case 8: regval |= (1 << 11); @@ -240,24 +304,22 @@ lbc_banks_enable(struct lbc_softc *sc) regval |= (sc->sc_banks[i].msel << 5); regval |= (sc->sc_banks[i].atom << 2); regval |= 1; - - lbc_write_reg(sc, LBC85XX_BR(i), regval); + bus_space_write_4(sc->sc_bst, sc->sc_bsh, + LBC85XX_BR(i), regval); /* * Compute and program OR value. */ - regval = 0; - regval |= lbc_address_mask(size); - + regval = lbc_address_mask(size); switch (sc->sc_banks[i].msel) { case LBCRES_MSEL_GPCM: /* TODO Add flag support for option registers */ - regval |= 0x00000ff7; + regval |= 0x0ff7; break; case LBCRES_MSEL_FCM: - printf("FCM mode not supported yet!"); - error = ENOSYS; - goto fail; + /* TODO Add flag support for options register */ + regval |= 0x0796; + break; case LBCRES_MSEL_UPMA: case LBCRES_MSEL_UPMB: case LBCRES_MSEL_UPMC: @@ -265,7 +327,8 @@ lbc_banks_enable(struct lbc_softc *sc) error = ENOSYS; goto fail; } - lbc_write_reg(sc, LBC85XX_OR(i), regval); + bus_space_write_4(sc->sc_bst, sc->sc_bsh, + LBC85XX_OR(i), regval); } /* @@ -276,7 +339,7 @@ lbc_banks_enable(struct lbc_softc *sc) * - set ECC parity type * - set bus monitor timing and timer prescale */ - lbc_write_reg(sc, LBC85XX_LBCR, 0); + bus_space_write_4(sc->sc_bst, sc->sc_bsh, LBC85XX_LBCR, 0); /* * Initialize clock ratio register: @@ -284,8 +347,7 @@ lbc_banks_enable(struct lbc_softc *sc) * - configure LCLK delay cycles for the assertion of LALE * - set system clock divider */ - lbc_write_reg(sc, LBC85XX_LCRR, 0x00030008); - + bus_space_write_4(sc->sc_bst, sc->sc_bsh, LBC85XX_LCRR, 0x00030008); return (0); fail: @@ -348,7 +410,7 @@ fdt_lbc_reg_decode(phandle_t node, struct lbc_softc *sc, reg += addr_cells - 1 + size_cells; /* Calculate address range relative to VA base. */ - start = sc->sc_banks[bank].va + start; + start = sc->sc_banks[bank].kva + start; end = start + count - 1; debugf("reg addr bank = %d, start = %lx, end = %lx, " @@ -479,7 +541,7 @@ lbc_attach(device_t dev) debugf("bank = %d, start = %lx, size = %lx\n", bank, start, size); - sc->sc_banks[bank].pa = start + offset; + sc->sc_banks[bank].addr = start + offset; sc->sc_banks[bank].size = size; /* @@ -676,3 +738,21 @@ lbc_get_devinfo(device_t bus, device_t child) di = device_get_ivars(child); return (&di->di_ofw); } + +void +lbc_write_reg(device_t child, u_int off, uint32_t val) +{ + struct lbc_softc *sc; + + sc = device_get_softc(device_get_parent(child)); + bus_space_write_4(sc->sc_bst, sc->sc_bsh, off, val); +} + +uint32_t +lbc_read_reg(device_t child, u_int off) +{ + struct lbc_softc *sc; + + sc = device_get_softc(device_get_parent(child)); + return (bus_space_read_4(sc->sc_bst, sc->sc_bsh, off)); +} diff --git a/sys/powerpc/mpc85xx/lbc.h b/sys/powerpc/mpc85xx/lbc.h index ee58607661d..53d9e1c71a7 100644 --- a/sys/powerpc/mpc85xx/lbc.h +++ b/sys/powerpc/mpc85xx/lbc.h @@ -33,10 +33,35 @@ #define LBC_DEV_MAX 8 /* Local access registers */ -#define LBC85XX_BR(n) (8 * n) -#define LBC85XX_OR(n) (4 + (8 * n)) -#define LBC85XX_LBCR (0xd0) -#define LBC85XX_LCRR (0xd4) +#define LBC85XX_BR(n) (0x0 + (8 * n)) /* Base register 0-7 */ +#define LBC85XX_OR(n) (0x4 + (8 * n)) /* Options register 0-7 */ +#define LBC85XX_MAR 0x068 /* UPM address register */ +#define LBC85XX_MAMR 0x070 /* UPMA mode register */ +#define LBC85XX_MBMR 0x074 /* UPMB mode register */ +#define LBC85XX_MCMR 0x078 /* UPMC mode register */ +#define LBC85XX_MRTPR 0x084 /* Memory refresh timer prescaler */ +#define LBC85XX_MDR 0x088 /* UPM data register */ +#define LBC85XX_LSOR 0x090 /* Special operation initiation */ +#define LBC85XX_LURT 0x0a0 /* UPM refresh timer */ +#define LBC85XX_LSRT 0x0a4 /* SDRAM refresh timer */ +#define LBC85XX_LTESR 0x0b0 /* Transfer error status register */ +#define LBC85XX_LTEDR 0x0b4 /* Transfer error disable register */ +#define LBC85XX_LTEIR 0x0b8 /* Transfer error interrupt register */ +#define LBC85XX_LTEATR 0x0bc /* Transfer error attributes register */ +#define LBC85XX_LTEAR 0x0c0 /* Transfer error address register */ +#define LBC85XX_LTECCR 0x0c4 /* Transfer error ECC register */ +#define LBC85XX_LBCR 0x0d0 /* Configuration register */ +#define LBC85XX_LCRR 0x0d4 /* Clock ratio register */ +#define LBC85XX_FMR 0x0e0 /* Flash mode register */ +#define LBC85XX_FIR 0x0e4 /* Flash instruction register */ +#define LBC85XX_FCR 0x0e8 /* Flash command register */ +#define LBC85XX_FBAR 0x0ec /* Flash block address register */ +#define LBC85XX_FPAR 0x0f0 /* Flash page address register */ +#define LBC85XX_FBCR 0x0f4 /* Flash byte count register */ +#define LBC85XX_FECC0 0x100 /* Flash ECC block 0 register */ +#define LBC85XX_FECC1 0x104 /* Flash ECC block 0 register */ +#define LBC85XX_FECC2 0x108 /* Flash ECC block 0 register */ +#define LBC85XX_FECC3 0x10c /* Flash ECC block 0 register */ /* LBC machine select */ #define LBCRES_MSEL_GPCM 0 @@ -55,10 +80,16 @@ #define LBCRES_ATOM_RAWA 1 #define LBCRES_ATOM_WARA 2 +struct lbc_memrange { + vm_paddr_t addr; + vm_size_t size; + vm_offset_t kva; +}; + struct lbc_bank { - u_long pa; /* physical addr of the bank */ - u_long size; /* bank size */ - vm_offset_t va; /* VA of the bank */ + vm_paddr_t addr; /* physical addr of the bank */ + vm_size_t size; /* bank size */ + vm_offset_t kva; /* VA of the bank */ /* * XXX the following bank attributes do not have properties specified @@ -84,6 +115,7 @@ struct lbc_softc { int sc_addr_cells; int sc_size_cells; + struct lbc_memrange sc_range[LBC_DEV_MAX]; struct lbc_bank sc_banks[LBC_DEV_MAX]; }; @@ -93,4 +125,7 @@ struct lbc_devinfo { int di_bank; }; +uint32_t lbc_read_reg(device_t child, u_int off); +void lbc_write_reg(device_t child, u_int off, uint32_t val); + #endif /* _MACHINE_LBC_H_ */