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