lynxfb.c revision 1.1 1 /* $NetBSD: lynxfb.c,v 1.1 2012/03/02 13:20:57 nonaka Exp $ */
2 /* $OpenBSD: smfb.c,v 1.13 2011/07/21 20:36:12 miod Exp $ */
3
4 /*
5 * Copyright (c) 2012 NONAKA Kimihiro <nonaka (at) netbsd.org>
6 * Copyright (c) 2009, 2010 Miodrag Vallat.
7 *
8 * Permission to use, copy, modify, and distribute this software for any
9 * purpose with or without fee is hereby granted, provided that the above
10 * copyright notice and this permission notice appear in all copies.
11 *
12 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
13 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
14 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
15 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
16 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
17 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
18 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19 */
20
21 /*
22 * SiliconMotion SM712 frame buffer driver.
23 *
24 * Assumes its video output is an LCD panel, in 5:6:5 mode, and fixed
25 * 1024x600 resolution, depending on the system model.
26 */
27
28 #include <sys/cdefs.h>
29 __KERNEL_RCSID(0, "$NetBSD: lynxfb.c,v 1.1 2012/03/02 13:20:57 nonaka Exp $");
30
31 #include "opt_wsemul.h"
32
33 #include <sys/param.h>
34 #include <sys/systm.h>
35 #include <sys/device.h>
36 #include <sys/endian.h>
37
38 #include <sys/bus.h>
39
40 #include <dev/ic/vgareg.h>
41 #include <dev/isa/isareg.h>
42 #include <dev/pci/pcireg.h>
43 #include <dev/pci/pcivar.h>
44 #include <dev/pci/pcidevs.h>
45 #include <dev/pci/pciio.h>
46
47 #include <dev/wscons/wsconsio.h>
48 #include <dev/wscons/wsdisplayvar.h>
49 #include <dev/rasops/rasops.h>
50 #include <dev/wscons/wsdisplay_vconsvar.h>
51 #include <dev/pci/wsdisplay_pci.h>
52
53 #include <dev/pci/lynxfbreg.h>
54 #include <dev/pci/lynxfbvar.h>
55
56 #ifndef LYNXFB_DEFAULT_WIDTH
57 #define LYNXFB_DEFAULT_WIDTH 1024
58 #endif
59 #ifndef LYNXFB_DEFAULT_HEIGHT
60 #define LYNXFB_DEFAULT_HEIGHT 600
61 #endif
62 #ifndef LYNXFB_DEFAULT_DEPTH
63 #define LYNXFB_DEFAULT_DEPTH 16
64 #endif
65 #ifndef LYNXFB_DEFAULT_STRIDE
66 #define LYNXFB_DEFAULT_STRIDE 0
67 #endif
68 #ifndef LYNXFB_DEFAULT_FLAGS
69 #ifdef __MIPSEL__
70 #define LYNXFB_DEFAULT_FLAGS LYNXFB_FLAG_SWAPBR
71 #else
72 #define LYNXFB_DEFAULT_FLAGS 0
73 #endif
74 #endif
75
76 struct lynxfb_softc;
77
78 /* minimal frame buffer information, suitable for early console */
79 struct lynxfb {
80 struct lynxfb_softc *sc;
81 void *fbaddr;
82
83 bus_space_tag_t memt;
84 bus_space_handle_t memh;
85
86 /* DPR registers */
87 bus_space_tag_t dprt;
88 bus_space_handle_t dprh;
89 /* MMIO space */
90 bus_space_tag_t mmiot;
91 bus_space_handle_t mmioh;
92
93 struct vcons_screen vcs;
94 struct wsscreen_descr wsd;
95
96 int width, height, depth, stride;
97 int accel;
98 int blank;
99
100 /* LYNXFB_FLAG_* */
101 int flags;
102 #define LYNXFB_FLAG_SWAPBR (1 << 0)
103 };
104
105 #define DPR_READ(fb, reg) \
106 bus_space_read_4((fb)->memt, (fb)->dprh, (reg))
107 #define DPR_WRITE(fb, reg, val) \
108 bus_space_write_4((fb)->memt, (fb)->dprh, (reg), (val))
109
110 struct lynxfb_softc {
111 device_t sc_dev;
112 bus_space_tag_t sc_memt;
113 bus_space_handle_t sc_memh;
114
115 pci_chipset_tag_t sc_pc;
116 pcitag_t sc_pcitag;
117
118 struct lynxfb *sc_fb;
119 struct lynxfb sc_fb_store;
120
121 struct vcons_data sc_vd;
122 struct wsscreen_list sc_screenlist;
123 const struct wsscreen_descr *sc_screens[1];
124 int sc_mode;
125 };
126
127 static int lynxfb_match_by_id(pcireg_t);
128 static int lynxfb_match(device_t, cfdata_t, void *);
129 static void lynxfb_attach(device_t, device_t, void *);
130
131 CFATTACH_DECL_NEW(lynxfb, sizeof(struct lynxfb_softc),
132 lynxfb_match, lynxfb_attach, NULL, NULL);
133
134 static int lynxfb_ioctl(void *, void *, u_long, void *, int, struct lwp *);
135 static paddr_t lynxfb_mmap(void *, void *, off_t, int);
136
137 static struct wsdisplay_accessops lynxfb_accessops = {
138 lynxfb_ioctl,
139 lynxfb_mmap,
140 NULL, /* alloc_screen */
141 NULL, /* free_screen */
142 NULL, /* show_screen */
143 NULL, /* load_font */
144 NULL, /* pollc */
145 NULL, /* scroll */
146 };
147
148 static bool lynxfb_is_console(struct lynxfb_softc *, pcitag_t);
149 static void lynxfb_init_screen(void *, struct vcons_screen *, int, long *);
150 static int lynxfb_setup(struct lynxfb *);
151
152 static int lynxfb_wait(struct lynxfb *);
153 static void lynxfb_copyrect(struct lynxfb *, int, int, int, int, int, int);
154 static void lynxfb_fillrect(struct lynxfb *, int, int, int, int, int);
155 static void lynxfb_copyrows(void *, int, int, int);
156 static void lynxfb_copycols(void *, int, int, int, int);
157 static void lynxfb_erasecols(void *, int, int, int, long);
158 static void lynxfb_eraserows(void *, int, int, long);
159 static void lynxfb_vcons_copyrows(void *, int, int, int);
160 static void lynxfb_vcons_copycols(void *, int, int, int, int);
161 static void lynxfb_vcons_erasecols(void *, int, int, int, long);
162 static void lynxfb_vcons_eraserows(void *, int, int, long);
163 static void lynxfb_blank(struct lynxfb *, int);
164
165 static struct {
166 bool is_console;
167 pcitag_t tag;
168 bus_space_tag_t memt;
169 bus_space_handle_t memh;
170 struct lynxfb fb;
171 } lynxfb_console;
172
173 int lynxfb_default_width = LYNXFB_DEFAULT_WIDTH;
174 int lynxfb_default_height = LYNXFB_DEFAULT_HEIGHT;
175 int lynxfb_default_depth = LYNXFB_DEFAULT_DEPTH;
176 int lynxfb_default_stride = LYNXFB_DEFAULT_STRIDE;
177 int lynxfb_default_flags = LYNXFB_DEFAULT_FLAGS;
178
179 static int
180 lynxfb_match_by_id(pcireg_t id)
181 {
182
183 if (PCI_VENDOR(id) != PCI_VENDOR_SILMOTION)
184 return (0);
185 if (PCI_PRODUCT(id) != PCI_PRODUCT_SILMOTION_SM712)
186 return (0);
187 return (1);
188 }
189
190 int
191 lynxfb_cnattach(bus_space_tag_t memt, bus_space_tag_t iot, pci_chipset_tag_t pc,
192 pcitag_t tag, pcireg_t id)
193 {
194 struct rasops_info *ri = &lynxfb_console.fb.vcs.scr_ri;
195 struct lynxfb *fb;
196 bus_space_handle_t memh;
197 bus_addr_t base;
198 bus_size_t size;
199 long defattr;
200 int mapflags;
201 int error;
202
203 if (!lynxfb_match_by_id(id))
204 return (ENODEV);
205
206 if (pci_mapreg_info(pc, tag, PCI_MAPREG_START, PCI_MAPREG_TYPE_MEM,
207 &base, &size, &mapflags))
208 return (EINVAL);
209 error = bus_space_map(memt, base, size, BUS_SPACE_MAP_LINEAR | mapflags,
210 &memh);
211 if (error)
212 return (error);
213
214 fb = &lynxfb_console.fb;
215 fb->memt = memt;
216 fb->memh = memh;
217 fb->width = lynxfb_default_width;
218 fb->height = lynxfb_default_height;
219 fb->depth = lynxfb_default_depth;
220 fb->stride = lynxfb_default_stride;
221 if (fb->stride == 0)
222 fb->stride = fb->width * fb->depth / 8;
223 fb->flags = lynxfb_default_flags;
224 error = lynxfb_setup(fb);
225 if (error) {
226 bus_space_unmap(memt, memh, size);
227 return (error);
228 }
229
230 lynxfb_console.is_console = true;
231 lynxfb_console.tag = tag;
232 (*ri->ri_ops.allocattr)(ri, 0, 0, 0, &defattr);
233 wsdisplay_preattach(&fb->wsd, ri, 0, 0, defattr);
234
235 return (0);
236 }
237
238 static bool
239 lynxfb_is_console(struct lynxfb_softc *sc, pcitag_t tag)
240 {
241
242 return (lynxfb_console.is_console &&
243 !memcmp(&lynxfb_console.tag, &tag, sizeof(tag)));
244 }
245
246 static int
247 lynxfb_match(device_t parent, cfdata_t match, void *aux)
248 {
249 struct pci_attach_args *pa = (struct pci_attach_args *)aux;
250
251 if (PCI_CLASS(pa->pa_class) != PCI_CLASS_DISPLAY)
252 return (0);
253 if (!lynxfb_match_by_id(pa->pa_id))
254 return (0);
255 return (1);
256 }
257
258 static void
259 lynxfb_attach(device_t parent, device_t self, void *aux)
260 {
261 struct lynxfb_softc *sc = device_private(self);
262 struct pci_attach_args *pa = (struct pci_attach_args *)aux;
263 struct wsemuldisplaydev_attach_args waa;
264 struct lynxfb *fb;
265 struct rasops_info *ri;
266 prop_dictionary_t dict;
267 bus_size_t size;
268 long defattr;
269 bool is_console;
270
271 sc->sc_dev = self;
272 sc->sc_pc = pa->pa_pc;
273 sc->sc_pcitag = pa->pa_tag;
274
275 pci_aprint_devinfo(pa, NULL);
276
277 is_console = lynxfb_is_console(sc, sc->sc_pcitag);
278
279 fb = is_console ? &lynxfb_console.fb : &sc->sc_fb_store;
280 sc->sc_fb = fb;
281 fb->sc = sc;
282
283 if (!is_console) {
284 if (pci_mapreg_map(pa, PCI_MAPREG_START, PCI_MAPREG_TYPE_MEM,
285 BUS_SPACE_MAP_LINEAR, &fb->memt, &fb->memh, NULL, &size)) {
286 aprint_error_dev(self, "can't map frame buffer\n");
287 return;
288 }
289
290 dict = device_properties(self);
291 if (!prop_dictionary_get_uint32(dict, "width", &fb->width))
292 fb->width = lynxfb_default_width;
293 if (!prop_dictionary_get_uint32(dict, "height", &fb->height))
294 fb->height = lynxfb_default_height;
295 if (!prop_dictionary_get_uint32(dict, "depth", &fb->depth))
296 fb->depth = lynxfb_default_depth;
297 if (!prop_dictionary_get_uint32(dict, "linebytes", &fb->stride)) {
298 if (lynxfb_default_stride == 0)
299 fb->stride = fb->width * fb->depth / 8;
300 else
301 fb->stride = lynxfb_default_stride;
302 }
303 if (!prop_dictionary_get_uint32(dict, "flags", &fb->flags))
304 fb->flags = lynxfb_default_flags;
305
306 if (lynxfb_setup(fb)) {
307 aprint_error_dev(self, "can't setup frame buffer\n");
308 bus_space_unmap(fb->memt, fb->memh, size);
309 return;
310 }
311 }
312 sc->sc_memt = fb->memt;
313 sc->sc_memh = fb->memh;
314
315 aprint_normal_dev(self, "%d x %d, %d bpp, stride %d\n", fb->width,
316 fb->height, fb->depth, fb->stride);
317
318 fb->wsd = (struct wsscreen_descr) {
319 "default",
320 0, 0,
321 NULL,
322 8, 16,
323 WSSCREEN_WSCOLORS | WSSCREEN_HILIT,
324 NULL,
325 };
326 sc->sc_screens[0] = &fb->wsd;
327 sc->sc_screenlist = (struct wsscreen_list){ 1, sc->sc_screens };
328 sc->sc_mode = WSDISPLAYIO_MODE_EMUL;
329
330 vcons_init(&sc->sc_vd, sc, &fb->wsd, &lynxfb_accessops);
331 sc->sc_vd.init_screen = lynxfb_init_screen;
332
333 ri = &fb->vcs.scr_ri;
334 if (is_console) {
335 vcons_init_screen(&sc->sc_vd, &fb->vcs, 1, &defattr);
336 fb->vcs.scr_flags |= VCONS_SCREEN_IS_STATIC;
337
338 fb->wsd.textops = &ri->ri_ops;
339 fb->wsd.capabilities = ri->ri_caps;
340 fb->wsd.nrows = ri->ri_rows;
341 fb->wsd.ncols = ri->ri_cols;
342 wsdisplay_cnattach(&fb->wsd, ri, 0, 0, defattr);
343 vcons_replay_msgbuf(&fb->vcs);
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 (*ri->ri_ops.allocattr)(ri, 0, 0, 0, &defattr);
350 }
351
352 waa.console = is_console;
353 waa.scrdata = &sc->sc_screenlist;
354 waa.accessops = &lynxfb_accessops;
355 waa.accesscookie = &sc->sc_vd;
356
357 config_found(self, &waa, wsemuldisplaydevprint);
358 }
359
360 /*
361 * vga sequencer access through MMIO space
362 */
363 static __inline uint8_t
364 lynxfb_vgats_read(struct lynxfb *fb, uint regno)
365 {
366
367 bus_space_write_1(fb->mmiot, fb->mmioh, IO_VGA + VGA_TS_INDEX, regno);
368 return bus_space_read_1(fb->mmiot, fb->mmioh, IO_VGA + VGA_TS_DATA);
369 }
370
371 static __inline void
372 lynxfb_vgats_write(struct lynxfb *fb, uint regno, uint8_t value)
373 {
374
375 bus_space_write_1(fb->mmiot, fb->mmioh, IO_VGA + VGA_TS_INDEX, regno);
376 bus_space_write_1(fb->mmiot, fb->mmioh, IO_VGA + VGA_TS_DATA, value);
377 }
378
379 /*
380 * wsdisplay accesops
381 */
382 static int
383 lynxfb_ioctl(void *v, void *vs, u_long cmd, void *data, int flags,
384 struct lwp *l)
385 {
386 struct vcons_data *vd = v;
387 struct lynxfb_softc *sc = vd->cookie;
388 struct lynxfb *fb = sc->sc_fb;
389 struct vcons_screen *ms = vd->active;
390 struct wsdisplay_fbinfo *wdf;
391 struct wsdisplay_param *param;
392
393 switch (cmd) {
394 case WSDISPLAYIO_GTYPE:
395 *(uint *)data = WSDISPLAY_TYPE_PCIMISC;
396 return (0);
397
398 /* PCI config read/write passthrough. */
399 case PCI_IOC_CFGREAD:
400 case PCI_IOC_CFGWRITE:
401 return pci_devioctl(sc->sc_pc, sc->sc_pcitag,
402 cmd, data, flags, l);
403
404 case WSDISPLAYIO_GET_BUSID:
405 return wsdisplayio_busid_pci(device_parent(sc->sc_dev),
406 sc->sc_pc, sc->sc_pcitag, data);
407
408 case WSDISPLAYIO_GINFO:
409 if (ms == NULL)
410 return (ENODEV);
411 wdf = (struct wsdisplay_fbinfo *)data;
412 wdf->width = ms->scr_ri.ri_width;
413 wdf->height = ms->scr_ri.ri_height;
414 wdf->depth = ms->scr_ri.ri_depth;
415 wdf->cmsize = 0;
416 return (0);
417
418 case WSDISPLAYIO_LINEBYTES:
419 *(uint *)data = fb->stride;
420 return (0);
421
422 case WSDISPLAYIO_GVIDEO:
423 *(int *)data = fb->blank ? WSDISPLAYIO_VIDEO_OFF :
424 WSDISPLAYIO_VIDEO_ON;
425 return (0);
426
427 case WSDISPLAYIO_SVIDEO:
428 lynxfb_blank(fb, *(int *)data);
429 return (0);
430
431 case WSDISPLAYIO_GETPARAM:
432 param = (struct wsdisplay_param *)data;
433 switch (param->param) {
434 case WSDISPLAYIO_PARAM_BACKLIGHT:
435 param->min = 0;
436 param->max = 1;
437 param->curval = fb->blank;
438 return (0);
439 }
440 break;
441
442 case WSDISPLAYIO_SETPARAM:
443 param = (struct wsdisplay_param *)data;
444 switch (param->param) {
445 case WSDISPLAYIO_PARAM_BACKLIGHT:
446 lynxfb_blank(fb, param->curval);
447 return (0);
448 }
449 break;
450 }
451 return (EPASSTHROUGH);
452 }
453
454 static paddr_t
455 lynxfb_mmap(void *v, void *vs, off_t offset, int prot)
456 {
457 struct vcons_data *vd = v;
458 struct lynxfb_softc *sc = vd->cookie;
459 struct rasops_info *ri = &sc->sc_fb->vcs.scr_ri;
460
461 if ((offset & PAGE_MASK) != 0)
462 return (-1);
463
464 if (offset < 0 || offset >= ri->ri_stride * ri->ri_height)
465 return (-1);
466
467 return bus_space_mmap(sc->sc_memt, offset, 0, prot,
468 BUS_SPACE_MAP_LINEAR | BUS_SPACE_MAP_PREFETCHABLE);
469 }
470
471 static void
472 lynxfb_init_screen(void *cookie, struct vcons_screen *scr,
473 int existing, long *defattr)
474 {
475 struct lynxfb_softc *sc = cookie;
476 struct lynxfb *fb = sc->sc_fb;
477 struct rasops_info *ri = &scr->scr_ri;
478
479 ri->ri_width = fb->width;
480 ri->ri_height = fb->height;
481 ri->ri_depth = fb->depth;
482 ri->ri_stride = fb->stride;
483 ri->ri_flg = RI_CENTER;
484 ri->ri_bits = fb->fbaddr;
485
486 #ifdef VCONS_DRAW_INTR
487 scr->scr_flags |= VCONS_DONT_READ;
488 #endif
489
490 if (existing)
491 ri->ri_flg |= RI_CLEAR;
492
493 rasops_init(ri, 0, 0);
494 ri->ri_caps = WSSCREEN_WSCOLORS;
495 rasops_reconfig(ri, fb->height / ri->ri_font->fontheight,
496 fb->width / ri->ri_font->fontwidth);
497
498 ri->ri_hw = scr;
499
500 if (fb->accel) {
501 ri->ri_ops.copycols = lynxfb_vcons_copycols;
502 ri->ri_ops.copyrows = lynxfb_vcons_copyrows;
503 ri->ri_ops.erasecols = lynxfb_vcons_erasecols;
504 ri->ri_ops.eraserows = lynxfb_vcons_eraserows;
505 }
506 }
507
508 /*
509 * Frame buffer initialization.
510 */
511 static int
512 lynxfb_setup(struct lynxfb *fb)
513 {
514 struct rasops_info *ri = &fb->vcs.scr_ri;
515 int error;
516
517 fb->dprt = fb->memt;
518 error = bus_space_subregion(fb->memt, fb->memh, SM7XX_DPR_BASE,
519 SMXXX_DPR_SIZE, &fb->dprh);
520 if (error != 0)
521 return (error);
522
523 fb->mmiot = fb->memt;
524 error = bus_space_subregion(fb->mmiot, fb->memh, SM7XX_MMIO_BASE,
525 SM7XX_MMIO_SIZE, &fb->mmioh);
526 if (error != 0)
527 return (error);
528
529 ri->ri_width = fb->width;
530 ri->ri_height = fb->height;
531 ri->ri_depth = fb->depth;
532 ri->ri_stride = fb->stride;
533 ri->ri_flg = RI_CENTER | RI_CLEAR | RI_NO_AUTO;
534 fb->fbaddr = ri->ri_bits = (void *)bus_space_vaddr(fb->memt, fb->memh);
535 ri->ri_hw = fb;
536
537 if (fb->flags & LYNXFB_FLAG_SWAPBR) {
538 switch (fb->depth) {
539 case 16:
540 ri->ri_rnum = 5;
541 ri->ri_rpos = 11;
542 ri->ri_gnum = 6;
543 ri->ri_gpos = 5;
544 ri->ri_bnum = 5;
545 ri->ri_bpos = 0;
546 break;
547 }
548 }
549
550 rasops_init(ri, 0, 0);
551 rasops_reconfig(ri, ri->ri_height / ri->ri_font->fontheight,
552 ri->ri_width / ri->ri_font->fontwidth);
553
554 fb->wsd.name = "std";
555 fb->wsd.ncols = ri->ri_cols;
556 fb->wsd.nrows = ri->ri_rows;
557 fb->wsd.textops = &ri->ri_ops;
558 fb->wsd.fontwidth = ri->ri_font->fontwidth;
559 fb->wsd.fontheight = ri->ri_font->fontheight;
560 fb->wsd.capabilities = ri->ri_caps;
561
562 /*
563 * Setup 2D acceleration whenever possible
564 */
565 if (lynxfb_wait(fb) == 0) {
566 fb->accel = 1;
567
568 DPR_WRITE(fb, DPR_CROP_TOPLEFT_COORDS, DPR_COORDS(0, 0));
569 /* use of width both times is intentional */
570 DPR_WRITE(fb, DPR_PITCH,
571 DPR_COORDS(ri->ri_width, ri->ri_width));
572 DPR_WRITE(fb, DPR_SRC_WINDOW,
573 DPR_COORDS(ri->ri_width, ri->ri_width));
574 DPR_WRITE(fb, DPR_BYTE_BIT_MASK, 0xffffffff);
575 DPR_WRITE(fb, DPR_COLOR_COMPARE_MASK, 0);
576 DPR_WRITE(fb, DPR_COLOR_COMPARE, 0);
577 DPR_WRITE(fb, DPR_SRC_BASE, 0);
578 DPR_WRITE(fb, DPR_DST_BASE, 0);
579 DPR_READ(fb, DPR_DST_BASE);
580
581 ri->ri_ops.copycols = lynxfb_copycols;
582 ri->ri_ops.copyrows = lynxfb_copyrows;
583 ri->ri_ops.erasecols = lynxfb_erasecols;
584 ri->ri_ops.eraserows = lynxfb_eraserows;
585 }
586
587 return (0);
588 }
589
590 static int
591 lynxfb_wait(struct lynxfb *fb)
592 {
593 uint32_t reg;
594 int i;
595
596 for (i = 10000; i > 0; i--) {
597 reg = lynxfb_vgats_read(fb, 0x16);
598 if ((reg & 0x18) == 0x10)
599 return (0);
600 delay(1);
601 }
602 return (EBUSY);
603 }
604
605 static void
606 lynxfb_copyrect(struct lynxfb *fb, int sx, int sy, int dx, int dy, int w, int h)
607 {
608 uint32_t dir;
609
610 /* Compute rop direction */
611 if (sy < dy || (sy == dy && sx <= dx)) {
612 sx += w - 1;
613 dx += w - 1;
614 sy += h - 1;
615 dy += h - 1;
616 dir = DE_CTRL_RTOL;
617 } else
618 dir = 0;
619
620 DPR_WRITE(fb, DPR_SRC_COORDS, DPR_COORDS(sx, sy));
621 DPR_WRITE(fb, DPR_DST_COORDS, DPR_COORDS(dx, dy));
622 DPR_WRITE(fb, DPR_SPAN_COORDS, DPR_COORDS(w, h));
623 DPR_WRITE(fb, DPR_DE_CTRL, DE_CTRL_START | DE_CTRL_ROP_ENABLE | dir |
624 (DE_CTRL_COMMAND_BITBLT << DE_CTRL_COMMAND_SHIFT) |
625 (DE_CTRL_ROP_SRC << DE_CTRL_ROP_SHIFT));
626 DPR_READ(fb, DPR_DE_CTRL);
627
628 lynxfb_wait(fb);
629 }
630
631 static void
632 lynxfb_fillrect(struct lynxfb *fb, int x, int y, int w, int h, int bg)
633 {
634 struct rasops_info *ri = &fb->vcs.scr_ri;
635
636 DPR_WRITE(fb, DPR_FG_COLOR, ri->ri_devcmap[bg]);
637 DPR_WRITE(fb, DPR_DST_COORDS, DPR_COORDS(x, y));
638 DPR_WRITE(fb, DPR_SPAN_COORDS, DPR_COORDS(w, h));
639 DPR_WRITE(fb, DPR_DE_CTRL, DE_CTRL_START | DE_CTRL_ROP_ENABLE |
640 (DE_CTRL_COMMAND_SOLIDFILL << DE_CTRL_COMMAND_SHIFT) |
641 (DE_CTRL_ROP_SRC << DE_CTRL_ROP_SHIFT));
642 DPR_READ(fb, DPR_DE_CTRL);
643
644 lynxfb_wait(fb);
645 }
646
647 static inline void
648 lynxfb_copyrows1(struct rasops_info *ri, int src, int dst, int num,
649 struct lynxfb *fb)
650 {
651 struct wsdisplay_font *f = ri->ri_font;
652
653 num *= f->fontheight;
654 src *= f->fontheight;
655 dst *= f->fontheight;
656
657 lynxfb_copyrect(fb, ri->ri_xorigin, ri->ri_yorigin + src,
658 ri->ri_xorigin, ri->ri_yorigin + dst, ri->ri_emuwidth, num);
659 }
660
661 static inline void
662 lynxfb_copycols1(struct rasops_info *ri, int row, int src, int dst, int num,
663 struct lynxfb *fb)
664 {
665 struct wsdisplay_font *f = ri->ri_font;
666
667 num *= f->fontwidth;
668 src *= f->fontwidth;
669 dst *= f->fontwidth;
670 row *= f->fontheight;
671
672 lynxfb_copyrect(fb, ri->ri_xorigin + src, ri->ri_yorigin + row,
673 ri->ri_xorigin + dst, ri->ri_yorigin + row, num, f->fontheight);
674 }
675
676 static inline void
677 lynxfb_erasecols1(struct rasops_info *ri, int row, int col, int num, long attr,
678 struct lynxfb *fb)
679 {
680 struct wsdisplay_font *f = ri->ri_font;
681 int32_t bg, fg, ul;
682
683 row *= f->fontheight;
684 col *= f->fontwidth;
685 num *= f->fontwidth;
686 rasops_unpack_attr(attr, &fg, &bg, &ul);
687
688 lynxfb_fillrect(fb, ri->ri_xorigin + col, ri->ri_yorigin + row,
689 num, f->fontheight, bg);
690 }
691
692 static inline void
693 lynxfb_eraserows1(struct rasops_info *ri, int row, int num, long attr,
694 struct lynxfb *fb)
695 {
696 struct wsdisplay_font *f = ri->ri_font;
697 int32_t bg, fg, ul;
698 int x, y, w;
699
700 if ((num == ri->ri_rows) && ISSET(ri->ri_flg, RI_FULLCLEAR)) {
701 num = ri->ri_height;
702 x = y = 0;
703 w = ri->ri_width;
704 } else {
705 num *= f->fontheight;
706 x = ri->ri_xorigin;
707 y = ri->ri_yorigin + row * f->fontheight;
708 w = ri->ri_emuwidth;
709 }
710 rasops_unpack_attr(attr, &fg, &bg, &ul);
711 lynxfb_fillrect(fb, x, y, w, num, bg);
712 }
713
714 static void
715 lynxfb_copyrows(void *cookie, int src, int dst, int num)
716 {
717 struct rasops_info *ri = cookie;
718 struct lynxfb *fb = ri->ri_hw;
719
720 lynxfb_copyrows1(ri, src, dst, num, fb);
721 }
722
723 static void
724 lynxfb_copycols(void *cookie, int row, int src, int dst, int num)
725 {
726 struct rasops_info *ri = cookie;
727 struct lynxfb *fb = ri->ri_hw;
728
729 lynxfb_copycols1(ri, row, src, dst, num, fb);
730 }
731
732 static void
733 lynxfb_erasecols(void *cookie, int row, int col, int num, long attr)
734 {
735 struct rasops_info *ri = cookie;
736 struct lynxfb *fb = ri->ri_hw;
737
738 lynxfb_erasecols1(ri, row, col, num, attr, fb);
739 }
740
741 static void
742 lynxfb_eraserows(void *cookie, int row, int num, long attr)
743 {
744 struct rasops_info *ri = cookie;
745 struct lynxfb *fb = ri->ri_hw;
746
747 lynxfb_eraserows1(ri, row, num, attr, fb);
748 }
749
750 static void
751 lynxfb_vcons_copyrows(void *cookie, int src, int dst, int num)
752 {
753 struct rasops_info *ri = cookie;
754 struct vcons_screen *scr = ri->ri_hw;
755 struct lynxfb_softc *sc = scr->scr_cookie;
756 struct lynxfb *fb = sc->sc_fb;
757
758 lynxfb_copyrows1(ri, src, dst, num, fb);
759 }
760
761 static void
762 lynxfb_vcons_copycols(void *cookie, int row, int src, int dst, int num)
763 {
764 struct rasops_info *ri = cookie;
765 struct vcons_screen *scr = ri->ri_hw;
766 struct lynxfb_softc *sc = scr->scr_cookie;
767 struct lynxfb *fb = sc->sc_fb;
768
769 lynxfb_copycols1(ri, row, src, dst, num, fb);
770 }
771
772 static void
773 lynxfb_vcons_erasecols(void *cookie, int row, int col, int num, long attr)
774 {
775 struct rasops_info *ri = cookie;
776 struct vcons_screen *scr = ri->ri_hw;
777 struct lynxfb_softc *sc = scr->scr_cookie;
778 struct lynxfb *fb = sc->sc_fb;
779
780 lynxfb_erasecols1(ri, row, col, num, attr, fb);
781 }
782
783 static void
784 lynxfb_vcons_eraserows(void *cookie, int row, int num, long attr)
785 {
786 struct rasops_info *ri = cookie;
787 struct vcons_screen *scr = ri->ri_hw;
788 struct lynxfb_softc *sc = scr->scr_cookie;
789 struct lynxfb *fb = sc->sc_fb;
790
791 lynxfb_eraserows1(ri, row, num, attr, fb);
792 }
793
794 static void
795 lynxfb_blank(struct lynxfb *fb, int blank)
796 {
797
798 fb->blank = blank;
799 if (!blank) {
800 lynxfb_vgats_write(fb, 0x31,
801 lynxfb_vgats_read(fb, 0x31) | 0x01);
802 } else {
803 lynxfb_vgats_write(fb, 0x21,
804 lynxfb_vgats_read(fb, 0x21) | 0x30);
805 lynxfb_vgats_write(fb, 0x31,
806 lynxfb_vgats_read(fb, 0x31) & ~0x01);
807 }
808 }
809