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