2016-11-25 17:18:40 +01:00
|
|
|
/*
|
|
|
|
* This file is part of the UCB release of Plan 9. It is subject to the license
|
|
|
|
* terms in the LICENSE file found in the top-level directory of this
|
|
|
|
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
|
|
|
|
* part of the UCB release of Plan 9, including this file, may be copied,
|
|
|
|
* modified, propagated, or distributed except according to the terms contained
|
|
|
|
* in the LICENSE file.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <u.h>
|
2017-04-19 23:33:14 +02:00
|
|
|
#include <lib9.h>
|
2016-11-25 17:18:40 +01:00
|
|
|
#include <bio.h>
|
|
|
|
|
|
|
|
#include "pci.h"
|
|
|
|
#include "vga.h"
|
|
|
|
|
|
|
|
enum {
|
|
|
|
NSeqx = 0x05,
|
|
|
|
NCrtx = 0x19,
|
|
|
|
NGrx = 0x09,
|
|
|
|
NAttrx = 0x15,
|
|
|
|
};
|
|
|
|
|
|
|
|
uint8_t
|
|
|
|
vgai(int32_t port)
|
|
|
|
{
|
|
|
|
uint8_t data;
|
|
|
|
|
|
|
|
switch(port){
|
|
|
|
|
|
|
|
case MiscR:
|
|
|
|
case Status0:
|
|
|
|
case Status1:
|
|
|
|
case FeatureR:
|
|
|
|
case PaddrW:
|
|
|
|
case Pdata:
|
|
|
|
case Pixmask:
|
|
|
|
case Pstatus:
|
|
|
|
data = inportb(port);
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
error("vgai(0x%4.4lX): unknown port\n", port);
|
|
|
|
/*NOTREACHED*/
|
|
|
|
data = 0xFF;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return data;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint8_t
|
|
|
|
vgaxi(int32_t port, uint8_t index)
|
|
|
|
{
|
|
|
|
uint8_t data;
|
|
|
|
|
|
|
|
switch(port){
|
|
|
|
|
|
|
|
case Seqx:
|
|
|
|
case Crtx:
|
|
|
|
case Grx:
|
|
|
|
outportb(port, index);
|
|
|
|
data = inportb(port+1);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case Attrx:
|
|
|
|
/*
|
|
|
|
* Allow processor access to the colour
|
|
|
|
* palette registers. Writes to Attrx must
|
|
|
|
* be preceded by a read from Status1 to
|
|
|
|
* initialise the register to point to the
|
|
|
|
* index register and not the data register.
|
|
|
|
* Processor access is allowed by turning
|
|
|
|
* off bit 0x20.
|
|
|
|
*/
|
|
|
|
inportb(Status1);
|
|
|
|
if(index < 0x10){
|
|
|
|
outportb(Attrx, index);
|
|
|
|
data = inportb(Attrx+1);
|
|
|
|
inportb(Status1);
|
|
|
|
outportb(Attrx, 0x20|index);
|
|
|
|
}
|
|
|
|
else{
|
|
|
|
outportb(Attrx, 0x20|index);
|
|
|
|
data = inportb(Attrx+1);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
error("vgaxi(0x%4.4lx, 0x%2.2uX): unknown port\n", port, index);
|
|
|
|
/*NOTREACHED*/
|
|
|
|
data = 0xFF;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return data;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
vgao(int32_t port, uint8_t data)
|
|
|
|
{
|
|
|
|
switch(port){
|
|
|
|
|
|
|
|
case MiscW:
|
|
|
|
case FeatureW:
|
|
|
|
case PaddrW:
|
|
|
|
case Pdata:
|
|
|
|
case Pixmask:
|
|
|
|
case PaddrR:
|
|
|
|
outportb(port, data);
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
error("vgao(0x%4.4lX, 0x%2.2uX): unknown port\n", port, data);
|
|
|
|
/*NOTREACHED*/
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
vgaxo(int32_t port, uint8_t index, uint8_t data)
|
|
|
|
{
|
|
|
|
switch(port){
|
|
|
|
|
|
|
|
case Seqx:
|
|
|
|
case Crtx:
|
|
|
|
case Grx:
|
|
|
|
/*
|
|
|
|
* We could use an outport here, but some chips
|
|
|
|
* (e.g. 86C928) have trouble with that for some
|
|
|
|
* registers.
|
|
|
|
*/
|
|
|
|
outportb(port, index);
|
|
|
|
outportb(port+1, data);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case Attrx:
|
|
|
|
inportb(Status1);
|
|
|
|
if(index < 0x10){
|
|
|
|
outportb(Attrx, index);
|
|
|
|
outportb(Attrx, data);
|
|
|
|
inportb(Status1);
|
|
|
|
outportb(Attrx, 0x20|index);
|
|
|
|
}
|
|
|
|
else{
|
|
|
|
outportb(Attrx, 0x20|index);
|
|
|
|
outportb(Attrx, data);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
error("vgaxo(0x%4.4lX, 0x%2.2uX, 0x%2.2uX): unknown port\n",
|
|
|
|
port, index, data);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
snarf(Vga* vga, Ctlr* ctlr)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Generic VGA registers:
|
|
|
|
* misc, feature;
|
|
|
|
* sequencer;
|
|
|
|
* crt;
|
|
|
|
* graphics;
|
|
|
|
* attribute;
|
|
|
|
* palette.
|
|
|
|
*/
|
|
|
|
vga->misc = vgai(MiscR);
|
|
|
|
vga->feature = vgai(FeatureR);
|
|
|
|
|
|
|
|
for(i = 0; i < NSeqx; i++)
|
|
|
|
vga->sequencer[i] = vgaxi(Seqx, i);
|
|
|
|
|
|
|
|
for(i = 0; i < NCrtx; i++)
|
|
|
|
vga->crt[i] = vgaxi(Crtx, i);
|
|
|
|
|
|
|
|
for(i = 0; i < NGrx; i++)
|
|
|
|
vga->graphics[i] = vgaxi(Grx, i);
|
|
|
|
|
|
|
|
for(i = 0; i < NAttrx; i++)
|
|
|
|
vga->attribute[i] = vgaxi(Attrx, i);
|
|
|
|
|
|
|
|
if(dflag)
|
|
|
|
palette.snarf(vga, ctlr);
|
|
|
|
|
|
|
|
ctlr->flag |= Fsnarf;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
init(Vga* vga, Ctlr* ctlr)
|
|
|
|
{
|
|
|
|
Mode *mode;
|
|
|
|
int vt, vde, vrs, vre;
|
|
|
|
uint32_t tmp;
|
|
|
|
|
|
|
|
mode = vga->mode;
|
|
|
|
|
|
|
|
memset(vga->sequencer, 0, NSeqx*sizeof(vga->sequencer[0]));
|
|
|
|
memset(vga->crt, 0, NCrtx*sizeof(vga->crt[0]));
|
|
|
|
memset(vga->graphics, 0, NGrx*sizeof(vga->graphics[0]));
|
|
|
|
memset(vga->attribute, 0, NAttrx*sizeof(vga->attribute[0]));
|
|
|
|
if(dflag)
|
|
|
|
memset(vga->palette, 0, sizeof(vga->palette));
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Misc. If both the horizontal and vertical sync polarity
|
|
|
|
* options are set, use them. Otherwise use the defaults for
|
|
|
|
* the given vertical size.
|
|
|
|
*/
|
|
|
|
vga->misc = 0x23;
|
|
|
|
if(mode->frequency == VgaFreq1)
|
|
|
|
vga->misc |= 0x04;
|
|
|
|
if(mode->hsync && mode->vsync){
|
|
|
|
if(mode->hsync == '-')
|
|
|
|
vga->misc |= 0x40;
|
|
|
|
if(mode->vsync == '-')
|
|
|
|
vga->misc |= 0x80;
|
|
|
|
}
|
|
|
|
else{
|
|
|
|
if(mode->y < 480)
|
|
|
|
vga->misc |= 0x40;
|
|
|
|
else if(mode->y < 400)
|
|
|
|
vga->misc |= 0x80;
|
|
|
|
else if(mode->y < 768)
|
|
|
|
vga->misc |= 0xC0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Sequencer
|
|
|
|
*/
|
|
|
|
vga->sequencer[0x00] = 0x03;
|
|
|
|
vga->sequencer[0x01] = 0x01;
|
|
|
|
vga->sequencer[0x02] = 0x0F;
|
|
|
|
vga->sequencer[0x03] = 0x00;
|
|
|
|
if(mode->z >= 8)
|
|
|
|
vga->sequencer[0x04] = 0x0A;
|
|
|
|
else
|
|
|
|
vga->sequencer[0x04] = 0x06;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Crt. Most of the work here is in dealing
|
|
|
|
* with field overflow.
|
|
|
|
*/
|
|
|
|
memset(vga->crt, 0, NCrtx);
|
|
|
|
|
|
|
|
vga->crt[0x00] = (mode->ht>>3)-5;
|
|
|
|
vga->crt[0x01] = (mode->x>>3)-1;
|
|
|
|
vga->crt[0x02] = (mode->shb>>3)-1;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* End Horizontal Blank is a 6-bit field, 5-bits
|
|
|
|
* in Crt3, high bit in Crt5.
|
|
|
|
*/
|
|
|
|
tmp = mode->ehb>>3;
|
|
|
|
vga->crt[0x03] = 0x80|(tmp & 0x1F);
|
|
|
|
if(tmp & 0x20)
|
|
|
|
vga->crt[0x05] |= 0x80;
|
|
|
|
|
|
|
|
if(mode->shs == 0)
|
|
|
|
mode->shs = mode->shb;
|
|
|
|
vga->crt[0x04] = mode->shs>>3;
|
|
|
|
if(mode->ehs == 0)
|
|
|
|
mode->ehs = mode->ehb;
|
|
|
|
vga->crt[0x05] |= ((mode->ehs>>3) & 0x1F);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Vertical Total is 10-bits, 8 in Crt6, the high
|
|
|
|
* two bits in Crt7. What if vt is >= 1024? We hope
|
|
|
|
* the specific controller has some more overflow
|
|
|
|
* bits.
|
|
|
|
*
|
|
|
|
* Interlace: if 'v', divide the vertical timing
|
|
|
|
* values by 2.
|
|
|
|
*/
|
|
|
|
vt = mode->vt;
|
|
|
|
vde = mode->y;
|
|
|
|
vrs = mode->vrs;
|
|
|
|
vre = mode->vre;
|
|
|
|
|
|
|
|
if(mode->interlace == 'v'){
|
|
|
|
vt /= 2;
|
|
|
|
vde /= 2;
|
|
|
|
vrs /= 2;
|
|
|
|
vre /= 2;
|
|
|
|
}
|
|
|
|
|
|
|
|
tmp = vt-2;
|
|
|
|
vga->crt[0x06] = tmp;
|
|
|
|
if(tmp & 0x100)
|
|
|
|
vga->crt[0x07] |= 0x01;
|
|
|
|
if(tmp & 0x200)
|
|
|
|
vga->crt[0x07] |= 0x20;
|
|
|
|
|
|
|
|
tmp = vrs;
|
|
|
|
vga->crt[0x10] = tmp;
|
|
|
|
if(tmp & 0x100)
|
|
|
|
vga->crt[0x07] |= 0x04;
|
|
|
|
if(tmp & 0x200)
|
|
|
|
vga->crt[0x07] |= 0x80;
|
|
|
|
|
|
|
|
vga->crt[0x11] = 0x20|(vre & 0x0F);
|
|
|
|
|
|
|
|
tmp = vde-1;
|
|
|
|
vga->crt[0x12] = tmp;
|
|
|
|
if(tmp & 0x100)
|
|
|
|
vga->crt[0x07] |= 0x02;
|
|
|
|
if(tmp & 0x200)
|
|
|
|
vga->crt[0x07] |= 0x40;
|
|
|
|
|
|
|
|
vga->crt[0x15] = vrs;
|
|
|
|
if(vrs & 0x100)
|
|
|
|
vga->crt[0x07] |= 0x08;
|
|
|
|
if(vrs & 0x200)
|
|
|
|
vga->crt[0x09] |= 0x20;
|
|
|
|
|
|
|
|
vga->crt[0x16] = (vrs+1);
|
|
|
|
|
|
|
|
vga->crt[0x17] = 0x83;
|
|
|
|
tmp = ((vga->virtx*mode->z)/8);
|
|
|
|
if(tmp >= 512){
|
|
|
|
vga->crt[0x14] |= 0x60;
|
|
|
|
tmp /= 8;
|
|
|
|
}
|
|
|
|
else if(tmp >= 256){
|
|
|
|
vga->crt[0x17] |= 0x08;
|
|
|
|
tmp /= 4;
|
|
|
|
}
|
|
|
|
else{
|
|
|
|
vga->crt[0x17] |= 0x40;
|
|
|
|
tmp /= 2;
|
|
|
|
}
|
|
|
|
vga->crt[0x13] = tmp;
|
|
|
|
|
|
|
|
if(mode->x*mode->y*mode->z/8 > 64*1024)
|
|
|
|
vga->crt[0x17] |= 0x20;
|
|
|
|
|
|
|
|
vga->crt[0x18] = 0x7FF;
|
|
|
|
if(vga->crt[0x18] & 0x100)
|
|
|
|
vga->crt[0x07] |= 0x10;
|
|
|
|
if(vga->crt[0x18] & 0x200)
|
|
|
|
vga->crt[0x09] |= 0x40;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Graphics
|
|
|
|
*/
|
|
|
|
memset(vga->graphics, 0, NGrx);
|
|
|
|
if((vga->sequencer[0x04] & 0x04) == 0)
|
|
|
|
vga->graphics[0x05] |= 0x10;
|
|
|
|
if(mode->z >= 8)
|
|
|
|
vga->graphics[0x05] |= 0x40;
|
|
|
|
vga->graphics[0x06] = 0x05;
|
|
|
|
vga->graphics[0x07] = 0x0F;
|
|
|
|
vga->graphics[0x08] = 0xFF;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Attribute
|
|
|
|
*/
|
|
|
|
memset(vga->attribute, 0, NAttrx);
|
|
|
|
for(tmp = 0; tmp < 0x10; tmp++)
|
|
|
|
vga->attribute[tmp] = tmp;
|
|
|
|
vga->attribute[0x10] = 0x01;
|
|
|
|
if(mode->z >= 8)
|
|
|
|
vga->attribute[0x10] |= 0x40;
|
|
|
|
vga->attribute[0x11] = 0xFF;
|
|
|
|
vga->attribute[0x12] = 0x0F;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Palette
|
|
|
|
*/
|
|
|
|
if(dflag)
|
|
|
|
palette.init(vga, ctlr);
|
|
|
|
|
|
|
|
ctlr->flag |= Finit;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
load(Vga* vga, Ctlr* ctlr)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Reset the sequencer and leave it off.
|
|
|
|
* Load the generic VGA registers:
|
|
|
|
* misc;
|
|
|
|
* sequencer (but not seq01, display enable);
|
|
|
|
* take the sequencer out of reset;
|
|
|
|
* take off write-protect on crt[0x00-0x07];
|
|
|
|
* crt;
|
|
|
|
* graphics;
|
|
|
|
* attribute;
|
|
|
|
* palette.
|
|
|
|
vgaxo(Seqx, 0x00, 0x00);
|
|
|
|
*/
|
|
|
|
|
|
|
|
vgao(MiscW, vga->misc);
|
|
|
|
|
|
|
|
for(i = 2; i < NSeqx; i++)
|
|
|
|
vgaxo(Seqx, i, vga->sequencer[i]);
|
|
|
|
/*vgaxo(Seqx, 0x00, 0x03);*/
|
|
|
|
|
|
|
|
vgaxo(Crtx, 0x11, vga->crt[0x11] & ~0x80);
|
|
|
|
for(i = 0; i < NCrtx; i++)
|
|
|
|
vgaxo(Crtx, i, vga->crt[i]);
|
|
|
|
|
|
|
|
for(i = 0; i < NGrx; i++)
|
|
|
|
vgaxo(Grx, i, vga->graphics[i]);
|
|
|
|
|
|
|
|
for(i = 0; i < NAttrx; i++)
|
|
|
|
vgaxo(Attrx, i, vga->attribute[i]);
|
|
|
|
|
|
|
|
if(dflag)
|
|
|
|
palette.load(vga, ctlr);
|
|
|
|
|
|
|
|
ctlr->flag |= Fload;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
dump(Vga* vga, Ctlr* ctlr)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
printitem(ctlr->name, "misc");
|
|
|
|
printreg(vga->misc);
|
|
|
|
printitem(ctlr->name, "feature");
|
|
|
|
printreg(vga->feature);
|
|
|
|
|
|
|
|
printitem(ctlr->name, "sequencer");
|
|
|
|
for(i = 0; i < NSeqx; i++)
|
|
|
|
printreg(vga->sequencer[i]);
|
|
|
|
|
|
|
|
printitem(ctlr->name, "crt");
|
|
|
|
for(i = 0; i < NCrtx; i++)
|
|
|
|
printreg(vga->crt[i]);
|
|
|
|
|
|
|
|
printitem(ctlr->name, "graphics");
|
|
|
|
for(i = 0; i < NGrx; i++)
|
|
|
|
printreg(vga->graphics[i]);
|
|
|
|
|
|
|
|
printitem(ctlr->name, "attribute");
|
|
|
|
for(i = 0; i < NAttrx; i++)
|
|
|
|
printreg(vga->attribute[i]);
|
|
|
|
|
|
|
|
if(dflag)
|
|
|
|
palette.dump(vga, ctlr);
|
|
|
|
|
|
|
|
printitem(ctlr->name, "virtual");
|
|
|
|
Bprint(&stdout, "%ld %ld\n", vga->virtx, vga->virty);
|
|
|
|
printitem(ctlr->name, "panning");
|
|
|
|
Bprint(&stdout, "%s\n", vga->panning ? "on" : "off");
|
|
|
|
if(vga->f[0]){
|
|
|
|
printitem(ctlr->name, "clock[0] f");
|
|
|
|
Bprint(&stdout, "%9ld\n", vga->f[0]);
|
|
|
|
printitem(ctlr->name, "clock[0] d i m");
|
|
|
|
Bprint(&stdout, "%9ld %8ld - %8ld\n",
|
|
|
|
vga->d[0], vga->i[0], vga->m[0]);
|
|
|
|
printitem(ctlr->name, "clock[0] n p q r");
|
|
|
|
Bprint(&stdout, "%9ld %8ld - %8ld %8ld\n",
|
|
|
|
vga->n[0], vga->p[0], vga->q[0], vga->r[0]);
|
|
|
|
}
|
|
|
|
if(vga->f[1]){
|
|
|
|
printitem(ctlr->name, "clock[1] f");
|
|
|
|
Bprint(&stdout, "%9ld\n", vga->f[1]);
|
|
|
|
printitem(ctlr->name, "clock[1] d i m");
|
|
|
|
Bprint(&stdout, "%9ld %8ld - %8ld\n",
|
|
|
|
vga->d[1], vga->i[1], vga->m[1]);
|
|
|
|
printitem(ctlr->name, "clock[1] n p q r");
|
|
|
|
Bprint(&stdout, "%9ld %8ld - %8ld %8ld\n",
|
|
|
|
vga->n[1], vga->p[1], vga->q[1], vga->r[1]);
|
|
|
|
}
|
|
|
|
|
|
|
|
if(vga->vma || vga->vmb){
|
|
|
|
printitem(ctlr->name, "vm a b");
|
|
|
|
Bprint(&stdout, "%9lud %8lud\n", vga->vma, vga->vmb);
|
|
|
|
}
|
|
|
|
if(vga->vmz){
|
|
|
|
printitem(ctlr->name, "vmz");
|
|
|
|
Bprint(&stdout, "%9lud\n", vga->vmz);
|
|
|
|
}
|
|
|
|
printitem(ctlr->name, "apz");
|
|
|
|
Bprint(&stdout, "%9lud\n", vga->apz);
|
|
|
|
|
|
|
|
printitem(ctlr->name, "linear");
|
|
|
|
Bprint(&stdout, "%9d\n", vga->linear);
|
|
|
|
}
|
|
|
|
|
|
|
|
Ctlr generic = {
|
|
|
|
"vga", /* name */
|
|
|
|
snarf, /* snarf */
|
|
|
|
0, /* options */
|
|
|
|
init, /* init */
|
|
|
|
load, /* load */
|
|
|
|
dump, /* dump */
|
|
|
|
};
|