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