void magma_attach(struct device *parent, struct device *dev, void *aux) { struct sbus_attach_args *sa = aux; struct magma_softc *sc = (struct magma_softc *)dev; const struct magma_board_info *card; char magma_prom[40], *clockstr; int chip, cd_clock; getpropstringA(sa->sa_node, "magma_prom", magma_prom); for (card = supported_cards; card->mb_name != NULL; card++) { if (strcmp(sa->sa_name, card->mb_sbusname) != 0) continue; if (strcmp(magma_prom, card->mb_name) == 0) break; } if (card->mb_name == NULL) { printf(": %s (unsupported)\n", magma_prom); return; } sc->sc_bustag = sa->sa_bustag; clockstr = getpropstring(sa->sa_node, "clock"); if (strlen(clockstr) == 0) cd_clock = 25; else { cd_clock = 0; while (*clockstr != '\0') cd_clock = cd_clock * 10 + *clockstr++ - '0'; } if (sbus_bus_map(sa->sa_bustag, sa->sa_reg[0].sbr_slot, sa->sa_reg[0].sbr_offset, sa->sa_reg[0].sbr_size, 0, 0, &sc->sc_iohandle) != 0) { printf(": can't map registers\n"); return; } if (sa->sa_nintr < 1) { printf(": can't find interrupt\n"); return; } sc->sc_ih = bus_intr_establish(sa->sa_bustag, sa->sa_pri, IPL_TTY, 0, magma_hard, sc, dev->dv_xname); if (sc->sc_ih == NULL) { printf(": couldn't establish interrupt, pri %d\n", INTLEV(sa->sa_pri)); bus_space_unmap(sc->sc_bustag, sc->sc_iohandle, sa->sa_reg[0].sbr_size); return; } sc->sc_sih = softintr_establish(IPL_TTY, magma_soft, sc); if (sc->sc_sih == NULL) { printf(": can't get soft intr\n"); bus_space_unmap(sc->sc_bustag, sc->sc_iohandle, sa->sa_reg[0].sbr_size); return; } printf(": %s\n", card->mb_realname); sc->ms_board = card; sc->ms_ncd1400 = card->mb_ncd1400; sc->ms_ncd1190 = card->mb_ncd1190; /* the SVCACK* lines are daisychained */ if (bus_space_subregion(sc->sc_bustag, sc->sc_iohandle, card->mb_svcackr, 1, &sc->sc_svcackrh)) { printf(": failed to map svcackr\n"); return; } if (bus_space_subregion(sc->sc_bustag, sc->sc_iohandle, card->mb_svcackt, 1, &sc->sc_svcackth)) { printf(": failed to map svcackt\n"); return; } if (bus_space_subregion(sc->sc_bustag, sc->sc_iohandle, card->mb_svcackm, 1, &sc->sc_svcackmh)) { printf(": failed to map svcackm\n"); return; } /* init the cd1400 chips */ for (chip = 0 ; chip < card->mb_ncd1400 ; chip++) { struct cd1400 *cd = &sc->ms_cd1400[chip]; cd->cd_clock = cd_clock; if (bus_space_subregion(sc->sc_bustag, sc->sc_iohandle, card->mb_cd1400[chip], CD1400_REGMAPSIZE, &cd->cd_regh)) { printf(": failed to map cd1400 regs\n"); return; } cd->cd_regt = sc->sc_bustag; /* getpropstring(sa->sa_node, "chiprev"); */ /* seemingly the Magma drivers just ignore the propstring */ cd->cd_chiprev = CD1400_READ_REG(cd, CD1400_GFRCR); dprintf(("%s attach CD1400 %d addr 0x%x rev %x clock %dMHz\n", sc->ms_dev.dv_xname, chip, cd->cd_reg, cd->cd_chiprev, cd->cd_clock)); /* clear GFRCR */ CD1400_WRITE_REG(cd, CD1400_GFRCR, 0x00); /* reset whole chip */ cd1400_write_ccr(cd, CD1400_CCR_CMDRESET | CD1400_CCR_FULLRESET); /* wait for revision code to be restored */ while (CD1400_READ_REG(cd, CD1400_GFRCR) != cd->cd_chiprev) ; /* set the Prescaler Period Register to tick at 1ms */ CD1400_WRITE_REG(cd, CD1400_PPR, ((cd->cd_clock * 1000000 / CD1400_PPR_PRESCALER + 500) / 1000)); /* * The LC2+1Sp card is the only card that doesn't have a * CD1190 for the parallel port, but uses channel 0 of the * CD1400, so we make a note of it for later and set up the * CD1400 for parallel mode operation. */ if (card->mb_npar && card->mb_ncd1190 == 0) { CD1400_WRITE_REG(cd, CD1400_GCR, CD1400_GCR_PARALLEL); cd->cd_parmode = 1; } } /* init the cd1190 chips */ for (chip = 0 ; chip < card->mb_ncd1190 ; chip++) { struct cd1190 *cd = &sc->ms_cd1190[chip]; if (bus_space_subregion(sc->sc_bustag, sc->sc_iohandle, card->mb_cd1190[chip], CD1190_REGMAPSIZE, &cd->cd_regh)) { printf(": failed to map cd1190 regs\n"); return; } cd->cd_regt = sc->sc_bustag; dprintf(("%s attach CD1190 %d addr 0x%x (failed)\n", sc->ms_dev.dv_xname, chip, cd->cd_reg)); /* XXX don't know anything about these chips yet */ } /* configure the children */ (void)config_found(dev, mtty_match, NULL); (void)config_found(dev, mbpp_match, NULL); }
void cgsixattach(struct device *parent, struct device *self, void *aux) { struct cgsix_softc *sc = (struct cgsix_softc *)self; struct sbus_attach_args *sa = aux; int node, console; u_int32_t fhc, rev; const char *nam; node = sa->sa_node; sc->sc_bustag = sa->sa_bustag; sc->sc_paddr = sbus_bus_addr(sa->sa_bustag, sa->sa_slot, sa->sa_offset); if (sa->sa_nreg != 1) { printf(": expected %d registers, got %d\n", 1, sa->sa_nreg); goto fail; } fb_setsize(&sc->sc_sunfb, 8, 1152, 900, node, 0); /* * Map just BT, FHC, FBC, THC, and video RAM. */ if (sbus_bus_map(sa->sa_bustag, sa->sa_reg[0].sbr_slot, sa->sa_reg[0].sbr_offset + CGSIX_BT_OFFSET, CGSIX_BT_SIZE, 0, 0, &sc->sc_bt_regs) != 0) { printf(": cannot map bt registers\n"); goto fail_bt; } if (sbus_bus_map(sa->sa_bustag, sa->sa_reg[0].sbr_slot, sa->sa_reg[0].sbr_offset + CGSIX_FHC_OFFSET, CGSIX_FHC_SIZE, 0, 0, &sc->sc_fhc_regs) != 0) { printf(": cannot map fhc registers\n"); goto fail_fhc; } if (sbus_bus_map(sa->sa_bustag, sa->sa_reg[0].sbr_slot, sa->sa_reg[0].sbr_offset + CGSIX_THC_OFFSET, CGSIX_THC_SIZE, 0, 0, &sc->sc_thc_regs) != 0) { printf(": cannot map thc registers\n"); goto fail_thc; } if (sbus_bus_map(sa->sa_bustag, sa->sa_reg[0].sbr_slot, sa->sa_reg[0].sbr_offset + CGSIX_VID_OFFSET, sc->sc_sunfb.sf_fbsize, BUS_SPACE_MAP_LINEAR, 0, &sc->sc_vid_regs) != 0) { printf(": cannot map vid registers\n"); goto fail_vid; } if (sbus_bus_map(sa->sa_bustag, sa->sa_reg[0].sbr_slot, sa->sa_reg[0].sbr_offset + CGSIX_TEC_OFFSET, CGSIX_TEC_SIZE, 0, 0, &sc->sc_tec_regs) != 0) { printf(": cannot map tec registers\n"); goto fail_tec; } if (sbus_bus_map(sa->sa_bustag, sa->sa_reg[0].sbr_slot, sa->sa_reg[0].sbr_offset + CGSIX_FBC_OFFSET, CGSIX_FBC_SIZE, 0, 0, &sc->sc_fbc_regs) != 0) { printf(": cannot map fbc registers\n"); goto fail_fbc; } if ((sc->sc_ih = bus_intr_establish(sa->sa_bustag, sa->sa_pri, IPL_TTY, 0, cgsix_intr, sc, self->dv_xname)) == NULL) { printf(": couldn't establish interrupt, pri %d\n%s", INTLEV(sa->sa_pri), self->dv_xname); } /* if prom didn't initialize us, do it the hard way */ if (OF_getproplen(node, "width") != sizeof(u_int32_t)) cgsix_hardreset(sc); nam = getpropstring(node, "model"); if (*nam == '\0') nam = sa->sa_name; printf(": %s", nam); console = cgsix_is_console(node); fhc = FHC_READ(sc); rev = (fhc & FHC_REV_MASK) >> FHC_REV_SHIFT; cgsix_reset(sc, rev); cgsix_burner(sc, 1, 0); sc->sc_sunfb.sf_ro.ri_bits = (void *)bus_space_vaddr(sc->sc_bustag, sc->sc_vid_regs); sc->sc_sunfb.sf_ro.ri_hw = sc; printf(", %dx%d, rev %d\n", sc->sc_sunfb.sf_width, sc->sc_sunfb.sf_height, rev); fbwscons_init(&sc->sc_sunfb, 0, console); fbwscons_setcolormap(&sc->sc_sunfb, cgsix_setcolor); /* * Old rev. cg6 cards do not like the current acceleration code. * * Some hints from Sun point out at timing and cache problems, which * will be investigated later. */ if (rev < 5) sc->sc_sunfb.sf_dev.dv_cfdata->cf_flags |= CG6_CFFLAG_NOACCEL; if ((sc->sc_sunfb.sf_dev.dv_cfdata->cf_flags & CG6_CFFLAG_NOACCEL) == 0) { sc->sc_sunfb.sf_ro.ri_ops.copyrows = cgsix_ras_copyrows; sc->sc_sunfb.sf_ro.ri_ops.copycols = cgsix_ras_copycols; sc->sc_sunfb.sf_ro.ri_ops.eraserows = cgsix_ras_eraserows; sc->sc_sunfb.sf_ro.ri_ops.erasecols = cgsix_ras_erasecols; sc->sc_sunfb.sf_ro.ri_do_cursor = cgsix_ras_do_cursor; cgsix_ras_init(sc); } if (console) fbwscons_console_init(&sc->sc_sunfb, -1); fbwscons_attach(&sc->sc_sunfb, &cgsix_accessops, console); return; fail_fbc: bus_space_unmap(sa->sa_bustag, sc->sc_tec_regs, CGSIX_TEC_SIZE); fail_tec: bus_space_unmap(sa->sa_bustag, sc->sc_vid_regs, sc->sc_sunfb.sf_fbsize); fail_vid: bus_space_unmap(sa->sa_bustag, sc->sc_thc_regs, CGSIX_THC_SIZE); fail_thc: bus_space_unmap(sa->sa_bustag, sc->sc_fhc_regs, CGSIX_FHC_SIZE); fail_fhc: bus_space_unmap(sa->sa_bustag, sc->sc_bt_regs, CGSIX_BT_SIZE); fail_bt: fail: return; }
void cs4231_attach(struct device *parent, struct device *self, void *aux) { struct sbus_attach_args *sa = aux; struct cs4231_softc *sc = (struct cs4231_softc *)self; int node; u_int32_t sbusburst, burst; node = sa->sa_node; /* Pass on the bus tags */ sc->sc_bustag = sa->sa_bustag; sc->sc_dmatag = sa->sa_dmatag; /* Make sure things are sane. */ if (sa->sa_nintr != 1) { printf(": expected 1 interrupt, got %d\n", sa->sa_nintr); return; } if (sa->sa_nreg != 1) { printf(": expected 1 register set, got %d\n", sa->sa_nreg); return; } if (bus_intr_establish(sa->sa_bustag, sa->sa_pri, IPL_AUDIO, 0, cs4231_intr, sc, self->dv_xname) == NULL) { printf(": couldn't establish interrupt, pri %d\n", INTLEV(sa->sa_pri)); return; } if (sbus_bus_map(sa->sa_bustag, sa->sa_reg[0].sbr_slot, (bus_addr_t)sa->sa_reg[0].sbr_offset, (bus_size_t)sa->sa_reg[0].sbr_size, BUS_SPACE_MAP_LINEAR, 0, &sc->sc_regs) != 0) { printf(": couldn't map registers\n"); return; } 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) burst = sbusburst; sc->sc_burst = burst & sbusburst; printf("\n"); audio_attach_mi(&cs4231_sa_hw_if, sc, &sc->sc_dev); /* Default to speaker, unmuted, reasonable volume */ sc->sc_out_port = CSPORT_SPEAKER; sc->sc_in_port = CSPORT_MICROPHONE; sc->sc_mute[CSPORT_SPEAKER] = 1; sc->sc_mute[CSPORT_MONITOR] = 1; sc->sc_volume[CSPORT_SPEAKER].left = 192; sc->sc_volume[CSPORT_SPEAKER].right = 192; }
/* * Attach and initialize a vigra display, as well as a child wsdisplay. */ void vigraattach(struct device *parent, struct device *self, void *args) { struct vigra_softc *sc = (struct vigra_softc *)self; struct sbus_attach_args *sa = args; bus_space_tag_t bt; bus_space_handle_t bh; int node, row, isconsole = 0; char *nam; bt = sa->sa_bustag; node = sa->sa_node; nam = getpropstring(node, "model"); if (*nam == '\0') nam = (char *)sa->sa_name; printf(": %s", nam); isconsole = node == fbnode; if (sa->sa_nreg < VIGRA_NREG) { printf("\n%s: expected %d registers, got %d", self->dv_xname, VIGRA_NREG, sa->sa_nreg); return; } /* * Check whether we are using an G300 or an G335 chip. * The VS10 and VS12 use the G300, while the VS11 uses a G335. */ sc->sc_g300 = strncmp(nam, "VIGRA,vs11", strlen("VIGRA,vs11")); sc->sc_bustag = bt; if (sbus_bus_map(bt, sa->sa_reg[VIGRA_REG_CSR].sbr_slot, sa->sa_reg[VIGRA_REG_CSR].sbr_offset, sa->sa_reg[VIGRA_REG_CSR].sbr_size, BUS_SPACE_MAP_LINEAR, 0, &bh) != 0) { printf("\n%s: can't map control registers\n", self->dv_xname); return; } sc->sc_regs = bus_space_vaddr(bt, bh); if (sbus_bus_map(bt, sa->sa_reg[VIGRA_REG_RAMDAC].sbr_slot, sa->sa_reg[VIGRA_REG_RAMDAC].sbr_offset, sa->sa_reg[VIGRA_REG_RAMDAC].sbr_size, BUS_SPACE_MAP_LINEAR, 0, &bh) != 0) { printf("\n%s: can't map ramdac registers\n", self->dv_xname); return; } sc->sc_ramdac = bus_space_vaddr(bt, bh); /* enable video */ vigra_burner(sc, 1, 0); fb_setsize(&sc->sc_sunfb, 8, 1152, 900, node, 0); if (sbus_bus_map(bt, sa->sa_reg[VIGRA_REG_VRAM].sbr_slot, sa->sa_reg[VIGRA_REG_VRAM].sbr_offset, round_page(sc->sc_sunfb.sf_fbsize), BUS_SPACE_MAP_LINEAR, 0, &bh) != 0) { printf("\n%s: can't map video memory\n", self->dv_xname); return; } sc->sc_sunfb.sf_ro.ri_bits = bus_space_vaddr(bt, bh); sc->sc_sunfb.sf_ro.ri_hw = sc; sc->sc_paddr = sbus_bus_addr(bt, sa->sa_reg[VIGRA_REG_VRAM].sbr_slot, sa->sa_reg[VIGRA_REG_VRAM].sbr_offset); printf(", %dx%d\n", sc->sc_sunfb.sf_width, sc->sc_sunfb.sf_height); if ((sc->sc_ih = bus_intr_establish(sa->sa_bustag, sa->sa_pri, IPL_TTY, 0, vigra_intr, sc, self->dv_xname)) == NULL) { printf("%s: couldn't establish interrupt, pri %d\n", self->dv_xname, INTLEV(sa->sa_pri)); } /* * If the framebuffer width is under 1024x768, we will switch from the * PROM font to the more adequate 8x16 font here. * However, we need to adjust two things in this case: * - the display row should be overrided from the current PROM metrics, * to prevent us from overwriting the last few lines of text. * - if the 80x34 screen would make a large margin appear around it, * choose to clear the screen rather than keeping old prom output in * the margins. * XXX there should be a rasops "clear margins" feature * * Also, in 1280x1024 resolution, the PROM display is not centered * vertically (why? no other frame buffer does this in such a mode!), * so be lazy and clear the screen here too anyways... */ fbwscons_init(&sc->sc_sunfb, isconsole && (sc->sc_sunfb.sf_width != 800 && sc->sc_sunfb.sf_width != 1280) ? 0 : RI_CLEAR); fbwscons_setcolormap(&sc->sc_sunfb, vigra_setcolor); if (isconsole) { switch (sc->sc_sunfb.sf_width) { case 640: row = sc->sc_sunfb.sf_ro.ri_rows - 1; break; case 800: case 1280: row = 0; /* screen has been cleared above */ break; default: row = -1; break; } fbwscons_console_init(&sc->sc_sunfb, row); } fbwscons_attach(&sc->sc_sunfb, &vigra_accessops, isconsole); }