static void fsl_nand_init_regs(struct fsl_nand_softc *sc) { uint32_t or_v, br_v; device_t dev; dev = sc->dev; sc->fcm.reg_fmr = (15 << FMR_CWTO_SHIFT); /* * Setup 4 row cycles and hope that chip ignores superfluous address * bytes. */ sc->fcm.reg_fmr |= (2 << FMR_AL_SHIFT); /* Reprogram BR(x) */ br_v = lbc_read_reg(dev, LBC85XX_BR(sc->dinfo->di_bank)); br_v &= 0xffff8000; br_v |= 1 << 11; /* 8-bit port size */ br_v |= 0 << 9; /* No ECC checking and generation */ br_v |= 1 << 5; /* FCM machine */ br_v |= 1; /* Valid */ lbc_write_reg(dev, LBC85XX_BR(sc->dinfo->di_bank), br_v); /* Reprogram OR(x) */ or_v = lbc_read_reg(dev, LBC85XX_OR(sc->dinfo->di_bank)); or_v &= 0xfffffc00; or_v |= 0x03AE; /* Default POR timing */ lbc_write_reg(dev, LBC85XX_OR(sc->dinfo->di_bank), or_v); if (or_v & OR_FCM_PAGESIZE) { sc->pgsz = FSL_LARGE_PAGE_SIZE; sc->col_cycles = 2; nand_debug(NDBG_DRV, "%s: large page NAND device at #%d", device_get_nameunit(dev), sc->dinfo->di_bank); } else { sc->pgsz = FSL_SMALL_PAGE_SIZE; sc->col_cycles = 1; nand_debug(NDBG_DRV, "%s: small page NAND device at #%d", device_get_nameunit(dev), sc->dinfo->di_bank); } }
static int lbc_banks_enable(struct lbc_softc *sc) { u_long size; uint32_t regval; int error, i; for (i = 0; i < LBC_DEV_MAX; i++) { size = sc->sc_banks[i].size; if (size == 0) continue; /* * Compute and program BR value. */ regval = 0; regval |= sc->sc_banks[i].pa; switch (sc->sc_banks[i].width) { case 8: regval |= (1 << 11); break; case 16: regval |= (2 << 11); break; case 32: regval |= (3 << 11); break; default: error = EINVAL; goto fail; } regval |= (sc->sc_banks[i].decc << 9); regval |= (sc->sc_banks[i].wp << 8); regval |= (sc->sc_banks[i].msel << 5); regval |= (sc->sc_banks[i].atom << 2); regval |= 1; lbc_write_reg(sc, LBC85XX_BR(i), regval); /* * Compute and program OR value. */ regval = 0; regval |= lbc_address_mask(size); switch (sc->sc_banks[i].msel) { case LBCRES_MSEL_GPCM: /* TODO Add flag support for option registers */ regval |= 0x00000ff7; break; case LBCRES_MSEL_FCM: printf("FCM mode not supported yet!"); error = ENOSYS; goto fail; case LBCRES_MSEL_UPMA: case LBCRES_MSEL_UPMB: case LBCRES_MSEL_UPMC: printf("UPM mode not supported yet!"); error = ENOSYS; goto fail; } lbc_write_reg(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 */ lbc_write_reg(sc, LBC85XX_LBCR, 0); /* * Initialize clock ratio register: * - disable PLL bypass mode * - configure LCLK delay cycles for the assertion of LALE * - set system clock divider */ lbc_write_reg(sc, LBC85XX_LCRR, 0x00030008); return (0); fail: lbc_banks_unmap(sc); return (error); }
static int lbc_attach(device_t dev) { struct lbc_softc *sc; struct rman *rm; const struct lbc_resource *lbcres; int error; 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, RF_ACTIVE); if (sc->sc_res == NULL) return (ENXIO); sc->sc_bst = rman_get_bustag(sc->sc_res); sc->sc_bsh = rman_get_bushandle(sc->sc_res); rm = &sc->sc_rman; rm->rm_type = RMAN_ARRAY; rm->rm_descr = "MPC85XX Local Bus Space"; rm->rm_start = 0UL; rm->rm_end = ~0UL; error = rman_init(rm); if (error) goto fail; error = rman_manage_region(rm, rm->rm_start, rm->rm_end); if (error) { rman_fini(rm); goto fail; } /* * 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 */ lbc_write_reg(sc, LBC85XX_LBCR, 0x00000000); /* * Initialize clock ratio register: * - disable PLL bypass mode * - configure LCLK delay cycles for the assertion of LALE * - set system clock divider */ lbc_write_reg(sc, LBC85XX_LCRR, 0x00030008); lbcres = mpc85xx_lbc_resources; for (; lbcres->lbr_devtype; lbcres++) if (!lbc_mk_child(dev, lbcres)) { error = ENXIO; goto fail; } return (bus_generic_attach(dev)); fail: bus_release_resource(dev, SYS_RES_MEMORY, sc->sc_rid, sc->sc_res); return (error); }
static int lbc_init_child(device_t dev, device_t child) { struct lbc_softc *sc; struct lbc_devinfo *dinfo; const struct lbc_resource *res; u_long start, size; uint32_t regbuff; int error, unit; sc = device_get_softc(dev); dinfo = device_get_ivars(child); res = mpc85xx_lbc_resources; regbuff = 0; unit = -1; for (; res->lbr_devtype; res++) { if (res->lbr_unit != dinfo->lbc_unit) continue; start = res->lbr_base_addr; size = res->lbr_size; unit = res->lbr_unit; /* * Configure LAW for this LBC device and map its physical * memory region into KVA */ error = law_enable(OCP85XX_TGTIF_LBC, start, size); if (error) return (error); sc->sc_kva[unit] = (vm_offset_t)pmap_mapdev(start, size); if (sc->sc_kva[unit] == 0) { law_disable(OCP85XX_TGTIF_LBC, start, size); return (ENOSPC); } /* * Compute and program BR value */ regbuff |= start; switch (res->lbr_port_size) { case 8: regbuff |= (1 << 11); break; case 16: regbuff |= (2 << 11); break; case 32: regbuff |= (3 << 11); break; default: error = EINVAL; goto fail; } regbuff |= (res->lbr_decc << 9); regbuff |= (res->lbr_wp << 8); regbuff |= (res->lbr_msel << 5); regbuff |= (res->lbr_atom << 2); regbuff |= 1; lbc_write_reg(sc, LBC85XX_BR(unit), regbuff); /* * Compute and program OR value */ regbuff = 0; regbuff |= lbc_address_mask(size); switch (res->lbr_msel) { case LBCRES_MSEL_GPCM: /* TODO Add flag support for option registers */ regbuff |= 0x00000ff7; break; case LBCRES_MSEL_FCM: printf("FCM mode not supported yet!"); error = ENOSYS; goto fail; case LBCRES_MSEL_UPMA: case LBCRES_MSEL_UPMB: case LBCRES_MSEL_UPMC: printf("UPM mode not supported yet!"); error = ENOSYS; goto fail; } lbc_write_reg(sc, LBC85XX_OR(unit), regbuff); return (0); } fail: if (unit != -1) { law_disable(OCP85XX_TGTIF_LBC, start, size); pmap_unmapdev(sc->sc_kva[unit], size); return (error); } else return (ENOENT); }