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