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