FreeBSD/Linux Kernel Cross Reference
sys/dev/sbus/p9100.c
1 /* $NetBSD: p9100.c,v 1.19 2004/03/17 17:04:58 pk Exp $ */
2
3 /*-
4 * Copyright (c) 1998 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Matt Thomas.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. All advertising materials mentioning features or use of this software
19 * must display the following acknowledgement:
20 * This product includes software developed by the NetBSD
21 * Foundation, Inc. and its contributors.
22 * 4. Neither the name of The NetBSD Foundation nor the names of its
23 * contributors may be used to endorse or promote products derived
24 * from this software without specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36 * POSSIBILITY OF SUCH DAMAGE.
37 */
38
39 /*
40 * color display (p9100) driver.
41 *
42 * Does not handle interrupts, even though they can occur.
43 *
44 * XXX should defer colormap updates to vertical retrace interrupts
45 */
46
47 #include <sys/cdefs.h>
48 __KERNEL_RCSID(0, "$NetBSD: p9100.c,v 1.19 2004/03/17 17:04:58 pk Exp $");
49
50 #include <sys/param.h>
51 #include <sys/systm.h>
52 #include <sys/buf.h>
53 #include <sys/device.h>
54 #include <sys/ioctl.h>
55 #include <sys/malloc.h>
56 #include <sys/mman.h>
57 #include <sys/tty.h>
58 #include <sys/conf.h>
59
60 #include <machine/bus.h>
61 #include <machine/autoconf.h>
62
63 #include <dev/sun/fbio.h>
64 #include <dev/sun/fbvar.h>
65 #include <dev/sun/btreg.h>
66 #include <dev/sun/btvar.h>
67 #if 0
68 #include <dev/sbus/p9100reg.h>
69 #endif
70
71 #include <dev/sbus/sbusvar.h>
72
73 #include "tctrl.h"
74 #if NTCTRL > 0
75 #include <machine/tctrl.h>
76 #include <sparc/dev/tctrlvar.h>/*XXX*/
77 #endif
78
79 /* per-display variables */
80 struct p9100_softc {
81 struct device sc_dev; /* base device */
82 struct sbusdev sc_sd; /* sbus device */
83 struct fbdevice sc_fb; /* frame buffer device */
84 bus_space_tag_t sc_bustag;
85
86 bus_addr_t sc_ctl_paddr; /* phys address description */
87 bus_size_t sc_ctl_psize; /* for device mmap() */
88 bus_space_handle_t sc_ctl_memh; /* bus space handle */
89
90 bus_addr_t sc_cmd_paddr; /* phys address description */
91 bus_size_t sc_cmd_psize; /* for device mmap() */
92 bus_space_handle_t sc_cmd_memh; /* bus space handle */
93
94 bus_addr_t sc_fb_paddr; /* phys address description */
95 bus_size_t sc_fb_psize; /* for device mmap() */
96 bus_space_handle_t sc_fb_memh; /* bus space handle */
97
98 uint32_t sc_junk;
99
100 union bt_cmap sc_cmap; /* Brooktree color map */
101 };
102
103 /* The Tadpole 3GX Technical Reference Manual lies. The ramdac registers
104 * are map in 4 byte increments, not 8.
105 */
106 #define SCRN_RPNT_CTL_1 0x0138 /* Screen Respaint Timing Control 1 */
107 #define VIDEO_ENABLED 0x00000020
108 #define PWRUP_CNFG 0x0194 /* Power Up Configuration */
109 #define DAC_CMAP_WRIDX 0x0200 /* IBM RGB528 Palette Address (Write) */
110 #define DAC_CMAP_DATA 0x0204 /* IBM RGB528 Palette Data */
111 #define DAC_PXL_MASK 0x0208 /* IBM RGB528 Pixel Mask */
112 #define DAC_CMAP_RDIDX 0x020c /* IBM RGB528 Palette Address (Read) */
113 #define DAC_INDX_LO 0x0210 /* IBM RGB528 Index Low */
114 #define DAC_INDX_HI 0x0214 /* IBM RGB528 Index High */
115 #define DAC_INDX_DATA 0x0218 /* IBM RGB528 Index Data (Indexed Registers) */
116 #define DAC_INDX_CTL 0x021c /* IBM RGB528 Index Control */
117
118 /* autoconfiguration driver */
119 static int p9100_sbus_match(struct device *, struct cfdata *, void *);
120 static void p9100_sbus_attach(struct device *, struct device *, void *);
121
122 static void p9100unblank(struct device *);
123 static void p9100_shutdown(void *);
124
125 CFATTACH_DECL(pnozz, sizeof(struct p9100_softc),
126 p9100_sbus_match, p9100_sbus_attach, NULL, NULL);
127
128 extern struct cfdriver pnozz_cd;
129
130 dev_type_open(p9100open);
131 dev_type_ioctl(p9100ioctl);
132 dev_type_mmap(p9100mmap);
133
134 const struct cdevsw pnozz_cdevsw = {
135 p9100open, nullclose, noread, nowrite, p9100ioctl,
136 nostop, notty, nopoll, p9100mmap, nokqfilter,
137 };
138
139 /* frame buffer generic driver */
140 static struct fbdriver p9100fbdriver = {
141 p9100unblank, p9100open, nullclose, p9100ioctl, nopoll,
142 p9100mmap, nokqfilter
143 };
144
145 static void p9100loadcmap(struct p9100_softc *, int, int);
146 static void p9100_set_video(struct p9100_softc *, int);
147 static int p9100_get_video(struct p9100_softc *);
148 static uint32_t p9100_ctl_read_4(struct p9100_softc *, bus_size_t);
149 static void p9100_ctl_write_4(struct p9100_softc *, bus_size_t, uint32_t);
150 #if 0
151 static uint8_t p9100_ramdac_read(struct p9100_softc *, bus_size_t);
152 #endif
153 static void p9100_ramdac_write(struct p9100_softc *, bus_size_t, uint8_t);
154
155 /*
156 * Match a p9100.
157 */
158 static int
159 p9100_sbus_match(struct device *parent, struct cfdata *cf, void *aux)
160 {
161 struct sbus_attach_args *sa = aux;
162
163 return (strcmp("p9100", sa->sa_name) == 0);
164 }
165
166
167 /*
168 * Attach a display. We need to notice if it is the console, too.
169 */
170 static void
171 p9100_sbus_attach(struct device *parent, struct device *self, void *args)
172 {
173 struct p9100_softc *sc = (struct p9100_softc *)self;
174 struct sbus_attach_args *sa = args;
175 struct fbdevice *fb = &sc->sc_fb;
176 int isconsole;
177 int node;
178 int i;
179
180 /* Remember cookies for p9100_mmap() */
181 sc->sc_bustag = sa->sa_bustag;
182 sc->sc_ctl_paddr = sbus_bus_addr(sa->sa_bustag,
183 sa->sa_reg[0].oa_space, sa->sa_reg[0].oa_base);
184 sc->sc_ctl_psize = (bus_size_t)sa->sa_reg[0].oa_size;
185
186 sc->sc_cmd_paddr = sbus_bus_addr(sa->sa_bustag,
187 sa->sa_reg[1].oa_space, sa->sa_reg[1].oa_base);
188 sc->sc_cmd_psize = (bus_size_t)sa->sa_reg[1].oa_size;
189
190 sc->sc_fb_paddr = sbus_bus_addr(sa->sa_bustag,
191 sa->sa_reg[2].oa_space, sa->sa_reg[2].oa_base);
192 sc->sc_fb_psize = (bus_size_t)sa->sa_reg[2].oa_size;
193
194 fb->fb_driver = &p9100fbdriver;
195 fb->fb_device = &sc->sc_dev;
196 fb->fb_flags = sc->sc_dev.dv_cfdata->cf_flags & FB_USERMASK;
197 fb->fb_type.fb_type = FBTYPE_SUN3COLOR;
198 fb->fb_pixels = NULL;
199
200 node = sa->sa_node;
201 isconsole = fb_is_console(node);
202 if (!isconsole) {
203 printf("\n%s: fatal error: PROM didn't configure device: not console\n", self->dv_xname);
204 return;
205 }
206
207 /*
208 * When the ROM has mapped in a p9100 display, the address
209 * maps only the video RAM, so in any case we have to map the
210 * registers ourselves. We only need the video RAM if we are
211 * going to print characters via rconsole.
212 */
213 if (sbus_bus_map(sc->sc_bustag,
214 sa->sa_reg[0].oa_space,
215 sa->sa_reg[0].oa_base,
216 sc->sc_ctl_psize,
217 BUS_SPACE_MAP_LINEAR, &sc->sc_ctl_memh) != 0) {
218 printf("%s: cannot map control registers\n", self->dv_xname);
219 return;
220 }
221
222 if (sbus_bus_map(sc->sc_bustag,
223 sa->sa_reg[1].oa_space,
224 sa->sa_reg[1].oa_base,
225 sc->sc_cmd_psize,
226 BUS_SPACE_MAP_LINEAR, &sc->sc_cmd_memh) != 0) {
227 printf("%s: cannot map command registers\n", self->dv_xname);
228 return;
229 }
230
231 if (sa->sa_npromvaddrs != 0)
232 fb->fb_pixels = (caddr_t)sa->sa_promvaddrs[0];
233
234 if (fb->fb_pixels == NULL) {
235 if (sbus_bus_map(sc->sc_bustag,
236 sa->sa_reg[2].oa_space,
237 sa->sa_reg[2].oa_base,
238 sc->sc_fb_psize,
239 BUS_SPACE_MAP_LINEAR, &sc->sc_fb_memh) != 0) {
240 printf("%s: cannot map framebuffer\n", self->dv_xname);
241 return;
242 }
243 fb->fb_pixels = (char *)sc->sc_fb_memh;
244 } else {
245 sc->sc_fb_memh = (bus_space_handle_t) fb->fb_pixels;
246 }
247
248 i = p9100_ctl_read_4(sc, 0x0004);
249 switch ((i >> 26) & 7) {
250 case 5: fb->fb_type.fb_depth = 32; break;
251 case 7: fb->fb_type.fb_depth = 24; break;
252 case 3: fb->fb_type.fb_depth = 16; break;
253 case 2: fb->fb_type.fb_depth = 8; break;
254 default: {
255 panic("pnozz: can't determine screen depth (0x%02x)", i);
256 }
257 }
258 fb_setsize_obp(fb, fb->fb_type.fb_depth, 800, 600, node);
259
260 sbus_establish(&sc->sc_sd, &sc->sc_dev);
261
262 fb->fb_type.fb_size = fb->fb_type.fb_height * fb->fb_linebytes;
263 printf(": rev %d, %dx%d, depth %d",
264 (i & 7), fb->fb_type.fb_width, fb->fb_type.fb_height,
265 fb->fb_type.fb_depth);
266
267 fb->fb_type.fb_cmsize = prom_getpropint(node, "cmsize", 256);
268 if ((1 << fb->fb_type.fb_depth) != fb->fb_type.fb_cmsize)
269 printf(", %d entry colormap", fb->fb_type.fb_cmsize);
270
271 /* Initialize the default color map. */
272 bt_initcmap(&sc->sc_cmap, 256);
273 p9100loadcmap(sc, 0, 256);
274
275 /* make sure we are not blanked */
276 if (isconsole)
277 p9100_set_video(sc, 1);
278
279 if (shutdownhook_establish(p9100_shutdown, sc) == NULL) {
280 panic("%s: could not establish shutdown hook",
281 sc->sc_dev.dv_xname);
282 }
283
284 if (isconsole) {
285 printf(" (console)\n");
286 #ifdef RASTERCONSOLE
287 for (i = 0; i < fb->fb_type.fb_size; i++) {
288 if (fb->fb_pixels[i] == 0) {
289 fb->fb_pixels[i] = 1;
290 } else if (fb->fb_pixels[i] == (char) 255) {
291 fb->fb_pixels[i] = 0;
292 }
293 }
294 p9100loadcmap(sc, 255, 1);
295 fbrcons_init(fb);
296 #endif
297 } else
298 printf("\n");
299
300 fb_attach(fb, isconsole);
301 }
302
303 static void
304 p9100_shutdown(arg)
305 void *arg;
306 {
307 struct p9100_softc *sc = arg;
308 #ifdef RASTERCONSOLE
309 struct fbdevice *fb = &sc->sc_fb;
310 int i;
311
312 for (i = 0; i < fb->fb_type.fb_size; i++) {
313 if (fb->fb_pixels[i] == 1) {
314 fb->fb_pixels[i] = 0;
315 } else if (fb->fb_pixels[i] == 0) {
316 fb->fb_pixels[i] = 255;
317 }
318 }
319 sc->sc_cmap.cm_map[0][0] = 0xff;
320 sc->sc_cmap.cm_map[0][1] = 0xff;
321 sc->sc_cmap.cm_map[0][2] = 0xff;
322 sc->sc_cmap.cm_map[1][0] = 0;
323 sc->sc_cmap.cm_map[1][1] = 0;
324 sc->sc_cmap.cm_map[1][2] = 0x80;
325 p9100loadcmap(sc, 0, 2);
326 sc->sc_cmap.cm_map[255][0] = 0;
327 sc->sc_cmap.cm_map[255][1] = 0;
328 sc->sc_cmap.cm_map[255][2] = 0;
329 p9100loadcmap(sc, 255, 1);
330 #endif
331 p9100_set_video(sc, 1);
332 }
333
334 int
335 p9100open(dev_t dev, int flags, int mode, struct proc *p)
336 {
337 int unit = minor(dev);
338
339 if (unit >= pnozz_cd.cd_ndevs || pnozz_cd.cd_devs[unit] == NULL)
340 return (ENXIO);
341 return (0);
342 }
343
344 int
345 p9100ioctl(dev_t dev, u_long cmd, caddr_t data, int flags, struct proc *p)
346 {
347 struct p9100_softc *sc = pnozz_cd.cd_devs[minor(dev)];
348 struct fbgattr *fba;
349 int error;
350
351 switch (cmd) {
352
353 case FBIOGTYPE:
354 *(struct fbtype *)data = sc->sc_fb.fb_type;
355 break;
356
357 case FBIOGATTR:
358 fba = (struct fbgattr *)data;
359 fba->real_type = sc->sc_fb.fb_type.fb_type;
360 fba->owner = 0; /* XXX ??? */
361 fba->fbtype = sc->sc_fb.fb_type;
362 fba->sattr.flags = 0;
363 fba->sattr.emu_type = sc->sc_fb.fb_type.fb_type;
364 fba->sattr.dev_specific[0] = -1;
365 fba->emu_types[0] = sc->sc_fb.fb_type.fb_type;
366 fba->emu_types[1] = -1;
367 break;
368
369 case FBIOGETCMAP:
370 #define p ((struct fbcmap *)data)
371 return (bt_getcmap(p, &sc->sc_cmap, 256, 1));
372
373 case FBIOPUTCMAP:
374 /* copy to software map */
375 error = bt_putcmap(p, &sc->sc_cmap, 256, 1);
376 if (error)
377 return (error);
378 /* now blast them into the chip */
379 /* XXX should use retrace interrupt */
380 p9100loadcmap(sc, p->index, p->count);
381 #undef p
382 break;
383
384 case FBIOGVIDEO:
385 *(int *)data = p9100_get_video(sc);
386 break;
387
388 case FBIOSVIDEO:
389 p9100_set_video(sc, *(int *)data);
390 break;
391
392 default:
393 return (ENOTTY);
394 }
395 return (0);
396 }
397
398 static uint32_t
399 p9100_ctl_read_4(struct p9100_softc *sc, bus_size_t off)
400 {
401 sc->sc_junk = bus_space_read_4(sc->sc_bustag, sc->sc_fb_memh, off);
402 return bus_space_read_4(sc->sc_bustag, sc->sc_ctl_memh, off);
403 }
404
405 static void
406 p9100_ctl_write_4(struct p9100_softc *sc, bus_size_t off, uint32_t v)
407 {
408 sc->sc_junk = bus_space_read_4(sc->sc_bustag, sc->sc_fb_memh, off);
409 bus_space_write_4(sc->sc_bustag, sc->sc_ctl_memh, off, v);
410 }
411
412 #if 0
413 static uint8_t
414 p9100_ramdac_read(struct p9100_softc *sc, bus_size_t off)
415 {
416 sc->sc_junk = p9100_ctl_read_4(sc, PWRUP_CNFG);
417 return p9100_ctl_read_4(sc, off) >> 16;
418 }
419 #endif
420
421 static void
422 p9100_ramdac_write(struct p9100_softc *sc, bus_size_t off, uint8_t v)
423 {
424 sc->sc_junk = p9100_ctl_read_4(sc, PWRUP_CNFG);
425 p9100_ctl_write_4(sc, off, v << 16);
426 }
427
428 /*
429 * Undo the effect of an FBIOSVIDEO that turns the video off.
430 */
431 static void
432 p9100unblank(struct device *dev)
433 {
434
435 p9100_set_video((struct p9100_softc *)dev, 1);
436 }
437
438 static void
439 p9100_set_video(struct p9100_softc *sc, int enable)
440 {
441 u_int32_t v = p9100_ctl_read_4(sc, SCRN_RPNT_CTL_1);
442 if (enable)
443 v |= VIDEO_ENABLED;
444 else
445 v &= ~VIDEO_ENABLED;
446 p9100_ctl_write_4(sc, SCRN_RPNT_CTL_1, v);
447 #if NTCTRL > 0
448 /* Turn On/Off the TFT if we know how.
449 */
450 tadpole_set_video(enable);
451 #endif
452 }
453
454 static int
455 p9100_get_video(struct p9100_softc *sc)
456 {
457 return (p9100_ctl_read_4(sc, SCRN_RPNT_CTL_1) & VIDEO_ENABLED) != 0;
458 }
459
460 /*
461 * Load a subset of the current (new) colormap into the IBM RAMDAC.
462 */
463 static void
464 p9100loadcmap(struct p9100_softc *sc, int start, int ncolors)
465 {
466 u_char *p;
467
468 p9100_ramdac_write(sc, DAC_CMAP_WRIDX, start);
469
470 for (p = sc->sc_cmap.cm_map[start], ncolors *= 3; ncolors-- > 0; p++) {
471 p9100_ramdac_write(sc, DAC_CMAP_DATA, *p);
472 }
473 }
474
475 /*
476 * Return the address that would map the given device at the given
477 * offset, allowing for the given protection, or return -1 for error.
478 */
479 paddr_t
480 p9100mmap(dev_t dev, off_t off, int prot)
481 {
482 struct p9100_softc *sc = pnozz_cd.cd_devs[minor(dev)];
483
484 if (off & PGOFSET)
485 panic("p9100mmap");
486 if (off < 0)
487 return (-1);
488
489 #define CG3_MMAP_OFFSET 0x04000000
490 /* Make Xsun think we are a CG3 (SUN3COLOR)
491 */
492 if (off >= CG3_MMAP_OFFSET && off < CG3_MMAP_OFFSET + sc->sc_fb_psize) {
493 off -= CG3_MMAP_OFFSET;
494 return (bus_space_mmap(sc->sc_bustag,
495 sc->sc_fb_paddr,
496 off,
497 prot,
498 BUS_SPACE_MAP_LINEAR));
499 }
500
501 if (off >= sc->sc_fb_psize + sc->sc_ctl_psize + sc->sc_cmd_psize)
502 return (-1);
503
504 if (off < sc->sc_fb_psize) {
505 return (bus_space_mmap(sc->sc_bustag,
506 sc->sc_fb_paddr,
507 off,
508 prot,
509 BUS_SPACE_MAP_LINEAR));
510 }
511 off -= sc->sc_fb_psize;
512 if (off < sc->sc_ctl_psize) {
513 return (bus_space_mmap(sc->sc_bustag,
514 sc->sc_ctl_paddr,
515 off,
516 prot,
517 BUS_SPACE_MAP_LINEAR));
518 }
519 off -= sc->sc_ctl_psize;
520
521 return (bus_space_mmap(sc->sc_bustag,
522 sc->sc_cmd_paddr,
523 off,
524 prot,
525 BUS_SPACE_MAP_LINEAR));
526 }
Cache object: 99c334dd1eda37d881f0375356bed559
|