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