grf_cv3d.c revision 1.19.4.1 1 /* $NetBSD: grf_cv3d.c,v 1.19.4.1 2007/03/12 05:46:40 rmind 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.19.4.1 2007/03/12 05:46:40 rmind 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 void *);
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 void *);
113 static inline void cv3d_gfx_on_off(int, volatile void *);
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 void *cv3d_boardaddr;
254 static int cv3d_fbsize;
255
256 static volatile void *cv3d_memory_io_base;
257 static volatile void *cv3d_register_base;
258 static volatile void *cv3d_vcode_switch_base;
259 static volatile void *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 void *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 char *)cv3d_boardaddr + 0x04800000;
387 cv3d_memory_io_base =
388 (volatile char *)cv3d_boardaddr + 0x05000000;
389 cv3d_register_base =
390 (volatile char *)cv3d_boardaddr + 0x05008000;
391 cv3d_vcode_switch_base =
392 (volatile char *)cv3d_boardaddr + 0x08000000;
393 cv3d_special_register_base =
394 (volatile char *)cv3d_boardaddr + 0x0C000000;
395 } else {
396 gp->g_fbkva =
397 (volatile char *)cv3d_boardaddr + 0x00000000;
398 cv3d_memory_io_base =
399 (volatile char *)cv3d_boardaddr + 0x003E0000;
400 cv3d_register_base =
401 (volatile char *)cv3d_boardaddr + 0x003C8000;
402 cv3d_vcode_switch_base =
403 (volatile char *)cv3d_boardaddr + 0x003A0000;
404 cv3d_special_register_base =
405 (volatile char *)cv3d_boardaddr + 0x003C0000;
406 }
407
408 gp->g_regkva = (volatile void *)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 void *ba;
504 volatile char *special;
505 unsigned char test;
506 unsigned int clockpar;
507 int i;
508 struct grfinfo *gi;
509
510 ba = gp->g_regkva;
511
512 /* PCI config */
513 if (cv3d_zorroIII) {
514 special = ((volatile char*)cv3d_special_register_base +
515 0x000E0000);
516 } else {
517 special = ((volatile char*)cv3d_special_register_base);
518 }
519 *((volatile short *)(special + 0x10)) = 0;
520 *((volatile long *)(special + 0x4)) = 0x02000003;
521
522 /* Wakeup Chip */
523 vgawio(cv3d_boardaddr, SREG_VIDEO_SUBS_ENABLE, 1);
524
525 vgaw(ba, SREG_VIDEO_SUBS_ENABLE, 0x01);
526
527 vgaw(ba, GREG_MISC_OUTPUT_W, 0x03);
528
529 WCrt(ba, CRT_ID_REGISTER_LOCK_1, 0x48); /* unlock S3 VGA regs */
530 WCrt(ba, CRT_ID_REGISTER_LOCK_2, 0xA5); /* unlock syscontrol */
531
532 WCrt(ba, CRT_ID_EXT_MISC_CNTL_1, 0x02);
533 WCrt(ba, CRT_ID_EXT_MISC_CNTL_1, 0x00);
534
535 WSeq(ba, SEQ_ID_UNLOCK_EXT, 0x06); /* Unlock extensions */
536
537 /*
538 * bit 0=1: enable enhanced mode functions
539 * bit 4=1: enable linear addressing
540 */
541 vgaw32(cv3d_memory_io_base, MR_ADVANCED_FUNCTION_CONTROL, 0x00000011);
542
543 /* -hsync and -vsync */
544 vgaw(ba, GREG_MISC_OUTPUT_W, 0xC3);
545
546 /* Reset. This does nothing, but everyone does it:) */
547 WSeq(ba, SEQ_ID_RESET, 0x03);
548
549 WSeq(ba, SEQ_ID_CLOCKING_MODE, 0x01); /* 8 Dot Clock */
550 WSeq(ba, SEQ_ID_MAP_MASK, 0x0F); /* Enable write planes */
551 WSeq(ba, SEQ_ID_CHAR_MAP_SELECT, 0x00); /* Character Font */
552
553 WSeq(ba, SEQ_ID_MEMORY_MODE, 0x02); /* Complete mem access */
554 WSeq(ba, SEQ_ID_MMIO_SELECT, 0x00);
555
556 test = RSeq(ba, SEQ_ID_BUS_REQ_CNTL); /* Bus Request */
557
558 /* enable 4MB fast Page Mode */
559 test = test | 0xC0;
560 WSeq(ba, SEQ_ID_BUS_REQ_CNTL, test);
561
562 #if 0 /* XXX */
563 /* faster LUT write */
564 WSeq(ba, SEQ_ID_RAMDAC_CNTL, 0xC0);
565 #else
566 WSeq(ba, SEQ_ID_UNKNOWN6, 0x00);
567 WSeq(ba, SEQ_ID_SIGNAL_SELECT, 0x02);
568 #endif
569
570 test = RSeq(ba, SEQ_ID_CLKSYN_CNTL_2); /* Clksyn2 read */
571
572 /* immediately Clkload bit clear */
573 test = test & 0xDF;
574
575 /* 2 MCLK Memory Write.... */
576 if (cv3d_memclk >= 55000000)
577 test |= 0x80;
578
579 WSeq(ba, SEQ_ID_CLKSYN_CNTL_2, test);
580
581 /* Memory CLK */
582 clockpar = cv3d_compute_clock(cv3d_memclk);
583 test = (clockpar & 0xFF00) >> 8;
584 WSeq(ba, SEQ_ID_MCLK_HI, test); /* PLL N-Divider Value */
585
586 test = clockpar & 0xFF;
587 WSeq(ba, SEQ_ID_MCLK_LO, test); /* PLL M-Divider Value */
588
589 /* We now load an 25 MHz, 31 kHz, 640x480 standard VGA Mode. */
590 /* DCLK */
591 WSeq(ba, SEQ_ID_DCLK_HI, 0x13);
592 WSeq(ba, SEQ_ID_DCLK_LO, 0x41);
593
594 test = RSeq (ba, SEQ_ID_CLKSYN_CNTL_2);
595 test = test | 0x22;
596
597 /* DCLK + MCLK Clock immediate load! */
598 WSeq(ba,SEQ_ID_CLKSYN_CNTL_2, test);
599
600 /* DCLK load */
601 test = vgar(ba, 0x3cc);
602 test = test | 0x0c;
603 vgaw(ba, 0x3c2, test);
604
605 /* Clear bit 5 again, prevent further loading. */
606 WSeq(ba, SEQ_ID_CLKSYN_CNTL_2, 0x02);
607
608 WCrt(ba, CRT_ID_HOR_TOTAL, 0x5F);
609 WCrt(ba, CRT_ID_HOR_DISP_ENA_END, 0x4F);
610 WCrt(ba, CRT_ID_START_HOR_BLANK, 0x50);
611 WCrt(ba, CRT_ID_END_HOR_BLANK, 0x82);
612 WCrt(ba, CRT_ID_START_HOR_RETR, 0x54);
613 WCrt(ba, CRT_ID_END_HOR_RETR, 0x80);
614 WCrt(ba, CRT_ID_VER_TOTAL, 0xBF);
615
616 WCrt(ba, CRT_ID_OVERFLOW, 0x1F); /* overflow reg */
617
618 WCrt(ba, CRT_ID_PRESET_ROW_SCAN, 0x00); /* no panning */
619
620 WCrt(ba, CRT_ID_MAX_SCAN_LINE, 0x40); /* vscan */
621
622 WCrt(ba, CRT_ID_CURSOR_START, 0x00);
623 WCrt(ba, CRT_ID_CURSOR_END, 0x00);
624
625 /* Display start address */
626 WCrt(ba, CRT_ID_START_ADDR_HIGH, 0x00);
627 WCrt(ba, CRT_ID_START_ADDR_LOW, 0x00);
628
629 /* Cursor location */
630 WCrt(ba, CRT_ID_CURSOR_LOC_HIGH, 0x00);
631 WCrt(ba, CRT_ID_CURSOR_LOC_LOW, 0x00);
632
633 /* Vertical retrace */
634 WCrt(ba, CRT_ID_START_VER_RETR, 0x9C);
635 WCrt(ba, CRT_ID_END_VER_RETR, 0x0E);
636
637 WCrt(ba, CRT_ID_VER_DISP_ENA_END, 0x8F);
638 WCrt(ba, CRT_ID_SCREEN_OFFSET, 0x50);
639
640 WCrt(ba, CRT_ID_UNDERLINE_LOC, 0x00);
641
642 WCrt(ba, CRT_ID_START_VER_BLANK, 0x96);
643 WCrt(ba, CRT_ID_END_VER_BLANK, 0xB9);
644
645 WCrt(ba, CRT_ID_MODE_CONTROL, 0xE3);
646
647 WCrt(ba, CRT_ID_LINE_COMPARE, 0xFF);
648
649 WCrt(ba, CRT_ID_SYSTEM_CONFIG, 0x21);
650 WCrt(ba, CRT_ID_MEMORY_CONF, 0x04);
651 WCrt(ba, CRT_ID_BACKWAD_COMP_1, 0x00);
652 WCrt(ba, CRT_ID_BACKWAD_COMP_2, 0x02);
653 WCrt(ba, CRT_ID_BACKWAD_COMP_3, 0x10); /* FIFO enabled */
654
655 /* Refresh count 1, High speed text font, enhanced color mode */
656 WCrt(ba, CRT_ID_MISC_1, 0x35);
657
658 /* start fifo position */
659 WCrt(ba, CRT_ID_DISPLAY_FIFO, 0x5A);
660
661 WCrt(ba, CRT_ID_EXT_MEM_CNTL_2, 0x02);
662
663 WCrt(ba, CRT_ID_LAW_POS_LO, 0x40);
664
665 WCrt(ba, CRT_ID_EXT_MISC_CNTL_1, 0x81);
666 WCrt(ba, CRT_ID_MISC_1, 0xB5);
667 WCrt(ba, CRT_ID_CONFIG_1, 0x0E);
668
669 WGfx(ba, GCT_ID_SET_RESET, 0x00);
670 WGfx(ba, GCT_ID_ENABLE_SET_RESET, 0x00);
671 WGfx(ba, GCT_ID_COLOR_COMPARE, 0x00);
672 WGfx(ba, GCT_ID_DATA_ROTATE, 0x00);
673 WGfx(ba, GCT_ID_READ_MAP_SELECT, 0x00);
674 WGfx(ba, GCT_ID_GRAPHICS_MODE, 0x40);
675 WGfx(ba, GCT_ID_MISC, 0x01);
676 WGfx(ba, GCT_ID_COLOR_XCARE, 0x0F);
677 WGfx(ba, GCT_ID_BITMASK, 0xFF);
678
679 /* colors for text mode */
680 for (i = 0; i <= 0xf; i++)
681 WAttr (ba, i, i);
682
683 WAttr(ba, ACT_ID_ATTR_MODE_CNTL, 0x41);
684 WAttr(ba, ACT_ID_OVERSCAN_COLOR, 0x01);
685 WAttr(ba, ACT_ID_COLOR_PLANE_ENA, 0x0F);
686 WAttr(ba, ACT_ID_HOR_PEL_PANNING, 0x00);
687 WAttr(ba, ACT_ID_COLOR_SELECT, 0x00);
688
689 vgawio(cv3d_boardaddr, VDAC_MASK, 0xFF); /* DAC Mask */
690
691 /* colors initially set to greyscale */
692
693 vgawio(cv3d_boardaddr, VDAC_ADDRESS_W, 0);
694
695 for (i = 255; i >= 0 ; i--) {
696 vgawio(cv3d_boardaddr, VDAC_DATA, i);
697 vgawio(cv3d_boardaddr, VDAC_DATA, i);
698 vgawio(cv3d_boardaddr, VDAC_DATA, i);
699 }
700
701 /* GFx hardware cursor off */
702 WCrt(ba, CRT_ID_HWGC_MODE, 0x00);
703
704 /* Set first to 4 MB, so test will work */
705 WCrt(ba, CRT_ID_LAW_CNTL, 0x13);
706
707 /* find *correct* fbsize of z3 board */
708 if (cv3d_has_4mb(gp->g_fbkva)) {
709 cv3d_fbsize = 1024 * 1024 * 4;
710 WCrt(ba, CRT_ID_LAW_CNTL, 0x13); /* 4 MB */
711 } else {
712 cv3d_fbsize = 1024 * 1024 * 2;
713 WCrt(ba, CRT_ID_LAW_CNTL, 0x12); /* 2 MB */
714 }
715
716 /* Initialize graphics engine */
717 GfxBusyWait(cv3d_memory_io_base);
718 vgaw32(cv3d_memory_io_base, BLT_COMMAND_SET, CMD_NOP);
719 vgaw32(cv3d_memory_io_base, BLT_CLIP_LEFT_RIGHT, 0x000007ff);
720 vgaw32(cv3d_memory_io_base, BLT_CLIP_TOP_BOTTOM, 0x000007ff);
721 vgaw32(cv3d_memory_io_base, L2D_COMMAND_SET, CMD_NOP);
722 vgaw32(cv3d_memory_io_base, L2D_CLIP_LEFT_RIGHT, 0x000007ff);
723 vgaw32(cv3d_memory_io_base, L2D_CLIP_TOP_BOTTOM, 0x000007ff);
724 vgaw32(cv3d_memory_io_base, P2D_COMMAND_SET, CMD_NOP);
725 vgaw32(cv3d_memory_io_base, P2D_CLIP_LEFT_RIGHT, 0x000007ff);
726 vgaw32(cv3d_memory_io_base, P2D_CLIP_TOP_BOTTOM, 0x000007ff);
727
728 /* Enable Video Display (Set Bit 5) */
729 WAttr(ba, 0x33, 0);
730
731
732 gi = &gp->g_display;
733 gi->gd_regaddr = (void *) kvtop (__UNVOLATILE(ba));
734 gi->gd_regsize = 64 * 1024;
735 gi->gd_fbaddr = (void *) kvtop (__UNVOLATILE(gp->g_fbkva));
736 gi->gd_fbsize = cv3d_fbsize;
737 }
738
739
740 int
741 cv3d_getvmode(struct grf_softc *gp, struct grfvideo_mode *vm)
742 {
743 struct grfvideo_mode *gv;
744
745 #ifdef CV3DCONSOLE
746 /* Handle grabbing console mode */
747 if (vm->mode_num == 255) {
748 bcopy(&cv3dconsole_mode, vm, sizeof(struct grfvideo_mode));
749 /* XXX so grfconfig can tell us the correct text dimensions. */
750 vm->depth = cv3dconsole_mode.fy;
751 } else
752 #endif
753 {
754 if (vm->mode_num == 0)
755 vm->mode_num = (monitor_current - monitor_def) + 1;
756 if (vm->mode_num < 1 || vm->mode_num > monitor_def_max)
757 return (EINVAL);
758 gv = monitor_def + (vm->mode_num - 1);
759 if (gv->mode_num == 0)
760 return (EINVAL);
761
762 bcopy(gv, vm, sizeof(struct grfvideo_mode));
763 }
764
765 /* adjust internal values to pixel values */
766
767 vm->hblank_start *= 8;
768 vm->hsync_start *= 8;
769 vm->hsync_stop *= 8;
770 vm->htotal *= 8;
771
772 return (0);
773 }
774
775
776 int
777 cv3d_setvmode(struct grf_softc *gp, unsigned mode)
778 {
779
780 if (!mode || (mode > monitor_def_max) ||
781 monitor_def[mode - 1].mode_num == 0)
782 return (EINVAL);
783
784 monitor_current = monitor_def + (mode - 1);
785
786 return (0);
787 }
788
789
790 int
791 cv3d_blank(struct grf_softc *gp, int *on)
792 {
793 volatile void *ba;
794
795 ba = gp->g_regkva;
796 cv3d_gfx_on_off(*on > 0 ? 0 : 1, ba);
797 return (0);
798 }
799
800
801 /*
802 * Change the mode of the display.
803 * Return a UNIX error number or 0 for success.
804 */
805 int
806 cv3d_mode(register struct grf_softc *gp, u_long cmd, void *arg, u_long a2,
807 int a3)
808 {
809 int error;
810
811 switch (cmd) {
812 case GM_GRFON:
813 error = cv3d_load_mon (gp,
814 (struct grfcv3dtext_mode *) monitor_current) ? 0 : EINVAL;
815 return (error);
816
817 case GM_GRFOFF:
818 #ifndef CV3DCONSOLE
819 cv3dscreen(1, cv3d_vcode_switch_base);
820 #else
821 cv3d_load_mon(gp, &cv3dconsole_mode);
822 ite_reinit(gp->g_itedev);
823 #endif
824 return (0);
825
826 case GM_GRFCONFIG:
827 return (0);
828
829 case GM_GRFGETVMODE:
830 return (cv3d_getvmode (gp, (struct grfvideo_mode *) arg));
831
832 case GM_GRFSETVMODE:
833 error = cv3d_setvmode (gp, *(unsigned *) arg);
834 if (!error && (gp->g_flags & GF_GRFON))
835 cv3d_load_mon(gp,
836 (struct grfcv3dtext_mode *) monitor_current);
837 return (error);
838
839 case GM_GRFGETNUMVM:
840 *(int *)arg = monitor_def_max;
841 return (0);
842
843 case GM_GRFIOCTL:
844 return (cv3d_ioctl (gp, a2, arg));
845
846 default:
847 break;
848 }
849
850 return (EPASSTHROUGH);
851 }
852
853
854 int
855 cv3d_ioctl(register struct grf_softc *gp, u_long cmd, void *data)
856 {
857 switch (cmd) {
858 #ifdef CV3D_HARDWARE_CURSOR
859 case GRFIOCGSPRITEPOS:
860 return(cv3d_getspritepos (gp, (struct grf_position *) data));
861
862 case GRFIOCSSPRITEPOS:
863 return(cv3d_setspritepos (gp, (struct grf_position *) data));
864
865 case GRFIOCSSPRITEINF:
866 return(cv3d_setspriteinfo (gp, (struct grf_spriteinfo *) data));
867
868 case GRFIOCGSPRITEINF:
869 return(cv3d_getspriteinfo (gp, (struct grf_spriteinfo *) data));
870
871 case GRFIOCGSPRITEMAX:
872 return(cv3d_getspritemax (gp, (struct grf_position *) data));
873 #else /* CV3D_HARDWARE_CURSOR */
874 case GRFIOCGSPRITEPOS:
875 case GRFIOCSSPRITEPOS:
876 case GRFIOCSSPRITEINF:
877 case GRFIOCGSPRITEINF:
878 case GRFIOCGSPRITEMAX:
879 break;
880 #endif /* CV3D_HARDWARE_CURSOR */
881
882 case GRFIOCGETCMAP:
883 return (cv3d_getcmap (gp, (struct grf_colormap *) data));
884
885 case GRFIOCPUTCMAP:
886 return (cv3d_putcmap (gp, (struct grf_colormap *) data));
887
888 case GRFIOCBITBLT:
889 break;
890
891 case GRFTOGGLE:
892 return (cv3d_toggle (gp));
893
894 case GRFIOCSETMON:
895 return (cv3d_setmonitor (gp, (struct grfvideo_mode *)data));
896
897 case GRFIOCBLANK:
898 return (cv3d_blank (gp, (int *)data));
899 }
900 return (EPASSTHROUGH);
901 }
902
903
904 int
905 cv3d_setmonitor(struct grf_softc *gp, struct grfvideo_mode *gv)
906 {
907 struct grfvideo_mode *md;
908
909 if (!cv3d_mondefok(gv))
910 return (EINVAL);
911
912 #ifdef CV3DCONSOLE
913 /* handle interactive setting of console mode */
914 if (gv->mode_num == 255) {
915 bcopy(gv, &cv3dconsole_mode.gv, sizeof(struct grfvideo_mode));
916 cv3dconsole_mode.gv.hblank_start /= 8;
917 cv3dconsole_mode.gv.hsync_start /= 8;
918 cv3dconsole_mode.gv.hsync_stop /= 8;
919 cv3dconsole_mode.gv.htotal /= 8;
920 cv3dconsole_mode.rows = gv->disp_height / cv3dconsole_mode.fy;
921 cv3dconsole_mode.cols = gv->disp_width / cv3dconsole_mode.fx;
922 if (!(gp->g_flags & GF_GRFON))
923 cv3d_load_mon(gp, &cv3dconsole_mode);
924 ite_reinit(gp->g_itedev);
925 return (0);
926 }
927 #endif
928
929 md = monitor_def + (gv->mode_num - 1);
930
931 /*
932 * Prevent user from crashing the system by using
933 * grfconfig while in X
934 */
935 if (gp->g_flags & GF_GRFON)
936 if (md == monitor_current) {
937 printf("grfcv3d: Changing the used mode not allowed!\n");
938 return (EINVAL);
939 }
940
941 bcopy(gv, md, sizeof(struct grfvideo_mode));
942
943 /* adjust pixel oriented values to internal rep. */
944
945 md->hblank_start /= 8;
946 md->hsync_start /= 8;
947 md->hsync_stop /= 8;
948 md->htotal /= 8;
949
950 return (0);
951 }
952
953
954 int
955 cv3d_getcmap(struct grf_softc *gfp, struct grf_colormap *cmap)
956 {
957 volatile void *ba;
958 u_char red[256], green[256], blue[256], *rp, *gp, *bp;
959 short x;
960 int error;
961
962 ba = gfp->g_regkva;
963 if (cmap->count == 0 || cmap->index >= 256)
964 return (0);
965
966 if (cmap->count > 256 - cmap->index)
967 cmap->count = 256 - cmap->index;
968
969 /* first read colors out of the chip, then copyout to userspace */
970 vgawio(cv3d_boardaddr, VDAC_ADDRESS_W, cmap->index);
971 x = cmap->count - 1;
972
973 rp = red + cmap->index;
974 gp = green + cmap->index;
975 bp = blue + cmap->index;
976
977 do {
978 *rp++ = vgario(cv3d_special_register_base, VDAC_DATA) << 2;
979 *gp++ = vgario(cv3d_special_register_base, VDAC_DATA) << 2;
980 *bp++ = vgario(cv3d_special_register_base, VDAC_DATA) << 2;
981 } while (x-- > 0);
982
983 if (!(error = copyout (red + cmap->index, cmap->red, cmap->count))
984 && !(error = copyout (green + cmap->index, cmap->green, cmap->count))
985 && !(error = copyout (blue + cmap->index, cmap->blue, cmap->count)))
986 return (0);
987
988 return (error);
989 }
990
991
992 int
993 cv3d_putcmap(struct grf_softc *gfp, struct grf_colormap *cmap)
994 {
995 volatile void *ba;
996 u_char red[256], green[256], blue[256], *rp, *gp, *bp;
997 short x;
998 int error;
999
1000 ba = gfp->g_regkva;
1001 if (cmap->count == 0 || cmap->index >= 256)
1002 return (0);
1003
1004 if (cmap->index + cmap->count > 256)
1005 cmap->count = 256 - cmap->index;
1006
1007 /* first copy the colors into kernelspace */
1008 if (!(error = copyin (cmap->red, red + cmap->index, cmap->count))
1009 && !(error = copyin (cmap->green, green + cmap->index, cmap->count))
1010 && !(error = copyin (cmap->blue, blue + cmap->index, cmap->count))) {
1011 vgawio(cv3d_boardaddr, VDAC_ADDRESS_W, cmap->index);
1012 x = cmap->count - 1;
1013
1014 rp = red + cmap->index;
1015 gp = green + cmap->index;
1016 bp = blue + cmap->index;
1017
1018 do {
1019 vgawio(cv3d_boardaddr, VDAC_DATA, *rp++ >> 2);
1020 vgawio(cv3d_boardaddr, VDAC_DATA, *gp++ >> 2);
1021 vgawio(cv3d_boardaddr, VDAC_DATA, *bp++ >> 2);
1022 } while (x-- > 0);
1023 return (0);
1024 } else
1025 return (error);
1026 }
1027
1028
1029 int
1030 cv3d_toggle(struct grf_softc *gp)
1031 {
1032 volatile void *ba;
1033
1034 ba = gp->g_regkva;
1035 #ifndef CV3DCONSOLE
1036 cv3d_pass_toggle = 1;
1037 #endif /* !CV3DCONSOLE */
1038
1039 if (cv3d_pass_toggle) {
1040 cv3dscreen(0, cv3d_vcode_switch_base);
1041 cv3d_pass_toggle = 0;
1042 } else {
1043 cv3dscreen(1, cv3d_vcode_switch_base);
1044 cv3d_pass_toggle = 1;
1045 }
1046
1047 return (0);
1048 }
1049
1050
1051 int
1052 cv3d_mondefok(struct grfvideo_mode *gv)
1053 {
1054 unsigned long maxpix;
1055
1056 if (gv->mode_num < 1 || gv->mode_num > monitor_def_max) {
1057 if (gv->mode_num != 255 || gv->depth != 4)
1058 return (0);
1059 }
1060
1061 switch(gv->depth) {
1062 case 4:
1063 maxpix = MAXPIXELCLOCK - 55000000;
1064 break;
1065 case 8:
1066 maxpix = MAXPIXELCLOCK;
1067 break;
1068 case 15:
1069 case 16:
1070 #ifdef CV3D_AGGRESSIVE_TIMING
1071 maxpix = MAXPIXELCLOCK - 35000000;
1072 #else
1073 maxpix = MAXPIXELCLOCK - 55000000;
1074 #endif
1075 break;
1076 case 24:
1077 case 32:
1078 #ifdef CV3D_AGGRESSIVE_TIMING
1079 maxpix = MAXPIXELCLOCK - 75000000;
1080 #else
1081 maxpix = MAXPIXELCLOCK - 85000000;
1082 #endif
1083 break;
1084 default:
1085 printf("grfcv3d: Illegal depth in mode %d\n",
1086 (int) gv->mode_num);
1087 return (0);
1088 }
1089
1090 if (gv->pixel_clock > maxpix) {
1091 printf("grfcv3d: Pixelclock too high in mode %d\n",
1092 (int) gv->mode_num);
1093 return (0);
1094 }
1095
1096 if (gv->mode_num == 255) { /* console mode */
1097 if ((gv->disp_width / 8) > MAXCOLS) {
1098 printf ("grfcv3d: Too many columns for console\n");
1099 return (0);
1100 } else if ((gv->disp_height / S3FONTY) > MAXROWS) {
1101 printf ("grfcv3d: Too many rows for console\n");
1102 return (0);
1103 }
1104 }
1105
1106 if (gv->disp_flags & GRF_FLAGS_SYNC_ON_GREEN) {
1107 printf("grfcv3d: sync-on-green is not supported\n");
1108 return (0);
1109 }
1110
1111 return (1);
1112 }
1113
1114
1115 int
1116 cv3d_load_mon(struct grf_softc *gp, struct grfcv3dtext_mode *md)
1117 {
1118 struct grfvideo_mode *gv;
1119 struct grfinfo *gi;
1120 volatile void *ba, *fb;
1121 unsigned short mnr;
1122 unsigned short HT, HDE, HBS, HBE, HSS, HSE, VDE, VBS, VBE, VSS,
1123 VSE, VT;
1124 int cr50, cr66, sr15, sr18, clock_mode, test;
1125 int hmul; /* Multiplier for hor. Values */
1126 int fb_flag = 2; /* default value for 8bit memory access */
1127 unsigned char hvsync_pulse;
1128 char TEXT, CONSOLE;
1129
1130 /* identity */
1131 gv = &md->gv;
1132
1133 TEXT = (gv->depth == 4);
1134 CONSOLE = (gv->mode_num == 255);
1135
1136 if (!cv3d_mondefok(gv)) {
1137 printf("grfcv3d: Monitor definition not ok\n");
1138 return (0);
1139 }
1140
1141 ba = gp->g_regkva;
1142 fb = gp->g_fbkva;
1143
1144 /* turn gfx off, don't mess up the display */
1145 cv3d_gfx_on_off(1, ba);
1146
1147 /* provide all needed information in grf device-independent locations */
1148 gp->g_data = (void *) gv;
1149 gi = &gp->g_display;
1150 gi->gd_colors = 1 << gv->depth;
1151 gi->gd_planes = gv->depth;
1152 gi->gd_fbwidth = gv->disp_width;
1153 gi->gd_fbheight = gv->disp_height;
1154 gi->gd_fbx = 0;
1155 gi->gd_fby = 0;
1156 if (CONSOLE) {
1157 gi->gd_dwidth = md->fx * md->cols;
1158 gi->gd_dheight = md->fy * md->rows;
1159 } else {
1160 gi->gd_dwidth = gv->disp_width;
1161 gi->gd_dheight = gv->disp_height;
1162 }
1163 gi->gd_dx = 0;
1164 gi->gd_dy = 0;
1165
1166 /* get display mode parameters */
1167 switch (gv->depth) {
1168 case 15:
1169 case 16:
1170 hmul = 2;
1171 break;
1172 default:
1173 hmul = 1;
1174 break;
1175 }
1176
1177 HBS = gv->hblank_start * hmul;
1178 HSS = gv->hsync_start * hmul;
1179 HSE = gv->hsync_stop * hmul;
1180 HBE = gv->htotal * hmul - 6;
1181 HT = gv->htotal * hmul - 5;
1182 VBS = gv->vblank_start - 1;
1183 VSS = gv->vsync_start;
1184 VSE = gv->vsync_stop;
1185 VBE = gv->vtotal - 3;
1186 VT = gv->vtotal - 2;
1187
1188 /*
1189 * Disable enhanced Mode for text display
1190 *
1191 * XXX You need to set this bit in CRT_ID_EXT_MISC_CNTL_1
1192 * _and_ MR_ADVANCED_FUNCTION_CONTROL, because the same
1193 * function exists in both registers.
1194 */
1195 cr66 = RCrt(ba, CRT_ID_EXT_MISC_CNTL_1);
1196 if (TEXT) {
1197 cr66 &= ~0x01;
1198 vgaw32(cv3d_memory_io_base, MR_ADVANCED_FUNCTION_CONTROL,
1199 0x00000010);
1200 } else {
1201 cr66 |= 0x01;
1202 vgaw32(cv3d_memory_io_base, MR_ADVANCED_FUNCTION_CONTROL,
1203 0x00000011);
1204 }
1205 WCrt(ba, CRT_ID_EXT_MISC_CNTL_1, cr66);
1206
1207 if (TEXT)
1208 HDE = ((gv->disp_width + md->fx - 1) / md->fx) - 1;
1209 else
1210 HDE = (gv->disp_width + 3) * hmul / 8 - 1; /*HBS;*/
1211 VDE = gv->disp_height - 1;
1212
1213 /* adjustments */
1214
1215 if (gv->disp_flags & GRF_FLAGS_LACE) {
1216 VDE = VDE / 2;
1217 VBS = VBS / 2;
1218 VSS = VSS / 2;
1219 VSE = VSE / 2;
1220 VBE = VBE / 2;
1221 VT = VT / 2;
1222 }
1223
1224 /* Horizontal/Vertical Sync Pulse */
1225 /*
1226 * GREG_MISC_OUTPUT_W Register:
1227 * bit description (0/1)
1228 * 0 Monochrome/Color emulation
1229 * 1 Disable/Enable access of the display memory from the CPU
1230 * 5 Select the low/high 64K page of memory
1231 * 6 Select a positive/negative horizontal retrace sync pulse
1232 * 7 Select a positive/negative vertical retrace sync pulse
1233 */
1234 hvsync_pulse = vgar(ba, GREG_MISC_OUTPUT_R);
1235 if (gv->disp_flags & GRF_FLAGS_PHSYNC)
1236 hvsync_pulse &= ~0x40;
1237 else
1238 hvsync_pulse |= 0x40;
1239 if (gv->disp_flags & GRF_FLAGS_PVSYNC)
1240 hvsync_pulse &= ~0x80;
1241 else
1242 hvsync_pulse |= 0x80;
1243 vgaw(ba, GREG_MISC_OUTPUT_W, hvsync_pulse);
1244
1245 /* GFX hardware cursor off */
1246 WCrt(ba, CRT_ID_HWGC_MODE, 0x00);
1247 WCrt(ba, CRT_ID_EXT_DAC_CNTL, 0x00);
1248
1249 WSeq(ba, SEQ_ID_MEMORY_MODE, (TEXT || (gv->depth == 1)) ? 0x06 : 0x0e);
1250 WGfx(ba, GCT_ID_READ_MAP_SELECT, 0x00);
1251 WSeq(ba, SEQ_ID_MAP_MASK, (gv->depth == 1) ? 0x01 : 0xff);
1252 WSeq(ba, SEQ_ID_CHAR_MAP_SELECT, 0x00);
1253
1254 /* Set clock */
1255
1256 mnr = cv3d_compute_clock(gv->pixel_clock);
1257 WSeq(ba, SEQ_ID_DCLK_HI, ((mnr & 0xFF00) >> 8));
1258 WSeq(ba, SEQ_ID_DCLK_LO, (mnr & 0xFF));
1259
1260 /* load display parameters into board */
1261
1262 WCrt(ba, CRT_ID_EXT_HOR_OVF,
1263 ((HT & 0x100) ? 0x01 : 0x00) |
1264 ((HDE & 0x100) ? 0x02 : 0x00) |
1265 ((HBS & 0x100) ? 0x04 : 0x00) |
1266 /* ((HBE & 0x40) ? 0x08 : 0x00) | */ /* Later... */
1267 ((HSS & 0x100) ? 0x10 : 0x00) |
1268 /* ((HSE & 0x20) ? 0x20 : 0x00) | */
1269 (((HT-5) & 0x100) ? 0x40 : 0x00) );
1270
1271 WCrt(ba, CRT_ID_EXT_VER_OVF,
1272 0x40 | /* Line compare */
1273 ((VT & 0x400) ? 0x01 : 0x00) |
1274 ((VDE & 0x400) ? 0x02 : 0x00) |
1275 ((VBS & 0x400) ? 0x04 : 0x00) |
1276 ((VSS & 0x400) ? 0x10 : 0x00) );
1277
1278 WCrt(ba, CRT_ID_HOR_TOTAL, HT);
1279 WCrt(ba, CRT_ID_DISPLAY_FIFO, HT - 5);
1280
1281 WCrt(ba, CRT_ID_HOR_DISP_ENA_END, ((HDE >= HBS) ? (HBS - 1) : HDE));
1282 WCrt(ba, CRT_ID_START_HOR_BLANK, HBS);
1283 WCrt(ba, CRT_ID_END_HOR_BLANK, ((HBE & 0x1f) | 0x80));
1284 WCrt(ba, CRT_ID_START_HOR_RETR, HSS);
1285 WCrt(ba, CRT_ID_END_HOR_RETR,
1286 (HSE & 0x1f) |
1287 ((HBE & 0x20) ? 0x80 : 0x00) );
1288 WCrt(ba, CRT_ID_VER_TOTAL, VT);
1289 WCrt(ba, CRT_ID_OVERFLOW,
1290 0x10 |
1291 ((VT & 0x100) ? 0x01 : 0x00) |
1292 ((VDE & 0x100) ? 0x02 : 0x00) |
1293 ((VSS & 0x100) ? 0x04 : 0x00) |
1294 ((VBS & 0x100) ? 0x08 : 0x00) |
1295 ((VT & 0x200) ? 0x20 : 0x00) |
1296 ((VDE & 0x200) ? 0x40 : 0x00) |
1297 ((VSS & 0x200) ? 0x80 : 0x00) );
1298
1299 WCrt(ba, CRT_ID_MAX_SCAN_LINE,
1300 0x40 | /* TEXT ? 0x00 ??? */
1301 ((gv->disp_flags & GRF_FLAGS_DBLSCAN) ? 0x80 : 0x00) |
1302 ((VBS & 0x200) ? 0x20 : 0x00) |
1303 (TEXT ? ((md->fy - 1) & 0x1f) : 0x00));
1304
1305 WCrt(ba, CRT_ID_MODE_CONTROL, 0xE3);
1306
1307 /* text cursor */
1308
1309 if (TEXT) {
1310 #if CV3D_ULCURSOR
1311 WCrt(ba, CRT_ID_CURSOR_START, (md->fy & 0x1f) - 2);
1312 WCrt(ba, CRT_ID_CURSOR_END, (md->fy & 0x1f) - 1);
1313 #else
1314 WCrt(ba, CRT_ID_CURSOR_START, 0x00);
1315 WCrt(ba, CRT_ID_CURSOR_END, md->fy & 0x1f);
1316 #endif
1317 WCrt(ba, CRT_ID_UNDERLINE_LOC, (md->fy - 1) & 0x1f);
1318
1319 WCrt(ba, CRT_ID_CURSOR_LOC_HIGH, 0x00);
1320 WCrt(ba, CRT_ID_CURSOR_LOC_LOW, 0x00);
1321 }
1322
1323 WCrt(ba, CRT_ID_START_ADDR_HIGH, 0x00);
1324 WCrt(ba, CRT_ID_START_ADDR_LOW, 0x00);
1325
1326 WCrt(ba, CRT_ID_START_VER_RETR, VSS);
1327 WCrt(ba, CRT_ID_END_VER_RETR, (VSE & 0x0f));
1328 WCrt(ba, CRT_ID_VER_DISP_ENA_END, VDE);
1329 WCrt(ba, CRT_ID_START_VER_BLANK, VBS);
1330 WCrt(ba, CRT_ID_END_VER_BLANK, VBE);
1331
1332 WCrt(ba, CRT_ID_LINE_COMPARE, 0xff);
1333 WCrt(ba, CRT_ID_LACE_RETR_START, HT / 2);
1334 WCrt(ba, CRT_ID_LACE_CONTROL,
1335 ((gv->disp_flags & GRF_FLAGS_LACE) ? 0x20 : 0x00));
1336
1337 WGfx(ba, GCT_ID_GRAPHICS_MODE,
1338 ((TEXT || (gv->depth == 1)) ? 0x00 : 0x40));
1339 WGfx(ba, GCT_ID_MISC, (TEXT ? 0x04 : 0x01));
1340
1341 WSeq (ba, SEQ_ID_MEMORY_MODE,
1342 ((TEXT || (gv->depth == 1)) ? 0x06 : 0x02));
1343
1344 vgawio(cv3d_boardaddr, VDAC_MASK, 0xff);
1345
1346 /* Blank border */
1347 test = RCrt(ba, CRT_ID_BACKWAD_COMP_2);
1348 WCrt(ba, CRT_ID_BACKWAD_COMP_2, (test | 0x20));
1349
1350 sr15 = RSeq(ba, SEQ_ID_CLKSYN_CNTL_2);
1351 sr15 &= ~0x10;
1352 sr18 = RSeq(ba, SEQ_ID_RAMDAC_CNTL);
1353 sr18 &= ~0x80;
1354 clock_mode = 0x00;
1355 cr50 = 0x00;
1356
1357 test = RCrt(ba, CRT_ID_EXT_MISC_CNTL_2);
1358 test &= 0xd;
1359
1360 switch (gv->depth) {
1361 case 1:
1362 case 4: /* text */
1363 fb_flag = 2;
1364 HDE = gv->disp_width / 16;
1365 break;
1366 case 8:
1367 fb_flag = 2;
1368 if (gv->pixel_clock > 80000000) {
1369 /*
1370 * CR67 bit 1 is undocumented but needed to prevent
1371 * a white line on the left side of the screen.
1372 */
1373 clock_mode = 0x10 | 0x02;
1374 sr15 |= 0x10;
1375 sr18 |= 0x80;
1376 }
1377 HDE = gv->disp_width / 8;
1378 cr50 |= 0x00;
1379 break;
1380 case 15:
1381 fb_flag = 1;
1382 clock_mode = 0x30;
1383 HDE = gv->disp_width / 4;
1384 cr50 |= 0x10;
1385 break;
1386 case 16:
1387 fb_flag = 1;
1388 clock_mode = 0x50;
1389 HDE = gv->disp_width / 4;
1390 cr50 |= 0x10;
1391 break;
1392 case 24: /* this is really 32 Bit on CV64/3D */
1393 case 32:
1394 fb_flag = 0;
1395 clock_mode = 0xd0;
1396 HDE = (gv->disp_width / 2);
1397 cr50 |= 0x30;
1398 break;
1399 }
1400
1401 if (cv3d_zorroIII) {
1402 gp->g_fbkva = (volatile char *)cv3d_boardaddr + 0x04000000 +
1403 (0x00400000 * fb_flag);
1404 } else {
1405 /* XXX This is totaly untested */
1406 Select_Zorro2_FrameBuffer(fb_flag);
1407 }
1408
1409 WCrt(ba, CRT_ID_EXT_MISC_CNTL_2, clock_mode | test);
1410 WSeq(ba, SEQ_ID_CLKSYN_CNTL_2, sr15);
1411 WSeq(ba, SEQ_ID_RAMDAC_CNTL, sr18);
1412 WCrt(ba, CRT_ID_SCREEN_OFFSET, HDE);
1413
1414 WCrt(ba, CRT_ID_MISC_1, (TEXT ? 0x05 : 0x35));
1415
1416 test = RCrt(ba, CRT_ID_EXT_SYS_CNTL_2);
1417 test &= ~0x30;
1418 /* HDE Overflow in bits 4-5 */
1419 test |= (HDE >> 4) & 0x30;
1420 WCrt(ba, CRT_ID_EXT_SYS_CNTL_2, test);
1421
1422 #if 0 /* XXX */
1423 /* Set up graphics engine */
1424 switch (gv->disp_width) {
1425 case 1024:
1426 cr50 |= 0x00;
1427 break;
1428 case 640:
1429 cr50 |= 0x40;
1430 break;
1431 case 800:
1432 cr50 |= 0x80;
1433 break;
1434 case 1280:
1435 cr50 |= 0xc0;
1436 break;
1437 case 1152:
1438 cr50 |= 0x01;
1439 break;
1440 case 1600:
1441 cr50 |= 0x81;
1442 break;
1443 default: /* XXX The Xserver has to handle this */
1444 break;
1445 }
1446
1447 WCrt(ba, CRT_ID_EXT_SYS_CNTL_1, cr50);
1448 #endif
1449
1450 delay(100000);
1451 WAttr(ba, ACT_ID_ATTR_MODE_CNTL, (TEXT ? 0x08 : 0x41));
1452 delay(100000);
1453 WAttr(ba, ACT_ID_COLOR_PLANE_ENA,
1454 (gv->depth == 1) ? 0x01 : 0x0f);
1455 delay(100000);
1456
1457 /* text initialization */
1458
1459 if (TEXT) {
1460 cv3d_inittextmode(gp);
1461 }
1462
1463 if (CONSOLE) {
1464 int i;
1465 vgawio(cv3d_boardaddr, VDAC_ADDRESS_W, 0);
1466 for (i = 0; i < 16; i++) {
1467 vgawio(cv3d_boardaddr, VDAC_DATA, cv3dconscolors[i][0]);
1468 vgawio(cv3d_boardaddr, VDAC_DATA, cv3dconscolors[i][1]);
1469 vgawio(cv3d_boardaddr, VDAC_DATA, cv3dconscolors[i][2]);
1470 }
1471 }
1472
1473 /* Set display enable flag */
1474 WAttr(ba, 0x33, 0);
1475
1476 /* turn gfx on again */
1477 cv3d_gfx_on_off(0, ba);
1478
1479 /* Pass-through */
1480 cv3dscreen(0, cv3d_vcode_switch_base);
1481
1482 return (1);
1483 }
1484
1485
1486 void
1487 cv3d_inittextmode(struct grf_softc *gp)
1488 {
1489 struct grfcv3dtext_mode *tm = (struct grfcv3dtext_mode *)gp->g_data;
1490 volatile void *ba, *fb;
1491 volatile unsigned char *c;
1492 unsigned char *f, y;
1493 unsigned short z;
1494
1495 ba = gp->g_regkva;
1496 fb = gp->g_fbkva;
1497
1498 /* load text font into beginning of display memory.
1499 * Each character cell is 32 bytes long (enough for 4 planes)
1500 * In linear addressing text mode, the memory is organized
1501 * so, that the Bytes of all 4 planes are interleaved.
1502 * 1st byte plane 0, 1st byte plane 1, 1st byte plane 2,
1503 * 1st byte plane 3, 2nd byte plane 0, 2nd byte plane 1,...
1504 * The font is loaded in plane 2.
1505 */
1506
1507 c = (volatile unsigned char *) fb;
1508
1509 /* clear screen */
1510 for (z = 0; z < tm->cols * tm->rows * 3; z++) {
1511 *c++ = 0x20;
1512 *c++ = 0x07;
1513 *c++ = 0;
1514 *c++ = 0;
1515 }
1516
1517 c = (volatile unsigned char *)fb + (32 * tm->fdstart * 4 + 2);
1518 f = tm->fdata;
1519 for (z = tm->fdstart; z <= tm->fdend; z++, c += (32 - tm->fy) * 4)
1520 for (y = 0; y < tm->fy; y++) {
1521 *c = *f++;
1522 c += 4;
1523 }
1524
1525 /* print out a little init msg */
1526 c = (volatile unsigned char *)fb + (tm->cols - 9) * 4;
1527 *c++ = 'C';
1528 *c++ = 0x0c;
1529 c +=2;
1530 *c++ = 'V';
1531 *c++ = 0x0c;
1532 c +=2;
1533 *c++ = '6';
1534 *c++ = 0x0b;
1535 c +=2;
1536 *c++ = '4';
1537 *c++ = 0x0f;
1538 c +=2;
1539 *c++ = '/';
1540 *c++ = 0x0e;
1541 c +=2;
1542 *c++ = '3';
1543 *c++ = 0x0a;
1544 c +=2;
1545 *c++ = 'D';
1546 *c++ = 0x0a;
1547 }
1548
1549 /*
1550 * Monitor Switch
1551 * 0 = CyberVision Signal
1552 * 1 = Amiga Signal,
1553 * ba = boardaddr
1554 */
1555 static inline void
1556 cv3dscreen(int toggle, volatile void *ba)
1557 {
1558 *((volatile short *)(ba)) = (toggle & 1);
1559 }
1560
1561
1562 /* 0 = on, 1= off */
1563 /* ba= registerbase */
1564 static inline void
1565 cv3d_gfx_on_off(int toggle, volatile void *ba)
1566 {
1567 int r;
1568
1569 toggle &= 0x1;
1570 toggle = toggle << 5;
1571
1572 r = RSeq(ba, SEQ_ID_CLOCKING_MODE);
1573 r &= ~0x20; /* set Bit 5 to 0 */
1574
1575 WSeq(ba, SEQ_ID_CLOCKING_MODE, r | toggle);
1576 }
1577
1578
1579 #ifdef CV3D_HARDWARE_CURSOR
1580
1581 static unsigned char cv3d_hotx = 0, cv3d_hoty = 0;
1582 static char cv_cursor_on = 0;
1583
1584 #define HWC_OFF (cv3d_fbsize - 1024*2)
1585 #define HWC_SIZE 1024
1586
1587 /* Hardware Cursor handling routines */
1588
1589 int
1590 cv3d_getspritepos(struct grf_softc *gp, struct grf_position *pos)
1591 {
1592 int hi,lo;
1593 volatile void *ba = gp->g_regkva;
1594
1595 hi = RCrt(ba, CRT_ID_HWGC_ORIGIN_Y_HI);
1596 lo = RCrt(ba, CRT_ID_HWGC_ORIGIN_Y_LO);
1597
1598 pos->y = (hi << 8) + lo;
1599 hi = RCrt(ba, CRT_ID_HWGC_ORIGIN_X_HI);
1600 lo = RCrt(ba, CRT_ID_HWGC_ORIGIN_X_LO);
1601 pos->x = (hi << 8) + lo;
1602 return (0);
1603 }
1604
1605
1606 int
1607 cv3d_setspritepos(struct grf_softc *gp, struct grf_position *pos)
1608 {
1609 volatile void *ba = gp->g_regkva;
1610 short x, y;
1611 static short savex, savey;
1612 short xoff, yoff;
1613
1614 if (pos) {
1615 x = pos->x;
1616 y = pos->y;
1617 savex = x;
1618 savey= y;
1619 } else { /* restore cursor */
1620 x = savex;
1621 y = savey;
1622 }
1623 x -= cv3d_hotx;
1624 y -= cv3d_hoty;
1625 if (x < 0) {
1626 xoff = ((-x) & 0xFE);
1627 x = 0;
1628 } else {
1629 xoff = 0;
1630 }
1631
1632 if (y < 0) {
1633 yoff = ((-y) & 0xFE);
1634 y = 0;
1635 } else {
1636 yoff = 0;
1637 }
1638
1639 WCrt(ba, CRT_ID_HWGC_ORIGIN_X_HI, (x >> 8));
1640 WCrt(ba, CRT_ID_HWGC_ORIGIN_X_LO, (x & 0xff));
1641
1642 WCrt(ba, CRT_ID_HWGC_ORIGIN_Y_LO, (y & 0xff));
1643 WCrt(ba, CRT_ID_HWGC_DSTART_X, xoff);
1644 WCrt(ba, CRT_ID_HWGC_DSTART_Y, yoff);
1645 WCrt(ba, CRT_ID_HWGC_ORIGIN_Y_HI, (y >> 8));
1646
1647 return(0);
1648 }
1649
1650 static inline short
1651 M2I(short val)
1652 {
1653 return ( ((val & 0xff00) >> 8) | ((val & 0xff) << 8));
1654 }
1655
1656 int
1657 cv3d_getspriteinfo(struct grf_softc *gp, struct grf_spriteinfo *info)
1658 {
1659 volatile void *ba, fb;
1660
1661 ba = gp->g_regkva;
1662 fb = gp->g_fbkva;
1663
1664 if (info->set & GRFSPRSET_ENABLE)
1665 info->enable = RCrt(ba, CRT_ID_HWGC_MODE) & 0x01;
1666
1667 if (info->set & GRFSPRSET_POS)
1668 cv3d_getspritepos (gp, &info->pos);
1669
1670 #if 0 /* XXX */
1671 if (info->set & GRFSPRSET_SHAPE) {
1672 u_char image[512], mask[512];
1673 volatile u_long *hwp;
1674 u_char *imp, *mp;
1675 short row;
1676 info->size.x = 64;
1677 info->size.y = 64;
1678 for (row = 0, hwp = (u_long *)(fb + HWC_OFF),
1679 mp = mask, imp = image;
1680 row < 64;
1681 row++) {
1682 u_long bp10, bp20, bp11, bp21;
1683 bp10 = *hwp++;
1684 bp20 = *hwp++;
1685 bp11 = *hwp++;
1686 bp21 = *hwp++;
1687 M2I (bp10);
1688 M2I (bp20);
1689 M2I (bp11);
1690 M2I (bp21);
1691 *imp++ = (~bp10) & bp11;
1692 *imp++ = (~bp20) & bp21;
1693 *mp++ = (~bp10) | (bp10 & ~bp11);
1694 *mp++ = (~bp20) & (bp20 & ~bp21);
1695 }
1696 copyout (image, info->image, sizeof (image));
1697 copyout (mask, info->mask, sizeof (mask));
1698 }
1699 #endif
1700 return(0);
1701 }
1702
1703
1704 void
1705 cv3d_setup_hwc(struct grf_softc *gp)
1706 {
1707 volatile void *ba = gp->g_regkva;
1708 volatile void *hwc;
1709 int test;
1710
1711 if (gp->g_display.gd_planes <= 4)
1712 cv3d_cursor_on = 0; /* don't enable hwc in text modes */
1713 if (cv3d_cursor_on == 0)
1714 return;
1715
1716 /* reset colour stack */
1717 #if 0
1718 test = RCrt(ba, CRT_ID_HWGC_MODE);
1719 __asm volatile("nop");
1720 #else
1721 /* do it in assembler, the above does't seem to work */
1722 __asm volatile ("moveb #0x45, %1@(0x3d4); \
1723 moveb %1@(0x3d5),%0" : "=r" (test) : "a" (ba));
1724 #endif
1725
1726 WCrt (ba, CRT_ID_HWGC_FG_STACK, 0);
1727
1728 hwc = ba + CRT_ADDRESS_W;
1729 *hwc = 0;
1730 *hwc = 0;
1731
1732 #if 0
1733 test = RCrt(ba, CRT_ID_HWGC_MODE);
1734 __asm volatile("nop");
1735 #else
1736 /* do it in assembler, the above does't seem to work */
1737 __asm volatile ("moveb #0x45, %1@(0x3d4); \
1738 moveb %1@(0x3d5),%0" : "=r" (test) : "a" (ba));
1739 #endif
1740 switch (gp->g_display.gd_planes) {
1741 case 8:
1742 WCrt (ba, CRT_ID_HWGC_BG_STACK, 0x1);
1743 *hwc = 1;
1744 break;
1745 default:
1746 WCrt (ba, CRT_ID_HWGC_BG_STACK, 0xff);
1747 *hwc = 0xff;
1748 *hwc = 0xff;
1749 }
1750
1751 test = HWC_OFF / HWC_SIZE;
1752 WCrt (ba, CRT_ID_HWGC_START_AD_HI, (test >> 8));
1753 WCrt (ba, CRT_ID_HWGC_START_AD_LO, (test & 0xff));
1754
1755 WCrt (ba, CRT_ID_HWGC_DSTART_X , 0);
1756 WCrt (ba, CRT_ID_HWGC_DSTART_Y , 0);
1757
1758 WCrt (ba, CRT_ID_EXT_DAC_CNTL, 0x10); /* Cursor X11 Mode */
1759 /*
1760 * Put it into Windoze Mode or you'll see sometimes a white stripe
1761 * on the right side (in double clocking modes with a screen bigger
1762 * > 1023 pixels).
1763 */
1764 WCrt (ba, CRT_ID_EXT_DAC_CNTL, 0x00); /* Cursor Windoze Mode */
1765
1766 WCrt (ba, CRT_ID_HWGC_MODE, 0x01);
1767 }
1768
1769
1770 /*
1771 * This was the reason why you shouldn't use the HWC in the Kernel:(
1772 * Obsoleted now by use of interrupts :-)
1773 */
1774
1775 #define VerticalRetraceWait(ba) \
1776 { \
1777 while (vgar(ba, GREG_INPUT_STATUS1_R) == 0x00) ; \
1778 while ((vgar(ba, GREG_INPUT_STATUS1_R) & 0x08) == 0x08) ; \
1779 while ((vgar(ba, GREG_INPUT_STATUS1_R) & 0x08) == 0x00) ; \
1780 }
1781
1782
1783 int
1784 cv3d_setspriteinfo(struct grf_softc *gp, struct grf_spriteinfo *info)
1785 {
1786 volatile void *ba, fb;
1787 int depth = gp->g_display.gd_planes;
1788
1789 ba = gp->g_regkva;
1790 fb = gp->g_fbkva;
1791
1792 if (info->set & GRFSPRSET_SHAPE) {
1793 /*
1794 * For an explanation of these weird actions here, see above
1795 * when reading the shape. We set the shape directly into
1796 * the video memory, there's no reason to keep 1k on the
1797 * kernel stack just as template
1798 */
1799 u_char *image, *mask;
1800 volatile u_short *hwp;
1801 u_char *imp, *mp;
1802 unsigned short row;
1803
1804 /* Cursor off */
1805 WCrt (ba, CRT_ID_HWGC_MODE, 0x00);
1806
1807 /*
1808 * The Trio64 crashes if the cursor data is written
1809 * while the cursor is displayed.
1810 * Sadly, turning the cursor off is not enough.
1811 * What we have to do is:
1812 * 1. Wait for vertical retrace, to make sure no-one
1813 * has moved the cursor in this sync period (because
1814 * another write then would have no effect, argh!).
1815 * 2. Move the cursor off-screen
1816 * 3. Another wait for v. retrace to make sure the cursor
1817 * is really off.
1818 * 4. Write the data, finally.
1819 * (thanks to Harald Koenig for this tip!)
1820 */
1821
1822 /*
1823 * Remark 06/06/96: Update in interrupt obsoletes this,
1824 * but the warning should stay there!
1825 */
1826
1827 VerticalRetraceWait(ba);
1828
1829 WCrt (ba, CRT_ID_HWGC_ORIGIN_X_HI, 0x7);
1830 WCrt (ba, CRT_ID_HWGC_ORIGIN_X_LO, 0xff);
1831 WCrt (ba, CRT_ID_HWGC_ORIGIN_Y_LO, 0xff);
1832 WCrt (ba, CRT_ID_HWGC_DSTART_X, 0x3f);
1833 WCrt (ba, CRT_ID_HWGC_DSTART_Y, 0x3f);
1834 WCrt (ba, CRT_ID_HWGC_ORIGIN_Y_HI, 0x7);
1835
1836 if (info->size.y > 64)
1837 info->size.y = 64;
1838 if (info->size.x > 64)
1839 info->size.x = 64;
1840 if (info->size.x < 32)
1841 info->size.x = 32;
1842
1843 image = malloc(HWC_SIZE, M_TEMP, M_WAITOK);
1844 mask = image + HWC_SIZE/2;
1845
1846 copyin(info->image, image, info->size.y * info->size.x / 8);
1847 copyin(info->mask, mask, info->size.y * info->size.x / 8);
1848
1849 hwp = (u_short *)(fb +HWC_OFF);
1850
1851 /* This is necessary in order not to crash the board */
1852 VerticalRetraceWait(ba);
1853
1854 /*
1855 * setting it is slightly more difficult, because we can't
1856 * force the application to not pass a *smaller* than
1857 * supported bitmap
1858 */
1859
1860 for (row = 0, mp = mask, imp = image;
1861 row < info->size.y; row++) {
1862 u_short im1, im2, im3, im4, m1, m2, m3, m4;
1863
1864 m1 = ~(*(unsigned short *)mp);
1865 im1 = *(unsigned short *)imp & *(unsigned short *)mp;
1866 mp += 2;
1867 imp += 2;
1868
1869 m2 = ~(*(unsigned short *)mp);
1870 im2 = *(unsigned short *)imp & *(unsigned short *)mp;
1871 mp += 2;
1872 imp += 2;
1873
1874 if (info->size.x > 32) {
1875 m3 = ~(*(unsigned short *)mp);
1876 im3 = *(unsigned short *)imp & *(unsigned short *)mp;
1877 mp += 2;
1878 imp += 2;
1879 m4 = ~(*(unsigned short *)mp);
1880 im4 = *(unsigned short *)imp & *(unsigned short *)mp;
1881 mp += 2;
1882 imp += 2;
1883 } else {
1884 m3 = 0xffff;
1885 im3 = 0;
1886 m4 = 0xffff;
1887 im4 = 0;
1888 }
1889
1890 switch (depth) {
1891 case 8:
1892 *hwp++ = m1;
1893 *hwp++ = im1;
1894 *hwp++ = m2;
1895 *hwp++ = im2;
1896 *hwp++ = m3;
1897 *hwp++ = im3;
1898 *hwp++ = m4;
1899 *hwp++ = im4;
1900 break;
1901 case 15:
1902 case 16:
1903 *hwp++ = M2I(m1);
1904 *hwp++ = M2I(im1);
1905 *hwp++ = M2I(m2);
1906 *hwp++ = M2I(im2);
1907 *hwp++ = M2I(m3);
1908 *hwp++ = M2I(im3);
1909 *hwp++ = M2I(m4);
1910 *hwp++ = M2I(im4);
1911 break;
1912 case 24:
1913 case 32:
1914 *hwp++ = M2I(im1);
1915 *hwp++ = M2I(m1);
1916 *hwp++ = M2I(im2);
1917 *hwp++ = M2I(m2);
1918 *hwp++ = M2I(im3);
1919 *hwp++ = M2I(m3);
1920 *hwp++ = M2I(im4);
1921 *hwp++ = M2I(m4);
1922 break;
1923 }
1924 }
1925
1926 if (depth < 24) {
1927 for (; row < 64; row++) {
1928 *hwp++ = 0xffff;
1929 *hwp++ = 0x0000;
1930 *hwp++ = 0xffff;
1931 *hwp++ = 0x0000;
1932 *hwp++ = 0xffff;
1933 *hwp++ = 0x0000;
1934 *hwp++ = 0xffff;
1935 *hwp++ = 0x0000;
1936 }
1937 } else {
1938 for (; row < 64; row++) {
1939 *hwp++ = 0x0000;
1940 *hwp++ = 0xffff;
1941 *hwp++ = 0x0000;
1942 *hwp++ = 0xffff;
1943 *hwp++ = 0x0000;
1944 *hwp++ = 0xffff;
1945 *hwp++ = 0x0000;
1946 *hwp++ = 0xffff;
1947 }
1948 }
1949
1950 free(image, M_TEMP);
1951 /* cv3d_setup_hwc(gp); */
1952 cv3d_hotx = info->hot.x;
1953 cv3d_hoty = info->hot.y;
1954
1955 /* One must not write twice per vertical blank :-( */
1956 VerticalRetraceWait(ba);
1957 cv3d_setspritepos(gp, &info->pos);
1958 }
1959 if (info->set & GRFSPRSET_CMAP) {
1960 volatile void *hwc;
1961 int test;
1962
1963 /* reset colour stack */
1964 test = RCrt(ba, CRT_ID_HWGC_MODE);
1965 __asm volatile("nop");
1966 switch (depth) {
1967 case 8:
1968 case 15:
1969 case 16:
1970 WCrt (ba, CRT_ID_HWGC_FG_STACK, 0);
1971 hwc = ba + CRT_ADDRESS_W;
1972 *hwc = 0;
1973 break;
1974 case 32:
1975 case 24:
1976 WCrt (ba, CRT_ID_HWGC_FG_STACK, 0);
1977 hwc = ba + CRT_ADDRESS_W;
1978 *hwc = 0;
1979 *hwc = 0;
1980 break;
1981 }
1982
1983 test = RCrt(ba, CRT_ID_HWGC_MODE);
1984 __asm volatile("nop");
1985 switch (depth) {
1986 case 8:
1987 WCrt (ba, CRT_ID_HWGC_BG_STACK, 1);
1988 hwc = ba + CRT_ADDRESS_W;
1989 *hwc = 1;
1990 break;
1991 case 15:
1992 case 16:
1993 WCrt (ba, CRT_ID_HWGC_BG_STACK, 0xff);
1994 hwc = ba + CRT_ADDRESS_W;
1995 *hwc = 0xff;
1996 break;
1997 case 32:
1998 case 24:
1999 WCrt (ba, CRT_ID_HWGC_BG_STACK, 0xff);
2000 hwc = ba + CRT_ADDRESS_W;
2001 *hwc = 0xff;
2002 *hwc = 0xff;
2003 break;
2004 }
2005 }
2006
2007 if (info->set & GRFSPRSET_ENABLE) {
2008 if (info->enable) {
2009 cv3d_cursor_on = 1;
2010 cv3d_setup_hwc(gp);
2011 /* WCrt(ba, CRT_ID_HWGC_MODE, 0x01); */
2012 } else
2013 WCrt(ba, CRT_ID_HWGC_MODE, 0x00);
2014 }
2015 if (info->set & GRFSPRSET_POS)
2016 cv3d_setspritepos(gp, &info->pos);
2017 if (info->set & GRFSPRSET_HOT) {
2018
2019 cv3d_hotx = info->hot.x;
2020 cv3d_hoty = info->hot.y;
2021 cv3d_setspritepos (gp, &info->pos);
2022 }
2023 return(0);
2024 }
2025
2026
2027 int
2028 cv3d_getspritemax(struct grf_softc *gp, struct grf_position *pos)
2029 {
2030
2031 pos->x = 64;
2032 pos->y = 64;
2033 return(0);
2034 }
2035
2036 #endif /* CV3D_HARDWARE_CURSOR */
2037
2038 #endif /* NGRFCV3D */
2039