agten.c revision 1.4 1 /* $NetBSD: agten.c,v 1.4 2007/08/28 00:21:43 macallan 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 * 3. Neither the name of The NetBSD Foundation nor the names of its
16 * contributors may be used to endorse or promote products derived
17 * from this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 */
31
32 #include <sys/cdefs.h>
33 __KERNEL_RCSID(0, "$NetBSD: agten.c,v 1.4 2007/08/28 00:21:43 macallan Exp $");
34
35 /*
36 * a driver for the Fujitsu AG-10e SBus framebuffer
37 *
38 * this thing is Frankenstein's Monster among graphics boards.
39 * it contains three graphics chips:
40 * a GLint - 24bit stuff, double-buffered
41 * an Imagine 128 which provides an 8bit overlay
42 * a Weitek P9100 which provides WIDs
43 * so here we need to mess only with the P9100 and the I128 - for X we just
44 * hide the overlay and let the Xserver mess with the GLint
45 */
46
47 #include <sys/param.h>
48 #include <sys/systm.h>
49 #include <sys/kernel.h>
50 #include <sys/device.h>
51 #include <sys/proc.h>
52 #include <sys/mutex.h>
53 #include <sys/ioctl.h>
54 #include <sys/kernel.h>
55 #include <sys/systm.h>
56 #include <sys/malloc.h>
57
58 #include <dev/sun/fbio.h>
59 #include <dev/sun/fbvar.h>
60 #include <dev/sun/btreg.h>
61 #include <dev/sun/btvar.h>
62
63 #include <machine/bus.h>
64 #include <machine/autoconf.h>
65
66 #include <dev/sbus/sbusvar.h>
67
68 #include <dev/wscons/wsconsio.h>
69 #include <dev/wscons/wsdisplayvar.h>
70 #include <dev/rasops/rasops.h>
71 #include <dev/wsfont/wsfont.h>
72
73 #include <dev/wscons/wsdisplay_vconsvar.h>
74
75 #include <dev/sbus/p9100reg.h>
76 #include <dev/ic/ibm561reg.h>
77 #include <dev/ic/i128reg.h>
78 #include <dev/ic/i128var.h>
79
80 #include "opt_agten.h"
81
82 static int agten_match(struct device *, struct cfdata *, void *);
83 static void agten_attach(struct device *, struct device *, void *);
84
85 #if 0
86 static void agten_unblank(struct device *);
87 #endif
88
89 static int agten_ioctl(void *, void *, u_long, void *, int, struct lwp *);
90 static paddr_t agten_mmap(void *, void *, off_t, int);
91 static void agten_init_screen(void *, struct vcons_screen *, int, long *);
92
93 struct agten_softc {
94 struct device sc_dev; /* base device */
95 struct sbusdev sc_sd; /* sbus device */
96 struct fbdevice sc_fb; /* frame buffer device */
97
98 struct vcons_screen sc_console_screen;
99 struct wsscreen_descr sc_defaultscreen_descr;
100 const struct wsscreen_descr *sc_screens[1];
101 struct wsscreen_list sc_screenlist;
102
103 bus_space_tag_t sc_bustag;
104
105 bus_space_handle_t sc_i128_fbh;
106 bus_size_t sc_i128_fbsz;
107 bus_space_handle_t sc_i128_regh;
108 bus_space_handle_t sc_p9100_regh;
109 bus_addr_t sc_glint_fb;
110 bus_addr_t sc_glint_regs;
111 uint32_t sc_glint_fbsz;
112
113 uint32_t sc_width;
114 uint32_t sc_height; /* panel width / height */
115 uint32_t sc_stride;
116 uint32_t sc_depth;
117
118 int sc_cursor_x;
119 int sc_cursor_y;
120
121 union bt_cmap sc_cmap; /* Brooktree color map */
122
123 int sc_mode;
124 int sc_video, sc_powerstate;
125 uint32_t sc_bg;
126 struct vcons_data vd;
127 };
128
129 CFATTACH_DECL(agten, sizeof(struct agten_softc),
130 agten_match, agten_attach, NULL, NULL);
131
132
133 static int agten_putcmap(struct agten_softc *, struct wsdisplay_cmap *);
134 static int agten_getcmap(struct agten_softc *, struct wsdisplay_cmap *);
135 static int agten_putpalreg(struct agten_softc *, uint8_t, uint8_t,
136 uint8_t, uint8_t);
137 static void agten_init(struct agten_softc *);
138 static void agten_gfx(struct agten_softc *);
139
140 static void agten_copycols(void *, int, int, int, int);
141 static void agten_erasecols(void *, int, int, int, long);
142 static void agten_copyrows(void *, int, int, int);
143 static void agten_eraserows(void *, int, int, long);
144
145 static void agten_move_cursor(struct agten_softc *, int, int);
146 static int agten_do_cursor(struct agten_softc *sc,
147 struct wsdisplay_cursor *);
148
149 uint16_t util_interleave(uint8_t, uint8_t);
150
151 extern const u_char rasops_cmap[768];
152
153 struct wsdisplay_accessops agten_accessops = {
154 agten_ioctl,
155 agten_mmap,
156 NULL, /* alloc_screen */
157 NULL, /* free_screen */
158 NULL, /* show_screen */
159 NULL, /* load_font */
160 NULL, /* pollc */
161 NULL /* scroll */
162 };
163
164 static inline void
165 agten_write_dac(struct agten_softc *sc, int reg, uint8_t val)
166 {
167 bus_space_write_4(sc->sc_bustag, sc->sc_p9100_regh,
168 0x200 + (reg << 2), (uint32_t)val << 16);
169 }
170
171 static inline void
172 agten_write_idx(struct agten_softc *sc, int offset)
173 {
174 bus_space_write_4(sc->sc_bustag, sc->sc_p9100_regh,
175 0x200 + (IBM561_ADDR_LOW << 2), (offset & 0xff) << 16);
176 bus_space_write_4(sc->sc_bustag, sc->sc_p9100_regh,
177 0x200 + (IBM561_ADDR_HIGH << 2), ((offset >> 8) & 0xff) << 16);
178 }
179
180 static inline void
181 agten_write_dac_10(struct agten_softc *sc, int reg, uint16_t val)
182 {
183 agten_write_dac(sc, reg, (val >> 2) & 0xff);
184 agten_write_dac(sc, reg, (val & 0x3) << 6);
185 }
186
187 static int
188 agten_match(struct device *dev, struct cfdata *cf, void *aux)
189 {
190 struct sbus_attach_args *sa = aux;
191
192 if (strcmp("PFU,aga", sa->sa_name) == 0)
193 return 100;
194 return 0;
195 }
196
197 static void
198 agten_attach(struct device *parent, struct device *dev, void *aux)
199 {
200 struct agten_softc *sc = (struct agten_softc *)dev;
201 struct sbus_attach_args *sa = aux;
202 struct fbdevice *fb = &sc->sc_fb;
203 struct wsemuldisplaydev_attach_args aa;
204 struct rasops_info *ri;
205 long defattr;
206 uint32_t reg;
207 int node = sa->sa_node;
208 int console;
209
210 sc->sc_defaultscreen_descr = (struct wsscreen_descr){
211 "default",
212 0, 0,
213 NULL,
214 8, 16,
215 WSSCREEN_WSCOLORS | WSSCREEN_HILIT,
216 NULL
217 };
218 sc->sc_screens[0] = &sc->sc_defaultscreen_descr;
219 sc->sc_screenlist = (struct wsscreen_list){1, sc->sc_screens};
220 sc->sc_mode = WSDISPLAYIO_MODE_EMUL;
221 sc->sc_bustag = sa->sa_bustag;
222 #if 0
223 sc->sc_shadowfb = malloc(sc->sc_fbsize, M_DEVBUF, M_WAITOK);
224
225 dict = device_properties(&sc->sc_dev);
226
227 prop_dictionary_get_bool(dict, "is_console", &console);
228 #endif
229
230 reg = prom_getpropint(node, "i128_fb_physaddr", -1);
231 sc->sc_i128_fbsz = prom_getpropint(node, "i128_fb_size", -1);
232 if (sbus_bus_map(sc->sc_bustag,
233 sa->sa_reg[0].oa_space, sa->sa_reg[0].oa_base + reg,
234 sc->sc_i128_fbsz, BUS_SPACE_MAP_LINEAR, &sc->sc_i128_fbh) != 0) {
235
236 aprint_error("%s: unable to map the framebuffer\n",
237 dev->dv_xname);
238 return;
239 }
240 fb->fb_pixels = bus_space_vaddr(sc->sc_bustag, sc->sc_i128_fbh);
241
242 reg = prom_getpropint(node, "i128_reg_physaddr", -1);
243 if (sbus_bus_map(sc->sc_bustag,
244 sa->sa_reg[0].oa_space, sa->sa_reg[0].oa_base + reg,
245 0x10000, 0, &sc->sc_i128_regh) != 0) {
246
247 aprint_error("%s: unable to map I128 registers\n",
248 dev->dv_xname);
249 return;
250 }
251
252 reg = prom_getpropint(node, "p9100_reg_physaddr", -1);
253 if (sbus_bus_map(sc->sc_bustag,
254 sa->sa_reg[0].oa_space, sa->sa_reg[0].oa_base + reg,
255 0x8000, 0, &sc->sc_p9100_regh) != 0) {
256
257 aprint_error("%s: unable to map P9100 registers\n",
258 dev->dv_xname);
259 return;
260 }
261
262 reg = prom_getpropint(node, "glint_fb0_physaddr", -1);
263 sc->sc_glint_fb = sbus_bus_addr(sc->sc_bustag,
264 sa->sa_reg[0].oa_space, sa->sa_reg[0].oa_base + reg);
265 sc->sc_glint_fbsz = prom_getpropint(node, "glint_fb0_size", -1);
266 reg = prom_getpropint(node, "glint_reg_physaddr", -1);
267 sc->sc_glint_regs = sbus_bus_addr(sc->sc_bustag,
268 sa->sa_reg[0].oa_space, sa->sa_reg[0].oa_base + reg);
269
270 sbus_establish(&sc->sc_sd, &sc->sc_dev);
271 #if 0
272 bus_intr_establish(sc->sc_bustag, sa->sa_pri, IPL_BIO,
273 agten_intr, sc);
274 #endif
275
276 sc->sc_width = prom_getpropint(node, "ffb_width", 800);
277 sc->sc_height = prom_getpropint(node, "ffb_height", 600);
278 sc->sc_depth = prom_getpropint(node, "ffb_depth", 8);
279 sc->sc_stride = sc->sc_width * (sc->sc_depth >> 3);
280
281 agten_init(sc);
282
283 console = fb_is_console(node);
284
285 vcons_init(&sc->vd, sc, &sc->sc_defaultscreen_descr,
286 &agten_accessops);
287 sc->vd.init_screen = agten_init_screen;
288
289 ri = &sc->sc_console_screen.scr_ri;
290
291 if (console) {
292 vcons_init_screen(&sc->vd, &sc->sc_console_screen, 1,
293 &defattr);
294 sc->sc_console_screen.scr_flags |= VCONS_SCREEN_IS_STATIC;
295
296 sc->sc_defaultscreen_descr.textops = &ri->ri_ops;
297 sc->sc_defaultscreen_descr.capabilities = ri->ri_caps;
298 sc->sc_defaultscreen_descr.nrows = ri->ri_rows;
299 sc->sc_defaultscreen_descr.ncols = ri->ri_cols;
300 wsdisplay_cnattach(&sc->sc_defaultscreen_descr, ri, 0, 0,
301 defattr);
302 i128_rectfill(sc->sc_bustag, sc->sc_i128_regh, 0, 0,
303 sc->sc_width, sc->sc_height,
304 ri->ri_devcmap[(defattr >> 16) & 0xff]);
305 } else {
306 /*
307 * since we're not the console we can postpone the rest
308 * until someone actually allocates a screen for us
309 */
310 }
311
312 /* Initialize the default color map. */
313
314 aa.console = console;
315 aa.scrdata = &sc->sc_screenlist;
316 aa.accessops = &agten_accessops;
317 aa.accesscookie = &sc->vd;
318
319 config_found(&sc->sc_dev, &aa, wsemuldisplaydevprint);
320 }
321
322 static int
323 agten_ioctl(void *v, void *vs, u_long cmd, void *data, int flag,
324 struct lwp *l)
325 {
326 struct vcons_data *vd = v;
327 struct agten_softc *sc = vd->cookie;
328 struct wsdisplay_fbinfo *wdf;
329 struct vcons_screen *ms = vd->active;
330
331 switch (cmd) {
332
333 case WSDISPLAYIO_GTYPE:
334 *(u_int *)data = WSDISPLAY_TYPE_AG10;
335 return 0;
336
337 case WSDISPLAYIO_GINFO:
338 if (ms == NULL)
339 return ENODEV;
340 wdf = (void *)data;
341 wdf->height = ms->scr_ri.ri_height;
342 wdf->width = ms->scr_ri.ri_width;
343 wdf->depth = 32;
344 wdf->cmsize = 256;
345 return 0;
346
347 case WSDISPLAYIO_GETCMAP:
348 return agten_getcmap(sc,
349 (struct wsdisplay_cmap *)data);
350
351 case WSDISPLAYIO_PUTCMAP:
352 return agten_putcmap(sc,
353 (struct wsdisplay_cmap *)data);
354
355 case WSDISPLAYIO_LINEBYTES:
356 *(u_int *)data = sc->sc_stride << 2;
357 return 0;
358
359 case WSDISPLAYIO_SMODE:
360 {
361 int new_mode = *(int*)data;
362 if (new_mode != sc->sc_mode) {
363 sc->sc_mode = new_mode;
364 if(new_mode == WSDISPLAYIO_MODE_EMUL) {
365 agten_init(sc);
366 vcons_redraw_screen(ms);
367 } else {
368 agten_gfx(sc);
369 }
370 }
371 }
372 return 0;
373
374 case WSDISPLAYIO_GCURPOS:
375 {
376 struct wsdisplay_curpos *cp = (void *)data;
377
378 cp->x = sc->sc_cursor_x;
379 cp->y = sc->sc_cursor_y;
380 }
381 return 0;
382
383 case WSDISPLAYIO_SCURPOS:
384 {
385 struct wsdisplay_curpos *cp = (void *)data;
386
387 agten_move_cursor(sc, cp->x, cp->y);
388 }
389 return 0;
390
391 case WSDISPLAYIO_GCURMAX:
392 {
393 struct wsdisplay_curpos *cp = (void *)data;
394
395 cp->x = 64;
396 cp->y = 64;
397 }
398 return 0;
399
400 case WSDISPLAYIO_SCURSOR:
401 {
402 struct wsdisplay_cursor *cursor = (void *)data;
403
404 return agten_do_cursor(sc, cursor);
405 }
406 }
407 return EPASSTHROUGH;
408 }
409
410 static paddr_t
411 agten_mmap(void *v, void *vs, off_t offset, int prot)
412 {
413 struct vcons_data *vd = v;
414 struct agten_softc *sc = vd->cookie;
415
416 if (offset < sc->sc_glint_fbsz)
417 return bus_space_mmap(sc->sc_bustag, sc->sc_glint_fb, offset,
418 prot, BUS_SPACE_MAP_LINEAR);
419 return -1;
420 }
421
422 static void
423 agten_init_screen(void *cookie, struct vcons_screen *scr,
424 int existing, long *defattr)
425 {
426 struct agten_softc *sc = cookie;
427 struct rasops_info *ri = &scr->scr_ri;
428
429 ri->ri_depth = sc->sc_depth;
430 ri->ri_width = sc->sc_width;
431 ri->ri_height = sc->sc_height;
432 ri->ri_stride = sc->sc_stride;
433 ri->ri_flg = RI_CENTER | RI_FULLCLEAR;
434
435 ri->ri_bits = (char *)sc->sc_fb.fb_pixels;
436
437 if (existing) {
438 ri->ri_flg |= RI_CLEAR;
439 }
440
441 rasops_init(ri, sc->sc_height / 8, sc->sc_width / 8);
442 ri->ri_caps = WSSCREEN_WSCOLORS;
443
444 rasops_reconfig(ri, sc->sc_height / ri->ri_font->fontheight,
445 sc->sc_width / ri->ri_font->fontwidth);
446
447 ri->ri_hw = scr;
448 ri->ri_ops.copyrows = agten_copyrows;
449 ri->ri_ops.eraserows = agten_eraserows;
450 ri->ri_ops.copycols = agten_copycols;
451 ri->ri_ops.erasecols = agten_erasecols;
452
453 }
454
455 static int
456 agten_putcmap(struct agten_softc *sc, struct wsdisplay_cmap *cm)
457 {
458 u_int index = cm->index;
459 u_int count = cm->count;
460 int i, error;
461 u_char rbuf[256], gbuf[256], bbuf[256];
462 u_char *r, *g, *b;
463
464 if (cm->index >= 256 || cm->count > 256 ||
465 (cm->index + cm->count) > 256)
466 return EINVAL;
467 error = copyin(cm->red, &rbuf[index], count);
468 if (error)
469 return error;
470 error = copyin(cm->green, &gbuf[index], count);
471 if (error)
472 return error;
473 error = copyin(cm->blue, &bbuf[index], count);
474 if (error)
475 return error;
476
477 r = &rbuf[index];
478 g = &gbuf[index];
479 b = &bbuf[index];
480
481 for (i = 0; i < count; i++) {
482 agten_putpalreg(sc, index, *r, *g, *b);
483 index++;
484 r++, g++, b++;
485 }
486 return 0;
487 }
488
489 static int
490 agten_getcmap(struct agten_softc *sc, struct wsdisplay_cmap *cm)
491 {
492 u_int index = cm->index;
493 u_int count = cm->count;
494 int error, i;
495 uint8_t red[256], green[256], blue[256];
496
497 if (index >= 255 || count > 256 || index + count > 256)
498 return EINVAL;
499
500 i = index;
501 while (i < (index + count)) {
502 red[i] = sc->sc_cmap.cm_map[i][0];
503 green[i] = sc->sc_cmap.cm_map[i][1];
504 blue[i] = sc->sc_cmap.cm_map[i][2];
505 i++;
506 }
507 error = copyout(&red[index], cm->red, count);
508 if (error)
509 return error;
510 error = copyout(&green[index], cm->green, count);
511 if (error)
512 return error;
513 error = copyout(&blue[index], cm->blue, count);
514 if (error)
515 return error;
516
517 return 0;
518 }
519
520 static int
521 agten_putpalreg(struct agten_softc *sc, uint8_t idx, uint8_t r, uint8_t g,
522 uint8_t b)
523 {
524
525 sc->sc_cmap.cm_map[idx][0] = r;
526 sc->sc_cmap.cm_map[idx][1] = g;
527 sc->sc_cmap.cm_map[idx][2] = b;
528 agten_write_idx(sc, IBM561_CMAP_TABLE + idx);
529 agten_write_dac(sc, IBM561_CMD_CMAP, r);
530 agten_write_dac(sc, IBM561_CMD_CMAP, g);
531 agten_write_dac(sc, IBM561_CMD_CMAP, b);
532 return 0;
533 }
534
535 static void
536 agten_init(struct agten_softc *sc)
537 {
538 int i, j;
539 uint32_t src, srcw;
540 volatile uint32_t junk;
541
542 /* first we set up the colour map */
543 j = 0;
544 for (i = 0; i < 256; i++) {
545
546 agten_putpalreg(sc, i, rasops_cmap[j], rasops_cmap[j + 1],
547 rasops_cmap[j + 2]);
548 j += 3;
549 }
550
551 /* then we set up a linear LUT for 24bit colour */
552 agten_write_idx(sc, IBM561_CMAP_TABLE + 256);
553 for (i = 0; i < 256; i++) {
554 agten_write_dac(sc, IBM561_CMD_CMAP, i);
555 agten_write_dac(sc, IBM561_CMD_CMAP, i);
556 agten_write_dac(sc, IBM561_CMD_CMAP, i);
557 }
558
559 /* and the linear gamma maps */
560 agten_write_idx(sc, IBM561_RED_GAMMA_TABLE);
561 for (i = 0; i < 0x3ff; i+= 4)
562 agten_write_dac_10(sc, IBM561_CMD_GAMMA, i);
563 agten_write_idx(sc, IBM561_GREEN_GAMMA_TABLE);
564 for (i = 0; i < 0x3ff; i+= 4)
565 agten_write_dac_10(sc, IBM561_CMD_GAMMA, i);
566 agten_write_idx(sc, IBM561_BLUE_GAMMA_TABLE);
567 for (i = 0; i < 0x3ff; i+= 4)
568 agten_write_dac_10(sc, IBM561_CMD_GAMMA, i);
569
570 /* enable outouts, RGB mode */
571 agten_write_idx(sc, IBM561_CONFIG_REG3);
572 agten_write_dac(sc, IBM561_CMD, 0x41);
573
574 /* MUX 4:1 basic, 8bit overlay, 8bit WIDs */
575 agten_write_idx(sc, IBM561_CONFIG_REG1);
576 agten_write_dac(sc, IBM561_CMD, 0x2c);
577
578 /* now set up some window attributes */
579
580 /*
581 * direct colour, 24 bit, transparency off, LUT from 0x100
582 * we need to use direct colour and a linear LUT because for some
583 * reason true color mode gives messed up colours
584 */
585 agten_write_idx(sc, IBM561_FB_WINTYPE);
586 agten_write_dac_10(sc, IBM561_CMD_FB_WAT, 0x134);
587
588 /* use gamma LUTs, no crosshair, 0 is transparent */
589 agten_write_idx(sc, IBM561_AUXFB_WINTYPE);
590 agten_write_dac(sc, IBM561_CMD_FB_WAT, 0x0);
591
592 /* overlay is 8 bit, opaque */
593 agten_write_idx(sc, IBM561_OL_WINTYPE);
594 agten_write_dac_10(sc, IBM561_CMD_FB_WAT, 0x00);
595
596 /* now we fill the WID fb with zeroes */
597 src = 0;
598 srcw = sc->sc_width << 16 | sc->sc_height;
599 bus_space_write_4(sc->sc_bustag, sc->sc_p9100_regh, FOREGROUND_COLOR,
600 0x0);
601 bus_space_write_4(sc->sc_bustag, sc->sc_p9100_regh, BACKGROUND_COLOR,
602 0x0);
603 bus_space_write_4(sc->sc_bustag, sc->sc_p9100_regh, RASTER_OP, ROP_PAT);
604 bus_space_write_4(sc->sc_bustag, sc->sc_p9100_regh, COORD_INDEX, 0);
605 bus_space_write_4(sc->sc_bustag, sc->sc_p9100_regh, RECT_RTW_XY, src);
606 bus_space_write_4(sc->sc_bustag, sc->sc_p9100_regh, RECT_RTW_XY, srcw);
607 junk = bus_space_read_4(sc->sc_bustag, sc->sc_p9100_regh, COMMAND_QUAD);
608
609 /* initialize the cursor registers */
610
611 /* initialize the Imagine 128 */
612 i128_init(sc->sc_bustag, sc->sc_i128_regh, sc->sc_stride, 8);
613 }
614
615 static void
616 agten_gfx(struct agten_softc *sc)
617 {
618 /* enable overlay transparency on colour 0x00 */
619 agten_write_idx(sc, IBM561_OL_WINTYPE);
620 agten_write_dac_10(sc, IBM561_CMD_FB_WAT, 0x01);
621
622 /* then blit the overlay full of 0x00 */
623 i128_rectfill(sc->sc_bustag, sc->sc_i128_regh, 0, 0, sc->sc_width,
624 sc->sc_height, 0);
625
626 /* ... so we can see the 24bit framebuffer */
627 }
628
629 static void
630 agten_copycols(void *cookie, int row, int srccol, int dstcol, int ncols)
631 {
632 struct rasops_info *ri = cookie;
633 struct vcons_screen *scr = ri->ri_hw;
634 struct agten_softc *sc = scr->scr_cookie;
635 int32_t xs, xd, y, width, height;
636
637 xs = ri->ri_xorigin + ri->ri_font->fontwidth * srccol;
638 xd = ri->ri_xorigin + ri->ri_font->fontwidth * dstcol;
639 y = ri->ri_yorigin + ri->ri_font->fontheight * row;
640 width = ri->ri_font->fontwidth * ncols;
641 height = ri->ri_font->fontheight;
642 i128_bitblt(sc->sc_bustag, sc->sc_i128_regh, xs, y, xd, y, width,
643 height, CR_COPY);
644 }
645
646 static void
647 agten_erasecols(void *cookie, int row, int startcol, int ncols, long fillattr)
648 {
649 struct rasops_info *ri = cookie;
650 struct vcons_screen *scr = ri->ri_hw;
651 struct agten_softc *sc = scr->scr_cookie;
652 int32_t x, y, width, height, bg;
653
654 x = ri->ri_xorigin + ri->ri_font->fontwidth * startcol;
655 y = ri->ri_yorigin + ri->ri_font->fontheight * row;
656 width = ri->ri_font->fontwidth * ncols;
657 height = ri->ri_font->fontheight;
658 bg = (uint32_t)ri->ri_devcmap[(fillattr >> 16) & 0xff];
659 i128_rectfill(sc->sc_bustag, sc->sc_i128_regh, x, y, width, height, bg);
660 }
661
662 static void
663 agten_copyrows(void *cookie, int srcrow, int dstrow, int nrows)
664 {
665 struct rasops_info *ri = cookie;
666 struct vcons_screen *scr = ri->ri_hw;
667 struct agten_softc *sc = scr->scr_cookie;
668 int32_t x, ys, yd, width, height;
669
670 x = ri->ri_xorigin;
671 ys = ri->ri_yorigin + ri->ri_font->fontheight * srcrow;
672 yd = ri->ri_yorigin + ri->ri_font->fontheight * dstrow;
673 width = ri->ri_emuwidth;
674 height = ri->ri_font->fontheight * nrows;
675 i128_bitblt(sc->sc_bustag, sc->sc_i128_regh, x, ys, x, yd, width,
676 height, CR_COPY);
677 }
678
679 static void
680 agten_eraserows(void *cookie, int row, int nrows, long fillattr)
681 {
682 struct rasops_info *ri = cookie;
683 struct vcons_screen *scr = ri->ri_hw;
684 struct agten_softc *sc = scr->scr_cookie;
685 int32_t x, y, width, height, bg;
686
687 if ((row == 0) && (nrows == ri->ri_rows)) {
688 x = y = 0;
689 width = ri->ri_width;
690 height = ri->ri_height;
691 } else {
692 x = ri->ri_xorigin;
693 y = ri->ri_yorigin + ri->ri_font->fontheight * row;
694 width = ri->ri_emuwidth;
695 height = ri->ri_font->fontheight * nrows;
696 }
697 bg = (uint32_t)ri->ri_devcmap[(fillattr >> 16) & 0xff];
698 i128_rectfill(sc->sc_bustag, sc->sc_i128_regh, x, y, width, height, bg);
699 }
700
701 static void
702 agten_move_cursor(struct agten_softc *sc, int x, int y)
703 {
704
705 sc->sc_cursor_x = x;
706 sc->sc_cursor_y = y;
707 agten_write_idx(sc, IBM561_CURSOR_X_REG);
708 agten_write_dac(sc, IBM561_CMD, x & 0xff);
709 agten_write_dac(sc, IBM561_CMD, (x >> 8) & 0xff);
710 agten_write_dac(sc, IBM561_CMD, y & 0xff);
711 agten_write_dac(sc, IBM561_CMD, (y >> 8) & 0xff);
712 }
713
714 static int
715 agten_do_cursor(struct agten_softc *sc, struct wsdisplay_cursor *cur)
716 {
717 if (cur->which & WSDISPLAY_CURSOR_DOCUR) {
718
719 agten_write_idx(sc, IBM561_CURS_CNTL_REG);
720 agten_write_dac(sc, IBM561_CMD, cur->enable ?
721 CURS_ENABLE : 0);
722 }
723 if (cur->which & WSDISPLAY_CURSOR_DOHOT) {
724
725 agten_write_idx(sc, IBM561_HOTSPOT_X_REG);
726 agten_write_dac(sc, IBM561_CMD, cur->hot.x);
727 agten_write_dac(sc, IBM561_CMD, cur->hot.y);
728 }
729 if (cur->which & WSDISPLAY_CURSOR_DOPOS) {
730
731 agten_move_cursor(sc, cur->pos.x, cur->pos.y);
732 }
733 if (cur->which & WSDISPLAY_CURSOR_DOCMAP) {
734 int i;
735
736 agten_write_idx(sc, IBM561_CURSOR_LUT + cur->cmap.index + 2);
737 for (i = 0; i < cur->cmap.count; i++) {
738 agten_write_dac(sc, IBM561_CMD_CMAP, cur->cmap.red[i]);
739 agten_write_dac(sc, IBM561_CMD_CMAP, cur->cmap.green[i]);
740 agten_write_dac(sc, IBM561_CMD_CMAP, cur->cmap.blue[i]);
741 }
742 }
743 if (cur->which & WSDISPLAY_CURSOR_DOSHAPE) {
744 int i;
745 uint16_t tmp;
746
747 agten_write_idx(sc, IBM561_CURSOR_BITMAP);
748 for (i = 0; i < 512; i++) {
749 tmp = util_interleave(cur->mask[i], cur->image[i]);
750 agten_write_dac(sc, IBM561_CMD, (tmp >> 8) & 0xff);
751 agten_write_dac(sc, IBM561_CMD, tmp & 0xff);
752 }
753 }
754 return 0;
755 }
756
757 uint16_t
758 util_interleave(uint8_t b1, uint8_t b2)
759 {
760 int i;
761 uint16_t ret = 0;
762 uint16_t mask = 0x8000;
763 uint8_t mask8 = 0x01;
764
765 for (i = 0; i < 8; i++) {
766 if (b1 & mask8)
767 ret |= mask;
768 mask = mask >> 1;
769 if (b2 & mask8)
770 ret |= mask;
771 mask = mask >> 1;
772 mask8 = mask8 << 1;
773 }
774 return ret;
775 }
776