agten.c revision 1.28.6.1 1 /* $NetBSD: agten.c,v 1.28.6.1 2012/11/20 03:02:32 tls Exp $ */
2
3 /*-
4 * Copyright (c) 2007 Michael Lorenz
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
17 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
18 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
20 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 * POSSIBILITY OF SUCH DAMAGE.
27 */
28
29 #include <sys/cdefs.h>
30 __KERNEL_RCSID(0, "$NetBSD: agten.c,v 1.28.6.1 2012/11/20 03:02:32 tls Exp $");
31
32 /*
33 * a driver for the Fujitsu AG-10e SBus framebuffer
34 *
35 * this thing is Frankenstein's Monster among graphics boards.
36 * it contains three graphics chips:
37 * a GLint 300SX - 24bit stuff, double-buffered
38 * an Imagine 128 which provides an 8bit overlay
39 * a Weitek P9100 which provides WIDs
40 * so here we need to mess only with the P9100 and the I128 - for X we just
41 * hide the overlay and let the Xserver mess with the GLint
42 */
43
44 #include <sys/param.h>
45 #include <sys/systm.h>
46 #include <sys/kernel.h>
47 #include <sys/device.h>
48 #include <sys/proc.h>
49 #include <sys/mutex.h>
50 #include <sys/ioctl.h>
51 #include <sys/kernel.h>
52 #include <sys/systm.h>
53 #include <sys/conf.h>
54
55 #include <dev/sun/fbio.h>
56 #include <dev/sun/fbvar.h>
57 #include <dev/sun/btreg.h>
58 #include <dev/sun/btvar.h>
59
60 #include <sys/bus.h>
61 #include <machine/autoconf.h>
62
63 #include <dev/sbus/sbusvar.h>
64
65 #include <dev/wscons/wsconsio.h>
66 #include <dev/wscons/wsdisplayvar.h>
67 #include <dev/rasops/rasops.h>
68 #include <dev/wsfont/wsfont.h>
69
70 #include <dev/wscons/wsdisplay_vconsvar.h>
71 #include <dev/wscons/wsdisplay_glyphcachevar.h>
72
73 #include <dev/sbus/p9100reg.h>
74 #include <dev/ic/ibm561reg.h>
75 #include <dev/ic/i128reg.h>
76 #include <dev/ic/i128var.h>
77
78 #include "opt_agten.h"
79 #include "ioconf.h"
80
81 static int agten_match(device_t, cfdata_t, void *);
82 static void agten_attach(device_t, device_t, void *);
83
84 static int agten_ioctl(void *, void *, u_long, void *, int, struct lwp *);
85 static paddr_t agten_mmap(void *, void *, off_t, int);
86 static void agten_init_screen(void *, struct vcons_screen *, int, long *);
87
88 struct agten_softc {
89 device_t sc_dev; /* base device */
90 struct fbdevice sc_fb; /* frame buffer device */
91
92 struct vcons_screen sc_console_screen;
93 struct wsscreen_descr sc_defaultscreen_descr;
94 const struct wsscreen_descr *sc_screens[1];
95 struct wsscreen_list sc_screenlist;
96
97 bus_space_tag_t sc_bustag;
98
99 bus_space_handle_t sc_i128_fbh;
100 bus_size_t sc_i128_fbsz;
101 bus_space_handle_t sc_i128_regh;
102 bus_space_handle_t sc_p9100_regh;
103 bus_addr_t sc_glint_fb;
104 bus_addr_t sc_glint_regs;
105 uint32_t sc_glint_fbsz;
106
107 uint32_t sc_width;
108 uint32_t sc_height; /* panel width / height */
109 uint32_t sc_stride;
110 uint32_t sc_depth;
111
112 int sc_cursor_x;
113 int sc_cursor_y;
114 int sc_video; /* video output enabled */
115
116 /* some /dev/fb* stuff */
117 int sc_fb_is_open;
118
119 union bt_cmap sc_cmap; /* Brooktree color map */
120
121 int sc_mode;
122 uint32_t sc_bg;
123
124 void (*sc_putchar)(void *, int, int, u_int, long);
125
126 struct vcons_data vd;
127 glyphcache sc_gc;
128 };
129
130 CFATTACH_DECL_NEW(agten, sizeof(struct agten_softc),
131 agten_match, agten_attach, NULL, NULL);
132
133
134 static int agten_putcmap(struct agten_softc *, struct wsdisplay_cmap *);
135 static int agten_getcmap(struct agten_softc *, struct wsdisplay_cmap *);
136 static int agten_putpalreg(struct agten_softc *, uint8_t, uint8_t,
137 uint8_t, uint8_t);
138 static void agten_init(struct agten_softc *);
139 static void agten_init_cmap(struct agten_softc *, struct rasops_info *);
140 static void agten_gfx(struct agten_softc *);
141 static void agten_set_video(struct agten_softc *, int);
142 static int agten_get_video(struct agten_softc *);
143
144 static void agten_bitblt(void *, int, int, int, int, int, int, int);
145 static void agten_rectfill(void *, int, int, int, int, long);
146
147 static void agten_putchar(void *, int, int, u_int, long);
148 static void agten_cursor(void *, int, int, int);
149 static void agten_copycols(void *, int, int, int, int);
150 static void agten_erasecols(void *, int, int, int, long);
151 static void agten_copyrows(void *, int, int, int);
152 static void agten_eraserows(void *, int, int, long);
153
154 static void agten_move_cursor(struct agten_softc *, int, int);
155 static int agten_do_cursor(struct agten_softc *sc,
156 struct wsdisplay_cursor *);
157 static int agten_do_sun_cursor(struct agten_softc *sc,
158 struct fbcursor *);
159
160 static uint16_t util_interleave(uint8_t, uint8_t);
161 static uint16_t util_interleave_lin(uint8_t, uint8_t);
162
163 extern const u_char rasops_cmap[768];
164
165 struct wsdisplay_accessops agten_accessops = {
166 agten_ioctl,
167 agten_mmap,
168 NULL, /* alloc_screen */
169 NULL, /* free_screen */
170 NULL, /* show_screen */
171 NULL, /* load_font */
172 NULL, /* pollc */
173 NULL /* scroll */
174 };
175
176 /* /dev/fb* stuff */
177
178 static int agten_fb_open(dev_t, int, int, struct lwp *);
179 static int agten_fb_close(dev_t, int, int, struct lwp *);
180 static int agten_fb_ioctl(dev_t, u_long, void *, int, struct lwp *);
181 static paddr_t agten_fb_mmap(dev_t, off_t, int);
182 static void agten_fb_unblank(device_t);
183
184 static struct fbdriver agtenfbdriver = {
185 agten_fb_unblank, agten_fb_open, agten_fb_close, agten_fb_ioctl,
186 nopoll, agten_fb_mmap, nokqfilter
187 };
188
189 static inline void
190 agten_write_dac(struct agten_softc *sc, int reg, uint8_t val)
191 {
192 bus_space_write_4(sc->sc_bustag, sc->sc_p9100_regh,
193 0x200 + (reg << 2), (uint32_t)val << 16);
194 }
195
196 static inline void
197 agten_write_idx(struct agten_softc *sc, int offset)
198 {
199 bus_space_write_4(sc->sc_bustag, sc->sc_p9100_regh,
200 0x200 + (IBM561_ADDR_LOW << 2), (offset & 0xff) << 16);
201 bus_space_write_4(sc->sc_bustag, sc->sc_p9100_regh,
202 0x200 + (IBM561_ADDR_HIGH << 2), ((offset >> 8) & 0xff) << 16);
203 }
204
205 static inline void
206 agten_write_dac_10(struct agten_softc *sc, int reg, uint16_t val)
207 {
208 agten_write_dac(sc, reg, (val >> 2) & 0xff);
209 agten_write_dac(sc, reg, (val & 0x3) << 6);
210 }
211
212 static int
213 agten_match(device_t dev, cfdata_t cf, void *aux)
214 {
215 struct sbus_attach_args *sa = aux;
216
217 if (strcmp("PFU,aga", sa->sa_name) == 0)
218 return 100;
219 return 0;
220 }
221
222 static void
223 agten_attach(device_t parent, device_t dev, void *aux)
224 {
225 struct agten_softc *sc = device_private(dev);
226 struct sbus_attach_args *sa = aux;
227 struct fbdevice *fb = &sc->sc_fb;
228 struct wsemuldisplaydev_attach_args aa;
229 struct rasops_info *ri;
230 long defattr;
231 uint32_t reg;
232 int node = sa->sa_node;
233 int console;
234
235 sc->sc_dev = dev;
236 sc->sc_defaultscreen_descr = (struct wsscreen_descr){
237 "default",
238 0, 0,
239 NULL,
240 8, 16,
241 WSSCREEN_WSCOLORS | WSSCREEN_HILIT,
242 NULL
243 };
244 sc->sc_screens[0] = &sc->sc_defaultscreen_descr;
245 sc->sc_screenlist = (struct wsscreen_list){1, sc->sc_screens};
246 sc->sc_mode = WSDISPLAYIO_MODE_EMUL;
247 sc->sc_fb_is_open = 0;
248 sc->sc_video = -1;
249 sc->sc_bustag = sa->sa_bustag;
250 sc->sc_putchar = NULL;
251
252 sc->sc_width = prom_getpropint(node, "ffb_width", 1152);
253 sc->sc_height = prom_getpropint(node, "ffb_height", 900);
254 sc->sc_depth = prom_getpropint(node, "ffb_depth", 8);
255 sc->sc_stride = sc->sc_width * (sc->sc_depth >> 3);
256
257 reg = prom_getpropint(node, "i128_fb_physaddr", -1);
258 sc->sc_i128_fbsz = prom_getpropint(node, "i128_fb_size", -1);
259 if (sbus_bus_map(sc->sc_bustag,
260 sa->sa_reg[0].oa_space, sa->sa_reg[0].oa_base + reg,
261 round_page(sc->sc_stride * sc->sc_height),
262 BUS_SPACE_MAP_LINEAR | BUS_SPACE_MAP_LARGE,
263 &sc->sc_i128_fbh) != 0) {
264
265 aprint_error_dev(dev, "unable to map the framebuffer\n");
266 return;
267 }
268 fb->fb_pixels = bus_space_vaddr(sc->sc_bustag, sc->sc_i128_fbh);
269
270 reg = prom_getpropint(node, "i128_reg_physaddr", -1);
271 if (sbus_bus_map(sc->sc_bustag,
272 sa->sa_reg[0].oa_space, sa->sa_reg[0].oa_base + reg,
273 0x10000, 0, &sc->sc_i128_regh) != 0) {
274
275 aprint_error_dev(dev, "unable to map I128 registers\n");
276 return;
277 }
278
279 reg = prom_getpropint(node, "p9100_reg_physaddr", -1);
280 if (sbus_bus_map(sc->sc_bustag,
281 sa->sa_reg[0].oa_space, sa->sa_reg[0].oa_base + reg,
282 0x8000, 0, &sc->sc_p9100_regh) != 0) {
283
284 aprint_error_dev(dev, "unable to map P9100 registers\n");
285 return;
286 }
287
288 reg = prom_getpropint(node, "glint_fb0_physaddr", -1);
289 sc->sc_glint_fb = sbus_bus_addr(sc->sc_bustag,
290 sa->sa_reg[0].oa_space, sa->sa_reg[0].oa_base + reg);
291 sc->sc_glint_fbsz = prom_getpropint(node, "glint_lb_size", -1);
292 reg = prom_getpropint(node, "glint_reg_physaddr", -1);
293 sc->sc_glint_regs = sbus_bus_addr(sc->sc_bustag,
294 sa->sa_reg[0].oa_space, sa->sa_reg[0].oa_base + reg);
295
296 #if 0
297 bus_intr_establish(sc->sc_bustag, sa->sa_pri, IPL_BIO,
298 agten_intr, sc);
299 #endif
300
301 printf(": %dx%d\n", sc->sc_width, sc->sc_height);
302 agten_init(sc);
303
304 console = fb_is_console(node);
305
306 vcons_init(&sc->vd, sc, &sc->sc_defaultscreen_descr,
307 &agten_accessops);
308 sc->vd.init_screen = agten_init_screen;
309
310 ri = &sc->sc_console_screen.scr_ri;
311
312 sc->sc_gc.gc_bitblt = agten_bitblt;
313 sc->sc_gc.gc_rectfill = agten_rectfill;
314 sc->sc_gc.gc_blitcookie = sc;
315 sc->sc_gc.gc_rop = CR_COPY;
316
317 #if defined(AGTEN_DEBUG)
318 sc->sc_height -= 200;
319 #endif
320
321 if (console) {
322 vcons_init_screen(&sc->vd, &sc->sc_console_screen, 1,
323 &defattr);
324 sc->sc_console_screen.scr_flags |= VCONS_SCREEN_IS_STATIC;
325
326 sc->sc_defaultscreen_descr.textops = &ri->ri_ops;
327 sc->sc_defaultscreen_descr.capabilities = ri->ri_caps;
328 sc->sc_defaultscreen_descr.nrows = ri->ri_rows;
329 sc->sc_defaultscreen_descr.ncols = ri->ri_cols;
330 glyphcache_init(&sc->sc_gc,
331 sc->sc_height + 5,
332 (0x400000 / sc->sc_stride) - sc->sc_height - 5,
333 sc->sc_width,
334 ri->ri_font->fontwidth,
335 ri->ri_font->fontheight,
336 defattr);
337
338 wsdisplay_cnattach(&sc->sc_defaultscreen_descr, ri, 0, 0,
339 defattr);
340 i128_rectfill(sc->sc_bustag, sc->sc_i128_regh, 0, 0,
341 sc->sc_width, sc->sc_height,
342 ri->ri_devcmap[(defattr >> 16) & 0xff]);
343 vcons_replay_msgbuf(&sc->sc_console_screen);
344 } else {
345 /*
346 * since we're not the console we can postpone the rest
347 * until someone actually allocates a screen for us
348 */
349 if (sc->sc_console_screen.scr_ri.ri_rows == 0) {
350 /* do some minimal setup to avoid weirdnesses later */
351 vcons_init_screen(&sc->vd, &sc->sc_console_screen, 1,
352 &defattr);
353 }
354 glyphcache_init(&sc->sc_gc,
355 sc->sc_height + 5,
356 (0x400000 / sc->sc_stride) - sc->sc_height - 5,
357 sc->sc_width,
358 ri->ri_font->fontwidth,
359 ri->ri_font->fontheight,
360 defattr);
361 }
362
363 /* Initialize the default color map. */
364 agten_init_cmap(sc, ri);
365
366 aa.console = console;
367 aa.scrdata = &sc->sc_screenlist;
368 aa.accessops = &agten_accessops;
369 aa.accesscookie = &sc->vd;
370
371 config_found(sc->sc_dev, &aa, wsemuldisplaydevprint);
372
373 fb->fb_driver = &agtenfbdriver;
374 fb->fb_device = sc->sc_dev;
375 fb->fb_flags = device_cfdata(sc->sc_dev)->cf_flags & FB_USERMASK;
376 fb->fb_type.fb_type = FBTYPE_AG10E;
377 fb->fb_type.fb_cmsize = 256; /* doesn't matter, we're always 24bit */
378 fb->fb_type.fb_size = sc->sc_glint_fbsz;
379 fb->fb_type.fb_width = sc->sc_width;
380 fb->fb_type.fb_height = sc->sc_height;
381 fb->fb_type.fb_depth = 32;
382 fb->fb_linebytes = sc->sc_stride << 2;
383 fb_attach(fb, console);
384 agten_set_video(sc, 1); /* make sure video's on */
385 }
386
387 static int
388 agten_ioctl(void *v, void *vs, u_long cmd, void *data, int flag,
389 struct lwp *l)
390 {
391 struct vcons_data *vd = v;
392 struct agten_softc *sc = vd->cookie;
393 struct wsdisplay_fbinfo *wdf;
394 struct vcons_screen *ms = vd->active;
395
396 switch (cmd) {
397
398 case WSDISPLAYIO_GTYPE:
399 *(u_int *)data = WSDISPLAY_TYPE_AG10;
400 return 0;
401
402 case WSDISPLAYIO_GINFO:
403 if (ms == NULL)
404 return ENODEV;
405 wdf = (void *)data;
406 wdf->height = ms->scr_ri.ri_height;
407 wdf->width = ms->scr_ri.ri_width;
408 wdf->depth = 32;
409 wdf->cmsize = 256;
410 return 0;
411
412 case WSDISPLAYIO_GVIDEO:
413 *(int *)data = sc->sc_video;
414 return 0;
415
416 case WSDISPLAYIO_SVIDEO:
417 agten_set_video(sc, *(int *)data);
418 return 0;
419
420 case WSDISPLAYIO_GETCMAP:
421 return agten_getcmap(sc,
422 (struct wsdisplay_cmap *)data);
423
424 case WSDISPLAYIO_PUTCMAP:
425 return agten_putcmap(sc,
426 (struct wsdisplay_cmap *)data);
427
428 case WSDISPLAYIO_LINEBYTES:
429 *(u_int *)data = sc->sc_stride << 2;
430 return 0;
431
432 case WSDISPLAYIO_SMODE:
433 {
434 int new_mode = *(int*)data;
435 if (new_mode != sc->sc_mode) {
436 sc->sc_mode = new_mode;
437 if(new_mode == WSDISPLAYIO_MODE_EMUL) {
438 agten_init(sc);
439 agten_init_cmap(sc,
440 &ms->scr_ri);
441 vcons_redraw_screen(ms);
442 } else {
443 agten_gfx(sc);
444 }
445 }
446 }
447 return 0;
448
449 case WSDISPLAYIO_GCURPOS:
450 {
451 struct wsdisplay_curpos *cp = (void *)data;
452
453 cp->x = sc->sc_cursor_x;
454 cp->y = sc->sc_cursor_y;
455 }
456 return 0;
457
458 case WSDISPLAYIO_SCURPOS:
459 {
460 struct wsdisplay_curpos *cp = (void *)data;
461
462 agten_move_cursor(sc, cp->x, cp->y);
463 }
464 return 0;
465
466 case WSDISPLAYIO_GCURMAX:
467 {
468 struct wsdisplay_curpos *cp = (void *)data;
469
470 cp->x = 64;
471 cp->y = 64;
472 }
473 return 0;
474
475 case WSDISPLAYIO_SCURSOR:
476 {
477 struct wsdisplay_cursor *cursor = (void *)data;
478
479 return agten_do_cursor(sc, cursor);
480 }
481 }
482 return EPASSTHROUGH;
483 }
484
485 static paddr_t
486 agten_mmap(void *v, void *vs, off_t offset, int prot)
487 {
488 struct vcons_data *vd = v;
489 struct agten_softc *sc = vd->cookie;
490
491 if (offset < sc->sc_glint_fbsz)
492 return bus_space_mmap(sc->sc_bustag, sc->sc_glint_fb, offset,
493 prot, BUS_SPACE_MAP_LINEAR);
494 return -1;
495 }
496
497 static void
498 agten_init_screen(void *cookie, struct vcons_screen *scr,
499 int existing, long *defattr)
500 {
501 struct agten_softc *sc = cookie;
502 struct rasops_info *ri = &scr->scr_ri;
503
504 ri->ri_depth = sc->sc_depth;
505 ri->ri_width = sc->sc_width;
506 ri->ri_height = sc->sc_height;
507 ri->ri_stride = sc->sc_stride;
508 ri->ri_flg = RI_CENTER | RI_FULLCLEAR | RI_8BIT_IS_RGB | RI_ENABLE_ALPHA;
509
510 ri->ri_bits = (char *)sc->sc_fb.fb_pixels;
511
512 if (existing) {
513 ri->ri_flg |= RI_CLEAR;
514 }
515
516 rasops_init(ri, 0, 0);
517 sc->sc_putchar = ri->ri_ops.putchar;
518
519 ri->ri_caps = WSSCREEN_WSCOLORS;
520
521 rasops_reconfig(ri, sc->sc_height / ri->ri_font->fontheight,
522 sc->sc_width / ri->ri_font->fontwidth);
523
524 ri->ri_hw = scr;
525 ri->ri_ops.putchar = agten_putchar;
526 ri->ri_ops.cursor = agten_cursor;
527 ri->ri_ops.copyrows = agten_copyrows;
528 ri->ri_ops.eraserows = agten_eraserows;
529 ri->ri_ops.copycols = agten_copycols;
530 ri->ri_ops.erasecols = agten_erasecols;
531
532 }
533
534 static int
535 agten_putcmap(struct agten_softc *sc, struct wsdisplay_cmap *cm)
536 {
537 u_int index = cm->index;
538 u_int count = cm->count;
539 int i, error;
540 u_char rbuf[256], gbuf[256], bbuf[256];
541 u_char *r, *g, *b;
542
543 if (cm->index >= 256 || cm->count > 256 ||
544 (cm->index + cm->count) > 256)
545 return EINVAL;
546 error = copyin(cm->red, &rbuf[index], count);
547 if (error)
548 return error;
549 error = copyin(cm->green, &gbuf[index], count);
550 if (error)
551 return error;
552 error = copyin(cm->blue, &bbuf[index], count);
553 if (error)
554 return error;
555
556 r = &rbuf[index];
557 g = &gbuf[index];
558 b = &bbuf[index];
559
560 for (i = 0; i < count; i++) {
561 agten_putpalreg(sc, index, *r, *g, *b);
562 index++;
563 r++, g++, b++;
564 }
565 return 0;
566 }
567
568 static int
569 agten_getcmap(struct agten_softc *sc, struct wsdisplay_cmap *cm)
570 {
571 u_int index = cm->index;
572 u_int count = cm->count;
573 int error, i;
574 uint8_t red[256], green[256], blue[256];
575
576 if (index >= 255 || count > 256 || index + count > 256)
577 return EINVAL;
578
579 i = index;
580 while (i < (index + count)) {
581 red[i] = sc->sc_cmap.cm_map[i][0];
582 green[i] = sc->sc_cmap.cm_map[i][1];
583 blue[i] = sc->sc_cmap.cm_map[i][2];
584 i++;
585 }
586 error = copyout(&red[index], cm->red, count);
587 if (error)
588 return error;
589 error = copyout(&green[index], cm->green, count);
590 if (error)
591 return error;
592 error = copyout(&blue[index], cm->blue, count);
593 if (error)
594 return error;
595
596 return 0;
597 }
598
599 static int
600 agten_putpalreg(struct agten_softc *sc, uint8_t idx, uint8_t r, uint8_t g,
601 uint8_t b)
602 {
603
604 sc->sc_cmap.cm_map[idx][0] = r;
605 sc->sc_cmap.cm_map[idx][1] = g;
606 sc->sc_cmap.cm_map[idx][2] = b;
607 agten_write_idx(sc, IBM561_CMAP_TABLE + idx);
608 agten_write_dac(sc, IBM561_CMD_CMAP, r);
609 agten_write_dac(sc, IBM561_CMD_CMAP, g);
610 agten_write_dac(sc, IBM561_CMD_CMAP, b);
611 return 0;
612 }
613
614 static void
615 agten_init(struct agten_softc *sc)
616 {
617 int i;
618 uint32_t src, srcw;
619 volatile uint32_t junk;
620
621 /* then we set up a linear LUT for 24bit colour */
622 agten_write_idx(sc, IBM561_CMAP_TABLE + 256);
623 for (i = 0; i < 256; i++) {
624 agten_write_dac(sc, IBM561_CMD_CMAP, i);
625 agten_write_dac(sc, IBM561_CMD_CMAP, i);
626 agten_write_dac(sc, IBM561_CMD_CMAP, i);
627 }
628
629 /* and the linear gamma maps */
630 agten_write_idx(sc, IBM561_RED_GAMMA_TABLE);
631 for (i = 0; i < 0x3ff; i+= 4)
632 agten_write_dac_10(sc, IBM561_CMD_GAMMA, i);
633 agten_write_idx(sc, IBM561_GREEN_GAMMA_TABLE);
634 for (i = 0; i < 0x3ff; i+= 4)
635 agten_write_dac_10(sc, IBM561_CMD_GAMMA, i);
636 agten_write_idx(sc, IBM561_BLUE_GAMMA_TABLE);
637 for (i = 0; i < 0x3ff; i+= 4)
638 agten_write_dac_10(sc, IBM561_CMD_GAMMA, i);
639
640 /* enable outputs, RGB mode */
641 agten_write_idx(sc, IBM561_CONFIG_REG3);
642 agten_write_dac(sc, IBM561_CMD, CR3_SERIAL_CLK_CTRL | CR3_RGB);
643
644 /* MUX 4:1 basic, 8bit overlay, 8bit WIDs */
645 agten_write_idx(sc, IBM561_CONFIG_REG1);
646 agten_write_dac(sc, IBM561_CMD, CR1_MODE_4_1_BASIC | CR1_OVL_8BPP |
647 CR1_WID_8);
648
649 /* use external clock, enable video output */
650 agten_write_idx(sc, IBM561_CONFIG_REG2);
651 agten_write_dac(sc, IBM561_CMD, CR2_ENABLE_CLC | CR2_PLL_REF_SELECT |
652 CR2_PIXEL_CLOCK_SELECT | CR2_ENABLE_RGB_OUTPUT);
653
654 /* now set up some window attributes */
655
656 /*
657 * direct colour, 24 bit, transparency off, LUT from 0x100
658 * we need to use direct colour and a linear LUT because for some
659 * reason true color mode gives messed up colours
660 */
661 agten_write_idx(sc, IBM561_FB_WINTYPE);
662 agten_write_dac_10(sc, IBM561_CMD_FB_WAT, 0x100 | FB_PIXEL_24BIT |
663 FB_MODE_DIRECT);
664
665 /* use gamma LUTs, no crosshair, 0 is transparent */
666 agten_write_idx(sc, IBM561_AUXFB_WINTYPE);
667 agten_write_dac(sc, IBM561_CMD_FB_WAT, 0x0);
668
669 /* overlay is 8 bit, opaque */
670 agten_write_idx(sc, IBM561_OL_WINTYPE);
671 agten_write_dac_10(sc, IBM561_CMD_FB_WAT, 0x00);
672
673 /* now we fill the WID fb with zeroes */
674 src = 0;
675 srcw = sc->sc_width << 16 | sc->sc_height;
676 bus_space_write_4(sc->sc_bustag, sc->sc_p9100_regh, FOREGROUND_COLOR,
677 0x0);
678 bus_space_write_4(sc->sc_bustag, sc->sc_p9100_regh, BACKGROUND_COLOR,
679 0x0);
680 bus_space_write_4(sc->sc_bustag, sc->sc_p9100_regh, RASTER_OP, ROP_PAT);
681 bus_space_write_4(sc->sc_bustag, sc->sc_p9100_regh, COORD_INDEX, 0);
682 bus_space_write_4(sc->sc_bustag, sc->sc_p9100_regh, RECT_RTW_XY, src);
683 bus_space_write_4(sc->sc_bustag, sc->sc_p9100_regh, RECT_RTW_XY, srcw);
684 junk = bus_space_read_4(sc->sc_bustag, sc->sc_p9100_regh, COMMAND_QUAD);
685
686 /* initialize the cursor registers */
687
688 /* initialize the Imagine 128 */
689 i128_init(sc->sc_bustag, sc->sc_i128_regh, sc->sc_stride, 8);
690 }
691
692 static void
693 agten_init_cmap(struct agten_softc *sc, struct rasops_info *ri)
694 {
695 int i, j;
696 uint8_t cmap[768];
697
698 rasops_get_cmap(ri, cmap, 768);
699 j = 0;
700 for (i = 0; i < 256; i++) {
701
702 agten_putpalreg(sc, i, cmap[j], cmap[j + 1], cmap[j + 2]);
703 j += 3;
704 }
705 }
706
707 static void
708 agten_gfx(struct agten_softc *sc)
709 {
710 /* enable overlay transparency on colour 0x00 */
711 agten_write_idx(sc, IBM561_OL_WINTYPE);
712 agten_write_dac_10(sc, IBM561_CMD_FB_WAT, OL_MODE_TRANSP_ENABLE);
713
714 /* then blit the overlay full of 0x00 */
715 i128_rectfill(sc->sc_bustag, sc->sc_i128_regh, 0, 0, sc->sc_width,
716 sc->sc_height, 0);
717
718 /* ... so we can see the 24bit framebuffer */
719 }
720
721 static void
722 agten_set_video(struct agten_softc *sc, int flag)
723 {
724 uint8_t reg =
725 CR2_ENABLE_CLC | CR2_PLL_REF_SELECT | CR2_PIXEL_CLOCK_SELECT;
726
727 if (flag == sc->sc_video)
728 return;
729
730 agten_write_idx(sc, IBM561_CONFIG_REG2);
731 agten_write_dac(sc, IBM561_CMD, flag ? reg | CR2_ENABLE_RGB_OUTPUT :
732 reg);
733
734 sc->sc_video = flag;
735 }
736
737 static int
738 agten_get_video(struct agten_softc *sc)
739 {
740
741 return sc->sc_video;
742 }
743
744 static void
745 agten_bitblt(void *cookie, int xs, int ys, int xd, int yd, int wi, int he,
746 int rop)
747 {
748 struct agten_softc *sc = cookie;
749
750 i128_bitblt(sc->sc_bustag, sc->sc_i128_regh,
751 xs, ys, xd, yd, wi, he, rop);
752 }
753
754 static void
755 agten_rectfill(void *cookie, int x, int y, int wi, int he, long fg)
756 {
757 struct agten_softc *sc = cookie;
758 struct vcons_screen *scr = sc->vd.active;
759 uint32_t col;
760
761 if (scr == NULL)
762 return;
763 col = scr->scr_ri.ri_devcmap[fg];
764 i128_rectfill(sc->sc_bustag, sc->sc_i128_regh, x, y, wi, he, col);
765 }
766
767 static void
768 agten_putchar(void *cookie, int row, int col, u_int c, long attr)
769 {
770 struct rasops_info *ri = cookie;
771 struct wsdisplay_font *font = PICK_FONT(ri, c);
772 struct vcons_screen *scr = ri->ri_hw;
773 struct agten_softc *sc = scr->scr_cookie;
774 uint32_t fg, bg;
775 int x, y, wi, he, rv;
776
777 wi = font->fontwidth;
778 he = font->fontheight;
779
780 bg = ri->ri_devcmap[(attr >> 16) & 0xf];
781 fg = ri->ri_devcmap[(attr >> 24) & 0xf];
782
783 x = ri->ri_xorigin + col * wi;
784 y = ri->ri_yorigin + row * he;
785
786 if (c == 0x20) {
787 i128_rectfill(sc->sc_bustag, sc->sc_i128_regh, x, y, wi, he,
788 bg);
789 if (attr & 1)
790 i128_rectfill(sc->sc_bustag, sc->sc_i128_regh, x,
791 y + he - 2, wi, 1, fg);
792 return;
793 }
794 rv = glyphcache_try(&sc->sc_gc, c, x, y, attr);
795 if (rv == GC_OK)
796 return;
797 i128_sync(sc->sc_bustag, sc->sc_i128_regh);
798 sc->sc_putchar(cookie, row, col, c, attr & ~1);
799
800 if (rv == GC_ADD) {
801 glyphcache_add(&sc->sc_gc, c, x, y);
802 } else {
803 if (attr & 1)
804 i128_rectfill(sc->sc_bustag, sc->sc_i128_regh, x,
805 y + he - 2, wi, 1, fg);
806 }
807 }
808
809 static void
810 agten_cursor(void *cookie, int on, int row, int col)
811 {
812 struct rasops_info *ri = cookie;
813 struct vcons_screen *scr = ri->ri_hw;
814 struct agten_softc *sc = scr->scr_cookie;
815 int x, y, wi,he;
816
817 wi = ri->ri_font->fontwidth;
818 he = ri->ri_font->fontheight;
819
820 if (ri->ri_flg & RI_CURSOR) {
821 x = ri->ri_ccol * wi + ri->ri_xorigin;
822 y = ri->ri_crow * he + ri->ri_yorigin;
823 i128_bitblt(sc->sc_bustag, sc->sc_i128_regh, x, y, x, y, wi, he,
824 CR_COPY_INV);
825 ri->ri_flg &= ~RI_CURSOR;
826 }
827
828 ri->ri_crow = row;
829 ri->ri_ccol = col;
830
831 if (on)
832 {
833 x = ri->ri_ccol * wi + ri->ri_xorigin;
834 y = ri->ri_crow * he + ri->ri_yorigin;
835 i128_bitblt(sc->sc_bustag, sc->sc_i128_regh, x, y, x, y, wi, he,
836 CR_COPY_INV);
837 ri->ri_flg |= RI_CURSOR;
838 }
839 }
840
841 static void
842 agten_copycols(void *cookie, int row, int srccol, int dstcol, int ncols)
843 {
844 struct rasops_info *ri = cookie;
845 struct vcons_screen *scr = ri->ri_hw;
846 struct agten_softc *sc = scr->scr_cookie;
847 int32_t xs, xd, y, width, height;
848
849 xs = ri->ri_xorigin + ri->ri_font->fontwidth * srccol;
850 xd = ri->ri_xorigin + ri->ri_font->fontwidth * dstcol;
851 y = ri->ri_yorigin + ri->ri_font->fontheight * row;
852 width = ri->ri_font->fontwidth * ncols;
853 height = ri->ri_font->fontheight;
854 i128_bitblt(sc->sc_bustag, sc->sc_i128_regh, xs, y, xd, y, width,
855 height, CR_COPY);
856 }
857
858 static void
859 agten_erasecols(void *cookie, int row, int startcol, int ncols, long fillattr)
860 {
861 struct rasops_info *ri = cookie;
862 struct vcons_screen *scr = ri->ri_hw;
863 struct agten_softc *sc = scr->scr_cookie;
864 int32_t x, y, width, height, bg;
865
866 x = ri->ri_xorigin + ri->ri_font->fontwidth * startcol;
867 y = ri->ri_yorigin + ri->ri_font->fontheight * row;
868 width = ri->ri_font->fontwidth * ncols;
869 height = ri->ri_font->fontheight;
870 bg = (uint32_t)ri->ri_devcmap[(fillattr >> 16) & 0xff];
871 i128_rectfill(sc->sc_bustag, sc->sc_i128_regh, x, y, width, height, bg);
872 }
873
874 static void
875 agten_copyrows(void *cookie, int srcrow, int dstrow, int nrows)
876 {
877 struct rasops_info *ri = cookie;
878 struct vcons_screen *scr = ri->ri_hw;
879 struct agten_softc *sc = scr->scr_cookie;
880 int32_t x, ys, yd, width, height;
881
882 x = ri->ri_xorigin;
883 ys = ri->ri_yorigin + ri->ri_font->fontheight * srcrow;
884 yd = ri->ri_yorigin + ri->ri_font->fontheight * dstrow;
885 width = ri->ri_emuwidth;
886 height = ri->ri_font->fontheight * nrows;
887 i128_bitblt(sc->sc_bustag, sc->sc_i128_regh, x, ys, x, yd, width,
888 height, CR_COPY);
889 }
890
891 static void
892 agten_eraserows(void *cookie, int row, int nrows, long fillattr)
893 {
894 struct rasops_info *ri = cookie;
895 struct vcons_screen *scr = ri->ri_hw;
896 struct agten_softc *sc = scr->scr_cookie;
897 int32_t x, y, width, height, bg;
898
899 if ((row == 0) && (nrows == ri->ri_rows)) {
900 x = y = 0;
901 width = ri->ri_width;
902 height = ri->ri_height;
903 } else {
904 x = ri->ri_xorigin;
905 y = ri->ri_yorigin + ri->ri_font->fontheight * row;
906 width = ri->ri_emuwidth;
907 height = ri->ri_font->fontheight * nrows;
908 }
909 bg = (uint32_t)ri->ri_devcmap[(fillattr >> 16) & 0xff];
910 i128_rectfill(sc->sc_bustag, sc->sc_i128_regh, x, y, width, height, bg);
911 }
912
913 static void
914 agten_move_cursor(struct agten_softc *sc, int x, int y)
915 {
916
917 sc->sc_cursor_x = x;
918 sc->sc_cursor_y = y;
919 agten_write_idx(sc, IBM561_CURSOR_X_REG);
920 agten_write_dac(sc, IBM561_CMD, x & 0xff);
921 agten_write_dac(sc, IBM561_CMD, (x >> 8) & 0xff);
922 agten_write_dac(sc, IBM561_CMD, y & 0xff);
923 agten_write_dac(sc, IBM561_CMD, (y >> 8) & 0xff);
924 }
925
926 static int
927 agten_do_cursor(struct agten_softc *sc, struct wsdisplay_cursor *cur)
928 {
929 if (cur->which & WSDISPLAY_CURSOR_DOCUR) {
930
931 agten_write_idx(sc, IBM561_CURS_CNTL_REG);
932 agten_write_dac(sc, IBM561_CMD, cur->enable ?
933 CURS_ENABLE : 0);
934 }
935 if (cur->which & WSDISPLAY_CURSOR_DOHOT) {
936
937 agten_write_idx(sc, IBM561_HOTSPOT_X_REG);
938 agten_write_dac(sc, IBM561_CMD, cur->hot.x);
939 agten_write_dac(sc, IBM561_CMD, cur->hot.y);
940 }
941 if (cur->which & WSDISPLAY_CURSOR_DOPOS) {
942
943 agten_move_cursor(sc, cur->pos.x, cur->pos.y);
944 }
945 if (cur->which & WSDISPLAY_CURSOR_DOCMAP) {
946 int i;
947
948 agten_write_idx(sc, IBM561_CURSOR_LUT + cur->cmap.index + 2);
949 for (i = 0; i < cur->cmap.count; i++) {
950 agten_write_dac(sc, IBM561_CMD_CMAP, cur->cmap.red[i]);
951 agten_write_dac(sc, IBM561_CMD_CMAP,
952 cur->cmap.green[i]);
953 agten_write_dac(sc, IBM561_CMD_CMAP, cur->cmap.blue[i]);
954 }
955 }
956 if (cur->which & WSDISPLAY_CURSOR_DOSHAPE) {
957 int i;
958 uint16_t tmp;
959
960 agten_write_idx(sc, IBM561_CURSOR_BITMAP);
961 for (i = 0; i < 512; i++) {
962 tmp = util_interleave(cur->mask[i], cur->image[i]);
963 agten_write_dac(sc, IBM561_CMD, (tmp >> 8) & 0xff);
964 agten_write_dac(sc, IBM561_CMD, tmp & 0xff);
965 }
966 }
967 return 0;
968 }
969
970 static int
971 agten_do_sun_cursor(struct agten_softc *sc, struct fbcursor *cur)
972 {
973 if (cur->set & FB_CUR_SETCUR) {
974
975 agten_write_idx(sc, IBM561_CURS_CNTL_REG);
976 agten_write_dac(sc, IBM561_CMD, cur->enable ?
977 CURS_ENABLE : 0);
978 }
979 if (cur->set & FB_CUR_SETHOT) {
980
981 agten_write_idx(sc, IBM561_HOTSPOT_X_REG);
982 agten_write_dac(sc, IBM561_CMD, cur->hot.x);
983 agten_write_dac(sc, IBM561_CMD, cur->hot.y);
984 }
985 if (cur->set & FB_CUR_SETPOS) {
986
987 agten_move_cursor(sc, cur->pos.x, cur->pos.y);
988 }
989 if (cur->set & FB_CUR_SETCMAP) {
990 int i;
991
992 agten_write_idx(sc, IBM561_CURSOR_LUT + cur->cmap.index + 2);
993 for (i = 0; i < cur->cmap.count; i++) {
994 agten_write_dac(sc, IBM561_CMD_CMAP, cur->cmap.red[i]);
995 agten_write_dac(sc, IBM561_CMD_CMAP,
996 cur->cmap.green[i]);
997 agten_write_dac(sc, IBM561_CMD_CMAP, cur->cmap.blue[i]);
998 }
999 }
1000 if (cur->set & FB_CUR_SETSHAPE) {
1001 int i;
1002 uint16_t tmp;
1003
1004 agten_write_idx(sc, IBM561_CURSOR_BITMAP);
1005 for (i = 0; i < 512; i++) {
1006 tmp = util_interleave_lin(cur->mask[i], cur->image[i]);
1007 agten_write_dac(sc, IBM561_CMD, (tmp >> 8) & 0xff);
1008 agten_write_dac(sc, IBM561_CMD, tmp & 0xff);
1009 }
1010 }
1011 return 0;
1012 }
1013
1014 uint16_t
1015 util_interleave(uint8_t b1, uint8_t b2)
1016 {
1017 int i;
1018 uint16_t ret = 0;
1019 uint16_t mask = 0x8000;
1020 uint8_t mask8 = 0x01;
1021
1022 for (i = 0; i < 8; i++) {
1023 if (b1 & mask8)
1024 ret |= mask;
1025 mask = mask >> 1;
1026 if (b2 & mask8)
1027 ret |= mask;
1028 mask = mask >> 1;
1029 mask8 = mask8 << 1;
1030 }
1031 return ret;
1032 }
1033
1034 uint16_t
1035 util_interleave_lin(uint8_t b1, uint8_t b2)
1036 {
1037 int i;
1038 uint16_t ret = 0;
1039 uint16_t mask = 0x8000;
1040 uint8_t mask8 = 0x80;
1041
1042 for (i = 0; i < 8; i++) {
1043 if (b1 & mask8)
1044 ret |= mask;
1045 mask = mask >> 1;
1046 if (b2 & mask8)
1047 ret |= mask;
1048 mask = mask >> 1;
1049 mask8 = mask8 >> 1;
1050 }
1051 return ret;
1052 }
1053
1054 /* and now the /dev/fb* stuff */
1055 static void
1056 agten_fb_unblank(device_t dev)
1057 {
1058 struct agten_softc *sc = device_private(dev);
1059
1060 agten_init(sc);
1061 agten_set_video(sc, 1);
1062 }
1063
1064 static int
1065 agten_fb_open(dev_t dev, int flags, int mode, struct lwp *l)
1066 {
1067 struct agten_softc *sc;
1068
1069 sc = device_lookup_private(&agten_cd, minor(dev));
1070 if (sc == NULL)
1071 return (ENXIO);
1072 if (sc->sc_fb_is_open)
1073 return 0;
1074
1075 sc->sc_fb_is_open++;
1076 agten_gfx(sc);
1077
1078 return (0);
1079 }
1080
1081 static int
1082 agten_fb_close(dev_t dev, int flags, int mode, struct lwp *l)
1083 {
1084 struct agten_softc *sc;
1085
1086 sc = device_lookup_private(&agten_cd, minor(dev));
1087
1088 sc->sc_fb_is_open--;
1089 if (sc->sc_fb_is_open < 0)
1090 sc->sc_fb_is_open = 0;
1091
1092 if (sc->sc_fb_is_open == 0) {
1093 agten_init(sc);
1094 vcons_redraw_screen(sc->vd.active);
1095 }
1096
1097 return (0);
1098 }
1099
1100 static int
1101 agten_fb_ioctl(dev_t dev, u_long cmd, void *data, int flags, struct lwp *l)
1102 {
1103 struct agten_softc *sc = device_lookup_private(&agten_cd, minor(dev));
1104 struct fbgattr *fba;
1105 int error;
1106
1107 switch (cmd) {
1108
1109 case FBIOGTYPE:
1110 *(struct fbtype *)data = sc->sc_fb.fb_type;
1111 break;
1112
1113 case FBIOGATTR:
1114 fba = (struct fbgattr *)data;
1115 fba->real_type = sc->sc_fb.fb_type.fb_type;
1116 fba->owner = 0; /* XXX ??? */
1117 fba->fbtype = sc->sc_fb.fb_type;
1118 fba->sattr.flags = 0;
1119 fba->sattr.emu_type = sc->sc_fb.fb_type.fb_type;
1120 fba->sattr.dev_specific[0] = -1;
1121 fba->emu_types[0] = sc->sc_fb.fb_type.fb_type;
1122 fba->emu_types[1] = -1;
1123 break;
1124
1125 case FBIOGETCMAP:
1126 #define p ((struct fbcmap *)data)
1127 return (bt_getcmap(p, &sc->sc_cmap, 256, 1));
1128
1129 case FBIOPUTCMAP:
1130 /* copy to software map */
1131 error = bt_putcmap(p, &sc->sc_cmap, 256, 1);
1132 if (error)
1133 return (error);
1134 /* now blast them into the chip */
1135 /* don't bother - we're 24bit */
1136 #undef p
1137 break;
1138
1139 case FBIOGVIDEO:
1140 *(int *)data = agten_get_video(sc);
1141 break;
1142
1143 case FBIOSVIDEO:
1144 agten_set_video(sc, *(int *)data);
1145 break;
1146
1147 /* these are for both FBIOSCURSOR and FBIOGCURSOR */
1148 #define p ((struct fbcursor *)data)
1149 #define pc (&sc->sc_cursor)
1150
1151 case FBIOGCURSOR:
1152 /* does anyone use this ioctl?! */
1153 p->set = FB_CUR_SETALL; /* close enough, anyway */
1154 p->enable = 1;
1155 p->pos.x = sc->sc_cursor_x;
1156 p->pos.y = sc->sc_cursor_y;
1157 p->size.x = 64;
1158 p->size.y = 64;
1159 break;
1160
1161 case FBIOSCURSOR:
1162 agten_do_sun_cursor(sc, p);
1163 break;
1164
1165 #undef p
1166 #undef cc
1167
1168 case FBIOGCURPOS:
1169 {
1170 struct fbcurpos *cp = (struct fbcurpos *)data;
1171 cp->x = sc->sc_cursor_x;
1172 cp->y = sc->sc_cursor_y;
1173 }
1174 break;
1175
1176 case FBIOSCURPOS:
1177 {
1178 struct fbcurpos *cp = (struct fbcurpos *)data;
1179 agten_move_cursor(sc, cp->x, cp->y);
1180 }
1181 break;
1182
1183 case FBIOGCURMAX:
1184 /* max cursor size is 64x64 */
1185 ((struct fbcurpos *)data)->x = 64;
1186 ((struct fbcurpos *)data)->y = 64;
1187 break;
1188
1189 default:
1190 return (ENOTTY);
1191 }
1192 return (0);
1193 }
1194
1195 static paddr_t
1196 agten_fb_mmap(dev_t dev, off_t off, int prot)
1197 {
1198 struct agten_softc *sc = device_lookup_private(&agten_cd, minor(dev));
1199
1200 /*
1201 * mappings are subject to change
1202 * for now we put the framebuffer at offset 0 and the GLint registers
1203 * right after that. We may want to expose more register ranges and
1204 * probably will want to map the 2nd framebuffer as well
1205 */
1206
1207 if (off < 0)
1208 return EINVAL;
1209
1210 if (off >= sc->sc_glint_fbsz + 0x10000)
1211 return EINVAL;
1212
1213 if (off < sc->sc_glint_fbsz) {
1214 return (bus_space_mmap(sc->sc_bustag,
1215 sc->sc_glint_fb,
1216 off,
1217 prot,
1218 BUS_SPACE_MAP_LINEAR));
1219 }
1220
1221 off -= sc->sc_glint_fbsz;
1222 if (off < 0x10000) {
1223 return (bus_space_mmap(sc->sc_bustag,
1224 sc->sc_glint_regs,
1225 off,
1226 prot,
1227 BUS_SPACE_MAP_LINEAR));
1228 }
1229 return EINVAL;
1230 }
1231