75c4b3bf70
is now at offset 0xa0000.
864 lines
22 KiB
C
864 lines
22 KiB
C
/* $NetBSD: grfabs_et.c,v 1.11 1998/12/20 14:32:53 thomas Exp $ */
|
|
|
|
/*
|
|
* Copyright (c) 1996 Leo Weppelman.
|
|
* All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the distribution.
|
|
* 3. All advertising materials mentioning features or use of this software
|
|
* must display the following acknowledgement:
|
|
* This product includes software developed by Leo Weppelman.
|
|
* 4. The name of the author may not be used to endorse or promote products
|
|
* derived from this software without specific prior written permission
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
|
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
|
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
|
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
|
|
/*
|
|
* Most of the lower-level et4000 stuff was derived from:
|
|
* .../amiga/dev/grf_et.c
|
|
*
|
|
* Which was copyrighted by:
|
|
* Copyright (c) 1996 Tobias Abt
|
|
* Copyright (c) 1995 Ezra Story
|
|
* Copyright (c) 1995 Kari Mettinen
|
|
* Copyright (c) 1994 Markus Wild
|
|
* Copyright (c) 1994 Lutz Vieweg
|
|
*
|
|
* Thanks guys!
|
|
*
|
|
*/
|
|
#include <sys/param.h>
|
|
#include <sys/queue.h>
|
|
#include <sys/malloc.h>
|
|
#include <sys/device.h>
|
|
#include <sys/systm.h>
|
|
|
|
#include <vm/vm.h>
|
|
#include <vm/vm_kern.h>
|
|
|
|
/*
|
|
* For PCI probing...
|
|
*/
|
|
#include <dev/pci/pcireg.h>
|
|
#include <dev/pci/pcivar.h>
|
|
#include <dev/pci/pcidevs.h>
|
|
|
|
#include <machine/iomap.h>
|
|
#include <machine/video.h>
|
|
#include <machine/mfp.h>
|
|
#include <machine/cpu.h>
|
|
#include <atari/atari/device.h>
|
|
#include <atari/dev/grfioctl.h>
|
|
#include <atari/dev/grfabs_reg.h>
|
|
#include <atari/dev/grfabs_et.h>
|
|
#include <atari/dev/grf_etreg.h>
|
|
|
|
#define SAVEBUF_SIZE (32*1024 + sizeof(save_area_t))
|
|
|
|
/*
|
|
* Allow a 16Kb io-region and a 4MB frame buffer to be mapped. This
|
|
* is more or less required by the XFree server.
|
|
*/
|
|
#define REG_MAPPABLE (16 * 1024)
|
|
#define FRAME_MAPPABLE (4 * 1024 * 1024)
|
|
#define VGA_MAPPABLE (128 * 1024)
|
|
#define VGA_BASE 0xa0000
|
|
|
|
/*
|
|
* Where we map the PCI registers in the io-space (et6000)
|
|
* XXX: 0x400 would probably work too...
|
|
*/
|
|
#define PCI_IOBASE 0x800
|
|
/*
|
|
* Linear memory base, near the end of the pci area
|
|
*/
|
|
#define PCI_LINMEMBASE 0x0e000000
|
|
|
|
/*
|
|
* Function decls
|
|
*/
|
|
static void init_view __P((view_t *, bmap_t *, dmode_t *, box_t *));
|
|
static colormap_t *alloc_colormap __P((dmode_t *));
|
|
static void et6000_init __P((void));
|
|
static void et_display_view __P((view_t *));
|
|
static view_t *et_alloc_view __P((dmode_t *, dimen_t *, u_char));
|
|
static void et_boardinit __P((void));
|
|
static void et_free_view __P((view_t *));
|
|
static void et_loadmode __P((struct grfvideo_mode *, et_sv_reg_t *));
|
|
static void et_remove_view __P((view_t *));
|
|
static void et_save_view __P((view_t *));
|
|
static int et_use_colormap __P((view_t *, colormap_t *));
|
|
|
|
/*
|
|
* Our function switch table
|
|
*/
|
|
struct grfabs_sw et_vid_sw = {
|
|
et_display_view,
|
|
et_alloc_view,
|
|
et_free_view,
|
|
et_remove_view,
|
|
et_save_view,
|
|
et_use_colormap
|
|
};
|
|
|
|
static struct grfvideo_mode hw_modes[] = {
|
|
{
|
|
0, "", 25175000, /* num, descr, pix-clock */
|
|
640, 400, 4, /* width, height, depth */
|
|
632/8, 672/8, 688/8, 808/8, 768/8,/* HBS, HBE, HSS, HSE, HT */
|
|
399, 450, 408, 413, 449 /* VBS, VBE, VSS, VSE, VT */
|
|
},
|
|
{
|
|
0, "", 25175000, /* num, descr, pix-clock */
|
|
640, 480, 4, /* width, height, depth */
|
|
632/8, 672/8, 688/8, 752/8, 752/8,/* HBS, HBE, HSS, HSE, HT */
|
|
481, 522, 490, 498, 522 /* VBS, VBE, VSS, VSE, VT */
|
|
}
|
|
};
|
|
|
|
static dmode_t vid_modes[] = {
|
|
{ { NULL, NULL },
|
|
"640x400", { 640, 400 }, 1, (void*)&hw_modes[0], &et_vid_sw },
|
|
{ { NULL, NULL },
|
|
"640x480", { 640, 480 }, 1, (void*)&hw_modes[1], &et_vid_sw },
|
|
{ { NULL, NULL }, NULL, }
|
|
};
|
|
|
|
#define ET_NUMCLOCKS 32
|
|
|
|
static u_int et_clockfreqs[ET_NUMCLOCKS] = {
|
|
6293750, 7080500, 7875000, 8125000,
|
|
9000000, 9375000, 10000000, 11225000,
|
|
12587500, 14161000, 15750000, 16250000,
|
|
18000000, 18750000, 20000000, 22450000,
|
|
25175000, 28322000, 31500000, 32500000,
|
|
36000000, 37500000, 40000000, 44900000,
|
|
50350000, 56644000, 63000000, 65000000,
|
|
72000000, 75000000, 80000000, 89800000
|
|
};
|
|
|
|
static bmap_t con_bm; /* XXX */
|
|
|
|
struct grfabs_et_priv {
|
|
pcitag_t pci_tag;
|
|
volatile caddr_t regkva;
|
|
volatile caddr_t memkva;
|
|
u_int linbase;
|
|
int regsz;
|
|
int memsz;
|
|
int board_type;
|
|
} et_priv;
|
|
|
|
/*
|
|
* Board types:
|
|
*/
|
|
#define BT_ET4000 1
|
|
#define BT_ET6000 2
|
|
|
|
/*
|
|
* XXX: called from ite console init routine.
|
|
* Initialize list of posible video modes.
|
|
*/
|
|
void
|
|
et_probe_video(modelp)
|
|
MODES *modelp;
|
|
{
|
|
dmode_t *dm;
|
|
int i;
|
|
|
|
for (i = 0; (dm = &vid_modes[i])->name != NULL; i++) {
|
|
LIST_INSERT_HEAD(modelp, dm, link);
|
|
}
|
|
}
|
|
|
|
static void
|
|
et_display_view(v)
|
|
view_t *v;
|
|
{
|
|
dmode_t *dm = v->mode;
|
|
bmap_t *bm = v->bitmap;
|
|
int sv_size;
|
|
u_short *src, *dst;
|
|
save_area_t *sa;
|
|
|
|
if (dm->current_view && (dm->current_view != v)) {
|
|
/*
|
|
* Mark current view for this mode as no longer displayed
|
|
*/
|
|
dm->current_view->flags &= ~VF_DISPLAY;
|
|
}
|
|
dm->current_view = v;
|
|
v->flags |= VF_DISPLAY;
|
|
|
|
if ((sa = (save_area_t*)v->save_area) == NULL)
|
|
return; /* XXX: Can't happen.... */
|
|
|
|
/*
|
|
* Restore register settings and turn the plane pointer
|
|
* to the card-memory
|
|
*/
|
|
et_hwrest(&sa->sv_regs);
|
|
bm->plane = et_priv.memkva;
|
|
|
|
et_use_colormap(v, v->colormap);
|
|
|
|
/*
|
|
* Copy the backing store to card-memory
|
|
*/
|
|
sv_size = sa->fb_size;
|
|
src = sa->sv_fb;
|
|
dst = (u_short *)bm->plane;
|
|
while (sv_size--)
|
|
*dst++ = *src++;
|
|
}
|
|
|
|
void
|
|
et_remove_view(v)
|
|
view_t *v;
|
|
{
|
|
dmode_t *mode = v->mode;
|
|
|
|
if (mode->current_view == v) {
|
|
#if 0
|
|
if (v->flags & VF_DISPLAY)
|
|
panic("Cannot shutdown display\n"); /* XXX */
|
|
#endif
|
|
mode->current_view = NULL;
|
|
}
|
|
v->flags &= ~VF_DISPLAY;
|
|
}
|
|
|
|
void
|
|
et_save_view(v)
|
|
view_t *v;
|
|
{
|
|
bmap_t *bm = v->bitmap;
|
|
u_char font_height;
|
|
int sv_size;
|
|
u_short *src, *dst;
|
|
save_area_t *sa;
|
|
|
|
if (!atari_realconfig)
|
|
return;
|
|
|
|
if (RGfx(et_priv.regkva, GCT_ID_MISC) & 1) {
|
|
#if 0 /* XXX: Can't use printf here.... */
|
|
printf("et_save_view: Don't know how to save"
|
|
" a graphics mode\n");
|
|
#endif
|
|
return;
|
|
}
|
|
if (v->save_area == NULL)
|
|
v->save_area = malloc(SAVEBUF_SIZE, M_DEVBUF, M_NOWAIT);
|
|
|
|
/*
|
|
* Calculate the size of the copy
|
|
*/
|
|
font_height = RCrt(et_priv.regkva, CRT_ID_MAX_ROW_ADDRESS) & 0x1f;
|
|
sv_size = bm->bytes_per_row * (bm->rows / (font_height + 1));
|
|
sv_size = min(SAVEBUF_SIZE, sv_size);
|
|
|
|
/*
|
|
* Save all we need to know....
|
|
*/
|
|
sa = (save_area_t *)v->save_area;
|
|
et_hwsave(&sa->sv_regs);
|
|
sa->fb_size = sv_size;
|
|
src = (u_short *)bm->plane;
|
|
dst = sa->sv_fb;
|
|
while (sv_size--)
|
|
*dst++ = *src++;
|
|
bm->plane = (u_char *)sa->sv_fb;
|
|
}
|
|
|
|
void
|
|
et_free_view(v)
|
|
view_t *v;
|
|
{
|
|
if(v) {
|
|
et_remove_view(v);
|
|
if (v->colormap != &gra_con_cmap)
|
|
free(v->colormap, M_DEVBUF);
|
|
if (v->save_area != NULL)
|
|
free(v->save_area, M_DEVBUF);
|
|
if (v != &gra_con_view) {
|
|
free(v->bitmap, M_DEVBUF);
|
|
free(v, M_DEVBUF);
|
|
}
|
|
}
|
|
}
|
|
|
|
static int
|
|
et_use_colormap(v, cm)
|
|
view_t *v;
|
|
colormap_t *cm;
|
|
{
|
|
return (0); /* XXX: Nothing here for now... */
|
|
}
|
|
|
|
static view_t *
|
|
et_alloc_view(mode, dim, depth)
|
|
dmode_t *mode;
|
|
dimen_t *dim;
|
|
u_char depth;
|
|
{
|
|
view_t *v;
|
|
bmap_t *bm;
|
|
box_t box;
|
|
save_area_t *sa;
|
|
|
|
if (!atari_realconfig) {
|
|
v = &gra_con_view;
|
|
bm = &con_bm;
|
|
}
|
|
else {
|
|
v = malloc(sizeof(*v), M_DEVBUF, M_WAITOK);
|
|
bm = malloc(sizeof(*bm), M_DEVBUF, M_WAITOK);
|
|
}
|
|
v->bitmap = bm;
|
|
|
|
/*
|
|
* Initialize the bitmap
|
|
*/
|
|
bm->plane = et_priv.memkva;
|
|
bm->vga_address = (caddr_t)kvtop(et_priv.memkva);
|
|
bm->vga_base = VGA_BASE;
|
|
bm->hw_address = (caddr_t)(PCI_MEM_PHYS | et_priv.linbase);
|
|
bm->lin_base = et_priv.linbase;
|
|
bm->regs = et_priv.regkva;
|
|
bm->hw_regs = (caddr_t)kvtop(et_priv.regkva);
|
|
bm->reg_size = REG_MAPPABLE;
|
|
bm->phys_mappable = FRAME_MAPPABLE;
|
|
bm->vga_mappable = VGA_MAPPABLE;
|
|
|
|
bm->bytes_per_row = (mode->size.width * depth) / NBBY;
|
|
bm->rows = mode->size.height;
|
|
bm->depth = depth;
|
|
|
|
/*
|
|
* Allocate a save_area.
|
|
* Note: If atari_realconfig is false, no save area is (can be)
|
|
* allocated. This means that the plane is the video memory,
|
|
* which is what's wanted in this case.
|
|
*/
|
|
if (atari_realconfig) {
|
|
v->save_area = malloc(SAVEBUF_SIZE, M_DEVBUF, M_WAITOK);
|
|
sa = (save_area_t*)v->save_area;
|
|
sa->fb_size = 0;
|
|
bm->plane = (u_char *)sa->sv_fb;
|
|
et_loadmode(mode->data, &sa->sv_regs);
|
|
}
|
|
else v->save_area = NULL;
|
|
|
|
v->colormap = alloc_colormap(mode);
|
|
if (v->colormap) {
|
|
INIT_BOX(&box,0,0,mode->size.width,mode->size.height);
|
|
init_view(v, bm, mode, &box);
|
|
return (v);
|
|
}
|
|
if (v != &gra_con_view) {
|
|
free(v, M_DEVBUF);
|
|
free(bm, M_DEVBUF);
|
|
}
|
|
return (NULL);
|
|
}
|
|
|
|
static void
|
|
init_view(v, bm, mode, dbox)
|
|
view_t *v;
|
|
bmap_t *bm;
|
|
dmode_t *mode;
|
|
box_t *dbox;
|
|
{
|
|
v->bitmap = bm;
|
|
v->mode = mode;
|
|
v->flags = 0;
|
|
bcopy(dbox, &v->display, sizeof(box_t));
|
|
}
|
|
|
|
/* XXX: No more than a stub... */
|
|
static colormap_t *
|
|
alloc_colormap(dm)
|
|
dmode_t *dm;
|
|
{
|
|
colormap_t *cm;
|
|
int i;
|
|
|
|
cm = &gra_con_cmap;
|
|
cm->entry = gra_con_colors;
|
|
|
|
cm->first = 0;
|
|
cm->size = 2;
|
|
|
|
for (i = 0; i < 2; i++)
|
|
cm->entry[i] = gra_def_color16[i % 16];
|
|
return (cm);
|
|
}
|
|
|
|
/*
|
|
* Go look for a VGA card on the PCI-bus. This search is a
|
|
* stripped down version of the PCI-probe. It only looks on
|
|
* bus0 for et4000/et6000 cards. The first card found is used.
|
|
*/
|
|
int
|
|
et_probe_card()
|
|
{
|
|
pci_chipset_tag_t pc = NULL; /* XXX */
|
|
pcitag_t tag, csr;
|
|
int device, found, id, maxndevs;
|
|
|
|
found = 0;
|
|
tag = 0;
|
|
id = 0;
|
|
maxndevs = pci_bus_maxdevs(pc, 0);
|
|
|
|
for (device = 0; !found && (device < maxndevs); device++) {
|
|
|
|
tag = pci_make_tag(pc, 0, device, 0);
|
|
id = pci_conf_read(pc, tag, PCI_ID_REG);
|
|
if (id == 0 || id == 0xffffffff)
|
|
continue;
|
|
switch (PCI_PRODUCT(id)) {
|
|
case PCI_PRODUCT_TSENG_ET6000:
|
|
case PCI_PRODUCT_TSENG_ET4000_W32P_A:
|
|
case PCI_PRODUCT_TSENG_ET4000_W32P_B:
|
|
case PCI_PRODUCT_TSENG_ET4000_W32P_C:
|
|
case PCI_PRODUCT_TSENG_ET4000_W32P_D:
|
|
found = 1;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
if (!found)
|
|
return (0);
|
|
|
|
if (PCI_PRODUCT(id) == PCI_PRODUCT_TSENG_ET6000)
|
|
et_priv.board_type = BT_ET6000;
|
|
else et_priv.board_type = BT_ET4000;
|
|
|
|
/* Turn on the card */
|
|
pci_conf_write(pc, tag, PCI_MAPREG_START, PCI_LINMEMBASE);
|
|
if (et_priv.board_type == BT_ET6000)
|
|
pci_conf_write(pc, tag, PCI_MAPREG_START+4,
|
|
PCI_IOBASE | PCI_MAPREG_TYPE_IO);
|
|
csr = pci_conf_read(pc, tag, PCI_COMMAND_STATUS_REG);
|
|
csr |= (PCI_COMMAND_MEM_ENABLE|PCI_COMMAND_IO_ENABLE);
|
|
csr |= PCI_COMMAND_MASTER_ENABLE;
|
|
pci_conf_write(pc, tag, PCI_COMMAND_STATUS_REG, csr);
|
|
|
|
et_priv.pci_tag = tag;
|
|
|
|
/*
|
|
* The things below are setup in atari_init.c
|
|
*/
|
|
et_priv.regkva = (volatile caddr_t)pci_io_addr;
|
|
et_priv.memkva = (volatile caddr_t)pci_mem_addr;
|
|
et_priv.linbase = PCI_LINMEMBASE;
|
|
et_priv.memsz = PCI_VGA_SIZE;
|
|
et_priv.regsz = PCI_IO_SIZE;
|
|
|
|
if (found && !atari_realconfig) {
|
|
et_boardinit();
|
|
et_loadmode(&hw_modes[0], NULL);
|
|
return (1);
|
|
}
|
|
|
|
return (1);
|
|
}
|
|
|
|
static void
|
|
et_loadmode(mode, regs)
|
|
struct grfvideo_mode *mode;
|
|
et_sv_reg_t *regs;
|
|
{
|
|
unsigned short HDE, VDE;
|
|
int lace, dblscan;
|
|
int uplim, lowlim;
|
|
int i;
|
|
unsigned char clock, tmp;
|
|
volatile u_char *ba;
|
|
et_sv_reg_t loc_regs;
|
|
|
|
if (regs == NULL)
|
|
regs = &loc_regs;
|
|
|
|
ba = et_priv.regkva;
|
|
HDE = mode->disp_width / 8 - 1;
|
|
VDE = mode->disp_height - 1;
|
|
|
|
/* figure out whether lace or dblscan is needed */
|
|
|
|
uplim = mode->disp_height + (mode->disp_height / 4);
|
|
lowlim = mode->disp_height - (mode->disp_height / 4);
|
|
lace = (((mode->vtotal * 2) > lowlim)
|
|
&& ((mode->vtotal * 2) < uplim)) ? 1 : 0;
|
|
dblscan = (((mode->vtotal / 2) > lowlim)
|
|
&& ((mode->vtotal / 2) < uplim)) ? 1 : 0;
|
|
|
|
/* adjustments */
|
|
if (lace)
|
|
VDE /= 2;
|
|
|
|
regs->misc_output = 0x23; /* Page 0, Color mode */
|
|
regs->seg_sel = 0x00;
|
|
regs->state_ctl = 0x00;
|
|
|
|
regs->seq[SEQ_ID_RESET] = 0x03; /* reset off */
|
|
regs->seq[SEQ_ID_CLOCKING_MODE] = 0x21; /* Turn off screen */
|
|
regs->seq[SEQ_ID_MAP_MASK] = 0xff; /* Cpu writes all planes*/
|
|
regs->seq[SEQ_ID_CHAR_MAP_SELECT] = 0x00; /* Char. generator 0 */
|
|
regs->seq[SEQ_ID_MEMORY_MODE] = 0x0e; /* Seq. Memory mode */
|
|
|
|
/*
|
|
* Set the clock...
|
|
*/
|
|
for(clock = ET_NUMCLOCKS-1; clock > 0; clock--) {
|
|
if (et_clockfreqs[clock] <= mode->pixel_clock)
|
|
break;
|
|
}
|
|
regs->misc_output |= (clock & 3) << 2;
|
|
regs->aux_mode = 0xb4 | ((clock & 8) << 3);
|
|
regs->compat_6845 = (clock & 4) ? 0x0a : 0x08;
|
|
|
|
/*
|
|
* The display parameters...
|
|
*/
|
|
regs->crt[CRT_ID_HOR_TOTAL] = mode->htotal;
|
|
regs->crt[CRT_ID_HOR_DISP_ENA_END] = ((HDE >= mode->hblank_start)
|
|
? mode->hblank_stop - 1
|
|
: HDE);
|
|
regs->crt[CRT_ID_START_HOR_BLANK] = mode->hblank_start;
|
|
regs->crt[CRT_ID_END_HOR_BLANK] = (mode->hblank_stop & 0x1f) | 0x80;
|
|
regs->crt[CRT_ID_START_HOR_RETR] = mode->hsync_start;
|
|
regs->crt[CRT_ID_END_HOR_RETR] = (mode->hsync_stop & 0x1f)
|
|
| ((mode->hblank_stop & 0x20)
|
|
? 0x80 : 0x00);
|
|
regs->crt[CRT_ID_VER_TOTAL] = mode->vtotal;
|
|
regs->crt[CRT_ID_START_VER_RETR] = mode->vsync_start;
|
|
regs->crt[CRT_ID_END_VER_RETR] = (mode->vsync_stop & 0x0f) | 0x30;
|
|
regs->crt[CRT_ID_VER_DISP_ENA_END] = VDE;
|
|
regs->crt[CRT_ID_START_VER_BLANK] = mode->vblank_start;
|
|
regs->crt[CRT_ID_END_VER_BLANK] = mode->vblank_stop;
|
|
regs->crt[CRT_ID_MODE_CONTROL] = 0xab;
|
|
regs->crt[CRT_ID_START_ADDR_HIGH] = 0x00;
|
|
regs->crt[CRT_ID_START_ADDR_LOW] = 0x00;
|
|
regs->crt[CRT_ID_LINE_COMPARE] = 0xff;
|
|
regs->crt[CRT_ID_UNDERLINE_LOC] = 0x00;
|
|
regs->crt[CRT_ID_OFFSET] = mode->disp_width/16;
|
|
regs->crt[CRT_ID_MAX_ROW_ADDRESS] =
|
|
0x40 |
|
|
(dblscan ? 0x80 : 0x00) |
|
|
((mode->vblank_start & 0x200) ? 0x20 : 0x00);
|
|
regs->crt[CRT_ID_OVERFLOW] =
|
|
0x10 |
|
|
((mode->vtotal & 0x100) ? 0x01 : 0x00) |
|
|
((VDE & 0x100) ? 0x02 : 0x00) |
|
|
((mode->vsync_start & 0x100) ? 0x04 : 0x00) |
|
|
((mode->vblank_start & 0x100) ? 0x08 : 0x00) |
|
|
((mode->vtotal & 0x200) ? 0x20 : 0x00) |
|
|
((VDE & 0x200) ? 0x40 : 0x00) |
|
|
((mode->vsync_start & 0x200) ? 0x80 : 0x00);
|
|
regs->overfl_high =
|
|
0x10 |
|
|
((mode->vblank_start & 0x400) ? 0x01 : 0x00) |
|
|
((mode->vtotal & 0x400) ? 0x02 : 0x00) |
|
|
((VDE & 0x400) ? 0x04 : 0x00) |
|
|
((mode->vsync_start & 0x400) ? 0x08 : 0x00) |
|
|
(lace ? 0x80 : 0x00);
|
|
regs->hor_overfl =
|
|
((mode->htotal & 0x100) ? 0x01 : 0x00) |
|
|
((mode->hblank_start & 0x100) ? 0x04 : 0x00) |
|
|
((mode->hsync_start & 0x100) ? 0x10 : 0x00);
|
|
|
|
regs->grf[GCT_ID_SET_RESET] = 0x00;
|
|
regs->grf[GCT_ID_ENABLE_SET_RESET] = 0x00;
|
|
regs->grf[GCT_ID_COLOR_COMPARE] = 0x00;
|
|
regs->grf[GCT_ID_DATA_ROTATE] = 0x00;
|
|
regs->grf[GCT_ID_READ_MAP_SELECT] = 0x00;
|
|
regs->grf[GCT_ID_GRAPHICS_MODE] = mode->depth == 1 ? 0x00: 0x40;
|
|
regs->grf[GCT_ID_MISC] = 0x01;
|
|
regs->grf[GCT_ID_COLOR_XCARE] = 0x0f;
|
|
regs->grf[GCT_ID_BITMASK] = 0xff;
|
|
|
|
for (i = 0; i < 0x10; i++)
|
|
regs->attr[i] = i;
|
|
regs->attr[ACT_ID_ATTR_MODE_CNTL] = 0x01;
|
|
regs->attr[ACT_ID_OVERSCAN_COLOR] = 0x00;
|
|
regs->attr[ACT_ID_COLOR_PLANE_ENA] = 0x0f;
|
|
regs->attr[ACT_ID_HOR_PEL_PANNING] = 0x00;
|
|
regs->attr[ACT_ID_COLOR_SELECT] = 0x00;
|
|
regs->attr[ACT_ID_MISCELLANEOUS] = 0x00;
|
|
|
|
/*
|
|
* XXX: This works for depth == 4. I need some better docs
|
|
* to fix the other modes....
|
|
*/
|
|
/*
|
|
* What we need would be probe functions for RAMDAC/clock chip
|
|
*/
|
|
vgar(ba, VDAC_ADDRESS); /* clear old state */
|
|
vgar(ba, VDAC_MASK);
|
|
vgar(ba, VDAC_MASK);
|
|
vgar(ba, VDAC_MASK);
|
|
vgar(ba, VDAC_MASK);
|
|
|
|
vgaw(ba, VDAC_MASK, 0); /* set to palette */
|
|
vgar(ba, VDAC_ADDRESS); /* clear state */
|
|
|
|
vgaw(ba, VDAC_MASK, 0xff);
|
|
/*
|
|
* End of depth stuff
|
|
*/
|
|
|
|
/*
|
|
* Compute Hsync & Vsync polarity
|
|
* Note: This seems to be some kind of a black art :-(
|
|
*/
|
|
tmp = regs->misc_output & 0x3f;
|
|
#if 1 /* This is according to my BW monitor & Xfree... */
|
|
if (VDE < 400)
|
|
tmp |= 0x40; /* -hsync +vsync */
|
|
else if (VDE < 480)
|
|
tmp |= 0xc0; /* -hsync -vsync */
|
|
#else /* This is according to my color monitor.... */
|
|
if (VDE < 400)
|
|
tmp |= 0x00; /* +hsync +vsync */
|
|
else if (VDE < 480)
|
|
tmp |= 0x80; /* +hsync -vsync */
|
|
#endif
|
|
/* I'm unable to try the rest.... */
|
|
regs->misc_output = tmp;
|
|
|
|
if(regs == &loc_regs)
|
|
et_hwrest(regs);
|
|
}
|
|
|
|
static void
|
|
et_boardinit()
|
|
{
|
|
volatile u_char *ba;
|
|
int i, j;
|
|
|
|
ba = et_priv.regkva;
|
|
|
|
vgaw(ba, GREG_HERCULESCOMPAT, 0x03);
|
|
vgaw(ba, GREG_DISPMODECONTROL, 0xa0);
|
|
vgaw(ba, GREG_MISC_OUTPUT_W, 0x23);
|
|
|
|
WSeq(ba, SEQ_ID_RESET, 0x03);
|
|
WSeq(ba, SEQ_ID_CLOCKING_MODE, 0x21); /* 8 dot, Display off */
|
|
WSeq(ba, SEQ_ID_MAP_MASK, 0x0f);
|
|
WSeq(ba, SEQ_ID_CHAR_MAP_SELECT, 0x00);
|
|
WSeq(ba, SEQ_ID_MEMORY_MODE, 0x0e);
|
|
WSeq(ba, SEQ_ID_AUXILIARY_MODE, 0xf4);
|
|
|
|
WCrt(ba, CRT_ID_PRESET_ROW_SCAN, 0x00);
|
|
WCrt(ba, CRT_ID_CURSOR_START, 0x00);
|
|
WCrt(ba, CRT_ID_CURSOR_END, 0x08);
|
|
WCrt(ba, CRT_ID_START_ADDR_HIGH, 0x00);
|
|
WCrt(ba, CRT_ID_START_ADDR_LOW, 0x00);
|
|
WCrt(ba, CRT_ID_CURSOR_LOC_HIGH, 0x00);
|
|
WCrt(ba, CRT_ID_CURSOR_LOC_LOW, 0x00);
|
|
|
|
WCrt(ba, CRT_ID_UNDERLINE_LOC, 0x07);
|
|
WCrt(ba, CRT_ID_MODE_CONTROL, 0xa3);
|
|
WCrt(ba, CRT_ID_LINE_COMPARE, 0xff);
|
|
/*
|
|
* ET4000 special
|
|
*/
|
|
WCrt(ba, CRT_ID_RASCAS_CONFIG, 0x28);
|
|
WCrt(ba, CTR_ID_EXT_START, 0x00);
|
|
WCrt(ba, CRT_ID_6845_COMPAT, 0x08);
|
|
if (et_priv.board_type == BT_ET6000)
|
|
et6000_init();
|
|
else {
|
|
WCrt(ba, CRT_ID_VIDEO_CONFIG1, 0x43);
|
|
WCrt(ba, CRT_ID_VIDEO_CONFIG2, 0x09);
|
|
}
|
|
|
|
WCrt(ba, CRT_ID_HOR_OVERFLOW, 0x00);
|
|
|
|
WGfx(ba, GCT_ID_SET_RESET, 0x00);
|
|
WGfx(ba, GCT_ID_ENABLE_SET_RESET, 0x00);
|
|
WGfx(ba, GCT_ID_COLOR_COMPARE, 0x00);
|
|
WGfx(ba, GCT_ID_DATA_ROTATE, 0x00);
|
|
WGfx(ba, GCT_ID_READ_MAP_SELECT, 0x00);
|
|
WGfx(ba, GCT_ID_GRAPHICS_MODE, 0x40);
|
|
WGfx(ba, GCT_ID_MISC, 0x05);
|
|
WGfx(ba, GCT_ID_COLOR_XCARE, 0x0f);
|
|
WGfx(ba, GCT_ID_BITMASK, 0xff);
|
|
|
|
vgaw(ba, GREG_SEGMENTSELECT, 0x00);
|
|
|
|
for (i = 0; i < 0x10; i++)
|
|
WAttr(ba, i, i);
|
|
WAttr(ba, ACT_ID_ATTR_MODE_CNTL, 0x01);
|
|
WAttr(ba, ACT_ID_OVERSCAN_COLOR, 0x00);
|
|
WAttr(ba, ACT_ID_COLOR_PLANE_ENA, 0x0f);
|
|
WAttr(ba, ACT_ID_HOR_PEL_PANNING, 0x00);
|
|
WAttr(ba, ACT_ID_COLOR_SELECT, 0x00);
|
|
WAttr(ba, ACT_ID_MISCELLANEOUS, 0x00);
|
|
|
|
vgaw(ba, VDAC_MASK, 0xff);
|
|
|
|
#if 0 /* XXX: We like to do this: */
|
|
delay(200000);
|
|
#else /* But because we run before the delay is initialized: */
|
|
for(i = 0; i < 4000; i++)
|
|
for(j = 0; j < 400; j++);
|
|
#endif
|
|
|
|
/*
|
|
* colors initially set to greyscale
|
|
*/
|
|
vgaw(ba, VDAC_ADDRESS_W, 0);
|
|
for (i = 255; i >= 0; i--) {
|
|
vgaw(ba, VDAC_DATA, i);
|
|
vgaw(ba, VDAC_DATA, i);
|
|
vgaw(ba, VDAC_DATA, i);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Initialize the et6000 specific (PCI) registers. Try to do it like the
|
|
* video-bios would have done it, so things like Xservers get what they
|
|
* expect. Most info was kindly provided by Koen Gadeyne.
|
|
*
|
|
* XXX: not fit for programming beauty contest...
|
|
*/
|
|
static void
|
|
et6000_init()
|
|
{
|
|
|
|
volatile u_char *ba;
|
|
int i;
|
|
u_char dac_tab[] = { 0x7d,0x67, 0x5d,0x64, 0x56,0x63,
|
|
0x28,0x22, 0x79,0x49, 0x6f,0x47,
|
|
0x28,0x41, 0x6b,0x44, 0xfe,0xff,
|
|
0x00,0x00, 0x3d,0x23, 0x79,0x2e,
|
|
0xa8,0x00, 0x00,0x84 };
|
|
|
|
ba = et_priv.regkva + PCI_IOBASE;
|
|
|
|
ba[0x40] = 0x00; /* Use standard vga addressing */
|
|
ba[0x41] = 0x2a; /* Performance control */
|
|
ba[0x43] = 0x02; /* XCLK/SCLK config */
|
|
ba[0x44] = 0x11; /* RAS/CAS config */
|
|
ba[0x46] = 0x00; /* CRT display feature */
|
|
ba[0x58] = 0x00; /* Video Control 1 */
|
|
ba[0x59] = 0x04; /* Video Control 2 */
|
|
|
|
/*
|
|
* Setup a 'standard' CLKDAC
|
|
*/
|
|
ba[0x42] = 0x00; /* MCLK == CLK0 */
|
|
ba[0x67] = 0x00; /* Start filling from dac-reg 0 and up... */
|
|
for (i = 0; i < 0x0b; i++)
|
|
ba[0x69] = dac_tab[i];
|
|
}
|
|
|
|
void
|
|
et_hwsave(et_regs)
|
|
et_sv_reg_t *et_regs;
|
|
{
|
|
volatile u_char *ba;
|
|
int i, s;
|
|
|
|
ba = et_priv.regkva;
|
|
|
|
s = splhigh();
|
|
|
|
/*
|
|
* General VGA registers
|
|
*/
|
|
et_regs->misc_output = vgar(ba, GREG_MISC_OUTPUT_R);
|
|
for(i = 0; i < 25; i++)
|
|
et_regs->crt[i] = RCrt(ba, i);
|
|
for(i = 0; i < 21; i++)
|
|
et_regs->attr[i] = RAttr(ba, i | 0x20);
|
|
for(i = 0; i < 9; i++)
|
|
et_regs->grf[i] = RGfx(ba, i);
|
|
for(i = 0; i < 5; i++)
|
|
et_regs->seq[i] = RSeq(ba, i);
|
|
|
|
/*
|
|
* ET4000 extensions
|
|
*/
|
|
et_regs->ext_start = RCrt(ba, CTR_ID_EXT_START);
|
|
et_regs->compat_6845 = RCrt(ba, CRT_ID_6845_COMPAT);
|
|
et_regs->overfl_high = RCrt(ba, CRT_ID_OVERFLOW_HIGH);
|
|
et_regs->hor_overfl = RCrt(ba, CRT_ID_HOR_OVERFLOW);
|
|
et_regs->state_ctl = RSeq(ba, SEQ_ID_STATE_CONTROL);
|
|
et_regs->aux_mode = RSeq(ba, SEQ_ID_AUXILIARY_MODE);
|
|
et_regs->seg_sel = vgar(ba, GREG_SEGMENTSELECT);
|
|
|
|
s = splx(s);
|
|
}
|
|
|
|
void
|
|
et_hwrest(et_regs)
|
|
et_sv_reg_t *et_regs;
|
|
{
|
|
volatile u_char *ba;
|
|
int i, s;
|
|
|
|
ba = et_priv.regkva;
|
|
|
|
s = splhigh();
|
|
|
|
vgaw(ba, GREG_SEGMENTSELECT, 0);
|
|
vgaw(ba, GREG_MISC_OUTPUT_W, et_regs->misc_output);
|
|
|
|
/*
|
|
* General VGA registers
|
|
*/
|
|
for(i = 0; i < 5; i++)
|
|
WSeq(ba, i, et_regs->seq[i]);
|
|
|
|
/*
|
|
* Make sure we're allowed to write all crt-registers
|
|
*/
|
|
WCrt(ba, CRT_ID_END_VER_RETR,
|
|
et_regs->crt[CRT_ID_END_VER_RETR] & 0x7f);
|
|
for(i = 0; i < 25; i++)
|
|
WCrt(ba, i, et_regs->crt[i]);
|
|
for(i = 0; i < 9; i++)
|
|
WGfx(ba, i, et_regs->grf[i]);
|
|
for(i = 0; i < 21; i++)
|
|
WAttr(ba, i | 0x20, et_regs->attr[i]);
|
|
|
|
/*
|
|
* ET4000 extensions
|
|
*/
|
|
WSeq(ba, SEQ_ID_STATE_CONTROL, et_regs->state_ctl);
|
|
WSeq(ba, SEQ_ID_AUXILIARY_MODE, et_regs->aux_mode);
|
|
WCrt(ba, CTR_ID_EXT_START, et_regs->ext_start);
|
|
WCrt(ba, CRT_ID_6845_COMPAT, et_regs->compat_6845);
|
|
WCrt(ba, CRT_ID_OVERFLOW_HIGH, et_regs->overfl_high);
|
|
WCrt(ba, CRT_ID_HOR_OVERFLOW, et_regs->hor_overfl);
|
|
vgaw(ba, GREG_SEGMENTSELECT, et_regs->seg_sel);
|
|
|
|
i = et_regs->seq[SEQ_ID_CLOCKING_MODE] & ~0x20;
|
|
WSeq(ba, SEQ_ID_CLOCKING_MODE, i);
|
|
|
|
s = splx(s);
|
|
}
|