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