unichromefb.c revision 1.18.32.1 1 /* $NetBSD: unichromefb.c,v 1.18.32.1 2015/12/27 12:09:57 skrll Exp $ */
2
3 /*-
4 * Copyright (c) 2006, 2008 Jared D. McNeill <jmcneill (at) invisible.ca>
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 /*
30 * Copyright 1998-2006 VIA Technologies, Inc. All Rights Reserved.
31 * Copyright 2001-2006 S3 Graphics, Inc. All Rights Reserved.
32 *
33 * Permission is hereby granted, free of charge, to any person obtaining a
34 * copy of this software and associated documentation files (the "Software"),
35 * to deal in the Software without restriction, including without limitation
36 * the rights to use, copy, modify, merge, publish, distribute, sub license,
37 * and/or sell copies of the Software, and to permit persons to whom the
38 * Software is furnished to do so, subject to the following conditions:
39 *
40 * The above copyright notice and this permission notice (including the
41 * next paragraph) shall be included in all copies or substantial portions
42 * of the Software.
43 *
44 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
45 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
46 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
47 * THE AUTHOR(S) OR COPYRIGHT HOLDER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
48 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
49 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
50 * DEALINGS IN THE SOFTWARE.
51 */
52
53 #include <sys/cdefs.h>
54 __KERNEL_RCSID(0, "$NetBSD: unichromefb.c,v 1.18.32.1 2015/12/27 12:09:57 skrll Exp $");
55
56 #include <sys/param.h>
57 #include <sys/systm.h>
58 #include <sys/device.h>
59 #include <sys/malloc.h>
60
61 #include <sys/bus.h>
62
63 #include <dev/pci/pcivar.h>
64 #include <dev/pci/pcireg.h>
65 #include <dev/pci/pcidevs.h>
66 #include <dev/pci/pciio.h>
67
68 #include <dev/wscons/wsdisplayvar.h>
69 #include <dev/wscons/wsconsio.h>
70 #include <dev/wsfont/wsfont.h>
71 #include <dev/rasops/rasops.h>
72 #include <dev/wscons/wsdisplay_vconsvar.h>
73 #include <dev/pci/wsdisplay_pci.h>
74
75 #include <dev/pci/unichromereg.h>
76 #include <dev/pci/unichromemode.h>
77 #include <dev/pci/unichromehw.h>
78 #include <dev/pci/unichromeconfig.h>
79 #include <dev/pci/unichromeaccel.h>
80
81 #include "vga.h"
82
83 #if NVGA > 0
84 #include <dev/ic/mc6845reg.h>
85 #include <dev/ic/pcdisplayvar.h>
86 #include <dev/ic/vgareg.h>
87 #include <dev/ic/vgavar.h>
88 #endif
89
90 /* XXX */
91 #define UNICHROMEFB_DEPTH 16
92 #define UNICHROMEFB_MODE VIA_RES_1280X1024
93 #define UNICHROMEFB_WIDTH 1280
94 #define UNICHROMEFB_HEIGHT 1024
95
96 struct unichromefb_softc {
97 device_t sc_dev;
98 struct vcons_data sc_vd;
99 void * sc_fbbase;
100 unsigned int sc_fbaddr;
101 unsigned int sc_fbsize;
102 bus_addr_t sc_mmiobase;
103 bus_size_t sc_mmiosize;
104
105 bus_space_tag_t sc_iot;
106 bus_space_handle_t sc_ioh;
107
108 bus_space_tag_t sc_memt;
109 bus_space_handle_t sc_memh;
110 bus_space_tag_t sc_apmemt;
111 bus_space_handle_t sc_apmemh;
112
113 struct pci_attach_args sc_pa;
114
115 int sc_width;
116 int sc_height;
117 int sc_depth;
118 int sc_stride;
119
120 int sc_wsmode;
121
122 int sc_accel;
123 };
124
125 static int unichromefb_match(device_t, cfdata_t, void *);
126 static void unichromefb_attach(device_t, device_t, void *);
127
128 static int unichromefb_drm_print(void *, const char *);
129 static int unichromefb_drm_unmap(struct unichromefb_softc *);
130 static int unichromefb_drm_map(struct unichromefb_softc *);
131
132 struct wsscreen_descr unichromefb_stdscreen = {
133 "fb",
134 0, 0,
135 NULL,
136 8, 16,
137 WSSCREEN_WSCOLORS, NULL,
138 };
139
140 static int unichromefb_ioctl(void *, void *, u_long, void *, int,
141 struct lwp *);
142 static paddr_t unichromefb_mmap(void *, void *, off_t, int);
143
144 static void unichromefb_init_screen(void *, struct vcons_screen *,
145 int, long *);
146
147 /* hardware access */
148 static uint8_t uni_rd(struct unichromefb_softc *, int, uint8_t);
149 static void uni_wr(struct unichromefb_softc *, int, uint8_t, uint8_t);
150 static void uni_wr_mask(struct unichromefb_softc *, int, uint8_t,
151 uint8_t, uint8_t);
152 static void uni_wr_x(struct unichromefb_softc *, struct io_reg *, int);
153 static void uni_wr_dac(struct unichromefb_softc *, uint8_t, uint8_t,
154 uint8_t, uint8_t);
155
156 /* helpers */
157 static struct VideoModeTable * uni_getmode(int);
158 static void uni_setmode(struct unichromefb_softc *, int, int);
159 static void uni_crt_lock(struct unichromefb_softc *);
160 static void uni_crt_unlock(struct unichromefb_softc *);
161 static void uni_crt_enable(struct unichromefb_softc *);
162 static void uni_crt_disable(struct unichromefb_softc *);
163 static void uni_screen_enable(struct unichromefb_softc *);
164 static void uni_screen_disable(struct unichromefb_softc *);
165 static void uni_set_start(struct unichromefb_softc *);
166 static void uni_set_crtc(struct unichromefb_softc *,
167 struct crt_mode_table *, int, int, int);
168 static void uni_load_crtc(struct unichromefb_softc *, struct display_timing,
169 int);
170 static void uni_load_reg(struct unichromefb_softc *, int, int,
171 struct io_register *, int);
172 static void uni_fix_crtc(struct unichromefb_softc *);
173 static void uni_load_offset(struct unichromefb_softc *, int, int, int);
174 static void uni_load_fetchcnt(struct unichromefb_softc *, int, int, int);
175 static void uni_load_fifo(struct unichromefb_softc *, int, int, int);
176 static void uni_set_depth(struct unichromefb_softc *, int, int);
177 static uint32_t uni_get_clkval(struct unichromefb_softc *, int);
178 static void uni_set_vclk(struct unichromefb_softc *, uint32_t, int);
179 static void uni_init_dac(struct unichromefb_softc *, int);
180 static void uni_init_accel(struct unichromefb_softc *);
181 static void uni_set_accel_depth(struct unichromefb_softc *);
182
183 /* graphics ops */
184 static void uni_wait_idle(struct unichromefb_softc *);
185 static void uni_fillrect(struct unichromefb_softc *,
186 int, int, int, int, int);
187 static void uni_rectinvert(struct unichromefb_softc *,
188 int, int, int, int);
189 static void uni_bitblit(struct unichromefb_softc *, int, int, int, int,
190 int, int);
191 static void uni_setup_mono(struct unichromefb_softc *, int, int, int,
192 int, uint32_t, uint32_t);
193 #if notyet
194 static void uni_cursor_show(struct unichromefb_softc *);
195 static void uni_cursor_hide(struct unichromefb_softc *);
196 #endif
197
198 /* rasops glue */
199 static void uni_copycols(void *, int, int, int, int);
200 static void uni_copyrows(void *, int, int, int);
201 static void uni_erasecols(void *, int, int, int, long);
202 static void uni_eraserows(void *, int, int, long);
203 static void uni_cursor(void *, int, int, int);
204 static void uni_putchar(void *, int, int, u_int, long);
205
206 struct wsdisplay_accessops unichromefb_accessops = {
207 unichromefb_ioctl,
208 unichromefb_mmap,
209 NULL,
210 NULL,
211 NULL,
212 NULL,
213 NULL,
214 NULL,
215 };
216
217 static struct vcons_screen unichromefb_console_screen;
218
219 const struct wsscreen_descr *_unichromefb_scrlist[] = {
220 &unichromefb_stdscreen,
221 };
222
223 struct wsscreen_list unichromefb_screenlist = {
224 sizeof(_unichromefb_scrlist) / sizeof(struct wsscreen_descr *),
225 _unichromefb_scrlist
226 };
227
228 CFATTACH_DECL_NEW(unichromefb, sizeof(struct unichromefb_softc),
229 unichromefb_match, unichromefb_attach, NULL, NULL);
230
231 static int
232 unichromefb_match(device_t parent, cfdata_t match, void *opaque)
233 {
234 struct pci_attach_args *pa;
235
236 pa = (struct pci_attach_args *)opaque;
237
238 if (PCI_CLASS(pa->pa_class) != PCI_CLASS_DISPLAY ||
239 PCI_SUBCLASS(pa->pa_class) != PCI_SUBCLASS_DISPLAY_VGA)
240 return 0;
241
242 if (PCI_VENDOR(pa->pa_id) != PCI_VENDOR_VIATECH)
243 return 0;
244
245 switch (PCI_PRODUCT(pa->pa_id)) {
246 case PCI_PRODUCT_VIATECH_VT3314_IG:
247 return 10; /* beat vga(4) */
248 }
249
250 return 0;
251 }
252
253 static void
254 unichromefb_attach(device_t parent, device_t self, void *opaque)
255 {
256 struct unichromefb_softc *sc = device_private(self);
257 struct pci_attach_args *pa;
258 struct rasops_info *ri;
259 struct wsemuldisplaydev_attach_args aa;
260 uint8_t val;
261 long defattr;
262
263 pa = (struct pci_attach_args *)opaque;
264
265 sc->sc_dev = self;
266 sc->sc_width = UNICHROMEFB_WIDTH;
267 sc->sc_height = UNICHROMEFB_HEIGHT;
268 sc->sc_depth = UNICHROMEFB_DEPTH;
269 sc->sc_stride = sc->sc_width * (sc->sc_depth / 8);
270
271 sc->sc_wsmode = WSDISPLAYIO_MODE_EMUL;
272
273 sc->sc_iot = pa->pa_iot;
274 sc->sc_pa = *pa;
275
276 #if NVGA > 0
277 /* XXX vga_cnattach claims the I/O registers that we need;
278 * we need to nuke it here so we can take over.
279 */
280 vga_cndetach();
281 #endif
282
283 if (bus_space_map(sc->sc_iot, VIA_REGBASE, 0x20, 0, &sc->sc_ioh)) {
284 aprint_error(": failed to map I/O registers\n");
285 return;
286 }
287
288 sc->sc_apmemt = pa->pa_memt;
289 val = uni_rd(sc, VIASR, SR30);
290 sc->sc_fbaddr = val << 24;
291 val = uni_rd(sc, VIASR, SR39);
292 sc->sc_fbsize = val * (4*1024*1024);
293 if (sc->sc_fbsize < 16*1024*1024 || sc->sc_fbsize > 64*1024*1024)
294 sc->sc_fbsize = 16*1024*1024;
295 if (bus_space_map(sc->sc_apmemt, sc->sc_fbaddr, sc->sc_fbsize,
296 BUS_SPACE_MAP_LINEAR, &sc->sc_apmemh)) {
297 aprint_error(": failed to map aperture at 0x%08x/0x%x\n",
298 sc->sc_fbaddr, sc->sc_fbsize);
299 return;
300 }
301 sc->sc_fbbase = (void *)bus_space_vaddr(sc->sc_apmemt, sc->sc_apmemh);
302
303 if (pci_mapreg_map(pa, 0x14, PCI_MAPREG_TYPE_MEM, 0,
304 &sc->sc_memt, &sc->sc_memh, &sc->sc_mmiobase,
305 &sc->sc_mmiosize)) {
306 sc->sc_accel = 0;
307 aprint_error(": failed to map MMIO registers\n");
308 } else {
309 sc->sc_accel = 1;
310 }
311
312 aprint_naive("\n");
313 aprint_normal(": VIA UniChrome frame buffer\n");
314
315 if (sc->sc_accel)
316 aprint_normal_dev(self, "MMIO @0x%08x/0x%x\n",
317 (uint32_t)sc->sc_mmiobase,
318 (uint32_t)sc->sc_mmiosize);
319
320 ri = &unichromefb_console_screen.scr_ri;
321 memset(ri, 0, sizeof(struct rasops_info));
322
323 vcons_init(&sc->sc_vd, sc, &unichromefb_stdscreen,
324 &unichromefb_accessops);
325 sc->sc_vd.init_screen = unichromefb_init_screen;
326
327 uni_setmode(sc, UNICHROMEFB_MODE, sc->sc_depth);
328
329 uni_init_dac(sc, IGA1);
330 if (sc->sc_accel) {
331 uni_init_accel(sc);
332 uni_fillrect(sc, 0, 0, sc->sc_width, sc->sc_height, 0);
333 }
334
335 aprint_normal_dev(self, "FB @0x%08x (%dx%dx%d)\n",
336 sc->sc_fbaddr, sc->sc_width, sc->sc_height, sc->sc_depth);
337
338 unichromefb_console_screen.scr_flags |= VCONS_SCREEN_IS_STATIC;
339 vcons_init_screen(&sc->sc_vd, &unichromefb_console_screen, 1, &defattr);
340
341 unichromefb_stdscreen.ncols = ri->ri_cols;
342 unichromefb_stdscreen.nrows = ri->ri_rows;
343 unichromefb_stdscreen.textops = &ri->ri_ops;
344 unichromefb_stdscreen.capabilities = ri->ri_caps;
345 unichromefb_stdscreen.modecookie = NULL;
346
347 wsdisplay_cnattach(&unichromefb_stdscreen, ri, 0, 0, defattr);
348
349 aa.console = 1; /* XXX */
350 aa.scrdata = &unichromefb_screenlist;
351 aa.accessops = &unichromefb_accessops;
352 aa.accesscookie = &sc->sc_vd;
353
354 config_found(self, &aa, wsemuldisplaydevprint);
355
356 config_found_ia(self, "drm", opaque, unichromefb_drm_print);
357
358 return;
359 }
360
361 static int
362 unichromefb_drm_print(void *opaque, const char *pnp)
363 {
364 if (pnp)
365 aprint_normal("drm at %s", pnp);
366
367 return UNCONF;
368 }
369
370 static int
371 unichromefb_drm_unmap(struct unichromefb_softc *sc)
372 {
373 aprint_debug_dev(sc->sc_dev, "releasing bus resources\n");
374
375 bus_space_unmap(sc->sc_apmemt, sc->sc_apmemh, sc->sc_fbsize);
376 bus_space_unmap(sc->sc_memt, sc->sc_memh, sc->sc_mmiosize);
377 bus_space_unmap(sc->sc_iot, sc->sc_ioh, 0x20);
378
379 return 0;
380 }
381
382 static int
383 unichromefb_drm_map(struct unichromefb_softc *sc)
384 {
385 int rv;
386
387 rv = bus_space_map(sc->sc_iot, VIA_REGBASE, 0x20, 0,
388 &sc->sc_ioh);
389 if (rv) {
390 aprint_error_dev(sc->sc_dev, "failed to map I/O registers\n");
391 return rv;
392 }
393 rv = bus_space_map(sc->sc_apmemt, sc->sc_fbaddr, sc->sc_fbsize,
394 BUS_SPACE_MAP_LINEAR, &sc->sc_apmemh);
395 if (rv) {
396 aprint_error_dev(sc->sc_dev,
397 "failed to map aperture at 0x%08x/0x%x\n",
398 sc->sc_fbaddr, sc->sc_fbsize);
399 return rv;
400 }
401 sc->sc_fbbase = (void *)bus_space_vaddr(sc->sc_apmemt, sc->sc_apmemh);
402 rv = pci_mapreg_map(&sc->sc_pa, 0x14, PCI_MAPREG_TYPE_MEM, 0,
403 &sc->sc_memt, &sc->sc_memh, &sc->sc_mmiobase,
404 &sc->sc_mmiosize);
405 if (rv) {
406 aprint_error_dev(sc->sc_dev, "failed to map MMIO registers\n");
407 sc->sc_accel = 0;
408 }
409
410 uni_setmode(sc, UNICHROMEFB_MODE, sc->sc_depth);
411 uni_init_dac(sc, IGA1);
412 if (sc->sc_accel)
413 uni_init_accel(sc);
414
415 aprint_debug_dev(sc->sc_dev, "re-acquired bus resources\n");
416
417 return 0;
418 }
419
420 static int
421 unichromefb_ioctl(void *v, void *vs, u_long cmd, void *data, int flag,
422 struct lwp *l)
423 {
424 struct vcons_data *vd;
425 struct unichromefb_softc *sc;
426 struct wsdisplay_fbinfo *fb;
427
428 vd = (struct vcons_data *)v;
429 sc = (struct unichromefb_softc *)vd->cookie;
430
431 switch (cmd) {
432 case WSDISPLAYIO_GTYPE:
433 *(u_int *)data = WSDISPLAY_TYPE_PCIMISC;
434 return 0;
435 case WSDISPLAYIO_GINFO:
436 if (vd->active != NULL) {
437 fb = (struct wsdisplay_fbinfo *)data;
438 fb->width = sc->sc_width;
439 fb->height = sc->sc_height;
440 fb->depth = sc->sc_depth;
441 fb->cmsize = 256;
442 return 0;
443 } else
444 return ENODEV;
445 case WSDISPLAYIO_GVIDEO:
446 return ENODEV;
447 case WSDISPLAYIO_SVIDEO:
448 return ENODEV;
449 case WSDISPLAYIO_GETCMAP:
450 return EINVAL;
451 case WSDISPLAYIO_PUTCMAP:
452 return EINVAL;
453 case WSDISPLAYIO_LINEBYTES:
454 *(u_int *)data = sc->sc_stride;
455 return 0;
456 case WSDISPLAYIO_SMODE: {
457 int new_mode = *(int *)data;
458 if (new_mode != sc->sc_wsmode) {
459 sc->sc_wsmode = new_mode;
460 switch (new_mode) {
461 case WSDISPLAYIO_MODE_EMUL:
462 unichromefb_drm_map(sc);
463 vcons_redraw_screen(vd->active);
464 break;
465 default:
466 unichromefb_drm_unmap(sc);
467 break;
468 }
469 }
470 }
471 return 0;
472 case WSDISPLAYIO_SSPLASH:
473 return ENODEV;
474
475 /* PCI config read/write passthrough. */
476 case PCI_IOC_CFGREAD:
477 case PCI_IOC_CFGWRITE:
478 return (pci_devioctl(sc->sc_pa.pa_pc, sc->sc_pa.pa_tag,
479 cmd, data, flag, l));
480
481 case WSDISPLAYIO_GET_BUSID:
482 return wsdisplayio_busid_pci(sc->sc_dev,
483 sc->sc_pa.pa_pc, sc->sc_pa.pa_tag, data);
484
485 }
486
487 return EPASSTHROUGH;
488 }
489
490 static paddr_t
491 unichromefb_mmap(void *v, void *vs, off_t offset, int prot)
492 {
493 return -1;
494 }
495
496 static void
497 unichromefb_init_screen(void *c, struct vcons_screen *scr, int existing,
498 long *defattr)
499 {
500 struct unichromefb_softc *sc;
501 struct rasops_info *ri;
502
503 sc = (struct unichromefb_softc *)c;
504 ri = &scr->scr_ri;
505 ri->ri_flg = RI_CENTER;
506 ri->ri_depth = sc->sc_depth;
507 ri->ri_width = sc->sc_width;
508 ri->ri_height = sc->sc_height;
509 ri->ri_stride = sc->sc_stride;
510 ri->ri_bits = sc->sc_fbbase;
511 if (existing)
512 ri->ri_flg |= RI_CLEAR;
513
514 switch (ri->ri_depth) {
515 case 32:
516 ri->ri_rnum = ri->ri_gnum = ri->ri_bnum = 8;
517 ri->ri_rpos = 16;
518 ri->ri_gpos = 8;
519 ri->ri_bpos = 0;
520 break;
521 case 16:
522 ri->ri_rnum = 5;
523 ri->ri_gnum = 6;
524 ri->ri_bnum = 5;
525 ri->ri_rpos = 11;
526 ri->ri_gpos = 5;
527 ri->ri_bpos = 0;
528 break;
529 }
530
531 rasops_init(ri, sc->sc_height / 16, sc->sc_width / 8);
532 ri->ri_caps = WSSCREEN_WSCOLORS;
533 rasops_reconfig(ri, sc->sc_height / ri->ri_font->fontheight,
534 sc->sc_width / ri->ri_font->fontwidth);
535
536 ri->ri_hw = scr;
537 if (sc->sc_accel) {
538 ri->ri_ops.copyrows = uni_copyrows;
539 ri->ri_ops.copycols = uni_copycols;
540 ri->ri_ops.eraserows = uni_eraserows;
541 ri->ri_ops.erasecols = uni_erasecols;
542 ri->ri_ops.cursor = uni_cursor;
543 ri->ri_ops.putchar = uni_putchar;
544 }
545
546 return;
547 }
548
549 /*
550 * hardware access
551 */
552 static uint8_t
553 uni_rd(struct unichromefb_softc *sc, int off, uint8_t idx)
554 {
555 bus_space_write_1(sc->sc_iot, sc->sc_ioh, off, idx);
556 return bus_space_read_1(sc->sc_iot, sc->sc_ioh, off + 1);
557 }
558
559 static void
560 uni_wr(struct unichromefb_softc *sc, int off, uint8_t idx, uint8_t val)
561 {
562 bus_space_write_1(sc->sc_iot, sc->sc_ioh, off, idx);
563 bus_space_write_1(sc->sc_iot, sc->sc_ioh, off + 1, val);
564 }
565
566 static void
567 uni_wr_mask(struct unichromefb_softc *sc, int off, uint8_t idx,
568 uint8_t val, uint8_t mask)
569 {
570 uint8_t tmp;
571
572 bus_space_write_1(sc->sc_iot, sc->sc_ioh, off, idx);
573 tmp = bus_space_read_1(sc->sc_iot, sc->sc_ioh, off + 1);
574 bus_space_write_1(sc->sc_iot, sc->sc_ioh, off + 1,
575 ((val & mask) | (tmp & ~mask)));
576 }
577
578 static void
579 uni_wr_dac(struct unichromefb_softc *sc, uint8_t idx,
580 uint8_t r, uint8_t g, uint8_t b)
581 {
582 bus_space_write_1(sc->sc_iot, sc->sc_ioh, LUT_INDEX_WRITE, idx);
583 bus_space_write_1(sc->sc_iot, sc->sc_ioh, LUT_DATA, r);
584 bus_space_write_1(sc->sc_iot, sc->sc_ioh, LUT_DATA, g);
585 bus_space_write_1(sc->sc_iot, sc->sc_ioh, LUT_DATA, b);
586 }
587
588 static void
589 uni_wr_x(struct unichromefb_softc *sc, struct io_reg *tbl, int num)
590 {
591 int i;
592 uint8_t tmp;
593
594 for (i = 0; i < num; i++) {
595 bus_space_write_1(sc->sc_iot, sc->sc_ioh, tbl[i].port,
596 tbl[i].index);
597 tmp = bus_space_read_1(sc->sc_iot, sc->sc_ioh,
598 tbl[i].port + 1);
599 tmp = (tmp & (~tbl[i].mask)) | tbl[i].value;
600 bus_space_write_1(sc->sc_iot, sc->sc_ioh, tbl[i].index + 1,
601 tmp);
602 }
603 }
604
605 /*
606 * helpers
607 */
608 static struct VideoModeTable *
609 uni_getmode(int mode)
610 {
611 int i;
612
613 for (i = 0; i < NUM_TOTAL_MODETABLE; i++)
614 if (CLE266Modes[i].ModeIndex == mode)
615 return &CLE266Modes[i];
616
617 return NULL;
618 }
619
620 static void
621 uni_setmode(struct unichromefb_softc *sc, int idx, int bpp)
622 {
623 struct VideoModeTable *vtbl;
624 struct crt_mode_table *crt;
625 int i;
626
627 /* XXX */
628 vtbl = uni_getmode(idx);
629 if (vtbl == NULL)
630 panic("%s: unsupported mode: %d\n",
631 device_xname(sc->sc_dev), idx);
632
633 crt = vtbl->crtc;
634
635 uni_screen_disable(sc);
636
637 (void)bus_space_read_1(sc->sc_iot, sc->sc_ioh, VIAStatus);
638 bus_space_write_1(sc->sc_iot, sc->sc_ioh, VIAAR, 0);
639
640 /* XXX assume CN900 for now */
641 uni_wr_x(sc, CN900_ModeXregs, NUM_TOTAL_CN900_ModeXregs);
642
643 uni_crt_disable(sc);
644
645 /* Fill VPIT params */
646 bus_space_write_1(sc->sc_iot, sc->sc_ioh, VIAWMisc, VPIT.Misc);
647
648 /* Write sequencer */
649 for (i = 1; i <= StdSR; i++) {
650 bus_space_write_1(sc->sc_iot, sc->sc_ioh, VIASR, i);
651 bus_space_write_1(sc->sc_iot, sc->sc_ioh, VIASR + 1,
652 VPIT.SR[i - 1]);
653 }
654
655 uni_set_start(sc);
656
657 uni_set_crtc(sc, crt, idx, bpp / 8, IGA1);
658
659 for (i = 0; i < StdGR; i++) {
660 bus_space_write_1(sc->sc_iot, sc->sc_ioh, VIAGR, i);
661 bus_space_write_1(sc->sc_iot, sc->sc_ioh, VIAGR + 1,
662 VPIT.GR[i]);
663 }
664
665 for (i = 0; i < StdAR; i++) {
666 (void)bus_space_read_1(sc->sc_iot, sc->sc_ioh, VIAStatus);
667 bus_space_write_1(sc->sc_iot, sc->sc_ioh, VIAAR, i);
668 bus_space_write_1(sc->sc_iot, sc->sc_ioh, VIAAR,
669 VPIT.AR[i]);
670 }
671
672 (void)bus_space_read_1(sc->sc_iot, sc->sc_ioh, VIAStatus);
673 bus_space_write_1(sc->sc_iot, sc->sc_ioh, VIAAR, 0x20);
674
675 uni_set_crtc(sc, crt, idx, bpp / 8, IGA1);
676 /* set crt output path */
677 uni_wr_mask(sc, VIASR, SR16, 0x00, BIT6);
678
679 uni_crt_enable(sc);
680 uni_screen_enable(sc);
681
682 return;
683 }
684
685 static void
686 uni_crt_lock(struct unichromefb_softc *sc)
687 {
688 uni_wr_mask(sc, VIACR, CR11, BIT7, BIT7);
689 }
690
691 static void
692 uni_crt_unlock(struct unichromefb_softc *sc)
693 {
694 uni_wr_mask(sc, VIACR, CR11, 0, BIT7);
695 uni_wr_mask(sc, VIACR, CR47, 0, BIT0);
696 }
697
698 static void
699 uni_crt_enable(struct unichromefb_softc *sc)
700 {
701 uni_wr_mask(sc, VIACR, CR36, 0, BIT5+BIT4);
702 }
703
704 static void
705 uni_crt_disable(struct unichromefb_softc *sc)
706 {
707 uni_wr_mask(sc, VIACR, CR36, BIT5+BIT4, BIT5+BIT4);
708 }
709
710 static void
711 uni_screen_enable(struct unichromefb_softc *sc)
712 {
713 uni_wr_mask(sc, VIASR, SR01, 0, BIT5);
714 }
715
716 static void
717 uni_screen_disable(struct unichromefb_softc *sc)
718 {
719 uni_wr_mask(sc, VIASR, SR01, 0x20, BIT5);
720 }
721
722 static void
723 uni_set_start(struct unichromefb_softc *sc)
724 {
725 uni_crt_unlock(sc);
726
727 uni_wr(sc, VIACR, CR0C, 0x00);
728 uni_wr(sc, VIACR, CR0D, 0x00);
729 uni_wr(sc, VIACR, CR34, 0x00);
730 uni_wr_mask(sc, VIACR, CR48, 0x00, BIT0 + BIT1);
731
732 uni_wr(sc, VIACR, CR62, 0x00);
733 uni_wr(sc, VIACR, CR63, 0x00);
734 uni_wr(sc, VIACR, CR64, 0x00);
735 uni_wr(sc, VIACR, CRA3, 0x00);
736
737 uni_crt_lock(sc);
738 }
739
740 static void
741 uni_set_crtc(struct unichromefb_softc *sc, struct crt_mode_table *ctbl,
742 int mode, int bpp_byte, int iga)
743 {
744 struct VideoModeTable *vtbl;
745 struct display_timing crtreg;
746 int i;
747 int index;
748 int haddr, vaddr;
749 uint8_t val;
750 uint32_t pll_d_n;
751
752 index = 0;
753
754 vtbl = uni_getmode(mode);
755 for (i = 0; i < vtbl->mode_array; i++) {
756 index = i;
757 if (ctbl[i].refresh_rate == 60)
758 break;
759 }
760
761 crtreg = ctbl[index].crtc;
762
763 haddr = crtreg.hor_addr;
764 vaddr = crtreg.ver_addr;
765
766 val = bus_space_read_1(sc->sc_iot, sc->sc_ioh, VIARMisc);
767 if (ctbl[index].h_sync_polarity == NEGATIVE) {
768 if (ctbl[index].v_sync_polarity == NEGATIVE)
769 bus_space_write_1(sc->sc_iot, sc->sc_ioh, VIAWMisc,
770 (val & (~(BIT6+BIT7))) | (BIT6+BIT7));
771 else
772 bus_space_write_1(sc->sc_iot, sc->sc_ioh, VIAWMisc,
773 (val & (~(BIT6+BIT7))) | (BIT6));
774 } else {
775 if (ctbl[index].v_sync_polarity == NEGATIVE)
776 bus_space_write_1(sc->sc_iot, sc->sc_ioh, VIAWMisc,
777 (val & (~(BIT6+BIT7))) | (BIT7));
778 else
779 bus_space_write_1(sc->sc_iot, sc->sc_ioh, VIAWMisc,
780 (val & (~(BIT6+BIT7))));
781 }
782
783 if (iga == IGA1) {
784 uni_crt_unlock(sc);
785 uni_wr(sc, VIACR, CR09, 0x00);
786 uni_wr_mask(sc, VIACR, CR11, 0x00, BIT4+BIT5+BIT6);
787 uni_wr_mask(sc, VIACR, CR17, 0x00, BIT7);
788 }
789
790 uni_load_crtc(sc, crtreg, iga);
791 uni_fix_crtc(sc);
792 uni_crt_lock(sc);
793 uni_wr_mask(sc, VIACR, CR17, 0x80, BIT7);
794
795 uni_load_offset(sc, haddr, bpp_byte, iga);
796 uni_load_fetchcnt(sc, haddr, bpp_byte, iga);
797 uni_load_fifo(sc, iga, haddr, vaddr);
798
799 uni_set_depth(sc, bpp_byte, iga);
800 pll_d_n = uni_get_clkval(sc, ctbl[index].clk);
801 uni_set_vclk(sc, pll_d_n, iga);
802 }
803
804 static void
805 uni_load_crtc(struct unichromefb_softc *sc,
806 struct display_timing device_timing, int iga)
807 {
808 int regnum, val;
809 struct io_register *reg;
810 int i;
811
812 regnum = val = 0;
813 reg = NULL;
814
815 uni_crt_unlock(sc);
816
817 for (i = 0; i < 12; i++) {
818 switch (iga) {
819 case IGA1:
820 switch (i) {
821 case H_TOTAL_INDEX:
822 val = IGA1_HOR_TOTAL_FORMULA(
823 device_timing.hor_total);
824 regnum = iga1_crtc_reg.hor_total.reg_num;
825 reg = iga1_crtc_reg.hor_total.reg;
826 break;
827 case H_ADDR_INDEX:
828 val = IGA1_HOR_ADDR_FORMULA(
829 device_timing.hor_addr);
830 regnum = iga1_crtc_reg.hor_addr.reg_num;
831 reg = iga1_crtc_reg.hor_addr.reg;
832 break;
833 case H_BLANK_START_INDEX:
834 val = IGA1_HOR_BLANK_START_FORMULA(
835 device_timing.hor_blank_start);
836 regnum = iga1_crtc_reg.hor_blank_start.reg_num;
837 reg = iga1_crtc_reg.hor_blank_start.reg;
838 break;
839 case H_BLANK_END_INDEX:
840 val = IGA1_HOR_BLANK_END_FORMULA(
841 device_timing.hor_blank_start,
842 device_timing.hor_blank_end);
843 regnum = iga1_crtc_reg.hor_blank_end.reg_num;
844 reg = iga1_crtc_reg.hor_blank_end.reg;
845 break;
846 case H_SYNC_START_INDEX:
847 val = IGA1_HOR_SYNC_START_FORMULA(
848 device_timing.hor_sync_start);
849 regnum = iga1_crtc_reg.hor_sync_start.reg_num;
850 reg = iga1_crtc_reg.hor_sync_start.reg;
851 break;
852 case H_SYNC_END_INDEX:
853 val = IGA1_HOR_SYNC_END_FORMULA(
854 device_timing.hor_sync_start,
855 device_timing.hor_sync_end);
856 regnum = iga1_crtc_reg.hor_sync_end.reg_num;
857 reg = iga1_crtc_reg.hor_sync_end.reg;
858 break;
859 case V_TOTAL_INDEX:
860 val = IGA1_VER_TOTAL_FORMULA(
861 device_timing.ver_total);
862 regnum = iga1_crtc_reg.ver_total.reg_num;
863 reg = iga1_crtc_reg.ver_total.reg;
864 break;
865 case V_ADDR_INDEX:
866 val = IGA1_VER_ADDR_FORMULA(
867 device_timing.ver_addr);
868 regnum = iga1_crtc_reg.ver_addr.reg_num;
869 reg = iga1_crtc_reg.ver_addr.reg;
870 break;
871 case V_BLANK_START_INDEX:
872 val = IGA1_VER_BLANK_START_FORMULA(
873 device_timing.ver_blank_start);
874 regnum = iga1_crtc_reg.ver_blank_start.reg_num;
875 reg = iga1_crtc_reg.ver_blank_start.reg;
876 break;
877 case V_BLANK_END_INDEX:
878 val = IGA1_VER_BLANK_END_FORMULA(
879 device_timing.ver_blank_start,
880 device_timing.ver_blank_end);
881 regnum = iga1_crtc_reg.ver_blank_end.reg_num;
882 reg = iga1_crtc_reg.ver_blank_end.reg;
883 break;
884 case V_SYNC_START_INDEX:
885 val = IGA1_VER_SYNC_START_FORMULA(
886 device_timing.ver_sync_start);
887 regnum = iga1_crtc_reg.ver_sync_start.reg_num;
888 reg = iga1_crtc_reg.ver_sync_start.reg;
889 break;
890 case V_SYNC_END_INDEX:
891 val = IGA1_VER_SYNC_END_FORMULA(
892 device_timing.ver_sync_start,
893 device_timing.ver_sync_end);
894 regnum = iga1_crtc_reg.ver_sync_end.reg_num;
895 reg = iga1_crtc_reg.ver_sync_end.reg;
896 break;
897 default:
898 aprint_error_dev(sc->sc_dev,
899 "unknown index %d while setting up CRTC\n",
900 i);
901 break;
902 }
903 break;
904 case IGA2:
905 aprint_error_dev(sc->sc_dev, "%s: IGA2 not supported\n",
906 __func__);
907 break;
908 }
909
910 uni_load_reg(sc, val, regnum, reg, VIACR);
911 }
912
913 uni_crt_lock(sc);
914 }
915
916 static void
917 uni_load_reg(struct unichromefb_softc *sc, int timing, int regnum,
918 struct io_register *reg, int type)
919 {
920 int regmask, bitnum, data;
921 int i, j;
922 int shift_next_reg;
923 int startidx, endidx, cridx;
924 uint16_t getbit;
925
926 bitnum = 0;
927
928 for (i = 0; i < regnum; i++) {
929 regmask = data = 0;
930 startidx = reg[i].start_bit;
931 endidx = reg[i].end_bit;
932 cridx = reg[i].io_addr;
933
934 shift_next_reg = bitnum;
935
936 for (j = startidx; j <= endidx; j++) {
937 regmask = regmask | (BIT0 << j);
938 getbit = (timing & (BIT0 << bitnum));
939 data = data | ((getbit >> shift_next_reg) << startidx);
940 ++bitnum;
941 }
942
943 if (type == VIACR)
944 uni_wr_mask(sc, VIACR, cridx, data, regmask);
945 else
946 uni_wr_mask(sc, VIASR, cridx, data, regmask);
947 }
948
949 return;
950 }
951
952 static void
953 uni_fix_crtc(struct unichromefb_softc *sc)
954 {
955 uni_wr_mask(sc, VIACR, CR03, 0x80, BIT7);
956 uni_wr(sc, VIACR, CR18, 0xff);
957 uni_wr_mask(sc, VIACR, CR07, 0x10, BIT4);
958 uni_wr_mask(sc, VIACR, CR09, 0x40, BIT6);
959 uni_wr_mask(sc, VIACR, CR35, 0x10, BIT4);
960 uni_wr_mask(sc, VIACR, CR33, 0x06, BIT0+BIT1+BIT2);
961 uni_wr(sc, VIACR, CR17, 0xe3);
962 uni_wr(sc, VIACR, CR08, 0x00);
963 uni_wr(sc, VIACR, CR14, 0x00);
964
965 return;
966 }
967
968 static void
969 uni_load_offset(struct unichromefb_softc *sc, int haddr, int bpp, int iga)
970 {
971
972 switch (iga) {
973 case IGA1:
974 uni_load_reg(sc,
975 IGA1_OFFSET_FORMULA(haddr, bpp),
976 offset_reg.iga1_offset_reg.reg_num,
977 offset_reg.iga1_offset_reg.reg,
978 VIACR);
979 break;
980 default:
981 aprint_error_dev(sc->sc_dev, "%s: only IGA1 is supported\n",
982 __func__);
983 break;
984 }
985
986 return;
987 }
988
989 static void
990 uni_load_fetchcnt(struct unichromefb_softc *sc, int haddr, int bpp, int iga)
991 {
992
993 switch (iga) {
994 case IGA1:
995 uni_load_reg(sc,
996 IGA1_FETCH_COUNT_FORMULA(haddr, bpp),
997 fetch_count_reg.iga1_fetch_count_reg.reg_num,
998 fetch_count_reg.iga1_fetch_count_reg.reg,
999 VIASR);
1000 break;
1001 default:
1002 aprint_error_dev(sc->sc_dev, "%s: only IGA1 is supported\n",
1003 __func__);
1004 break;
1005 }
1006
1007 return;
1008 }
1009
1010 static void
1011 uni_load_fifo(struct unichromefb_softc *sc, int iga, int horact, int veract)
1012 {
1013 int val, regnum;
1014 struct io_register *reg;
1015 int iga1_fifo_max_depth, iga1_fifo_threshold;
1016 int iga1_fifo_high_threshold, iga1_display_queue_expire_num;
1017
1018 reg = NULL;
1019 iga1_fifo_max_depth = iga1_fifo_threshold = 0;
1020 iga1_fifo_high_threshold = iga1_display_queue_expire_num = 0;
1021
1022 switch (iga) {
1023 case IGA1:
1024 /* XXX if (type == CN900) { */
1025 iga1_fifo_max_depth = CN900_IGA1_FIFO_MAX_DEPTH;
1026 iga1_fifo_threshold = CN900_IGA1_FIFO_THRESHOLD;
1027 iga1_fifo_high_threshold = CN900_IGA1_FIFO_HIGH_THRESHOLD;
1028 if (horact > 1280 && veract > 1024)
1029 iga1_display_queue_expire_num = 16;
1030 else
1031 iga1_display_queue_expire_num =
1032 CN900_IGA1_DISPLAY_QUEUE_EXPIRE_NUM;
1033 /* XXX } */
1034
1035 /* set display FIFO depth select */
1036 val = IGA1_FIFO_DEPTH_SELECT_FORMULA(iga1_fifo_max_depth);
1037 regnum =
1038 display_fifo_depth_reg.iga1_fifo_depth_select_reg.reg_num;
1039 reg = display_fifo_depth_reg.iga1_fifo_depth_select_reg.reg;
1040 uni_load_reg(sc, val, regnum, reg, VIASR);
1041
1042 /* set display FIFO threshold select */
1043 val = IGA1_FIFO_THRESHOLD_FORMULA(iga1_fifo_threshold);
1044 regnum = fifo_threshold_select_reg.iga1_fifo_threshold_select_reg.reg_num;
1045 reg = fifo_threshold_select_reg.iga1_fifo_threshold_select_reg.reg;
1046 uni_load_reg(sc, val, regnum, reg, VIASR);
1047
1048 /* set display FIFO high threshold select */
1049 val = IGA1_FIFO_HIGH_THRESHOLD_FORMULA(iga1_fifo_high_threshold);
1050 regnum = fifo_high_threshold_select_reg.iga1_fifo_high_threshold_select_reg.reg_num;
1051 reg = fifo_high_threshold_select_reg.iga1_fifo_high_threshold_select_reg.reg;
1052 uni_load_reg(sc, val, regnum, reg, VIASR);
1053
1054 /* set display queue expire num */
1055 val = IGA1_DISPLAY_QUEUE_EXPIRE_NUM_FORMULA(iga1_display_queue_expire_num);
1056 regnum = display_queue_expire_num_reg.iga1_display_queue_expire_num_reg.reg_num;
1057 reg = display_queue_expire_num_reg.iga1_display_queue_expire_num_reg.reg;
1058 uni_load_reg(sc, val, regnum, reg, VIASR);
1059
1060 break;
1061 default:
1062 aprint_error_dev(sc->sc_dev, "%s: only IGA1 is supported\n",
1063 __func__);
1064 break;
1065 }
1066
1067 return;
1068 }
1069
1070 static void
1071 uni_set_depth(struct unichromefb_softc *sc, int bpp, int iga)
1072 {
1073 switch (iga) {
1074 case IGA1:
1075 switch (bpp) {
1076 case MODE_32BPP:
1077 uni_wr_mask(sc, VIASR, SR15, 0xae, 0xfe);
1078 break;
1079 case MODE_16BPP:
1080 uni_wr_mask(sc, VIASR, SR15, 0xb6, 0xfe);
1081 break;
1082 case MODE_8BPP:
1083 uni_wr_mask(sc, VIASR, SR15, 0x22, 0xfe);
1084 break;
1085 default:
1086 aprint_error_dev(sc->sc_dev,
1087 "%s: mode (%d) unsupported\n", __func__, bpp);
1088 }
1089 break;
1090 default:
1091 aprint_error_dev(sc->sc_dev, "%s: only IGA1 is supported\n",
1092 __func__);
1093 break;
1094 }
1095 }
1096
1097 static uint32_t
1098 uni_get_clkval(struct unichromefb_softc *sc, int clk)
1099 {
1100 int i;
1101
1102 for (i = 0; i < NUM_TOTAL_PLL_TABLE; i++) {
1103 if (clk == pll_value[i].clk) {
1104 /* XXX only CN900 supported for now */
1105 return pll_value[i].k800_pll;
1106 }
1107 }
1108
1109 aprint_error_dev(sc->sc_dev, "can't find matching PLL value\n");
1110
1111 return 0;
1112 }
1113
1114 static void
1115 uni_set_vclk(struct unichromefb_softc *sc, uint32_t clk, int iga)
1116 {
1117 uint8_t val;
1118
1119 /* hardware reset on */
1120 uni_wr_mask(sc, VIACR, CR17, 0x00, BIT7);
1121
1122 switch (iga) {
1123 case IGA1:
1124 /* XXX only CN900 is supported */
1125 uni_wr(sc, VIASR, SR44, clk / 0x10000);
1126 uni_wr(sc, VIASR, SR45, (clk & 0xffff) / 0x100);
1127 uni_wr(sc, VIASR, SR46, clk % 0x100);
1128 break;
1129 default:
1130 aprint_error_dev(sc->sc_dev, "%s: only IGA1 is supported\n",
1131 __func__);
1132 break;
1133 }
1134
1135 /* hardware reset off */
1136 uni_wr_mask(sc, VIACR, CR17, 0x80, BIT7);
1137
1138 /* reset pll */
1139 switch (iga) {
1140 case IGA1:
1141 uni_wr_mask(sc, VIASR, SR40, 0x02, BIT1);
1142 uni_wr_mask(sc, VIASR, SR40, 0x00, BIT1);
1143 break;
1144 }
1145
1146 /* good to go */
1147 val = bus_space_read_1(sc->sc_iot, sc->sc_ioh, VIARMisc);
1148 val |= (BIT2+BIT3);
1149 bus_space_write_1(sc->sc_iot, sc->sc_ioh, VIAWMisc, val);
1150
1151 return;
1152 }
1153
1154 static void
1155 uni_init_dac(struct unichromefb_softc *sc, int iga)
1156 {
1157 int i;
1158
1159 /* XXX only IGA1 for now */
1160 uni_wr_mask(sc, VIASR, SR1A, 0x00, BIT0);
1161 uni_wr_mask(sc, VIASR, SR18, 0x00, BIT7+BIT6);
1162 for (i = 0; i < 256; i++)
1163 uni_wr_dac(sc, i,
1164 palLUT_table[i].red, palLUT_table[i].green, palLUT_table[i].blue);
1165
1166 uni_wr_mask(sc, VIASR, SR18, 0xc0, BIT7+BIT6);
1167
1168 return;
1169 }
1170
1171 static void
1172 uni_init_accel(struct unichromefb_softc *sc)
1173 {
1174
1175 /* init 2D engine regs to reset 2D engine */
1176 MMIO_OUT32(VIA_REG_GEMODE, 0);
1177 MMIO_OUT32(VIA_REG_SRCPOS, 0);
1178 MMIO_OUT32(VIA_REG_DSTPOS, 0);
1179 MMIO_OUT32(VIA_REG_DIMENSION, 0);
1180 MMIO_OUT32(VIA_REG_PATADDR, 0);
1181 MMIO_OUT32(VIA_REG_FGCOLOR, 0);
1182 MMIO_OUT32(VIA_REG_BGCOLOR, 0);
1183 MMIO_OUT32(VIA_REG_CLIPTL, 0);
1184 MMIO_OUT32(VIA_REG_CLIPBR, 0);
1185 MMIO_OUT32(VIA_REG_OFFSET, 0);
1186 MMIO_OUT32(VIA_REG_KEYCONTROL, 0);
1187 MMIO_OUT32(VIA_REG_SRCBASE, 0);
1188 MMIO_OUT32(VIA_REG_DSTBASE, 0);
1189 MMIO_OUT32(VIA_REG_PITCH, 0);
1190 MMIO_OUT32(VIA_REG_MONOPAT1, 0);
1191
1192 /* init AGP and VQ registers */
1193 MMIO_OUT32(VIA_REG_TRANSET, 0x00100000);
1194 MMIO_OUT32(VIA_REG_TRANSPACE, 0x00000000);
1195 MMIO_OUT32(VIA_REG_TRANSPACE, 0x00333004);
1196 MMIO_OUT32(VIA_REG_TRANSPACE, 0x60000000);
1197 MMIO_OUT32(VIA_REG_TRANSPACE, 0x61000000);
1198 MMIO_OUT32(VIA_REG_TRANSPACE, 0x62000000);
1199 MMIO_OUT32(VIA_REG_TRANSPACE, 0x63000000);
1200 MMIO_OUT32(VIA_REG_TRANSPACE, 0x64000000);
1201 MMIO_OUT32(VIA_REG_TRANSPACE, 0x7d000000);
1202
1203 MMIO_OUT32(VIA_REG_TRANSET, 0xfe020000);
1204 MMIO_OUT32(VIA_REG_TRANSPACE, 0x00000000);
1205
1206 /* disable VQ */
1207 MMIO_OUT32(VIA_REG_TRANSET, 0x00fe0000);
1208 MMIO_OUT32(VIA_REG_TRANSPACE, 0x00000004);
1209 MMIO_OUT32(VIA_REG_TRANSPACE, 0x40008c0f);
1210 MMIO_OUT32(VIA_REG_TRANSPACE, 0x44000000);
1211 MMIO_OUT32(VIA_REG_TRANSPACE, 0x45080c04);
1212 MMIO_OUT32(VIA_REG_TRANSPACE, 0x46800408);
1213
1214 uni_set_accel_depth(sc);
1215
1216 MMIO_OUT32(VIA_REG_SRCBASE, 0);
1217 MMIO_OUT32(VIA_REG_DSTBASE, 0);
1218
1219 MMIO_OUT32(VIA_REG_PITCH, VIA_PITCH_ENABLE |
1220 (((sc->sc_width * sc->sc_depth >> 3) >> 3) |
1221 (((sc->sc_width * sc->sc_depth >> 3) >> 3) << 16)));
1222
1223 return;
1224 }
1225
1226 static void
1227 uni_set_accel_depth(struct unichromefb_softc *sc)
1228 {
1229 uint32_t gemode;
1230
1231 gemode = MMIO_IN32(0x04) & 0xfffffcff;
1232
1233 switch (sc->sc_depth) {
1234 case 32:
1235 gemode |= VIA_GEM_32bpp;
1236 break;
1237 case 16:
1238 gemode |= VIA_GEM_16bpp;
1239 break;
1240 default:
1241 gemode |= VIA_GEM_8bpp;
1242 break;
1243 }
1244
1245 /* set colour depth and pitch */
1246 MMIO_OUT32(VIA_REG_GEMODE, gemode);
1247
1248 return;
1249 }
1250
1251 static void
1252 uni_wait_idle(struct unichromefb_softc *sc)
1253 {
1254 int loop = 0;
1255
1256 while (!(MMIO_IN32(VIA_REG_STATUS) & VIA_VR_QUEUE_BUSY) &&
1257 (loop++ < MAXLOOP))
1258 ;
1259
1260 while ((MMIO_IN32(VIA_REG_STATUS) &
1261 (VIA_CMD_RGTR_BUSY | VIA_2D_ENG_BUSY | VIA_3D_ENG_BUSY)) &&
1262 (loop++ < MAXLOOP))
1263 ;
1264
1265 if (loop >= MAXLOOP)
1266 aprint_error_dev(sc->sc_dev, "engine stall\n");
1267
1268 return;
1269 }
1270
1271 static void
1272 uni_fillrect(struct unichromefb_softc *sc, int x, int y, int width,
1273 int height, int colour)
1274 {
1275
1276 uni_wait_idle(sc);
1277
1278 MMIO_OUT32(VIA_REG_SRCPOS, 0);
1279 MMIO_OUT32(VIA_REG_SRCBASE, 0);
1280 MMIO_OUT32(VIA_REG_DSTBASE, 0);
1281 MMIO_OUT32(VIA_REG_PITCH, VIA_PITCH_ENABLE |
1282 (((sc->sc_width * sc->sc_depth >> 3) >> 3) |
1283 (((sc->sc_width * sc->sc_depth >> 3) >> 3) << 16)));
1284 MMIO_OUT32(VIA_REG_DSTPOS, ((y << 16) | x));
1285 MMIO_OUT32(VIA_REG_DIMENSION,
1286 (((height - 1) << 16) | (width - 1)));
1287 MMIO_OUT32(VIA_REG_FGCOLOR, colour);
1288 MMIO_OUT32(VIA_REG_GECMD, (0x01 | 0x2000 | 0xf0 << 24));
1289
1290 return;
1291 }
1292
1293 static void
1294 uni_rectinvert(struct unichromefb_softc *sc, int x, int y, int width,
1295 int height)
1296 {
1297
1298 uni_wait_idle(sc);
1299
1300 MMIO_OUT32(VIA_REG_SRCPOS, 0);
1301 MMIO_OUT32(VIA_REG_SRCBASE, 0);
1302 MMIO_OUT32(VIA_REG_DSTBASE, 0);
1303 MMIO_OUT32(VIA_REG_PITCH, VIA_PITCH_ENABLE |
1304 (((sc->sc_width * sc->sc_depth >> 3) >> 3) |
1305 (((sc->sc_width * sc->sc_depth >> 3) >> 3) << 16)));
1306 MMIO_OUT32(VIA_REG_DSTPOS, ((y << 16) | x));
1307 MMIO_OUT32(VIA_REG_DIMENSION,
1308 (((height - 1) << 16) | (width - 1)));
1309 MMIO_OUT32(VIA_REG_GECMD, (0x01 | 0x2000 | 0x55 << 24));
1310
1311 return;
1312 }
1313
1314 static void
1315 uni_bitblit(struct unichromefb_softc *sc, int xs, int ys, int xd, int yd, int width, int height)
1316 {
1317 uint32_t dir;
1318
1319 dir = 0;
1320
1321 if (ys < yd) {
1322 yd += height - 1;
1323 ys += height - 1;
1324 dir |= 0x4000;
1325 }
1326
1327 if (xs < xd) {
1328 xd += width - 1;
1329 xs += width - 1;
1330 dir |= 0x8000;
1331 }
1332
1333 uni_wait_idle(sc);
1334
1335 MMIO_OUT32(VIA_REG_SRCBASE, 0);
1336 MMIO_OUT32(VIA_REG_DSTBASE, 0);
1337 MMIO_OUT32(VIA_REG_PITCH, VIA_PITCH_ENABLE |
1338 (((sc->sc_width * sc->sc_depth >> 3) >> 3) |
1339 (((sc->sc_width * sc->sc_depth >> 3) >> 3) << 16)));
1340 MMIO_OUT32(VIA_REG_SRCPOS, ys << 16 | xs);
1341 MMIO_OUT32(VIA_REG_DSTPOS, yd << 16 | xd);
1342 MMIO_OUT32(VIA_REG_DIMENSION, ((height - 1) << 16) | (width - 1));
1343 MMIO_OUT32(VIA_REG_GECMD, (0x01 | dir | (0xcc << 24)));
1344
1345 return;
1346 }
1347
1348 static void
1349 uni_setup_mono(struct unichromefb_softc *sc, int xd, int yd, int width, int height,
1350 uint32_t fg, uint32_t bg)
1351 {
1352
1353 uni_wait_idle(sc);
1354
1355 MMIO_OUT32(VIA_REG_SRCBASE, 0);
1356 MMIO_OUT32(VIA_REG_DSTBASE, 0);
1357 MMIO_OUT32(VIA_REG_PITCH, VIA_PITCH_ENABLE |
1358 (((sc->sc_width * sc->sc_depth >> 3) >> 3) |
1359 (((sc->sc_width * sc->sc_depth >> 3) >> 3) << 16)));
1360 MMIO_OUT32(VIA_REG_SRCPOS, 0);
1361 MMIO_OUT32(VIA_REG_DSTPOS, (yd << 16) | xd);
1362 MMIO_OUT32(VIA_REG_DIMENSION, ((height - 1) << 16) | (width - 1));
1363 MMIO_OUT32(VIA_REG_FGCOLOR, fg);
1364 MMIO_OUT32(VIA_REG_BGCOLOR, bg);
1365 MMIO_OUT32(VIA_REG_GECMD, 0xcc020142);
1366
1367 return;
1368 }
1369
1370 #if notyet
1371 static void
1372 uni_cursor_show(struct unichromefb_softc *sc)
1373 {
1374 uint32_t val;
1375
1376 val = MMIO_IN32(VIA_REG_CURSOR_MODE);
1377 val |= 1;
1378 MMIO_OUT32(VIA_REG_CURSOR_MODE, val);
1379
1380 return;
1381 }
1382
1383 static void
1384 uni_cursor_hide(struct unichromefb_softc *sc)
1385 {
1386 uint32_t val;
1387
1388 val = MMIO_IN32(VIA_REG_CURSOR_MODE);
1389 val &= 0xfffffffe;
1390 MMIO_OUT32(VIA_REG_CURSOR_MODE, val);
1391
1392 return;
1393 }
1394 #endif
1395
1396 /*
1397 * rasops glue
1398 */
1399 static void
1400 uni_copycols(void *opaque, int row, int srccol, int dstcol, int ncols)
1401 {
1402 struct rasops_info *ri;
1403 struct vcons_screen *scr;
1404 struct unichromefb_softc *sc;
1405 int xs, xd, y, width, height;
1406
1407 ri = (struct rasops_info *)opaque;
1408 scr = (struct vcons_screen *)ri->ri_hw;
1409 sc = (struct unichromefb_softc *)scr->scr_cookie;
1410
1411 if (sc->sc_wsmode == WSDISPLAYIO_MODE_EMUL) {
1412 xs = ri->ri_xorigin + ri->ri_font->fontwidth * srccol;
1413 xd = ri->ri_xorigin + ri->ri_font->fontwidth * dstcol;
1414 y = ri->ri_yorigin + ri->ri_font->fontheight * row;
1415 width = ri->ri_font->fontwidth * ncols;
1416 height = ri->ri_font->fontheight;
1417 uni_bitblit(sc, xs, y, xd, y, width, height);
1418 }
1419
1420 return;
1421 }
1422
1423 static void
1424 uni_copyrows(void *opaque, int srcrow, int dstrow, int nrows)
1425 {
1426 struct rasops_info *ri;
1427 struct vcons_screen *scr;
1428 struct unichromefb_softc *sc;
1429 int x, ys, yd, width, height;
1430
1431 ri = (struct rasops_info *)opaque;
1432 scr = (struct vcons_screen *)ri->ri_hw;
1433 sc = (struct unichromefb_softc *)scr->scr_cookie;
1434
1435 if (sc->sc_wsmode == WSDISPLAYIO_MODE_EMUL) {
1436 x = ri->ri_xorigin;
1437 ys = ri->ri_yorigin + ri->ri_font->fontheight * srcrow;
1438 yd = ri->ri_yorigin + ri->ri_font->fontheight * dstrow;
1439 width = ri->ri_emuwidth;
1440 height = ri->ri_font->fontheight * nrows;
1441 uni_bitblit(sc, x, ys, x, yd, width, height);
1442 }
1443
1444 return;
1445 }
1446
1447 static void
1448 uni_erasecols(void *opaque, int row, int startcol, int ncols, long fillattr)
1449 {
1450 struct rasops_info *ri;
1451 struct vcons_screen *scr;
1452 struct unichromefb_softc *sc;
1453 int x, y, width, height, fg, bg, ul;
1454
1455 ri = (struct rasops_info *)opaque;
1456 scr = (struct vcons_screen *)ri->ri_hw;
1457 sc = (struct unichromefb_softc *)scr->scr_cookie;
1458
1459 if (sc->sc_wsmode == WSDISPLAYIO_MODE_EMUL) {
1460 x = ri->ri_xorigin + ri->ri_font->fontwidth * startcol;
1461 y = ri->ri_yorigin + ri->ri_font->fontheight * row;
1462 width = ri->ri_font->fontwidth * ncols;
1463 height = ri->ri_font->fontheight;
1464 rasops_unpack_attr(fillattr, &fg, &bg, &ul);
1465 uni_fillrect(sc, x, y, width, height, ri->ri_devcmap[bg]);
1466 }
1467
1468 return;
1469 }
1470
1471 static void
1472 uni_eraserows(void *opaque, int row, int nrows, long fillattr)
1473 {
1474 struct rasops_info *ri;
1475 struct vcons_screen *scr;
1476 struct unichromefb_softc *sc;
1477 int x, y, width, height, fg, bg, ul;
1478
1479 ri = (struct rasops_info *)opaque;
1480 scr = (struct vcons_screen *)ri->ri_hw;
1481 sc = (struct unichromefb_softc *)scr->scr_cookie;
1482
1483 if (sc->sc_wsmode == WSDISPLAYIO_MODE_EMUL) {
1484 rasops_unpack_attr(fillattr, &fg, &bg, &ul);
1485 if ((row == 0) && (nrows == ri->ri_rows)) {
1486 /* clear the whole screen */
1487 uni_fillrect(sc, 0, 0, ri->ri_width,
1488 ri->ri_height, ri->ri_devcmap[bg]);
1489 } else {
1490 x = ri->ri_xorigin;
1491 y = ri->ri_yorigin + ri->ri_font->fontheight * row;
1492 width = ri->ri_emuwidth;
1493 height = ri->ri_font->fontheight * nrows;
1494 uni_fillrect(sc, x, y, width, height,
1495 ri->ri_devcmap[bg]);
1496 }
1497 }
1498
1499 return;
1500 }
1501
1502 static void
1503 uni_cursor(void *opaque, int on, int row, int col)
1504 {
1505 struct rasops_info *ri;
1506 struct vcons_screen *scr;
1507 struct unichromefb_softc *sc;
1508 int x, y, wi, he;
1509
1510 ri = (struct rasops_info *)opaque;
1511 scr = (struct vcons_screen *)ri->ri_hw;
1512 sc = (struct unichromefb_softc *)scr->scr_cookie;
1513
1514 uni_wait_idle(sc);
1515
1516 wi = ri->ri_font->fontwidth;
1517 he = ri->ri_font->fontheight;
1518
1519 if (sc->sc_wsmode == WSDISPLAYIO_MODE_EMUL) {
1520 x = ri->ri_ccol * wi + ri->ri_xorigin;
1521 y = ri->ri_crow * he + ri->ri_yorigin;
1522 if (ri->ri_flg & RI_CURSOR) {
1523 uni_rectinvert(sc, x, y, wi, he);
1524 ri->ri_flg &= ~RI_CURSOR;
1525 }
1526 ri->ri_crow = row;
1527 ri->ri_ccol = col;
1528 if (on) {
1529 x = ri->ri_ccol * wi + ri->ri_xorigin;
1530 y = ri->ri_crow * he + ri->ri_yorigin;
1531 uni_rectinvert(sc, x, y, wi, he);
1532 ri->ri_flg |= RI_CURSOR;
1533 }
1534 } else {
1535 ri->ri_flg &= ~RI_CURSOR;
1536 ri->ri_crow = row;
1537 ri->ri_ccol = col;
1538 }
1539
1540 return;
1541 }
1542
1543 static void
1544 uni_putchar(void *opaque, int row, int col, u_int c, long attr)
1545 {
1546 struct rasops_info *ri;
1547 struct vcons_screen *scr;
1548 struct unichromefb_softc *sc;
1549
1550 ri = (struct rasops_info *)opaque;
1551 scr = (struct vcons_screen *)ri->ri_hw;
1552 sc = (struct unichromefb_softc *)scr->scr_cookie;
1553
1554 if (sc->sc_wsmode == WSDISPLAYIO_MODE_EMUL) {
1555 uint32_t *data;
1556 int fg, bg, ul, uc, i;
1557 int x, y, wi, he;
1558
1559 wi = ri->ri_font->fontwidth;
1560 he = ri->ri_font->fontheight;
1561
1562 if (!CHAR_IN_FONT(c, ri->ri_font))
1563 return;
1564
1565 rasops_unpack_attr(attr, &fg, &bg, &ul);
1566 x = ri->ri_xorigin + col * wi;
1567 y = ri->ri_yorigin + row * he;
1568 if (c == 0x20)
1569 uni_fillrect(sc, x, y, wi, he, ri->ri_devcmap[bg]);
1570 else {
1571 uc = c - ri->ri_font->firstchar;
1572 data = (uint32_t *)((uint8_t *)ri->ri_font->data +
1573 uc * ri->ri_fontscale);
1574 uni_setup_mono(sc, x, y, wi, he,
1575 ri->ri_devcmap[fg], ri->ri_devcmap[bg]);
1576 for (i = 0; i < (wi * he) / 4; i++) {
1577 MMIO_OUT32(VIA_MMIO_BLTBASE, *data);
1578 data++;
1579 }
1580 }
1581 }
1582
1583 return;
1584 }
1585