unichromefb.c revision 1.2 1 /* $NetBSD: unichromefb.c,v 1.2 2006/08/13 03:37:02 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.2 2006/08/13 03:37:02 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_bitblit(struct unichromefb_softc *, int, int, int, int, int, int);
175
176 /* rasops glue */
177 static void uni_copycols(void *, int, int, int, int);
178 static void uni_copyrows(void *, int, int, int);
179 static void uni_erasecols(void *, int, int, int, long);
180 static void uni_eraserows(void *, int, int, long);
181 #if notyet
182 static void uni_cursor(void *, int, int, int);
183 static void uni_putchar(void *, int, int, u_int, long);
184 #endif
185
186 struct wsdisplay_accessops unichromefb_accessops = {
187 unichromefb_ioctl,
188 unichromefb_mmap,
189 NULL,
190 NULL,
191 NULL,
192 NULL,
193 };
194
195 static struct vcons_screen unichromefb_console_screen;
196
197 const struct wsscreen_descr *_unichromefb_scrlist[] = {
198 &unichromefb_stdscreen,
199 };
200
201 struct wsscreen_list unichromefb_screenlist = {
202 sizeof(_unichromefb_scrlist) / sizeof(struct wsscreen_descr *),
203 _unichromefb_scrlist
204 };
205
206 CFATTACH_DECL(unichromefb, sizeof(struct unichromefb_softc),
207 unichromefb_match, unichromefb_attach, NULL, NULL);
208
209 static int
210 unichromefb_match(struct device *parent, struct cfdata *match, void *opaque)
211 {
212 struct pci_attach_args *pa;
213
214 pa = (struct pci_attach_args *)opaque;
215
216 if (PCI_CLASS(pa->pa_class) != PCI_CLASS_DISPLAY ||
217 PCI_SUBCLASS(pa->pa_class) != PCI_SUBCLASS_DISPLAY_VGA)
218 return 0;
219
220 if (PCI_VENDOR(pa->pa_id) != PCI_VENDOR_VIATECH)
221 return 0;
222
223 switch (PCI_PRODUCT(pa->pa_id)) {
224 case PCI_PRODUCT_VIATECH_VT3314_IG:
225 return 10; /* beat vga(4) */
226 }
227
228 return 0;
229 }
230
231 static void
232 unichromefb_attach(struct device *parent, struct device *self, void *opaque)
233 {
234 struct unichromefb_softc *sc;
235 struct pci_attach_args *pa;
236 struct rasops_info *ri;
237 struct wsemuldisplaydev_attach_args aa;
238 bus_space_handle_t ap_memh;
239 uint8_t val;
240 bus_addr_t mmiobase;
241 bus_size_t mmiosize;
242 long defattr;
243
244 sc = (struct unichromefb_softc *)self;
245 pa = (struct pci_attach_args *)opaque;
246
247 sc->sc_width = UNICHROMEFB_WIDTH;
248 sc->sc_height = UNICHROMEFB_HEIGHT;
249 sc->sc_depth = UNICHROMEFB_DEPTH;
250 sc->sc_stride = sc->sc_width * (sc->sc_depth / 8);
251
252 sc->sc_wsmode = WSDISPLAYIO_MODE_EMUL;
253
254 sc->sc_iot = pa->pa_iot;
255 if (bus_space_map(sc->sc_iot, VIA_REGBASE, 0x20, 0, &sc->sc_ioh)) {
256 aprint_error(": failed to map I/O registers\n");
257 return;
258 }
259
260 val = uni_rd(sc, VIASR, SR30);
261 sc->sc_fbaddr = val << 24;
262 val = uni_rd(sc, VIASR, SR39);
263 sc->sc_fbsize = val * (4*1024*1024);
264 if (sc->sc_fbsize < 16*1024*1024 || sc->sc_fbsize > 64*1024*1024)
265 sc->sc_fbsize = 16*1024*1024;
266 sc->sc_memt = pa->pa_memt;
267 if (bus_space_map(sc->sc_memt, sc->sc_fbaddr, sc->sc_fbsize,
268 BUS_SPACE_MAP_LINEAR, &ap_memh)) {
269 aprint_error(": failed to map aperture at 0x%08x/0x%x\n",
270 sc->sc_fbaddr, sc->sc_fbsize);
271 return;
272 }
273 sc->sc_fbbase = (caddr_t)bus_space_vaddr(sc->sc_memt, ap_memh);
274
275 if (pci_mapreg_map(pa, 0x14, PCI_MAPREG_TYPE_MEM, 0,
276 &sc->sc_memt, &sc->sc_memh, &mmiobase, &mmiosize)) {
277 sc->sc_accel = 0;
278 aprint_error(": failed to map MMIO registers\n");
279 } else {
280 sc->sc_accel = 1;
281 }
282
283 aprint_naive("\n");
284 aprint_normal(": VIA UniChrome frame buffer\n");
285
286 if (sc->sc_accel)
287 aprint_normal("%s: MMIO @0x%08x/0x%x\n",
288 sc->sc_dev.dv_xname, (uint32_t)mmiobase, (uint32_t)mmiosize);
289
290 ri = &unichromefb_console_screen.scr_ri;
291 memset(ri, 0, sizeof(struct rasops_info));
292
293 vcons_init(&sc->sc_vd, sc, &unichromefb_stdscreen,
294 &unichromefb_accessops);
295 sc->sc_vd.init_screen = unichromefb_init_screen;
296
297 uni_setmode(sc, UNICHROMEFB_MODE, sc->sc_depth);
298
299 uni_init_dac(sc, IGA1);
300 if (sc->sc_accel) {
301 uni_init_accel(sc);
302 uni_fillrect(sc, 0, 0, sc->sc_width, sc->sc_height, 0);
303 }
304
305 aprint_normal("%s: FB @0x%08x (%dx%dx%d)\n", sc->sc_dev.dv_xname,
306 sc->sc_fbaddr, sc->sc_width, sc->sc_height, sc->sc_depth);
307
308 unichromefb_console_screen.scr_flags |= VCONS_SCREEN_IS_STATIC;
309 vcons_init_screen(&sc->sc_vd, &unichromefb_console_screen, 1, &defattr);
310
311 unichromefb_stdscreen.ncols = ri->ri_cols;
312 unichromefb_stdscreen.nrows = ri->ri_rows;
313 unichromefb_stdscreen.textops = &ri->ri_ops;
314 unichromefb_stdscreen.capabilities = ri->ri_caps;
315 unichromefb_stdscreen.modecookie = NULL;
316
317 wsdisplay_cnattach(&unichromefb_stdscreen, ri, 0, 0, defattr);
318
319 aa.console = 1; /* XXX */
320 aa.scrdata = &unichromefb_screenlist;
321 aa.accessops = &unichromefb_accessops;
322 aa.accesscookie = &sc->sc_vd;
323
324 config_found(self, &aa, wsemuldisplaydevprint);
325
326 return;
327 }
328
329 static int
330 unichromefb_ioctl(void *v, void *vs, u_long cmd, caddr_t data, int flag,
331 struct lwp *l)
332 {
333 struct vcons_data *vd;
334 struct unichromefb_softc *sc;
335 struct wsdisplay_fbinfo *fb;
336
337 vd = (struct vcons_data *)v;
338 sc = (struct unichromefb_softc *)vd->cookie;
339
340 switch (cmd) {
341 case WSDISPLAYIO_GTYPE:
342 *(u_int *)data = WSDISPLAY_TYPE_PCIMISC;
343 return 0;
344 case WSDISPLAYIO_GINFO:
345 if (vd->active != NULL) {
346 fb = (struct wsdisplay_fbinfo *)data;
347 fb->width = sc->sc_width;
348 fb->height = sc->sc_height;
349 fb->depth = sc->sc_depth;
350 fb->cmsize = 256;
351 return 0;
352 } else
353 return ENODEV;
354 case WSDISPLAYIO_GVIDEO:
355 return ENODEV;
356 case WSDISPLAYIO_SVIDEO:
357 return ENODEV;
358 case WSDISPLAYIO_GETCMAP:
359 return EINVAL;
360 case WSDISPLAYIO_PUTCMAP:
361 return EINVAL;
362 case WSDISPLAYIO_LINEBYTES:
363 *(u_int *)data = sc->sc_stride;
364 return 0;
365 case WSDISPLAYIO_SMODE:
366 {
367 int new_mode = *(int *)data;
368 if (new_mode != sc->sc_wsmode) {
369 sc->sc_wsmode = new_mode;
370 if (new_mode == WSDISPLAYIO_MODE_EMUL)
371 vcons_redraw_screen(vd->active);
372 }
373 }
374 return 0;
375 case WSDISPLAYIO_SSPLASH:
376 return ENODEV;
377 case WSDISPLAYIO_SPROGRESS:
378 return ENODEV;
379 }
380
381 return EPASSTHROUGH;
382 }
383
384 static paddr_t
385 unichromefb_mmap(void *v, void *vs, off_t offset, int prot)
386 {
387 return -1;
388 }
389
390 static void
391 unichromefb_init_screen(void *c, struct vcons_screen *scr, int existing,
392 long *defattr)
393 {
394 struct unichromefb_softc *sc;
395 struct rasops_info *ri;
396
397 sc = (struct unichromefb_softc *)c;
398 ri = &scr->scr_ri;
399 ri->ri_flg = RI_CENTER;
400 ri->ri_depth = sc->sc_depth;
401 ri->ri_width = sc->sc_width;
402 ri->ri_height = sc->sc_height;
403 ri->ri_stride = sc->sc_stride;
404 ri->ri_bits = sc->sc_fbbase;
405 if (existing)
406 ri->ri_flg |= RI_CLEAR;
407
408 switch (ri->ri_depth) {
409 case 32:
410 ri->ri_rnum = ri->ri_gnum = ri->ri_bnum = 8;
411 ri->ri_rpos = 16;
412 ri->ri_gpos = 8;
413 ri->ri_bpos = 0;
414 break;
415 case 16:
416 ri->ri_rnum = 5;
417 ri->ri_gnum = 6;
418 ri->ri_bnum = 5;
419 ri->ri_rpos = 11;
420 ri->ri_gpos = 5;
421 ri->ri_bpos = 0;
422 break;
423 }
424
425 rasops_init(ri, sc->sc_height / 16, sc->sc_width / 8);
426 ri->ri_caps = WSSCREEN_WSCOLORS;
427 rasops_reconfig(ri, sc->sc_height / ri->ri_font->fontheight,
428 sc->sc_width / ri->ri_font->fontwidth);
429
430 ri->ri_hw = scr;
431 if (sc->sc_accel) {
432 ri->ri_ops.copyrows = uni_copyrows;
433 ri->ri_ops.copycols = uni_copycols;
434 ri->ri_ops.eraserows = uni_eraserows;
435 ri->ri_ops.erasecols = uni_erasecols;
436 #if notyet
437 ri->ri_ops.cursor = uni_cursor;
438 ri->ri_ops.putchar = uni_putchar;
439 #endif
440 }
441
442 return;
443 }
444
445 /*
446 * hardware access
447 */
448 static uint8_t
449 uni_rd(struct unichromefb_softc *sc, int off, uint8_t idx)
450 {
451 bus_space_write_1(sc->sc_iot, sc->sc_ioh, off, idx);
452 return bus_space_read_1(sc->sc_iot, sc->sc_ioh, off + 1);
453 }
454
455 static void
456 uni_wr(struct unichromefb_softc *sc, int off, uint8_t idx, uint8_t val)
457 {
458 bus_space_write_1(sc->sc_iot, sc->sc_ioh, off, idx);
459 bus_space_write_1(sc->sc_iot, sc->sc_ioh, off + 1, val);
460 }
461
462 static void
463 uni_wr_mask(struct unichromefb_softc *sc, int off, uint8_t idx,
464 uint8_t val, uint8_t mask)
465 {
466 uint8_t tmp;
467
468 bus_space_write_1(sc->sc_iot, sc->sc_ioh, off, idx);
469 tmp = bus_space_read_1(sc->sc_iot, sc->sc_ioh, off + 1);
470 bus_space_write_1(sc->sc_iot, sc->sc_ioh, off + 1,
471 ((val & mask) | (tmp & ~mask)));
472 }
473
474 static void
475 uni_wr_dac(struct unichromefb_softc *sc, uint8_t idx,
476 uint8_t r, uint8_t g, uint8_t b)
477 {
478 bus_space_write_1(sc->sc_iot, sc->sc_ioh, LUT_INDEX_WRITE, idx);
479 bus_space_write_1(sc->sc_iot, sc->sc_ioh, LUT_DATA, r);
480 bus_space_write_1(sc->sc_iot, sc->sc_ioh, LUT_DATA, g);
481 bus_space_write_1(sc->sc_iot, sc->sc_ioh, LUT_DATA, b);
482 }
483
484 static void
485 uni_wr_x(struct unichromefb_softc *sc, struct io_reg *tbl, int num)
486 {
487 int i;
488 uint8_t tmp;
489
490 for (i = 0; i < num; i++) {
491 bus_space_write_1(sc->sc_iot, sc->sc_ioh, tbl[i].port,
492 tbl[i].index);
493 tmp = bus_space_read_1(sc->sc_iot, sc->sc_iot,
494 tbl[i].port + 1);
495 tmp = (tmp & (~tbl[i].mask)) | tbl[i].value;
496 bus_space_write_1(sc->sc_iot, sc->sc_ioh, tbl[i].index + 1,
497 tmp);
498 }
499 }
500
501 /*
502 * helpers
503 */
504 static struct VideoModeTable *
505 uni_getmode(int mode)
506 {
507 int i;
508
509 for (i = 0; i < NUM_TOTAL_MODETABLE; i++)
510 if (CLE266Modes[i].ModeIndex == mode)
511 return &CLE266Modes[i];
512
513 return NULL;
514 }
515
516 static void
517 uni_setmode(struct unichromefb_softc *sc, int idx, int bpp)
518 {
519 struct VideoModeTable *vtbl;
520 struct crt_mode_table *crt;
521 int i;
522
523 /* XXX */
524 vtbl = uni_getmode(idx);
525 if (vtbl == NULL)
526 panic("%s: unsupported mode: %d\n", sc->sc_dev.dv_xname, idx);
527
528 crt = vtbl->crtc;
529
530 uni_screen_disable(sc);
531
532 (void)bus_space_read_1(sc->sc_iot, sc->sc_ioh, VIAStatus);
533 bus_space_write_1(sc->sc_iot, sc->sc_ioh, VIAAR, 0);
534
535 /* XXX assume CN900 for now */
536 uni_wr_x(sc, CN900_ModeXregs, NUM_TOTAL_CN900_ModeXregs);
537
538 uni_crt_disable(sc);
539
540 /* Fill VPIT params */
541 bus_space_write_1(sc->sc_iot, sc->sc_ioh, VIAWMisc, VPIT.Misc);
542
543 /* Write sequencer */
544 for (i = 1; i <= StdSR; i++) {
545 bus_space_write_1(sc->sc_iot, sc->sc_ioh, VIASR, i);
546 bus_space_write_1(sc->sc_iot, sc->sc_ioh, VIASR + 1,
547 VPIT.SR[i - 1]);
548 }
549
550 uni_set_start(sc);
551
552 uni_set_crtc(sc, crt, idx, bpp / 8, IGA1);
553
554 for (i = 0; i < StdGR; i++) {
555 bus_space_write_1(sc->sc_iot, sc->sc_ioh, VIAGR, i);
556 bus_space_write_1(sc->sc_iot, sc->sc_ioh, VIAGR + 1,
557 VPIT.GR[i]);
558 }
559
560 for (i = 0; i < StdAR; i++) {
561 (void)bus_space_read_1(sc->sc_iot, sc->sc_ioh, VIAStatus);
562 bus_space_write_1(sc->sc_iot, sc->sc_ioh, VIAAR, i);
563 bus_space_write_1(sc->sc_iot, sc->sc_ioh, VIAAR,
564 VPIT.AR[i]);
565 }
566
567 (void)bus_space_read_1(sc->sc_iot, sc->sc_ioh, VIAStatus);
568 bus_space_write_1(sc->sc_iot, sc->sc_ioh, VIAAR, 0x20);
569
570 uni_set_crtc(sc, crt, idx, bpp / 8, IGA1);
571 /* set crt output path */
572 uni_wr_mask(sc, VIASR, SR16, 0x00, BIT6);
573
574 uni_crt_enable(sc);
575 uni_screen_enable(sc);
576
577 return;
578 }
579
580 static void
581 uni_crt_lock(struct unichromefb_softc *sc)
582 {
583 uni_wr_mask(sc, VIACR, CR11, BIT7, BIT7);
584 }
585
586 static void
587 uni_crt_unlock(struct unichromefb_softc *sc)
588 {
589 uni_wr_mask(sc, VIACR, CR11, 0, BIT7);
590 uni_wr_mask(sc, VIACR, CR47, 0, BIT0);
591 }
592
593 static void
594 uni_crt_enable(struct unichromefb_softc *sc)
595 {
596 uni_wr_mask(sc, VIACR, CR36, 0, BIT5+BIT4);
597 }
598
599 static void
600 uni_crt_disable(struct unichromefb_softc *sc)
601 {
602 uni_wr_mask(sc, VIACR, CR36, BIT5+BIT4, BIT5+BIT4);
603 }
604
605 static void
606 uni_screen_enable(struct unichromefb_softc *sc)
607 {
608 uni_wr_mask(sc, VIASR, SR01, 0, BIT5);
609 }
610
611 static void
612 uni_screen_disable(struct unichromefb_softc *sc)
613 {
614 uni_wr_mask(sc, VIASR, SR01, 0x20, BIT5);
615 }
616
617 static void
618 uni_set_start(struct unichromefb_softc *sc)
619 {
620 uni_crt_unlock(sc);
621
622 uni_wr(sc, VIACR, CR0C, 0x00);
623 uni_wr(sc, VIACR, CR0D, 0x00);
624 uni_wr(sc, VIACR, CR34, 0x00);
625 uni_wr_mask(sc, VIACR, CR48, 0x00, BIT0 + BIT1);
626
627 uni_wr(sc, VIACR, CR62, 0x00);
628 uni_wr(sc, VIACR, CR63, 0x00);
629 uni_wr(sc, VIACR, CR64, 0x00);
630 uni_wr(sc, VIACR, CRA3, 0x00);
631
632 uni_crt_lock(sc);
633 }
634
635 static void
636 uni_set_crtc(struct unichromefb_softc *sc, struct crt_mode_table *ctbl,
637 int mode, int bpp_byte, int iga)
638 {
639 struct VideoModeTable *vtbl;
640 struct display_timing crtreg;
641 int i;
642 int index;
643 int haddr, vaddr;
644 uint8_t val;
645 uint32_t pll_d_n;
646
647 index = 0;
648
649 vtbl = uni_getmode(mode);
650 for (i = 0; i < vtbl->mode_array; i++) {
651 index = i;
652 if (ctbl[i].refresh_rate == 60)
653 break;
654 }
655
656 crtreg = ctbl[index].crtc;
657
658 haddr = crtreg.hor_addr;
659 vaddr = crtreg.ver_addr;
660
661 val = bus_space_read_1(sc->sc_iot, sc->sc_ioh, VIARMisc);
662 if (ctbl[index].h_sync_polarity == NEGATIVE) {
663 if (ctbl[index].v_sync_polarity == NEGATIVE)
664 bus_space_write_1(sc->sc_iot, sc->sc_ioh, VIAWMisc,
665 (val & (~(BIT6+BIT7))) | (BIT6+BIT7));
666 else
667 bus_space_write_1(sc->sc_iot, sc->sc_ioh, VIAWMisc,
668 (val & (~(BIT6+BIT7))) | (BIT6));
669 } else {
670 if (ctbl[index].v_sync_polarity == NEGATIVE)
671 bus_space_write_1(sc->sc_iot, sc->sc_ioh, VIAWMisc,
672 (val & (~(BIT6+BIT7))) | (BIT7));
673 else
674 bus_space_write_1(sc->sc_iot, sc->sc_ioh, VIAWMisc,
675 (val & (~(BIT6+BIT7))));
676 }
677
678 if (iga == IGA1) {
679 uni_crt_unlock(sc);
680 uni_wr(sc, VIACR, CR09, 0x00);
681 uni_wr_mask(sc, VIACR, CR11, 0x00, BIT4+BIT5+BIT6);
682 uni_wr_mask(sc, VIACR, CR17, 0x00, BIT7);
683 }
684
685 uni_load_crtc(sc, crtreg, iga);
686 uni_fix_crtc(sc);
687 uni_crt_lock(sc);
688 uni_wr_mask(sc, VIACR, CR17, 0x80, BIT7);
689
690 uni_load_offset(sc, haddr, bpp_byte, iga);
691 uni_load_fetchcnt(sc, haddr, bpp_byte, iga);
692 uni_load_fifo(sc, iga, haddr, vaddr);
693
694 uni_set_depth(sc, bpp_byte, iga);
695 pll_d_n = uni_get_clkval(sc, ctbl[index].clk);
696 uni_set_vclk(sc, pll_d_n, iga);
697 }
698
699 static void
700 uni_load_crtc(struct unichromefb_softc *sc,
701 struct display_timing device_timing, int iga)
702 {
703 int regnum, val;
704 struct io_register *reg;
705 int i;
706
707 regnum = val = 0;
708 reg = NULL;
709
710 uni_crt_unlock(sc);
711
712 for (i = 0; i < 12; i++) {
713 switch (iga) {
714 case IGA1:
715 switch (i) {
716 case H_TOTAL_INDEX:
717 val = IGA1_HOR_TOTAL_FORMULA(
718 device_timing.hor_total);
719 regnum = iga1_crtc_reg.hor_total.reg_num;
720 reg = iga1_crtc_reg.hor_total.reg;
721 break;
722 case H_ADDR_INDEX:
723 val = IGA1_HOR_ADDR_FORMULA(
724 device_timing.hor_addr);
725 regnum = iga1_crtc_reg.hor_addr.reg_num;
726 reg = iga1_crtc_reg.hor_addr.reg;
727 break;
728 case H_BLANK_START_INDEX:
729 val = IGA1_HOR_BLANK_START_FORMULA(
730 device_timing.hor_blank_start);
731 regnum = iga1_crtc_reg.hor_blank_start.reg_num;
732 reg = iga1_crtc_reg.hor_blank_start.reg;
733 break;
734 case H_BLANK_END_INDEX:
735 val = IGA1_HOR_BLANK_END_FORMULA(
736 device_timing.hor_blank_start,
737 device_timing.hor_blank_end);
738 regnum = iga1_crtc_reg.hor_blank_end.reg_num;
739 reg = iga1_crtc_reg.hor_blank_end.reg;
740 break;
741 case H_SYNC_START_INDEX:
742 val = IGA1_HOR_SYNC_START_FORMULA(
743 device_timing.hor_sync_start);
744 regnum = iga1_crtc_reg.hor_sync_start.reg_num;
745 reg = iga1_crtc_reg.hor_sync_start.reg;
746 break;
747 case H_SYNC_END_INDEX:
748 val = IGA1_HOR_SYNC_END_FORMULA(
749 device_timing.hor_sync_start,
750 device_timing.hor_sync_end);
751 regnum = iga1_crtc_reg.hor_sync_end.reg_num;
752 reg = iga1_crtc_reg.hor_sync_end.reg;
753 break;
754 case V_TOTAL_INDEX:
755 val = IGA1_VER_TOTAL_FORMULA(
756 device_timing.ver_total);
757 regnum = iga1_crtc_reg.ver_total.reg_num;
758 reg = iga1_crtc_reg.ver_total.reg;
759 break;
760 case V_ADDR_INDEX:
761 val = IGA1_VER_ADDR_FORMULA(
762 device_timing.ver_addr);
763 regnum = iga1_crtc_reg.ver_addr.reg_num;
764 reg = iga1_crtc_reg.ver_addr.reg;
765 break;
766 case V_BLANK_START_INDEX:
767 val = IGA1_VER_BLANK_START_FORMULA(
768 device_timing.ver_blank_start);
769 regnum = iga1_crtc_reg.ver_blank_start.reg_num;
770 reg = iga1_crtc_reg.ver_blank_start.reg;
771 break;
772 case V_BLANK_END_INDEX:
773 val = IGA1_VER_BLANK_END_FORMULA(
774 device_timing.ver_blank_start,
775 device_timing.ver_blank_end);
776 regnum = iga1_crtc_reg.ver_blank_end.reg_num;
777 reg = iga1_crtc_reg.ver_blank_end.reg;
778 break;
779 case V_SYNC_START_INDEX:
780 val = IGA1_VER_SYNC_START_FORMULA(
781 device_timing.ver_sync_start);
782 regnum = iga1_crtc_reg.ver_sync_start.reg_num;
783 reg = iga1_crtc_reg.ver_sync_start.reg;
784 break;
785 case V_SYNC_END_INDEX:
786 val = IGA1_VER_SYNC_END_FORMULA(
787 device_timing.ver_sync_start,
788 device_timing.ver_sync_end);
789 regnum = iga1_crtc_reg.ver_sync_end.reg_num;
790 reg = iga1_crtc_reg.ver_sync_end.reg;
791 break;
792 default:
793 printf("%s: unknown index %d while setting up CRTC\n",
794 sc->sc_dev.dv_xname, i);
795 break;
796 }
797 break;
798 case IGA2:
799 printf("%s: %s: IGA2 not supported\n",
800 sc->sc_dev.dv_xname, __func__);
801 break;
802 }
803
804 uni_load_reg(sc, val, regnum, reg, VIACR);
805 }
806
807 uni_crt_lock(sc);
808 }
809
810 static void
811 uni_load_reg(struct unichromefb_softc *sc, int timing, int regnum,
812 struct io_register *reg, int type)
813 {
814 int regmask, bitnum, data;
815 int i, j;
816 int shift_next_reg;
817 int startidx, endidx, cridx;
818 uint16_t getbit;
819
820 bitnum = 0;
821
822 for (i = 0; i < regnum; i++) {
823 regmask = data = 0;
824 startidx = reg[i].start_bit;
825 endidx = reg[i].end_bit;
826 cridx = reg[i].io_addr;
827
828 shift_next_reg = bitnum;
829
830 for (j = startidx; j <= endidx; j++) {
831 regmask = regmask | (BIT0 << j);
832 getbit = (timing & (BIT0 << bitnum));
833 data = data | ((getbit >> shift_next_reg) << startidx);
834 ++bitnum;
835 }
836
837 if (type == VIACR)
838 uni_wr_mask(sc, VIACR, cridx, data, regmask);
839 else
840 uni_wr_mask(sc, VIASR, cridx, data, regmask);
841 }
842
843 return;
844 }
845
846 static void
847 uni_fix_crtc(struct unichromefb_softc *sc)
848 {
849 uni_wr_mask(sc, VIACR, CR03, 0x80, BIT7);
850 uni_wr(sc, VIACR, CR18, 0xff);
851 uni_wr_mask(sc, VIACR, CR07, 0x10, BIT4);
852 uni_wr_mask(sc, VIACR, CR09, 0x40, BIT6);
853 uni_wr_mask(sc, VIACR, CR35, 0x10, BIT4);
854 uni_wr_mask(sc, VIACR, CR33, 0x06, BIT0+BIT1+BIT2);
855 uni_wr(sc, VIACR, CR17, 0xe3);
856 uni_wr(sc, VIACR, CR08, 0x00);
857 uni_wr(sc, VIACR, CR14, 0x00);
858
859 return;
860 }
861
862 static void
863 uni_load_offset(struct unichromefb_softc *sc, int haddr, int bpp, int iga)
864 {
865
866 switch (iga) {
867 case IGA1:
868 uni_load_reg(sc,
869 IGA1_OFFSET_FORMULA(haddr, bpp),
870 offset_reg.iga1_offset_reg.reg_num,
871 offset_reg.iga1_offset_reg.reg,
872 VIACR);
873 break;
874 default:
875 printf("%s: %s: only IGA1 is supported\n", sc->sc_dev.dv_xname,
876 __func__);
877 break;
878 }
879
880 return;
881 }
882
883 static void
884 uni_load_fetchcnt(struct unichromefb_softc *sc, int haddr, int bpp, int iga)
885 {
886
887 switch (iga) {
888 case IGA1:
889 uni_load_reg(sc,
890 IGA1_FETCH_COUNT_FORMULA(haddr, bpp),
891 fetch_count_reg.iga1_fetch_count_reg.reg_num,
892 fetch_count_reg.iga1_fetch_count_reg.reg,
893 VIASR);
894 break;
895 default:
896 printf("%s: %s: only IGA1 is supported\n", sc->sc_dev.dv_xname,
897 __func__);
898 break;
899 }
900
901 return;
902 }
903
904 static void
905 uni_load_fifo(struct unichromefb_softc *sc, int iga, int horact, int veract)
906 {
907 int val, regnum;
908 struct io_register *reg;
909 int iga1_fifo_max_depth, iga1_fifo_threshold;
910 int iga1_fifo_high_threshold, iga1_display_queue_expire_num;
911
912 reg = NULL;
913 iga1_fifo_max_depth = iga1_fifo_threshold = 0;
914 iga1_fifo_high_threshold = iga1_display_queue_expire_num = 0;
915
916 switch (iga) {
917 case IGA1:
918 /* XXX if (type == CN900) { */
919 iga1_fifo_max_depth = CN900_IGA1_FIFO_MAX_DEPTH;
920 iga1_fifo_threshold = CN900_IGA1_FIFO_THRESHOLD;
921 iga1_fifo_high_threshold = CN900_IGA1_FIFO_HIGH_THRESHOLD;
922 if (horact > 1280 && veract > 1024)
923 iga1_display_queue_expire_num = 16;
924 else
925 iga1_display_queue_expire_num =
926 CN900_IGA1_DISPLAY_QUEUE_EXPIRE_NUM;
927 /* XXX } */
928
929 /* set display FIFO depth select */
930 val = IGA1_FIFO_DEPTH_SELECT_FORMULA(iga1_fifo_max_depth);
931 regnum =
932 display_fifo_depth_reg.iga1_fifo_depth_select_reg.reg_num;
933 reg = display_fifo_depth_reg.iga1_fifo_depth_select_reg.reg;
934 uni_load_reg(sc, val, regnum, reg, VIASR);
935
936 /* set display FIFO threshold select */
937 val = IGA1_FIFO_THRESHOLD_FORMULA(iga1_fifo_threshold);
938 regnum = fifo_threshold_select_reg.iga1_fifo_threshold_select_reg.reg_num;
939 reg = fifo_threshold_select_reg.iga1_fifo_threshold_select_reg.reg;
940 uni_load_reg(sc, val, regnum, reg, VIASR);
941
942 /* set display FIFO high threshold select */
943 val = IGA1_FIFO_HIGH_THRESHOLD_FORMULA(iga1_fifo_high_threshold);
944 regnum = fifo_high_threshold_select_reg.iga1_fifo_high_threshold_select_reg.reg_num;
945 reg = fifo_high_threshold_select_reg.iga1_fifo_high_threshold_select_reg.reg;
946 uni_load_reg(sc, val, regnum, reg, VIASR);
947
948 /* set display queue expire num */
949 val = IGA1_DISPLAY_QUEUE_EXPIRE_NUM_FORMULA(iga1_display_queue_expire_num);
950 regnum = display_queue_expire_num_reg.iga1_display_queue_expire_num_reg.reg_num;
951 reg = display_queue_expire_num_reg.iga1_display_queue_expire_num_reg.reg;
952 uni_load_reg(sc, val, regnum, reg, VIASR);
953
954 break;
955 default:
956 printf("%s: %s: only IGA1 is supported\n", sc->sc_dev.dv_xname,
957 __func__);
958 break;
959 }
960
961 return;
962 }
963
964 static void
965 uni_set_depth(struct unichromefb_softc *sc, int bpp, int iga)
966 {
967 switch (iga) {
968 case IGA1:
969 switch (bpp) {
970 case MODE_32BPP:
971 uni_wr_mask(sc, VIASR, SR15, 0xae, 0xfe);
972 break;
973 case MODE_16BPP:
974 uni_wr_mask(sc, VIASR, SR15, 0xb6, 0xfe);
975 break;
976 case MODE_8BPP:
977 uni_wr_mask(sc, VIASR, SR15, 0x22, 0xfe);
978 break;
979 default:
980 printf("%s: %s: mode (%d) unsupported\n",
981 sc->sc_dev.dv_xname, __func__, bpp);
982 }
983 break;
984 default:
985 printf("%s: %s: only IGA1 is supported\n", sc->sc_dev.dv_xname,
986 __func__);
987 break;
988 }
989 }
990
991 static uint32_t
992 uni_get_clkval(struct unichromefb_softc *sc, int clk)
993 {
994 int i;
995
996 for (i = 0; i < NUM_TOTAL_PLL_TABLE; i++) {
997 if (clk == pll_value[i].clk) {
998 /* XXX only CN900 supported for now */
999 return pll_value[i].k800_pll;
1000 }
1001 }
1002
1003 aprint_error("%s: can't find matching PLL value\n",
1004 sc->sc_dev.dv_xname);
1005
1006 return 0;
1007 }
1008
1009 static void
1010 uni_set_vclk(struct unichromefb_softc *sc, uint32_t clk, int iga)
1011 {
1012 uint8_t val;
1013
1014 /* hardware reset on */
1015 uni_wr_mask(sc, VIACR, CR17, 0x00, BIT7);
1016
1017 switch (iga) {
1018 case IGA1:
1019 /* XXX only CN900 is supported */
1020 uni_wr(sc, VIASR, SR44, clk / 0x10000);
1021 uni_wr(sc, VIASR, SR45, (clk & 0xffff) / 0x100);
1022 uni_wr(sc, VIASR, SR46, clk % 0x100);
1023 break;
1024 default:
1025 printf("%s: %s: only IGA1 is supported\n", sc->sc_dev.dv_xname,
1026 __func__);
1027 break;
1028 }
1029
1030 /* hardware reset off */
1031 uni_wr_mask(sc, VIACR, CR17, 0x80, BIT7);
1032
1033 /* reset pll */
1034 switch (iga) {
1035 case IGA1:
1036 uni_wr_mask(sc, VIASR, SR40, 0x02, BIT1);
1037 uni_wr_mask(sc, VIASR, SR40, 0x00, BIT1);
1038 break;
1039 }
1040
1041 /* good to go */
1042 val = bus_space_read_1(sc->sc_iot, sc->sc_ioh, VIARMisc);
1043 val |= (BIT2+BIT3);
1044 bus_space_write_1(sc->sc_iot, sc->sc_ioh, VIAWMisc, val);
1045
1046 return;
1047 }
1048
1049 static void
1050 uni_init_dac(struct unichromefb_softc *sc, int iga)
1051 {
1052 int i;
1053
1054 /* XXX only IGA1 for now */
1055 uni_wr_mask(sc, VIASR, SR1A, 0x00, BIT0);
1056 uni_wr_mask(sc, VIASR, SR18, 0x00, BIT7+BIT6);
1057 for (i = 0; i < 256; i++)
1058 uni_wr_dac(sc, i,
1059 palLUT_table[i].red, palLUT_table[i].green, palLUT_table[i].blue);
1060
1061 uni_wr_mask(sc, VIASR, SR18, 0xc0, BIT7+BIT6);
1062
1063 return;
1064 }
1065
1066 static void
1067 uni_init_accel(struct unichromefb_softc *sc)
1068 {
1069
1070 /* init 2D engine regs to reset 2D engine */
1071 MMIO_OUT32(VIA_REG_GEMODE, 0);
1072 MMIO_OUT32(VIA_REG_SRCPOS, 0);
1073 MMIO_OUT32(VIA_REG_DSTPOS, 0);
1074 MMIO_OUT32(VIA_REG_DIMENSION, 0);
1075 MMIO_OUT32(VIA_REG_PATADDR, 0);
1076 MMIO_OUT32(VIA_REG_FGCOLOR, 0);
1077 MMIO_OUT32(VIA_REG_BGCOLOR, 0);
1078 MMIO_OUT32(VIA_REG_CLIPTL, 0);
1079 MMIO_OUT32(VIA_REG_CLIPBR, 0);
1080 MMIO_OUT32(VIA_REG_OFFSET, 0);
1081 MMIO_OUT32(VIA_REG_KEYCONTROL, 0);
1082 MMIO_OUT32(VIA_REG_SRCBASE, 0);
1083 MMIO_OUT32(VIA_REG_DSTBASE, 0);
1084 MMIO_OUT32(VIA_REG_PITCH, 0);
1085 MMIO_OUT32(VIA_REG_MONOPAT1, 0);
1086
1087 /* init AGP and VQ registers */
1088 MMIO_OUT32(VIA_REG_TRANSET, 0x00100000);
1089 MMIO_OUT32(VIA_REG_TRANSPACE, 0x00000000);
1090 MMIO_OUT32(VIA_REG_TRANSPACE, 0x00333004);
1091 MMIO_OUT32(VIA_REG_TRANSPACE, 0x60000000);
1092 MMIO_OUT32(VIA_REG_TRANSPACE, 0x61000000);
1093 MMIO_OUT32(VIA_REG_TRANSPACE, 0x62000000);
1094 MMIO_OUT32(VIA_REG_TRANSPACE, 0x63000000);
1095 MMIO_OUT32(VIA_REG_TRANSPACE, 0x64000000);
1096 MMIO_OUT32(VIA_REG_TRANSPACE, 0x7d000000);
1097
1098 MMIO_OUT32(VIA_REG_TRANSET, 0xfe020000);
1099 MMIO_OUT32(VIA_REG_TRANSPACE, 0x00000000);
1100
1101 /* disable VQ */
1102 MMIO_OUT32(VIA_REG_TRANSET, 0x00fe0000);
1103 MMIO_OUT32(VIA_REG_TRANSPACE, 0x00000004);
1104 MMIO_OUT32(VIA_REG_TRANSPACE, 0x40008c0f);
1105 MMIO_OUT32(VIA_REG_TRANSPACE, 0x44000000);
1106 MMIO_OUT32(VIA_REG_TRANSPACE, 0x45080c04);
1107 MMIO_OUT32(VIA_REG_TRANSPACE, 0x46800408);
1108
1109 uni_set_accel_depth(sc);
1110
1111 MMIO_OUT32(VIA_REG_SRCBASE, 0);
1112 MMIO_OUT32(VIA_REG_DSTBASE, 0);
1113
1114 MMIO_OUT32(VIA_REG_PITCH, VIA_PITCH_ENABLE |
1115 (((sc->sc_width * sc->sc_depth >> 3) >> 3) |
1116 (((sc->sc_width * sc->sc_depth >> 3) >> 3) << 16)));
1117
1118 return;
1119 }
1120
1121 static void
1122 uni_set_accel_depth(struct unichromefb_softc *sc)
1123 {
1124 uint32_t gemode;
1125
1126 gemode = MMIO_IN32(0x04) & 0xfffffcff;
1127
1128 switch (sc->sc_depth) {
1129 case 32:
1130 gemode |= VIA_GEM_32bpp;
1131 break;
1132 case 16:
1133 gemode |= VIA_GEM_16bpp;
1134 break;
1135 default:
1136 gemode |= VIA_GEM_8bpp;
1137 break;
1138 }
1139
1140 /* set colour depth and pitch */
1141 MMIO_OUT32(VIA_REG_GEMODE, gemode);
1142
1143 return;
1144 }
1145
1146 static void
1147 uni_wait_idle(struct unichromefb_softc *sc)
1148 {
1149 int loop = 0;
1150
1151 while (!(MMIO_IN32(VIA_REG_STATUS) & VIA_VR_QUEUE_BUSY) &&
1152 (loop++ < MAXLOOP))
1153 ;
1154
1155 while ((MMIO_IN32(VIA_REG_STATUS) &
1156 (VIA_CMD_RGTR_BUSY | VIA_2D_ENG_BUSY | VIA_3D_ENG_BUSY)) &&
1157 (loop++ < MAXLOOP))
1158 ;
1159
1160 if (loop >= MAXLOOP)
1161 aprint_error("%s: engine stall\n", sc->sc_dev.dv_xname);
1162
1163 return;
1164 }
1165
1166 static void
1167 uni_fillrect(struct unichromefb_softc *sc, int x, int y, int width,
1168 int height, int colour)
1169 {
1170
1171 MMIO_OUT32(VIA_REG_SRCPOS, 0);
1172 MMIO_OUT32(VIA_REG_SRCBASE, 0);
1173 MMIO_OUT32(VIA_REG_DSTBASE, 0);
1174 MMIO_OUT32(VIA_REG_PITCH, VIA_PITCH_ENABLE |
1175 (((sc->sc_width * sc->sc_depth >> 3) >> 3) |
1176 (((sc->sc_width * sc->sc_depth >> 3) >> 3) << 16)));
1177 MMIO_OUT32(VIA_REG_DSTPOS, ((y << 16) | x));
1178 MMIO_OUT32(VIA_REG_DIMENSION,
1179 (((height - 1) << 16) | (width - 1)));
1180 MMIO_OUT32(VIA_REG_FGCOLOR, colour);
1181 MMIO_OUT32(VIA_REG_GECMD, (0x01 | 0x2000 | 0xf0 << 24));
1182
1183 /* XXX */
1184 uni_wait_idle(sc);
1185
1186 return;
1187 }
1188
1189 static void
1190 uni_bitblit(struct unichromefb_softc *sc, int xs, int ys, int xd, int yd, int width, int height)
1191 {
1192 uint32_t dir;
1193
1194 dir = 0;
1195
1196 if (ys < yd) {
1197 yd += height - 1;
1198 ys += height - 1;
1199 dir |= 0x8000;
1200 }
1201
1202 if (xs < xd) {
1203 xd += width - 1;
1204 xs += width - 1;
1205 dir |= 0x4000;
1206 }
1207
1208 MMIO_OUT32(VIA_REG_SRCBASE, 0);
1209 MMIO_OUT32(VIA_REG_DSTBASE, 0);
1210 MMIO_OUT32(VIA_REG_PITCH, VIA_PITCH_ENABLE |
1211 (((sc->sc_width * sc->sc_depth >> 3) >> 3) |
1212 (((sc->sc_width * sc->sc_depth >> 3) >> 3) << 16)));
1213 MMIO_OUT32(VIA_REG_SRCPOS, ys << 16 | xs);
1214 MMIO_OUT32(VIA_REG_DSTPOS, yd << 16 | xd);
1215 MMIO_OUT32(VIA_REG_DIMENSION, ((height - 1) << 16) | (width - 1));
1216 MMIO_OUT32(VIA_REG_GECMD, (0x01 | dir | (0xcc << 24)));
1217
1218 /* XXX */
1219 uni_wait_idle(sc);
1220
1221 return;
1222 }
1223
1224 /*
1225 * rasops glue
1226 */
1227 static void
1228 uni_copycols(void *opaque, int row, int srccol, int dstcol, int ncols)
1229 {
1230 struct rasops_info *ri;
1231 struct vcons_screen *scr;
1232 struct unichromefb_softc *sc;
1233 int xs, xd, y, width, height;
1234
1235 ri = (struct rasops_info *)opaque;
1236 scr = (struct vcons_screen *)ri->ri_hw;
1237 sc = (struct unichromefb_softc *)scr->scr_cookie;
1238
1239 if (sc->sc_wsmode == WSDISPLAYIO_MODE_EMUL) {
1240 xs = ri->ri_xorigin + ri->ri_font->fontwidth * srccol;
1241 xd = ri->ri_xorigin + ri->ri_font->fontwidth * dstcol;
1242 y = ri->ri_yorigin + ri->ri_font->fontheight * row;
1243 width = ri->ri_font->fontwidth * ncols;
1244 height = ri->ri_font->fontheight;
1245 uni_bitblit(sc, xs, y, xd, y, width, height);
1246 }
1247
1248 return;
1249 }
1250
1251 static void
1252 uni_copyrows(void *opaque, int srcrow, int dstrow, int nrows)
1253 {
1254 struct rasops_info *ri;
1255 struct vcons_screen *scr;
1256 struct unichromefb_softc *sc;
1257 int x, ys, yd, width, height;
1258
1259 ri = (struct rasops_info *)opaque;
1260 scr = (struct vcons_screen *)ri->ri_hw;
1261 sc = (struct unichromefb_softc *)scr->scr_cookie;
1262
1263 if (sc->sc_wsmode == WSDISPLAYIO_MODE_EMUL) {
1264 x = ri->ri_xorigin;
1265 ys = ri->ri_yorigin + ri->ri_font->fontheight * srcrow;
1266 yd = ri->ri_yorigin + ri->ri_font->fontheight * dstrow;
1267 width = ri->ri_emuwidth;
1268 height = ri->ri_font->fontheight * nrows;
1269 uni_bitblit(sc, x, ys, x, yd, width, height);
1270 }
1271
1272 return;
1273 }
1274
1275 static void
1276 uni_erasecols(void *opaque, int row, int startcol, int ncols, long fillattr)
1277 {
1278 struct rasops_info *ri;
1279 struct vcons_screen *scr;
1280 struct unichromefb_softc *sc;
1281 int x, y, width, height, fg, bg, ul;
1282
1283 ri = (struct rasops_info *)opaque;
1284 scr = (struct vcons_screen *)ri->ri_hw;
1285 sc = (struct unichromefb_softc *)scr->scr_cookie;
1286
1287 if (sc->sc_wsmode == WSDISPLAYIO_MODE_EMUL) {
1288 x = ri->ri_xorigin + ri->ri_font->fontwidth * startcol;
1289 y = ri->ri_yorigin + ri->ri_font->fontheight * row;
1290 width = ri->ri_font->fontwidth * ncols;
1291 height = ri->ri_font->fontheight;
1292 rasops_unpack_attr(fillattr, &fg, &bg, &ul);
1293 uni_fillrect(sc, x, y, width, height, ri->ri_devcmap[bg]);
1294 }
1295
1296 return;
1297 }
1298
1299 static void
1300 uni_eraserows(void *opaque, int row, int nrows, long fillattr)
1301 {
1302 struct rasops_info *ri;
1303 struct vcons_screen *scr;
1304 struct unichromefb_softc *sc;
1305 int x, y, width, height, fg, bg, ul;
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 rasops_unpack_attr(fillattr, &fg, &bg, &ul);
1313 if ((row == 0) && (nrows == ri->ri_rows)) {
1314 /* clear the whole screen */
1315 uni_fillrect(sc, 0, 0, ri->ri_width,
1316 ri->ri_height, ri->ri_devcmap[bg]);
1317 } else {
1318 x = ri->ri_xorigin;
1319 y = ri->ri_yorigin + ri->ri_font->fontheight * row;
1320 width = ri->ri_emuwidth;
1321 height = ri->ri_font->fontheight * nrows;
1322 uni_fillrect(sc, x, y, width, height,
1323 ri->ri_devcmap[bg]);
1324 }
1325 }
1326
1327 return;
1328 }
1329
1330 #if notyet
1331 static void
1332 uni_cursor(void *opaque, int on, int row, int col)
1333 {
1334 struct rasops_info *ri;
1335 struct vcons_screen *scr;
1336 struct unichromefb_softc *sc;
1337
1338 ri = (struct rasops_info *)opaque;
1339 scr = (struct vcons_screen *)ri->ri_hw;
1340 sc = (struct unichromefb_softc *)scr->scr_cookie;
1341
1342 uni_wait_idle(sc);
1343
1344 if (sc->sc_cursor)
1345 sc->sc_cursor(opaque, on, row, col);
1346
1347 return;
1348 }
1349
1350 static void
1351 uni_putchar(void *opaque, int row, int col, u_int c, long fillattr)
1352 {
1353 struct rasops_info *ri;
1354 struct vcons_screen *scr;
1355 struct unichromefb_softc *sc;
1356
1357 ri = (struct rasops_info *)opaque;
1358 scr = (struct vcons_screen *)ri->ri_hw;
1359 sc = (struct unichromefb_softc *)scr->scr_cookie;
1360
1361 uni_wait_idle(sc);
1362
1363 if (sc->sc_putchar)
1364 sc->sc_putchar(opaque, row, col, c, fillattr);
1365
1366 return;
1367 }
1368 #endif
1369
1370 /* XXX TODO */
1371 int
1372 unichromefb_cnattach(void)
1373 {
1374 return 0;
1375 }
1376