grf_cv.c revision 1.3.2.4 1 /* $NetBSD: grf_cv.c,v 1.3.2.4 1996/03/06 18:20:17 is Exp $ */
2
3 /*
4 * Copyright (c) 1995 Michael Teske
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 Ezra Story, by Kari
18 * Mettinen and by Bernd Ernesti.
19 * 4. The name of the author may not be used to endorse or promote products
20 * derived from this software without specific prior written permission
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
23 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
24 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
25 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
26 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
27 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
31 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 */
33 #include "grfcv.h"
34 #if NGRFCV > 0
35
36 #undef CV64CONSOLE /* DO NOT REMOVE THIS till ite5 is ready */
37
38 /*
39 * Graphics routines for the CyberVision 64 board, using the S3 Trio64.
40 *
41 * Modified for CV64 from
42 * Kari Mettinen's Cirrus driver by Michael Teske 10/95
43 * For questions mail me at teske (at) dice2.desy.de
44 *
45 * Thanks to Tekelec Airtronic for providing me with a S3 Trio64 documentation.
46 * Thanks to Bernd 'the fabulous bug-finder' Ernesti for bringing my messy
47 * source to NetBSD style :)
48 *
49 * TODO:
50 * Hardware Cursor support
51 * Blitter support
52 *
53 * BUGS:
54 * Xamiag24 and grf_cv can crash when you use fvwm with xterm's, you can
55 * avoid this by starting the xterm with '-ah', see the manpage of xterm
56 * for more informations about this switch.
57 * There is a bug in the Trio64 which produce a small (1 or 2 pixel) white
58 * vertical bar on the right side of an 8bit-Screen (only when you use more
59 * then 80MHz pixelclock). This has to be fixed in the Xserver.
60 *
61 */
62
63 #include <sys/param.h>
64 #include <sys/errno.h>
65 #include <sys/ioctl.h>
66 #include <sys/device.h>
67 #include <sys/malloc.h>
68 #include <sys/systm.h>
69 #include <machine/cpu.h>
70 #include <dev/cons.h>
71 #include <amiga/amiga/device.h>
72 #include <amiga/dev/grfioctl.h>
73 #include <amiga/dev/grfvar.h>
74 #include <amiga/dev/grf_cvreg.h>
75 #include <amiga/dev/zbusvar.h>
76
77 int grfcvmatch __P((struct device *, struct cfdata *, void *));
78 void grfcvattach __P((struct device *, struct device *, void *));
79 int grfcvprint __P((void *, char *));
80
81 static int cv_has_4mb __P((volatile char *));
82 static unsigned short compute_clock __P((unsigned long));
83 void cv_boardinit __P((struct grf_softc *));
84 int cv_getvmode __P((struct grf_softc *, struct grfvideo_mode *));
85 int cv_setvmode __P((struct grf_softc *, unsigned int));
86 int cv_blank __P((struct grf_softc *, int *));
87 int cv_mode __P((register struct grf_softc *, int, void *, int, int));
88 int cv_ioctl __P((register struct grf_softc *gp, int cmd, void *data));
89 int cv_setmonitor __P((struct grf_softc *, struct grfvideo_mode *));
90 int cv_getcmap __P((struct grf_softc *, struct grf_colormap *));
91 int cv_putcmap __P((struct grf_softc *, struct grf_colormap *));
92 int cv_toggle __P((struct grf_softc *));
93 int cv_mondefok __P((struct grfvideo_mode *));
94 int cv_load_mon __P((struct grf_softc *, struct grfcvtext_mode *));
95 void cv_inittextmode __P((struct grf_softc *));
96 void cv_memset __P((unsigned char *, unsigned char, int));
97
98 #ifdef CV64CONSOLE
99 extern void grfcv_iteinit __P((struct grf_softc *));
100 #endif
101
102 /* Graphics display definitions.
103 * These are filled by 'grfconfig' using GRFIOCSETMON.
104 */
105 #define monitor_def_max 8
106 static struct grfvideo_mode monitor_def[8] = {
107 {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0}
108 };
109 static struct grfvideo_mode *monitor_current = &monitor_def[0];
110 #define MAXPIXELCLOCK 135000000 /* safety */
111
112
113 /* Console display definition.
114 * Default hardcoded text mode. This grf_cv is set up to
115 * use one text mode only, and this is it. You may use
116 * grfconfig to change the mode after boot.
117 */
118
119 /* Console font */
120 #define S3FONT kernel_font_8x8
121 #define S3FONTX 8
122 #define S3FONTY 8
123 extern unsigned char S3FONT[];
124
125 struct grfcvtext_mode cvconsole_mode = {
126 {255, "", 25000000, 640, 400, 4, 640, 656, 672, 720, 760, 406,
127 441, 412, 426, 447},
128 S3FONTX, S3FONTY, 80, 506/S3FONTY, S3FONT, 32, 255
129 };
130
131 /* Console colors */
132 unsigned char cvconscolors[3][3] = { /* background, foreground, hilite */
133 {0,0x40,0x50}, {152,152,152}, {255,255,255}
134 };
135
136
137 /* Board Address of CV64 */
138
139 static volatile caddr_t cv_boardaddr;
140 static int cv_fbsize;
141
142 int
143 grfcv_cnprobe()
144 {
145 int rv;
146 rv = CN_DEAD;
147 return (rv);
148 }
149
150 /* standard driver stuff */
151 struct cfdriver grfcvcd = {
152 NULL, "grfcv", (cfmatch_t)grfcvmatch, grfcvattach,
153 DV_DULL, sizeof(struct grf_softc), NULL, 0
154 };
155 static struct cfdata *cfdata;
156
157
158 /* Reads from the fb must be done at addr + 0x02000000 */
159 #define READ_OFFSET 0x02000000
160
161 /*
162 * Get frambuffer memory size.
163 * phase5 didn't provide the bit in CR36,
164 * so we have to do it this way.
165 * Return 0 for 2MB, 1 for 4MB
166 */
167
168 static int
169 cv_has_4mb (volatile char *fb)
170 {
171 volatile unsigned long *testfbw, *testfbr;
172
173 /* write patterns in memory and test if they can be read */
174 testfbw = (volatile unsigned long *) fb;
175 *testfbw = 0x87654321;
176 testfbr = (volatile unsigned long *)(fb + READ_OFFSET);
177 if (*testfbr != 0x87654321)
178 return (0);
179 /* upper memory region */
180 testfbw = (volatile unsigned long *)(fb + 0x00200000);
181 testfbr = (volatile unsigned long *)(fb + 0x00200000 + READ_OFFSET);
182 *testfbw = 0x87654321;
183 if (*testfbr != 0x87654321)
184 return (0);
185 *testfbw = 0xAAAAAAAA;
186 if (*testfbr != 0xAAAAAAAA)
187 return (0);
188 *testfbw = 0x55555555;
189 if (*testfbr != 0x55555555)
190 return (0);
191 return (1);
192 }
193
194 int
195 grfcvmatch(pdp, cfp, auxp)
196 struct device *pdp;
197 struct cfdata *cfp;
198 void *auxp;
199 {
200 struct zbus_args *zap;
201
202 zap = auxp;
203
204 #ifndef CV64CONSOLE
205 if (amiga_realconfig == 0)
206 return (0);
207 #endif
208
209 /* Lets be Paranoid: Test man and prod id */
210 if (zap->manid != 8512 || zap->prodid != 34)
211 return (0);
212
213 cv_boardaddr = zap->va;
214
215 #ifdef CV64CONSOLE
216 if (amiga_realconfig == 0) {
217 cfdata = cfp;
218 }
219 #endif
220
221 return (1);
222 }
223
224 void
225 grfcvattach(pdp, dp, auxp)
226 struct device *pdp, *dp;
227 void *auxp;
228 {
229 struct zbus_args *zap;
230 struct grf_softc *gp;
231
232 zap = auxp;
233
234 printf("\n");
235
236 gp = (struct grf_softc *)dp;
237
238 gp->g_regkva = (volatile caddr_t)cv_boardaddr + READ_OFFSET;
239 gp->g_fbkva = (volatile caddr_t)cv_boardaddr + 0x01400000;
240
241 gp->g_unit = GRF_CV64_UNIT;
242 gp->g_mode = cv_mode;
243 gp->g_conpri = grfcv_cnprobe();
244 gp->g_flags = GF_ALIVE;
245
246 /* wakeup the board */
247 cv_boardinit(gp);
248
249 #ifdef CV64CONSOLE
250 grfcv_iteinit(gp);
251 (void)cv_load_mon(gp, &cvconsole_mode);
252 #endif
253
254 /*
255 * attach grf
256 */
257 if (amiga_config_found(cfdata, &gp->g_device, gp, grfcvprint))
258 printf("grfcv: CyberVision64 with %dMB being used\n", cv_fbsize/0x100000);
259 }
260
261 int
262 grfcvprint(auxp, pnp)
263 void *auxp;
264 char *pnp;
265 {
266 if (pnp)
267 printf("ite at %s: ", pnp);
268 return (UNCONF);
269 }
270
271
272 /*
273 * Computes M, N, and R values from
274 * given input frequency. It uses a table of
275 * precomputed values, to keep CPU time low.
276 *
277 * The return value consist of:
278 * lower byte: Bits 4-0: N Divider Value
279 * Bits 5-6: R Value for e.g. SR10 or SR12
280 * higher byte: Bits 0-6: M divider value for e.g. SR11 or SR13
281 */
282
283 static unsigned short
284 compute_clock(freq)
285 unsigned long freq;
286 {
287
288 static unsigned char *mnr, *save; /* M, N + R vals */
289 unsigned long work_freq, r;
290 unsigned short erg;
291 long diff, d2;
292
293 /* 0xBEBC20 = 12.5M */
294 /* 0x080BEFC0 = 135M */
295 if (freq < 0x00BEBC20 || freq > 0x080BEFC0) {
296 printf("grfcv: Wrong clock frequency: %dMHz", freq/1000000);
297 printf("grfcv: Using default frequency: 25MHz");
298 freq = 0x017D7840;
299 }
300
301 mnr = clocks; /* there the vals are stored */
302 d2 = 0x7fffffff;
303
304 while (*mnr) { /* mnr vals are 0-terminated */
305 work_freq = (0x37EE * (mnr[0] + 2)) / ((mnr[1] & 0x1F) + 2);
306
307 r = (mnr[1] >> 5) & 0x03;
308 if (r != 0)
309 work_freq=work_freq >> r; /* r is the freq divider */
310
311 work_freq *= 0x3E8; /* 2nd part of OSC */
312
313 diff = abs(freq - work_freq);
314
315 if (d2 >= diff) {
316 d2 = diff;
317 /* In save are the vals for minimal diff */
318 save = mnr;
319 }
320 mnr += 2;
321 }
322 erg = *((unsigned short *)save);
323
324 return (erg);
325 }
326
327
328 void
329 cv_boardinit(gp)
330 struct grf_softc *gp;
331 {
332 volatile caddr_t ba = gp->g_regkva;
333 unsigned char test;
334 unsigned int clockpar;
335 int i;
336 struct grfinfo *gi;
337
338 /* Reset board */
339 for (i = 0; i < 6; i++)
340 cv_write_port (0xff, ba - READ_OFFSET); /* Clear all bits */
341
342 /* Return to operational Mode */
343 cv_write_port(0x8004, ba - READ_OFFSET);
344
345 /* Wakeup Chip */
346 vgaw(ba, SREG_VIDEO_SUBS_ENABLE, 0x10);
347 vgaw(ba, SREG_OPTION_SELECT, 0x1);
348 vgaw(ba, SREG_VIDEO_SUBS_ENABLE, 0x8);
349
350 vgaw(ba, GREG_MISC_OUTPUT_W, 0x23);
351
352 WCrt(ba, CRT_ID_REGISTER_LOCK_1, 0x48); /* unlock S3 VGA regs */
353 WCrt(ba, CRT_ID_REGISTER_LOCK_2, 0xA5); /* unlock syscontrol */
354
355 test = RCrt(ba, CRT_ID_SYSTEM_CONFIG);
356 test = test | 0x01; /* enable enhaced register access */
357 test = test & 0xEF; /* clear bit 4, 0 wait state */
358 WCrt(ba, CRT_ID_SYSTEM_CONFIG, test);
359
360 /*
361 * bit 1=1: enable enhanced mode functions
362 * bit 4=1: enable linear adressing
363 */
364 vgaw(ba, ECR_ADV_FUNC_CNTL, 0x11);
365
366 /* enable cpu acess, color mode, high 64k page */
367 vgaw(ba, GREG_MISC_OUTPUT_W, 0x23);
368
369 /* Cpu base addr */
370 WCrt(ba, CRT_ID_EXT_SYS_CNTL_4, 0x0);
371
372 /* Reset. This does nothing, but everyone does it:) */
373 WSeq(ba, SEQ_ID_RESET, 0x3);
374
375 WSeq(ba, SEQ_ID_CLOCKING_MODE, 0x1); /* 8 Dot Clock */
376 WSeq(ba, SEQ_ID_MAP_MASK, 0xF); /* Enable write planes */
377 WSeq(ba, SEQ_ID_CHAR_MAP_SELECT, 0x0); /* Character Font */
378
379 WSeq(ba, SEQ_ID_MEMORY_MODE, 0x2); /* Complete mem access */
380
381 WSeq(ba, SEQ_ID_UNLOCK_EXT, 0x6); /* Unlock extensions */
382 test = RSeq(ba, SEQ_ID_BUS_REQ_CNTL); /* Bus Request */
383
384 /* enable 4MB fast Page Mode */
385 test = test | 1 << 6;
386 WSeq(ba, SEQ_ID_BUS_REQ_CNTL, test);
387 /* faster LUT write */
388 WSeq(ba, SEQ_ID_RAMDAC_CNTL, 0x40);
389
390 test = RSeq(ba, SEQ_ID_CLKSYN_CNTL_2); /* Clksyn2 read */
391
392 /* immediately Clkload bit clear */
393 test = test & 0xDF;
394 WSeq(ba, SEQ_ID_CLKSYN_CNTL_2, test);
395
396 clockpar = compute_clock(0x3473BC0);
397 test = (clockpar & 0xFF00) >> 8;
398
399 if (RCrt(ba, CRT_ID_REVISION) == 0x10) {
400 WSeq(ba, SEQ_ID_MCLK_HI, test); /* PLL N-Divider Value */
401
402 test = clockpar & 0xFF;
403 WSeq(ba, SEQ_ID_MCLK_LO, test); /* PLL M-Divider Value */
404
405 test = (clockpar & 0xFF00) >> 8;
406 WSeq(ba, SEQ_ID_MORE_MAGIC, test);
407 } else {
408 WSeq(ba, SEQ_ID_MCLK_HI, test); /* PLL N-Divider Value */
409
410 test = clockpar & 0xFF;
411 WSeq(ba, SEQ_ID_MCLK_LO, test); /* PLL M-Divider Value */
412 }
413
414 /* We now load an 25 MHz, 31 kHz, 640x480 standard VGA Mode. */
415 /* DCLK */
416 WSeq(ba, SEQ_ID_DCLK_HI, 0x13);
417 WSeq(ba, SEQ_ID_DCLK_LO, 0x41);
418
419 test = RSeq (ba, SEQ_ID_CLKSYN_CNTL_2);
420 test = test | 0x22;
421
422 /* DCLK + MCLK Clock immediate load! */
423 WSeq(ba,SEQ_ID_CLKSYN_CNTL_2, test);
424
425 /* DCLK load */
426 test = vgar(ba, 0x3cc);
427 test = test | 0x0c;
428 vgaw(ba, 0x3c2, test);
429
430 /* Clear bit 5 again, prevent further loading. */
431 WSeq(ba, SEQ_ID_CLKSYN_CNTL_2, 0x2);
432
433 WCrt(ba, CRT_ID_HOR_TOTAL, 0x5F);
434 WCrt(ba, CRT_ID_HOR_DISP_ENA_END, 0x4F);
435 WCrt(ba, CRT_ID_START_HOR_BLANK, 0x50);
436 WCrt(ba, CRT_ID_END_HOR_BLANK, 0x82);
437 WCrt(ba, CRT_ID_START_HOR_RETR, 0x54);
438 WCrt(ba, CRT_ID_END_HOR_RETR, 0x80);
439 WCrt(ba, CRT_ID_VER_TOTAL, 0xBF);
440
441 WCrt(ba, CRT_ID_OVERFLOW, 0x1F); /* overflow reg */
442
443 WCrt(ba, CRT_ID_PRESET_ROW_SCAN, 0x0); /* no panning */
444
445 WCrt(ba, CRT_ID_MAX_SCAN_LINE, 0x40); /* vscan */
446
447 WCrt(ba, CRT_ID_CURSOR_START, 0x00);
448 WCrt(ba, CRT_ID_CURSOR_END, 0x00);
449
450 /* Display start adress */
451 WCrt(ba, CRT_ID_START_ADDR_HIGH, 0x00);
452 WCrt(ba, CRT_ID_START_ADDR_LOW, 0x00);
453
454 /* Cursor location */
455 WCrt(ba, CRT_ID_CURSOR_LOC_HIGH, 0x00);
456 WCrt(ba, CRT_ID_CURSOR_LOC_LOW, 0x00);
457
458 /* Vertical retrace */
459 WCrt(ba, CRT_ID_START_VER_RETR, 0x9C);
460 WCrt(ba, CRT_ID_END_VER_RETR, 0x0E);
461
462 WCrt(ba, CRT_ID_VER_DISP_ENA_END, 0x8F);
463 WCrt(ba, CRT_ID_SCREEN_OFFSET, 0x50);
464
465 WCrt(ba, CRT_ID_UNDERLINE_LOC, 0x00);
466
467 WCrt(ba, CRT_ID_START_VER_BLANK, 0x96);
468 WCrt(ba, CRT_ID_END_VER_BLANK, 0xB9);
469
470 WCrt(ba, CRT_ID_MODE_CONTROL, 0xE3);
471
472 WCrt(ba, CRT_ID_LINE_COMPARE, 0xFF);
473
474 WCrt(ba, CRT_ID_BACKWAD_COMP_3, 0x10); /* FIFO enabled */
475
476 /* Refresh count 1, High speed text font, enhanced color mode */
477 WCrt(ba, CRT_ID_MISC_1, 0x35);
478
479 /* start fifo position */
480 WCrt(ba, CRT_ID_DISPLAY_FIFO, 0x5a);
481
482 WCrt(ba, CRT_ID_EXT_MEM_CNTL_2, 0x70);
483
484 /* address window position */
485 WCrt(ba, CRT_ID_LAW_POS_LO, 0x40);
486
487 /* N Parameter for Display FIFO */
488 WCrt(ba, CRT_ID_EXT_MEM_CNTL_3, 0xFF);
489
490 WGfx(ba, GCT_ID_SET_RESET, 0x0);
491 WGfx(ba, GCT_ID_ENABLE_SET_RESET, 0x0);
492 WGfx(ba, GCT_ID_COLOR_COMPARE, 0x0);
493 WGfx(ba, GCT_ID_DATA_ROTATE, 0x0);
494 WGfx(ba, GCT_ID_READ_MAP_SELECT, 0x0);
495 WGfx(ba, GCT_ID_GRAPHICS_MODE, 0x40);
496 WGfx(ba, GCT_ID_MISC, 0x01);
497 WGfx(ba, GCT_ID_COLOR_XCARE, 0x0F);
498 WGfx(ba, GCT_ID_BITMASK, 0xFF);
499
500 /* colors for text mode */
501 for (i = 0; i <= 0xf; i++)
502 WAttr (ba, i, i);
503
504 WAttr(ba, ACT_ID_ATTR_MODE_CNTL, 0x41);
505 WAttr(ba, ACT_ID_OVERSCAN_COLOR, 0x01);
506 WAttr(ba, ACT_ID_COLOR_PLANE_ENA, 0x0F);
507 WAttr(ba, ACT_ID_HOR_PEL_PANNING, 0x0);
508 WAttr(ba, ACT_ID_COLOR_SELECT, 0x0);
509
510 vgaw(ba, VDAC_MASK, 0xFF); /* DAC Mask */
511
512 *((unsigned long *)(ba + ECR_FRGD_COLOR)) = 0xFF;
513 *((unsigned long *)(ba + ECR_BKGD_COLOR)) = 0;
514
515 /* colors initially set to greyscale */
516
517 vgaw(ba, VDAC_ADDRESS_W, 0);
518 for (i = 255; i >= 0 ; i--) {
519 vgaw(ba, VDAC_DATA, i);
520 vgaw(ba, VDAC_DATA, i);
521 vgaw(ba, VDAC_DATA, i);
522 }
523
524 /* GFx hardware cursor off */
525 WCrt(ba, CRT_ID_HWGC_MODE, 0x00);
526
527 /* Set first to 4 MB, so test will work */
528 WCrt(ba, CRT_ID_LAW_CNTL, 0x13);
529
530 /* find *correct* fbsize of z3 board */
531 if (cv_has_4mb((volatile char *)cv_boardaddr + 0x01400000)) {
532 cv_fbsize = 1024 * 1024 * 4;
533 WCrt(ba, CRT_ID_LAW_CNTL, 0x13); /* 4 MB */
534 } else {
535 cv_fbsize = 1024 * 1024 * 2;
536 WCrt(ba, CRT_ID_LAW_CNTL, 0x12); /* 2 MB */
537 }
538
539 /* If I knew what this really does... but it _is_ necessary
540 to get any gfx on the screen!! Undocumented register? */
541 WAttr(ba, 0x33, 0);
542
543 gi = &gp->g_display;
544 gi->gd_regaddr = (caddr_t) kvtop (ba);
545 gi->gd_regsize = 64 * 1024;
546 gi->gd_fbaddr = (caddr_t) kvtop (gp->g_fbkva);
547 gi->gd_fbsize = cv_fbsize;
548 }
549
550
551 int
552 cv_getvmode(gp, vm)
553 struct grf_softc *gp;
554 struct grfvideo_mode *vm;
555 {
556 struct grfvideo_mode *gv;
557
558 #ifdef CV64CONSOLE
559 /* Handle grabbing console mode */
560 if (vm->mode_num == 255) {
561 bcopy(&cvconsole_mode, vm, sizeof(struct grfvideo_mode));
562 /* XXX so grfconfig can tell us the correct text dimensions. */
563 vm->depth = cvconsole_mode.fy;
564 } else
565 #endif
566 {
567 if (vm->mode_num == 0)
568 vm->mode_num = (monitor_current - monitor_def) + 1;
569 if (vm->mode_num < 1 || vm->mode_num > monitor_def_max)
570 return (EINVAL);
571 gv = monitor_def + (vm->mode_num - 1);
572 if (gv->mode_num == 0)
573 return (EINVAL);
574
575 bcopy(gv, vm, sizeof(struct grfvideo_mode));
576 }
577
578 /* adjust internal values to pixel values */
579
580 vm->hblank_start *= 8;
581 vm->hblank_stop *= 8;
582 vm->hsync_start *= 8;
583 vm->hsync_stop *= 8;
584 vm->htotal *= 8;
585
586 return (0);
587 }
588
589
590 int
591 cv_setvmode(gp, mode)
592 struct grf_softc *gp;
593 unsigned mode;
594 {
595 if (!mode || (mode > monitor_def_max) ||
596 monitor_def[mode - 1].mode_num == 0)
597 return (EINVAL);
598
599 monitor_current = monitor_def + (mode - 1);
600
601 return (0);
602 }
603
604
605 int
606 cv_blank(gp, on)
607 struct grf_softc *gp;
608 int *on;
609 {
610 volatile caddr_t ba = gp->g_regkva;
611
612 gfx_on_off(*on ? 1 : 0, ba);
613 return (0);
614 }
615
616
617 /*
618 * Change the mode of the display.
619 * Return a UNIX error number or 0 for success.
620 */
621 int
622 cv_mode(gp, cmd, arg, a2, a3)
623 register struct grf_softc *gp;
624 int cmd;
625 void *arg;
626 int a2, a3;
627 {
628 int error;
629
630 switch (cmd) {
631 case GM_GRFON:
632 error = cv_load_mon (gp,
633 (struct grfcvtext_mode *) monitor_current) ? 0 : EINVAL;
634 return (error);
635
636 case GM_GRFOFF:
637 #ifndef CV64CONSOLE
638 (void)cv_toggle(gp);
639 #else
640 cv_load_mon(gp, &cvconsole_mode);
641 #endif
642 return (0);
643
644 case GM_GRFCONFIG:
645 return (0);
646
647 case GM_GRFGETVMODE:
648 return (cv_getvmode (gp, (struct grfvideo_mode *) arg));
649
650 case GM_GRFSETVMODE:
651 error = cv_setvmode (gp, *(unsigned *) arg);
652 if (!error && (gp->g_flags & GF_GRFON))
653 cv_load_mon(gp,
654 (struct grfcvtext_mode *) monitor_current);
655 return (error);
656
657 case GM_GRFGETNUMVM:
658 *(int *)arg = monitor_def_max;
659 return (0);
660
661 case GM_GRFIOCTL:
662 return (cv_ioctl (gp, (int) arg, (caddr_t) a2));
663
664 default:
665 break;
666 }
667
668 return (EINVAL);
669 }
670
671 int
672 cv_ioctl (gp, cmd, data)
673 register struct grf_softc *gp;
674 int cmd;
675 void *data;
676 {
677 switch (cmd) {
678 case GRFIOCGSPRITEPOS:
679 case GRFIOCSSPRITEPOS:
680 case GRFIOCSSPRITEINF:
681 case GRFIOCGSPRITEINF:
682 case GRFIOCGSPRITEMAX:
683 break;
684
685 case GRFIOCGETCMAP:
686 return (cv_getcmap (gp, (struct grf_colormap *) data));
687
688 case GRFIOCPUTCMAP:
689 return (cv_putcmap (gp, (struct grf_colormap *) data));
690
691 case GRFIOCBITBLT:
692 break;
693
694 case GRFTOGGLE:
695 return (cv_toggle (gp));
696
697 case GRFIOCSETMON:
698 return (cv_setmonitor (gp, (struct grfvideo_mode *)data));
699
700 case GRFIOCBLANK:
701 return (cv_blank (gp, (int *)data));
702 }
703 return (EINVAL);
704 }
705
706 int
707 cv_setmonitor(gp, gv)
708 struct grf_softc *gp;
709 struct grfvideo_mode *gv;
710 {
711 struct grfvideo_mode *md;
712
713 if (!cv_mondefok(gv))
714 return (EINVAL);
715
716 #ifdef CV64CONSOLE
717 /* handle interactive setting of console mode */
718 if (gv->mode_num == 255) {
719 bcopy(gv, &cvconsole_mode.gv, sizeof(struct grfvideo_mode));
720 cvconsole_mode.gv.hblank_start /= 8;
721 cvconsole_mode.gv.hblank_stop /= 8;
722 cvconsole_mode.gv.hsync_start /= 8;
723 cvconsole_mode.gv.hsync_stop /= 8;
724 cvconsole_mode.gv.htotal /= 8;
725 cvconsole_mode.rows = gv->disp_height / cvconsole_mode.fy;
726 cvconsole_mode.cols = gv->disp_width / cvconsole_mode.fx;
727 if (!(gp->g_flags & GF_GRFON))
728 cv_load_mon(gp, &cvconsole_mode);
729 ite_reinit(gp->g_itedev);
730 return (0);
731 }
732 #endif
733
734 md = monitor_def + (gv->mode_num - 1);
735 bcopy(gv, md, sizeof(struct grfvideo_mode));
736
737 /* adjust pixel oriented values to internal rep. */
738
739 md->hblank_start /= 8;
740 md->hblank_stop /= 8;
741 md->hsync_start /= 8;
742 md->hsync_stop /= 8;
743 md->htotal /= 8;
744
745 return (0);
746 }
747
748 int
749 cv_getcmap(gfp, cmap)
750 struct grf_softc *gfp;
751 struct grf_colormap *cmap;
752 {
753 volatile caddr_t ba;
754 u_char red[256], green[256], blue[256], *rp, *gp, *bp;
755 short x;
756 int error;
757
758 if (cmap->count == 0 || cmap->index >= 256)
759 return (0);
760
761 if (cmap->index + cmap->count > 256)
762 cmap->count = 256 - cmap->index;
763
764 ba = gfp->g_regkva;
765 /* first read colors out of the chip, then copyout to userspace */
766 vgaw (ba, VDAC_ADDRESS_W, cmap->index);
767 x = cmap->count - 1;
768
769 rp = red + cmap->index;
770 gp = green + cmap->index;
771 bp = blue + cmap->index;
772
773 do {
774 *rp++ = vgar (ba, VDAC_DATA) << 2;
775 *gp++ = vgar (ba, VDAC_DATA) << 2;
776 *bp++ = vgar (ba, VDAC_DATA) << 2;
777 } while (x-- > 0);
778
779 if (!(error = copyout (red + cmap->index, cmap->red, cmap->count))
780 && !(error = copyout (green + cmap->index, cmap->green, cmap->count))
781 && !(error = copyout (blue + cmap->index, cmap->blue, cmap->count)))
782 return (0);
783
784 return (error);
785 }
786
787 int
788 cv_putcmap(gfp, cmap)
789 struct grf_softc *gfp;
790 struct grf_colormap *cmap;
791 {
792 volatile caddr_t ba;
793 u_char red[256], green[256], blue[256], *rp, *gp, *bp;
794 short x;
795 int error;
796
797 if (cmap->count == 0 || cmap->index >= 256)
798 return (0);
799
800 if (cmap->index + cmap->count > 256)
801 cmap->count = 256 - cmap->index;
802
803 /* first copy the colors into kernelspace */
804 if (!(error = copyin (cmap->red, red + cmap->index, cmap->count))
805 && !(error = copyin (cmap->green, green + cmap->index, cmap->count))
806 && !(error = copyin (cmap->blue, blue + cmap->index, cmap->count))) {
807 ba = gfp->g_regkva;
808 vgaw (ba, VDAC_ADDRESS_W, cmap->index);
809 x = cmap->count - 1;
810
811 rp = red + cmap->index;
812 gp = green + cmap->index;
813 bp = blue + cmap->index;
814
815 do {
816 vgaw (ba, VDAC_DATA, *rp++ >> 2);
817 vgaw (ba, VDAC_DATA, *gp++ >> 2);
818 vgaw (ba, VDAC_DATA, *bp++ >> 2);
819 } while (x-- > 0);
820 return (0);
821 } else
822 return (error);
823 }
824
825
826 int
827 cv_toggle(gp)
828 struct grf_softc *gp;
829 {
830 volatile caddr_t ba;
831
832 ba = gp->g_regkva;
833 cvscreen(1, ba - READ_OFFSET);
834
835 return (0);
836 }
837
838
839 int
840 cv_mondefok(gv)
841 struct grfvideo_mode *gv;
842 {
843 unsigned long maxpix;
844
845 if (gv->mode_num < 1 || gv->mode_num > monitor_def_max)
846 if (gv->mode_num != 255 || gv->depth != 4)
847 return (0);
848
849 switch(gv->depth) {
850 case 1:
851 case 4:
852 /* Remove this comment when ite5 is ready */
853 /* if (gv->mode_num != 255) */
854 return (0);
855 case 8:
856 maxpix = MAXPIXELCLOCK;
857 break;
858 case 15:
859 case 16:
860 maxpix = MAXPIXELCLOCK - 55000000;
861 break;
862 case 24:
863 maxpix = MAXPIXELCLOCK - 85000000;
864 break;
865 default:
866 return (0);
867 }
868
869 if (gv->pixel_clock > maxpix)
870 return (0);
871 return (1);
872 }
873
874 int
875 cv_load_mon(gp, md)
876 struct grf_softc *gp;
877 struct grfcvtext_mode *md;
878 {
879 struct grfvideo_mode *gv;
880 struct grfinfo *gi;
881 volatile caddr_t ba, fb;
882 unsigned short mnr;
883 unsigned short HT, HDE, HBS, HBE, HSS, HSE, VDE, VBS, VBE, VSS,
884 VSE, VT;
885 char LACE, DBLSCAN, TEXT;
886 int uplim, lowlim;
887 int cr33, sr15, sr18, clock_mode, test;
888 int m, n, clock; /* For calc'ing display FIFO */
889
890 /* identity */
891 gv = &md->gv;
892 TEXT = (gv->depth == 4);
893
894 if (!cv_mondefok(gv)) {
895 printf("mondef not ok\n");
896 return (0);
897 }
898 ba = gp->g_regkva;
899 fb = gp->g_fbkva;
900
901 /* turn gfx off, don't mess up the display */
902 gfx_on_off(1, ba);
903
904 /* provide all needed information in grf device-independant locations */
905 gp->g_data = (caddr_t) gv;
906 gi = &gp->g_display;
907 gi->gd_colors = 1 << gv->depth;
908 gi->gd_planes = gv->depth;
909 gi->gd_fbwidth = gv->disp_width;
910 gi->gd_fbheight = gv->disp_height;
911 gi->gd_fbx = 0;
912 gi->gd_fby = 0;
913 if (TEXT) {
914 gi->gd_dwidth = md->fx * md->cols;
915 gi->gd_dheight = md->fy * md->rows;
916 } else {
917 gi->gd_dwidth = gv->disp_width;
918 gi->gd_dheight = gv->disp_height;
919 }
920 gi->gd_dx = 0;
921 gi->gd_dy = 0;
922
923 /* get display mode parameters */
924
925 HBS = gv->hblank_start;
926 HBE = gv->hblank_stop;
927 HSS = gv->hsync_start;
928 HSE = gv->hsync_stop;
929 HT = gv->htotal - 5;
930 VBS = gv->vblank_start - 1;
931 VSS = gv->vsync_start;
932 VSE = gv->vsync_stop;
933 VBE = gv->vblank_stop;
934 VT = gv->vtotal - 2;
935
936 if (TEXT)
937 HDE = ((gv->disp_width + md->fx - 1) / md->fx) - 1;
938 else
939 HDE = (gv->disp_width + 3) / 8 - 1; /*HBS;*/
940 VDE = gv->disp_height - 1;
941
942 /* figure out whether lace or dblscan is needed */
943
944 uplim = gv->disp_height + (gv->disp_height / 4);
945 lowlim = gv->disp_height - (gv->disp_height / 4);
946 LACE = (((VT * 2) > lowlim) && ((VT * 2) < uplim)) ? 1 : 0;
947 DBLSCAN = (((VT / 2) > lowlim) && ((VT / 2) < uplim)) ? 1 : 0;
948
949 /* adjustments */
950
951 if (LACE)
952 VDE /= 2;
953
954 WSeq(ba, SEQ_ID_MEMORY_MODE, (TEXT || (gv->depth == 1)) ? 0x06 : 0x0e);
955 WGfx(ba, GCT_ID_READ_MAP_SELECT, 0x00);
956 WSeq(ba, SEQ_ID_MAP_MASK, (gv->depth == 1) ? 0x01 : 0xff);
957 WSeq(ba, SEQ_ID_CHAR_MAP_SELECT, 0x00);
958
959 /* Set clock */
960
961 switch (gv->depth) {
962 case 15:
963 case 16:
964 mnr = compute_clock(gv->pixel_clock * 2);
965 break;
966 case 24:
967 mnr = compute_clock(gv->pixel_clock * 3);
968 break;
969 default:
970 mnr = compute_clock(gv->pixel_clock);
971 break;
972 }
973
974 WSeq(ba, SEQ_ID_DCLK_HI, ((mnr & 0xFF00) >> 8) );
975 WSeq(ba, SEQ_ID_DCLK_LO, (mnr & 0xFF));
976
977 /* load display parameters into board */
978
979 WCrt(ba, CRT_ID_EXT_HOR_OVF,
980 ((HT & 0x100) ? 0x01 : 0x00) |
981 ((HDE & 0x100) ? 0x02 : 0x00) |
982 ((HBS & 0x100) ? 0x04 : 0x00) |
983 /* ((HBE & 0x40) ? 0x08 : 0x00) | */ /* Later... */
984 ((HSS & 0x100) ? 0x10 : 0x00) |
985 /* ((HSE & 0x20) ? 0x20 : 0x00) | */
986 (((HT-5) & 0x100) ? 0x40 : 0x00) );
987
988 WCrt(ba, CRT_ID_EXT_VER_OVF,
989 0x40 | /* Line compare */
990 ((VT & 0x400) ? 0x01 : 0x00) |
991 ((VDE & 0x400) ? 0x02 : 0x00) |
992 ((VBS & 0x400) ? 0x04 : 0x00) |
993 ((VSS & 0x400) ? 0x10 : 0x00) );
994
995 WCrt(ba, CRT_ID_HOR_TOTAL, HT);
996 WCrt(ba, CRT_ID_DISPLAY_FIFO, HT - 5);
997
998 WCrt(ba, CRT_ID_HOR_DISP_ENA_END, ((HDE >= HBS) ? (HBS - 1) : HDE));
999 WCrt(ba, CRT_ID_START_HOR_BLANK, HBS);
1000 WCrt(ba, CRT_ID_END_HOR_BLANK, ((HBE & 0x1f) | 0x80));
1001 WCrt(ba, CRT_ID_START_HOR_RETR, HSS);
1002 WCrt(ba, CRT_ID_END_HOR_RETR,
1003 (HSE & 0x1f) |
1004 ((HBE & 0x20) ? 0x80 : 0x00) );
1005 WCrt(ba, CRT_ID_VER_TOTAL, VT);
1006 WCrt(ba, CRT_ID_OVERFLOW,
1007 0x10 |
1008 ((VT & 0x100) ? 0x01 : 0x00) |
1009 ((VDE & 0x100) ? 0x02 : 0x00) |
1010 ((VSS & 0x100) ? 0x04 : 0x00) |
1011 ((VBS & 0x100) ? 0x08 : 0x00) |
1012 ((VT & 0x200) ? 0x20 : 0x00) |
1013 ((VDE & 0x200) ? 0x40 : 0x00) |
1014 ((VSS & 0x200) ? 0x80 : 0x00) );
1015
1016 WCrt(ba, CRT_ID_MAX_SCAN_LINE,
1017 0x40 | /* TEXT ? 0x00 ??? */
1018 (DBLSCAN ? 0x80 : 0x00) |
1019 ((VBS & 0x200) ? 0x20 : 0x00) |
1020 (TEXT ? ((md->fy - 1) & 0x1f) : 0x00));
1021
1022 WCrt(ba, CRT_ID_MODE_CONTROL,
1023 ((TEXT || (gv->depth == 1)) ? 0xc3 : 0xe3));
1024
1025 /* text cursor */
1026
1027 if (TEXT) {
1028 #if 1
1029 WCrt(ba, CRT_ID_CURSOR_START, (md->fy & 0x1f) - 2);
1030 WCrt(ba, CRT_ID_CURSOR_END, (md->fy & 0x1f) - 1);
1031 #else
1032 WCrt(ba, CRT_ID_CURSOR_START, 0x00);
1033 WCrt(ba, CRT_ID_CURSOR_END, md->fy & 0x1f);
1034 #endif
1035 WCrt(ba, CRT_ID_UNDERLINE_LOC, (md->fy - 1) & 0x1f);
1036
1037 WCrt(ba, CRT_ID_CURSOR_LOC_HIGH, 0x00);
1038 WCrt(ba, CRT_ID_CURSOR_LOC_LOW, 0x00);
1039 }
1040
1041 WCrt(ba, CRT_ID_START_ADDR_HIGH, 0x00);
1042 WCrt(ba, CRT_ID_START_ADDR_LOW, 0x00);
1043
1044 WCrt(ba, CRT_ID_START_VER_RETR, VSS);
1045 WCrt(ba, CRT_ID_END_VER_RETR, (VSE & 0x0f));
1046 WCrt(ba, CRT_ID_VER_DISP_ENA_END, VDE);
1047 WCrt(ba, CRT_ID_START_VER_BLANK, VBS);
1048 WCrt(ba, CRT_ID_END_VER_BLANK, VBE);
1049
1050 WCrt(ba, CRT_ID_LINE_COMPARE, 0xff);
1051 WCrt(ba, CRT_ID_LACE_RETR_START, HT / 2);
1052 WCrt(ba, CRT_ID_LACE_CONTROL, (LACE ? 0x20 : 0x00));
1053
1054 WGfx(ba, GCT_ID_GRAPHICS_MODE,
1055 ((TEXT || (gv->depth == 1)) ? 0x00 : 0x40));
1056 WGfx(ba, GCT_ID_MISC, (TEXT ? 0x04 : 0x01));
1057
1058 WSeq (ba, SEQ_ID_MEMORY_MODE,
1059 ((TEXT || (gv->depth == 1)) ? 0x6 : 0x02));
1060
1061 vgaw(ba, VDAC_MASK, 0xff);
1062
1063 sr15 = RSeq(ba, SEQ_ID_CLKSYN_CNTL_2);
1064 sr15 &= 0xef;
1065 sr18 = RSeq(ba, SEQ_ID_RAMDAC_CNTL);
1066 sr18 &= 0x7f;
1067 cr33 = RCrt(ba, CRT_ID_BACKWAD_COMP_2);
1068 cr33 &= 0xdf;
1069 clock_mode = 0x00;
1070
1071 test = RCrt(ba, CRT_ID_EXT_MISC_CNTL_2);
1072 test &= 0xd;
1073
1074 switch (gv->depth) {
1075 case 1:
1076 case 4: /* text */
1077 HDE = gv->disp_width / 16;
1078 break;
1079 case 8:
1080 if (gv->pixel_clock > 80000000) {
1081 clock_mode = 0x10 | 0x02;
1082 sr15 |= 0x10;
1083 sr18 |= 0x80;
1084 cr33 |= 0x20;
1085 }
1086 HDE = gv->disp_width / 8;
1087 break;
1088 case 15:
1089 clock_mode = 0x30;
1090 HDE = gv->disp_width / 4;
1091 break;
1092 case 16:
1093 clock_mode = 0x50;
1094 HDE = gv->disp_width / 4;
1095 break;
1096 case 24:
1097 clock_mode = 0xd0;
1098 HDE = (gv->disp_width / 8) * 3;
1099 break;
1100 }
1101
1102 WCrt(ba, CRT_ID_EXT_MISC_CNTL_2, clock_mode | test);
1103 WSeq(ba, SEQ_ID_CLKSYN_CNTL_2, sr15);
1104 WSeq(ba, SEQ_ID_RAMDAC_CNTL, sr18);
1105 WCrt(ba, CRT_ID_BACKWAD_COMP_2, cr33);
1106 WCrt(ba, CRT_ID_SCREEN_OFFSET, HDE);
1107
1108 test = RCrt(ba, CRT_ID_EXT_SYS_CNTL_2);
1109 /* HDE Overflow in bits 4-5 */
1110 test |= (HDE >> 4) & 0x30;
1111 WCrt(ba, CRT_ID_EXT_SYS_CNTL_2, test);
1112
1113 delay(100000);
1114 WAttr(ba, ACT_ID_ATTR_MODE_CNTL, (TEXT ? 0x0a : 0x41));
1115 delay(100000);
1116 WAttr(ba, ACT_ID_COLOR_PLANE_ENA,
1117 (gv->depth == 1) ? 0x01 : 0x0f);
1118 delay(100000);
1119
1120 /*
1121 * Calc. display fifo m and n parameters
1122 * Dont't ask me what the hell these values mean.
1123 */
1124
1125 n = 0xff;
1126 if (gv->depth < 9)
1127 clock = gv->pixel_clock / 500000.0;
1128 else if (gv->depth == 15)
1129 clock = gv->pixel_clock / 250000.0;
1130 else
1131 clock = (gv->pixel_clock * (gv->depth / 8)) / 500000.0;
1132
1133 m = ((int)((55 * .72 + 16.867) * 89.736 / (clock + 39) - 21.1543) / 2) - 1;
1134
1135 if (m > 31)
1136 m = 31;
1137 else if (m <= 0) {
1138 m = 0;
1139 n = 16;
1140 }
1141
1142 m = m << 3;
1143 WCrt(ba, CRT_ID_EXT_MEM_CNTL_2, m);
1144 WCrt(ba, CRT_ID_EXT_MEM_CNTL_3, n);
1145 delay(10000);
1146
1147 /* text initialization */
1148
1149 if (TEXT) {
1150 cv_inittextmode(gp);
1151 }
1152
1153 /* Some kind of Magic */
1154 WAttr(ba, 0x33, 0);
1155
1156 /* turn gfx on again */
1157 gfx_on_off(0, ba);
1158
1159 /* Pass-through */
1160 cvscreen(0, ba - READ_OFFSET);
1161
1162 return (1);
1163 }
1164
1165 void
1166 cv_inittextmode(gp)
1167 struct grf_softc *gp;
1168 {
1169 struct grfcvtext_mode *tm = (struct grfcvtext_mode *)gp->g_data;
1170 volatile caddr_t ba = gp->g_regkva;
1171 volatile caddr_t fb = gp->g_fbkva;
1172 unsigned char *c, *f, y;
1173 unsigned short z;
1174
1175
1176 /* load text font into beginning of display memory.
1177 * Each character cell is 32 bytes long (enough for 4 planes)
1178 */
1179
1180 SetTextPlane(ba, 0x02);
1181 cv_memset(fb, 0, 256 * 32);
1182 c = (unsigned char *) (fb) + (32 * tm->fdstart);
1183 f = tm->fdata;
1184 for (z = tm->fdstart; z <= tm->fdend; z++, c += (32 - tm->fy))
1185 for (y = 0; y < tm->fy; y++)
1186 *c++ = *f++;
1187
1188 /* clear out text/attr planes (three screens worth) */
1189
1190 SetTextPlane(ba, 0x01);
1191 cv_memset(fb, 0x07, tm->cols * tm->rows * 3);
1192 SetTextPlane(ba, 0x00);
1193 cv_memset(fb, 0x20, tm->cols * tm->rows * 3);
1194
1195 /* print out a little init msg */
1196
1197 c = (unsigned char *)(fb) + (tm->cols-16);
1198 strcpy(c, "CV64");
1199 c[6] = 0x20;
1200
1201 /* set colors (B&W) */
1202
1203 vgaw(ba, VDAC_ADDRESS_W, 0);
1204 for (z=0; z<256; z++) {
1205 unsigned char r, g, b;
1206
1207 y = (z & 1) ? ((z > 7) ? 2 : 1) : 0;
1208
1209 r = cvconscolors[y][0];
1210 g = cvconscolors[y][1];
1211 b = cvconscolors[y][2];
1212 vgaw(ba, VDAC_DATA, r >> 2);
1213 vgaw(ba, VDAC_DATA, g >> 2);
1214 vgaw(ba, VDAC_DATA, b >> 2);
1215 }
1216 }
1217
1218 void
1219 cv_memset(d, c, l)
1220 unsigned char *d;
1221 unsigned char c;
1222 int l;
1223 {
1224 for(; l > 0; l--)
1225 *d++ = c;
1226 }
1227
1228 #endif /* NGRFCV */
1229