Annotation of sys/arch/sparc/dev/p9100.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: p9100.c,v 1.45 2007/07/13 19:18:18 miod Exp $ */
2:
3: /*
4: * Copyright (c) 2003, 2005, 2006, Miodrag Vallat.
5: * Copyright (c) 1999 Jason L. Wright (jason@thought.net)
6: * All rights reserved.
7: *
8: * Redistribution and use in source and binary forms, with or without
9: * modification, are permitted provided that the following conditions
10: * are met:
11: * 1. Redistributions of source code must retain the above copyright
12: * notice, this list of conditions and the following disclaimer.
13: * 2. Redistributions in binary form must reproduce the above copyright
14: * notice, this list of conditions and the following disclaimer in the
15: * documentation and/or other materials provided with the distribution.
16: *
17: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19: * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20: * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
21: * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22: * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
23: * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
25: * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
26: * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27: * POSSIBILITY OF SUCH DAMAGE.
28: */
29:
30: /*
31: * color display (p9100) driver.
32: * Initially based on cgthree.c and the NetBSD p9100 driver, then hacked
33: * beyond recognition.
34: */
35:
36: #include <sys/param.h>
37: #include <sys/systm.h>
38: #include <sys/buf.h>
39: #include <sys/device.h>
40: #include <sys/ioctl.h>
41: #include <sys/malloc.h>
42: #include <sys/mman.h>
43: #include <sys/tty.h>
44: #include <sys/conf.h>
45:
46: #include <uvm/uvm_extern.h>
47:
48: #include <machine/autoconf.h>
49: #include <machine/bsd_openprom.h>
50: #include <machine/pmap.h>
51: #include <machine/cpu.h>
52: #include <machine/conf.h>
53:
54: #include <dev/wscons/wsconsio.h>
55: #include <dev/wscons/wsdisplayvar.h>
56: #include <dev/rasops/rasops.h>
57: #include <dev/wsfont/wsfont.h>
58: #include <machine/fbvar.h>
59:
60: #include <sparc/dev/btreg.h>
61: #include <sparc/dev/btvar.h>
62: #include <sparc/dev/sbusvar.h>
63:
64: #include <dev/ic/ibm525reg.h>
65: #include <dev/ic/p9000.h>
66:
67: #include "tctrl.h"
68: #if NTCTRL > 0
69: #include <sparc/dev/tctrlvar.h>
70: #endif
71:
72: #undef FIDDLE_WITH_PCI_REGISTERS
73:
74: /*
75: * SBus registers mappings
76: */
77: #define P9100_NREG 4
78: #define P9100_REG_CTL 0
79: #define P9100_REG_CMD 1
80: #define P9100_REG_VRAM 2
81: #define P9100_REG_CONFIG 3
82:
83: #ifdef FIDDLE_WITH_PCI_REGISTERS
84: /*
85: * This structure, mapped at register address 0x9100, allows non-PCI
86: * designs (such as the SPARCbook) to access the PCI configuration space.
87: */
88: struct p9100_pci {
89: volatile u_int32_t address; /* within configuration space */
90: volatile u_int32_t data; /* _byte_ to read or write */
91: };
92: #endif
93:
94: /* per-display variables */
95: struct p9100_softc {
96: struct sunfb sc_sunfb; /* common base part */
97: struct rom_reg sc_phys[P9100_NREG - 1];
98: volatile u_int8_t *sc_cmd; /* command registers (dac, etc) */
99: volatile u_int8_t *sc_ctl; /* control registers (draw engine) */
100: #ifdef FIDDLE_WITH_PCI_REGISTERS
101: struct p9100_pci *sc_pci; /* pci configuration space access */
102: #endif
103: vsize_t sc_vramsize; /* total VRAM available */
104: union bt_cmap sc_cmap; /* Brooktree color map */
105: struct intrhand sc_ih;
106: int sc_mapmode;
107: u_int sc_flags;
108: #define SCF_INTERNAL 0x01 /* internal video enabled */
109: #define SCF_EXTERNAL 0x02 /* external video enabled */
110: #if NTCTRL > 0
111: #define SCF_MAPPEDSWITCH 0x04 /* switch mode when leaving emul */
112: u_int sc_mapwidth; /* non-emul video mode parameters */
113: u_int sc_mapheight;
114: u_int sc_mapdepth;
115: #endif
116: u_int sc_lcdheight; /* LCD panel geometry */
117: u_int sc_lcdwidth;
118:
119: u_int32_t sc_junk; /* throwaway value */
120: };
121:
122: void p9100_burner(void *, u_int, u_int);
123: void p9100_external_video(void *, int);
124: void p9100_initialize_ramdac(struct p9100_softc *, u_int, u_int);
125: int p9100_intr(void *);
126: int p9100_ioctl(void *, u_long, caddr_t, int, struct proc *);
127: static __inline__
128: void p9100_loadcmap_deferred(struct p9100_softc *, u_int, u_int);
129: void p9100_loadcmap_immediate(struct p9100_softc *, u_int, u_int);
130: paddr_t p9100_mmap(void *, off_t, int);
131: int p9100_pick_romfont(struct p9100_softc *);
132: void p9100_prom(void *);
133: void p9100_setcolor(void *, u_int, u_int8_t, u_int8_t, u_int8_t);
134: u_int p9100_read_ramdac(struct p9100_softc *, u_int);
135: void p9100_write_ramdac(struct p9100_softc *, u_int, u_int);
136:
137: struct wsdisplay_accessops p9100_accessops = {
138: p9100_ioctl,
139: p9100_mmap,
140: NULL, /* alloc_screen */
141: NULL, /* free_screen */
142: NULL, /* show_screen */
143: NULL, /* load_font */
144: NULL, /* scrollback */
145: NULL, /* getchar */
146: p9100_burner,
147: NULL /* pollc */
148: };
149:
150: void p9100_ras_copycols(void *, int, int, int, int);
151: void p9100_ras_copyrows(void *, int, int, int);
152: void p9100_ras_do_cursor(struct rasops_info *);
153: void p9100_ras_erasecols(void *, int, int, int, long int);
154: void p9100_ras_eraserows(void *, int, int, long int);
155: void p9100_ras_init(struct p9100_softc *);
156:
157: int p9100match(struct device *, void *, void *);
158: void p9100attach(struct device *, struct device *, void *);
159:
160: struct cfattach pnozz_ca = {
161: sizeof (struct p9100_softc), p9100match, p9100attach
162: };
163:
164: struct cfdriver pnozz_cd = {
165: NULL, "pnozz", DV_DULL
166: };
167:
168: /*
169: * IBM RGB525 RAMDAC registers
170: */
171:
172: #define IBM525_WRADDR 0 /* Palette write address */
173: #define IBM525_DATA 1 /* Palette data */
174: #define IBM525_PIXMASK 2 /* Pixel mask */
175: #define IBM525_RDADDR 3 /* Read palette address */
176: #define IBM525_IDXLOW 4 /* Register index low */
177: #define IBM525_IDXHIGH 5 /* Register index high */
178: #define IBM525_REGDATA 6 /* Register data */
179: #define IBM525_IDXCONTROL 7 /* Index control */
180:
181: /*
182: * P9100 read/write macros
183: */
184:
185: #define P9100_READ_CTL(sc,reg) \
186: *(volatile u_int32_t *)((sc)->sc_ctl + (reg))
187: #define P9100_READ_CMD(sc,reg) \
188: *(volatile u_int32_t *)((sc)->sc_cmd + (reg))
189: #define P9100_READ_RAMDAC(sc,reg) \
190: (*(volatile u_int32_t *)((sc)->sc_ctl + P9100_RAMDAC_REGISTER(reg)) \
191: >> 16)
192:
193: #define P9100_WRITE_CTL(sc,reg,value) \
194: *(volatile u_int32_t *)((sc)->sc_ctl + (reg)) = (value)
195: #define P9100_WRITE_CMD(sc,reg,value) \
196: *(volatile u_int32_t *)((sc)->sc_cmd + (reg)) = (value)
197: #define P9100_WRITE_RAMDAC(sc,reg,value) \
198: *(volatile u_int32_t *)((sc)->sc_ctl + P9100_RAMDAC_REGISTER(reg)) = \
199: ((value) << 16)
200:
201: /*
202: * On the Tadpole, the first write to a register group is ignored until
203: * the proper group address is latched, which can be done by reading from the
204: * register group first.
205: *
206: * Register groups are 0x80 bytes long (i.e. it is necessary to force a read
207: * when writing to an address which upper 25 bit differ from the previous
208: * read or write operation).
209: *
210: * This is specific to the Tadpole design, and not a limitation of the
211: * Power 9100 hardware.
212: */
213: #define P9100_SELECT_SCR(sc) \
214: (sc)->sc_junk = P9100_READ_CTL(sc, P9000_SYSTEM_CONFIG)
215: #define P9100_SELECT_VCR(sc) \
216: (sc)->sc_junk = P9100_READ_CTL(sc, P9000_HCR)
217: #define P9100_SELECT_VRAM(sc) \
218: (sc)->sc_junk = P9100_READ_CTL(sc, P9000_MCR)
219: #define P9100_SELECT_DAC(sc) \
220: (sc)->sc_junk = P9100_READ_CTL(sc, P9100_RAMDAC_REGISTER(0))
221: #define P9100_SELECT_PE(sc) \
222: (sc)->sc_junk = P9100_READ_CMD(sc, P9000_PE_STATUS)
223: #define P9100_SELECT_DE_LOW(sc) \
224: (sc)->sc_junk = P9100_READ_CMD(sc, P9000_DE_FG_COLOR)
225: #define P9100_SELECT_DE_HIGH(sc) \
226: (sc)->sc_junk = P9100_READ_CMD(sc, P9000_DE_PATTERN(0))
227: #define P9100_SELECT_COORD(sc,field) \
228: (sc)->sc_junk = P9100_READ_CMD(sc, field)
229:
230: /*
231: * For some reason, every write to a DAC register needs to be followed by a
232: * read from the ``free fifo number'' register, supposedly to have the write
233: * take effect faster...
234: */
235: #define P9100_FLUSH_DAC(sc) \
236: do { \
237: P9100_SELECT_VRAM(sc); \
238: (sc)->sc_junk = P9100_READ_CTL(sc, P9100_FREE_FIFO); \
239: } while (0)
240:
241: int
242: p9100match(struct device *parent, void *vcf, void *aux)
243: {
244: struct confargs *ca = aux;
245: struct romaux *ra = &ca->ca_ra;
246:
247: if (strcmp("p9100", ra->ra_name))
248: return (0);
249:
250: return (1);
251: }
252:
253: /*
254: * Attach a display.
255: */
256: void
257: p9100attach(struct device *parent, struct device *self, void *args)
258: {
259: struct p9100_softc *sc = (struct p9100_softc *)self;
260: struct rasops_info *ri = &sc->sc_sunfb.sf_ro;
261: struct confargs *ca = args;
262: struct romaux *ra = &ca->ca_ra;
263: int node, pri, scr, force_reset;
264: int isconsole, fontswitch, clear = 0;
265:
266: pri = ca->ca_ra.ra_intr[0].int_pri;
267: printf(" pri %d", pri);
268:
269: #ifdef DIAGNOSTIC
270: if (ra->ra_nreg < P9100_NREG) {
271: printf(": expected %d registers, got only %d\n",
272: P9100_NREG, ra->ra_nreg);
273: return;
274: }
275: #endif
276:
277: sc->sc_flags = SCF_INTERNAL;
278: sc->sc_mapmode = WSDISPLAYIO_MODE_EMUL;
279:
280: bcopy(ra->ra_reg, sc->sc_phys, sizeof(sc->sc_phys));
281:
282: sc->sc_ctl = mapiodev(&ra->ra_reg[P9100_REG_CTL], 0,
283: ra->ra_reg[P9100_REG_CTL].rr_len);
284: sc->sc_cmd = mapiodev(&ra->ra_reg[P9100_REG_CMD], 0,
285: ra->ra_reg[P9100_REG_CMD].rr_len);
286: #ifdef FIDDLE_WITH_PCI_REGISTERS
287: sc->sc_pci = (struct p9100_pci *)
288: mapiodev(&ra->ra_reg[P9100_REG_CONFIG], 0,
289: ra->ra_reg[P9100_REG_CONFIG].rr_len);
290: #endif
291:
292: node = ra->ra_node;
293: isconsole = node == fbnode;
294:
295: P9100_SELECT_SCR(sc);
296: scr = P9100_READ_CTL(sc, P9000_SYSTEM_CONFIG);
297: switch (scr & SCR_PIXEL_MASK) {
298: default:
299: #ifdef DIAGNOSTIC
300: printf(": unknown color depth code 0x%x",
301: scr & SCR_PIXEL_MASK);
302: #endif
303: /* FALLTHROUGH */
304: case SCR_PIXEL_32BPP:
305: case SCR_PIXEL_24BPP:
306: case SCR_PIXEL_16BPP:
307: force_reset = 1;
308: break;
309: case SCR_PIXEL_8BPP:
310: force_reset = 0;
311: break;
312: }
313:
314: fb_setsize(&sc->sc_sunfb, 8, 800, 600, node, ca->ca_bustype);
315:
316: /*
317: * We expect the PROM to initialize us in the best 8 bit mode
318: * supported by the LCD (640x480 on 3XP, 800x600 on 3GS/3GX).
319: */
320: sc->sc_lcdwidth = sc->sc_sunfb.sf_width;
321: sc->sc_lcdheight = sc->sc_sunfb.sf_height;
322:
323: #if NTCTRL > 0
324: /*
325: * We want to run the frame buffer in 8bpp mode for the emulation mode,
326: * and use a potentially better mode for the mapped (X11) mode.
327: * Eventually this will become runtime user-selectable.
328: */
329:
330: sc->sc_mapwidth = sc->sc_lcdwidth;
331: sc->sc_mapheight = sc->sc_lcdheight;
332: sc->sc_mapdepth = 8;
333:
334: if (sc->sc_mapwidth != sc->sc_sunfb.sf_width ||
335: sc->sc_mapdepth != sc->sc_sunfb.sf_depth)
336: SET(sc->sc_flags, SCF_MAPPEDSWITCH);
337: #endif
338:
339: ri->ri_bits = mapiodev(&ra->ra_reg[P9100_REG_VRAM], 0,
340: sc->sc_vramsize = round_page(ra->ra_reg[P9100_REG_VRAM].rr_len));
341: ri->ri_hw = sc;
342:
343: printf(": rev %x, %dx%d\n", scr & SCR_ID_MASK,
344: sc->sc_lcdwidth, sc->sc_lcdheight);
345:
346: /* Disable frame buffer interrupts */
347: P9100_SELECT_SCR(sc);
348: P9100_WRITE_CTL(sc, P9000_INTERRUPT_ENABLE, IER_MASTER_ENABLE | 0);
349:
350: sc->sc_ih.ih_fun = p9100_intr;
351: sc->sc_ih.ih_arg = sc;
352: intr_establish(pri, &sc->sc_ih, IPL_FB, self->dv_xname);
353:
354: /*
355: * Try to get a copy of the PROM font.
356: *
357: * If we can, we still need to adjust the visible portion of the
358: * display, as the PROM output is offset two chars to the left.
359: *
360: * If we can't, we'll switch to the 8x16 font, and we'll need to adjust
361: * two things:
362: * - the display row should be overrided from the current PROM metrics,
363: * to prevent us from overwriting the last few lines of text.
364: * - if the 80x34 screen would make a large margin appear around it,
365: * choose to clear the screen rather than keeping old prom output in
366: * the margins.
367: * XXX there should be a rasops "clear margins" feature
368: */
369: fontswitch = p9100_pick_romfont(sc);
370:
371: /*
372: * Register the external video control callback with tctrl; tctrl
373: * will invoke it immediately to set the appropriate behaviour.
374: * If tctrl is not configured, simply enable external video.
375: */
376: #if NTCTRL > 0
377: tadpole_register_extvideo(p9100_external_video, sc);
378: #else
379: p9100_external_video(sc, 1);
380: #endif
381:
382: if (isconsole == 0 || fontswitch)
383: clear = 1;
384: fbwscons_init(&sc->sc_sunfb, clear ? RI_CLEAR : 0);
385: if (clear == 0) {
386: ri->ri_bits -= 2 * ri->ri_xscale;
387: ri->ri_xorigin -= 2 * ri->ri_xscale;
388: }
389: fbwscons_setcolormap(&sc->sc_sunfb, p9100_setcolor);
390:
391: /*
392: * Plug-in accelerated console operations.
393: */
394: if (sc->sc_sunfb.sf_dev.dv_cfdata->cf_flags != 0 ||
395: sc->sc_sunfb.sf_width == 800)
396: p9100_ras_init(sc);
397:
398: /* enable video */
399: p9100_burner(sc, 1, 0);
400:
401: if (isconsole) {
402: fbwscons_console_init(&sc->sc_sunfb, clear ? 0 : -1);
403: #if NTCTRL > 0
404: shutdownhook_establish(p9100_prom, sc);
405: #endif
406: }
407:
408: fbwscons_attach(&sc->sc_sunfb, &p9100_accessops, isconsole);
409: }
410:
411: int
412: p9100_ioctl(void *v, u_long cmd, caddr_t data, int flags, struct proc *p)
413: {
414: struct p9100_softc *sc = v;
415: struct wsdisplay_fbinfo *wdf;
416: struct wsdisplay_cmap *cm;
417: #if NTCTRL > 0
418: struct wsdisplay_param *dp;
419: #endif
420: int error;
421:
422: switch (cmd) {
423:
424: case WSDISPLAYIO_GTYPE:
425: *(u_int *)data = WSDISPLAY_TYPE_SB_P9100;
426: break;
427:
428: case WSDISPLAYIO_SMODE:
429: sc->sc_mapmode = *(u_int *)data;
430: switch (sc->sc_mapmode) {
431: case WSDISPLAYIO_MODE_DUMBFB:
432: case WSDISPLAYIO_MODE_MAPPED:
433: #if NTCTRL > 0
434: if (ISSET(sc->sc_flags, SCF_MAPPEDSWITCH))
435: p9100_initialize_ramdac(sc,
436: sc->sc_mapwidth, sc->sc_mapdepth);
437: #endif
438: break;
439: case WSDISPLAYIO_MODE_EMUL:
440: #if NTCTRL > 0
441: if (ISSET(sc->sc_flags, SCF_MAPPEDSWITCH))
442: p9100_initialize_ramdac(sc, sc->sc_lcdwidth, 8);
443: #endif
444: fbwscons_setcolormap(&sc->sc_sunfb, p9100_setcolor);
445: /* Restore proper acceleration state as well */
446: if (sc->sc_sunfb.sf_dev.dv_cfdata->cf_flags != 0 ||
447: sc->sc_sunfb.sf_width == 800)
448: p9100_ras_init(sc);
449: break;
450: }
451: break;
452:
453: case WSDISPLAYIO_GINFO:
454: wdf = (struct wsdisplay_fbinfo *)data;
455: #if NTCTRL > 0
456: if (ISSET(sc->sc_flags, SCF_MAPPEDSWITCH)) {
457: wdf->width = sc->sc_mapwidth;
458: wdf->height = sc->sc_mapheight;
459: wdf->depth = sc->sc_mapdepth;
460: wdf->cmsize = sc->sc_mapdepth == 8 ? 256 : 0;
461: } else
462: #endif
463: {
464: wdf->width = sc->sc_lcdwidth;
465: wdf->height = sc->sc_lcdheight;
466: wdf->depth = 8;
467: wdf->cmsize = 256;
468: }
469: break;
470:
471: case WSDISPLAYIO_LINEBYTES:
472: #if NTCTRL > 0
473: if (ISSET(sc->sc_flags, SCF_MAPPEDSWITCH))
474: *(u_int *)data = sc->sc_mapwidth *
475: (sc->sc_mapdepth / 8);
476: else
477: #endif
478: *(u_int *)data = sc->sc_sunfb.sf_linebytes;
479: break;
480:
481: case WSDISPLAYIO_GETCMAP:
482: cm = (struct wsdisplay_cmap *)data;
483: error = bt_getcmap(&sc->sc_cmap, cm);
484: if (error)
485: return (error);
486: break;
487:
488: case WSDISPLAYIO_PUTCMAP:
489: cm = (struct wsdisplay_cmap *)data;
490: error = bt_putcmap(&sc->sc_cmap, cm);
491: if (error)
492: return (error);
493: p9100_loadcmap_deferred(sc, cm->index, cm->count);
494: break;
495:
496: #if NTCTRL > 0
497: case WSDISPLAYIO_GETPARAM:
498: dp = (struct wsdisplay_param *)data;
499:
500: switch (dp->param) {
501: case WSDISPLAYIO_PARAM_BRIGHTNESS:
502: dp->min = 0;
503: dp->max = 255;
504: dp->curval = tadpole_get_brightness();
505: break;
506: case WSDISPLAYIO_PARAM_BACKLIGHT:
507: dp->min = 0;
508: dp->max = 1;
509: if (ISSET(sc->sc_flags, SCF_INTERNAL))
510: dp->curval =
511: tadpole_get_video() & TV_ON ? 1 : 0;
512: else
513: dp->curval = 0;
514: break;
515: default:
516: return (-1);
517: }
518: break;
519:
520: case WSDISPLAYIO_SETPARAM:
521: dp = (struct wsdisplay_param *)data;
522:
523: switch (dp->param) {
524: case WSDISPLAYIO_PARAM_BRIGHTNESS:
525: tadpole_set_brightness(dp->curval);
526: break;
527: case WSDISPLAYIO_PARAM_BACKLIGHT:
528: if (ISSET(sc->sc_flags, SCF_INTERNAL))
529: tadpole_set_video(dp->curval);
530: break;
531: default:
532: return (-1);
533: }
534: break;
535: #endif /* NTCTRL > 0 */
536:
537: case WSDISPLAYIO_SVIDEO:
538: case WSDISPLAYIO_GVIDEO:
539: break;
540:
541: case WSDISPLAYIO_GCURPOS:
542: case WSDISPLAYIO_SCURPOS:
543: case WSDISPLAYIO_GCURMAX:
544: case WSDISPLAYIO_GCURSOR:
545: case WSDISPLAYIO_SCURSOR:
546: default:
547: return (-1); /* not supported yet */
548: }
549:
550: return (0);
551: }
552:
553: paddr_t
554: p9100_mmap(void *v, off_t offset, int prot)
555: {
556: struct p9100_softc *sc = v;
557: struct rom_reg *rr;
558:
559: if ((offset & PAGE_MASK) != 0)
560: return (-1);
561:
562: switch (sc->sc_mapmode) {
563: case WSDISPLAYIO_MODE_MAPPED:
564: /*
565: * We provide the following mapping:
566: * 000000 - 0000ff control registers
567: * 002000 - 003fff command registers
568: * 800000 - 9fffff vram
569: */
570: rr = &sc->sc_phys[P9100_REG_CTL];
571: if (offset >= 0 && offset < rr->rr_len)
572: break;
573: offset -= 0x2000;
574: rr = &sc->sc_phys[P9100_REG_CMD];
575: if (offset >= 0 && offset < rr->rr_len)
576: break;
577: offset -= (0x800000 - 0x2000);
578: /* FALLTHROUGH */
579: case WSDISPLAYIO_MODE_DUMBFB:
580: rr = &sc->sc_phys[P9100_REG_VRAM];
581: if (offset >= 0 && offset < sc->sc_vramsize)
582: break;
583: /* FALLTHROUGH */
584: default:
585: return (-1);
586: }
587:
588: return (REG2PHYS(rr, offset) | PMAP_NC);
589: }
590:
591: void
592: p9100_setcolor(void *v, u_int index, u_int8_t r, u_int8_t g, u_int8_t b)
593: {
594: struct p9100_softc *sc = v;
595: union bt_cmap *bcm = &sc->sc_cmap;
596:
597: bcm->cm_map[index][0] = r;
598: bcm->cm_map[index][1] = g;
599: bcm->cm_map[index][2] = b;
600: p9100_loadcmap_immediate(sc, index, 1);
601: }
602:
603: void
604: p9100_loadcmap_immediate(struct p9100_softc *sc, u_int start, u_int ncolors)
605: {
606: u_char *p;
607:
608: P9100_SELECT_DAC(sc);
609: P9100_WRITE_RAMDAC(sc, IBM525_WRADDR, start);
610: P9100_FLUSH_DAC(sc);
611:
612: for (p = sc->sc_cmap.cm_map[start], ncolors *= 3; ncolors-- > 0; p++) {
613: P9100_SELECT_DAC(sc);
614: P9100_WRITE_RAMDAC(sc, IBM525_DATA, (*p));
615: P9100_FLUSH_DAC(sc);
616: }
617: }
618:
619: static __inline__ void
620: p9100_loadcmap_deferred(struct p9100_softc *sc, u_int start, u_int ncolors)
621: {
622: /* Schedule an interrupt for next retrace */
623: P9100_SELECT_SCR(sc);
624: P9100_WRITE_CTL(sc, P9000_INTERRUPT_ENABLE,
625: IER_MASTER_ENABLE | IER_MASTER_INTERRUPT |
626: IER_VBLANK_ENABLE | IER_VBLANK_INTERRUPT);
627: }
628:
629: u_int
630: p9100_read_ramdac(struct p9100_softc *sc, u_int reg)
631: {
632: P9100_SELECT_DAC(sc);
633:
634: P9100_WRITE_RAMDAC(sc, IBM525_IDXLOW, (reg & 0xff));
635: P9100_FLUSH_DAC(sc);
636: P9100_WRITE_RAMDAC(sc, IBM525_IDXHIGH, ((reg >> 8) & 0xff));
637: P9100_FLUSH_DAC(sc);
638: return (P9100_READ_RAMDAC(sc, IBM525_REGDATA));
639: }
640:
641: void
642: p9100_write_ramdac(struct p9100_softc *sc, u_int reg, u_int value)
643: {
644: P9100_SELECT_DAC(sc);
645:
646: P9100_WRITE_RAMDAC(sc, IBM525_IDXLOW, (reg & 0xff));
647: P9100_FLUSH_DAC(sc);
648: P9100_WRITE_RAMDAC(sc, IBM525_IDXHIGH, ((reg >> 8) & 0xff));
649: P9100_FLUSH_DAC(sc);
650: P9100_WRITE_RAMDAC(sc, IBM525_REGDATA, value);
651: P9100_FLUSH_DAC(sc);
652: }
653:
654: void
655: p9100_burner(void *v, u_int on, u_int flags)
656: {
657: struct p9100_softc *sc = v;
658: u_int32_t vcr;
659: int s;
660:
661: s = splhigh();
662: P9100_SELECT_VCR(sc);
663: vcr = P9100_READ_CTL(sc, P9000_SRTC1);
664: if (on)
665: vcr |= SRTC1_VIDEN;
666: else
667: vcr &= ~SRTC1_VIDEN;
668: P9100_WRITE_CTL(sc, P9000_SRTC1, vcr);
669: #if NTCTRL > 0
670: if (ISSET(sc->sc_flags, SCF_INTERNAL))
671: tadpole_set_video(on);
672: #endif
673: splx(s);
674: }
675:
676: int
677: p9100_intr(void *v)
678: {
679: struct p9100_softc *sc = v;
680:
681: if (P9100_READ_CTL(sc, P9000_INTERRUPT) & IER_VBLANK_INTERRUPT) {
682: p9100_loadcmap_immediate(sc, 0, 256);
683:
684: /* Disable further interrupts now */
685: /* P9100_SELECT_SCR(sc); */
686: P9100_WRITE_CTL(sc, P9000_INTERRUPT_ENABLE,
687: IER_MASTER_ENABLE | 0);
688:
689: /* Clear interrupt condition */
690: P9100_WRITE_CTL(sc, P9000_INTERRUPT,
691: IER_VBLANK_ENABLE | 0);
692:
693: return (1);
694: }
695:
696: return (0);
697: }
698:
699: /*
700: * Accelerated text console code
701: */
702:
703: static int p9100_drain(struct p9100_softc *);
704:
705: static int
706: p9100_drain(struct p9100_softc *sc)
707: {
708: u_int i;
709:
710: for (i = 10000; i !=0; i--) {
711: if ((P9100_READ_CMD(sc, P9000_PE_STATUS) &
712: (STATUS_QUAD_BUSY | STATUS_BLIT_BUSY)) == 0)
713: break;
714: }
715:
716: return (i);
717: }
718:
719: void
720: p9100_ras_init(struct p9100_softc *sc)
721: {
722:
723: if (p9100_drain(sc) == 0)
724: return;
725:
726: sc->sc_sunfb.sf_ro.ri_ops.copycols = p9100_ras_copycols;
727: sc->sc_sunfb.sf_ro.ri_ops.copyrows = p9100_ras_copyrows;
728: sc->sc_sunfb.sf_ro.ri_ops.erasecols = p9100_ras_erasecols;
729: sc->sc_sunfb.sf_ro.ri_ops.eraserows = p9100_ras_eraserows;
730: sc->sc_sunfb.sf_ro.ri_do_cursor = p9100_ras_do_cursor;
731:
732: /*
733: * Setup safe defaults for the parameter and drawing engines, in
734: * order to minimize the operations to do for ri_ops.
735: */
736:
737: P9100_SELECT_DE_LOW(sc);
738: P9100_WRITE_CMD(sc, P9000_DE_DRAWMODE,
739: DM_PICK_CONTROL | 0 | DM_BUFFER_CONTROL | DM_BUFFER_ENABLE0);
740:
741: P9100_WRITE_CMD(sc, P9000_DE_PATTERN_ORIGIN_X, 0);
742: P9100_WRITE_CMD(sc, P9000_DE_PATTERN_ORIGIN_Y, 0);
743: /* enable all planes */
744: P9100_WRITE_CMD(sc, P9000_DE_PLANEMASK, 0xffffffff);
745:
746: /* Unclip */
747: P9100_WRITE_CMD(sc, P9000_DE_WINMIN, 0);
748: P9100_WRITE_CMD(sc, P9000_DE_WINMAX,
749: P9000_COORDS(sc->sc_sunfb.sf_width - 1, sc->sc_sunfb.sf_height - 1));
750:
751: P9100_SELECT_DE_HIGH(sc);
752: P9100_WRITE_CMD(sc, P9100_DE_B_WINMIN, 0);
753: P9100_WRITE_CMD(sc, P9100_DE_B_WINMAX,
754: P9000_COORDS(sc->sc_sunfb.sf_width - 1, sc->sc_sunfb.sf_height - 1));
755:
756: P9100_SELECT_PE(sc);
757: P9100_WRITE_CMD(sc, P9000_PE_WINOFFSET, 0);
758: P9100_WRITE_CMD(sc, P9000_PE_INDEX, 0);
759: P9100_WRITE_CMD(sc, P9000_PE_WINMIN, 0);
760: P9100_WRITE_CMD(sc, P9000_PE_WINMAX,
761: P9000_COORDS(sc->sc_sunfb.sf_width - 1, sc->sc_sunfb.sf_height - 1));
762: }
763:
764: void
765: p9100_ras_copycols(void *v, int row, int src, int dst, int n)
766: {
767: struct rasops_info *ri = v;
768: struct p9100_softc *sc = ri->ri_hw;
769:
770: n *= ri->ri_font->fontwidth;
771: n--;
772: src *= ri->ri_font->fontwidth;
773: src += ri->ri_xorigin;
774: dst *= ri->ri_font->fontwidth;
775: dst += ri->ri_xorigin;
776: row *= ri->ri_font->fontheight;
777: row += ri->ri_yorigin;
778:
779: p9100_drain(sc);
780: P9100_SELECT_DE_LOW(sc);
781: P9100_WRITE_CMD(sc, P9000_DE_RASTER,
782: P9100_RASTER_SRC & P9100_RASTER_MASK);
783:
784: P9100_SELECT_COORD(sc, P9000_DC_COORD(0));
785: P9100_WRITE_CMD(sc, P9000_DC_COORD(0) + P9000_COORD_XY,
786: P9000_COORDS(src, row));
787: P9100_WRITE_CMD(sc, P9000_DC_COORD(1) + P9000_COORD_XY,
788: P9000_COORDS(src + n, row + ri->ri_font->fontheight - 1));
789: P9100_SELECT_COORD(sc, P9000_DC_COORD(2));
790: P9100_WRITE_CMD(sc, P9000_DC_COORD(2) + P9000_COORD_XY,
791: P9000_COORDS(dst, row));
792: P9100_WRITE_CMD(sc, P9000_DC_COORD(3) + P9000_COORD_XY,
793: P9000_COORDS(dst + n, row + ri->ri_font->fontheight - 1));
794:
795: sc->sc_junk = P9100_READ_CMD(sc, P9000_PE_BLIT);
796:
797: p9100_drain(sc);
798: }
799:
800: void
801: p9100_ras_copyrows(void *v, int src, int dst, int n)
802: {
803: struct rasops_info *ri = v;
804: struct p9100_softc *sc = ri->ri_hw;
805:
806: n *= ri->ri_font->fontheight;
807: n--;
808: src *= ri->ri_font->fontheight;
809: src += ri->ri_yorigin;
810: dst *= ri->ri_font->fontheight;
811: dst += ri->ri_yorigin;
812:
813: p9100_drain(sc);
814: P9100_SELECT_DE_LOW(sc);
815: P9100_WRITE_CMD(sc, P9000_DE_RASTER,
816: P9100_RASTER_SRC & P9100_RASTER_MASK);
817:
818: P9100_SELECT_COORD(sc, P9000_DC_COORD(0));
819: P9100_WRITE_CMD(sc, P9000_DC_COORD(0) + P9000_COORD_XY,
820: P9000_COORDS(ri->ri_xorigin, src));
821: P9100_WRITE_CMD(sc, P9000_DC_COORD(1) + P9000_COORD_XY,
822: P9000_COORDS(ri->ri_xorigin + ri->ri_emuwidth - 1, src + n));
823: P9100_SELECT_COORD(sc, P9000_DC_COORD(2));
824: P9100_WRITE_CMD(sc, P9000_DC_COORD(2) + P9000_COORD_XY,
825: P9000_COORDS(ri->ri_xorigin, dst));
826: P9100_WRITE_CMD(sc, P9000_DC_COORD(3) + P9000_COORD_XY,
827: P9000_COORDS(ri->ri_xorigin + ri->ri_emuwidth - 1, dst + n));
828:
829: sc->sc_junk = P9100_READ_CMD(sc, P9000_PE_BLIT);
830:
831: p9100_drain(sc);
832: }
833:
834: void
835: p9100_ras_erasecols(void *v, int row, int col, int n, long int attr)
836: {
837: struct rasops_info *ri = v;
838: struct p9100_softc *sc = ri->ri_hw;
839: int fg, bg;
840:
841: ri->ri_ops.unpack_attr(v, attr, &fg, &bg, NULL);
842: bg = ri->ri_devcmap[bg];
843:
844: n *= ri->ri_font->fontwidth;
845: col *= ri->ri_font->fontwidth;
846: col += ri->ri_xorigin;
847: row *= ri->ri_font->fontheight;
848: row += ri->ri_yorigin;
849:
850: p9100_drain(sc);
851: P9100_SELECT_DE_LOW(sc);
852: P9100_WRITE_CMD(sc, P9000_DE_RASTER,
853: P9100_RASTER_PATTERN & P9100_RASTER_MASK);
854: P9100_WRITE_CMD(sc, P9100_DE_COLOR0, P9100_COLOR8(bg));
855:
856: P9100_SELECT_COORD(sc, P9000_LC_RECT);
857: P9100_WRITE_CMD(sc, P9000_LC_RECT + P9000_COORD_XY,
858: P9000_COORDS(col, row));
859: P9100_WRITE_CMD(sc, P9000_LC_RECT + P9000_COORD_XY,
860: P9000_COORDS(col + n, row + ri->ri_font->fontheight));
861:
862: sc->sc_junk = P9100_READ_CMD(sc, P9000_PE_QUAD);
863:
864: p9100_drain(sc);
865: }
866:
867: void
868: p9100_ras_eraserows(void *v, int row, int n, long int attr)
869: {
870: struct rasops_info *ri = v;
871: struct p9100_softc *sc = ri->ri_hw;
872: int fg, bg;
873:
874: ri->ri_ops.unpack_attr(v, attr, &fg, &bg, NULL);
875: bg = ri->ri_devcmap[bg];
876:
877: p9100_drain(sc);
878: P9100_SELECT_DE_LOW(sc);
879: P9100_WRITE_CMD(sc, P9000_DE_RASTER,
880: P9100_RASTER_PATTERN & P9100_RASTER_MASK);
881: P9100_WRITE_CMD(sc, P9100_DE_COLOR0, P9100_COLOR8(bg));
882:
883: P9100_SELECT_COORD(sc, P9000_LC_RECT);
884: if (n == ri->ri_rows && ISSET(ri->ri_flg, RI_FULLCLEAR)) {
885: P9100_WRITE_CMD(sc, P9000_LC_RECT + P9000_COORD_XY,
886: P9000_COORDS(0, 0));
887: P9100_WRITE_CMD(sc, P9000_LC_RECT + P9000_COORD_XY,
888: P9000_COORDS(ri->ri_width, ri->ri_height));
889: } else {
890: n *= ri->ri_font->fontheight;
891: row *= ri->ri_font->fontheight;
892: row += ri->ri_yorigin;
893:
894: P9100_WRITE_CMD(sc, P9000_LC_RECT + P9000_COORD_XY,
895: P9000_COORDS(ri->ri_xorigin, row));
896: P9100_WRITE_CMD(sc, P9000_LC_RECT + P9000_COORD_XY,
897: P9000_COORDS(ri->ri_xorigin + ri->ri_emuwidth, row + n));
898: }
899:
900: sc->sc_junk = P9100_READ_CMD(sc, P9000_PE_QUAD);
901:
902: p9100_drain(sc);
903: }
904:
905: void
906: p9100_ras_do_cursor(struct rasops_info *ri)
907: {
908: struct p9100_softc *sc = ri->ri_hw;
909: int row, col;
910:
911: row = ri->ri_crow * ri->ri_font->fontheight + ri->ri_yorigin;
912: col = ri->ri_ccol * ri->ri_font->fontwidth + ri->ri_xorigin;
913:
914: p9100_drain(sc);
915:
916: P9100_SELECT_DE_LOW(sc);
917: P9100_WRITE_CMD(sc, P9000_DE_RASTER,
918: (P9100_RASTER_PATTERN ^ P9100_RASTER_DST) & P9100_RASTER_MASK);
919: P9100_WRITE_CMD(sc, P9100_DE_COLOR0,
920: P9100_COLOR8(ri->ri_devcmap[WSCOL_BLACK]));
921:
922: P9100_SELECT_COORD(sc, P9000_LC_RECT);
923: P9100_WRITE_CMD(sc, P9000_LC_RECT + P9000_COORD_XY,
924: P9000_COORDS(col, row));
925: P9100_WRITE_CMD(sc, P9000_LC_RECT + P9000_COORD_XY,
926: P9000_COORDS(col + ri->ri_font->fontwidth,
927: row + ri->ri_font->fontheight));
928:
929: sc->sc_junk = P9100_READ_CMD(sc, P9000_PE_QUAD);
930:
931: p9100_drain(sc);
932: }
933:
934: /*
935: * PROM font managment
936: */
937:
938: #define ROMFONTNAME "p9100_romfont"
939: struct wsdisplay_font p9100_romfont = {
940: ROMFONTNAME,
941: 0,
942: 0, 256,
943: WSDISPLAY_FONTENC_ISO, /* should check the `character-set' property */
944: 0, 0, 0,
945: WSDISPLAY_FONTORDER_L2R,
946: WSDISPLAY_FONTORDER_L2R,
947: NULL,
948: NULL
949: };
950:
951: int
952: p9100_pick_romfont(struct p9100_softc *sc)
953: {
954: struct rasops_info *ri = &sc->sc_sunfb.sf_ro;
955: int *romwidth, *romheight;
956: u_int8_t **romaddr;
957: char buf[200];
958:
959: /*
960: * This code currently only works for PROM >= 2.9; see
961: * autoconf.c romgetcursoraddr() for details.
962: */
963: if (promvec->pv_romvec_vers < 2 || promvec->pv_printrev < 0x00020009)
964: return (1);
965:
966: /*
967: * Get the PROM font metrics and address
968: */
969: if (snprintf(buf, sizeof buf, "stdout @ is my-self "
970: "addr char-height %lx ! addr char-width %lx ! addr font-base %lx !",
971: (vaddr_t)&romheight, (vaddr_t)&romwidth, (vaddr_t)&romaddr) >=
972: sizeof buf)
973: return (1);
974: romheight = romwidth = NULL;
975: rominterpret(buf);
976:
977: if (romheight == NULL || romwidth == NULL || romaddr == NULL ||
978: *romheight == 0 || *romwidth == 0 || *romaddr == NULL)
979: return (1);
980:
981: p9100_romfont.fontwidth = *romwidth;
982: p9100_romfont.fontheight = *romheight;
983: p9100_romfont.stride = howmany(*romwidth, NBBY);
984: p9100_romfont.data = *romaddr;
985:
986: #ifdef DEBUG
987: printf("%s: PROM font %dx%d @%p",
988: sc->sc_sunfb.sf_dev.dv_xname, *romwidth, *romheight, *romaddr);
989: #endif
990:
991: /*
992: * Build and add a wsfont structure
993: */
994: wsfont_init(); /* if not done before */
995: if (wsfont_add(&p9100_romfont, 0) != 0)
996: return (1);
997:
998: /*
999: * Select this very font in our rasops structure
1000: */
1001: ri->ri_wsfcookie = wsfont_find(ROMFONTNAME, 0, 0, 0);
1002: if (wsfont_lock(ri->ri_wsfcookie, &ri->ri_font,
1003: WSDISPLAY_FONTORDER_L2R, WSDISPLAY_FONTORDER_L2R) <= 0) {
1004: ri->ri_wsfcookie = 0;
1005: return (1);
1006: }
1007:
1008: return (0);
1009: }
1010:
1011: /*
1012: * External video control
1013: */
1014:
1015: void
1016: p9100_external_video(void *v, int on)
1017: {
1018: struct p9100_softc *sc = v;
1019: int s;
1020:
1021: s = splhigh();
1022:
1023: if (on) {
1024: p9100_write_ramdac(sc, IBM525_POWER,
1025: p9100_read_ramdac(sc, IBM525_POWER) & ~P_DAC_PWR_DISABLE);
1026: SET(sc->sc_flags, SCF_EXTERNAL);
1027: } else {
1028: p9100_write_ramdac(sc, IBM525_POWER,
1029: p9100_read_ramdac(sc, IBM525_POWER) | P_DAC_PWR_DISABLE);
1030: CLR(sc->sc_flags, SCF_EXTERNAL);
1031: }
1032:
1033: splx(s);
1034: }
1035:
1036: /*
1037: * Video mode programming
1038: *
1039: * All magic values come from s3gxtrmb.pdf.
1040: */
1041:
1042: #if NTCTRL > 0
1043:
1044: /* IBM RGB525 registers and values */
1045:
1046: static const u_int8_t p9100_dacreg[] = {
1047: IBM525_MISC1,
1048: IBM525_MISC2,
1049: IBM525_MISC3,
1050: IBM525_MISC4,
1051: IBM525_MISC_CLOCK,
1052: IBM525_SYNC,
1053: IBM525_HSYNC_POS,
1054: IBM525_POWER,
1055: IBM525_DAC_OP,
1056: IBM525_PALETTE,
1057: IBM525_PIXEL,
1058: IBM525_PF8,
1059: IBM525_PF16,
1060: IBM525_PF24,
1061: IBM525_PF32,
1062: IBM525_PLL1,
1063: IBM525_PLL2,
1064: IBM525_PLL_FIXED_REF,
1065: IBM525_SYSCLK,
1066: IBM525_PLL_REF_DIV,
1067: IBM525_PLL_VCO_DIV,
1068: 0
1069: };
1070:
1071: static u_int8_t p9100_dacval[] = {
1072: M1_SENSE_DISABLE | M1_VRAM_64,
1073: M2_PCLK_PLL | M2_PALETTE_8 | M2_MODE_VRAM,
1074: 0,
1075: 0, /* will be computed */
1076: MC_B24P_SCLK | MC_PLL_ENABLE, /* will be modified */
1077: S_HSYN_NORMAL | S_VSYN_NORMAL,
1078: 0,
1079: 0, /* will be computed */
1080: DO_FAST_SLEW,
1081: 0,
1082: 0, /* will be computed */
1083: PF8_INDIRECT,
1084: PF16_DIRECT | PF16_LINEAR | PF16_565,
1085: PF24_DIRECT,
1086: PF32_DIRECT,
1087: P1_CLK_REF | P1_SRC_EXT_F | P1_SRC_DIRECT_F,
1088: 0, /* F0, will be set before */
1089: 5,
1090: SC_ENABLE,
1091: 5,
1092: MHZ_TO_PLL(50)
1093: };
1094:
1095: /* Power 9100 registers and values */
1096:
1097: static const u_int32_t p9100_reg[] = {
1098: P9000_HTR,
1099: P9000_HSRE,
1100: P9000_HBRE,
1101: P9000_HBFE,
1102: P9000_HCP,
1103: P9000_VL,
1104: P9000_VSRE,
1105: P9000_VBRE,
1106: P9000_VBFE,
1107: P9000_VCP,
1108: 0
1109: };
1110:
1111: static const u_int32_t p9100_val_800_32[] = {
1112: 0x1f3, 0x023, 0x053, 0x1e3, 0x000, 0x271, 0x002, 0x016, 0x26e, 0x000
1113: };
1114: #if 0 /* No X server for this mode, yet */
1115: static const u_int32_t p9100_val_800_24[] = {
1116: 0x176, 0x01a, 0x03d, 0x169, 0x000, 0x271, 0x002, 0x016, 0x26e, 0x000
1117: };
1118: #endif
1119: static const u_int32_t p9100_val_800_8[] = {
1120: 0x07c, 0x008, 0x011, 0x075, 0x000, 0x271, 0x002, 0x016, 0x26e, 0x000
1121: };
1122: #if NTCTRL > 0
1123: static const u_int32_t p9100_val_640_32[] = {
1124: 0x18f, 0x02f, 0x043, 0x183, 0x000, 0x205, 0x003, 0x022, 0x202, 0x000
1125: };
1126: static const u_int32_t p9100_val_640_8[] = {
1127: 0x063, 0x00b, 0x00d, 0x05d, 0x000, 0x205, 0x003, 0x022, 0x202, 0x000
1128: };
1129: static const u_int32_t p9100_val_1024_8[] = {
1130: 0x0a7, 0x019, 0x022, 0x0a2, 0x000, 0x325, 0x003, 0x023, 0x323, 0x000
1131: };
1132: #endif
1133:
1134: void
1135: p9100_initialize_ramdac(struct p9100_softc *sc, u_int width, u_int depth)
1136: {
1137: int s;
1138: const u_int8_t *dacregp, *dacvalp;
1139: const u_int32_t *p9regp, *p9valp;
1140: u_int8_t pllclk, dacval;
1141: u_int32_t scr;
1142:
1143: /*
1144: * XXX Switching to a low-res 8bpp mode causes kernel faults
1145: * XXX unless coming from an high-res 8bpp mode, and I have
1146: * XXX no idea why.
1147: */
1148: if (depth == 8 && width != 1024)
1149: p9100_initialize_ramdac(sc, 1024, 8);
1150:
1151: switch (width) {
1152: case 1024:
1153: p9valp = p9100_val_1024_8;
1154: pllclk = MHZ_TO_PLL(65);
1155: /* 1024 bytes scanline */
1156: scr = SCR_SC(0, 0, 0, 1) | SCR_PIXEL_8BPP;
1157: break;
1158: default:
1159: /* FALLTHROUGH */
1160: case 800:
1161: switch (depth) {
1162: case 32:
1163: p9valp = p9100_val_800_32;
1164: /* 3200 = 128 + 1024 + 2048 bytes scanline */
1165: scr = SCR_SC(3, 6, 7, 0) |
1166: SCR_PIXEL_32BPP | SCR_SWAP_WORDS | SCR_SWAP_BYTES;
1167: break;
1168: #if 0
1169: case 24:
1170: p9valp = p9100_val_800_24;
1171: /* 2400 = 32 + 64 + 256 + 2048 bytes scanline */
1172: scr = SCR_SC(1, 2, 4, 2) | SCR_PIXEL_24BPP;
1173: break;
1174: #endif
1175: default:
1176: case 8:
1177: p9valp = p9100_val_800_8;
1178: /* 800 = 32 + 256 + 512 bytes scanline */
1179: scr = SCR_SC(1, 4, 5, 0) | SCR_PIXEL_8BPP;
1180: break;
1181: }
1182: pllclk = MHZ_TO_PLL(36);
1183: break;
1184: case 640:
1185: switch (depth) {
1186: case 32:
1187: p9valp = p9100_val_640_32;
1188: /* 2560 = 512 + 2048 bytes scanline */
1189: scr = SCR_SC(5, 7, 0, 0) |
1190: SCR_PIXEL_32BPP | SCR_SWAP_WORDS | SCR_SWAP_BYTES;
1191: break;
1192: default:
1193: case 8:
1194: p9valp = p9100_val_640_8;
1195: /* 640 = 128 + 512 bytes scanline */
1196: scr = SCR_SC(3, 5, 0, 0) | SCR_PIXEL_8BPP;
1197: break;
1198: }
1199: pllclk = MHZ_TO_PLL(25);
1200: break;
1201: }
1202: dacvalp = p9100_dacval;
1203:
1204: s = splhigh();
1205:
1206: #ifdef FIDDLE_WITH_PCI_REGISTERS
1207: /*
1208: * Magical initialization sequence, from s3gxtrmb.pdf.
1209: * DANGER! Sometimes freezes the machine solid, cause unknown.
1210: */
1211: sc->sc_pci->address = 0x13000000;
1212: sc->sc_pci->data = 0;
1213: sc->sc_pci->address = 0x30000000;
1214: sc->sc_pci->data = 0;
1215: sc->sc_pci->address = 0x41000000;
1216: sc->sc_pci->data = 0; /* No register mapping at a0000 */
1217: sc->sc_pci->address = 0x04000000;
1218: sc->sc_pci->data = 0xa3000000;
1219: #endif
1220:
1221: /*
1222: * Initialize the RAMDAC
1223: */
1224: P9100_SELECT_DAC(sc);
1225: P9100_WRITE_RAMDAC(sc, IBM525_PIXMASK, 0xff);
1226: P9100_FLUSH_DAC(sc);
1227: P9100_WRITE_RAMDAC(sc, IBM525_IDXCONTROL, 0x00);
1228: P9100_FLUSH_DAC(sc);
1229:
1230: p9100_write_ramdac(sc, IBM525_F(0), pllclk);
1231: for (dacregp = p9100_dacreg; *dacregp != 0; dacregp++, dacvalp++) {
1232: switch (*dacregp) {
1233: case IBM525_MISC4:
1234: dacval = pllclk >= MHZ_TO_PLL(50) ?
1235: M4_FAST : M4_INVERT_DCLK;
1236: break;
1237: case IBM525_MISC_CLOCK:
1238: dacval = *dacvalp & ~MC_DDOT_DIV_MASK;
1239: switch (depth) {
1240: case 32:
1241: dacval |= MC_DDOT_DIV_2;
1242: break;
1243: case 16:
1244: dacval |= MC_DDOT_DIV_4;
1245: break;
1246: default:
1247: case 24:
1248: case 8:
1249: dacval |= MC_DDOT_DIV_8;
1250: break;
1251: }
1252: break;
1253: case IBM525_POWER:
1254: if (depth == 24)
1255: dacval = 0;
1256: else
1257: dacval = P_SCLK_DISABLE;
1258: break;
1259: case IBM525_PIXEL:
1260: switch (depth) {
1261: case 32:
1262: dacval = PIX_32BPP;
1263: break;
1264: case 24:
1265: dacval = PIX_24BPP;
1266: break;
1267: case 16:
1268: dacval = PIX_16BPP;
1269: break;
1270: default:
1271: case 8:
1272: dacval = PIX_8BPP;
1273: break;
1274: }
1275: break;
1276: default:
1277: dacval = *dacvalp;
1278: break;
1279: }
1280: p9100_write_ramdac(sc, *dacregp, dacval);
1281: }
1282:
1283: /*
1284: * Initialize the Power 9100
1285: */
1286:
1287: P9100_SELECT_SCR(sc);
1288: P9100_WRITE_CTL(sc, P9000_SYSTEM_CONFIG, scr);
1289: P9100_SELECT_VCR(sc);
1290: P9100_WRITE_CTL(sc, P9000_SRTC1,
1291: SRTC1_VSYNC_INTERNAL | SRTC1_HSYNC_INTERNAL | SRTC1_VIDEN | 0x03);
1292: P9100_WRITE_CTL(sc, P9000_SRTC2, 0x05);
1293: P9100_SELECT_VRAM(sc);
1294: P9100_WRITE_CTL(sc, P9000_MCR, 0xc808007d);
1295: delay(3000);
1296:
1297: P9100_SELECT_VCR(sc);
1298: for (p9regp = p9100_reg; *p9regp != 0; p9regp++, p9valp++)
1299: P9100_WRITE_CTL(sc, *p9regp, *p9valp);
1300:
1301: P9100_SELECT_VRAM(sc);
1302: P9100_WRITE_CTL(sc, P9000_REFRESH_PERIOD, 0x3ff);
1303:
1304: /* Disable frame buffer interrupts */
1305: P9100_SELECT_SCR(sc);
1306: P9100_WRITE_CTL(sc, P9000_INTERRUPT_ENABLE, IER_MASTER_ENABLE | 0);
1307:
1308: /*
1309: * Enable internal video... (it's a kind of magic)
1310: */
1311: p9100_write_ramdac(sc, IBM525_MISC4,
1312: p9100_read_ramdac(sc, IBM525_MISC4) | 0xc0);
1313:
1314: /*
1315: * ... unless it does not fit.
1316: */
1317: if (width != sc->sc_lcdwidth) {
1318: CLR(sc->sc_flags, SCF_INTERNAL);
1319: tadpole_set_video(0);
1320: } else {
1321: SET(sc->sc_flags, SCF_INTERNAL);
1322: tadpole_set_video(1);
1323: }
1324:
1325: p9100_external_video(sc, ISSET(sc->sc_flags, SCF_EXTERNAL));
1326:
1327: splx(s);
1328: }
1329:
1330: void
1331: p9100_prom(void *v)
1332: {
1333: struct p9100_softc *sc = v;
1334:
1335: if (ISSET(sc->sc_flags, SCF_MAPPEDSWITCH) &&
1336: sc->sc_mapmode != WSDISPLAYIO_MODE_EMUL) {
1337: p9100_initialize_ramdac(sc, sc->sc_lcdwidth, 8);
1338: fbwscons_setcolormap(&sc->sc_sunfb, p9100_setcolor);
1339: if (sc->sc_sunfb.sf_dev.dv_cfdata->cf_flags != 0 ||
1340: sc->sc_sunfb.sf_width == 800)
1341: p9100_ras_init(sc);
1342: }
1343: }
1344: #endif /* NTCTRL > 0 */
CVSweb