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