void bppattach(device_t parent, device_t self, void *aux) { struct bpp_softc *dsc = device_private(self); struct lsi64854_softc *sc = &dsc->sc_lsi64854; struct sbus_softc *sbsc = device_private(parent); struct sbus_attach_args *sa = aux; int burst, sbusburst; int node; sc->sc_dev = self; selinit(&dsc->sc_rsel); selinit(&dsc->sc_wsel); dsc->sc_sih = softint_establish(SOFTINT_CLOCK, bppsoftintr, dsc); sc->sc_bustag = sa->sa_bustag; sc->sc_dmatag = sa->sa_dmatag; node = sa->sa_node; /* Map device registers */ if (sbus_bus_map(sa->sa_bustag, sa->sa_slot, sa->sa_offset, sa->sa_size, 0, &sc->sc_regs) != 0) { aprint_error(": cannot map registers\n"); return; } /* * Get transfer burst size from PROM and plug it into the * controller registers. This is needed on the Sun4m; do * others need it too? */ sbusburst = sbsc->sc_burst; if (sbusburst == 0) sbusburst = SBUS_BURST_32 - 1; /* 1->16 */ burst = prom_getpropint(node, "burst-sizes", -1); if (burst == -1) /* take SBus burst sizes */ burst = sbusburst; /* Clamp at parent's burst sizes */ burst &= sbusburst; sc->sc_burst = (burst & SBUS_BURST_32) ? 32 : (burst & SBUS_BURST_16) ? 16 : 0; /* Join the Sbus device family */ dsc->sc_sd.sd_reset = NULL; sbus_establish(&dsc->sc_sd, self); /* Initialize the DMA channel */ sc->sc_channel = L64854_CHANNEL_PP; lsi64854_attach(sc); /* Establish interrupt handler */ if (sa->sa_nintr) { sc->sc_intrchain = bppintr; sc->sc_intrchainarg = dsc; (void)bus_intr_establish(sa->sa_bustag, sa->sa_pri, IPL_TTY, bppintr, sc); } /* Allocate buffer XXX - should actually use dmamap_uio() */ dsc->sc_bufsz = 1024; dsc->sc_buf = malloc(dsc->sc_bufsz, M_DEVBUF, M_NOWAIT); /* XXX read default state */ { bus_space_handle_t h = sc->sc_regs; struct hwstate *hw = &dsc->sc_hwdefault; int ack_rate = sa->sa_frequency / 1000000; hw->hw_hcr = bus_space_read_2(sc->sc_bustag, h, L64854_REG_HCR); hw->hw_ocr = bus_space_read_2(sc->sc_bustag, h, L64854_REG_OCR); hw->hw_tcr = bus_space_read_1(sc->sc_bustag, h, L64854_REG_TCR); hw->hw_or = bus_space_read_1(sc->sc_bustag, h, L64854_REG_OR); DPRINTF(("bpp: hcr %x ocr %x tcr %x or %x\n", hw->hw_hcr, hw->hw_ocr, hw->hw_tcr, hw->hw_or)); /* Set these to sane values */ hw->hw_hcr = ((ack_rate<<BPP_HCR_DSS_SHFT)&BPP_HCR_DSS_MASK) | ((ack_rate<<BPP_HCR_DSW_SHFT)&BPP_HCR_DSW_MASK); hw->hw_ocr |= BPP_OCR_ACK_OP; } }
void bppattach(struct device *parent, struct device *self, void *aux) { struct sbus_attach_args *sa = aux; struct bpp_softc *dsc = (void *)self; struct lsi64854_softc *sc = &dsc->sc_lsi64854; int burst, sbusburst; int node; node = sa->sa_node; sc->sc_bustag = sa->sa_bustag; sc->sc_dmatag = sa->sa_dmatag; /* Map device registers */ if (sa->sa_npromvaddrs != 0) { if (sbus_bus_map(sa->sa_bustag, 0, sa->sa_promvaddrs[0], sa->sa_size, /* ???? */ BUS_SPACE_MAP_PROMADDRESS, 0, &sc->sc_regs) != 0) { printf(": cannot map registers\n"); return; } } else if (sbus_bus_map(sa->sa_bustag, sa->sa_slot, sa->sa_offset, sa->sa_size, 0, 0, &sc->sc_regs) != 0) { printf(": cannot map registers\n"); return; } /* Check for the interrupt property */ if (sa->sa_nintr == 0) { printf(": no interrupt property\n"); return; } /* * Get transfer burst size from PROM and plug it into the * controller registers. This is needed on the Sun4m; do * others need it too? */ sbusburst = ((struct sbus_softc *)parent)->sc_burst; if (sbusburst == 0) sbusburst = SBUS_BURST_32 - 1; /* 1->16 */ burst = getpropint(node, "burst-sizes", -1); if (burst == -1) /* take SBus burst sizes */ burst = sbusburst; /* Clamp at parent's burst sizes */ burst &= sbusburst; sc->sc_burst = (burst & SBUS_BURST_32) ? 32 : (burst & SBUS_BURST_16) ? 16 : 0; /* Initialize the DMA channel */ sc->sc_channel = L64854_CHANNEL_PP; if (lsi64854_attach(sc) != 0) return; /* Establish interrupt handler */ sc->sc_intrchain = bppintr; sc->sc_intrchainarg = dsc; (void)bus_intr_establish(sa->sa_bustag, sa->sa_pri, IPL_TTY, 0, bppintr, sc, self->dv_xname); /* Allocate buffer XXX - should actually use dmamap_uio() */ dsc->sc_bufsz = 1024; dsc->sc_buf = malloc(dsc->sc_bufsz, M_DEVBUF, M_NOWAIT); /* XXX read default state */ { bus_space_handle_t h = sc->sc_regs; struct hwstate *hw = &dsc->sc_hwstate; int ack_rate = sa->sa_frequency/1000000; hw->hw_hcr = bus_space_read_2(sc->sc_bustag, h, L64854_REG_HCR); hw->hw_ocr = bus_space_read_2(sc->sc_bustag, h, L64854_REG_OCR); hw->hw_tcr = bus_space_read_1(sc->sc_bustag, h, L64854_REG_TCR); hw->hw_or = bus_space_read_1(sc->sc_bustag, h, L64854_REG_OR); DPRINTF(("bpp: hcr %x ocr %x tcr %x or %x\n", hw->hw_hcr, hw->hw_ocr, hw->hw_tcr, hw->hw_or)); /* Set these to sane values */ hw->hw_hcr = ((ack_rate<<BPP_HCR_DSS_SHFT)&BPP_HCR_DSS_MASK) | ((ack_rate<<BPP_HCR_DSW_SHFT)&BPP_HCR_DSW_MASK); hw->hw_ocr |= BPP_OCR_ACK_OP; } }
static int espattach(struct esp_softc *esc, const struct ncr53c9x_glue *gluep) { struct ncr53c9x_softc *sc = &esc->sc_ncr53c9x; unsigned int uid = 0; int error, i; NCR_LOCK_INIT(sc); /* Attach the DMA engine. */ error = lsi64854_attach(esc->sc_dma); if (error != 0) { device_printf(esc->sc_dev, "lsi64854_attach failed\n"); goto fail_lock; } sc->sc_id = OF_getscsinitid(esc->sc_dev); #ifdef ESP_SBUS_DEBUG device_printf(esc->sc_dev, "%s: sc_id %d, freq %d\n", __func__, sc->sc_id, sc->sc_freq); #endif /* * The `ESC' DMA chip must be reset before we can access * the ESP registers. */ if (esc->sc_dma->sc_rev == DMAREV_ESC) DMA_RESET(esc->sc_dma); /* * Set up glue for MI code early; we use some of it here. */ sc->sc_glue = gluep; /* gimme MHz */ sc->sc_freq /= 1000000; /* * XXX More of this should be in ncr53c9x_attach(), but * XXX should we really poke around the chip that much in * XXX the MI code? Think about this more... */ /* * Read the part-unique ID code of the SCSI chip. The contained * value is only valid if all of the following conditions are met: * - After power-up or chip reset. * - Before any value is written to this register. * - The NCRCFG2_FE bit is set. * - A (NCRCMD_NOP | NCRCMD_DMA) command has been issued. */ NCRCMD(sc, NCRCMD_RSTCHIP); NCRCMD(sc, NCRCMD_NOP); sc->sc_cfg2 = NCRCFG2_FE; NCR_WRITE_REG(sc, NCR_CFG2, sc->sc_cfg2); NCRCMD(sc, NCRCMD_NOP | NCRCMD_DMA); uid = NCR_READ_REG(sc, NCR_UID); /* * It is necessary to try to load the 2nd config register here, * to find out what rev the esp chip is, else the ncr53c9x_reset * will not set up the defaults correctly. */ sc->sc_cfg1 = sc->sc_id | NCRCFG1_PARENB; NCR_WRITE_REG(sc, NCR_CFG1, sc->sc_cfg1); sc->sc_cfg2 = 0; NCR_WRITE_REG(sc, NCR_CFG2, sc->sc_cfg2); sc->sc_cfg2 = NCRCFG2_SCSI2 | NCRCFG2_RPE; NCR_WRITE_REG(sc, NCR_CFG2, sc->sc_cfg2); if ((NCR_READ_REG(sc, NCR_CFG2) & ~NCRCFG2_RSVD) != (NCRCFG2_SCSI2 | NCRCFG2_RPE)) { sc->sc_rev = NCR_VARIANT_ESP100; } else { sc->sc_cfg2 = NCRCFG2_SCSI2; NCR_WRITE_REG(sc, NCR_CFG2, sc->sc_cfg2); sc->sc_cfg3 = 0; NCR_WRITE_REG(sc, NCR_CFG3, sc->sc_cfg3); sc->sc_cfg3 = (NCRCFG3_CDB | NCRCFG3_FCLK); NCR_WRITE_REG(sc, NCR_CFG3, sc->sc_cfg3); if (NCR_READ_REG(sc, NCR_CFG3) != (NCRCFG3_CDB | NCRCFG3_FCLK)) { sc->sc_rev = NCR_VARIANT_ESP100A; } else { /* NCRCFG2_FE enables > 64K transfers. */ sc->sc_cfg2 |= NCRCFG2_FE; sc->sc_cfg3 = 0; NCR_WRITE_REG(sc, NCR_CFG3, sc->sc_cfg3); if (sc->sc_freq <= 25) sc->sc_rev = NCR_VARIANT_ESP200; else { switch ((uid & 0xf8) >> 3) { case 0x00: sc->sc_rev = NCR_VARIANT_FAS100A; break; case 0x02: if ((uid & 0x07) == 0x02) sc->sc_rev = NCR_VARIANT_FAS216; else sc->sc_rev = NCR_VARIANT_FAS236; break; case 0x0a: sc->sc_rev = NCR_VARIANT_FAS366; break; default: /* * We could just treat unknown chips * as ESP200 but then we would most * likely drive them out of specs. */ device_printf(esc->sc_dev, "Unknown chip\n"); goto fail_lsi; } } } } #ifdef ESP_SBUS_DEBUG printf("%s: revision %d, uid 0x%x\n", __func__, sc->sc_rev, uid); #endif /* * XXX minsync and maxxfer _should_ be set up in MI code, * XXX but it appears to have some dependency on what sort * XXX of DMA we're hooked up to, etc. */ /* * This is the value used to start sync negotiations * Note that the NCR register "SYNCTP" is programmed * in "clocks per byte", and has a minimum value of 4. * The SCSI period used in negotiation is one-fourth * of the time (in nanoseconds) needed to transfer one byte. * Since the chip's clock is given in MHz, we have the following * formula: 4 * period = (1000 / freq) * 4 */ sc->sc_minsync = 1000 / sc->sc_freq; sc->sc_maxoffset = 15; sc->sc_extended_geom = 1; /* * Alas, we must now modify the value a bit, because it's * only valid when can switch on FASTCLK and FASTSCSI bits * in config register 3... */ switch (sc->sc_rev) { case NCR_VARIANT_ESP100: sc->sc_maxwidth = MSG_EXT_WDTR_BUS_8_BIT; sc->sc_maxxfer = 64 * 1024; sc->sc_minsync = 0; /* No synch on old chip? */ break; case NCR_VARIANT_ESP100A: sc->sc_maxwidth = MSG_EXT_WDTR_BUS_8_BIT; sc->sc_maxxfer = 64 * 1024; /* Min clocks/byte is 5 */ sc->sc_minsync = ncr53c9x_cpb2stp(sc, 5); break; case NCR_VARIANT_ESP200: sc->sc_maxwidth = MSG_EXT_WDTR_BUS_8_BIT; sc->sc_maxxfer = 16 * 1024 * 1024; /* Min clocks/byte is 5 */ sc->sc_minsync = ncr53c9x_cpb2stp(sc, 5); break; case NCR_VARIANT_FAS100A: case NCR_VARIANT_FAS216: case NCR_VARIANT_FAS236: /* * The onboard SCSI chips in Sun Ultra 1 are actually * documented to be NCR53C9X which use NCRCFG3_FCLK and * NCRCFG3_FSCSI. BSD/OS however probes these chips as * FAS100A and uses NCRF9XCFG3_FCLK and NCRF9XCFG3_FSCSI * instead which seems to be correct as otherwise sync * negotiation just doesn't work. Using NCRF9XCFG3_FCLK * and NCRF9XCFG3_FSCSI with these chips in fact also * yields Fast-SCSI speed. */ sc->sc_features = NCR_F_FASTSCSI; sc->sc_cfg3 = NCRF9XCFG3_FCLK; sc->sc_cfg3_fscsi = NCRF9XCFG3_FSCSI; sc->sc_maxwidth = MSG_EXT_WDTR_BUS_8_BIT; sc->sc_maxxfer = 16 * 1024 * 1024; break; case NCR_VARIANT_FAS366: sc->sc_maxwidth = MSG_EXT_WDTR_BUS_16_BIT; sc->sc_maxxfer = 16 * 1024 * 1024; break; } /* Establish interrupt channel. */ i = 0; if ((esc->sc_irqres = bus_alloc_resource_any(esc->sc_dev, SYS_RES_IRQ, &i, RF_SHAREABLE|RF_ACTIVE)) == NULL) { device_printf(esc->sc_dev, "cannot allocate interrupt\n"); goto fail_lsi; } if (bus_setup_intr(esc->sc_dev, esc->sc_irqres, INTR_MPSAFE | INTR_TYPE_CAM, NULL, ncr53c9x_intr, sc, &esc->sc_irq)) { device_printf(esc->sc_dev, "cannot set up interrupt\n"); error = ENXIO; goto fail_ires; } /* Turn on target selection using the `DMA' method. */ if (sc->sc_rev != NCR_VARIANT_FAS366) sc->sc_features |= NCR_F_DMASELECT; /* Do the common parts of attachment. */ sc->sc_dev = esc->sc_dev; error = ncr53c9x_attach(sc); if (error != 0) { device_printf(esc->sc_dev, "ncr53c9x_attach failed\n"); goto fail_intr; } return (0); fail_intr: bus_teardown_intr(esc->sc_dev, esc->sc_irqres, esc->sc_irq); fail_ires: bus_release_resource(esc->sc_dev, SYS_RES_IRQ, rman_get_rid(esc->sc_irqres), esc->sc_irqres); fail_lsi: lsi64854_detach(esc->sc_dma); fail_lock: NCR_LOCK_DESTROY(sc); return (error); }
static int le_dma_attach(device_t dev) { struct le_dma_softc *lesc; struct lsi64854_softc *dma; struct lance_softc *sc; int error, i; lesc = device_get_softc(dev); sc = &lesc->sc_am7990.lsc; LE_LOCK_INIT(sc, device_get_nameunit(dev)); /* * Establish link to `ledma' device. * XXX hackery. */ dma = (struct lsi64854_softc *)device_get_softc(device_get_parent(dev)); lesc->sc_dma = dma; lesc->sc_dma->sc_client = lesc; i = 0; lesc->sc_rres = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &i, RF_ACTIVE); if (lesc->sc_rres == NULL) { device_printf(dev, "cannot allocate registers\n"); error = ENXIO; goto fail_mtx; } i = 0; if ((lesc->sc_ires = bus_alloc_resource_any(dev, SYS_RES_IRQ, &i, RF_SHAREABLE | RF_ACTIVE)) == NULL) { device_printf(dev, "cannot allocate interrupt\n"); error = ENXIO; goto fail_rres; } /* Attach the DMA engine. */ error = lsi64854_attach(dma); if (error != 0) { device_printf(dev, "lsi64854_attach failed\n"); goto fail_ires; } sc->sc_memsize = LEDMA_MEMSIZE; error = bus_dma_tag_create( dma->sc_parent_dmat, /* parent */ LEDMA_ALIGNMENT, /* alignment */ LEDMA_BOUNDARY, /* boundary */ BUS_SPACE_MAXADDR_32BIT, /* lowaddr */ BUS_SPACE_MAXADDR, /* highaddr */ NULL, NULL, /* filter, filterarg */ sc->sc_memsize, /* maxsize */ 1, /* nsegments */ sc->sc_memsize, /* maxsegsize */ 0, /* flags */ NULL, NULL, /* lockfunc, lockarg */ &lesc->sc_dmat); if (error != 0) { device_printf(dev, "cannot allocate buffer DMA tag\n"); goto fail_lsi; } error = bus_dmamem_alloc(lesc->sc_dmat, (void **)&sc->sc_mem, BUS_DMA_WAITOK | BUS_DMA_COHERENT, &lesc->sc_dmam); if (error != 0) { device_printf(dev, "cannot allocate DMA buffer memory\n"); goto fail_dtag; } lesc->sc_laddr = 0; error = bus_dmamap_load(lesc->sc_dmat, lesc->sc_dmam, sc->sc_mem, sc->sc_memsize, le_dma_dma_callback, lesc, 0); if (error != 0 || lesc->sc_laddr == 0) { device_printf(dev, "cannot load DMA buffer map\n"); goto fail_dmem; } sc->sc_addr = lesc->sc_laddr & 0xffffff; sc->sc_flags = 0; sc->sc_conf3 = LE_C3_BSWP | LE_C3_ACON | LE_C3_BCON; sc->sc_mediachange = le_dma_supmediachange; sc->sc_mediastatus = le_dma_supmediastatus; sc->sc_supmedia = le_dma_supmedia; sc->sc_nsupmedia = nitems(le_dma_supmedia); sc->sc_defaultmedia = le_dma_supmedia[0]; OF_getetheraddr(dev, sc->sc_enaddr); sc->sc_copytodesc = lance_copytobuf_contig; sc->sc_copyfromdesc = lance_copyfrombuf_contig; sc->sc_copytobuf = lance_copytobuf_contig; sc->sc_copyfrombuf = lance_copyfrombuf_contig; sc->sc_zerobuf = lance_zerobuf_contig; sc->sc_rdcsr = le_dma_rdcsr; sc->sc_wrcsr = le_dma_wrcsr; sc->sc_hwreset = le_dma_hwreset; sc->sc_hwintr = le_dma_hwintr; sc->sc_nocarrier = le_dma_nocarrier; error = am7990_config(&lesc->sc_am7990, device_get_name(dev), device_get_unit(dev)); if (error != 0) { device_printf(dev, "cannot attach Am7990\n"); goto fail_dmap; } error = bus_setup_intr(dev, lesc->sc_ires, INTR_TYPE_NET | INTR_MPSAFE, NULL, am7990_intr, sc, &lesc->sc_ih); if (error != 0) { device_printf(dev, "cannot set up interrupt\n"); goto fail_am7990; } return (0); fail_am7990: am7990_detach(&lesc->sc_am7990); fail_dmap: bus_dmamap_unload(lesc->sc_dmat, lesc->sc_dmam); fail_dmem: bus_dmamem_free(lesc->sc_dmat, sc->sc_mem, lesc->sc_dmam); fail_dtag: bus_dma_tag_destroy(lesc->sc_dmat); fail_lsi: lsi64854_detach(dma); fail_ires: bus_release_resource(dev, SYS_RES_IRQ, rman_get_rid(lesc->sc_ires), lesc->sc_ires); fail_rres: bus_release_resource(dev, SYS_RES_MEMORY, rman_get_rid(lesc->sc_rres), lesc->sc_rres); fail_mtx: LE_LOCK_DESTROY(sc); return (error); }
void dmaattach_sbus(device_t parent, device_t self, void *aux) { struct dma_softc *dsc = device_private(self); struct lsi64854_softc *sc = &dsc->sc_lsi64854; struct sbus_attach_args *sa = aux; struct sbus_softc *sbsc = device_private(parent); bus_space_tag_t sbt; int sbusburst, burst; int node; node = sa->sa_node; sc->sc_dev = self; sc->sc_bustag = sa->sa_bustag; sc->sc_dmatag = sa->sa_dmatag; /* Map registers */ if (sa->sa_npromvaddrs) { sbus_promaddr_to_handle(sa->sa_bustag, sa->sa_promvaddrs[0], &sc->sc_regs); } else { if (sbus_bus_map(sa->sa_bustag, sa->sa_slot, sa->sa_offset, sa->sa_size, 0, &sc->sc_regs) != 0) { aprint_error(": cannot map registers\n"); return; } } /* * Get transfer burst size from PROM and plug it into the * controller registers. This is needed on the Sun4m; do * others need it too? */ sbusburst = sbsc->sc_burst; if (sbusburst == 0) sbusburst = SBUS_BURST_32 - 1; /* 1->16 */ burst = prom_getpropint(node,"burst-sizes", -1); if (burst == -1) /* take SBus burst sizes */ burst = sbusburst; /* Clamp at parent's burst sizes */ burst &= sbusburst; sc->sc_burst = (burst & SBUS_BURST_32) ? 32 : (burst & SBUS_BURST_16) ? 16 : 0; if (device_is_a(self, "ledma")) { char *cabletype; uint32_t csr; /* * Check to see which cable type is currently active and * set the appropriate bit in the ledma csr so that it * gets used. If we didn't netboot, the PROM won't have * the "cable-selection" property; default to TP and then * the user can change it via a "media" option to ifconfig. */ cabletype = prom_getpropstring(node, "cable-selection"); csr = L64854_GCSR(sc); if (strcmp(cabletype, "tpe") == 0) { csr |= E_TP_AUI; } else if (strcmp(cabletype, "aui") == 0) { csr &= ~E_TP_AUI; } else { /* assume TP if nothing there */ csr |= E_TP_AUI; } L64854_SCSR(sc, csr); delay(20000); /* manual says we need a 20ms delay */ sc->sc_channel = L64854_CHANNEL_ENET; } else { sc->sc_channel = L64854_CHANNEL_SCSI; } sbus_establish(&dsc->sc_sd, self); if ((sbt = bus_space_tag_alloc(sc->sc_bustag, dsc)) == NULL) { aprint_error(": out of memory\n"); return; } sbt->sparc_intr_establish = dmabus_intr_establish; lsi64854_attach(sc); /* Attach children */ for (node = firstchild(sa->sa_node); node; node = nextsibling(node)) { struct sbus_attach_args sax; sbus_setup_attach_args(sbsc, sbt, sc->sc_dmatag, node, &sax); (void)config_found(self, (void *)&sax, dmaprint_sbus); sbus_destroy_attach_args(&sax); } }