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