330 lines
6.6 KiB
C
330 lines
6.6 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 <libc.h>
|
||
|
#include <bio.h>
|
||
|
|
||
|
#include "pci.h"
|
||
|
#include "vga.h"
|
||
|
|
||
|
/*
|
||
|
* IBM RGB52x and compatibles.
|
||
|
* High Performance Palette DAC.
|
||
|
*/
|
||
|
uint8_t (*rgb524mnxi)(Vga*, int);
|
||
|
void (*rgb524mnxo)(Vga*, int, uint8_t);
|
||
|
|
||
|
enum { /* index registers */
|
||
|
MiscClock = 0x02,
|
||
|
SyncControl = 0x03,
|
||
|
HSyncControl = 0x04,
|
||
|
PowerMgmnt = 0x05,
|
||
|
PaletteControl = 0x07,
|
||
|
SYSCLKControl = 0x08,
|
||
|
PixelFormat = 0x0A,
|
||
|
Pixel8Control = 0x0B,
|
||
|
Pixel16Control = 0x0C,
|
||
|
Pixel32Control = 0x0E,
|
||
|
PLLControl1 = 0x10,
|
||
|
PLLControl2 = 0x11,
|
||
|
SYSCLKN = 0x15,
|
||
|
SYSCLKM = 0x16,
|
||
|
M0 = 0x20,
|
||
|
N0 = 0x21,
|
||
|
MiscControl1 = 0x70,
|
||
|
MiscControl2 = 0x71,
|
||
|
};
|
||
|
|
||
|
static void
|
||
|
clock(Vga* vga, Ctlr* ctlr, uint32_t fref, uint32_t maxpclk)
|
||
|
{
|
||
|
int d, mind;
|
||
|
uint32_t df, f, m, n, vrf;
|
||
|
|
||
|
mind = vga->f[0]+1;
|
||
|
for(df = 0; df < 4; df++){
|
||
|
for(m = 2; m < 64; m++){
|
||
|
for(n = 2; n < 32; n++){
|
||
|
f = (fref*(m+65))/n;
|
||
|
switch(df){
|
||
|
case 0:
|
||
|
vrf = fref/(n*2);
|
||
|
if(vrf > maxpclk/4 || vrf < 1000000)
|
||
|
continue;
|
||
|
f /= 8;
|
||
|
break;
|
||
|
case 1:
|
||
|
vrf = fref/(n*2);
|
||
|
if(vrf > maxpclk/2 || vrf < 1000000)
|
||
|
continue;
|
||
|
f /= 4;
|
||
|
break;
|
||
|
case 2:
|
||
|
vrf = fref/(n*2);
|
||
|
if(vrf > maxpclk || vrf < 1000000)
|
||
|
continue;
|
||
|
f /= 2;
|
||
|
break;
|
||
|
case 3:
|
||
|
vrf = fref/n;
|
||
|
if(vrf > maxpclk || vrf < 1000000)
|
||
|
continue;
|
||
|
break;
|
||
|
}
|
||
|
if(f > maxpclk)
|
||
|
continue;
|
||
|
|
||
|
d = vga->f[0] - f;
|
||
|
if(d < 0)
|
||
|
d = -d;
|
||
|
if(d <= mind){
|
||
|
vga->m[0] = m;
|
||
|
vga->n[0] = n;
|
||
|
vga->d[0] = df;
|
||
|
mind = d;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
init(Vga* vga, Ctlr* ctlr)
|
||
|
{
|
||
|
uint32_t fref, maxpclk;
|
||
|
char *p, *val;
|
||
|
|
||
|
/*
|
||
|
* Part comes in at least a -170MHz speed-grade.
|
||
|
*/
|
||
|
maxpclk = 170000000;
|
||
|
if(p = strrchr(ctlr->name, '-'))
|
||
|
maxpclk = strtoul(p+1, 0, 0) * 1000000;
|
||
|
|
||
|
/*
|
||
|
* If we don't already have a desired pclk,
|
||
|
* take it from the mode.
|
||
|
* Check it's within range.
|
||
|
*/
|
||
|
if(vga->f[0] == 0)
|
||
|
vga->f[0] = vga->mode->frequency;
|
||
|
if(vga->f[0] > maxpclk)
|
||
|
error("%s: invalid pclk - %ld\n", ctlr->name, vga->f[0]);
|
||
|
if(val = dbattr(vga->attr, "rgb524mnrefclk"))
|
||
|
fref = strtol(val, 0, 0);
|
||
|
else
|
||
|
fref = RefFreq;
|
||
|
|
||
|
/*
|
||
|
* Initialise the PLL parameters.
|
||
|
* Use m/n pair 2.
|
||
|
*/
|
||
|
clock(vga, ctlr, fref, maxpclk);
|
||
|
vga->i[0] = 2;
|
||
|
|
||
|
ctlr->flag |= Finit;
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
load(Vga* vga, Ctlr* ctlr)
|
||
|
{
|
||
|
char *val;
|
||
|
int hsyncdelay, x;
|
||
|
|
||
|
if(rgb524mnxi == nil && rgb524mnxo == nil)
|
||
|
error("%s->load: no access routines\n", ctlr->name);
|
||
|
|
||
|
/*
|
||
|
* Set the m/n values for the desired frequency and
|
||
|
* set pixel control to use compatibility mode with
|
||
|
* internal frequency select using the specified set
|
||
|
* of m/n registers.
|
||
|
*/
|
||
|
rgb524mnxo(vga, M0+vga->i[0]*2, vga->d[0]<<6|vga->m[0]);
|
||
|
rgb524mnxo(vga, N0+vga->i[0]*2, vga->n[0]);
|
||
|
rgb524mnxo(vga, PLLControl2, vga->i[0]);
|
||
|
rgb524mnxo(vga, PLLControl1, 0x03);
|
||
|
|
||
|
/*
|
||
|
* Enable pixel programming in MiscClock;
|
||
|
* nothing to do in MiscControl1;
|
||
|
* set internal PLL clock and !vga in MiscControl2;
|
||
|
*/
|
||
|
x = rgb524mnxi(vga, MiscClock) & ~0x01;
|
||
|
x |= 0x01;
|
||
|
rgb524mnxo(vga, MiscClock, x);
|
||
|
|
||
|
x = rgb524mnxi(vga, MiscControl2) & ~0x41;
|
||
|
x |= 0x41;
|
||
|
rgb524mnxo(vga, MiscControl2, x);
|
||
|
|
||
|
/*
|
||
|
* Syncs.
|
||
|
*/
|
||
|
x = 0;
|
||
|
if(vga->mode->hsync == '+')
|
||
|
x |= 0x10;
|
||
|
if(vga->mode->vsync == '+')
|
||
|
x |= 0x20;
|
||
|
rgb524mnxo(vga, SyncControl, x);
|
||
|
if(val = dbattr(vga->mode->attr, "hsyncdelay"))
|
||
|
hsyncdelay = strtol(val, 0, 0);
|
||
|
else switch(vga->mode->z){
|
||
|
default:
|
||
|
case 8:
|
||
|
hsyncdelay = 1;
|
||
|
break;
|
||
|
case 15:
|
||
|
case 16:
|
||
|
hsyncdelay = 5;
|
||
|
break;
|
||
|
case 32:
|
||
|
hsyncdelay = 7;
|
||
|
break;
|
||
|
}
|
||
|
rgb524mnxo(vga, HSyncControl, hsyncdelay);
|
||
|
|
||
|
rgb524mnxo(vga, SYSCLKM, 0x50);
|
||
|
rgb524mnxo(vga, SYSCLKN, 0x08);
|
||
|
sleep(50);
|
||
|
//rgb524mnxo(vga, SYSCLKM, 0x6F);
|
||
|
//rgb524mnxo(vga, SYSCLKN, 0x0F);
|
||
|
//sleep(500);
|
||
|
|
||
|
/*
|
||
|
* Set the palette for the desired format.
|
||
|
* ****NEEDS WORK FOR OTHER THAN 8-BITS****
|
||
|
*/
|
||
|
rgb524mnxo(vga, PaletteControl, 0x00);
|
||
|
switch(vga->mode->z){
|
||
|
case 8:
|
||
|
rgb524mnxo(vga, PixelFormat, 0x03);
|
||
|
rgb524mnxo(vga, Pixel8Control, 0x00);
|
||
|
break;
|
||
|
case 15:
|
||
|
rgb524mnxo(vga, PixelFormat, 0x04);
|
||
|
rgb524mnxo(vga, Pixel16Control, 0xC4);
|
||
|
case 16:
|
||
|
rgb524mnxo(vga, PixelFormat, 0x04);
|
||
|
rgb524mnxo(vga, Pixel16Control, 0xC6);
|
||
|
break;
|
||
|
case 32:
|
||
|
rgb524mnxo(vga, PixelFormat, 0x06);
|
||
|
rgb524mnxo(vga, Pixel32Control, 0x03);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
dumpclock(Vga* vga, Ctlr* ctlr, uint32_t fref, uint32_t m, uint32_t n,
|
||
|
char* name)
|
||
|
{
|
||
|
uint32_t df, f;
|
||
|
|
||
|
df = (m>>6) & 0x03;
|
||
|
m &= 0x3F;
|
||
|
n &= 0x1F;
|
||
|
if(m == 0 || n == 0)
|
||
|
return;
|
||
|
f = (fref*(m+65))/n;
|
||
|
switch(df){
|
||
|
case 0:
|
||
|
f /= 8;
|
||
|
break;
|
||
|
case 1:
|
||
|
f /= 4;
|
||
|
break;
|
||
|
case 2:
|
||
|
f /= 2;
|
||
|
break;
|
||
|
case 3:
|
||
|
break;
|
||
|
}
|
||
|
printitem(ctlr->name, name);
|
||
|
Bprint(&stdout, "%12lud\n", f);
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
dump(Vga* vga, Ctlr* ctlr)
|
||
|
{
|
||
|
int i;
|
||
|
char *val;
|
||
|
uint8_t x[256];
|
||
|
uint32_t fref, fs;
|
||
|
|
||
|
if(rgb524mnxi == nil && rgb524mnxo == nil)
|
||
|
error("%s->dump: no access routines\n", ctlr->name);
|
||
|
|
||
|
printitem(ctlr->name, "index00");
|
||
|
for(i = 0x00; i < 0x0F; i++){
|
||
|
x[i] = rgb524mnxi(vga, i);
|
||
|
printreg(x[i]);
|
||
|
}
|
||
|
printitem(ctlr->name, "index10");
|
||
|
for(i = 0x10; i < 0x18; i++){
|
||
|
x[i] = rgb524mnxi(vga, i);
|
||
|
printreg(x[i]);
|
||
|
}
|
||
|
printitem(ctlr->name, "index20");
|
||
|
for(i = 0x20; i < 0x30; i++){
|
||
|
x[i] = rgb524mnxi(vga, i);
|
||
|
printreg(x[i]);
|
||
|
}
|
||
|
printitem(ctlr->name, "index30");
|
||
|
for(i = 0x30; i < 0x39; i++){
|
||
|
x[i] = rgb524mnxi(vga, i);
|
||
|
printreg(x[i]);
|
||
|
}
|
||
|
printitem(ctlr->name, "index40");
|
||
|
for(i = 0x40; i < 0x49; i++){
|
||
|
x[i] = rgb524mnxi(vga, i);
|
||
|
printreg(x[i]);
|
||
|
}
|
||
|
printitem(ctlr->name, "index60");
|
||
|
for(i = 0x60; i < 0x63; i++){
|
||
|
x[i] = rgb524mnxi(vga, i);
|
||
|
printreg(x[i]);
|
||
|
}
|
||
|
printitem(ctlr->name, "index70");
|
||
|
for(i = 0x70; i < 0x73; i++){
|
||
|
x[i] = rgb524mnxi(vga, i);
|
||
|
printreg(x[i]);
|
||
|
}
|
||
|
printitem(ctlr->name, "index8E");
|
||
|
for(i = 0x8E; i < 0x92; i++){
|
||
|
x[i] = rgb524mnxi(vga, i);
|
||
|
printreg(x[i]);
|
||
|
}
|
||
|
|
||
|
if(val = dbattr(vga->attr, "rgb524mnrefclk"))
|
||
|
fref = strtol(val, 0, 0);
|
||
|
else
|
||
|
fref = RefFreq;
|
||
|
if(!(x[SYSCLKControl] & 0x04))
|
||
|
dumpclock(vga, ctlr, fref, x[0x16], x[0x15], "sysclk");
|
||
|
fs = x[PLLControl1] & 0x07;
|
||
|
if(fs == 0x01 || fs == 0x03){
|
||
|
if(fs == 0x01)
|
||
|
i = ((vga->misc>>2) & 0x03)*2;
|
||
|
else
|
||
|
i = x[PLLControl2] & 0x07;
|
||
|
dumpclock(vga, ctlr, fref, x[M0+i*2], x[N0+i*2], "pllclk");
|
||
|
}
|
||
|
}
|
||
|
|
||
|
Ctlr rgb524mn = {
|
||
|
"rgb524mn", /* name */
|
||
|
0, /* snarf */
|
||
|
0, /* options */
|
||
|
init, /* init */
|
||
|
load, /* load */
|
||
|
dump, /* dump */
|
||
|
};
|