391 lines
7.7 KiB
C
391 lines
7.7 KiB
C
/*
|
|
* 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>
|
|
#include <lib9.h>
|
|
#include <bio.h>
|
|
|
|
#include "pci.h"
|
|
#include "vga.h"
|
|
|
|
/*
|
|
* Generic S3 GUI Accelerator.
|
|
*/
|
|
static void
|
|
snarf(Vga* vga, Ctlr* ctlr)
|
|
{
|
|
int i;
|
|
|
|
trace("%s->snarf->s3generic\n", ctlr->name);
|
|
|
|
/*
|
|
* Unlock extended registers.
|
|
* 0xA5 ensures Crt36 and Crt37 are also unlocked
|
|
* (0xA0 unlocks everything else).
|
|
*/
|
|
vgaxo(Crtx, 0x38, 0x48);
|
|
vgaxo(Crtx, 0x39, 0xA5);
|
|
|
|
/*
|
|
* Not all registers exist on all chips.
|
|
* Crt3[EF] don't exist on any.
|
|
*/
|
|
for(i = 0x30; i < 0x70; i++)
|
|
vga->crt[i] = vgaxi(Crtx, i);
|
|
|
|
/*
|
|
* Memory size.
|
|
*/
|
|
switch((vga->crt[0x36]>>5) & 0x07){
|
|
|
|
case 0x00:
|
|
vga->vmz = 4*1024*1024;
|
|
break;
|
|
|
|
case 0x02:
|
|
vga->vmz = 3*1024*1024;
|
|
break;
|
|
|
|
case 0x04:
|
|
vga->vmz = 2*1024*1024;
|
|
break;
|
|
|
|
case 0x06:
|
|
vga->vmz = 1*1024*1024;
|
|
break;
|
|
|
|
case 0x07:
|
|
vga->vmz = 512*1024;
|
|
break;
|
|
}
|
|
|
|
ctlr->flag |= Fsnarf;
|
|
}
|
|
|
|
static void
|
|
init(Vga* vga, Ctlr* ctlr)
|
|
{
|
|
Mode *mode;
|
|
uint32_t x;
|
|
|
|
trace("%s->init->s3generic\n", ctlr->name);
|
|
mode = vga->mode;
|
|
|
|
/*
|
|
* Is enhanced mode is necessary?
|
|
*/
|
|
if((ctlr->flag & (Uenhanced|Henhanced)) == Henhanced){
|
|
if(mode->z >= 8)
|
|
resyncinit(vga, ctlr, Uenhanced, 0);
|
|
else
|
|
resyncinit(vga, ctlr, 0, Uenhanced|Henhanced);
|
|
}
|
|
if((ctlr->flag & Uenhanced) == 0 && mode->x > 1024)
|
|
error("%s: no support for 1-bit mode > 1024x768x1\n", ctlr->name);
|
|
|
|
vga->crt[0x31] = 0x85;
|
|
vga->crt[0x6A] &= 0xC0;
|
|
vga->crt[0x32] &= ~0x40;
|
|
|
|
vga->crt[0x31] |= 0x08;
|
|
vga->crt[0x32] |= 0x40;
|
|
|
|
vga->crt[0x33] |= 0x20;
|
|
if(mode->z >= 8)
|
|
vga->crt[0x3A] |= 0x10;
|
|
else
|
|
vga->crt[0x3A] &= ~0x10;
|
|
|
|
vga->crt[0x34] = 0x10;
|
|
vga->crt[0x35] = 0x00;
|
|
if(mode->interlace){
|
|
vga->crt[0x3C] = vga->crt[0]/2;
|
|
vga->crt[0x42] |= 0x20;
|
|
}
|
|
else{
|
|
vga->crt[0x3C] = 0x00;
|
|
vga->crt[0x42] &= ~0x20;
|
|
}
|
|
|
|
vga->crt[0x40] = (vga->crt[0x40] & 0xF2);
|
|
vga->crt[0x43] = 0x00;
|
|
vga->crt[0x45] = 0x00;
|
|
|
|
vga->crt[0x50] &= 0x3E;
|
|
if(mode->x <= 640)
|
|
x = 0x40;
|
|
else if(mode->x <= 800)
|
|
x = 0x80;
|
|
else if(mode->x <= 1024)
|
|
x = 0x00;
|
|
else if(mode->x <= 1152)
|
|
x = 0x01;
|
|
else if(mode->x <= 1280)
|
|
x = 0xC0;
|
|
else
|
|
x = 0x81;
|
|
vga->crt[0x50] |= x;
|
|
|
|
vga->crt[0x51] = (vga->crt[0x51] & 0xC3)|((vga->crt[0x13]>>4) & 0x30);
|
|
vga->crt[0x53] &= ~0x10;
|
|
|
|
/*
|
|
* Set up linear aperture. For the moment it's 64K at 0xA0000.
|
|
* The real base address will be assigned before load is called.
|
|
*/
|
|
vga->crt[0x58] = 0x88;
|
|
if(ctlr->flag & Uenhanced){
|
|
vga->crt[0x58] |= 0x10;
|
|
if(vga->linear && (ctlr->flag & Hlinear))
|
|
ctlr->flag |= Ulinear;
|
|
if(vga->vmz <= 1024*1024)
|
|
vga->vma = 1024*1024;
|
|
else if(vga->vmz <= 2*1024*1024)
|
|
vga->vma = 2*1024*1024;
|
|
else
|
|
vga->vma = 8*1024*1024;
|
|
}
|
|
vga->crt[0x59] = 0x00;
|
|
vga->crt[0x5A] = 0x0A;
|
|
|
|
vga->crt[0x5D] &= 0x80;
|
|
if(vga->crt[0x00] & 0x100)
|
|
vga->crt[0x5D] |= 0x01;
|
|
if(vga->crt[0x01] & 0x100)
|
|
vga->crt[0x5D] |= 0x02;
|
|
if(vga->crt[0x02] & 0x100)
|
|
vga->crt[0x5D] |= 0x04;
|
|
if(vga->crt[0x04] & 0x100)
|
|
vga->crt[0x5D] |= 0x10;
|
|
if(vga->crt[0x3B] & 0x100)
|
|
vga->crt[0x5D] |= 0x40;
|
|
|
|
vga->crt[0x5E] = 0x40;
|
|
if(vga->crt[0x06] & 0x400)
|
|
vga->crt[0x5E] |= 0x01;
|
|
if(vga->crt[0x12] & 0x400)
|
|
vga->crt[0x5E] |= 0x02;
|
|
if(vga->crt[0x15] & 0x400)
|
|
vga->crt[0x5E] |= 0x04;
|
|
if(vga->crt[0x10] & 0x400)
|
|
vga->crt[0x5E] |= 0x10;
|
|
|
|
ctlr->type = s3generic.name;
|
|
|
|
ctlr->flag |= Finit;
|
|
}
|
|
|
|
static void
|
|
load(Vga* vga, Ctlr* ctlr)
|
|
{
|
|
uint32_t l;
|
|
|
|
trace("%s->load->s3generic\n", ctlr->name);
|
|
|
|
vgaxo(Crtx, 0x31, vga->crt[0x31]);
|
|
vgaxo(Crtx, 0x32, vga->crt[0x32]);
|
|
vgaxo(Crtx, 0x33, vga->crt[0x33]);
|
|
vgaxo(Crtx, 0x34, vga->crt[0x34]);
|
|
vgaxo(Crtx, 0x35, vga->crt[0x35]);
|
|
vgaxo(Crtx, 0x3A, vga->crt[0x3A]);
|
|
vgaxo(Crtx, 0x3B, vga->crt[0x3B]);
|
|
vgaxo(Crtx, 0x3C, vga->crt[0x3C]);
|
|
|
|
vgaxo(Crtx, 0x40, vga->crt[0x40]|0x01);
|
|
vgaxo(Crtx, 0x42, vga->crt[0x42]);
|
|
vgaxo(Crtx, 0x43, vga->crt[0x43]);
|
|
vgaxo(Crtx, 0x45, vga->crt[0x45]);
|
|
|
|
vgaxo(Crtx, 0x50, vga->crt[0x50]);
|
|
vgaxo(Crtx, 0x51, vga->crt[0x51]);
|
|
vgaxo(Crtx, 0x53, vga->crt[0x53]);
|
|
vgaxo(Crtx, 0x54, vga->crt[0x54]);
|
|
vgaxo(Crtx, 0x55, vga->crt[0x55]);
|
|
|
|
if(ctlr->flag & Ulinear){
|
|
l = vga->vmb>>16;
|
|
vga->crt[0x59] = (l>>8) & 0xFF;
|
|
vga->crt[0x5A] = l & 0xFF;
|
|
if(vga->vmz <= 1024*1024)
|
|
vga->crt[0x58] |= 0x01;
|
|
else if(vga->vmz <= 2*1024*1024)
|
|
vga->crt[0x58] |= 0x02;
|
|
else
|
|
vga->crt[0x58] |= 0x03;
|
|
}
|
|
vgaxo(Crtx, 0x59, vga->crt[0x59]);
|
|
vgaxo(Crtx, 0x5A, vga->crt[0x5A]);
|
|
vgaxo(Crtx, 0x58, vga->crt[0x58]);
|
|
|
|
vgaxo(Crtx, 0x5D, vga->crt[0x5D]);
|
|
vgaxo(Crtx, 0x5E, vga->crt[0x5E]);
|
|
|
|
vgaxo(Crtx, 0x6A, vga->crt[0x6A]);
|
|
|
|
ctlr->flag |= Fload;
|
|
}
|
|
|
|
static void
|
|
dump(Vga* vga, Ctlr* ctlr)
|
|
{
|
|
int i, id, interlace, mul, div;
|
|
char *name;
|
|
uint16_t shb, vrs, x;
|
|
|
|
name = ctlr->name;
|
|
|
|
printitem(name, "Crt30");
|
|
for(i = 0x30; i < 0x3E; i++)
|
|
printreg(vga->crt[i]);
|
|
|
|
printitem(name, "Crt40");
|
|
for(i = 0x40; i < 0x50; i++)
|
|
printreg(vga->crt[i]);
|
|
|
|
printitem(name, "Crt50");
|
|
for(i = 0x50; i < 0x60; i++)
|
|
printreg(vga->crt[i]);
|
|
|
|
printitem(name, "Crt60");
|
|
for(i = 0x60; i < 0x70; i++)
|
|
printreg(vga->crt[i]);
|
|
|
|
/*
|
|
* Try to disassemble the snarfed values into
|
|
* understandable numbers.
|
|
* Only do this if we weren't called after Finit.
|
|
*/
|
|
if(ctlr->flag & Finit)
|
|
return;
|
|
|
|
|
|
/*
|
|
* If hde <= 400, assume this is a 928 or Vision964
|
|
* and the horizontal values have been divided by 4.
|
|
*
|
|
* if ViRGE/[DG]X and 15 or 16bpp, horizontal values have
|
|
* been multiplied by 2.
|
|
*/
|
|
mul = 1;
|
|
div = 1;
|
|
|
|
if(strcmp(name, "virge") == 0){
|
|
id = (vga->crt[0x2D]<<8)|vga->crt[0x2E];
|
|
/* S3 ViRGE/[DG]X */
|
|
if(id==0x8A01 && ((vga->crt[0x67] & 0x30) || (vga->crt[0x67] & 0x50))){
|
|
mul = 1;
|
|
div = 2;
|
|
}
|
|
}
|
|
|
|
x = vga->crt[0x01];
|
|
if(vga->crt[0x5D] & 0x02)
|
|
x |= 0x100;
|
|
x = (x+1)<<3;
|
|
|
|
if(x <= 400){
|
|
mul = 4;
|
|
div = 1;
|
|
}
|
|
|
|
x = (x * mul) / div;
|
|
printitem(name, "hde");
|
|
printreg(x);
|
|
Bprint(&stdout, "%6ud", x);
|
|
|
|
shb = vga->crt[0x02];
|
|
if(vga->crt[0x5D] & 0x04)
|
|
shb |= 0x100;
|
|
shb = (shb+1)<<3;
|
|
shb = (shb * mul) / div;
|
|
printitem(name, "shb");
|
|
printreg(shb);
|
|
Bprint(&stdout, "%6ud", shb);
|
|
|
|
x = vga->crt[0x03] & 0x1F;
|
|
if(vga->crt[0x05] & 0x80)
|
|
x |= 0x20;
|
|
x = (x * mul) / div;
|
|
x = shb|x; /* ???? */
|
|
if(vga->crt[0x5D] & 0x08)
|
|
x += 64;
|
|
printitem(name, "ehb");
|
|
printreg(x);
|
|
Bprint(&stdout, "%6ud", x);
|
|
|
|
x = vga->crt[0x00];
|
|
if(vga->crt[0x5D] & 0x01)
|
|
x |= 0x100;
|
|
x = (x+5)<<3;
|
|
x = (x * mul) / div;
|
|
printitem(name, "ht");
|
|
printreg(x);
|
|
Bprint(&stdout, "%6ud", x);
|
|
|
|
interlace = vga->crt[0x42] & 0x20;
|
|
x = vga->crt[0x12];
|
|
if(vga->crt[0x07] & 0x02)
|
|
x |= 0x100;
|
|
if(vga->crt[0x07] & 0x40)
|
|
x |= 0x200;
|
|
if(vga->crt[0x5E] & 0x02)
|
|
x |= 0x400;
|
|
x += 1;
|
|
if(interlace)
|
|
x *= 2;
|
|
printitem(name, "vde");
|
|
printreg(x);
|
|
Bprint(&stdout, "%6ud", x);
|
|
|
|
vrs = vga->crt[0x10];
|
|
if(vga->crt[0x07] & 0x04)
|
|
vrs |= 0x100;
|
|
if(vga->crt[0x07] & 0x80)
|
|
vrs |= 0x200;
|
|
if(vga->crt[0x5E] & 0x10)
|
|
vrs |= 0x400;
|
|
if(interlace)
|
|
vrs *= 2;
|
|
printitem(name, "vrs");
|
|
printreg(vrs);
|
|
Bprint(&stdout, "%6ud", vrs);
|
|
|
|
if(interlace)
|
|
vrs /= 2;
|
|
x = (vrs & ~0x0F)|(vga->crt[0x11] & 0x0F);
|
|
if(interlace)
|
|
x *= 2;
|
|
printitem(name, "vre");
|
|
printreg(x);
|
|
Bprint(&stdout, "%6ud", x);
|
|
|
|
x = vga->crt[0x06];
|
|
if(vga->crt[0x07] & 0x01)
|
|
x |= 0x100;
|
|
if(vga->crt[0x07] & 0x20)
|
|
x |= 0x200;
|
|
if(vga->crt[0x5E] & 0x01)
|
|
x |= 0x400;
|
|
x += 2;
|
|
if(interlace)
|
|
x *= 2;
|
|
printitem(name, "vt");
|
|
printreg(x);
|
|
Bprint(&stdout, "%6ud", x);
|
|
}
|
|
|
|
Ctlr s3generic = {
|
|
"s3", /* name */
|
|
snarf, /* snarf */
|
|
0, /* options */
|
|
init, /* init */
|
|
load, /* load */
|
|
dump, /* dump */
|
|
};
|