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