unichromefb.c revision 1.1 1 /* $NetBSD: unichromefb.c,v 1.1 2006/08/02 01:44:09 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.1 2006/08/02 01:44:09 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
84 /* XXX */
85 #define UNICHROMEFB_DEPTH 32
86
87 struct unichromefb_softc {
88 struct device sc_dev;
89 struct vcons_data sc_vd;
90 void * sc_fbbase;
91 unsigned int sc_fbaddr;
92 unsigned int sc_fbsize;
93
94 bus_space_tag_t sc_iot;
95 bus_space_handle_t sc_ioh;
96
97 bus_space_tag_t sc_memt;
98 bus_space_handle_t sc_memh;
99
100 int sc_width;
101 int sc_height;
102 int sc_depth;
103 int sc_stride;
104
105 int sc_wsmode;
106 };
107
108 static int unichromefb_match(struct device *, struct cfdata *, void *);
109 static void unichromefb_attach(struct device *, struct device *, void *);
110
111 /* XXX */
112 int unichromefb_cnattach(void);
113
114 struct wsscreen_descr unichromefb_stdscreen = {
115 "fb",
116 0, 0,
117 NULL,
118 8, 16,
119 };
120
121 static int unichromefb_ioctl(void *, void *, u_long, caddr_t, int,
122 struct lwp *);
123 static paddr_t unichromefb_mmap(void *, void *, off_t, int);
124
125 static void unichromefb_init_screen(void *, struct vcons_screen *,
126 int, long *);
127
128 /* hardware access */
129 static uint8_t uni_rd(struct unichromefb_softc *, int, uint8_t);
130 static void uni_wr(struct unichromefb_softc *, int, uint8_t, uint8_t);
131 static void uni_wr_mask(struct unichromefb_softc *, int, uint8_t,
132 uint8_t, uint8_t);
133 static void uni_wr_x(struct unichromefb_softc *, struct io_reg *, int);
134 #if notyet
135 static void uni_wr_dac(struct unichromefb_softc *, uint8_t, uint8_t,
136 uint8_t, uint8_t);
137 #endif
138
139 /* helpers */
140 static struct VideoModeTable * uni_getmode(int);
141 static void uni_setmode(struct unichromefb_softc *, int, int);
142 static void uni_crt_lock(struct unichromefb_softc *);
143 static void uni_crt_unlock(struct unichromefb_softc *);
144 static void uni_crt_enable(struct unichromefb_softc *);
145 static void uni_screen_enable(struct unichromefb_softc *);
146 static void uni_set_start(struct unichromefb_softc *);
147 static void uni_set_crtc(struct unichromefb_softc *,
148 struct crt_mode_table *, int, int, int);
149 static void uni_load_crtc(struct unichromefb_softc *, struct display_timing,
150 int);
151 static void uni_load_reg(struct unichromefb_softc *, int, int,
152 struct io_register *, int);
153 static void uni_fix_crtc(struct unichromefb_softc *);
154 static void uni_load_offset(struct unichromefb_softc *, int, int, int);
155 static void uni_load_fetchcnt(struct unichromefb_softc *, int, int, int);
156 static void uni_load_fifo(struct unichromefb_softc *, int, int, int);
157 static void uni_set_depth(struct unichromefb_softc *, int, int);
158 static uint32_t uni_get_clkval(struct unichromefb_softc *, int);
159 static void uni_set_vclk(struct unichromefb_softc *, uint32_t, int);
160
161 struct wsdisplay_accessops unichromefb_accessops = {
162 unichromefb_ioctl,
163 unichromefb_mmap,
164 NULL,
165 NULL,
166 NULL,
167 NULL,
168 };
169
170 static struct vcons_screen unichromefb_console_screen;
171
172 const struct wsscreen_descr *_unichromefb_scrlist[] = {
173 &unichromefb_stdscreen,
174 };
175
176 struct wsscreen_list unichromefb_screenlist = {
177 sizeof(_unichromefb_scrlist) / sizeof(struct wsscreen_descr *),
178 _unichromefb_scrlist
179 };
180
181 CFATTACH_DECL(unichromefb, sizeof(struct unichromefb_softc),
182 unichromefb_match, unichromefb_attach, NULL, NULL);
183
184 static int
185 unichromefb_match(struct device *parent, struct cfdata *match, void *opaque)
186 {
187 struct pci_attach_args *pa;
188
189 pa = (struct pci_attach_args *)opaque;
190
191 if (PCI_CLASS(pa->pa_class) != PCI_CLASS_DISPLAY ||
192 PCI_SUBCLASS(pa->pa_class) != PCI_SUBCLASS_DISPLAY_VGA)
193 return 0;
194
195 if (PCI_VENDOR(pa->pa_id) != PCI_VENDOR_VIATECH)
196 return 0;
197
198 switch (PCI_PRODUCT(pa->pa_id)) {
199 case PCI_PRODUCT_VIATECH_VT3314_IG:
200 return 10; /* beat vga(4) */
201 }
202
203 return 0;
204 }
205
206 static void
207 unichromefb_attach(struct device *parent, struct device *self, void *opaque)
208 {
209 struct unichromefb_softc *sc;
210 struct pci_attach_args *pa;
211 struct rasops_info *ri;
212 struct wsemuldisplaydev_attach_args aa;
213 uint8_t val;
214 long defattr;
215
216 sc = (struct unichromefb_softc *)self;
217 pa = (struct pci_attach_args *)opaque;
218
219 /* XXX */
220 sc->sc_width = 640;
221 sc->sc_height = 480;
222 sc->sc_depth = UNICHROMEFB_DEPTH;
223 sc->sc_stride = sc->sc_width * (sc->sc_depth / 8);
224
225 sc->sc_wsmode = WSDISPLAYIO_MODE_EMUL;
226
227 sc->sc_iot = pa->pa_iot;
228 if (bus_space_map(sc->sc_iot, VIA_REGBASE, 0x20, 0, &sc->sc_ioh)) {
229 aprint_error(": failed to map I/O registers\n");
230 return;
231 }
232
233 val = uni_rd(sc, VIASR, SR30);
234 sc->sc_fbaddr = val << 24;
235 sc->sc_fbsize = sc->sc_width * sc->sc_height * (sc->sc_depth / 8);
236 sc->sc_memt = pa->pa_memt;
237 if (bus_space_map(sc->sc_memt, sc->sc_fbaddr, sc->sc_fbsize,
238 BUS_SPACE_MAP_LINEAR, &sc->sc_memh)) {
239 aprint_error(": failed to map aperture at 0x%08x/0x%x\n",
240 sc->sc_fbaddr, sc->sc_fbsize);
241 return;
242 }
243 sc->sc_fbbase = (caddr_t)bus_space_vaddr(sc->sc_memt, sc->sc_memh);
244 /*memset(sc->sc_fbbase, 0, sc->sc_fbsize);*/
245
246 aprint_naive("\n");
247 aprint_normal(": VIA UniChrome frame buffer\n");
248
249 ri = &unichromefb_console_screen.scr_ri;
250 memset(ri, 0, sizeof(struct rasops_info));
251
252 vcons_init(&sc->sc_vd, sc, &unichromefb_stdscreen,
253 &unichromefb_accessops);
254 sc->sc_vd.init_screen = unichromefb_init_screen;
255
256 uni_setmode(sc, VIA_RES_640X480, sc->sc_depth);
257
258 aprint_normal("%s: fb %dx%dx%d @%p\n", sc->sc_dev.dv_xname,
259 sc->sc_width, sc->sc_height, sc->sc_depth, sc->sc_fbbase);
260 delay(5*1000*1000);
261
262 unichromefb_console_screen.scr_flags |= VCONS_SCREEN_IS_STATIC;
263 vcons_init_screen(&sc->sc_vd, &unichromefb_console_screen, 1, &defattr);
264
265 unichromefb_stdscreen.ncols = ri->ri_cols;
266 unichromefb_stdscreen.nrows = ri->ri_rows;
267 unichromefb_stdscreen.textops = &ri->ri_ops;
268 unichromefb_stdscreen.capabilities = ri->ri_caps;
269 unichromefb_stdscreen.modecookie = NULL;
270
271 wsdisplay_cnattach(&unichromefb_stdscreen, ri, 0, 0, defattr);
272
273 aa.console = 1; /* XXX */
274 aa.scrdata = &unichromefb_screenlist;
275 aa.accessops = &unichromefb_accessops;
276 aa.accesscookie = &sc->sc_vd;
277
278 config_found(self, &aa, wsemuldisplaydevprint);
279
280 return;
281 }
282
283 static int
284 unichromefb_ioctl(void *v, void *vs, u_long cmd, caddr_t data, int flag,
285 struct lwp *l)
286 {
287 struct vcons_data *vd;
288 struct unichromefb_softc *sc;
289 struct wsdisplay_fbinfo *fb;
290
291 vd = (struct vcons_data *)v;
292 sc = (struct unichromefb_softc *)vd->cookie;
293
294 switch (cmd) {
295 case WSDISPLAYIO_GTYPE:
296 *(u_int *)data = WSDISPLAY_TYPE_PCIMISC;
297 return 0;
298 case WSDISPLAYIO_GINFO:
299 if (vd->active != NULL) {
300 fb = (struct wsdisplay_fbinfo *)data;
301 fb->width = sc->sc_width;
302 fb->height = sc->sc_height;
303 fb->depth = sc->sc_depth;
304 fb->cmsize = 256;
305 return 0;
306 } else
307 return ENODEV;
308 case WSDISPLAYIO_GVIDEO:
309 return ENODEV;
310 case WSDISPLAYIO_SVIDEO:
311 return ENODEV;
312 case WSDISPLAYIO_GETCMAP:
313 return EINVAL;
314 case WSDISPLAYIO_PUTCMAP:
315 return EINVAL;
316 case WSDISPLAYIO_LINEBYTES:
317 *(u_int *)data = sc->sc_stride;
318 return 0;
319 case WSDISPLAYIO_SMODE:
320 {
321 int new_mode = *(int *)data;
322 if (new_mode != sc->sc_wsmode) {
323 sc->sc_wsmode = new_mode;
324 if (new_mode == WSDISPLAYIO_MODE_EMUL)
325 vcons_redraw_screen(vd->active);
326 }
327 }
328 return 0;
329 case WSDISPLAYIO_SSPLASH:
330 return ENODEV;
331 case WSDISPLAYIO_SPROGRESS:
332 return ENODEV;
333 }
334
335 return EPASSTHROUGH;
336 }
337
338 static paddr_t
339 unichromefb_mmap(void *v, void *vs, off_t offset, int prot)
340 {
341 return -1;
342 }
343
344 static void
345 unichromefb_init_screen(void *c, struct vcons_screen *scr, int existing,
346 long *defattr)
347 {
348 struct unichromefb_softc *sc;
349 struct rasops_info *ri;
350
351 sc = (struct unichromefb_softc *)c;
352 ri = &scr->scr_ri;
353 ri->ri_flg = RI_CENTER;
354 ri->ri_depth = sc->sc_depth;
355 ri->ri_width = sc->sc_width;
356 ri->ri_height = sc->sc_height;
357 ri->ri_stride = sc->sc_stride;
358 ri->ri_bits = sc->sc_fbbase;
359
360 ri->ri_rnum = ri->ri_gnum = ri->ri_bnum = 8;
361 ri->ri_rpos = 16;
362 ri->ri_gpos = 8;
363 ri->ri_bpos = 0;
364
365 rasops_init(ri, sc->sc_height / 16, sc->sc_width / 8);
366 ri->ri_caps = WSSCREEN_WSCOLORS;
367 rasops_reconfig(ri, sc->sc_height / ri->ri_font->fontheight,
368 sc->sc_width / ri->ri_font->fontwidth);
369
370 return;
371 }
372
373 /*
374 * hardware access
375 */
376 static uint8_t
377 uni_rd(struct unichromefb_softc *sc, int off, uint8_t idx)
378 {
379 bus_space_write_1(sc->sc_iot, sc->sc_ioh, off, idx);
380 return bus_space_read_1(sc->sc_iot, sc->sc_ioh, off + 1);
381 }
382
383 static void
384 uni_wr(struct unichromefb_softc *sc, int off, uint8_t idx, uint8_t val)
385 {
386 bus_space_write_1(sc->sc_iot, sc->sc_ioh, off, idx);
387 bus_space_write_1(sc->sc_iot, sc->sc_ioh, off + 1, val);
388 }
389
390 static void
391 uni_wr_mask(struct unichromefb_softc *sc, int off, uint8_t idx,
392 uint8_t val, uint8_t mask)
393 {
394 uint8_t tmp;
395
396 bus_space_write_1(sc->sc_iot, sc->sc_ioh, off, idx);
397 tmp = bus_space_read_1(sc->sc_iot, sc->sc_ioh, off + 1);
398 bus_space_write_1(sc->sc_iot, sc->sc_ioh, off + 1,
399 ((val & mask) | (tmp & ~mask)));
400 }
401
402 #if notyet
403 static void
404 uni_wr_dac(struct unichromefb_softc *sc, uint8_t idx,
405 uint8_t r, uint8_t g, uint8_t b)
406 {
407 bus_space_write_1(sc->sc_iot, sc->sc_ioh, LUT_INDEX_WRITE, idx);
408 bus_space_write_1(sc->sc_iot, sc->sc_ioh, LUT_DATA, r);
409 bus_space_write_1(sc->sc_iot, sc->sc_ioh, LUT_DATA, g);
410 bus_space_write_1(sc->sc_iot, sc->sc_ioh, LUT_DATA, b);
411 }
412 #endif
413
414 static void
415 uni_wr_x(struct unichromefb_softc *sc, struct io_reg *tbl, int num)
416 {
417 int i;
418 uint8_t tmp;
419
420 for (i = 0; i < num; i++) {
421 bus_space_write_1(sc->sc_iot, sc->sc_ioh, tbl[i].port,
422 tbl[i].index);
423 tmp = bus_space_read_1(sc->sc_iot, sc->sc_iot,
424 tbl[i].port + 1);
425 tmp = (tmp & (~tbl[i].mask)) | tbl[i].value;
426 bus_space_write_1(sc->sc_iot, sc->sc_ioh, tbl[i].index + 1,
427 tmp);
428 }
429 }
430
431 /*
432 * helpers
433 */
434 static struct VideoModeTable *
435 uni_getmode(int mode)
436 {
437 int i;
438
439 for (i = 0; i < NUM_TOTAL_MODETABLE; i++)
440 if (CLE266Modes[i].ModeIndex == mode)
441 return &CLE266Modes[i];
442
443 return NULL;
444 }
445
446 static void
447 uni_setmode(struct unichromefb_softc *sc, int idx, int bpp)
448 {
449 struct VideoModeTable *vtbl;
450 struct crt_mode_table *crt;
451 int i;
452
453 /* XXX */
454 vtbl = uni_getmode(idx);
455 if (vtbl == NULL)
456 panic("%s: unsupported mode: %d\n", sc->sc_dev.dv_xname, idx);
457
458 crt = vtbl->crtc;
459
460 (void)bus_space_read_1(sc->sc_iot, sc->sc_ioh, VIAStatus);
461 bus_space_write_1(sc->sc_iot, sc->sc_ioh, VIAAR, 0);
462
463 /* XXX assume CN900 for now */
464 uni_wr_x(sc, CN900_ModeXregs, NUM_TOTAL_CN900_ModeXregs);
465
466 /* Fill VPIT params */
467 bus_space_write_1(sc->sc_iot, sc->sc_ioh, VIAWMisc, VPIT.Misc);
468
469 /* Write sequencer */
470 for (i = 1; i <= StdSR; i++) {
471 bus_space_write_1(sc->sc_iot, sc->sc_ioh, VIASR, i);
472 bus_space_write_1(sc->sc_iot, sc->sc_ioh, VIASR + 1,
473 VPIT.SR[i - 1]);
474 }
475
476 uni_set_start(sc);
477
478 uni_set_crtc(sc, crt, idx, bpp / 8, IGA1);
479
480 for (i = 0; i < StdGR; i++) {
481 bus_space_write_1(sc->sc_iot, sc->sc_ioh, VIAGR, i);
482 bus_space_write_1(sc->sc_iot, sc->sc_ioh, VIAGR + 1,
483 VPIT.GR[i]);
484 }
485
486 for (i = 0; i < StdAR; i++) {
487 (void)bus_space_read_1(sc->sc_iot, sc->sc_ioh, VIAStatus);
488 bus_space_write_1(sc->sc_iot, sc->sc_ioh, VIAAR, i);
489 bus_space_write_1(sc->sc_iot, sc->sc_ioh, VIAAR + 1,
490 VPIT.AR[i]);
491 }
492
493 (void)bus_space_read_1(sc->sc_iot, sc->sc_ioh, VIAStatus);
494 bus_space_write_1(sc->sc_iot, sc->sc_ioh, VIAAR, 0x20);
495
496 uni_set_crtc(sc, crt, idx, bpp / 8, IGA1);
497 /* set crt output path */
498 uni_wr_mask(sc, VIASR, SR16, 0x00, BIT6);
499
500 uni_crt_enable(sc);
501 uni_screen_enable(sc);
502
503 return;
504 }
505
506 static void
507 uni_crt_lock(struct unichromefb_softc *sc)
508 {
509 uni_wr_mask(sc, VIACR, CR11, BIT7, BIT7);
510 }
511
512 static void
513 uni_crt_unlock(struct unichromefb_softc *sc)
514 {
515 uni_wr_mask(sc, VIACR, CR11, 0, BIT7);
516 uni_wr_mask(sc, VIACR, CR47, 0, BIT0);
517 }
518
519 static void
520 uni_crt_enable(struct unichromefb_softc *sc)
521 {
522 uni_wr_mask(sc, VIACR, CR36, 0, BIT5+BIT4);
523 }
524
525 static void
526 uni_screen_enable(struct unichromefb_softc *sc)
527 {
528 uni_wr_mask(sc, VIASR, SR01, 0, BIT5);
529 }
530
531 static void
532 uni_set_start(struct unichromefb_softc *sc)
533 {
534 uni_crt_unlock(sc);
535
536 uni_wr(sc, VIACR, CR0C, 0x00);
537 uni_wr(sc, VIACR, CR0D, 0x00);
538 uni_wr(sc, VIACR, CR34, 0x00);
539 uni_wr_mask(sc, VIACR, CR48, 0x00, BIT0 + BIT1);
540
541 uni_wr(sc, VIACR, CR62, 0x00);
542 uni_wr(sc, VIACR, CR63, 0x00);
543 uni_wr(sc, VIACR, CR64, 0x00);
544 uni_wr(sc, VIACR, CRA3, 0x00);
545
546 uni_crt_lock(sc);
547 }
548
549 static void
550 uni_set_crtc(struct unichromefb_softc *sc, struct crt_mode_table *ctbl,
551 int mode, int bpp_byte, int iga)
552 {
553 struct VideoModeTable *vtbl;
554 struct display_timing crtreg;
555 int i;
556 int index;
557 int haddr, vaddr;
558 uint8_t val;
559 uint32_t pll_d_n;
560
561 index = 0;
562
563 vtbl = uni_getmode(mode);
564 for (i = 0; i < vtbl->mode_array; i++) {
565 index = i;
566 if (ctbl[i].refresh_rate == 60)
567 break;
568 }
569
570 crtreg = ctbl[index].crtc;
571
572 haddr = crtreg.hor_addr;
573 vaddr = crtreg.ver_addr;
574
575 val = bus_space_read_1(sc->sc_iot, sc->sc_ioh, VIARMisc);
576 if (ctbl[index].h_sync_polarity == NEGATIVE) {
577 if (ctbl[index].v_sync_polarity == NEGATIVE)
578 bus_space_write_1(sc->sc_iot, sc->sc_ioh, VIAWMisc,
579 (val & (~(BIT6+BIT7))) | (BIT6+BIT7));
580 else
581 bus_space_write_1(sc->sc_iot, sc->sc_ioh, VIAWMisc,
582 (val & (~(BIT6+BIT7))) | (BIT6));
583 } else {
584 if (ctbl[index].v_sync_polarity == NEGATIVE)
585 bus_space_write_1(sc->sc_iot, sc->sc_ioh, VIAWMisc,
586 (val & (~(BIT6+BIT7))) | (BIT7));
587 else
588 bus_space_write_1(sc->sc_iot, sc->sc_ioh, VIAWMisc,
589 (val & (~(BIT6+BIT7))));
590 }
591
592 if (iga == IGA1) {
593 uni_crt_unlock(sc);
594 uni_wr(sc, VIACR, CR09, 0x00);
595 uni_wr_mask(sc, VIACR, CR11, 0x00, BIT4+BIT5+BIT6);
596 uni_wr_mask(sc, VIACR, CR17, 0x00, BIT7);
597 }
598
599 uni_load_crtc(sc, crtreg, iga);
600 uni_fix_crtc(sc);
601 uni_crt_lock(sc);
602 uni_wr_mask(sc, VIACR, CR17, 0x80, BIT7);
603
604 uni_load_offset(sc, haddr, bpp_byte, iga);
605 uni_load_fetchcnt(sc, haddr, bpp_byte, iga);
606 uni_load_fifo(sc, iga, haddr, vaddr);
607
608 uni_set_depth(sc, bpp_byte, iga);
609 pll_d_n = uni_get_clkval(sc, ctbl[index].clk);
610 uni_set_vclk(sc, pll_d_n, iga);
611 }
612
613 static void
614 uni_load_crtc(struct unichromefb_softc *sc,
615 struct display_timing device_timing, int iga)
616 {
617 int regnum, val;
618 struct io_register *reg;
619 int i;
620
621 regnum = val = 0;
622 reg = NULL;
623
624 uni_crt_unlock(sc);
625
626 for (i = 0; i < 12; i++) {
627 switch (iga) {
628 case IGA1:
629 switch (i) {
630 case H_TOTAL_INDEX:
631 val = IGA1_HOR_TOTAL_FORMULA(
632 device_timing.hor_total);
633 regnum = iga1_crtc_reg.hor_total.reg_num;
634 reg = iga1_crtc_reg.hor_total.reg;
635 break;
636 case H_ADDR_INDEX:
637 val = IGA1_HOR_ADDR_FORMULA(
638 device_timing.hor_addr);
639 regnum = iga1_crtc_reg.hor_addr.reg_num;
640 reg = iga1_crtc_reg.hor_addr.reg;
641 break;
642 case H_BLANK_START_INDEX:
643 val = IGA1_HOR_BLANK_START_FORMULA(
644 device_timing.hor_blank_start);
645 regnum = iga1_crtc_reg.hor_blank_start.reg_num;
646 reg = iga1_crtc_reg.hor_blank_start.reg;
647 break;
648 case H_BLANK_END_INDEX:
649 val = IGA1_HOR_BLANK_END_FORMULA(
650 device_timing.hor_blank_start,
651 device_timing.hor_blank_end);
652 regnum = iga1_crtc_reg.hor_blank_end.reg_num;
653 reg = iga1_crtc_reg.hor_blank_end.reg;
654 break;
655 case H_SYNC_START_INDEX:
656 val = IGA1_HOR_SYNC_START_FORMULA(
657 device_timing.hor_sync_start);
658 regnum = iga1_crtc_reg.hor_sync_start.reg_num;
659 reg = iga1_crtc_reg.hor_sync_start.reg;
660 break;
661 case H_SYNC_END_INDEX:
662 val = IGA1_HOR_SYNC_END_FORMULA(
663 device_timing.hor_sync_start,
664 device_timing.hor_sync_end);
665 regnum = iga1_crtc_reg.hor_sync_end.reg_num;
666 reg = iga1_crtc_reg.hor_sync_end.reg;
667 break;
668 case V_TOTAL_INDEX:
669 val = IGA1_VER_TOTAL_FORMULA(
670 device_timing.ver_total);
671 regnum = iga1_crtc_reg.ver_total.reg_num;
672 reg = iga1_crtc_reg.ver_total.reg;
673 break;
674 case V_ADDR_INDEX:
675 val = IGA1_VER_ADDR_FORMULA(
676 device_timing.ver_addr);
677 regnum = iga1_crtc_reg.ver_addr.reg_num;
678 reg = iga1_crtc_reg.ver_addr.reg;
679 break;
680 case V_BLANK_START_INDEX:
681 val = IGA1_VER_BLANK_START_FORMULA(
682 device_timing.ver_blank_start);
683 regnum = iga1_crtc_reg.ver_blank_start.reg_num;
684 reg = iga1_crtc_reg.ver_blank_start.reg;
685 break;
686 case V_BLANK_END_INDEX:
687 val = IGA1_VER_BLANK_END_FORMULA(
688 device_timing.ver_blank_start,
689 device_timing.ver_blank_end);
690 regnum = iga1_crtc_reg.ver_blank_end.reg_num;
691 reg = iga1_crtc_reg.ver_blank_end.reg;
692 break;
693 case V_SYNC_START_INDEX:
694 val = IGA1_VER_SYNC_START_FORMULA(
695 device_timing.ver_sync_start);
696 regnum = iga1_crtc_reg.ver_sync_start.reg_num;
697 reg = iga1_crtc_reg.ver_sync_start.reg;
698 break;
699 case V_SYNC_END_INDEX:
700 val = IGA1_VER_SYNC_END_FORMULA(
701 device_timing.ver_sync_start,
702 device_timing.ver_sync_end);
703 regnum = iga1_crtc_reg.ver_sync_end.reg_num;
704 reg = iga1_crtc_reg.ver_sync_end.reg;
705 break;
706 }
707 break;
708 case IGA2:
709 printf("%s: %s: IGA2 not supported\n",
710 sc->sc_dev.dv_xname, __func__);
711 break;
712 }
713
714 uni_load_reg(sc, val, regnum, reg, VIACR);
715 }
716
717 uni_crt_lock(sc);
718 }
719
720 static void
721 uni_load_reg(struct unichromefb_softc *sc, int timing, int regnum,
722 struct io_register *reg, int type)
723 {
724 int regmask, bitnum, data;
725 int i, j;
726 int shift_next_reg;
727 int startidx, endidx, cridx;
728 uint16_t getbit;
729
730 bitnum = 0;
731
732 for (i = 0; i < regnum; i++) {
733 regmask = data = 0;
734 startidx = reg[i].start_bit;
735 endidx = reg[i].end_bit;
736 cridx = reg[i].io_addr;
737
738 shift_next_reg = bitnum;
739
740 for (j = startidx; j <= endidx; j++) {
741 regmask = regmask | (BIT0 << j);
742 getbit = (timing & (BIT0 << bitnum));
743 data = data | ((getbit >> shift_next_reg) << startidx);
744 ++bitnum;
745 }
746
747 if (type == VIACR)
748 uni_wr_mask(sc, VIACR, cridx, data, regmask);
749 else
750 uni_wr_mask(sc, VIASR, cridx, data, regmask);
751 }
752
753 return;
754 }
755
756 static void
757 uni_fix_crtc(struct unichromefb_softc *sc)
758 {
759 uni_wr_mask(sc, VIACR, CR03, 0x80, BIT7);
760 uni_wr(sc, VIACR, CR18, 0xff);
761 uni_wr_mask(sc, VIACR, CR07, 0x10, BIT4);
762 uni_wr_mask(sc, VIACR, CR09, 0x40, BIT6);
763 uni_wr_mask(sc, VIACR, CR35, 0x10, BIT4);
764 uni_wr_mask(sc, VIACR, CR33, 0x06, BIT0+BIT1+BIT2);
765 uni_wr(sc, VIACR, CR17, 0xe3);
766 uni_wr(sc, VIACR, CR08, 0x00);
767 uni_wr(sc, VIACR, CR14, 0x00);
768
769 return;
770 }
771
772 static void
773 uni_load_offset(struct unichromefb_softc *sc, int haddr, int bpp, int iga)
774 {
775
776 switch (iga) {
777 case IGA1:
778 uni_load_reg(sc,
779 IGA1_OFFSET_FORMULA(haddr, bpp),
780 offset_reg.iga1_offset_reg.reg_num,
781 offset_reg.iga1_offset_reg.reg,
782 VIACR);
783 break;
784 default:
785 printf("%s: %s: only IGA1 is supported\n", sc->sc_dev.dv_xname,
786 __func__);
787 break;
788 }
789
790 return;
791 }
792
793 static void
794 uni_load_fetchcnt(struct unichromefb_softc *sc, int haddr, int bpp, int iga)
795 {
796
797 switch (iga) {
798 case IGA1:
799 uni_load_reg(sc,
800 IGA1_FETCH_COUNT_FORMULA(haddr, bpp),
801 fetch_count_reg.iga1_fetch_count_reg.reg_num,
802 fetch_count_reg.iga1_fetch_count_reg.reg,
803 VIASR);
804 break;
805 default:
806 printf("%s: %s: only IGA1 is supported\n", sc->sc_dev.dv_xname,
807 __func__);
808 break;
809 }
810
811 return;
812 }
813
814 static void
815 uni_load_fifo(struct unichromefb_softc *sc, int iga, int horact, int veract)
816 {
817 int val, regnum;
818 struct io_register *reg;
819 int iga1_fifo_max_depth, iga1_fifo_threshold;
820 int iga1_fifo_high_threshold, iga1_display_queue_expire_num;
821
822 reg = NULL;
823 iga1_fifo_max_depth = iga1_fifo_threshold = 0;
824 iga1_fifo_high_threshold = iga1_display_queue_expire_num = 0;
825
826 switch (iga) {
827 case IGA1:
828 /* XXX if (type == CN900) { */
829 iga1_fifo_max_depth = CN900_IGA1_FIFO_MAX_DEPTH;
830 iga1_fifo_threshold = CN900_IGA1_FIFO_THRESHOLD;
831 iga1_fifo_high_threshold = CN900_IGA1_FIFO_HIGH_THRESHOLD;
832 if (horact > 1280 && veract > 1024)
833 iga1_display_queue_expire_num = 16;
834 else
835 iga1_display_queue_expire_num =
836 CN900_IGA1_DISPLAY_QUEUE_EXPIRE_NUM;
837 /* XXX } */
838
839 /* set display FIFO depth select */
840 val = IGA1_FIFO_DEPTH_SELECT_FORMULA(iga1_fifo_max_depth);
841 regnum =
842 display_fifo_depth_reg.iga1_fifo_depth_select_reg.reg_num;
843 reg = display_fifo_depth_reg.iga1_fifo_depth_select_reg.reg;
844 uni_load_reg(sc, val, regnum, reg, VIASR);
845
846 /* set display FIFO threshold select */
847 val = IGA1_FIFO_THRESHOLD_FORMULA(iga1_fifo_threshold);
848 regnum = fifo_threshold_select_reg.iga1_fifo_threshold_select_reg.reg_num;
849 reg = fifo_threshold_select_reg.iga1_fifo_threshold_select_reg.reg;
850 uni_load_reg(sc, val, regnum, reg, VIASR);
851
852 /* set display FIFO high threshold select */
853 val = IGA1_FIFO_HIGH_THRESHOLD_FORMULA(iga1_fifo_high_threshold);
854 regnum = fifo_high_threshold_select_reg.iga1_fifo_high_threshold_select_reg.reg_num;
855 reg = fifo_high_threshold_select_reg.iga1_fifo_high_threshold_select_reg.reg;
856 uni_load_reg(sc, val, regnum, reg, VIASR);
857
858 /* set display queue expire num */
859 val = IGA1_DISPLAY_QUEUE_EXPIRE_NUM_FORMULA(iga1_display_queue_expire_num);
860 regnum = display_queue_expire_num_reg.iga1_display_queue_expire_num_reg.reg_num;
861 reg = display_queue_expire_num_reg.iga1_display_queue_expire_num_reg.reg;
862 uni_load_reg(sc, val, regnum, reg, VIASR);
863
864 break;
865 default:
866 printf("%s: %s: only IGA1 is supported\n", sc->sc_dev.dv_xname,
867 __func__);
868 break;
869 }
870
871 return;
872 }
873
874 static void
875 uni_set_depth(struct unichromefb_softc *sc, int bpp, int iga)
876 {
877 switch (iga) {
878 case IGA1:
879 switch (bpp) {
880 case MODE_32BPP:
881 uni_wr_mask(sc, VIASR, SR15, 0xae, 0xfe);
882 break;
883 case MODE_16BPP:
884 uni_wr_mask(sc, VIASR, SR15, 0xb6, 0xfe);
885 break;
886 case MODE_8BPP:
887 uni_wr_mask(sc, VIASR, SR15, 0x22, 0xfe);
888 break;
889 default:
890 printf("%s: %s: mode (%d) unsupported\n",
891 sc->sc_dev.dv_xname, __func__, bpp);
892 }
893 break;
894 default:
895 printf("%s: %s: only IGA1 is supported\n", sc->sc_dev.dv_xname,
896 __func__);
897 break;
898 }
899 }
900
901 static uint32_t
902 uni_get_clkval(struct unichromefb_softc *sc, int clk)
903 {
904 int i;
905
906 for (i = 0; i < NUM_TOTAL_PLL_TABLE; i++) {
907 if (clk == pll_value[i].clk) {
908 /* XXX only CN900 supported for now */
909 return pll_value[i].k800_pll;
910 }
911 }
912
913 aprint_error("%s: can't find matching PLL value\n",
914 sc->sc_dev.dv_xname);
915
916 return 0;
917 }
918
919 static void
920 uni_set_vclk(struct unichromefb_softc *sc, uint32_t clk, int iga)
921 {
922 uint8_t val;
923
924 /* hardware reset on */
925 uni_wr_mask(sc, VIACR, CR17, 0x00, BIT7);
926
927 switch (iga) {
928 case IGA1:
929 /* XXX only CN900 is supported */
930 uni_wr(sc, VIASR, SR44, clk / 0x10000);
931 uni_wr(sc, VIASR, SR45, (clk & 0xffff) / 0x100);
932 uni_wr(sc, VIASR, SR46, clk % 0x100);
933 break;
934 default:
935 printf("%s: %s: only IGA1 is supported\n", sc->sc_dev.dv_xname,
936 __func__);
937 break;
938 }
939
940 /* hardware reset off */
941 uni_wr_mask(sc, VIACR, CR17, 0x80, BIT7);
942
943 /* reset pll */
944 switch (iga) {
945 case IGA1:
946 uni_wr_mask(sc, VIASR, SR40, 0x02, BIT1);
947 uni_wr_mask(sc, VIASR, SR40, 0x00, BIT1);
948 break;
949 }
950
951 /* good to go */
952 val = bus_space_read_1(sc->sc_iot, sc->sc_ioh, VIARMisc);
953 val |= (BIT2+BIT3);
954 bus_space_write_1(sc->sc_iot, sc->sc_ioh, VIAWMisc, val);
955
956 return;
957 }
958
959 /* XXX */
960 int
961 unichromefb_cnattach(void)
962 {
963 return 0;
964 }
965