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