voyagerfb.c revision 1.1 1 /* $NetBSD: voyagerfb.c,v 1.1 2011/08/31 16:47:31 macallan Exp $ */
2
3 /*
4 * Copyright (c) 2009 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 AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28 /*
29 * A console driver for Silicon Motion SM502 / Voyager GX graphics controllers
30 * tested on GDIUM only so far
31 */
32
33 #include <sys/cdefs.h>
34 __KERNEL_RCSID(0, "$NetBSD: voyagerfb.c,v 1.1 2011/08/31 16:47:31 macallan Exp $");
35
36 #include <sys/param.h>
37 #include <sys/systm.h>
38 #include <sys/kernel.h>
39 #include <sys/device.h>
40 #include <sys/malloc.h>
41 #include <sys/lwp.h>
42 #include <sys/kauth.h>
43
44 #include <dev/videomode/videomode.h>
45
46 #include <dev/pci/pcivar.h>
47 #include <dev/pci/pcireg.h>
48 #include <dev/pci/pcidevs.h>
49 #include <dev/pci/pciio.h>
50 #include <dev/ic/sm502reg.h>
51
52 #include <dev/wscons/wsdisplayvar.h>
53 #include <dev/wscons/wsconsio.h>
54 #include <dev/wsfont/wsfont.h>
55 #include <dev/rasops/rasops.h>
56 #include <dev/wscons/wsdisplay_vconsvar.h>
57 #include <dev/pci/wsdisplay_pci.h>
58
59 #include <dev/i2c/i2cvar.h>
60 #include <dev/pci/voyagervar.h>
61
62 struct voyagerfb_softc {
63 device_t sc_dev;
64
65 pci_chipset_tag_t sc_pc;
66 pcitag_t sc_pcitag;
67 bus_space_tag_t sc_memt;
68
69 bus_space_handle_t sc_fbh;
70 bus_space_handle_t sc_regh;
71 bus_addr_t sc_fb, sc_reg;
72 bus_size_t sc_fbsize, sc_regsize;
73
74 int sc_width, sc_height, sc_depth, sc_stride;
75 int sc_locked;
76 void *sc_fbaddr;
77 struct vcons_screen sc_console_screen;
78 struct wsscreen_descr sc_defaultscreen_descr;
79 const struct wsscreen_descr *sc_screens[1];
80 struct wsscreen_list sc_screenlist;
81 struct vcons_data vd;
82 uint8_t *sc_dataport;
83 int sc_mode;
84 u_char sc_cmap_red[256];
85 u_char sc_cmap_green[256];
86 u_char sc_cmap_blue[256];
87 };
88
89 static int voyagerfb_match(device_t, cfdata_t, void *);
90 static void voyagerfb_attach(device_t, device_t, void *);
91
92 CFATTACH_DECL_NEW(voyagerfb, sizeof(struct voyagerfb_softc),
93 voyagerfb_match, voyagerfb_attach, NULL, NULL);
94
95 extern const u_char rasops_cmap[768];
96
97 static int voyagerfb_ioctl(void *, void *, u_long, void *, int,
98 struct lwp *);
99 static paddr_t voyagerfb_mmap(void *, void *, off_t, int);
100 static void voyagerfb_init_screen(void *, struct vcons_screen *, int,
101 long *);
102
103 static int voyagerfb_putcmap(struct voyagerfb_softc *,
104 struct wsdisplay_cmap *);
105 static int voyagerfb_getcmap(struct voyagerfb_softc *,
106 struct wsdisplay_cmap *);
107 static void voyagerfb_restore_palette(struct voyagerfb_softc *);
108 static int voyagerfb_putpalreg(struct voyagerfb_softc *, int, uint8_t,
109 uint8_t, uint8_t);
110
111 static void voyagerfb_init(struct voyagerfb_softc *);
112
113 static void voyagerfb_rectfill(struct voyagerfb_softc *, int, int, int, int,
114 uint32_t);
115 static void voyagerfb_bitblt(struct voyagerfb_softc *, int, int, int, int,
116 int, int, int);
117
118 static void voyagerfb_cursor(void *, int, int, int);
119 static void voyagerfb_putchar(void *, int, int, u_int, long);
120 static void voyagerfb_copycols(void *, int, int, int, int);
121 static void voyagerfb_erasecols(void *, int, int, int, long);
122 static void voyagerfb_copyrows(void *, int, int, int);
123 static void voyagerfb_eraserows(void *, int, int, long);
124
125 struct wsdisplay_accessops voyagerfb_accessops = {
126 voyagerfb_ioctl,
127 voyagerfb_mmap,
128 NULL, /* alloc_screen */
129 NULL, /* free_screen */
130 NULL, /* show_screen */
131 NULL, /* load_font */
132 NULL, /* pollc */
133 NULL /* scroll */
134 };
135
136 /* wait for FIFO empty so we can feed it another command */
137 static inline void
138 voyagerfb_ready(struct voyagerfb_softc *sc)
139 {
140 do {} while ((bus_space_read_4(sc->sc_memt, sc->sc_regh,
141 SM502_SYSTEM_CTRL) & SM502_SYSCTL_FIFO_EMPTY) == 0);
142 }
143
144 /* wait for the drawing engine to be idle */
145 static inline void
146 voyagerfb_wait(struct voyagerfb_softc *sc)
147 {
148 do {} while ((bus_space_read_4(sc->sc_memt, sc->sc_regh,
149 SM502_SYSTEM_CTRL) & SM502_SYSCTL_ENGINE_BUSY) != 0);
150 }
151
152 static int
153 voyagerfb_match(device_t parent, cfdata_t match, void *aux)
154 {
155 struct voyager_attach_args *vaa = (struct voyager_attach_args *)aux;
156
157 if (strcmp(vaa->vaa_name, "voyagerfb") == 0) return 100;
158 return 0;
159 }
160
161 static void
162 voyagerfb_attach(device_t parent, device_t self, void *aux)
163 {
164 struct voyagerfb_softc *sc = device_private(self);
165 struct voyager_attach_args *vaa = aux;
166 struct rasops_info *ri;
167 struct wsemuldisplaydev_attach_args aa;
168 prop_dictionary_t dict;
169 unsigned long defattr;
170 uint32_t reg;
171 bool is_console;
172 int i, j;
173
174 sc->sc_pc = vaa->vaa_pc;
175 sc->sc_pcitag = vaa->vaa_pcitag;
176 sc->sc_memt = vaa->vaa_tag;
177 sc->sc_dev = self;
178
179 aprint_normal("\n");
180
181 dict = device_properties(self);
182 prop_dictionary_get_bool(dict, "is_console", &is_console);
183
184 sc->sc_fb = vaa->vaa_mem_pa;
185 sc->sc_fbh = vaa->vaa_memh;
186 sc->sc_fbsize = 16 * 1024 * 1024;
187 sc->sc_fbaddr = bus_space_vaddr(sc->sc_memt, sc->sc_fbh);
188
189 sc->sc_reg = vaa->vaa_reg_pa;
190 sc->sc_regh = vaa->vaa_regh;
191 sc->sc_regsize = 2 * 1024 * 1024;
192 sc->sc_dataport = bus_space_vaddr(sc->sc_memt, sc->sc_regh);
193 sc->sc_dataport += SM502_DATAPORT;
194
195 reg = bus_space_read_4(sc->sc_memt, sc->sc_regh, SM502_PANEL_DISP_CRTL);
196 switch (reg & SM502_PDC_DEPTH_MASK) {
197 case SM502_PDC_8BIT:
198 sc->sc_depth = 8;
199 break;
200 case SM502_PDC_16BIT:
201 sc->sc_depth = 16;
202 break;
203 case SM502_PDC_32BIT:
204 sc->sc_depth = 24;
205 break;
206 default:
207 panic("%s: unsupported depth", device_xname(self));
208 }
209 sc->sc_stride = (bus_space_read_4(sc->sc_memt, sc->sc_regh,
210 SM502_PANEL_FB_OFFSET) & SM502_FBA_WIN_STRIDE_MASK) >> 16;
211 sc->sc_width = (bus_space_read_4(sc->sc_memt, sc->sc_regh,
212 SM502_PANEL_FB_WIDTH) & SM502_FBW_WIN_WIDTH_MASK) >> 16;
213 sc->sc_height = (bus_space_read_4(sc->sc_memt, sc->sc_regh,
214 SM502_PANEL_FB_HEIGHT) & SM502_FBH_WIN_HEIGHT_MASK) >> 16;
215
216 printf("%s: %d x %d, %d bit, stride %d\n", device_xname(self),
217 sc->sc_width, sc->sc_height, sc->sc_depth, sc->sc_stride);
218 /*
219 * XXX yeah, casting the fb address to uint32_t is formally wrong
220 * but as far as I know there are no SM502 with 64bit BARs
221 */
222 aprint_normal("%s: %d MB aperture at 0x%08x\n", device_xname(self),
223 (int)(sc->sc_fbsize >> 20), (uint32_t)sc->sc_fb);
224
225 sc->sc_defaultscreen_descr = (struct wsscreen_descr){
226 "default",
227 0, 0,
228 NULL,
229 8, 16,
230 WSSCREEN_WSCOLORS | WSSCREEN_HILIT,
231 NULL
232 };
233 sc->sc_screens[0] = &sc->sc_defaultscreen_descr;
234 sc->sc_screenlist = (struct wsscreen_list){1, sc->sc_screens};
235 sc->sc_mode = WSDISPLAYIO_MODE_EMUL;
236 sc->sc_locked = 0;
237
238 vcons_init(&sc->vd, sc, &sc->sc_defaultscreen_descr,
239 &voyagerfb_accessops);
240 sc->vd.init_screen = voyagerfb_init_screen;
241
242 /* init engine here */
243 voyagerfb_init(sc);
244
245 ri = &sc->sc_console_screen.scr_ri;
246
247 if (is_console) {
248 vcons_init_screen(&sc->vd, &sc->sc_console_screen, 1,
249 &defattr);
250 sc->sc_console_screen.scr_flags |= VCONS_SCREEN_IS_STATIC;
251
252 sc->sc_defaultscreen_descr.textops = &ri->ri_ops;
253 sc->sc_defaultscreen_descr.capabilities = ri->ri_caps;
254 sc->sc_defaultscreen_descr.nrows = ri->ri_rows;
255 sc->sc_defaultscreen_descr.ncols = ri->ri_cols;
256 wsdisplay_cnattach(&sc->sc_defaultscreen_descr, ri, 0, 0,
257 defattr);
258 } else {
259 /*
260 * since we're not the console we can postpone the rest
261 * until someone actually allocates a screen for us
262 */
263 (*ri->ri_ops.allocattr)(ri, 0, 0, 0, &defattr);
264 }
265
266 j = 0;
267 if (sc->sc_depth <= 8) {
268 for (i = 0; i < (1 << sc->sc_depth); i++) {
269
270 sc->sc_cmap_red[i] = rasops_cmap[j];
271 sc->sc_cmap_green[i] = rasops_cmap[j + 1];
272 sc->sc_cmap_blue[i] = rasops_cmap[j + 2];
273 voyagerfb_putpalreg(sc, i, rasops_cmap[j],
274 rasops_cmap[j + 1], rasops_cmap[j + 2]);
275 j += 3;
276 }
277 }
278
279 voyagerfb_rectfill(sc, 0, 0, sc->sc_width, sc->sc_height,
280 ri->ri_devcmap[(defattr >> 16) & 0xff]);
281
282 if (is_console)
283 vcons_replay_msgbuf(&sc->sc_console_screen);
284
285 aa.console = is_console;
286 aa.scrdata = &sc->sc_screenlist;
287 aa.accessops = &voyagerfb_accessops;
288 aa.accesscookie = &sc->vd;
289
290 config_found(sc->sc_dev, &aa, wsemuldisplaydevprint);
291 }
292
293 static int
294 voyagerfb_ioctl(void *v, void *vs, u_long cmd, void *data, int flag,
295 struct lwp *l)
296 {
297 struct vcons_data *vd = v;
298 struct voyagerfb_softc *sc = vd->cookie;
299 struct wsdisplay_fbinfo *wdf;
300 struct vcons_screen *ms = vd->active;
301
302 switch (cmd) {
303 case WSDISPLAYIO_GTYPE:
304 *(u_int *)data = WSDISPLAY_TYPE_PCIMISC;
305 return 0;
306
307 /* PCI config read/write passthrough. */
308 case PCI_IOC_CFGREAD:
309 case PCI_IOC_CFGWRITE:
310 return pci_devioctl(sc->sc_pc, sc->sc_pcitag,
311 cmd, data, flag, l);
312
313 case WSDISPLAYIO_GET_BUSID:
314 return wsdisplayio_busid_pci(sc->sc_dev, sc->sc_pc,
315 sc->sc_pcitag, data);
316
317 case WSDISPLAYIO_GINFO:
318 if (ms == NULL)
319 return ENODEV;
320 wdf = (void *)data;
321 wdf->height = ms->scr_ri.ri_height;
322 wdf->width = ms->scr_ri.ri_width;
323 wdf->depth = ms->scr_ri.ri_depth;
324 wdf->cmsize = 256;
325 return 0;
326
327 case WSDISPLAYIO_GETCMAP:
328 return voyagerfb_getcmap(sc,
329 (struct wsdisplay_cmap *)data);
330
331 case WSDISPLAYIO_PUTCMAP:
332 return voyagerfb_putcmap(sc,
333 (struct wsdisplay_cmap *)data);
334
335 case WSDISPLAYIO_LINEBYTES:
336 *(u_int *)data = sc->sc_stride;
337 return 0;
338
339 case WSDISPLAYIO_SMODE: {
340 int new_mode = *(int*)data;
341 if (new_mode != sc->sc_mode) {
342 sc->sc_mode = new_mode;
343 if(new_mode == WSDISPLAYIO_MODE_EMUL) {
344 voyagerfb_restore_palette(sc);
345 vcons_redraw_screen(ms);
346 }
347 }
348 }
349 return 0;
350 }
351 return EPASSTHROUGH;
352 }
353
354 static paddr_t
355 voyagerfb_mmap(void *v, void *vs, off_t offset, int prot)
356 {
357 struct vcons_data *vd = v;
358 struct voyagerfb_softc *sc = vd->cookie;
359 paddr_t pa;
360
361 /* 'regular' framebuffer mmap()ing */
362 if (offset < sc->sc_fbsize) {
363 pa = bus_space_mmap(sc->sc_memt, sc->sc_fb + offset, 0, prot,
364 BUS_SPACE_MAP_LINEAR);
365 return pa;
366 }
367
368 /*
369 * restrict all other mappings to processes with superuser privileges
370 * or the kernel itself
371 */
372 if (kauth_authorize_generic(kauth_cred_get(), KAUTH_GENERIC_ISSUSER,
373 NULL) != 0) {
374 aprint_normal("%s: mmap() rejected.\n",
375 device_xname(sc->sc_dev));
376 return -1;
377 }
378
379 if ((offset >= sc->sc_fb) && (offset < (sc->sc_fb + sc->sc_fbsize))) {
380 pa = bus_space_mmap(sc->sc_memt, offset, 0, prot,
381 BUS_SPACE_MAP_LINEAR);
382 return pa;
383 }
384
385 if ((offset >= sc->sc_reg) &&
386 (offset < (sc->sc_reg + sc->sc_regsize))) {
387 pa = bus_space_mmap(sc->sc_memt, offset, 0, prot,
388 BUS_SPACE_MAP_LINEAR);
389 return pa;
390 }
391
392 return -1;
393 }
394
395 static void
396 voyagerfb_init_screen(void *cookie, struct vcons_screen *scr,
397 int existing, long *defattr)
398 {
399 struct voyagerfb_softc *sc = cookie;
400 struct rasops_info *ri = &scr->scr_ri;
401
402 ri->ri_depth = sc->sc_depth;
403 ri->ri_width = sc->sc_width;
404 ri->ri_height = sc->sc_height;
405 ri->ri_stride = sc->sc_stride;
406 ri->ri_flg = RI_CENTER | RI_FULLCLEAR;
407
408 ri->ri_bits = (char *)sc->sc_fbaddr;
409
410 if (existing) {
411 ri->ri_flg |= RI_CLEAR;
412 }
413
414 rasops_init(ri, sc->sc_height / 8, sc->sc_width / 8);
415 ri->ri_caps = WSSCREEN_WSCOLORS;
416
417 rasops_reconfig(ri, sc->sc_height / ri->ri_font->fontheight,
418 sc->sc_width / ri->ri_font->fontwidth);
419
420 ri->ri_hw = scr;
421 ri->ri_ops.copyrows = voyagerfb_copyrows;
422 ri->ri_ops.copycols = voyagerfb_copycols;
423 ri->ri_ops.eraserows = voyagerfb_eraserows;
424 ri->ri_ops.erasecols = voyagerfb_erasecols;
425 ri->ri_ops.cursor = voyagerfb_cursor;
426 ri->ri_ops.putchar = voyagerfb_putchar;
427 }
428
429 static int
430 voyagerfb_putcmap(struct voyagerfb_softc *sc, struct wsdisplay_cmap *cm)
431 {
432 u_char *r, *g, *b;
433 u_int index = cm->index;
434 u_int count = cm->count;
435 int i, error;
436 u_char rbuf[256], gbuf[256], bbuf[256];
437
438 #ifdef VOYAGERFB_DEBUG
439 aprint_debug("putcmap: %d %d\n",index, count);
440 #endif
441 if (cm->index >= 256 || cm->count > 256 ||
442 (cm->index + cm->count) > 256)
443 return EINVAL;
444 error = copyin(cm->red, &rbuf[index], count);
445 if (error)
446 return error;
447 error = copyin(cm->green, &gbuf[index], count);
448 if (error)
449 return error;
450 error = copyin(cm->blue, &bbuf[index], count);
451 if (error)
452 return error;
453
454 memcpy(&sc->sc_cmap_red[index], &rbuf[index], count);
455 memcpy(&sc->sc_cmap_green[index], &gbuf[index], count);
456 memcpy(&sc->sc_cmap_blue[index], &bbuf[index], count);
457
458 r = &sc->sc_cmap_red[index];
459 g = &sc->sc_cmap_green[index];
460 b = &sc->sc_cmap_blue[index];
461
462 for (i = 0; i < count; i++) {
463 voyagerfb_putpalreg(sc, index, *r, *g, *b);
464 index++;
465 r++, g++, b++;
466 }
467 return 0;
468 }
469
470 static int
471 voyagerfb_getcmap(struct voyagerfb_softc *sc, struct wsdisplay_cmap *cm)
472 {
473 u_int index = cm->index;
474 u_int count = cm->count;
475 int error;
476
477 if (index >= 255 || count > 256 || index + count > 256)
478 return EINVAL;
479
480 error = copyout(&sc->sc_cmap_red[index], cm->red, count);
481 if (error)
482 return error;
483 error = copyout(&sc->sc_cmap_green[index], cm->green, count);
484 if (error)
485 return error;
486 error = copyout(&sc->sc_cmap_blue[index], cm->blue, count);
487 if (error)
488 return error;
489
490 return 0;
491 }
492
493 static void
494 voyagerfb_restore_palette(struct voyagerfb_softc *sc)
495 {
496 int i;
497
498 for (i = 0; i < (1 << sc->sc_depth); i++) {
499 voyagerfb_putpalreg(sc, i, sc->sc_cmap_red[i],
500 sc->sc_cmap_green[i], sc->sc_cmap_blue[i]);
501 }
502 }
503
504 static int
505 voyagerfb_putpalreg(struct voyagerfb_softc *sc, int idx, uint8_t r,
506 uint8_t g, uint8_t b)
507 {
508 uint32_t reg;
509
510 reg = (r << 16) | (g << 8) | b;
511 /* XXX we should probably write the CRT palette too */
512 bus_space_write_4(sc->sc_memt, sc->sc_regh,
513 SM502_PALETTE_PANEL + (idx << 2), reg);
514 return 0;
515 }
516
517 static void
518 voyagerfb_init(struct voyagerfb_softc *sc)
519 {
520
521 voyagerfb_wait(sc);
522 /* disable colour compare */
523 bus_space_write_4(sc->sc_memt, sc->sc_regh, SM502_COLOR_COMP_MASK, 0);
524 /* allow writes to all planes */
525 bus_space_write_4(sc->sc_memt, sc->sc_regh, SM502_PLANEMASK,
526 0xffffffff);
527 /* disable clipping */
528 bus_space_write_4(sc->sc_memt, sc->sc_regh, SM502_CLIP_TOP_LEFT, 0);
529 /* source and destination in local memory, no offset */
530 bus_space_write_4(sc->sc_memt, sc->sc_regh, SM502_SRC_BASE, 0);
531 bus_space_write_4(sc->sc_memt, sc->sc_regh, SM502_DST_BASE, 0);
532 /* pitch is screen stride */
533 bus_space_write_4(sc->sc_memt, sc->sc_regh, SM502_PITCH,
534 sc->sc_width | (sc->sc_width << 16));
535 /* window is screen width */
536 bus_space_write_4(sc->sc_memt, sc->sc_regh, SM502_WINDOW_WIDTH,
537 sc->sc_width | (sc->sc_width << 16));
538 switch (sc->sc_depth) {
539 case 8:
540 bus_space_write_4(sc->sc_memt, sc->sc_regh,
541 SM502_STRETCH, SM502_STRETCH_8BIT);
542 break;
543 case 16:
544 bus_space_write_4(sc->sc_memt, sc->sc_regh,
545 SM502_STRETCH, SM502_STRETCH_16BIT);
546 break;
547 case 24:
548 case 32:
549 bus_space_write_4(sc->sc_memt, sc->sc_regh,
550 SM502_STRETCH, SM502_STRETCH_32BIT);
551 break;
552 }
553 }
554
555 static void
556 voyagerfb_rectfill(struct voyagerfb_softc *sc, int x, int y, int wi, int he,
557 uint32_t colour)
558 {
559
560 voyagerfb_ready(sc);
561 bus_space_write_4(sc->sc_memt, sc->sc_regh, SM502_CONTROL,
562 ROP_COPY |
563 SM502_CTRL_USE_ROP2 |
564 SM502_CTRL_CMD_RECTFILL |
565 SM502_CTRL_QUICKSTART_E);
566 bus_space_write_4(sc->sc_memt, sc->sc_regh, SM502_FOREGROUND,
567 colour);
568 bus_space_write_4(sc->sc_memt, sc->sc_regh, SM502_DST,
569 (x << 16) | y);
570 bus_space_write_4(sc->sc_memt, sc->sc_regh, SM502_DIMENSION,
571 (wi << 16) | he);
572 }
573
574 static void
575 voyagerfb_bitblt(struct voyagerfb_softc *sc, int xs, int ys, int xd, int yd,
576 int wi, int he, int rop)
577 {
578 uint32_t cmd;
579
580 cmd = (rop & 0xf) | SM502_CTRL_USE_ROP2 | SM502_CTRL_CMD_BITBLT |
581 SM502_CTRL_QUICKSTART_E;
582
583 voyagerfb_ready(sc);
584
585 if (xd <= xs) {
586 /* left to right */
587 } else {
588 /*
589 * According to the manual this flag reverses only the blitter's
590 * X direction. At least on my Gdium it also reverses the Y
591 * direction
592 */
593 cmd |= SM502_CTRL_R_TO_L;
594 xs += wi - 1;
595 xd += wi - 1;
596 ys += he - 1;
597 yd += he - 1;
598 }
599
600 bus_space_write_4(sc->sc_memt, sc->sc_regh, SM502_CONTROL, cmd);
601 bus_space_write_4(sc->sc_memt, sc->sc_regh, SM502_SRC,
602 (xs << 16) | ys);
603 bus_space_write_4(sc->sc_memt, sc->sc_regh, SM502_DST,
604 (xd << 16) | yd);
605 bus_space_write_4(sc->sc_memt, sc->sc_regh, SM502_DIMENSION,
606 (wi << 16) | he);
607 }
608
609 static void
610 voyagerfb_cursor(void *cookie, int on, int row, int col)
611 {
612 struct rasops_info *ri = cookie;
613 struct vcons_screen *scr = ri->ri_hw;
614 struct voyagerfb_softc *sc = scr->scr_cookie;
615 int x, y, wi, he;
616
617 wi = ri->ri_font->fontwidth;
618 he = ri->ri_font->fontheight;
619
620 if (sc->sc_mode == WSDISPLAYIO_MODE_EMUL) {
621 x = ri->ri_ccol * wi + ri->ri_xorigin;
622 y = ri->ri_crow * he + ri->ri_yorigin;
623 if (ri->ri_flg & RI_CURSOR) {
624 voyagerfb_bitblt(sc, x, y, x, y, wi, he, ROP_INVERT);
625 ri->ri_flg &= ~RI_CURSOR;
626 }
627 ri->ri_crow = row;
628 ri->ri_ccol = col;
629 if (on) {
630 x = ri->ri_ccol * wi + ri->ri_xorigin;
631 y = ri->ri_crow * he + ri->ri_yorigin;
632 voyagerfb_bitblt(sc, x, y, x, y, wi, he, ROP_INVERT);
633 ri->ri_flg |= RI_CURSOR;
634 }
635 } else {
636 scr->scr_ri.ri_crow = row;
637 scr->scr_ri.ri_ccol = col;
638 scr->scr_ri.ri_flg &= ~RI_CURSOR;
639 }
640
641 }
642
643 static inline void
644 voyagerfb_feed8(struct voyagerfb_softc *sc, uint8_t *data, int len)
645 {
646 uint32_t *port = (uint32_t *)sc->sc_dataport;
647 int i;
648
649 for (i = 0; i < ((len + 3) & 0xfffc); i++) {
650 *port = *data;
651 data++;
652 }
653 }
654
655 static inline void
656 voyagerfb_feed16(struct voyagerfb_softc *sc, uint16_t *data, int len)
657 {
658 uint32_t *port = (uint32_t *)sc->sc_dataport;
659 int i;
660
661 len = len << 1;
662 for (i = 0; i < ((len + 1) & 0xfffe); i++) {
663 *port = *data;
664 data++;
665 }
666 }
667
668
669 static void
670 voyagerfb_putchar(void *cookie, int row, int col, u_int c, long attr)
671 {
672 struct rasops_info *ri = cookie;
673 struct wsdisplay_font *font = PICK_FONT(ri, c);
674 struct vcons_screen *scr = ri->ri_hw;
675 struct voyagerfb_softc *sc = scr->scr_cookie;
676 uint32_t cmd;
677
678 if (sc->sc_mode == WSDISPLAYIO_MODE_EMUL) {
679 int fg, bg, uc;
680 uint8_t *data;
681 int x, y, wi, he;
682 wi = font->fontwidth;
683 he = font->fontheight;
684
685 if (!CHAR_IN_FONT(c, font))
686 return;
687 bg = ri->ri_devcmap[(attr >> 16) & 0x0f];
688 fg = ri->ri_devcmap[(attr >> 24) & 0x0f];
689 x = ri->ri_xorigin + col * wi;
690 y = ri->ri_yorigin + row * he;
691 if (c == 0x20) {
692 voyagerfb_rectfill(sc, x, y, wi, he, bg);
693 } else {
694 uc = c - font->firstchar;
695 data = (uint8_t *)font->data + uc * ri->ri_fontscale;
696 cmd = ROP_COPY |
697 SM502_CTRL_USE_ROP2 |
698 SM502_CTRL_CMD_HOSTWRT |
699 SM502_CTRL_HOSTBLT_MONO |
700 SM502_CTRL_QUICKSTART_E |
701 SM502_CTRL_MONO_PACK_32BIT;
702 voyagerfb_ready(sc);
703 bus_space_write_4(sc->sc_memt, sc->sc_regh,
704 SM502_CONTROL, cmd);
705 bus_space_write_4(sc->sc_memt, sc->sc_regh,
706 SM502_FOREGROUND, fg);
707 bus_space_write_4(sc->sc_memt, sc->sc_regh,
708 SM502_BACKGROUND, bg);
709 bus_space_write_4(sc->sc_memt, sc->sc_regh,
710 SM502_SRC, 0);
711 bus_space_write_4(sc->sc_memt, sc->sc_regh,
712 SM502_DST, (x << 16) | y);
713 bus_space_write_4(sc->sc_memt, sc->sc_regh,
714 SM502_DIMENSION, (wi << 16) | he);
715 /* now feed the data, padded to 32bit */
716 switch (ri->ri_font->stride) {
717 case 1:
718 voyagerfb_feed8(sc, data, ri->ri_fontscale);
719 break;
720 case 2:
721 voyagerfb_feed16(sc, (uint16_t *)data,
722 ri->ri_fontscale);
723 break;
724
725 }
726 }
727 }
728 }
729
730 static void
731 voyagerfb_copycols(void *cookie, int row, int srccol, int dstcol, int ncols)
732 {
733 struct rasops_info *ri = cookie;
734 struct vcons_screen *scr = ri->ri_hw;
735 struct voyagerfb_softc *sc = scr->scr_cookie;
736 int32_t xs, xd, y, width, height;
737
738 if ((sc->sc_locked == 0) && (sc->sc_mode == WSDISPLAYIO_MODE_EMUL)) {
739 xs = ri->ri_xorigin + ri->ri_font->fontwidth * srccol;
740 xd = ri->ri_xorigin + ri->ri_font->fontwidth * dstcol;
741 y = ri->ri_yorigin + ri->ri_font->fontheight * row;
742 width = ri->ri_font->fontwidth * ncols;
743 height = ri->ri_font->fontheight;
744 voyagerfb_bitblt(sc, xs, y, xd, y, width, height, ROP_COPY);
745 }
746 }
747
748 static void
749 voyagerfb_erasecols(void *cookie, int row, int startcol, int ncols,
750 long fillattr)
751 {
752 struct rasops_info *ri = cookie;
753 struct vcons_screen *scr = ri->ri_hw;
754 struct voyagerfb_softc *sc = scr->scr_cookie;
755 int32_t x, y, width, height, fg, bg, ul;
756
757 if ((sc->sc_locked == 0) && (sc->sc_mode == WSDISPLAYIO_MODE_EMUL)) {
758 x = ri->ri_xorigin + ri->ri_font->fontwidth * startcol;
759 y = ri->ri_yorigin + ri->ri_font->fontheight * row;
760 width = ri->ri_font->fontwidth * ncols;
761 height = ri->ri_font->fontheight;
762 rasops_unpack_attr(fillattr, &fg, &bg, &ul);
763
764 voyagerfb_rectfill(sc, x, y, width, height, ri->ri_devcmap[bg]);
765 }
766 }
767
768 static void
769 voyagerfb_copyrows(void *cookie, int srcrow, int dstrow, int nrows)
770 {
771 struct rasops_info *ri = cookie;
772 struct vcons_screen *scr = ri->ri_hw;
773 struct voyagerfb_softc *sc = scr->scr_cookie;
774 int32_t x, ys, yd, width, height;
775 int i;
776
777 if ((sc->sc_locked == 0) && (sc->sc_mode == WSDISPLAYIO_MODE_EMUL)) {
778 x = ri->ri_xorigin;
779 ys = ri->ri_yorigin + ri->ri_font->fontheight * srcrow;
780 yd = ri->ri_yorigin + ri->ri_font->fontheight * dstrow;
781 width = ri->ri_emuwidth;
782 height = ri->ri_font->fontheight * nrows;
783 if ((nrows > 1) && (dstrow > srcrow)) {
784 /*
785 * the blitter can't do bottom-up copies so we have
786 * to copy line by line here
787 * should probably use a command sequence
788 */
789 ys += (height - ri->ri_font->fontheight);
790 yd += (height - ri->ri_font->fontheight);
791 for (i = 0; i < nrows; i++) {
792 voyagerfb_bitblt(sc, x, ys, x, yd, width,
793 ri->ri_font->fontheight, ROP_COPY);
794 ys -= ri->ri_font->fontheight;
795 yd -= ri->ri_font->fontheight;
796 }
797 } else
798 voyagerfb_bitblt(sc, x, ys, x, yd, width, height,
799 ROP_COPY);
800 }
801 }
802
803 static void
804 voyagerfb_eraserows(void *cookie, int row, int nrows, long fillattr)
805 {
806 struct rasops_info *ri = cookie;
807 struct vcons_screen *scr = ri->ri_hw;
808 struct voyagerfb_softc *sc = scr->scr_cookie;
809 int32_t x, y, width, height, fg, bg, ul;
810
811 if ((sc->sc_locked == 0) && (sc->sc_mode == WSDISPLAYIO_MODE_EMUL)) {
812 x = ri->ri_xorigin;
813 y = ri->ri_yorigin + ri->ri_font->fontheight * row;
814 width = ri->ri_emuwidth;
815 height = ri->ri_font->fontheight * nrows;
816 rasops_unpack_attr(fillattr, &fg, &bg, &ul);
817
818 voyagerfb_rectfill(sc, x, y, width, height, ri->ri_devcmap[bg]);
819 }
820 }
821