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