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