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