From owner-svn-src-all@FreeBSD.ORG Thu May 24 21:23:13 2012 Return-Path: Delivered-To: svn-src-all@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [69.147.83.52]) by hub.freebsd.org (Postfix) with ESMTP id B7C2C106564A; Thu, 24 May 2012 21:23:13 +0000 (UTC) (envelope-from marcel@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:4f8:fff6::2c]) by mx1.freebsd.org (Postfix) with ESMTP id A15FB8FC0A; Thu, 24 May 2012 21:23:13 +0000 (UTC) Received: from svn.freebsd.org (localhost [127.0.0.1]) by svn.freebsd.org (8.14.4/8.14.4) with ESMTP id q4OLNDPU061111; Thu, 24 May 2012 21:23:13 GMT (envelope-from marcel@svn.freebsd.org) Received: (from marcel@localhost) by svn.freebsd.org (8.14.4/8.14.4/Submit) id q4OLNDv7061108; Thu, 24 May 2012 21:23:13 GMT (envelope-from marcel@svn.freebsd.org) Message-Id: <201205242123.q4OLNDv7061108@svn.freebsd.org> From: Marcel Moolenaar Date: Thu, 24 May 2012 21:23:13 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: Subject: svn commit: r235937 - head/sys/powerpc/mpc85xx X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 24 May 2012 21:23:13 -0000 Author: marcel Date: Thu May 24 21:23:13 2012 New Revision: 235937 URL: http://svn.freebsd.org/changeset/base/235937 Log: A few improvements: 1. Define all registers. These definitions are needed to support the FCM driver for direct-connect NAND. 2. Repurpose lbc_read_reg() and lbc_write_reg() for use by localbus attached device drivers. Use bus_space functions directly in the lbc driver itself. 3. Be smarter about programming LAWs and mapping memory. The ranges defined in the FDT are per bank (= chip select) and since we can have up to 8 banks, we could easily use more than 8 LAWs or TLB enrties when per-bank memory ranges need multiple LAWs or TLBs due to alignment or size constraints. We now combine all memory ranges into the fewest possible set of contiguous regions and program the hardware for that. Thus, a cleverly written FDT with 8 devices may still only need 1 LAW or 1 TLB entry. Note that the memory ranges can be assigned randomly to the banks. We sort as we build to handle that. 4. Support the FCM when programming the OR register. This is mostly for documention purposes as we do not have a way to define the mode for a bank. 5. Remove Semihalf-ism: do not define DEBUG (only to undefine it again). Modified: head/sys/powerpc/mpc85xx/lbc.c head/sys/powerpc/mpc85xx/lbc.h Modified: head/sys/powerpc/mpc85xx/lbc.c ============================================================================== --- head/sys/powerpc/mpc85xx/lbc.c Thu May 24 21:13:24 2012 (r235936) +++ head/sys/powerpc/mpc85xx/lbc.c Thu May 24 21:23:13 2012 (r235937) @@ -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; - - for (i = 0; i < LBC_DEV_MAX; i++) { - if (sc->sc_banks[i].size == 0) - continue; + int r; - 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); + r = 0; + while (r < LBC_DEV_MAX) { + if (sc->sc_range[r].size == 0) + return; + + 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); + } + + /* 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; - 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); + 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, struc 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 c 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)); +} Modified: head/sys/powerpc/mpc85xx/lbc.h ============================================================================== --- head/sys/powerpc/mpc85xx/lbc.h Thu May 24 21:13:24 2012 (r235936) +++ head/sys/powerpc/mpc85xx/lbc.h Thu May 24 21:23:13 2012 (r235937) @@ -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_ */