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