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