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