Expand PMF_FN_* macros.
[netbsd-mini2440.git] / sys / arch / amiga / dev / grf_cv.c
blob89624ecfcf69a20009ed731d4204444cf487170b
1 /* $NetBSD: grf_cv.c,v 1.47 2009/03/18 17:06:42 cegger Exp $ */
3 /*
4 * Copyright (c) 1995 Michael Teske
5 * All rights reserved.
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
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.
33 #include "opt_amigacons.h"
35 #include <sys/cdefs.h>
36 __KERNEL_RCSID(0, "$NetBSD: grf_cv.c,v 1.47 2009/03/18 17:06:42 cegger Exp $");
38 #include "grfcv.h"
39 #if NGRFCV > 0
42 * Graphics routines for the CyberVision 64 board, using the S3 Trio64.
44 * Modified for CV64 from
45 * Kari Mettinen's Cirrus driver by Michael Teske 10/95
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.
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>
72 * finish all bus operations, flush pipelines
73 * XXX is this really needed?
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
81 int grfcvmatch(struct device *, struct cfdata *, void *);
82 void grfcvattach(struct device *, struct device *, void *);
83 int grfcvprint(void *, const char *);
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 *);
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 */
115 * Extension to grf_softc for interrupt support
118 struct grf_cv_softc {
119 struct grf_softc gcs_sc;
120 struct isr gcs_isr;
123 /* Graphics display definitions.
124 * These are filled by 'grfconfig' using GRFIOCSETMON.
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}
132 static struct grfvideo_mode *monitor_current = &monitor_def[0];
133 #define MAXPIXELCLOCK 135000000 /* safety */
135 unsigned char cv_pass_toggle; /* passthru status tracker */
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.
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[];
154 * Define default console mode
155 * (Internally, we still have to use hvalues/8!)
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
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}
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,
250 /* Board Address of CV64 */
251 static volatile void *cv_boardaddr;
252 static int cv_fbsize;
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 :-).
263 #ifdef CV_AGGRESSIVE_TIMING
264 long cv_memclk = 55000000;
265 #else
266 long cv_memclk = 50000000;
267 #endif
269 /* standard driver stuff */
270 CFATTACH_DECL(grfcv, sizeof(struct grf_cv_softc),
271 grfcvmatch, grfcvattach, NULL, NULL);
273 static struct cfdata *cfdata;
275 #define CV_INT_NUM 6 /* CV interrupt Level: #2 or #6 */
276 #define CV_ULCURSOR 1 /* Underlined Cursor in textmode */
278 #ifndef CV_NO_HARDWARE_CURSOR
280 #define HWC_OFF (cv_fbsize - 1024*2)
281 #define HWC_SIZE 1024
283 static unsigned short cv_cursor_storage[HWC_SIZE/2];
284 static short curs_update_flag = 0;
286 #endif /* !CV_NO_HARDWARE_CURSOR */
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
297 cvintr(void *arg)
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 */
308 if (gp == NULL)
309 return 0;
311 test = vgar(ba, GREG_INPUT_STATUS0_R);
313 if (test & 0x80) { /* VR int pending */
314 /* Save old CR index */
315 cridx = vgar (ba, CRT_ADDRESS);
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
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;
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);
347 /* Restore the old CR index */
348 vgaw(ba, CRT_ADDRESS, cridx);
349 cpu_sync();
350 #endif /* !CV_NO_HARDWARE_CURSOR */
351 return (1);
353 return (0);
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
362 static int
363 cv_has_4mb(volatile void *fb)
365 volatile unsigned long *testfbw, *testfbr;
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);
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);
394 grfcvmatch(struct device *pdp, struct cfdata *cfp, void *auxp)
396 #ifdef CV64CONSOLE
397 static int cvcons_unit = -1;
398 #endif
399 struct zbus_args *zap;
401 zap = auxp;
403 if (amiga_realconfig == 0)
404 #ifdef CV64CONSOLE
405 if (cvcons_unit != -1)
406 #endif
407 return (0);
409 /* Lets be Paranoid: Test man and prod id */
410 if (zap->manid != 8512 || zap->prodid != 34)
411 return (0);
413 cv_boardaddr = zap->va;
415 #ifdef CV64CONSOLE
416 if (amiga_realconfig == 0) {
417 cvcons_unit = cfp->cf_unit;
418 cfdata = cfp;
420 #endif
422 return (1);
425 void
426 grfcvattach(struct device *pdp, struct device *dp, void *auxp)
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;
434 zap = auxp;
437 * This function is called twice, once on console init (dp == NULL)
438 * and once on "normal" grf5 init.
441 if (dp == NULL) /* console init */
442 gcp = &congrf;
443 else
444 gcp = (struct grf_cv_softc *)dp;
446 gp = &gcp->gcs_sc;
448 if (dp != NULL && congrf.gcs_sc.g_regkva != 0) {
450 * inited earlier, just copy (not device struct)
453 printf("\n");
454 memcpy(&gp->g_display, &congrf.gcs_sc.g_display,
455 (char *) &gcp->gcs_isr - (char *) &gp->g_display);
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;
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;
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;
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);
480 /* wakeup the board */
481 cv_boardinit(gp);
483 #ifdef CV64CONSOLE
484 grfcv_iteinit(gp);
485 (void)cv_load_mon(gp, &cvconsole_mode);
486 #endif
490 * attach grf
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")*/;
504 grfcvprint(void *auxp, const char *pnp)
506 if (pnp)
507 aprint_normal("ite at %s: ", pnp);
508 return (UNCONF);
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.
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
523 static unsigned short
524 cv_compute_clock(unsigned long freq)
526 static unsigned char *mnr, *save; /* M, N + R vals */
527 unsigned long work_freq, r;
528 unsigned short erg;
529 long diff, d2;
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;
538 mnr = clocks; /* there the vals are stored */
539 d2 = 0x7fffffff;
541 while (*mnr) { /* mnr vals are 0-terminated */
542 work_freq = (0x37EE * (mnr[0] + 2)) / ((mnr[1] & 0x1F) + 2);
544 r = (mnr[1] >> 5) & 0x03;
545 if (r != 0)
546 work_freq=work_freq >> r; /* r is the freq divider */
548 work_freq *= 0x3E8; /* 2nd part of OSC */
550 diff = abs(freq - work_freq);
552 if (d2 >= diff) {
553 d2 = diff;
554 /* In save are the vals for minimal diff */
555 save = mnr;
557 mnr += 2;
559 erg = *((unsigned short *)save);
561 return (erg);
565 void
566 cv_boardinit(struct grf_softc *gp)
568 volatile void *ba;
569 unsigned char test;
570 unsigned int clockpar;
571 int i;
572 struct grfinfo *gi;
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);
580 /* Return to operational Mode */
581 cv_write_port(0x8004, (volatile char*)ba - 0x02000000);
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);
588 vgaw(ba, GREG_MISC_OUTPUT_W, 0x03);
590 WCrt(ba, CRT_ID_REGISTER_LOCK_1, 0x48); /* unlock S3 VGA regs */
591 WCrt(ba, CRT_ID_REGISTER_LOCK_2, 0xA5); /* unlock syscontrol */
594 * The default board interrupt is #6.
595 * Set the roxxler register to use interrupt #2, not #6.
597 #if CV_INT_NUM == 2
598 cv_write_port(0x8080, ba - 0x02000000);
599 #endif
601 /* Enable board interrupts */
602 cv_write_port(0x8008, (volatile char*)ba - 0x02000000);
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);
610 * bit 1=1: enable enhanced mode functions
611 * bit 4=1: enable linear addressing
612 * bit 5=1: enable MMIO
614 vgaw(ba, ECR_ADV_FUNC_CNTL, 0x31);
616 /* enable color mode (bit0), CPU access (bit1), high 64k page (bit5) */
617 vgaw(ba, GREG_MISC_OUTPUT_W, 0xe3);
619 /* CPU base addr */
620 WCrt(ba, CRT_ID_EXT_SYS_CNTL_4, 0x00);
622 /* Reset. This does nothing, but everyone does it:) */
623 WSeq(ba, SEQ_ID_RESET, 0x03);
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 */
629 WSeq(ba, SEQ_ID_MEMORY_MODE, 0x02); /* Complete mem access */
631 WSeq(ba, SEQ_ID_UNLOCK_EXT, 0x06); /* Unlock extensions */
632 test = RSeq(ba, SEQ_ID_BUS_REQ_CNTL); /* Bus Request */
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);
640 test = RSeq(ba, SEQ_ID_CLKSYN_CNTL_2); /* Clksyn2 read */
642 /* immediately Clkload bit clear */
643 test = test & 0xDF;
645 /* 2 MCLK Memory Write.... */
646 if (cv_memclk >= 55000000)
647 test |= 0x80;
649 WSeq(ba, SEQ_ID_CLKSYN_CNTL_2, test);
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 */
656 test = clockpar & 0xFF;
657 WSeq(ba, SEQ_ID_MCLK_LO, test); /* PLL M-Divider Value */
659 if (RCrt(ba, CRT_ID_REVISION) == 0x10) /* bugfix for new S3 chips */
660 WSeq(ba, SEQ_ID_MORE_MAGIC, test);
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);
667 test = RSeq (ba, SEQ_ID_CLKSYN_CNTL_2);
668 test = test | 0x22;
670 /* DCLK + MCLK Clock immediate load! */
671 WSeq(ba,SEQ_ID_CLKSYN_CNTL_2, test);
673 /* DCLK load */
674 test = vgar(ba, 0x3cc);
675 test = test | 0x0c;
676 vgaw(ba, 0x3c2, test);
678 /* Clear bit 5 again, prevent further loading. */
679 WSeq(ba, SEQ_ID_CLKSYN_CNTL_2, 0x02);
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);
689 WCrt(ba, CRT_ID_OVERFLOW, 0x1F); /* overflow reg */
691 WCrt(ba, CRT_ID_PRESET_ROW_SCAN, 0x00); /* no panning */
693 WCrt(ba, CRT_ID_MAX_SCAN_LINE, 0x40); /* vscan */
695 WCrt(ba, CRT_ID_CURSOR_START, 0x00);
696 WCrt(ba, CRT_ID_CURSOR_END, 0x00);
698 /* Display start address */
699 WCrt(ba, CRT_ID_START_ADDR_HIGH, 0x00);
700 WCrt(ba, CRT_ID_START_ADDR_LOW, 0x00);
702 /* Cursor location */
703 WCrt(ba, CRT_ID_CURSOR_LOC_HIGH, 0x00);
704 WCrt(ba, CRT_ID_CURSOR_LOC_LOW, 0x00);
706 /* Vertical retrace */
707 WCrt(ba, CRT_ID_START_VER_RETR, 0x9C);
708 WCrt(ba, CRT_ID_END_VER_RETR, 0x0E);
710 WCrt(ba, CRT_ID_VER_DISP_ENA_END, 0x8F);
711 WCrt(ba, CRT_ID_SCREEN_OFFSET, 0x50);
713 WCrt(ba, CRT_ID_UNDERLINE_LOC, 0x00);
715 WCrt(ba, CRT_ID_START_VER_BLANK, 0x96);
716 WCrt(ba, CRT_ID_END_VER_BLANK, 0xB9);
718 WCrt(ba, CRT_ID_MODE_CONTROL, 0xE3);
720 WCrt(ba, CRT_ID_LINE_COMPARE, 0xFF);
722 WCrt(ba, CRT_ID_BACKWAD_COMP_3, 0x10); /* FIFO enabled */
724 /* Refresh count 1, High speed text font, enhanced color mode */
725 WCrt(ba, CRT_ID_MISC_1, 0x35);
727 /* start fifo position */
728 WCrt(ba, CRT_ID_DISPLAY_FIFO, 0x5a);
730 WCrt(ba, CRT_ID_EXT_MEM_CNTL_2, 0x70);
732 /* address window position */
733 WCrt(ba, CRT_ID_LAW_POS_LO, 0x40);
735 /* N Parameter for Display FIFO */
736 WCrt(ba, CRT_ID_EXT_MEM_CNTL_3, 0xFF);
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);
748 /* colors for text mode */
749 for (i = 0; i <= 0xf; i++)
750 WAttr (ba, i, i);
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);
758 vgaw(ba, VDAC_MASK, 0xFF); /* DAC Mask */
760 *((volatile unsigned long *)((volatile char*)ba + ECR_FRGD_COLOR)) = 0xFF;
761 *((volatile unsigned long *)((volatile char*)ba + ECR_BKGD_COLOR)) = 0;
763 /* colors initially set to greyscale */
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);
772 /* GFx hardware cursor off */
773 WCrt(ba, CRT_ID_HWGC_MODE, 0x00);
775 /* Set first to 4 MB, so test will work */
776 WCrt(ba, CRT_ID_LAW_CNTL, 0x13);
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 */
787 /* Initialize graphics engine */
788 GfxBusyWait(ba);
789 vgaw16(ba, ECR_FRGD_MIX, 0x27);
790 vgaw16(ba, ECR_BKGD_MIX, 0x07);
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);
802 vgaw16(ba, ECR_BITPLANE_WRITE_MASK, ~0);
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);
817 /* It ain't easy to write here, so let's do it again */
818 vgaw16(ba, ECR_READ_REG_DATA, 0x4fff);
820 vgaw16(ba, ECR_BKGD_COLOR, 0x01);
821 vgaw16(ba, ECR_FRGD_COLOR, 0x00);
823 /* Enable Video Display (Set Bit 5) */
824 WAttr(ba, 0x33, 0);
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;
835 cv_getvmode(struct grf_softc *gp, struct grfvideo_mode *vm)
837 struct grfvideo_mode *gv;
839 #ifdef CV64CONSOLE
840 /* Handle grabbing console mode */
841 if (vm->mode_num == 255) {
842 memcpy(vm, &cvconsole_mode, 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
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);
856 memcpy(vm, gv, sizeof(struct grfvideo_mode));
859 /* adjust internal values to pixel values */
861 vm->hblank_start *= 8;
862 vm->hsync_start *= 8;
863 vm->hsync_stop *= 8;
864 vm->htotal *= 8;
866 return (0);
871 cv_setvmode(struct grf_softc *gp, unsigned mode)
874 if (!mode || (mode > monitor_def_max) ||
875 monitor_def[mode - 1].mode_num == 0)
876 return (EINVAL);
878 monitor_current = monitor_def + (mode - 1);
880 return (0);
885 cv_blank(struct grf_softc *gp, int *on)
887 volatile void *ba;
889 ba = gp->g_regkva;
890 gfx_on_off(*on > 0 ? 0 : 1, ba);
891 return (0);
896 * Change the mode of the display.
897 * Return a UNIX error number or 0 for success.
900 cv_mode(register struct grf_softc *gp, u_long cmd, void *arg, u_long a2,
901 int a3)
903 int error;
905 switch (cmd) {
906 case GM_GRFON:
907 error = cv_load_mon (gp,
908 (struct grfcvtext_mode *) monitor_current) ? 0 : EINVAL;
909 return (error);
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);
920 case GM_GRFCONFIG:
921 return (0);
923 case GM_GRFGETVMODE:
924 return (cv_getvmode (gp, (struct grfvideo_mode *) arg));
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);
933 case GM_GRFGETNUMVM:
934 *(int *)arg = monitor_def_max;
935 return (0);
937 case GM_GRFIOCTL:
938 return (cv_ioctl (gp, a2, arg));
940 default:
941 break;
944 return (EPASSTHROUGH);
949 cv_ioctl(register struct grf_softc *gp, u_long cmd, void *data)
951 switch (cmd) {
952 #ifndef CV_NO_HARDWARE_CURSOR
953 case GRFIOCGSPRITEPOS:
954 return(cv_getspritepos (gp, (struct grf_position *) data));
956 case GRFIOCSSPRITEPOS:
957 return(cv_setspritepos (gp, (struct grf_position *) data));
959 case GRFIOCSSPRITEINF:
960 return(cv_setspriteinfo (gp, (struct grf_spriteinfo *) data));
962 case GRFIOCGSPRITEINF:
963 return(cv_getspriteinfo (gp, (struct grf_spriteinfo *) data));
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 */
976 case GRFIOCGETCMAP:
977 return (cv_getcmap (gp, (struct grf_colormap *) data));
979 case GRFIOCPUTCMAP:
980 return (cv_putcmap (gp, (struct grf_colormap *) data));
982 case GRFIOCBITBLT:
983 break;
985 case GRFTOGGLE:
986 return (cv_toggle (gp));
988 case GRFIOCSETMON:
989 return (cv_setmonitor (gp, (struct grfvideo_mode *)data));
991 case GRFIOCBLANK:
992 return (cv_blank (gp, (int *)data));
994 return (EPASSTHROUGH);
999 cv_setmonitor(struct grf_softc *gp, struct grfvideo_mode *gv)
1001 struct grfvideo_mode *md;
1003 if (!cv_mondefok(gv))
1004 return (EINVAL);
1006 #ifdef CV64CONSOLE
1007 /* handle interactive setting of console mode */
1008 if (gv->mode_num == 255) {
1009 memcpy(&cvconsole_mode.gv, 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);
1021 #endif
1023 md = monitor_def + (gv->mode_num - 1);
1026 * Prevent user from crashing the system by using
1027 * grfconfig while in X
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);
1035 memcpy(md, gv, sizeof(struct grfvideo_mode));
1037 /* adjust pixel oriented values to internal rep. */
1039 md->hblank_start /= 8;
1040 md->hsync_start /= 8;
1041 md->hsync_stop /= 8;
1042 md->htotal /= 8;
1044 return (0);
1049 cv_getcmap(struct grf_softc *gfp, struct grf_colormap *cmap)
1051 volatile void *ba;
1052 u_char red[256], green[256], blue[256], *rp, *gp, *bp;
1053 short x;
1054 int error;
1056 ba = gfp->g_regkva;
1057 if (cmap->count == 0 || cmap->index >= 256)
1058 return (0);
1060 if (cmap->count > 256 - cmap->index)
1061 cmap->count = 256 - cmap->index;
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;
1067 rp = red + cmap->index;
1068 gp = green + cmap->index;
1069 bp = blue + cmap->index;
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);
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);
1082 return (error);
1087 cv_putcmap(struct grf_softc *gfp, struct grf_colormap *cmap)
1089 volatile void *ba;
1090 u_char red[256], green[256], blue[256], *rp, *gp, *bp;
1091 short x;
1092 int error;
1094 ba = gfp->g_regkva;
1095 if (cmap->count == 0 || cmap->index >= 256)
1096 return (0);
1098 if (cmap->count > 256 - cmap->index)
1099 cmap->count = 256 - cmap->index;
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;
1108 rp = red + cmap->index;
1109 gp = green + cmap->index;
1110 bp = blue + cmap->index;
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);
1124 cv_toggle(struct grf_softc *gp)
1126 volatile void *ba;
1128 ba = gp->g_regkva;
1129 #ifndef CV64CONSOLE
1130 cv_pass_toggle = 1;
1131 #endif /* !CV64CONSOLE */
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;
1141 return (0);
1146 cv_mondefok(struct grfvideo_mode *gv)
1148 unsigned long maxpix;
1150 if (gv->mode_num < 1 || gv->mode_num > monitor_def_max) {
1151 if (gv->mode_num != 255 || gv->depth != 4)
1152 return (0);
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);
1184 if (gv->pixel_clock > maxpix) {
1185 printf("grfcv: Pixelclock too high in mode %d\n",
1186 (int) gv->mode_num);
1187 return (0);
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);
1200 if (gv->disp_flags & GRF_FLAGS_SYNC_ON_GREEN) {
1201 printf("grfcv: sync-on-green is not supported\n");
1202 return (0);
1205 return (1);
1210 cv_load_mon(struct grf_softc *gp, struct grfcvtext_mode *md)
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;
1225 /* identity */
1226 gv = &md->gv;
1228 TEXT = (gv->depth == 4);
1229 CONSOLE = (gv->mode_num == 255);
1231 if (!cv_mondefok(gv)) {
1232 printf("grfcv: Monitor definition not ok\n");
1233 return (0);
1236 ba = gp->g_regkva;
1237 fb = gp->g_fbkva;
1239 /* Disable Interrupts */
1240 test = RCrt(ba, CRT_ID_BACKWAD_COMP_1);
1241 test &= ~0x10;
1242 WCrt(ba, CRT_ID_BACKWAD_COMP_1, test);
1244 /* turn gfx off, don't mess up the display */
1245 gfx_on_off(1, ba);
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;
1263 gi->gd_dx = 0;
1264 gi->gd_dy = 0;
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;
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;
1288 /* Disable enhanced Mode for text display */
1290 vgaw(ba, ECR_ADV_FUNC_CNTL, (TEXT ? 0x00 : 0x31));
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;
1298 /* adjustments */
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;
1309 /* Horizontal/Vertical Sync Pulse */
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
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);
1330 /* GFX hardware cursor off */
1331 WCrt(ba, CRT_ID_HWGC_MODE, 0x00);
1332 WCrt(ba, CRT_ID_EXT_DAC_CNTL, 0x00);
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);
1339 /* Set clock */
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));
1345 /* load display parameters into board */
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) );
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) );
1363 WCrt(ba, CRT_ID_HOR_TOTAL, HT);
1364 WCrt(ba, CRT_ID_DISPLAY_FIFO, HT - 5);
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) );
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));
1390 WCrt(ba, CRT_ID_MODE_CONTROL, 0xe3);
1392 /* text cursor */
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);
1404 WCrt(ba, CRT_ID_CURSOR_LOC_HIGH, 0x00);
1405 WCrt(ba, CRT_ID_CURSOR_LOC_LOW, 0x00);
1408 WCrt(ba, CRT_ID_START_ADDR_HIGH, 0x00);
1409 WCrt(ba, CRT_ID_START_ADDR_LOW, 0x00);
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);
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));
1422 WGfx(ba, GCT_ID_GRAPHICS_MODE,
1423 ((TEXT || (gv->depth == 1)) ? 0x00 : 0x40));
1424 WGfx(ba, GCT_ID_MISC, (TEXT ? 0x04 : 0x01));
1426 WSeq (ba, SEQ_ID_MEMORY_MODE,
1427 ((TEXT || (gv->depth == 1)) ? 0x06 : 0x02));
1429 vgaw(ba, VDAC_MASK, 0xff);
1431 /* Blank border */
1432 test = RCrt(ba, CRT_ID_BACKWAD_COMP_2);
1433 WCrt(ba, CRT_ID_BACKWAD_COMP_2, (test | 0x20));
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;
1442 test = RCrt(ba, CRT_ID_EXT_MISC_CNTL_2);
1443 test &= 0xd;
1445 /* clear roxxler byte-swapping... */
1446 cv_write_port(0x0040, cv_boardaddr);
1447 cv_write_port(0x0020, cv_boardaddr);
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;
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;
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);
1489 WCrt(ba, CRT_ID_MISC_1, (TEXT ? 0x05 : 0x35));
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);
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;
1521 WCrt(ba, CRT_ID_EXT_SYS_CNTL_1, cr50);
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);
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.
1542 tfillm = (96 * (cv_memclk/1000))/240000;
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;
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;
1569 WCrt(ba, CRT_ID_EXT_MEM_CNTL_2, m);
1570 WCrt(ba, CRT_ID_EXT_MEM_CNTL_3, n);
1571 delay(10000);
1573 /* text initialization */
1575 if (TEXT) {
1576 cv_inittextmode(gp);
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]);
1589 /* Set display enable flag */
1590 WAttr(ba, 0x33, 0);
1592 /* turn gfx on again */
1593 gfx_on_off(0, ba);
1595 /* enable interrupts */
1596 test = RCrt(ba, CRT_ID_BACKWAD_COMP_1);
1597 test |= 0x10;
1598 WCrt(ba, CRT_ID_BACKWAD_COMP_1, test);
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
1611 /* Pass-through */
1612 cvscreen(0, (volatile char*)ba - 0x02000000);
1614 return (1);
1618 void
1619 cv_inittextmode(struct grf_softc *gp)
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;
1627 ba = gp->g_regkva;
1628 fb = gp->g_fbkva;
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.
1639 c = (volatile unsigned char *) fb;
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;
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;
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;
1673 static inline void
1674 cv_write_port(unsigned short bits, volatile void *BoardAddr)
1676 volatile char *addr;
1677 static unsigned char CVPortBits = 0; /* mirror port bits here */
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 */
1688 *addr = CVPortBits;
1693 * Monitor Switch
1694 * 0 = CyberVision Signal
1695 * 1 = Amiga Signal,
1696 * ba = boardaddr
1698 static inline void
1699 cvscreen(int toggle, volatile void *ba)
1702 if (toggle == 1)
1703 cv_write_port (0x10, ba);
1704 else
1705 cv_write_port (0x8010, ba);
1709 /* 0 = on, 1= off */
1710 /* ba= registerbase */
1711 static inline void
1712 gfx_on_off(int toggle, volatile void *ba)
1714 int r;
1716 toggle &= 0x1;
1717 toggle = toggle << 5;
1719 r = RSeq(ba, SEQ_ID_CLOCKING_MODE);
1720 r &= ~0x20; /* set Bit 5 to 0 */
1722 WSeq(ba, SEQ_ID_CLOCKING_MODE, r | toggle);
1726 #ifndef CV_NO_HARDWARE_CURSOR
1728 static unsigned char cv_hotx = 0, cv_hoty = 0;
1729 static char cv_cursor_on = 0;
1731 /* Hardware Cursor handling routines */
1734 cv_getspritepos(struct grf_softc *gp, struct grf_position *pos)
1736 int hi,lo;
1737 volatile void *ba = gp->g_regkva;
1739 hi = RCrt(ba, CRT_ID_HWGC_ORIGIN_Y_HI);
1740 lo = RCrt(ba, CRT_ID_HWGC_ORIGIN_Y_LO);
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);
1751 cv_setspritepos(struct grf_softc *gp, struct grf_position *pos)
1753 volatile void *ba = gp->g_regkva;
1754 short x, y;
1755 static short savex, savey;
1756 short xoff, yoff;
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;
1767 x -= cv_hotx;
1768 y -= cv_hoty;
1769 if (x < 0) {
1770 xoff = ((-x) & 0xFE);
1771 x = 0;
1772 } else {
1773 xoff = 0;
1776 if (y < 0) {
1777 yoff = ((-y) & 0xFE);
1778 y = 0;
1779 } else {
1780 yoff = 0;
1783 WCrt(ba, CRT_ID_HWGC_ORIGIN_X_HI, (x >> 8));
1784 WCrt(ba, CRT_ID_HWGC_ORIGIN_X_LO, (x & 0xff));
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));
1791 return(0);
1794 static inline short
1795 M2I(short val)
1797 return ( ((val & 0xff00) >> 8) | ((val & 0xff) << 8));
1801 cv_getspriteinfo(struct grf_softc *gp, struct grf_spriteinfo *info)
1803 volatile void *ba, *fb;
1805 ba = gp->g_regkva;
1806 fb = gp->g_fbkva;
1808 if (info->set & GRFSPRSET_ENABLE)
1809 info->enable = RCrt(ba, CRT_ID_HWGC_MODE) & 0x01;
1811 if (info->set & GRFSPRSET_POS)
1812 cv_getspritepos (gp, &info->pos);
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);
1840 copyout (image, info->image, sizeof (image));
1841 copyout (mask, info->mask, sizeof (mask));
1843 #endif
1844 return(0);
1848 void
1849 cv_setup_hwc(struct grf_softc *gp)
1851 volatile void *ba = gp->g_regkva;
1852 volatile char *hwc;
1853 int test;
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;
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
1870 WCrt (ba, CRT_ID_HWGC_FG_STACK, 0);
1872 hwc = (volatile char*)ba + CRT_ADDRESS_W;
1873 *hwc = 0;
1874 *hwc = 0;
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;
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));
1899 WCrt (ba, CRT_ID_HWGC_DSTART_X , 0);
1900 WCrt (ba, CRT_ID_HWGC_DSTART_Y , 0);
1902 WCrt (ba, CRT_ID_EXT_DAC_CNTL, 0x10); /* Cursor X11 Mode */
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).
1908 WCrt (ba, CRT_ID_EXT_DAC_CNTL, 0x00); /* Cursor Windoze Mode */
1910 WCrt (ba, CRT_ID_HWGC_MODE, 0x01);
1915 * This was the reason why you shouldn't use the HWC in the Kernel:(
1916 * Obsoleted now by use of interrupts :-)
1919 #define VerticalRetraceWait(ba) \
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) ; \
1928 cv_setspriteinfo(struct grf_softc *gp, struct grf_spriteinfo *info)
1930 volatile void *ba, *fb;
1931 int depth = gp->g_display.gd_planes;
1933 ba = gp->g_regkva;
1934 fb = gp->g_fbkva;
1936 if (info->set & GRFSPRSET_SHAPE) {
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
1943 u_char *image, *mask;
1944 volatile u_short *hwp;
1945 u_char *imp, *mp;
1946 unsigned short row;
1948 #ifdef CV_NO_INT
1949 /* Cursor off */
1950 WCrt (ba, CRT_ID_HWGC_MODE, 0x00);
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!)
1968 * Remark 06/06/96: Update in interrupt obsoletes this,
1969 * but the warning should stay there!
1972 VerticalRetraceWait(ba);
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 */
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;
1989 image = malloc(HWC_SIZE, M_TEMP, M_WAITOK);
1990 mask = image + HWC_SIZE/2;
1992 copyin(info->image, image, info->size.y * info->size.x / 8);
1993 copyin(info->mask, mask, info->size.y * info->size.x / 8);
1995 #ifdef CV_NO_INT
1996 hwp = (u_short *)(fb +HWC_OFF);
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 */
2005 * setting it is slightly more difficult, because we can't
2006 * force the application to not pass a *smaller* than
2007 * supported bitmap
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;
2014 m1 = ~(*(unsigned short *)mp);
2015 im1 = *(unsigned short *)imp & *(unsigned short *)mp;
2016 mp += 2;
2017 imp += 2;
2019 m2 = ~(*(unsigned short *)mp);
2020 im2 = *(unsigned short *)imp & *(unsigned short *)mp;
2021 mp += 2;
2022 imp += 2;
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;
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;
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;
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;
2100 free(image, M_TEMP);
2101 /* cv_setup_hwc(gp); */
2102 cv_hotx = info->hot.x;
2103 cv_hoty = info->hot.y;
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 */
2114 if (info->set & GRFSPRSET_CMAP) {
2115 volatile char *hwc;
2116 int test;
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;
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;
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);
2170 if (info->set & GRFSPRSET_POS)
2171 cv_setspritepos(gp, &info->pos);
2172 if (info->set & GRFSPRSET_HOT) {
2174 cv_hotx = info->hot.x;
2175 cv_hoty = info->hot.y;
2176 cv_setspritepos (gp, &info->pos);
2178 return(0);
2183 cv_getspritemax (struct grf_softc *gp, struct grf_position *pos)
2186 pos->x = 64;
2187 pos->y = 64;
2188 return(0);
2191 #endif /* !CV_NO_HARDWARE_CURSOR */
2193 #endif /* NGRFCV */