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