xref: /netbsd/sys/arch/atari/dev/grfabs_et.c (revision 95b880f3)
1 /*	$NetBSD: grfabs_et.c,v 1.32 2009/07/19 05:43:22 tsutsui Exp $	*/
2 
3 /*
4  * Copyright (c) 1996 Leo Weppelman.
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 Leo Weppelman.
18  * 4. The name of the author may not be used to endorse or promote products
19  *    derived from this software without specific prior written permission
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
26  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
30  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32 
33 /*
34  * Most of the lower-level et4000 stuff was derived from:
35  *	.../amiga/dev/grf_et.c
36  *
37  * Which was copyrighted by:
38  *	Copyright (c) 1996 Tobias Abt
39  *	Copyright (c) 1995 Ezra Story
40  *	Copyright (c) 1995 Kari Mettinen
41  *	Copyright (c) 1994 Markus Wild
42  *	Copyright (c) 1994 Lutz Vieweg
43  *
44  * Thanks guys!
45  *
46  */
47 
48 #include <sys/cdefs.h>
49 __KERNEL_RCSID(0, "$NetBSD: grfabs_et.c,v 1.32 2009/07/19 05:43:22 tsutsui Exp $");
50 
51 #include <sys/param.h>
52 #include <sys/queue.h>
53 #include <sys/malloc.h>
54 #include <sys/device.h>
55 #include <sys/systm.h>
56 
57 #include <uvm/uvm_extern.h>
58 
59 /*
60  * For PCI probing...
61  */
62 #include <dev/pci/pcireg.h>
63 #include <dev/pci/pcivar.h>
64 #include <dev/pci/pcidevs.h>
65 
66 #include <machine/iomap.h>
67 #include <machine/video.h>
68 #include <machine/mfp.h>
69 #include <machine/cpu.h>
70 #include <atari/atari/device.h>
71 #include <atari/dev/grfioctl.h>
72 #include <atari/dev/grfabs_reg.h>
73 #include <atari/dev/grfabs_et.h>
74 #include <atari/dev/grf_etreg.h>
75 
76 #define	SAVEBUF_SIZE	(32*1024 + sizeof(save_area_t))
77 
78 /*
79  * Allow a 16Kb io-region and a 4MB frame buffer to be mapped. This
80  * is more or less required by the XFree server.
81  */
82 #define	REG_MAPPABLE	(16 * 1024)
83 #define	FRAME_MAPPABLE	(4 * 1024 * 1024)
84 #define VGA_MAPPABLE	(128 * 1024)
85 #define VGA_BASE	0xa0000
86 
87 /*
88  * Linear memory base, near the end of the pci area
89  */
90 #define PCI_LINMEMBASE  0x0e000000
91 
92 /*
93  * Function decls
94  */
95 static void       init_view(view_t *, bmap_t *, dmode_t *, box_t *);
96 static colormap_t *alloc_colormap(dmode_t *);
97 static void	  et_display_view(view_t *);
98 static view_t	  *et_alloc_view(dmode_t *, dimen_t *, u_char);
99 static void	  et_free_view(view_t *);
100 static void	  et_loadmode(struct grfvideo_mode *, et_sv_reg_t *);
101 static void	  et_remove_view(view_t *);
102 static void	  et_save_view(view_t *);
103 static int	  et_use_colormap(view_t *, colormap_t *);
104 
105 /*
106  * Our function switch table
107  */
108 struct grfabs_sw et_vid_sw = {
109 	et_display_view,
110 	et_alloc_view,
111 	et_free_view,
112 	et_remove_view,
113 	et_save_view,
114 	et_use_colormap
115 };
116 
117 static struct grfvideo_mode hw_modes[] = {
118     {
119 	0, "", 22450000,		/* num, descr, pix-clock	*/
120 	640, 400, 4,			/* width, height, depth		*/
121 	632/8, 672/8, 688/8, 808/8, 768/8,/* HBS, HBE, HSS, HSE, HT	*/
122 	399, 450, 408, 413, 449		/* VBS, VBE, VSS, VSE, VT	*/
123     },
124     {
125 	0, "", 25175000,		/* num, descr, pix-clock	*/
126 	640, 480, 4,			/* width, height, depth		*/
127 	632/8, 672/8, 688/8, 752/8, 752/8,/* HBS, HBE, HSS, HSE, HT	*/
128 	481, 522, 490, 498, 522		/* VBS, VBE, VSS, VSE, VT	*/
129     }
130 };
131 
132 static dmode_t vid_modes[] = {
133     { { NULL, NULL },
134 	"640x400", { 640, 400 }, 1, (void*)&hw_modes[0], &et_vid_sw },
135     { { NULL, NULL },
136 	"640x480", { 640, 480 }, 1, (void*)&hw_modes[1], &et_vid_sw },
137     { { NULL, NULL }, NULL,  }
138 };
139 
140 #define	ET_NUMCLOCKS	32
141 
142 static u_int et_clockfreqs[ET_NUMCLOCKS] = {
143 	 6293750,  7080500,  7875000,  8125000,
144 	 9000000,  9375000, 10000000, 11225000,
145 	12587500, 14161000, 15750000, 16250000,
146 	18000000, 18750000, 20000000, 22450000,
147 	25175000, 28322000, 31500000, 32500000,
148 	36000000, 37500000, 40000000, 44900000,
149 	50350000, 56644000, 63000000, 65000000,
150 	72000000, 75000000, 80000000, 89800000
151 };
152 
153 static bmap_t	con_bm; /* XXX */
154 
155 struct grfabs_et_priv {
156 	pcitag_t		pci_tag;
157 	void			*regkva;
158 	void 			*memkva;
159 	u_int			linbase;
160 	int			regsz;
161 	int			memsz;
162 	int			board_type;
163 } et_priv;
164 
165 /*
166  * Board types:
167  */
168 #define	BT_ET4000		1
169 #define	BT_ET6000		2
170 
171 /*
172  * XXX: called from ite console init routine.
173  * Initialize list of posible video modes.
174  */
175 void
176 et_probe_video(MODES *modelp)
177 {
178 	dmode_t	*dm;
179 	int	i;
180 
181 	for (i = 0; (dm = &vid_modes[i])->name != NULL; i++) {
182 		LIST_INSERT_HEAD(modelp, dm, link);
183 	}
184 }
185 
186 static void
187 et_display_view(view_t *v)
188 {
189 	dmode_t		*dm = v->mode;
190 	bmap_t		*bm = v->bitmap;
191 	int		sv_size;
192 	u_short		*src, *dst;
193 	save_area_t	*sa;
194 
195 	if (dm->current_view && (dm->current_view != v)) {
196 		/*
197 		 * Mark current view for this mode as no longer displayed
198 		 */
199 		dm->current_view->flags &= ~VF_DISPLAY;
200 	}
201 	dm->current_view = v;
202 	v->flags |= VF_DISPLAY;
203 
204 	if ((sa = (save_area_t*)v->save_area) == NULL)
205 		return; /* XXX: Can't happen.... */
206 
207 	/*
208 	 * Restore register settings and turn the plane pointer
209 	 * to the card-memory
210 	 */
211 	et_hwrest(&sa->sv_regs);
212 	bm->plane = et_priv.memkva;
213 
214 	et_use_colormap(v, v->colormap);
215 
216 	/*
217 	 * Copy the backing store to card-memory
218 	 */
219 	sv_size = sa->fb_size;
220 	src     = sa->sv_fb;
221 	dst     = (u_short *)bm->plane;
222 	while (sv_size--)
223 		*dst++ = *src++;
224 }
225 
226 void
227 et_remove_view(view_t *v)
228 {
229 	dmode_t *mode = v->mode;
230 
231 	if (mode->current_view == v) {
232 #if 0
233 		if (v->flags & VF_DISPLAY)
234 			panic("Cannot shutdown display"); /* XXX */
235 #endif
236 		mode->current_view = NULL;
237 	}
238 	v->flags &= ~VF_DISPLAY;
239 }
240 
241 void
242 et_save_view(view_t *v)
243 {
244 	bmap_t		*bm = v->bitmap;
245 	u_char		font_height;
246 	int		sv_size;
247 	u_short		*src, *dst;
248 	save_area_t	*sa;
249 	volatile u_char *ba;
250 
251 	if (!atari_realconfig)
252 		return;
253 
254 	ba = et_priv.regkva;
255 
256 	if (RGfx(ba, GCT_ID_MISC) & 1) {
257 #if 0 /* XXX: Can't use printf here.... */
258 		printf("et_save_view: Don't know how to save"
259 			" a graphics mode\n");
260 #endif
261 		return;
262 	}
263 	if (v->save_area == NULL)
264 		v->save_area = malloc(SAVEBUF_SIZE, M_DEVBUF, M_NOWAIT);
265 
266 	/*
267 	 * Calculate the size of the copy
268 	 */
269 	font_height = RCrt(ba, CRT_ID_MAX_ROW_ADDRESS) & 0x1f;
270 	sv_size = bm->bytes_per_row * (bm->rows / (font_height + 1));
271 	sv_size = min(SAVEBUF_SIZE, sv_size);
272 
273 	/*
274 	 * Save all we need to know....
275 	 */
276 	sa  = (save_area_t *)v->save_area;
277 	et_hwsave(&sa->sv_regs);
278 	sa->fb_size = sv_size;
279 	src = (u_short *)bm->plane;
280 	dst = sa->sv_fb;
281 	while (sv_size--)
282 		*dst++ = *src++;
283 	bm->plane = (u_char *)sa->sv_fb;
284 }
285 
286 void
287 et_free_view(view_t *v)
288 {
289 	if(v) {
290 		et_remove_view(v);
291 		if (v->colormap != &gra_con_cmap)
292 			free(v->colormap, M_DEVBUF);
293 		if (v->save_area != NULL)
294 			free(v->save_area, M_DEVBUF);
295 		if (v != &gra_con_view) {
296 			free(v->bitmap, M_DEVBUF);
297 			free(v, M_DEVBUF);
298 		}
299 	}
300 }
301 
302 static int
303 et_use_colormap(view_t *v, colormap_t *cm)
304 {
305 	return (0); /* XXX: Nothing here for now... */
306 }
307 
308 static view_t *
309 et_alloc_view(dmode_t *mode, dimen_t *dim, u_char depth)
310 {
311 	view_t		*v;
312 	bmap_t		*bm;
313 	box_t		box;
314 	save_area_t	*sa;
315 
316 	if (!atari_realconfig) {
317 		v  = &gra_con_view;
318 		bm = &con_bm;
319 	}
320 	else {
321 		v  = malloc(sizeof(*v), M_DEVBUF, M_WAITOK);
322 		bm = malloc(sizeof(*bm), M_DEVBUF, M_WAITOK);
323 	}
324 	v->bitmap = bm;
325 
326 	/*
327 	 * Initialize the bitmap
328 	 */
329 	bm->plane         = et_priv.memkva;
330 	bm->vga_address   = (void *)kvtop(et_priv.memkva);
331 	bm->vga_base      = VGA_BASE;
332 	bm->hw_address    = (void *)(PCI_MEM_PHYS | et_priv.linbase);
333 	bm->lin_base      = et_priv.linbase;
334 	bm->regs          = et_priv.regkva;
335 	bm->hw_regs       = (void *)kvtop(et_priv.regkva);
336 	bm->reg_size      = REG_MAPPABLE;
337 	bm->phys_mappable = FRAME_MAPPABLE;
338 	bm->vga_mappable  = VGA_MAPPABLE;
339 
340 	bm->bytes_per_row = (mode->size.width * depth) / NBBY;
341 	bm->rows          = mode->size.height;
342 	bm->depth         = depth;
343 
344 	/*
345 	 * Allocate a save_area.
346 	 * Note: If atari_realconfig is false, no save area is (can be)
347 	 * allocated. This means that the plane is the video memory,
348 	 * which is what's wanted in this case.
349 	 */
350 	if (atari_realconfig) {
351 		v->save_area = malloc(SAVEBUF_SIZE, M_DEVBUF, M_WAITOK);
352 		sa           = (save_area_t*)v->save_area;
353 		sa->fb_size  = 0;
354 		bm->plane    = (u_char *)sa->sv_fb;
355 		et_loadmode(mode->data, &sa->sv_regs);
356 	}
357 	else v->save_area = NULL;
358 
359 	v->colormap = alloc_colormap(mode);
360 	if (v->colormap) {
361 		INIT_BOX(&box,0,0,mode->size.width,mode->size.height);
362 		init_view(v, bm, mode, &box);
363 		return (v);
364 	}
365 	if (v != &gra_con_view) {
366 		free(v, M_DEVBUF);
367 		free(bm, M_DEVBUF);
368 	}
369 	return (NULL);
370 }
371 
372 static void
373 init_view(view_t *v, bmap_t *bm, dmode_t *mode, box_t *dbox)
374 {
375 	v->bitmap    = bm;
376 	v->mode      = mode;
377 	v->flags     = 0;
378 	memcpy(&v->display, dbox, sizeof(box_t));
379 }
380 
381 /* XXX: No more than a stub... */
382 static colormap_t *
383 alloc_colormap(dmode_t *dm)
384 {
385 	colormap_t	*cm;
386 	int		i;
387 
388 	cm = &gra_con_cmap;
389 	cm->entry = gra_con_colors;
390 
391 	cm->first = 0;
392 	cm->size  = 2;
393 
394 	for (i = 0; i < 2; i++)
395 		cm->entry[i] = gra_def_color16[i % 16];
396 	return (cm);
397 }
398 
399 /*
400  * Go look for a VGA card on the PCI-bus. This search is a
401  * stripped down version of the PCI-probe. It only looks on
402  * bus0 for et4000/et6000 cards. The first card found is used.
403  */
404 int
405 et_probe_card(void)
406 {
407 	pci_chipset_tag_t	pc = NULL; /* XXX */
408 	pcitag_t		tag;
409 	int			device, found, id, maxndevs;
410 
411 	found    = 0;
412 	tag      = 0;
413 	id       = 0;
414 	maxndevs = pci_bus_maxdevs(pc, 0);
415 
416 	for (device = 0; !found && (device < maxndevs); device++) {
417 
418 		tag = pci_make_tag(pc, 0, device, 0);
419 		id  = pci_conf_read(pc, tag, PCI_ID_REG);
420 		if (id == 0 || id == 0xffffffff)
421 			continue;
422 		switch (PCI_PRODUCT(id)) {
423 			case PCI_PRODUCT_TSENG_ET6000:
424 			case PCI_PRODUCT_TSENG_ET4000_W32P_A:
425 			case PCI_PRODUCT_TSENG_ET4000_W32P_B:
426 			case PCI_PRODUCT_TSENG_ET4000_W32P_C:
427 			case PCI_PRODUCT_TSENG_ET4000_W32P_D:
428 				found = 1;
429 				break;
430 			default:
431 				break;
432 		}
433 	}
434 	if (!found)
435 		return (0);
436 
437 	if (PCI_PRODUCT(id) ==  PCI_PRODUCT_TSENG_ET6000)
438 		et_priv.board_type = BT_ET6000;
439 	else {
440 #ifdef ET4000_HAS_2MB_MEM
441 		volatile u_char *ba;
442 #endif
443 
444 		et_priv.board_type = BT_ET4000;
445 
446 #ifdef ET4000_HAS_2MB_MEM
447 		/* set KEY to access the tseng private registers */
448 		ba = (volatile void *)pci_io_addr;
449 		vgaw(ba, GREG_HERCULESCOMPAT, 0x03);
450 		vgaw(ba, GREG_DISPMODECONTROL, 0xa0);
451 
452 		/* enable memory interleave */
453 		WCrt(ba, CRT_ID_RASCAS_CONFIG, 0xa0);
454 		WCrt(ba, CRT_ID_VIDEO_CONFIG2, 0x89);
455 #endif
456 	}
457 
458 	et_priv.pci_tag = tag;
459 
460 	/*
461 	 * The things below are setup in atari_init.c
462 	 */
463 	et_priv.regkva  = (void *)pci_io_addr;
464 	et_priv.memkva  = (void *)pci_mem_addr;
465 	et_priv.linbase = PCI_LINMEMBASE; /* XXX pci_conf_read??? */
466 	et_priv.memsz   = PCI_VGA_SIZE;
467 	et_priv.regsz   = PCI_IO_SIZE;
468 
469 	if (!atari_realconfig) {
470 		et_loadmode(&hw_modes[0], NULL);
471 		return (1);
472 	}
473 
474 	return (1);
475 }
476 
477 static void
478 et_loadmode(struct grfvideo_mode *mode, et_sv_reg_t *regs)
479 {
480 	unsigned short	HDE, VDE;
481 	int	    	lace, dblscan;
482 	int     	uplim, lowlim;
483 	int		i;
484 	unsigned char	clock, tmp;
485 	volatile u_char	*ba;
486 	et_sv_reg_t	loc_regs;
487 
488 	if (regs == NULL)
489 		regs = &loc_regs;
490 
491 	ba  = et_priv.regkva;
492 	HDE = mode->disp_width / 8 - 1;
493 	VDE = mode->disp_height - 1;
494 
495 	/* figure out whether lace or dblscan is needed */
496 
497 	uplim   = mode->disp_height + (mode->disp_height / 4);
498 	lowlim  = mode->disp_height - (mode->disp_height / 4);
499 	lace    = (((mode->vtotal * 2) > lowlim)
500 		   && ((mode->vtotal * 2) < uplim)) ? 1 : 0;
501 	dblscan = (((mode->vtotal / 2) > lowlim)
502 		   && ((mode->vtotal / 2) < uplim)) ? 1 : 0;
503 
504 	/* adjustments */
505 	if (lace)
506 		VDE /= 2;
507 
508 	regs->misc_output = 0x23; /* Page 0, Color mode */
509 	regs->seg_sel     = 0x00;
510 	regs->state_ctl   = 0x00;
511 
512 	regs->seq[SEQ_ID_RESET]           = 0x03; /* reset off		*/
513 	regs->seq[SEQ_ID_CLOCKING_MODE]   = 0x21; /* Turn off screen	*/
514 	regs->seq[SEQ_ID_MAP_MASK]        = 0xff; /* CPU writes all planes*/
515 	regs->seq[SEQ_ID_CHAR_MAP_SELECT] = 0x00; /* Char. generator 0	*/
516 	regs->seq[SEQ_ID_MEMORY_MODE]     = 0x0e; /* Seq. Memory mode	*/
517 
518 	/*
519 	 * Set the clock...
520 	 */
521 	for(clock = ET_NUMCLOCKS-1; clock > 0; clock--) {
522 		if (et_clockfreqs[clock] <= mode->pixel_clock)
523 			break;
524 	}
525 	regs->misc_output |= (clock & 3) << 2;
526 	regs->aux_mode     = 0xb4 | ((clock & 8) << 3);
527 	regs->compat_6845  = (clock & 4) ? 0x0a : 0x08;
528 
529 	/*
530 	 * The display parameters...
531 	 */
532 	regs->crt[CRT_ID_HOR_TOTAL]        =  mode->htotal;
533 	regs->crt[CRT_ID_HOR_DISP_ENA_END] = ((HDE >= mode->hblank_start)
534 						? mode->hblank_stop - 1
535 						: HDE);
536 	regs->crt[CRT_ID_START_HOR_BLANK]  = mode->hblank_start;
537 	regs->crt[CRT_ID_END_HOR_BLANK]    = (mode->hblank_stop & 0x1f) | 0x80;
538 	regs->crt[CRT_ID_START_HOR_RETR]   = mode->hsync_start;
539 	regs->crt[CRT_ID_END_HOR_RETR]     = (mode->hsync_stop & 0x1f)
540 						| ((mode->hblank_stop & 0x20)
541 							? 0x80 : 0x00);
542 	regs->crt[CRT_ID_VER_TOTAL]        = mode->vtotal;
543 	regs->crt[CRT_ID_START_VER_RETR]   = mode->vsync_start;
544 	regs->crt[CRT_ID_END_VER_RETR]     = (mode->vsync_stop & 0x0f) | 0x30;
545 	regs->crt[CRT_ID_VER_DISP_ENA_END] = VDE;
546 	regs->crt[CRT_ID_START_VER_BLANK]  = mode->vblank_start;
547 	regs->crt[CRT_ID_END_VER_BLANK]    = mode->vblank_stop;
548 	regs->crt[CRT_ID_MODE_CONTROL]     = 0xab;
549 	regs->crt[CRT_ID_START_ADDR_HIGH]  = 0x00;
550 	regs->crt[CRT_ID_START_ADDR_LOW]   = 0x00;
551 	regs->crt[CRT_ID_LINE_COMPARE]     = 0xff;
552 	regs->crt[CRT_ID_UNDERLINE_LOC]    = 0x00;
553 	regs->crt[CRT_ID_PRESET_ROW_SCAN]  = 0x00;
554 	regs->crt[CRT_ID_OFFSET]           = mode->disp_width/16;
555 	regs->crt[CRT_ID_MAX_ROW_ADDRESS]  =
556 		0x40 |
557 		(dblscan ? 0x80 : 0x00) |
558 		((mode->vblank_start & 0x200) ? 0x20 : 0x00);
559 	regs->crt[CRT_ID_OVERFLOW] =
560 		0x10 |
561 		((mode->vtotal       & 0x100) ? 0x01 : 0x00) |
562 		((VDE                & 0x100) ? 0x02 : 0x00) |
563 		((mode->vsync_start  & 0x100) ? 0x04 : 0x00) |
564 		((mode->vblank_start & 0x100) ? 0x08 : 0x00) |
565 		((mode->vtotal       & 0x200) ? 0x20 : 0x00) |
566 		((VDE                & 0x200) ? 0x40 : 0x00) |
567 		((mode->vsync_start  & 0x200) ? 0x80 : 0x00);
568 	regs->overfl_high =
569 		0x10 |
570 		((mode->vblank_start & 0x400) ? 0x01 : 0x00) |
571 		((mode->vtotal       & 0x400) ? 0x02 : 0x00) |
572 		((VDE                & 0x400) ? 0x04 : 0x00) |
573 		((mode->vsync_start  & 0x400) ? 0x08 : 0x00) |
574 		(lace ? 0x80 : 0x00);
575 	regs->hor_overfl =
576 		((mode->htotal       & 0x100) ? 0x01 : 0x00) |
577 		((mode->hblank_start & 0x100) ? 0x04 : 0x00) |
578 		((mode->hsync_start  & 0x100) ? 0x10 : 0x00);
579 
580 	regs->grf[GCT_ID_SET_RESET]        = 0x00;
581 	regs->grf[GCT_ID_ENABLE_SET_RESET] = 0x00;
582 	regs->grf[GCT_ID_COLOR_COMPARE]    = 0x00;
583 	regs->grf[GCT_ID_DATA_ROTATE]      = 0x00;
584 	regs->grf[GCT_ID_READ_MAP_SELECT]  = 0x00;
585 	regs->grf[GCT_ID_GRAPHICS_MODE]    = mode->depth == 1 ? 0x00: 0x40;
586 	regs->grf[GCT_ID_MISC]             = 0x01;
587 	regs->grf[GCT_ID_COLOR_XCARE]      = 0x0f;
588 	regs->grf[GCT_ID_BITMASK]          = 0xff;
589 
590 	for (i = 0; i < 0x10; i++)
591 		regs->attr[i] = i;
592 	regs->attr[ACT_ID_ATTR_MODE_CNTL]  = 0x01;
593 	regs->attr[ACT_ID_OVERSCAN_COLOR]  = 0x00;
594 	regs->attr[ACT_ID_COLOR_PLANE_ENA] = 0x0f;
595 	regs->attr[ACT_ID_HOR_PEL_PANNING] = 0x00;
596 	regs->attr[ACT_ID_COLOR_SELECT]    = 0x00;
597 	regs->attr[ACT_ID_MISCELLANEOUS]   = 0x00;
598 
599 	/*
600 	 * XXX: This works for depth == 4. I need some better docs
601 	 * to fix the other modes....
602 	 */
603 	/*
604 	 * What we need would be probe functions for RAMDAC/clock chip
605 	 */
606 	vgar(ba, VDAC_ADDRESS);		/* clear old state */
607 	vgar(ba, VDAC_MASK);
608 	vgar(ba, VDAC_MASK);
609 	vgar(ba, VDAC_MASK);
610 	vgar(ba, VDAC_MASK);
611 
612 	vgaw(ba, VDAC_MASK, 0);		/* set to palette */
613 	vgar(ba, VDAC_ADDRESS);		/* clear state */
614 
615 	vgaw(ba, VDAC_MASK, 0xff);
616 	/*
617 	 * End of depth stuff
618 	 */
619 
620 	/*
621 	 * Compute Hsync & Vsync polarity
622 	 * Note: This seems to be some kind of a black art :-(
623 	 */
624 	tmp = regs->misc_output & 0x3f;
625 #if 1 /* This is according to my BW monitor & Xfree... */
626 	if (VDE < 400)
627 		tmp |= 0x40;	/* -hsync +vsync */
628 	else if (VDE < 480)
629 		tmp |= 0xc0;	/* -hsync -vsync */
630 #else /* This is according to my color monitor.... */
631 	if (VDE < 400)
632 		tmp |= 0x00;	/* +hsync +vsync */
633 	else if (VDE < 480)
634 		tmp |= 0x80;	/* +hsync -vsync */
635 #endif
636 	/* I'm unable to try the rest.... */
637 	regs->misc_output = tmp;
638 
639 	if(regs == &loc_regs)
640 		et_hwrest(regs);
641 }
642 
643 void
644 et_hwsave(et_sv_reg_t *et_regs)
645 {
646 	volatile u_char *ba;
647 	int		i, s;
648 
649 	ba = et_priv.regkva;
650 
651 	s = splhigh();
652 
653 	/*
654 	 * General VGA registers
655 	 */
656 	et_regs->misc_output = vgar(ba, GREG_MISC_OUTPUT_R);
657 	for(i = 0; i < 25; i++)
658 		et_regs->crt[i]  = RCrt(ba, i);
659 	for(i = 0; i < 21; i++)
660 		et_regs->attr[i] = RAttr(ba, i | 0x20);
661 	for(i = 0; i < 9; i++)
662 		et_regs->grf[i]  = RGfx(ba, i);
663 	for(i = 0; i < 5; i++)
664 		et_regs->seq[i]  = RSeq(ba, i);
665 
666 	/*
667 	 * ET4000 extensions
668 	 */
669 	et_regs->ext_start   = RCrt(ba, CTR_ID_EXT_START);
670 	et_regs->compat_6845 = RCrt(ba, CRT_ID_6845_COMPAT);
671 	et_regs->overfl_high = RCrt(ba, CRT_ID_OVERFLOW_HIGH);
672 	et_regs->hor_overfl  = RCrt(ba, CRT_ID_HOR_OVERFLOW);
673 	et_regs->state_ctl   = RSeq(ba, SEQ_ID_STATE_CONTROL);
674 	et_regs->aux_mode    = RSeq(ba, SEQ_ID_AUXILIARY_MODE);
675 	et_regs->seg_sel     = vgar(ba, GREG_SEGMENTSELECT);
676 
677 	splx(s);
678 }
679 
680 void
681 et_hwrest(et_sv_reg_t *et_regs)
682 {
683 	volatile u_char *ba;
684 	int		i, s;
685 
686 	ba = et_priv.regkva;
687 
688 	s = splhigh();
689 
690 	vgaw(ba, GREG_SEGMENTSELECT, 0);
691 	vgaw(ba, GREG_MISC_OUTPUT_W, et_regs->misc_output);
692 
693 	/*
694 	 * General VGA registers
695 	 */
696 	WSeq(ba, SEQ_ID_RESET, 0x01);
697 	for(i = 1; i < 5; i++)
698 		WSeq(ba, i, et_regs->seq[i]);
699 	WSeq(ba, SEQ_ID_RESET, 0x03);
700 
701 	/*
702 	 * Make sure we're allowed to write all crt-registers
703 	 */
704 	WCrt(ba, CRT_ID_END_VER_RETR,
705 		et_regs->crt[CRT_ID_END_VER_RETR] & 0x7f);
706 	for(i = 0; i < 25; i++)
707 		WCrt(ba, i, et_regs->crt[i]);
708 	for(i = 0; i < 9; i++)
709 		WGfx(ba, i, et_regs->grf[i]);
710 	for(i = 0; i < 21; i++)
711 		WAttr(ba, i | 0x20, et_regs->attr[i]);
712 
713 	/*
714 	 * ET4000 extensions
715 	 */
716 	WSeq(ba, SEQ_ID_STATE_CONTROL, et_regs->state_ctl);
717 	WSeq(ba, SEQ_ID_AUXILIARY_MODE, et_regs->aux_mode);
718 	WCrt(ba, CTR_ID_EXT_START, et_regs->ext_start);
719 	WCrt(ba, CRT_ID_6845_COMPAT, et_regs->compat_6845);
720 	WCrt(ba, CRT_ID_OVERFLOW_HIGH, et_regs->overfl_high);
721 	WCrt(ba, CRT_ID_HOR_OVERFLOW, et_regs->hor_overfl);
722 	vgaw(ba, GREG_SEGMENTSELECT, et_regs->seg_sel);
723 
724 	i = et_regs->seq[SEQ_ID_CLOCKING_MODE] & ~0x20;
725 	WSeq(ba, SEQ_ID_CLOCKING_MODE, i);
726 
727 	splx(s);
728 }
729