#ifndef lint static char sccsid[] = "@(#)bwtwo.c 1.1 86/02/03 Copyr 1985 Sun Micro"; #endif /* * Copyright (c) 1986 by Sun Microsystems, Inc. */ /* * Sun Two Black & White Board(s) Driver */ #include "bwtwo.h" #include "../h/param.h" #include "../h/systm.h" #include "../h/dir.h" #include "../h/user.h" #include "../h/proc.h" #include "../h/buf.h" #include "../h/conf.h" #include "../h/file.h" #include "../h/map.h" #include "../h/vmmac.h" #include "../sun/fbio.h" #include "../machine/pte.h" #include "../machine/mmu.h" #include "../machine/cpu.h" #include "../sundev/mbvar.h" #include "../sundev/bw2reg.h" #ifdef sun3 #include "../sun3/eeprom.h" #endif sun3 extern char CADDR1[]; int copyenpfnum; /* pfnum before shadow memory mapped in */ caddr_t copyenvirt = 0; /* virtual address mapped to shadow memory */ struct bw2_softc { caddr_t image; } bw2_softc[NBWTWO]; #define BW2SIZEX 1152 #define BW2SIZEY 900 #define BW2SQUARESIZEX 1024 #define BW2SQUARESIZEY 1024 /* * Driver information for auto-configuration stuff. */ int bwtwoprobe(), bwtwoattach(), bwtwointr(); struct mb_device *bwtwoinfo[NBWTWO]; struct mb_driver bwtwodriver = { bwtwoprobe, 0, bwtwoattach, 0, 0, bwtwointr, sizeof (struct bw2dev) + CLBYTES /* XXX */, "bwtwo", bwtwoinfo, 0, 0, 0, }; /* * Only allow opens for writing or reading and writing * because reading is nonsensical. */ bwtwoopen(dev, flag) dev_t dev; { fbopen(dev, flag, NBWTWO, bwtwoinfo); } bwtwoclose(dev, flag) dev_t dev; { } /*ARGSUSED*/ bwtwommap(dev, off, prot) dev_t dev; off_t off; int prot; { register caddr_t hold; register int unit = minor(dev); int page; hold = bwtwoinfo[unit]->md_addr; bwtwoinfo[unit]->md_addr = bw2_softc[unit].image; page = fbmmap(dev, off, prot, NBWTWO, bwtwoinfo, BW2_FBSIZE); bwtwoinfo[unit]->md_addr = hold; return (page); } /* * Determine if a bwtwo exists at the given address. */ /*ARGSUSED*/ bwtwoprobe(reg, unit) caddr_t reg; int unit; { #ifdef sun3 /* * For the sun3 we have to rely on the machine type since the bits * in the enable register may not be reliable. */ int result; /* * XXX - kludge used to get around current mem_rop bug. * We need to have the page before the frame buffer to not have * have any "holes" in them as the mem_rop code will sometimes * access this page. We kludge here to avoid this problem by * increasing the size of area to be mapped by adding CLBYTES * to the device size mapped by the autoconfig code. Here * we remap all but the first page so that the first page map * entry is duplicated and then we bump the virtual address * up by CLBYTES in bwtwoattach(). */ mapin(&Sysmap[btoc(reg + CLBYTES - KERNELBASE)], (u_int)btoc(reg + CLBYTES), ((*(u_int *)&Sysmap[btoc(reg - KERNELBASE)]) & PG_PFNUM), btoc(BW2_FBSIZE), PG_V | PG_KW); switch (cpu) { case CPU_SUN3_160: result = BW2_FBSIZE; break; case CPU_SUN3_50: result = BW2_FBSIZE; break; case CPU_SUN3_260: result = 0; break; default: result = 0; break; } return (result); #endif sun3 #ifdef sun2 struct bw2dev *bw2dev = (struct bw2dev *)(reg + CLBYTES); /* XXX */ register struct bw2cr *alias1; register struct bw2cr *alias2; short w1; register short w2, wrestore; int result = 0; /* * XXX - kludge used to get around current mem_rop bug. * We need to have the page before the frame buffer to not have * have any "holes" in them as the mem_rop code will sometimes * access this page. We kludge here to avoid this problem by * increasing the size of area to be mapped by adding CLBYTES * to the device size mapped by the autoconfig code. Here * we remap all but the first page so that the first page map * entry is duplicated and then we bump the virtual address * up by CLBYTES above for bw2dev and in bwtwoattach(). */ mapin(&Sysmap[btoc(reg + CLBYTES - KERNELBASE)], (u_int)btoc(reg + CLBYTES), ((*(u_int *)&Sysmap[btoc(reg - KERNELBASE)]) & PG_PFNUM), btoc(BW2_FBSIZE), PG_V | PG_KW); bw2crmapin(bw2dev); alias1 = &bw2dev->bw2cr; alias2 = alias1 + 1; /* * Two adjacent shorts should be the same because * the control register is replicated every 2 bytes * throughout the control page. */ if ((w1 = peek((short *)alias1)) == -1) return (0); wrestore = w1; ((struct bw2cr *)&w1)->vc_copybase = 0xAA & BW2_COPYBASEMASK; if (poke((short *)alias1, w1)) return (0); if ((w2 = peek((short *)alias2)) == -1) goto restore; if (w1 != w2) goto restore; ((struct bw2cr *)&w1)->vc_copybase = ~0xAA & BW2_COPYBASEMASK; if (poke((short *)alias1, w1)) goto restore; if ((w2 = peek((short *)alias2)) == -1) goto restore; if (w1 != w2) goto restore; result = BW2_FBSIZE; restore: if (poke((short *)alias1, wrestore)) panic("bwtwoprobe"); return (result); #endif sun2 } /* * Set up the softc structure */ bwtwoattach(md) register struct mb_device *md; { #ifdef sun2 register struct bw2dev *bw2dev; #endif int pfnum; caddr_t fbvirtaddr; caddr_t v; int i; /* * XXX - Last part of mem_rop bug kludge, increase the virtual * address set up by autoconfig by CLBYTES as we have remapped * the first page to be a duplicate in bwtwoprobe(). */ md->md_addr += CLBYTES; pfnum = getkpgmap(md->md_addr) & PG_PFNUM; #ifdef sun3 /* * If we are on a SUN3_50 (Model 25), then we must * reserve the on board memory for the frame buffer. */ if (cpu == CPU_SUN3_50) { if (fbobmemavail == 0) panic("No video memory"); else fbobmemavail = 0; } #endif sun3 /* * Have we passed this way before? */ if (fbobmemavail == 0) { if (copyenvirt == 0) { copyenvirt = (caddr_t)(*romp->v_fbaddr); if (pfnum == copyenpfnum) bw2_softc[md->md_unit].image = copyenvirt; else bw2_softc[md->md_unit].image = md->md_addr; } return; } /* * We know that the copy memory can be used. Use the * shadow memory if the config flags say to use it. */ if ((md->md_flags & BW2_USECOPYMEM) == 0) { /* don't bother using reserved shadow memory */ copyenvirt = md->md_addr; bw2_softc[md->md_unit].image = md->md_addr; return; } /* * Mark the onboard frame buffer memory as not available * anymore as we are going to use it for copy memory. */ fbobmemavail = 0; if (*romp->v_outsink != OUTSCREEN || *romp->v_fbtype != FBTYPE_SUN2BW) fbvirtaddr = (caddr_t)md->md_addr; else { rmfree(kernelmap, (long)btoc(BW2_FBSIZE), btokmx((struct pte *)(md->md_addr))); mapout(&Usrptmap[btokmx((struct pte *)(md->md_addr))], btoc(BW2_FBSIZE)); fbvirtaddr = (caddr_t)(*romp->v_fbaddr); } copyenvirt = fbvirtaddr; copyenpfnum = getkpgmap(fbvirtaddr) & PG_PFNUM; /* * Copy the current frame buffer memory * to the copy memory as we map it in. */ for (v = (caddr_t)fbvirtaddr, i = btop(OBFBADDR); i < btop(OBFBADDR + BW2_FBSIZE); v += NBPG, i++) { mapin(CMAP1, btop(CADDR1), (u_int)(i | PGT_OBMEM), 1, PG_V | PG_KW); bcopy(v, CADDR1, NBPG); setpgmap(v, (long)(PG_V|PG_KW|PGT_OBMEM|i)); } #ifdef sun2 bw2dev = (struct bw2dev *)md->md_addr; i = (OBFBADDR>>BW2_COPYSHIFT) | BW2_COPYENABLEMASK; (void) bwtwosetcr(&bw2dev->bw2cr, i, 1); #endif sun2 #ifdef sun3 setcopyenable(); #endif if (pfnum == copyenpfnum) bw2_softc[md->md_unit].image = copyenvirt; else bw2_softc[md->md_unit].image = md->md_addr; } /*ARGSUSED*/ bwtwoioctl(dev, cmd, data, flag) dev_t dev; caddr_t data; { register int unit = minor(dev); switch (cmd) { case FBIOGTYPE: { register struct fbtype *fb = (struct fbtype *)data; #ifdef sun2 register struct bw2dev *bw2dev = (struct bw2dev *)bwtwoinfo[unit]->md_addr; #endif fb->fb_type = FBTYPE_SUN2BW; fb->fb_depth = 1; fb->fb_cmsize = 2; fb->fb_size = BW2_FBSIZE; #ifdef sun3 /* * Look at the eeprom for screen configuration, * if unknown default to standard sizes. */ switch (EEPROM->ee_diag.eed_scrsize) { case EED_SCR_1024X1024: fb->fb_height = BW2SQUARESIZEY; fb->fb_width = BW2SQUARESIZEX; break; case EED_SCR_1152X900: default: fb->fb_height = BW2SIZEY; fb->fb_width = BW2SIZEX; break; } #endif sun3 #ifdef sun2 /* * Check for "square screen" jumper */ if (cpu != CPU_SUN2_120 && bwtwoinfo[unit]->md_unit == 0 && bw2dev->bw2cr.vc_1024_jumper) { fb->fb_height = BW2SQUARESIZEY; fb->fb_width = BW2SQUARESIZEX; } else { fb->fb_height = BW2SIZEY; fb->fb_width = BW2SIZEX; } #endif sun2 break; } default: u.u_error = ENOTTY; } } bwtwointr() { int bwtwointclear(); return (fbintr(NBWTWO, bwtwoinfo, bwtwointclear)); } /* * Turn off interrupts on bwtwo board. */ #ifdef sun3 /*ARGSUSED*/ bwtwointclear(bw2dev) struct bw2dev *bw2dev; { (void) setintrenable(0); return (0); } #endif sun3 #ifdef sun2 bwtwointclear(bw2dev) struct bw2dev *bw2dev; { int int_active; int_active = bw2dev->bw2cr.vc_int; (void) setintrenable(&bw2dev->bw2cr); return (int_active); } setvideoenable(bw2cr) struct bw2cr *bw2cr; { bwtwosetcr(bw2cr, BW2_VIDEOENABLEMASK, 1); } setintrenable(bw2cr) struct bw2cr *bw2cr; { bwtwosetcr(bw2cr, BW2_INTENABLEMASK, 0); } /* * Special access approach to video ctrl register needed because byte writes, * generated when do bit writes, replicates itself on the subsequent byte as * well (this is a hardware bug). Thus, we need to access the register as a * word. Also these routines assume that only one bit changes at a time. */ bwtwosetcr(bw2cr, mask, value) struct bw2cr *bw2cr; short mask; int value; { register short w; /* * Read word from video control register. */ w = *((short *)bw2cr); /* * Modify bit as requested. */ if (value) w |= mask; else w &= ~mask; /* * Write word back to video control register. */ *((short *)bw2cr) = w; return; } #endif sun2 #ifndef sun3 /* * Given the video base virtual address, * map in the control register address. * This lets us handle minor implementation differences. */ bw2crmapin(bw2dev) struct bw2dev *bw2dev; { struct bw2cr *bw2cr = &bw2dev->bw2cr; int pte = getkpgmap((caddr_t)bw2dev); int page, delta; page = pte & PGT_MASK; if (page == PGT_OBMEM) delta = (int)BW2MB_CR - (int)BW2MB_FB; else if (page == PGT_OBIO) delta = (int)BW2VME_CR - (int)BW2VME_FB; else panic("bwtwocraddr"); mapin(&Sysmap[btoc((u_int)bw2cr - KERNELBASE)], btoc(bw2cr), pte + btoc(delta), 1, PG_V | (pte & PG_PROT)); } #endif !sun3