1 /* 2 * Copyright (c) 1992, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * This software was developed by the Computer Systems Engineering group 6 * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and 7 * contributed to Berkeley. 8 * 9 * All advertising materials mentioning features or use of this software 10 * must display the following acknowledgement: 11 * This product includes software developed by the University of 12 * California, Lawrence Berkeley Laboratory. 13 * 14 * %sccs.include.redist.c% 15 * 16 * @(#)cgthree.c 8.2 (Berkeley) 10/30/93 17 * 18 * from: $Header: cgthree.c,v 1.8 93/10/31 05:09:24 torek Exp $ 19 */ 20 21 /* 22 * color display (cgthree) driver. 23 * 24 * Does not handle interrupts, even though they can occur. 25 * 26 * XXX should defer colormap updates to vertical retrace interrupts 27 */ 28 29 #include <sys/param.h> 30 #include <sys/buf.h> 31 #include <sys/device.h> 32 #include <sys/fbio.h> 33 #include <sys/ioctl.h> 34 #include <sys/malloc.h> 35 #include <sys/mman.h> 36 #include <sys/tty.h> 37 38 #include <machine/autoconf.h> 39 #include <machine/pmap.h> 40 #include <machine/fbvar.h> 41 42 #include <sparc/sbus/btreg.h> 43 #include <sparc/sbus/btvar.h> 44 #include <sparc/sbus/cgthreereg.h> 45 #include <sparc/sbus/sbusvar.h> 46 47 /* per-display variables */ 48 struct cgthree_softc { 49 struct device sc_dev; /* base device */ 50 struct sbusdev sc_sd; /* sbus device */ 51 struct fbdevice sc_fb; /* frame buffer device */ 52 volatile struct bt_regs *sc_bt; /* Brooktree registers */ 53 caddr_t sc_phys; /* display RAM (phys addr) */ 54 int sc_blanked; /* true if blanked */ 55 union bt_cmap sc_cmap; /* Brooktree color map */ 56 }; 57 58 /* autoconfiguration driver */ 59 static void cgthreeattach(struct device *, struct device *, void *); 60 struct cfdriver cgthreecd = 61 { NULL, "cgthree", matchbyname, cgthreeattach, 62 DV_DULL, sizeof(struct cgthree_softc) }; 63 64 /* frame buffer generic driver */ 65 static void cgthreeunblank(struct device *); 66 static struct fbdriver cgthreefbdriver = { cgthreeunblank }; 67 68 extern int fbnode; 69 extern struct tty *fbconstty; 70 extern int (*v_putc)(); 71 extern int nullop(); 72 static int cgthree_cnputc(); 73 74 static void cgthreeloadcmap __P((struct cgthree_softc *, int, int)); 75 76 #define CGTHREE_MAJOR 55 /* XXX */ 77 78 /* 79 * Attach a display. We need to notice if it is the console, too. 80 */ 81 void 82 cgthreeattach(parent, self, args) 83 struct device *parent, *self; 84 void *args; 85 { 86 register struct cgthree_softc *sc = (struct cgthree_softc *)self; 87 register struct sbus_attach_args *sa = args; 88 register int node = sa->sa_ra.ra_node, ramsize, i; 89 register volatile struct bt_regs *bt; 90 register struct cgthree_all *p; 91 int isconsole; 92 93 sc->sc_fb.fb_major = CGTHREE_MAJOR; /* XXX to be removed */ 94 95 sc->sc_fb.fb_driver = &cgthreefbdriver; 96 sc->sc_fb.fb_device = &sc->sc_dev; 97 /* 98 * The defaults below match my screen, but are not guaranteed 99 * to be correct as defaults go... 100 */ 101 sc->sc_fb.fb_type.fb_type = FBTYPE_SUN3COLOR; 102 sc->sc_fb.fb_type.fb_width = getpropint(node, "width", 1152); 103 sc->sc_fb.fb_type.fb_height = getpropint(node, "height", 900); 104 sc->sc_fb.fb_linebytes = getpropint(node, "linebytes", 1152); 105 ramsize = sc->sc_fb.fb_type.fb_height * sc->sc_fb.fb_linebytes; 106 sc->sc_fb.fb_type.fb_depth = 8; 107 sc->sc_fb.fb_type.fb_cmsize = 256; 108 sc->sc_fb.fb_type.fb_size = ramsize; 109 printf(": %s, %d x %d", getpropstring(node, "model"), 110 sc->sc_fb.fb_type.fb_width, sc->sc_fb.fb_type.fb_height); 111 112 /* 113 * When the ROM has mapped in a cgthree display, the address 114 * maps only the video RAM, so in any case we have to map the 115 * registers ourselves. We only need the video RAM if we are 116 * going to print characters via rconsole. 117 */ 118 isconsole = node == fbnode && fbconstty != NULL; 119 p = (struct cgthree_all *)sa->sa_ra.ra_paddr; 120 if ((sc->sc_fb.fb_pixels = sa->sa_ra.ra_vaddr) == NULL && isconsole) { 121 /* this probably cannot happen, but what the heck */ 122 sc->sc_fb.fb_pixels = mapiodev(p->ba_ram, ramsize); 123 } 124 sc->sc_bt = bt = (volatile struct bt_regs *) 125 mapiodev((caddr_t)&p->ba_btreg, sizeof(p->ba_btreg)); 126 sc->sc_phys = p->ba_ram; 127 128 /* grab initial (current) color map */ 129 bt->bt_addr = 0; 130 for (i = 0; i < 256 * 3 / 4; i++) 131 sc->sc_cmap.cm_chip[i] = bt->bt_cmap; 132 /* make sure we are not blanked (see cgthreeunblank) */ 133 bt->bt_addr = 0x06; /* command reg */ 134 bt->bt_ctrl = 0x73; /* overlay plane */ 135 bt->bt_addr = 0x04; /* read mask */ 136 bt->bt_ctrl = 0xff; /* color planes */ 137 138 if (isconsole) { 139 printf(" (console)\n"); 140 #ifdef RCONSOLE 141 rcons_init(&sc->sc_fb); 142 #endif 143 } else 144 printf("\n"); 145 sbus_establish(&sc->sc_sd, &sc->sc_dev); 146 if (node == fbnode) 147 fb_attach(&sc->sc_fb); 148 } 149 150 int 151 cgthreeopen(dev, flags, mode, p) 152 dev_t dev; 153 int flags, mode; 154 struct proc *p; 155 { 156 int unit = minor(dev); 157 158 if (unit >= cgthreecd.cd_ndevs || cgthreecd.cd_devs[unit] == NULL) 159 return (ENXIO); 160 return (0); 161 } 162 163 int 164 cgthreeclose(dev, flags, mode, p) 165 dev_t dev; 166 int flags, mode; 167 struct proc *p; 168 { 169 170 return (0); 171 } 172 173 int 174 cgthreeioctl(dev, cmd, data, flags, p) 175 dev_t dev; 176 int cmd; 177 register caddr_t data; 178 int flags; 179 struct proc *p; 180 { 181 register struct cgthree_softc *sc = cgthreecd.cd_devs[minor(dev)]; 182 register struct fbgattr *fba; 183 int error; 184 185 switch (cmd) { 186 187 case FBIOGTYPE: 188 *(struct fbtype *)data = sc->sc_fb.fb_type; 189 break; 190 191 case FBIOGATTR: 192 fba = (struct fbgattr *)data; 193 fba->real_type = sc->sc_fb.fb_type.fb_type; 194 fba->owner = 0; /* XXX ??? */ 195 fba->fbtype = sc->sc_fb.fb_type; 196 fba->sattr.flags = 0; 197 fba->sattr.emu_type = sc->sc_fb.fb_type.fb_type; 198 fba->sattr.dev_specific[0] = -1; 199 fba->emu_types[0] = sc->sc_fb.fb_type.fb_type; 200 fba->emu_types[1] = -1; 201 break; 202 203 case FBIOGETCMAP: 204 return (bt_getcmap((struct fbcmap *)data, &sc->sc_cmap, 256)); 205 206 case FBIOPUTCMAP: 207 /* copy to software map */ 208 #define p ((struct fbcmap *)data) 209 error = bt_putcmap(p, &sc->sc_cmap, 256); 210 if (error) 211 return (error); 212 /* now blast them into the chip */ 213 /* XXX should use retrace interrupt */ 214 cgthreeloadcmap(sc, p->index, p->count); 215 #undef p 216 break; 217 218 case FBIOGVIDEO: 219 *(int *)data = sc->sc_blanked; 220 break; 221 222 case FBIOSVIDEO: 223 if (*(int *)data) 224 cgthreeunblank(&sc->sc_dev); 225 else if (!sc->sc_blanked) { 226 register volatile struct bt_regs *bt; 227 228 bt = sc->sc_bt; 229 bt->bt_addr = 0x06; /* command reg */ 230 bt->bt_ctrl = 0x70; /* overlay plane */ 231 bt->bt_addr = 0x04; /* read mask */ 232 bt->bt_ctrl = 0x00; /* color planes */ 233 /* 234 * Set color 0 to black -- note that this overwrites 235 * R of color 1. 236 */ 237 bt->bt_addr = 0; 238 bt->bt_cmap = 0; 239 240 sc->sc_blanked = 1; 241 } 242 break; 243 244 default: 245 return (ENOTTY); 246 } 247 return (0); 248 } 249 250 /* 251 * Undo the effect of an FBIOSVIDEO that turns the video off. 252 */ 253 static void 254 cgthreeunblank(dev) 255 struct device *dev; 256 { 257 struct cgthree_softc *sc = (struct cgthree_softc *)dev; 258 register volatile struct bt_regs *bt; 259 260 if (sc->sc_blanked) { 261 sc->sc_blanked = 0; 262 bt = sc->sc_bt; 263 /* restore color 0 (and R of color 1) */ 264 bt->bt_addr = 0; 265 bt->bt_cmap = sc->sc_cmap.cm_chip[0]; 266 267 /* restore read mask */ 268 bt->bt_addr = 0x06; /* command reg */ 269 bt->bt_ctrl = 0x73; /* overlay plane */ 270 bt->bt_addr = 0x04; /* read mask */ 271 bt->bt_ctrl = 0xff; /* color planes */ 272 } 273 } 274 275 /* 276 * Load a subset of the current (new) colormap into the Brooktree DAC. 277 */ 278 static void 279 cgthreeloadcmap(sc, start, ncolors) 280 register struct cgthree_softc *sc; 281 register int start, ncolors; 282 { 283 register volatile struct bt_regs *bt; 284 register u_int *ip; 285 register int count; 286 287 ip = &sc->sc_cmap.cm_chip[BT_D4M3(start)]; /* start/4 * 3 */ 288 count = BT_D4M3(start + ncolors - 1) - BT_D4M3(start) + 3; 289 bt = sc->sc_bt; 290 bt->bt_addr = BT_D4M4(start); 291 while (--count >= 0) 292 bt->bt_cmap = *ip++; 293 } 294 295 /* 296 * Return the address that would map the given device at the given 297 * offset, allowing for the given protection, or return -1 for error. 298 * 299 * The cg3 is mapped starting at 256KB, for pseudo-compatibility with 300 * the cg4 (which had an overlay plane in the first 128K and an enable 301 * plane in the next 128K). X11 uses only 256k+ region but tries to 302 * map the whole thing, so we repeatedly map the first 256K to the 303 * first page of the color screen. If someone tries to use the overlay 304 * and enable regions, they will get a surprise.... 305 */ 306 int 307 cgthreemap(dev, off, prot) 308 dev_t dev; 309 int off, prot; 310 { 311 register struct cgthree_softc *sc = cgthreecd.cd_devs[minor(dev)]; 312 #define START (128*1024 + 128*1024) 313 314 if (off & PGOFSET) 315 panic("cgthreemap"); 316 if ((unsigned)off < START) 317 off = 0; 318 else 319 off -= START; 320 if ((unsigned)off >= sc->sc_fb.fb_type.fb_size) 321 return (-1); 322 /* 323 * I turned on PMAP_NC here to disable the cache as I was 324 * getting horribly broken behaviour with it on. 325 */ 326 return ((int)sc->sc_phys + off + PMAP_OBIO + PMAP_NC); 327 } 328