grf_cv.c revision 1.24.4.1 1 /* $NetBSD: grf_cv.c,v 1.24.4.1 1998/11/22 07:23:56 cgd Exp $ */
2
3 /*
4 * Copyright (c) 1995 Michael Teske
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. All advertising materials mentioning features or use of this software
16 * must display the following acknowledgement:
17 * This product includes software developed by Ezra Story, by Kari
18 * Mettinen, Michael Teske and by Bernd Ernesti.
19 * 4. The name of the author may not be used to endorse or promote products
20 * derived from this software without specific prior written permission
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
23 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
24 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
25 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
26 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
27 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
31 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 */
33 #include "grfcv.h"
34 #if NGRFCV > 0
35
36 /*
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 *
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 * Thanks to Harald Koenig for providing information about undocumented
46 * Trio64 Bugs.
47 */
48
49 #include <sys/param.h>
50 #include <sys/errno.h>
51 #include <sys/ioctl.h>
52 #include <sys/device.h>
53 #include <sys/malloc.h>
54 #include <sys/systm.h>
55 #include <sys/syslog.h>
56 #include <machine/cpu.h>
57 #include <dev/cons.h>
58 #include <amiga/dev/itevar.h>
59 #include <amiga/amiga/device.h>
60 #include <amiga/amiga/isr.h>
61 #include <amiga/dev/grfioctl.h>
62 #include <amiga/dev/grfvar.h>
63 #include <amiga/dev/grf_cvreg.h>
64 #include <amiga/dev/zbusvar.h>
65
66 int grfcvmatch __P((struct device *, struct cfdata *, void *));
67 void grfcvattach __P((struct device *, struct device *, void *));
68 int grfcvprint __P((void *, const char *));
69
70 int cvintr __P((void *));
71 static int cv_has_4mb __P((volatile caddr_t));
72 static unsigned short cv_compute_clock __P((unsigned long));
73 void cv_boardinit __P((struct grf_softc *));
74 int cv_getvmode __P((struct grf_softc *, struct grfvideo_mode *));
75 int cv_setvmode __P((struct grf_softc *, unsigned int));
76 int cv_blank __P((struct grf_softc *, int *));
77 int cv_mode __P((register struct grf_softc *, u_long, void *, u_long, int));
78 int cv_ioctl __P((register struct grf_softc *gp, u_long cmd, void *data));
79 int cv_setmonitor __P((struct grf_softc *, struct grfvideo_mode *));
80 int cv_getcmap __P((struct grf_softc *, struct grf_colormap *));
81 int cv_putcmap __P((struct grf_softc *, struct grf_colormap *));
82 int cv_toggle __P((struct grf_softc *));
83 int cv_mondefok __P((struct grfvideo_mode *));
84 int cv_load_mon __P((struct grf_softc *, struct grfcvtext_mode *));
85 void cv_inittextmode __P((struct grf_softc *));
86 static __inline void cv_write_port __P((unsigned short, volatile caddr_t));
87 static __inline void cvscreen __P((int, volatile caddr_t));
88 static __inline void gfx_on_off __P((int, volatile caddr_t));
89
90 #ifndef CV_NO_HARDWARE_CURSOR
91 int cv_getspritepos __P((struct grf_softc *, struct grf_position *));
92 int cv_setspritepos __P((struct grf_softc *, struct grf_position *));
93 int cv_getspriteinfo __P((struct grf_softc *,struct grf_spriteinfo *));
94 void cv_setup_hwc __P((struct grf_softc *));
95 int cv_setspriteinfo __P((struct grf_softc *,struct grf_spriteinfo *));
96 int cv_getspritemax __P((struct grf_softc *,struct grf_position *));
97 #endif /* !CV_NO_HARDWARE_CURSOR */
98
99 /*
100 * Extension to grf_softc for interrupt support
101 */
102
103 struct grf_cv_softc {
104 struct grf_softc gcs_sc;
105 struct isr gcs_isr;
106 };
107
108 /* Graphics display definitions.
109 * These are filled by 'grfconfig' using GRFIOCSETMON.
110 */
111 #define monitor_def_max 24
112 static struct grfvideo_mode monitor_def[24] = {
113 {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
114 {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0},
115 {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0}
116 };
117 static struct grfvideo_mode *monitor_current = &monitor_def[0];
118 #define MAXPIXELCLOCK 135000000 /* safety */
119
120 unsigned char cv_pass_toggle; /* passthru status tracker */
121
122 /* Console display definition.
123 * Default hardcoded text mode. This grf_cv is set up to
124 * use one text mode only, and this is it. You may use
125 * grfconfig to change the mode after boot.
126 */
127
128 /* Console font */
129 #ifdef KFONT_8X11
130 #define S3FONT kernel_font_8x11
131 #define S3FONTY 11
132 #else
133 #define S3FONT kernel_font_8x8
134 #define S3FONTY 8
135 #endif
136 extern unsigned char S3FONT[];
137
138 /*
139 * Define default console mode
140 * (Internally, we still have to use hvalues/8!)
141 */
142 struct grfcvtext_mode cvconsole_mode = {
143 {255, "", 25000000, 640, 480, 4, 640/8, 680/8, 768/8, 800/8,
144 481, 491, 493, 525, 0},
145 8, S3FONTY, 80, 480 / S3FONTY, S3FONT, 32, 255
146 };
147
148 /* Console colors */
149 unsigned char cvconscolors[16][3] = { /* background, foreground, hilite */
150 /* R G B */
151 {0x30, 0x30, 0x30},
152 {0x00, 0x00, 0x00},
153 {0x80, 0x00, 0x00},
154 {0x00, 0x80, 0x00},
155 {0x00, 0x00, 0x80},
156 {0x80, 0x80, 0x00},
157 {0x00, 0x80, 0x80},
158 {0x80, 0x00, 0x80},
159 {0xff, 0xff, 0xff},
160 {0x40, 0x40, 0x40},
161 {0xff, 0x00, 0x00},
162 {0x00, 0xff, 0x00},
163 {0x00, 0x00, 0xff},
164 {0xff, 0xff, 0x00},
165 {0x00, 0xff, 0xff},
166 {0x00, 0x00, 0xff}
167 };
168
169 static unsigned char clocks[]={
170 0x13, 0x61, 0x6b, 0x6d, 0x51, 0x69, 0x54, 0x69,
171 0x4f, 0x68, 0x6b, 0x6b, 0x18, 0x61, 0x7b, 0x6c,
172 0x51, 0x67, 0x24, 0x62, 0x56, 0x67, 0x77, 0x6a,
173 0x1d, 0x61, 0x53, 0x66, 0x6b, 0x68, 0x79, 0x69,
174 0x7c, 0x69, 0x7f, 0x69, 0x22, 0x61, 0x54, 0x65,
175 0x56, 0x65, 0x58, 0x65, 0x67, 0x66, 0x41, 0x63,
176 0x27, 0x61, 0x13, 0x41, 0x37, 0x62, 0x6b, 0x4d,
177 0x23, 0x43, 0x51, 0x49, 0x79, 0x66, 0x54, 0x49,
178 0x7d, 0x66, 0x34, 0x56, 0x4f, 0x63, 0x1f, 0x42,
179 0x6b, 0x4b, 0x7e, 0x4d, 0x18, 0x41, 0x2a, 0x43,
180 0x7b, 0x4c, 0x74, 0x4b, 0x51, 0x47, 0x65, 0x49,
181 0x24, 0x42, 0x68, 0x49, 0x56, 0x47, 0x75, 0x4a,
182 0x77, 0x4a, 0x31, 0x43, 0x1d, 0x41, 0x71, 0x49,
183 0x53, 0x46, 0x29, 0x42, 0x6b, 0x48, 0x1f, 0x41,
184 0x79, 0x49, 0x6f, 0x48, 0x7c, 0x49, 0x38, 0x43,
185 0x7f, 0x49, 0x5d, 0x46, 0x22, 0x41, 0x53, 0x45,
186 0x54, 0x45, 0x55, 0x45, 0x56, 0x45, 0x57, 0x45,
187 0x58, 0x45, 0x25, 0x41, 0x67, 0x46, 0x5b, 0x45,
188 0x41, 0x43, 0x78, 0x47, 0x27, 0x41, 0x51, 0x44,
189 0x13, 0x21, 0x7d, 0x47, 0x37, 0x42, 0x71, 0x46,
190 0x6b, 0x2d, 0x14, 0x21, 0x23, 0x23, 0x7d, 0x2f,
191 0x51, 0x29, 0x61, 0x2b, 0x79, 0x46, 0x1d, 0x22,
192 0x54, 0x29, 0x45, 0x27, 0x7d, 0x46, 0x7f, 0x46,
193 0x4f, 0x43, 0x2f, 0x41, 0x1f, 0x22, 0x6a, 0x2b,
194 0x6b, 0x2b, 0x5b, 0x29, 0x7e, 0x2d, 0x65, 0x44,
195 0x18, 0x21, 0x5e, 0x29, 0x2a, 0x23, 0x45, 0x26,
196 0x7b, 0x2c, 0x19, 0x21, 0x74, 0x2b, 0x75, 0x2b,
197 0x51, 0x27, 0x3f, 0x25, 0x65, 0x29, 0x40, 0x25,
198 0x24, 0x22, 0x41, 0x25, 0x68, 0x29, 0x42, 0x25,
199 0x56, 0x27, 0x7e, 0x2b, 0x75, 0x2a, 0x1c, 0x21,
200 0x77, 0x2a, 0x4f, 0x26, 0x31, 0x23, 0x6f, 0x29,
201 0x1d, 0x21, 0x32, 0x23, 0x71, 0x29, 0x72, 0x29,
202 0x53, 0x26, 0x69, 0x28, 0x29, 0x22, 0x75, 0x29,
203 0x6b, 0x28, 0x1f, 0x21, 0x1f, 0x21, 0x6d, 0x28,
204 0x79, 0x29, 0x2b, 0x22, 0x6f, 0x28, 0x59, 0x26,
205 0x7c, 0x29, 0x7d, 0x29, 0x38, 0x23, 0x21, 0x21,
206 0x7f, 0x29, 0x39, 0x23, 0x5d, 0x26, 0x75, 0x28,
207 0x22, 0x21, 0x77, 0x28, 0x53, 0x25, 0x6c, 0x27,
208 0x54, 0x25, 0x61, 0x26, 0x55, 0x25, 0x30, 0x22,
209 0x56, 0x25, 0x63, 0x26, 0x57, 0x25, 0x71, 0x27,
210 0x58, 0x25, 0x7f, 0x28, 0x25, 0x21, 0x74, 0x27,
211 0x67, 0x26, 0x40, 0x23, 0x5b, 0x25, 0x26, 0x21,
212 0x41, 0x23, 0x34, 0x22, 0x78, 0x27, 0x6b, 0x26,
213 0x27, 0x21, 0x35, 0x22, 0x51, 0x24, 0x7b, 0x27,
214 0x13, 0x1, 0x13, 0x1, 0x7d, 0x27, 0x4c, 0x9,
215 0x37, 0x22, 0x5b, 0xb, 0x71, 0x26, 0x5c, 0xb,
216 0x6b, 0xd, 0x47, 0x23, 0x14, 0x1, 0x4f, 0x9,
217 0x23, 0x3, 0x75, 0x26, 0x7d, 0xf, 0x1c, 0x2,
218 0x51, 0x9, 0x59, 0x24, 0x61, 0xb, 0x69, 0x25,
219 0x79, 0x26, 0x34, 0x5, 0x1d, 0x2, 0x6b, 0x25,
220 0x54, 0x9, 0x35, 0x5, 0x45, 0x7, 0x6d, 0x25,
221 0x7d, 0x26, 0x16, 0x1, 0x7f, 0x26, 0x77, 0xd,
222 0x4f, 0x23, 0x78, 0xd, 0x2f, 0x21, 0x27, 0x3,
223 0x1f, 0x2, 0x59, 0x9, 0x6a, 0xb, 0x73, 0x25,
224 0x6b, 0xb, 0x63, 0x24, 0x5b, 0x9, 0x20, 0x2,
225 0x7e, 0xd, 0x4b, 0x7, 0x65, 0x24, 0x43, 0x22,
226 0x18, 0x1, 0x6f, 0xb, 0x5e, 0x9, 0x70, 0xb,
227 0x2a, 0x3, 0x33, 0x4, 0x45, 0x6, 0x60, 0x9,
228 0x7b, 0xc, 0x19, 0x1, 0x19, 0x1, 0x7d, 0xc,
229 0x74, 0xb, 0x50, 0x7, 0x75, 0xb, 0x63, 0x9,
230 0x51, 0x7, 0x23, 0x2, 0x3f, 0x5, 0x1a, 0x1,
231 0x65, 0x9, 0x2d, 0x3, 0x40, 0x5, 0x0, 0x0,
232 };
233
234
235 /* Board Address of CV64 */
236 static volatile caddr_t cv_boardaddr;
237 static int cv_fbsize;
238
239 /*
240 * Memory clock (binpatchable).
241 * Let's be defensive: 50 MHz runs on all boards I know of.
242 * 55 MHz runs on most boards. But you should know what you're doing
243 * if you set this flag. Again: This flag may destroy your CV Board.
244 * Use it at your own risk!!!
245 * Anyway, this doesn't imply that I'm responsible if your board breaks
246 * without setting this flag :-).
247 */
248 #ifdef CV_AGGRESSIVE_TIMING
249 long cv_memclk = 55000000;
250 #else
251 long cv_memclk = 50000000;
252 #endif
253
254 /* standard driver stuff */
255 struct cfattach grfcv_ca = {
256 sizeof(struct grf_cv_softc), grfcvmatch, grfcvattach
257 };
258
259 struct cfdriver grfcv_cd = {
260 NULL, "grfcv", DV_DULL, NULL, 0
261 };
262 static struct cfdata *cfdata;
263
264 #define CV_INT_NUM 6 /* CV interrupt Level: #2 or #6 */
265 #define CV_ULCURSOR 1 /* Underlined Cursor in textmode */
266
267 #ifndef CV_NO_HARDWARE_CURSOR
268
269 #define HWC_OFF (cv_fbsize - 1024*2)
270 #define HWC_SIZE 1024
271
272 static unsigned short cv_cursor_storage[HWC_SIZE/2];
273 static short curs_update_flag = 0;
274
275 #endif /* !CV_NO_HARDWARE_CURSOR */
276
277 /*
278 * Interrupt handler
279 * This is used for updating the cursor shape (because it _must not_
280 * be changed while cursor is displayed)
281 * and maybe later to avoid busy waiting
282 * for Vertical Blank and/or gfx engine busy
283 */
284
285 int
286 cvintr(arg)
287 void * arg;
288 {
289 #ifndef CV_NO_HARDWARE_CURSOR
290 register unsigned long *csrc, *cdest;
291 int i;
292 #endif
293 struct grf_softc *gp = arg;
294 volatile caddr_t ba = gp->g_regkva;
295 unsigned char test;
296 unsigned char cridx; /* Save the cr Register index */
297
298 if (gp == NULL)
299 return 0;
300
301 test = vgar(ba, GREG_INPUT_STATUS0_R);
302
303 if (test & 0x80) { /* VR int pending */
304 /* Save old CR index */
305 cridx = vgar (ba, CRT_ADDRESS);
306
307 #if 0
308 test = RCrt(ba, CRT_ID_END_VER_RETR);
309 /* Clear int (bit 4) */
310 test &= ~0x10;
311 WCrt(ba, CRT_ID_END_VER_RETR, test);
312 #else
313 vgaw(ba, CRT_ADDRESS, CRT_ID_END_VER_RETR);
314 asm volatile("bclr #4,%0@(0x3d5);nop" : : "a" (ba));
315 #endif
316
317 #ifndef CV_NO_HARDWARE_CURSOR
318 /* update the hardware cursor, if necessary */
319 if (curs_update_flag) {
320 csrc = (unsigned long *)cv_cursor_storage;
321 cdest = (unsigned long *)((volatile char *)gp->g_fbkva
322 + HWC_OFF);
323 for (i = 0; i < HWC_SIZE / sizeof(long); i++)
324 *cdest++ = *csrc++;
325 curs_update_flag = 0;
326 }
327 /* Reenable int */
328 #if 0
329 test |= 0x10;
330 WCrt(ba, CRT_ID_END_VER_RETR, test);
331 #else
332 /* I don't trust the optimizer here... */
333 asm volatile("bset #4,%0@(0x3d5);nop" : : "a" (ba));
334 #endif
335 cv_setspritepos (gp, NULL);
336
337 /* Restore the old CR index */
338 vgaw(ba, CRT_ADDRESS, cridx);
339 asm volatile("nop");
340 #endif /* !CV_NO_HARDWARE_CURSOR */
341 return (1);
342 }
343 return (0);
344 }
345
346 /*
347 * Get frambuffer memory size.
348 * phase5 didn't provide the bit in CR36,
349 * so we have to do it this way.
350 * Return 0 for 2MB, 1 for 4MB
351 */
352 static int
353 cv_has_4mb(fb)
354 volatile caddr_t fb;
355 {
356 volatile unsigned long *testfbw, *testfbr;
357
358 /* write patterns in memory and test if they can be read */
359 testfbw = (volatile unsigned long *)fb;
360 testfbr = (volatile unsigned long *)(fb + 0x02000000);
361 *testfbw = 0x87654321;
362 asm volatile("nop");
363 if (*testfbr != 0x87654321)
364 return (0);
365
366 /* upper memory region */
367 testfbw = (volatile unsigned long *)(fb + 0x00200000);
368 testfbr = (volatile unsigned long *)(fb + 0x02200000);
369 *testfbw = 0x87654321;
370 asm volatile("nop");
371 if (*testfbr != 0x87654321)
372 return (0);
373 *testfbw = 0xAAAAAAAA;
374 asm volatile("nop");
375 if (*testfbr != 0xAAAAAAAA)
376 return (0);
377 *testfbw = 0x55555555;
378 asm volatile("nop");
379 if (*testfbr != 0x55555555)
380 return (0);
381 return (1);
382 }
383
384 int
385 grfcvmatch(pdp, cfp, auxp)
386 struct device *pdp;
387 struct cfdata *cfp;
388 void *auxp;
389 {
390 #ifdef CV64CONSOLE
391 static int cvcons_unit = -1;
392 #endif
393 struct zbus_args *zap;
394
395 zap = auxp;
396
397 if (amiga_realconfig == 0)
398 #ifdef CV64CONSOLE
399 if (cvcons_unit != -1)
400 #endif
401 return (0);
402
403 /* Lets be Paranoid: Test man and prod id */
404 if (zap->manid != 8512 || zap->prodid != 34)
405 return (0);
406
407 cv_boardaddr = zap->va;
408
409 #ifdef CV64CONSOLE
410 if (amiga_realconfig == 0) {
411 cvcons_unit = cfp->cf_unit;
412 cfdata = cfp;
413 }
414 #endif
415
416 return (1);
417 }
418
419 void
420 grfcvattach(pdp, dp, auxp)
421 struct device *pdp, *dp;
422 void *auxp;
423 {
424 static struct grf_cv_softc congrf;
425 struct zbus_args *zap;
426 struct grf_softc *gp;
427 struct grf_cv_softc *gcp;
428 static char attachflag = 0;
429
430 zap = auxp;
431
432 /*
433 * This function is called twice, once on console init (dp == NULL)
434 * and once on "normal" grf5 init.
435 */
436
437 if (dp == NULL) /* console init */
438 gcp = &congrf;
439 else
440 gcp = (struct grf_cv_softc *)dp;
441
442 gp = &gcp->gcs_sc;
443
444 if (dp != NULL && congrf.gcs_sc.g_regkva != 0) {
445 /*
446 * inited earlier, just copy (not device struct)
447 */
448
449 printf("\n");
450 bcopy(&congrf.gcs_sc.g_display, &gp->g_display,
451 (char *) &gcp->gcs_isr - (char *) &gp->g_display);
452
453 /* ... and transfer the isr */
454 gcp->gcs_isr.isr_ipl = CV_INT_NUM;
455 gcp->gcs_isr.isr_intr = cvintr;
456 gcp->gcs_isr.isr_arg = (void *)gp;
457
458 /* First add new isr */
459 add_isr(&gcp->gcs_isr);
460 remove_isr(&congrf.gcs_isr);
461 } else {
462 gp->g_regkva = (volatile caddr_t)cv_boardaddr + 0x02000000;
463 gp->g_fbkva = (volatile caddr_t)cv_boardaddr + 0x01400000;
464
465 gp->g_unit = GRF_CV64_UNIT;
466 gp->g_mode = cv_mode;
467 gp->g_conpri = grfcv_cnprobe();
468 gp->g_flags = GF_ALIVE;
469
470 /* add Interrupt Handler */
471 gcp->gcs_isr.isr_ipl = CV_INT_NUM;
472 gcp->gcs_isr.isr_intr = cvintr;
473 gcp->gcs_isr.isr_arg = (void *)gp;
474 add_isr(&gcp->gcs_isr);
475
476 /* wakeup the board */
477 cv_boardinit(gp);
478
479 #ifdef CV64CONSOLE
480 grfcv_iteinit(gp);
481 (void)cv_load_mon(gp, &cvconsole_mode);
482 #endif
483 }
484
485 /*
486 * attach grf
487 */
488 if (amiga_config_found(cfdata, &gp->g_device, gp, grfcvprint)) {
489 if (dp != NULL)
490 printf("grfcv: CyberVision64 with %dMB being used\n",
491 cv_fbsize/0x100000);
492 attachflag = 1;
493 } else {
494 if (!attachflag)
495 /*printf("grfcv unattached!!\n")*/;
496 }
497 }
498
499 int
500 grfcvprint(auxp, pnp)
501 void *auxp;
502 const char *pnp;
503 {
504 if (pnp)
505 printf("ite at %s: ", pnp);
506 return (UNCONF);
507 }
508
509
510 /*
511 * Computes M, N, and R values from
512 * given input frequency. It uses a table of
513 * precomputed values, to keep CPU time low.
514 *
515 * The return value consist of:
516 * lower byte: Bits 4-0: N Divider Value
517 * Bits 5-6: R Value for e.g. SR10 or SR12
518 * higher byte: Bits 0-6: M divider value for e.g. SR11 or SR13
519 */
520
521 static unsigned short
522 cv_compute_clock(freq)
523 unsigned long freq;
524 {
525 static unsigned char *mnr, *save; /* M, N + R vals */
526 unsigned long work_freq, r;
527 unsigned short erg;
528 long diff, d2;
529
530 if (freq < 12500000 || freq > MAXPIXELCLOCK) {
531 printf("grfcv: Illegal clock frequency: %ldMHz\n", freq/1000000);
532 printf("grfcv: Using default frequency: 25MHz\n");
533 printf("grfcv: See the manpage of grfconfig for more informations.\n");
534 freq = 25000000;
535 }
536
537 mnr = clocks; /* there the vals are stored */
538 d2 = 0x7fffffff;
539
540 while (*mnr) { /* mnr vals are 0-terminated */
541 work_freq = (0x37EE * (mnr[0] + 2)) / ((mnr[1] & 0x1F) + 2);
542
543 r = (mnr[1] >> 5) & 0x03;
544 if (r != 0)
545 work_freq=work_freq >> r; /* r is the freq divider */
546
547 work_freq *= 0x3E8; /* 2nd part of OSC */
548
549 diff = abs(freq - work_freq);
550
551 if (d2 >= diff) {
552 d2 = diff;
553 /* In save are the vals for minimal diff */
554 save = mnr;
555 }
556 mnr += 2;
557 }
558 erg = *((unsigned short *)save);
559
560 return (erg);
561 }
562
563
564 void
565 cv_boardinit(gp)
566 struct grf_softc *gp;
567 {
568 volatile caddr_t ba;
569 unsigned char test;
570 unsigned int clockpar;
571 int i;
572 struct grfinfo *gi;
573
574 ba = gp->g_regkva;
575 /* Reset board */
576 for (i = 0; i < 6; i++)
577 cv_write_port (0xff, ba - 0x02000000); /* Clear all bits */
578
579 /* Return to operational Mode */
580 cv_write_port(0x8004, ba - 0x02000000);
581
582 /* Wakeup Chip */
583 vgaw(ba, SREG_VIDEO_SUBS_ENABLE, 0x10);
584 vgaw(ba, SREG_OPTION_SELECT, 0x01);
585 vgaw(ba, SREG_VIDEO_SUBS_ENABLE, 0x08);
586
587 vgaw(ba, GREG_MISC_OUTPUT_W, 0x03);
588
589 WCrt(ba, CRT_ID_REGISTER_LOCK_1, 0x48); /* unlock S3 VGA regs */
590 WCrt(ba, CRT_ID_REGISTER_LOCK_2, 0xA5); /* unlock syscontrol */
591
592 /*
593 * The default board interrupt is #6.
594 * Set the roxxler register to use interrupt #2, not #6.
595 */
596 #if CV_INT_NUM == 2
597 cv_write_port(0x8080, ba - 0x02000000);
598 #endif
599
600 /* Enable board interrupts */
601 cv_write_port(0x8008, ba - 0x02000000);
602
603 test = RCrt(ba, CRT_ID_SYSTEM_CONFIG);
604 test = test | 0x01; /* enable enhaced register access */
605 test = test & 0xEF; /* clear bit 4, 0 wait state */
606 WCrt(ba, CRT_ID_SYSTEM_CONFIG, test);
607
608 /*
609 * bit 1=1: enable enhanced mode functions
610 * bit 4=1: enable linear adressing
611 * bit 5=1: enable MMIO
612 */
613 vgaw(ba, ECR_ADV_FUNC_CNTL, 0x31);
614
615 /* enable color mode (bit0), cpu acess (bit1), high 64k page (bit5) */
616 vgaw(ba, GREG_MISC_OUTPUT_W, 0xe3);
617
618 /* Cpu base addr */
619 WCrt(ba, CRT_ID_EXT_SYS_CNTL_4, 0x00);
620
621 /* Reset. This does nothing, but everyone does it:) */
622 WSeq(ba, SEQ_ID_RESET, 0x03);
623
624 WSeq(ba, SEQ_ID_CLOCKING_MODE, 0x01); /* 8 Dot Clock */
625 WSeq(ba, SEQ_ID_MAP_MASK, 0x0f); /* Enable write planes */
626 WSeq(ba, SEQ_ID_CHAR_MAP_SELECT, 0x00); /* Character Font */
627
628 WSeq(ba, SEQ_ID_MEMORY_MODE, 0x02); /* Complete mem access */
629
630 WSeq(ba, SEQ_ID_UNLOCK_EXT, 0x06); /* Unlock extensions */
631 test = RSeq(ba, SEQ_ID_BUS_REQ_CNTL); /* Bus Request */
632
633 /* enable 4MB fast Page Mode */
634 test = test | 1 << 6;
635 WSeq(ba, SEQ_ID_BUS_REQ_CNTL, test);
636 /* faster LUT write */
637 WSeq(ba, SEQ_ID_RAMDAC_CNTL, 0xC0);
638
639 test = RSeq(ba, SEQ_ID_CLKSYN_CNTL_2); /* Clksyn2 read */
640
641 /* immediately Clkload bit clear */
642 test = test & 0xDF;
643
644 /* 2 MCLK Memory Write.... */
645 if (cv_memclk >= 55000000)
646 test |= 0x80;
647
648 WSeq(ba, SEQ_ID_CLKSYN_CNTL_2, test);
649
650 /* Memory CLK */
651 clockpar = cv_compute_clock(cv_memclk);
652 test = (clockpar & 0xFF00) >> 8;
653 WSeq(ba, SEQ_ID_MCLK_HI, test); /* PLL N-Divider Value */
654
655 test = clockpar & 0xFF;
656 WSeq(ba, SEQ_ID_MCLK_LO, test); /* PLL M-Divider Value */
657
658 if (RCrt(ba, CRT_ID_REVISION) == 0x10) /* bugfix for new S3 chips */
659 WSeq(ba, SEQ_ID_MORE_MAGIC, test);
660
661 /* We now load an 25 MHz, 31 kHz, 640x480 standard VGA Mode. */
662 /* DCLK */
663 WSeq(ba, SEQ_ID_DCLK_HI, 0x13);
664 WSeq(ba, SEQ_ID_DCLK_LO, 0x41);
665
666 test = RSeq (ba, SEQ_ID_CLKSYN_CNTL_2);
667 test = test | 0x22;
668
669 /* DCLK + MCLK Clock immediate load! */
670 WSeq(ba,SEQ_ID_CLKSYN_CNTL_2, test);
671
672 /* DCLK load */
673 test = vgar(ba, 0x3cc);
674 test = test | 0x0c;
675 vgaw(ba, 0x3c2, test);
676
677 /* Clear bit 5 again, prevent further loading. */
678 WSeq(ba, SEQ_ID_CLKSYN_CNTL_2, 0x02);
679
680 WCrt(ba, CRT_ID_HOR_TOTAL, 0x5F);
681 WCrt(ba, CRT_ID_HOR_DISP_ENA_END, 0x4F);
682 WCrt(ba, CRT_ID_START_HOR_BLANK, 0x50);
683 WCrt(ba, CRT_ID_END_HOR_BLANK, 0x82);
684 WCrt(ba, CRT_ID_START_HOR_RETR, 0x54);
685 WCrt(ba, CRT_ID_END_HOR_RETR, 0x80);
686 WCrt(ba, CRT_ID_VER_TOTAL, 0xBF);
687
688 WCrt(ba, CRT_ID_OVERFLOW, 0x1F); /* overflow reg */
689
690 WCrt(ba, CRT_ID_PRESET_ROW_SCAN, 0x00); /* no panning */
691
692 WCrt(ba, CRT_ID_MAX_SCAN_LINE, 0x40); /* vscan */
693
694 WCrt(ba, CRT_ID_CURSOR_START, 0x00);
695 WCrt(ba, CRT_ID_CURSOR_END, 0x00);
696
697 /* Display start adress */
698 WCrt(ba, CRT_ID_START_ADDR_HIGH, 0x00);
699 WCrt(ba, CRT_ID_START_ADDR_LOW, 0x00);
700
701 /* Cursor location */
702 WCrt(ba, CRT_ID_CURSOR_LOC_HIGH, 0x00);
703 WCrt(ba, CRT_ID_CURSOR_LOC_LOW, 0x00);
704
705 /* Vertical retrace */
706 WCrt(ba, CRT_ID_START_VER_RETR, 0x9C);
707 WCrt(ba, CRT_ID_END_VER_RETR, 0x0E);
708
709 WCrt(ba, CRT_ID_VER_DISP_ENA_END, 0x8F);
710 WCrt(ba, CRT_ID_SCREEN_OFFSET, 0x50);
711
712 WCrt(ba, CRT_ID_UNDERLINE_LOC, 0x00);
713
714 WCrt(ba, CRT_ID_START_VER_BLANK, 0x96);
715 WCrt(ba, CRT_ID_END_VER_BLANK, 0xB9);
716
717 WCrt(ba, CRT_ID_MODE_CONTROL, 0xE3);
718
719 WCrt(ba, CRT_ID_LINE_COMPARE, 0xFF);
720
721 WCrt(ba, CRT_ID_BACKWAD_COMP_3, 0x10); /* FIFO enabled */
722
723 /* Refresh count 1, High speed text font, enhanced color mode */
724 WCrt(ba, CRT_ID_MISC_1, 0x35);
725
726 /* start fifo position */
727 WCrt(ba, CRT_ID_DISPLAY_FIFO, 0x5a);
728
729 WCrt(ba, CRT_ID_EXT_MEM_CNTL_2, 0x70);
730
731 /* address window position */
732 WCrt(ba, CRT_ID_LAW_POS_LO, 0x40);
733
734 /* N Parameter for Display FIFO */
735 WCrt(ba, CRT_ID_EXT_MEM_CNTL_3, 0xFF);
736
737 WGfx(ba, GCT_ID_SET_RESET, 0x00);
738 WGfx(ba, GCT_ID_ENABLE_SET_RESET, 0x00);
739 WGfx(ba, GCT_ID_COLOR_COMPARE, 0x00);
740 WGfx(ba, GCT_ID_DATA_ROTATE, 0x00);
741 WGfx(ba, GCT_ID_READ_MAP_SELECT, 0x00);
742 WGfx(ba, GCT_ID_GRAPHICS_MODE, 0x40);
743 WGfx(ba, GCT_ID_MISC, 0x01);
744 WGfx(ba, GCT_ID_COLOR_XCARE, 0x0F);
745 WGfx(ba, GCT_ID_BITMASK, 0xFF);
746
747 /* colors for text mode */
748 for (i = 0; i <= 0xf; i++)
749 WAttr (ba, i, i);
750
751 WAttr(ba, ACT_ID_ATTR_MODE_CNTL, 0x41);
752 WAttr(ba, ACT_ID_OVERSCAN_COLOR, 0x01);
753 WAttr(ba, ACT_ID_COLOR_PLANE_ENA, 0x0F);
754 WAttr(ba, ACT_ID_HOR_PEL_PANNING, 0x00);
755 WAttr(ba, ACT_ID_COLOR_SELECT, 0x00);
756
757 vgaw(ba, VDAC_MASK, 0xFF); /* DAC Mask */
758
759 *((unsigned long *)(ba + ECR_FRGD_COLOR)) = 0xFF;
760 *((unsigned long *)(ba + ECR_BKGD_COLOR)) = 0;
761
762 /* colors initially set to greyscale */
763
764 vgaw(ba, VDAC_ADDRESS_W, 0);
765 for (i = 255; i >= 0 ; i--) {
766 vgaw(ba, VDAC_DATA, i);
767 vgaw(ba, VDAC_DATA, i);
768 vgaw(ba, VDAC_DATA, i);
769 }
770
771 /* GFx hardware cursor off */
772 WCrt(ba, CRT_ID_HWGC_MODE, 0x00);
773
774 /* Set first to 4 MB, so test will work */
775 WCrt(ba, CRT_ID_LAW_CNTL, 0x13);
776
777 /* find *correct* fbsize of z3 board */
778 if (cv_has_4mb((volatile caddr_t)cv_boardaddr + 0x01400000)) {
779 cv_fbsize = 1024 * 1024 * 4;
780 WCrt(ba, CRT_ID_LAW_CNTL, 0x13); /* 4 MB */
781 } else {
782 cv_fbsize = 1024 * 1024 * 2;
783 WCrt(ba, CRT_ID_LAW_CNTL, 0x12); /* 2 MB */
784 }
785
786 /* Initialize graphics engine */
787 GfxBusyWait(ba);
788 vgaw16(ba, ECR_FRGD_MIX, 0x27);
789 vgaw16(ba, ECR_BKGD_MIX, 0x07);
790
791 vgaw16(ba, ECR_READ_REG_DATA, 0x1000);
792 delay(200000);
793 vgaw16(ba, ECR_READ_REG_DATA, 0x2000);
794 GfxBusyWait(ba);
795 vgaw16(ba, ECR_READ_REG_DATA, 0x3fff);
796 GfxBusyWait(ba);
797 delay(200000);
798 vgaw16(ba, ECR_READ_REG_DATA, 0x4fff);
799 GfxBusyWait(ba);
800
801 vgaw16(ba, ECR_BITPLANE_WRITE_MASK, ~0);
802
803 GfxBusyWait (ba);
804 vgaw16(ba, ECR_READ_REG_DATA, 0xe000);
805 vgaw16(ba, ECR_CURRENT_Y_POS2, 0x00);
806 vgaw16(ba, ECR_CURRENT_X_POS2, 0x00);
807 vgaw16(ba, ECR_READ_REG_DATA, 0xa000);
808 vgaw16(ba, ECR_DEST_Y__AX_STEP, 0x00);
809 vgaw16(ba, ECR_DEST_Y2__AX_STEP2, 0x00);
810 vgaw16(ba, ECR_DEST_X__DIA_STEP, 0x00);
811 vgaw16(ba, ECR_DEST_X2__DIA_STEP2, 0x00);
812 vgaw16(ba, ECR_SHORT_STROKE, 0x00);
813 vgaw16(ba, ECR_DRAW_CMD, 0x01);
814 GfxBusyWait (ba);
815
816 /* It ain't easy to write here, so let's do it again */
817 vgaw16(ba, ECR_READ_REG_DATA, 0x4fff);
818
819 vgaw16(ba, ECR_BKGD_COLOR, 0x01);
820 vgaw16(ba, ECR_FRGD_COLOR, 0x00);
821
822 /* Enable Video Display (Set Bit 5) */
823 WAttr(ba, 0x33, 0);
824
825 gi = &gp->g_display;
826 gi->gd_regaddr = (caddr_t) kvtop (ba);
827 gi->gd_regsize = 64 * 1024;
828 gi->gd_fbaddr = (caddr_t) kvtop (gp->g_fbkva);
829 gi->gd_fbsize = cv_fbsize;
830 }
831
832
833 int
834 cv_getvmode(gp, vm)
835 struct grf_softc *gp;
836 struct grfvideo_mode *vm;
837 {
838 struct grfvideo_mode *gv;
839
840 #ifdef CV64CONSOLE
841 /* Handle grabbing console mode */
842 if (vm->mode_num == 255) {
843 bcopy(&cvconsole_mode, vm, sizeof(struct grfvideo_mode));
844 /* XXX so grfconfig can tell us the correct text dimensions. */
845 vm->depth = cvconsole_mode.fy;
846 } else
847 #endif
848 {
849 if (vm->mode_num == 0)
850 vm->mode_num = (monitor_current - monitor_def) + 1;
851 if (vm->mode_num < 1 || vm->mode_num > monitor_def_max)
852 return (EINVAL);
853 gv = monitor_def + (vm->mode_num - 1);
854 if (gv->mode_num == 0)
855 return (EINVAL);
856
857 bcopy(gv, vm, sizeof(struct grfvideo_mode));
858 }
859
860 /* adjust internal values to pixel values */
861
862 vm->hblank_start *= 8;
863 vm->hsync_start *= 8;
864 vm->hsync_stop *= 8;
865 vm->htotal *= 8;
866
867 return (0);
868 }
869
870
871 int
872 cv_setvmode(gp, mode)
873 struct grf_softc *gp;
874 unsigned mode;
875 {
876
877 if (!mode || (mode > monitor_def_max) ||
878 monitor_def[mode - 1].mode_num == 0)
879 return (EINVAL);
880
881 monitor_current = monitor_def + (mode - 1);
882
883 return (0);
884 }
885
886
887 int
888 cv_blank(gp, on)
889 struct grf_softc *gp;
890 int *on;
891 {
892 volatile caddr_t ba;
893
894 ba = gp->g_regkva;
895 gfx_on_off(*on > 0 ? 0 : 1, ba);
896 return (0);
897 }
898
899
900 /*
901 * Change the mode of the display.
902 * Return a UNIX error number or 0 for success.
903 */
904 int
905 cv_mode(gp, cmd, arg, a2, a3)
906 register struct grf_softc *gp;
907 u_long cmd;
908 void *arg;
909 u_long a2;
910 int a3;
911 {
912 int error;
913
914 switch (cmd) {
915 case GM_GRFON:
916 error = cv_load_mon (gp,
917 (struct grfcvtext_mode *) monitor_current) ? 0 : EINVAL;
918 return (error);
919
920 case GM_GRFOFF:
921 #ifndef CV64CONSOLE
922 cvscreen(1, gp->g_regkva - 0x02000000);
923 #else
924 cv_load_mon(gp, &cvconsole_mode);
925 ite_reinit(gp->g_itedev);
926 #endif
927 return (0);
928
929 case GM_GRFCONFIG:
930 return (0);
931
932 case GM_GRFGETVMODE:
933 return (cv_getvmode (gp, (struct grfvideo_mode *) arg));
934
935 case GM_GRFSETVMODE:
936 error = cv_setvmode (gp, *(unsigned *) arg);
937 if (!error && (gp->g_flags & GF_GRFON))
938 cv_load_mon(gp,
939 (struct grfcvtext_mode *) monitor_current);
940 return (error);
941
942 case GM_GRFGETNUMVM:
943 *(int *)arg = monitor_def_max;
944 return (0);
945
946 case GM_GRFIOCTL:
947 return (cv_ioctl (gp, a2, arg));
948
949 default:
950 break;
951 }
952
953 return (EINVAL);
954 }
955
956
957 int
958 cv_ioctl (gp, cmd, data)
959 register struct grf_softc *gp;
960 u_long cmd;
961 void *data;
962 {
963 switch (cmd) {
964 #ifndef CV_NO_HARDWARE_CURSOR
965 case GRFIOCGSPRITEPOS:
966 return(cv_getspritepos (gp, (struct grf_position *) data));
967
968 case GRFIOCSSPRITEPOS:
969 return(cv_setspritepos (gp, (struct grf_position *) data));
970
971 case GRFIOCSSPRITEINF:
972 return(cv_setspriteinfo (gp, (struct grf_spriteinfo *) data));
973
974 case GRFIOCGSPRITEINF:
975 return(cv_getspriteinfo (gp, (struct grf_spriteinfo *) data));
976
977 case GRFIOCGSPRITEMAX:
978 return(cv_getspritemax (gp, (struct grf_position *) data));
979 #else /* !CV_NO_HARDWARE_CURSOR */
980 case GRFIOCGSPRITEPOS:
981 case GRFIOCSSPRITEPOS:
982 case GRFIOCSSPRITEINF:
983 case GRFIOCGSPRITEINF:
984 case GRFIOCGSPRITEMAX:
985 break;
986 #endif /* !CV_NO_HARDWARE_CURSOR */
987
988 case GRFIOCGETCMAP:
989 return (cv_getcmap (gp, (struct grf_colormap *) data));
990
991 case GRFIOCPUTCMAP:
992 return (cv_putcmap (gp, (struct grf_colormap *) data));
993
994 case GRFIOCBITBLT:
995 break;
996
997 case GRFTOGGLE:
998 return (cv_toggle (gp));
999
1000 case GRFIOCSETMON:
1001 return (cv_setmonitor (gp, (struct grfvideo_mode *)data));
1002
1003 case GRFIOCBLANK:
1004 return (cv_blank (gp, (int *)data));
1005 }
1006 return (EINVAL);
1007 }
1008
1009
1010 int
1011 cv_setmonitor(gp, gv)
1012 struct grf_softc *gp;
1013 struct grfvideo_mode *gv;
1014 {
1015 struct grfvideo_mode *md;
1016
1017 if (!cv_mondefok(gv))
1018 return (EINVAL);
1019
1020 #ifdef CV64CONSOLE
1021 /* handle interactive setting of console mode */
1022 if (gv->mode_num == 255) {
1023 bcopy(gv, &cvconsole_mode.gv, sizeof(struct grfvideo_mode));
1024 cvconsole_mode.gv.hblank_start /= 8;
1025 cvconsole_mode.gv.hsync_start /= 8;
1026 cvconsole_mode.gv.hsync_stop /= 8;
1027 cvconsole_mode.gv.htotal /= 8;
1028 cvconsole_mode.rows = gv->disp_height / cvconsole_mode.fy;
1029 cvconsole_mode.cols = gv->disp_width / cvconsole_mode.fx;
1030 if (!(gp->g_flags & GF_GRFON))
1031 cv_load_mon(gp, &cvconsole_mode);
1032 ite_reinit(gp->g_itedev);
1033 return (0);
1034 }
1035 #endif
1036
1037 md = monitor_def + (gv->mode_num - 1);
1038
1039 /*
1040 * Prevent user from crashing the system by using
1041 * grfconfig while in X
1042 */
1043 if (gp->g_flags & GF_GRFON)
1044 if (md == monitor_current) {
1045 printf("grfcv: Changing the used mode not allowed!\n");
1046 return (EINVAL);
1047 }
1048
1049 bcopy(gv, md, sizeof(struct grfvideo_mode));
1050
1051 /* adjust pixel oriented values to internal rep. */
1052
1053 md->hblank_start /= 8;
1054 md->hsync_start /= 8;
1055 md->hsync_stop /= 8;
1056 md->htotal /= 8;
1057
1058 return (0);
1059 }
1060
1061
1062 int
1063 cv_getcmap(gfp, cmap)
1064 struct grf_softc *gfp;
1065 struct grf_colormap *cmap;
1066 {
1067 volatile caddr_t ba;
1068 u_char red[256], green[256], blue[256], *rp, *gp, *bp;
1069 short x;
1070 int error;
1071
1072 ba = gfp->g_regkva;
1073 if (cmap->count == 0 || cmap->index >= 256)
1074 return (0);
1075
1076 if (cmap->index + cmap->count > 256)
1077 cmap->count = 256 - cmap->index;
1078
1079 /* first read colors out of the chip, then copyout to userspace */
1080 vgaw (ba, VDAC_ADDRESS_W, cmap->index);
1081 x = cmap->count - 1;
1082
1083 rp = red + cmap->index;
1084 gp = green + cmap->index;
1085 bp = blue + cmap->index;
1086
1087 do {
1088 *rp++ = vgar (ba, VDAC_DATA) << 2;
1089 *gp++ = vgar (ba, VDAC_DATA) << 2;
1090 *bp++ = vgar (ba, VDAC_DATA) << 2;
1091 } while (x-- > 0);
1092
1093 if (!(error = copyout (red + cmap->index, cmap->red, cmap->count))
1094 && !(error = copyout (green + cmap->index, cmap->green, cmap->count))
1095 && !(error = copyout (blue + cmap->index, cmap->blue, cmap->count)))
1096 return (0);
1097
1098 return (error);
1099 }
1100
1101
1102 int
1103 cv_putcmap(gfp, cmap)
1104 struct grf_softc *gfp;
1105 struct grf_colormap *cmap;
1106 {
1107 volatile caddr_t ba;
1108 u_char red[256], green[256], blue[256], *rp, *gp, *bp;
1109 short x;
1110 int error;
1111
1112 ba = gfp->g_regkva;
1113 if (cmap->count == 0 || cmap->index >= 256)
1114 return (0);
1115
1116 if (cmap->index + cmap->count > 256)
1117 cmap->count = 256 - cmap->index;
1118
1119 /* first copy the colors into kernelspace */
1120 if (!(error = copyin (cmap->red, red + cmap->index, cmap->count))
1121 && !(error = copyin (cmap->green, green + cmap->index, cmap->count))
1122 && !(error = copyin (cmap->blue, blue + cmap->index, cmap->count))) {
1123 vgaw (ba, VDAC_ADDRESS_W, cmap->index);
1124 x = cmap->count - 1;
1125
1126 rp = red + cmap->index;
1127 gp = green + cmap->index;
1128 bp = blue + cmap->index;
1129
1130 do {
1131 vgaw (ba, VDAC_DATA, *rp++ >> 2);
1132 vgaw (ba, VDAC_DATA, *gp++ >> 2);
1133 vgaw (ba, VDAC_DATA, *bp++ >> 2);
1134 } while (x-- > 0);
1135 return (0);
1136 } else
1137 return (error);
1138 }
1139
1140
1141 int
1142 cv_toggle(gp)
1143 struct grf_softc *gp;
1144 {
1145 volatile caddr_t ba;
1146
1147 ba = gp->g_regkva;
1148 #ifndef CV64CONSOLE
1149 cv_pass_toggle = 1;
1150 #endif /* !CV64CONSOLE */
1151
1152 if (cv_pass_toggle) {
1153 cvscreen(0, ba - 0x02000000);
1154 cv_pass_toggle = 0;
1155 } else {
1156 cvscreen(1, ba - 0x02000000);
1157 cv_pass_toggle = 1;
1158 }
1159
1160 return (0);
1161 }
1162
1163
1164 int
1165 cv_mondefok(gv)
1166 struct grfvideo_mode *gv;
1167 {
1168 unsigned long maxpix;
1169
1170 if (gv->mode_num < 1 || gv->mode_num > monitor_def_max) {
1171 if (gv->mode_num != 255 || gv->depth != 4)
1172 return (0);
1173 }
1174
1175 switch(gv->depth) {
1176 case 4:
1177 maxpix = MAXPIXELCLOCK - 55000000;
1178 break;
1179 case 8:
1180 maxpix = MAXPIXELCLOCK;
1181 break;
1182 case 15:
1183 case 16:
1184 #ifdef CV_AGGRESSIVE_TIMING
1185 maxpix = MAXPIXELCLOCK - 35000000;
1186 #else
1187 maxpix = MAXPIXELCLOCK - 55000000;
1188 #endif
1189 break;
1190 case 24:
1191 case 32:
1192 #ifdef CV_AGGRESSIVE_TIMING
1193 maxpix = MAXPIXELCLOCK - 75000000;
1194 #else
1195 maxpix = MAXPIXELCLOCK - 85000000;
1196 #endif
1197 break;
1198 default:
1199 printf("grfcv: Illegal depth in mode %d\n",
1200 (int) gv->mode_num);
1201 return (0);
1202 }
1203
1204 if (gv->pixel_clock > maxpix) {
1205 printf("grfcv: Pixelclock too high in mode %d\n",
1206 (int) gv->mode_num);
1207 return (0);
1208 }
1209
1210 if (gv->mode_num == 255) { /* console mode */
1211 if ((gv->disp_width / 8) > MAXCOLS) {
1212 printf ("grfcv: Too many columns for console\n");
1213 return (0);
1214 } else if ((gv->disp_height / S3FONTY) > MAXROWS) {
1215 printf ("grfcv: Too many rows for console\n");
1216 return (0);
1217 }
1218 }
1219
1220 if (gv->disp_flags & GRF_FLAGS_SYNC_ON_GREEN) {
1221 printf("grfcv: sync-on-green is not supported\n");
1222 return (0);
1223 }
1224
1225 return (1);
1226 }
1227
1228
1229 int
1230 cv_load_mon(gp, md)
1231 struct grf_softc *gp;
1232 struct grfcvtext_mode *md;
1233 {
1234 struct grfvideo_mode *gv;
1235 struct grfinfo *gi;
1236 volatile caddr_t ba, fb;
1237 unsigned short mnr;
1238 unsigned short HT, HDE, HBS, HBE, HSS, HSE, VDE, VBS, VBE, VSS,
1239 VSE, VT;
1240 int cr50, sr15, sr18, clock_mode, test;
1241 int m, n; /* For calc'ing display FIFO */
1242 int tfillm, temptym; /* FIFO fill and empty mclk's */
1243 int hmul; /* Multiplier for hor. Values */
1244 unsigned char hvsync_pulse;
1245 char TEXT, CONSOLE;
1246
1247 /* identity */
1248 gv = &md->gv;
1249
1250 TEXT = (gv->depth == 4);
1251 CONSOLE = (gv->mode_num == 255);
1252
1253 if (!cv_mondefok(gv)) {
1254 printf("grfcv: Monitor definition not ok\n");
1255 return (0);
1256 }
1257
1258 ba = gp->g_regkva;
1259 fb = gp->g_fbkva;
1260
1261 /* Disable Interrupts */
1262 test = RCrt(ba, CRT_ID_BACKWAD_COMP_1);
1263 test &= ~0x10;
1264 WCrt(ba, CRT_ID_BACKWAD_COMP_1, test);
1265
1266 /* turn gfx off, don't mess up the display */
1267 gfx_on_off(1, ba);
1268
1269 /* provide all needed information in grf device-independant locations */
1270 gp->g_data = (caddr_t) gv;
1271 gi = &gp->g_display;
1272 gi->gd_colors = 1 << gv->depth;
1273 gi->gd_planes = gv->depth;
1274 gi->gd_fbwidth = gv->disp_width;
1275 gi->gd_fbheight = gv->disp_height;
1276 gi->gd_fbx = 0;
1277 gi->gd_fby = 0;
1278 if (CONSOLE) {
1279 gi->gd_dwidth = md->fx * md->cols;
1280 gi->gd_dheight = md->fy * md->rows;
1281 } else {
1282 gi->gd_dwidth = gv->disp_width;
1283 gi->gd_dheight = gv->disp_height;
1284 }
1285 gi->gd_dx = 0;
1286 gi->gd_dy = 0;
1287
1288 /* get display mode parameters */
1289 switch (gv->depth) {
1290 case 15:
1291 case 16:
1292 hmul = 2;
1293 break;
1294 default:
1295 hmul = 1;
1296 break;
1297 }
1298
1299 HBS = gv->hblank_start * hmul;
1300 HSS = gv->hsync_start * hmul;
1301 HSE = gv->hsync_stop * hmul;
1302 HBE = gv->htotal * hmul - 6;
1303 HT = gv->htotal * hmul - 5;
1304 VBS = gv->vblank_start - 1;
1305 VSS = gv->vsync_start;
1306 VSE = gv->vsync_stop;
1307 VBE = gv->vtotal - 3;
1308 VT = gv->vtotal - 2;
1309
1310 /* Disable enhanced Mode for text display */
1311
1312 vgaw(ba, ECR_ADV_FUNC_CNTL, (TEXT ? 0x00 : 0x31));
1313
1314 if (TEXT)
1315 HDE = ((gv->disp_width + md->fx - 1) / md->fx) - 1;
1316 else
1317 HDE = (gv->disp_width + 3) * hmul / 8 - 1; /*HBS;*/
1318 VDE = gv->disp_height - 1;
1319
1320 /* adjustments */
1321
1322 if (gv->disp_flags & GRF_FLAGS_LACE) {
1323 VDE = VDE / 2;
1324 VBS = VBS / 2;
1325 VSS = VSS / 2;
1326 VSE = VSE / 2;
1327 VBE = VBE / 2;
1328 VT = VT / 2;
1329 }
1330
1331 /* Horizontal/Vertical Sync Pulse */
1332 /*
1333 * GREG_MISC_OUTPUT_W Register:
1334 * bit description (0/1)
1335 * 0 Monochrome/Color emulation
1336 * 1 Disable/Enable access of the display memory from the CPU
1337 * 5 Select the low/high 64K page of memory
1338 * 6 Select a positive/negative horizontal retrace sync pulse
1339 * 7 Select a positive/negative vertical retrace sync pulse
1340 */
1341 hvsync_pulse = vgar(ba, GREG_MISC_OUTPUT_R);
1342 if (gv->disp_flags & GRF_FLAGS_PHSYNC)
1343 hvsync_pulse &= ~0x40;
1344 else
1345 hvsync_pulse |= 0x40;
1346 if (gv->disp_flags & GRF_FLAGS_PVSYNC)
1347 hvsync_pulse &= ~0x80;
1348 else
1349 hvsync_pulse |= 0x80;
1350 vgaw(ba, GREG_MISC_OUTPUT_W, hvsync_pulse);
1351
1352 /* GFX hardware cursor off */
1353 WCrt(ba, CRT_ID_HWGC_MODE, 0x00);
1354 WCrt(ba, CRT_ID_EXT_DAC_CNTL, 0x00);
1355
1356 WSeq(ba, SEQ_ID_MEMORY_MODE, (TEXT || (gv->depth == 1)) ? 0x06 : 0x0e);
1357 WGfx(ba, GCT_ID_READ_MAP_SELECT, 0x00);
1358 WSeq(ba, SEQ_ID_MAP_MASK, (gv->depth == 1) ? 0x01 : 0xff);
1359 WSeq(ba, SEQ_ID_CHAR_MAP_SELECT, 0x00);
1360
1361 /* Set clock */
1362
1363 mnr = cv_compute_clock(gv->pixel_clock);
1364 WSeq(ba, SEQ_ID_DCLK_HI, ((mnr & 0xFF00) >> 8));
1365 WSeq(ba, SEQ_ID_DCLK_LO, (mnr & 0xFF));
1366
1367 /* load display parameters into board */
1368
1369 WCrt(ba, CRT_ID_EXT_HOR_OVF,
1370 ((HT & 0x100) ? 0x01 : 0x00) |
1371 ((HDE & 0x100) ? 0x02 : 0x00) |
1372 ((HBS & 0x100) ? 0x04 : 0x00) |
1373 /* ((HBE & 0x40) ? 0x08 : 0x00) | */ /* Later... */
1374 ((HSS & 0x100) ? 0x10 : 0x00) |
1375 /* ((HSE & 0x20) ? 0x20 : 0x00) | */
1376 (((HT-5) & 0x100) ? 0x40 : 0x00) );
1377
1378 WCrt(ba, CRT_ID_EXT_VER_OVF,
1379 0x40 | /* Line compare */
1380 ((VT & 0x400) ? 0x01 : 0x00) |
1381 ((VDE & 0x400) ? 0x02 : 0x00) |
1382 ((VBS & 0x400) ? 0x04 : 0x00) |
1383 ((VSS & 0x400) ? 0x10 : 0x00) );
1384
1385 WCrt(ba, CRT_ID_HOR_TOTAL, HT);
1386 WCrt(ba, CRT_ID_DISPLAY_FIFO, HT - 5);
1387
1388 WCrt(ba, CRT_ID_HOR_DISP_ENA_END, ((HDE >= HBS) ? (HBS - 1) : HDE));
1389 WCrt(ba, CRT_ID_START_HOR_BLANK, HBS);
1390 WCrt(ba, CRT_ID_END_HOR_BLANK, ((HBE & 0x1f) | 0x80));
1391 WCrt(ba, CRT_ID_START_HOR_RETR, HSS);
1392 WCrt(ba, CRT_ID_END_HOR_RETR,
1393 (HSE & 0x1f) |
1394 ((HBE & 0x20) ? 0x80 : 0x00) );
1395 WCrt(ba, CRT_ID_VER_TOTAL, VT);
1396 WCrt(ba, CRT_ID_OVERFLOW,
1397 0x10 |
1398 ((VT & 0x100) ? 0x01 : 0x00) |
1399 ((VDE & 0x100) ? 0x02 : 0x00) |
1400 ((VSS & 0x100) ? 0x04 : 0x00) |
1401 ((VBS & 0x100) ? 0x08 : 0x00) |
1402 ((VT & 0x200) ? 0x20 : 0x00) |
1403 ((VDE & 0x200) ? 0x40 : 0x00) |
1404 ((VSS & 0x200) ? 0x80 : 0x00) );
1405
1406 WCrt(ba, CRT_ID_MAX_SCAN_LINE,
1407 0x40 | /* TEXT ? 0x00 ??? */
1408 ((gv->disp_flags & GRF_FLAGS_DBLSCAN) ? 0x80 : 0x00) |
1409 ((VBS & 0x200) ? 0x20 : 0x00) |
1410 (TEXT ? ((md->fy - 1) & 0x1f) : 0x00));
1411
1412 WCrt(ba, CRT_ID_MODE_CONTROL, 0xe3);
1413
1414 /* text cursor */
1415
1416 if (TEXT) {
1417 #if CV_ULCURSOR
1418 WCrt(ba, CRT_ID_CURSOR_START, (md->fy & 0x1f) - 2);
1419 WCrt(ba, CRT_ID_CURSOR_END, (md->fy & 0x1f) - 1);
1420 #else
1421 WCrt(ba, CRT_ID_CURSOR_START, 0x00);
1422 WCrt(ba, CRT_ID_CURSOR_END, md->fy & 0x1f);
1423 #endif
1424 WCrt(ba, CRT_ID_UNDERLINE_LOC, (md->fy - 1) & 0x1f);
1425
1426 WCrt(ba, CRT_ID_CURSOR_LOC_HIGH, 0x00);
1427 WCrt(ba, CRT_ID_CURSOR_LOC_LOW, 0x00);
1428 }
1429
1430 WCrt(ba, CRT_ID_START_ADDR_HIGH, 0x00);
1431 WCrt(ba, CRT_ID_START_ADDR_LOW, 0x00);
1432
1433 WCrt(ba, CRT_ID_START_VER_RETR, VSS);
1434 WCrt(ba, CRT_ID_END_VER_RETR, (VSE & 0x0f));
1435 WCrt(ba, CRT_ID_VER_DISP_ENA_END, VDE);
1436 WCrt(ba, CRT_ID_START_VER_BLANK, VBS);
1437 WCrt(ba, CRT_ID_END_VER_BLANK, VBE);
1438
1439 WCrt(ba, CRT_ID_LINE_COMPARE, 0xff);
1440 WCrt(ba, CRT_ID_LACE_RETR_START, HT / 2);
1441 WCrt(ba, CRT_ID_LACE_CONTROL,
1442 ((gv->disp_flags & GRF_FLAGS_LACE) ? 0x20 : 0x00));
1443
1444 WGfx(ba, GCT_ID_GRAPHICS_MODE,
1445 ((TEXT || (gv->depth == 1)) ? 0x00 : 0x40));
1446 WGfx(ba, GCT_ID_MISC, (TEXT ? 0x04 : 0x01));
1447
1448 WSeq (ba, SEQ_ID_MEMORY_MODE,
1449 ((TEXT || (gv->depth == 1)) ? 0x06 : 0x02));
1450
1451 vgaw(ba, VDAC_MASK, 0xff);
1452
1453 /* Blank border */
1454 test = RCrt(ba, CRT_ID_BACKWAD_COMP_2);
1455 WCrt(ba, CRT_ID_BACKWAD_COMP_2, (test | 0x20));
1456
1457 sr15 = RSeq(ba, SEQ_ID_CLKSYN_CNTL_2);
1458 sr15 &= ~0x10;
1459 sr18 = RSeq(ba, SEQ_ID_RAMDAC_CNTL);
1460 sr18 &= ~0x80;
1461 clock_mode = 0x00;
1462 cr50 = 0x00;
1463
1464 test = RCrt(ba, CRT_ID_EXT_MISC_CNTL_2);
1465 test &= 0xd;
1466
1467 /* clear roxxler byte-swapping... */
1468 cv_write_port(0x0040, cv_boardaddr);
1469 cv_write_port(0x0020, cv_boardaddr);
1470
1471 switch (gv->depth) {
1472 case 1:
1473 case 4: /* text */
1474 HDE = gv->disp_width / 16;
1475 break;
1476 case 8:
1477 if (gv->pixel_clock > 80000000) {
1478 clock_mode = 0x10 | 0x02;
1479 sr15 |= 0x10;
1480 sr18 |= 0x80;
1481 }
1482 HDE = gv->disp_width / 8;
1483 cr50 |= 0x00;
1484 break;
1485 case 15:
1486 cv_write_port (0x8020, cv_boardaddr);
1487 clock_mode = 0x30;
1488 HDE = gv->disp_width / 4;
1489 cr50 |= 0x10;
1490 break;
1491 case 16:
1492 cv_write_port (0x8020, cv_boardaddr);
1493 clock_mode = 0x50;
1494 HDE = gv->disp_width / 4;
1495 cr50 |= 0x10;
1496 break;
1497 case 24: /* this is really 32 Bit on CV64 */
1498 case 32:
1499 cv_write_port(0x8040, cv_boardaddr);
1500 clock_mode = 0xd0;
1501 HDE = (gv->disp_width / 2);
1502 cr50 |= 0x30;
1503 break;
1504 }
1505
1506 WCrt(ba, CRT_ID_EXT_MISC_CNTL_2, clock_mode | test);
1507 WSeq(ba, SEQ_ID_CLKSYN_CNTL_2, sr15);
1508 WSeq(ba, SEQ_ID_RAMDAC_CNTL, sr18);
1509 WCrt(ba, CRT_ID_SCREEN_OFFSET, HDE);
1510
1511 WCrt(ba, CRT_ID_MISC_1, (TEXT ? 0x05 : 0x35));
1512
1513 test = RCrt(ba, CRT_ID_EXT_SYS_CNTL_2);
1514 test &= ~0x30;
1515 /* HDE Overflow in bits 4-5 */
1516 test |= (HDE >> 4) & 0x30;
1517 WCrt(ba, CRT_ID_EXT_SYS_CNTL_2, test);
1518
1519 /* Set up graphics engine */
1520 switch (gv->disp_width) {
1521 case 1024:
1522 cr50 |= 0x00;
1523 break;
1524 case 640:
1525 cr50 |= 0x40;
1526 break;
1527 case 800:
1528 cr50 |= 0x80;
1529 break;
1530 case 1280:
1531 cr50 |= 0xc0;
1532 break;
1533 case 1152:
1534 cr50 |= 0x01;
1535 break;
1536 case 1600:
1537 cr50 |= 0x81;
1538 break;
1539 default: /* XXX The Xserver has to handle this */
1540 break;
1541 }
1542
1543 WCrt(ba, CRT_ID_EXT_SYS_CNTL_1, cr50);
1544
1545 delay(100000);
1546 WAttr(ba, ACT_ID_ATTR_MODE_CNTL, (TEXT ? 0x08 : 0x41));
1547 delay(100000);
1548 WAttr(ba, ACT_ID_COLOR_PLANE_ENA,
1549 (gv->depth == 1) ? 0x01 : 0x0f);
1550 delay(100000);
1551
1552 /*
1553 * M-Parameter of Display FIFO
1554 * This is dependant on the pixel clock and the memory clock.
1555 * The FIFO filling bandwidth is 240 MHz and the FIFO is 96 Byte wide.
1556 * Then the time to fill the FIFO is tfill = (96/240000000) sec, the time
1557 * to empty the FIFO is tempty = (96/pixelclock) sec.
1558 * Then the M parameter maximum is ((tempty-tfill)*cv_memclk-9)/2.
1559 * This seems to be logical, ain't it?
1560 * Remember: We have to use integer arithmetics :(
1561 * Divide by 1000 to prevent overflows.
1562 */
1563
1564 tfillm = (96 * (cv_memclk/1000))/240000;
1565
1566 switch(gv->depth) {
1567 case 32:
1568 case 24:
1569 temptym = (24 * (cv_memclk/1000)) / (gv->pixel_clock/1000);
1570 break;
1571 case 15:
1572 case 16:
1573 temptym = (48 * (cv_memclk/1000)) / (gv->pixel_clock/1000);
1574 break;
1575 case 4:
1576 temptym = (192 * (cv_memclk/1000)) / (gv->pixel_clock/1000);
1577 break;
1578 default:
1579 temptym = (96 * (cv_memclk/1000)) / (gv->pixel_clock/1000);
1580 break;
1581 }
1582
1583 m = (temptym - tfillm - 9) / 2;
1584 if (m < 0)
1585 m = 0; /* prevent underflow */
1586 m = (m & 0x1f) << 3;
1587 if (m < 0x18)
1588 m = 0x18;
1589 n = 0xff;
1590
1591 WCrt(ba, CRT_ID_EXT_MEM_CNTL_2, m);
1592 WCrt(ba, CRT_ID_EXT_MEM_CNTL_3, n);
1593 delay(10000);
1594
1595 /* text initialization */
1596
1597 if (TEXT) {
1598 cv_inittextmode(gp);
1599 }
1600
1601 if (CONSOLE) {
1602 int i;
1603 vgaw(ba, VDAC_ADDRESS_W, 0);
1604 for (i = 0; i < 16; i++) {
1605 vgaw(ba, VDAC_DATA, cvconscolors[i][0]);
1606 vgaw(ba, VDAC_DATA, cvconscolors[i][1]);
1607 vgaw(ba, VDAC_DATA, cvconscolors[i][2]);
1608 }
1609 }
1610
1611 /* Set display enable flag */
1612 WAttr(ba, 0x33, 0);
1613
1614 /* turn gfx on again */
1615 gfx_on_off(0, ba);
1616
1617 /* enable interrupts */
1618 test = RCrt(ba, CRT_ID_BACKWAD_COMP_1);
1619 test |= 0x10;
1620 WCrt(ba, CRT_ID_BACKWAD_COMP_1, test);
1621
1622 test = RCrt(ba, CRT_ID_END_VER_RETR);
1623 test &= ~0x20;
1624 WCrt(ba, CRT_ID_END_VER_RETR, test);
1625 test &= ~0x10;
1626 WCrt(ba, CRT_ID_END_VER_RETR, test);
1627 test |= 0x10;
1628 WCrt(ba, CRT_ID_END_VER_RETR, test);
1629 #ifndef CV_NO_HARDWARE_CURSOR
1630 cv_setup_hwc(gp);
1631 #endif
1632
1633 /* Pass-through */
1634 cvscreen(0, ba - 0x02000000);
1635
1636 return (1);
1637 }
1638
1639
1640 void
1641 cv_inittextmode(gp)
1642 struct grf_softc *gp;
1643 {
1644 struct grfcvtext_mode *tm = (struct grfcvtext_mode *)gp->g_data;
1645 volatile caddr_t ba, fb;
1646 unsigned char *c, *f, y;
1647 unsigned short z;
1648
1649 ba = gp->g_regkva;
1650 fb = gp->g_fbkva;
1651
1652 /* load text font into beginning of display memory.
1653 * Each character cell is 32 bytes long (enough for 4 planes)
1654 * In linear adressing text mode, the memory is organized
1655 * so, that the Bytes of all 4 planes are interleaved.
1656 * 1st byte plane 0, 1st byte plane 1, 1st byte plane 2,
1657 * 1st byte plane 3, 2nd byte plane 0, 2nd byte plane 1,...
1658 * The font is loaded in plane 2.
1659 */
1660
1661 c = (unsigned char *) fb;
1662
1663 /* clear screen */
1664 for (z = 0; z < tm->cols * tm->rows * 3; z++) {
1665 *c++ = 0x20;
1666 *c++ = 0x07;
1667 *c++ = 0;
1668 *c++ = 0;
1669 }
1670
1671 c = (unsigned char *) (fb) + (32 * tm->fdstart * 4 + 2);
1672 f = tm->fdata;
1673 for (z = tm->fdstart; z <= tm->fdend; z++, c += (32 - tm->fy) * 4)
1674 for (y = 0; y < tm->fy; y++) {
1675 *c = *f++;
1676 c += 4;
1677 }
1678
1679 /* print out a little init msg */
1680 c = (unsigned char *)(fb) + (tm->cols - 6) * 4;
1681 *c++ = 'C';
1682 *c++ = 0x0a;
1683 c +=2;
1684 *c++ = 'V';
1685 *c++ = 0x0b;
1686 c +=2;
1687 *c++ = '6';
1688 *c++ = 0x0c;
1689 c +=2;
1690 *c++ = '4';
1691 *c++ = 0x0d;
1692 }
1693
1694
1695 static __inline void
1696 cv_write_port(bits, BoardAddr)
1697 unsigned short bits;
1698 volatile caddr_t BoardAddr;
1699 {
1700 volatile caddr_t addr;
1701 static unsigned char CVPortBits = 0; /* mirror port bits here */
1702
1703 addr = BoardAddr + 0x40001;
1704 if (bits & 0x8000)
1705 CVPortBits |= bits & 0xFF; /* Set bits */
1706 else {
1707 bits = bits & 0xFF;
1708 bits = (~bits) & 0xFF ;
1709 CVPortBits &= bits; /* Clear bits */
1710 }
1711
1712 *addr = CVPortBits;
1713 }
1714
1715
1716 /*
1717 * Monitor Switch
1718 * 0 = CyberVision Signal
1719 * 1 = Amiga Signal,
1720 * ba = boardaddr
1721 */
1722 static __inline void
1723 cvscreen(toggle, ba)
1724 int toggle;
1725 volatile caddr_t ba;
1726 {
1727
1728 if (toggle == 1)
1729 cv_write_port (0x10, ba);
1730 else
1731 cv_write_port (0x8010, ba);
1732 }
1733
1734
1735 /* 0 = on, 1= off */
1736 /* ba= registerbase */
1737 static __inline void
1738 gfx_on_off(toggle, ba)
1739 int toggle;
1740 volatile caddr_t ba;
1741 {
1742 int r;
1743
1744 toggle &= 0x1;
1745 toggle = toggle << 5;
1746
1747 r = RSeq(ba, SEQ_ID_CLOCKING_MODE);
1748 r &= ~0x20; /* set Bit 5 to 0 */
1749
1750 WSeq(ba, SEQ_ID_CLOCKING_MODE, r | toggle);
1751 }
1752
1753
1754 #ifndef CV_NO_HARDWARE_CURSOR
1755
1756 static unsigned char cv_hotx = 0, cv_hoty = 0;
1757 static char cv_cursor_on = 0;
1758
1759 /* Hardware Cursor handling routines */
1760
1761 int
1762 cv_getspritepos(gp, pos)
1763 struct grf_softc *gp;
1764 struct grf_position *pos;
1765 {
1766 int hi,lo;
1767 volatile caddr_t ba = gp->g_regkva;
1768
1769 hi = RCrt(ba, CRT_ID_HWGC_ORIGIN_Y_HI);
1770 lo = RCrt(ba, CRT_ID_HWGC_ORIGIN_Y_LO);
1771
1772 pos->y = (hi << 8) + lo;
1773 hi = RCrt(ba, CRT_ID_HWGC_ORIGIN_X_HI);
1774 lo = RCrt(ba, CRT_ID_HWGC_ORIGIN_X_LO);
1775 pos->x = (hi << 8) + lo;
1776 return (0);
1777 }
1778
1779
1780 int
1781 cv_setspritepos(gp, pos)
1782 struct grf_softc *gp;
1783 struct grf_position *pos;
1784 {
1785 volatile caddr_t ba = gp->g_regkva;
1786 short x, y;
1787 static short savex, savey;
1788 short xoff, yoff;
1789
1790 if (pos) {
1791 x = pos->x;
1792 y = pos->y;
1793 savex = x;
1794 savey= y;
1795 } else { /* restore cursor */
1796 x = savex;
1797 y = savey;
1798 }
1799 x -= cv_hotx;
1800 y -= cv_hoty;
1801 if (x < 0) {
1802 xoff = ((-x) & 0xFE);
1803 x = 0;
1804 } else {
1805 xoff = 0;
1806 }
1807
1808 if (y < 0) {
1809 yoff = ((-y) & 0xFE);
1810 y = 0;
1811 } else {
1812 yoff = 0;
1813 }
1814
1815 WCrt(ba, CRT_ID_HWGC_ORIGIN_X_HI, (x >> 8));
1816 WCrt(ba, CRT_ID_HWGC_ORIGIN_X_LO, (x & 0xff));
1817
1818 WCrt(ba, CRT_ID_HWGC_ORIGIN_Y_LO, (y & 0xff));
1819 WCrt(ba, CRT_ID_HWGC_DSTART_X, xoff);
1820 WCrt(ba, CRT_ID_HWGC_DSTART_Y, yoff);
1821 WCrt(ba, CRT_ID_HWGC_ORIGIN_Y_HI, (y >> 8));
1822
1823 return(0);
1824 }
1825
1826 static __inline short
1827 M2I(short val) {
1828 return ( ((val & 0xff00) >> 8) | ((val & 0xff) << 8));
1829 }
1830
1831 int
1832 cv_getspriteinfo(gp, info)
1833 struct grf_softc *gp;
1834 struct grf_spriteinfo *info;
1835 {
1836 volatile caddr_t ba, fb;
1837
1838 ba = gp->g_regkva;
1839 fb = gp->g_fbkva;
1840
1841 if (info->set & GRFSPRSET_ENABLE)
1842 info->enable = RCrt(ba, CRT_ID_HWGC_MODE) & 0x01;
1843
1844 if (info->set & GRFSPRSET_POS)
1845 cv_getspritepos (gp, &info->pos);
1846
1847 #if 0 /* XXX */
1848 if (info->set & GRFSPRSET_SHAPE) {
1849 u_char image[512], mask[512];
1850 volatile u_long *hwp;
1851 u_char *imp, *mp;
1852 short row;
1853 info->size.x = 64;
1854 info->size.y = 64;
1855 for (row = 0, hwp = (u_long *)(fb + HWC_OFF),
1856 mp = mask, imp = image;
1857 row < 64;
1858 row++) {
1859 u_long bp10, bp20, bp11, bp21;
1860 bp10 = *hwp++;
1861 bp20 = *hwp++;
1862 bp11 = *hwp++;
1863 bp21 = *hwp++;
1864 M2I (bp10);
1865 M2I (bp20);
1866 M2I (bp11);
1867 M2I (bp21);
1868 *imp++ = (~bp10) & bp11;
1869 *imp++ = (~bp20) & bp21;
1870 *mp++ = (~bp10) | (bp10 & ~bp11);
1871 *mp++ = (~bp20) & (bp20 & ~bp21);
1872 }
1873 copyout (image, info->image, sizeof (image));
1874 copyout (mask, info->mask, sizeof (mask));
1875 }
1876 #endif
1877 return(0);
1878 }
1879
1880
1881 void
1882 cv_setup_hwc(gp)
1883 struct grf_softc *gp;
1884 {
1885 volatile caddr_t ba = gp->g_regkva;
1886 volatile caddr_t hwc;
1887 int test;
1888
1889 if (gp->g_display.gd_planes <= 4)
1890 cv_cursor_on = 0; /* don't enable hwc in text modes */
1891 if (cv_cursor_on == 0)
1892 return;
1893
1894 /* reset colour stack */
1895 #if 0
1896 test = RCrt(ba, CRT_ID_HWGC_MODE);
1897 asm volatile("nop");
1898 #else
1899 /* do it in assembler, the above does't seem to work */
1900 asm volatile ("moveb #0x45, %1@(0x3d4); \
1901 moveb %1@(0x3d5),%0" : "=r" (test) : "a" (ba));
1902 #endif
1903
1904 WCrt (ba, CRT_ID_HWGC_FG_STACK, 0);
1905
1906 hwc = ba + CRT_ADDRESS_W;
1907 *hwc = 0;
1908 *hwc = 0;
1909
1910 #if 0
1911 test = RCrt(ba, CRT_ID_HWGC_MODE);
1912 asm volatile("nop");
1913 #else
1914 /* do it in assembler, the above does't seem to work */
1915 asm volatile ("moveb #0x45, %1@(0x3d4); \
1916 moveb %1@(0x3d5),%0" : "=r" (test) : "a" (ba));
1917 #endif
1918 switch (gp->g_display.gd_planes) {
1919 case 8:
1920 WCrt (ba, CRT_ID_HWGC_BG_STACK, 0x1);
1921 *hwc = 1;
1922 break;
1923 default:
1924 WCrt (ba, CRT_ID_HWGC_BG_STACK, 0xff);
1925 *hwc = 0xff;
1926 *hwc = 0xff;
1927 }
1928
1929 test = HWC_OFF / HWC_SIZE;
1930 WCrt (ba, CRT_ID_HWGC_START_AD_HI, (test >> 8));
1931 WCrt (ba, CRT_ID_HWGC_START_AD_LO, (test & 0xff));
1932
1933 WCrt (ba, CRT_ID_HWGC_DSTART_X , 0);
1934 WCrt (ba, CRT_ID_HWGC_DSTART_Y , 0);
1935
1936 WCrt (ba, CRT_ID_EXT_DAC_CNTL, 0x10); /* Cursor X11 Mode */
1937 /*
1938 * Put it into Windoze Mode or you'll see sometimes a white stripe
1939 * on the right side (in double clocking modes with a screen bigger
1940 * > 1023 pixels).
1941 */
1942 WCrt (ba, CRT_ID_EXT_DAC_CNTL, 0x00); /* Cursor Windoze Mode */
1943
1944 WCrt (ba, CRT_ID_HWGC_MODE, 0x01);
1945 }
1946
1947
1948 /*
1949 * This was the reason why you shouldn't use the HWC in the Kernel:(
1950 * Obsoleted now by use of interrupts :-)
1951 */
1952
1953 #define VerticalRetraceWait(ba) \
1954 { \
1955 while (vgar(ba, GREG_INPUT_STATUS1_R) == 0x00) ; \
1956 while ((vgar(ba, GREG_INPUT_STATUS1_R) & 0x08) == 0x08) ; \
1957 while ((vgar(ba, GREG_INPUT_STATUS1_R) & 0x08) == 0x00) ; \
1958 }
1959
1960
1961 int
1962 cv_setspriteinfo (gp, info)
1963 struct grf_softc *gp;
1964 struct grf_spriteinfo *info;
1965 {
1966 volatile caddr_t ba, fb;
1967 int depth = gp->g_display.gd_planes;
1968
1969 ba = gp->g_regkva;
1970 fb = gp->g_fbkva;
1971
1972 if (info->set & GRFSPRSET_SHAPE) {
1973 /*
1974 * For an explanation of these weird actions here, see above
1975 * when reading the shape. We set the shape directly into
1976 * the video memory, there's no reason to keep 1k on the
1977 * kernel stack just as template
1978 */
1979 u_char *image, *mask;
1980 volatile u_short *hwp;
1981 u_char *imp, *mp;
1982 unsigned short row;
1983
1984 #ifdef CV_NO_INT
1985 /* Cursor off */
1986 WCrt (ba, CRT_ID_HWGC_MODE, 0x00);
1987
1988 /*
1989 * The Trio64 crashes if the cursor data is written
1990 * while the cursor is displayed.
1991 * Sadly, turning the cursor off is not enough.
1992 * What we have to do is:
1993 * 1. Wait for vertical retrace, to make sure no-one
1994 * has moved the cursor in this sync period (because
1995 * another write then would have no effect, argh!).
1996 * 2. Move the cursor off-screen
1997 * 3. Another wait for v. retrace to make sure the cursor
1998 * is really off.
1999 * 4. Write the data, finally.
2000 * (thanks to Harald Koenig for this tip!)
2001 */
2002
2003 /*
2004 * Remark 06/06/96: Update in interrupt obsoletes this,
2005 * but the warning should stay there!
2006 */
2007
2008 VerticalRetraceWait(ba);
2009
2010 WCrt (ba, CRT_ID_HWGC_ORIGIN_X_HI, 0x7);
2011 WCrt (ba, CRT_ID_HWGC_ORIGIN_X_LO, 0xff);
2012 WCrt (ba, CRT_ID_HWGC_ORIGIN_Y_LO, 0xff);
2013 WCrt (ba, CRT_ID_HWGC_DSTART_X, 0x3f);
2014 WCrt (ba, CRT_ID_HWGC_DSTART_Y, 0x3f);
2015 WCrt (ba, CRT_ID_HWGC_ORIGIN_Y_HI, 0x7);
2016 #endif /* CV_NO_INT */
2017
2018 if (info->size.y > 64)
2019 info->size.y = 64;
2020 if (info->size.x > 64)
2021 info->size.x = 64;
2022 if (info->size.x < 32)
2023 info->size.x = 32;
2024
2025 image = malloc(HWC_SIZE, M_TEMP, M_WAITOK);
2026 mask = image + HWC_SIZE/2;
2027
2028 copyin(info->image, image, info->size.y * info->size.x / 8);
2029 copyin(info->mask, mask, info->size.y * info->size.x / 8);
2030
2031 #ifdef CV_NO_INT
2032 hwp = (u_short *)(fb +HWC_OFF);
2033
2034 /* This is necessary in order not to crash the board */
2035 VerticalRetraceWait(ba);
2036 #else /* CV_NO_INT */
2037 hwp = (u_short *) cv_cursor_storage;
2038 #endif /* CV_NO_INT */
2039
2040 /*
2041 * setting it is slightly more difficult, because we can't
2042 * force the application to not pass a *smaller* than
2043 * supported bitmap
2044 */
2045
2046 for (row = 0, mp = mask, imp = image;
2047 row < info->size.y; row++) {
2048 u_short im1, im2, im3, im4, m1, m2, m3, m4;
2049
2050 m1 = ~(*(unsigned short *)mp);
2051 im1 = *(unsigned short *)imp & *(unsigned short *)mp;
2052 mp += 2;
2053 imp += 2;
2054
2055 m2 = ~(*(unsigned short *)mp);
2056 im2 = *(unsigned short *)imp & *(unsigned short *)mp;
2057 mp += 2;
2058 imp += 2;
2059
2060 if (info->size.x > 32) {
2061 m3 = ~(*(unsigned short *)mp);
2062 im3 = *(unsigned short *)imp & *(unsigned short *)mp;
2063 mp += 2;
2064 imp += 2;
2065 m4 = ~(*(unsigned short *)mp);
2066 im4 = *(unsigned short *)imp & *(unsigned short *)mp;
2067 mp += 2;
2068 imp += 2;
2069 } else {
2070 m3 = 0xffff;
2071 im3 = 0;
2072 m4 = 0xffff;
2073 im4 = 0;
2074 }
2075
2076 switch (depth) {
2077 case 8:
2078 *hwp++ = m1;
2079 *hwp++ = im1;
2080 *hwp++ = m2;
2081 *hwp++ = im2;
2082 *hwp++ = m3;
2083 *hwp++ = im3;
2084 *hwp++ = m4;
2085 *hwp++ = im4;
2086 break;
2087 case 15:
2088 case 16:
2089 *hwp++ = M2I(m1);
2090 *hwp++ = M2I(im1);
2091 *hwp++ = M2I(m2);
2092 *hwp++ = M2I(im2);
2093 *hwp++ = M2I(m3);
2094 *hwp++ = M2I(im3);
2095 *hwp++ = M2I(m4);
2096 *hwp++ = M2I(im4);
2097 break;
2098 case 24:
2099 case 32:
2100 *hwp++ = M2I(im1);
2101 *hwp++ = M2I(m1);
2102 *hwp++ = M2I(im2);
2103 *hwp++ = M2I(m2);
2104 *hwp++ = M2I(im3);
2105 *hwp++ = M2I(m3);
2106 *hwp++ = M2I(im4);
2107 *hwp++ = M2I(m4);
2108 break;
2109 }
2110 }
2111
2112 if (depth < 24) {
2113 for (; row < 64; row++) {
2114 *hwp++ = 0xffff;
2115 *hwp++ = 0x0000;
2116 *hwp++ = 0xffff;
2117 *hwp++ = 0x0000;
2118 *hwp++ = 0xffff;
2119 *hwp++ = 0x0000;
2120 *hwp++ = 0xffff;
2121 *hwp++ = 0x0000;
2122 }
2123 } else {
2124 for (; row < 64; row++) {
2125 *hwp++ = 0x0000;
2126 *hwp++ = 0xffff;
2127 *hwp++ = 0x0000;
2128 *hwp++ = 0xffff;
2129 *hwp++ = 0x0000;
2130 *hwp++ = 0xffff;
2131 *hwp++ = 0x0000;
2132 *hwp++ = 0xffff;
2133 }
2134 }
2135
2136 free(image, M_TEMP);
2137 /* cv_setup_hwc(gp); */
2138 cv_hotx = info->hot.x;
2139 cv_hoty = info->hot.y;
2140
2141 #ifdef CV_NO_INT
2142 /* One must not write twice per vertical blank :-( */
2143 VerticalRetraceWait(ba);
2144 cv_setspritepos (gp, &info->pos);
2145 #else /* CV_NO_INT */
2146 cv_setspritepos (gp, &info->pos);
2147 curs_update_flag = 1;
2148 #endif /* CV_NO_INT */
2149 }
2150 if (info->set & GRFSPRSET_CMAP) {
2151 volatile caddr_t hwc;
2152 int test;
2153
2154 /* reset colour stack */
2155 test = RCrt(ba, CRT_ID_HWGC_MODE);
2156 asm volatile("nop");
2157 switch (depth) {
2158 case 8:
2159 case 15:
2160 case 16:
2161 WCrt (ba, CRT_ID_HWGC_FG_STACK, 0);
2162 hwc = ba + CRT_ADDRESS_W;
2163 *hwc = 0;
2164 break;
2165 case 32:
2166 case 24:
2167 WCrt (ba, CRT_ID_HWGC_FG_STACK, 0);
2168 hwc = ba + CRT_ADDRESS_W;
2169 *hwc = 0;
2170 *hwc = 0;
2171 break;
2172 }
2173
2174 test = RCrt(ba, CRT_ID_HWGC_MODE);
2175 asm volatile("nop");
2176 switch (depth) {
2177 case 8:
2178 WCrt (ba, CRT_ID_HWGC_BG_STACK, 1);
2179 hwc = ba + CRT_ADDRESS_W;
2180 *hwc = 1;
2181 break;
2182 case 15:
2183 case 16:
2184 WCrt (ba, CRT_ID_HWGC_BG_STACK, 0xff);
2185 hwc = ba + CRT_ADDRESS_W;
2186 *hwc = 0xff;
2187 break;
2188 case 32:
2189 case 24:
2190 WCrt (ba, CRT_ID_HWGC_BG_STACK, 0xff);
2191 hwc = ba + CRT_ADDRESS_W;
2192 *hwc = 0xff;
2193 *hwc = 0xff;
2194 break;
2195 }
2196 }
2197
2198 if (info->set & GRFSPRSET_ENABLE) {
2199 if (info->enable) {
2200 cv_cursor_on = 1;
2201 cv_setup_hwc(gp);
2202 /* WCrt(ba, CRT_ID_HWGC_MODE, 0x01); */
2203 } else
2204 WCrt(ba, CRT_ID_HWGC_MODE, 0x00);
2205 }
2206 if (info->set & GRFSPRSET_POS)
2207 cv_setspritepos(gp, &info->pos);
2208 if (info->set & GRFSPRSET_HOT) {
2209
2210 cv_hotx = info->hot.x;
2211 cv_hoty = info->hot.y;
2212 cv_setspritepos (gp, &info->pos);
2213 }
2214 return(0);
2215 }
2216
2217
2218 int
2219 cv_getspritemax (gp, pos)
2220 struct grf_softc *gp;
2221 struct grf_position *pos;
2222 {
2223
2224 pos->x = 64;
2225 pos->y = 64;
2226 return(0);
2227 }
2228
2229 #endif /* !CV_NO_HARDWARE_CURSOR */
2230
2231 #endif /* NGRFCV */
2232