jehanne/sys/src/cmd/hmi/vga/clgd546x.c

380 lines
8.3 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"
/*
* Laguna Visual Media Accelerators Family CL-GD546x.
*/
typedef struct {
Pcidev* pci;
uint8_t* mmio;
int mem;
int format; /* graphics and video format */
int threshold; /* display threshold */
int tilectrl; /* tiling control */
int vsc; /* vendor specific control */
int control; /* control */
int tilectrl2D3D; /* tiling control 2D3D */
} Laguna;
enum {
Format = 0xC0, /* graphics and video format */
Threshold = 0xEA, /* Display Threshold */
TileCtrl = 0x2C4,
Vsc = 0x3FC, /* Vendor Specific Control (32-bits) */
Control = 0x402, /* 2D Control */
TileCtrl2D3D = 0x407, /* (8-bits) */
};
static int
mmio8r(Laguna* laguna, int offset)
{
return *(laguna->mmio+offset) & 0xFF;
}
static void
mmio8w(Laguna* laguna, int offset, int data)
{
*(laguna->mmio+offset) = data;
}
static int
mmio16r(Laguna* laguna, int offset)
{
return *((uint16_t*)(laguna->mmio+offset)) & 0xFFFF;
}
static void
mmio16w(Laguna* laguna, int offset, int data)
{
*((uint16_t*)(laguna->mmio+offset)) = data;
}
static int
mmio32r(Laguna* laguna, int offset)
{
return *((uint32_t*)(laguna->mmio+offset));
}
static void
mmio32w(Laguna* laguna, int offset, int data)
{
*((uint32_t*)(laguna->mmio+offset)) = data;
}
static void
snarf(Vga* vga, Ctlr* ctlr)
{
int f, i;
uint8_t *mmio;
Pcidev *p;
Laguna *laguna;
/*
* Save all the registers, even though we'll only
* change a handful.
*/
for(i = 0x06; i < 0x20; i++)
vga->sequencer[i] = vgaxi(Seqx, i);
for(i = 0x09; i < 0x0C; i++)
vga->graphics[i] = vgaxi(Grx, i);
for(i = 0x19; i < 0x20; i++)
vga->crt[i] = vgaxi(Crtx, i);
if(vga->private == nil){
vga->private = alloc(sizeof(Laguna));
if((p = pcimatch(0, 0x1013, 0)) == nil)
error("%s: not found\n", ctlr->name);
switch(p->did){
case 0xD0: /* CL-GD5462 */
vga->f[1] = 170000000;
break;
case 0xD4: /* CL-GD5464 */
case 0xD6: /* CL-GD5465 */
vga->f[1] = 230000000;
break;
default:
error("%s: not found\n", ctlr->name);
}
if((f = sys_open("#v/vgactl", OWRITE)) < 0)
error("%s: can't open vgactl\n", ctlr->name);
if(jehanne_write(f, "type clgd546x", 13) != 13)
error("%s: can't set type\n", ctlr->name);
sys_close(f);
mmio = segattach(0, "clgd546xmmio", 0, p->mem[1].size);
if(mmio == (void*)-1)
error("%s: can't attach mmio segment\n", ctlr->name);
laguna = vga->private;
laguna->pci = p;
laguna->mmio = mmio;
}
laguna = vga->private;
laguna->mem = (vga->sequencer[0x14] & 0x07)+1;
laguna->format = mmio16r(laguna, Format);
laguna->threshold = mmio16r(laguna, Threshold);
laguna->tilectrl = mmio16r(laguna, TileCtrl);
laguna->vsc = mmio32r(laguna, Vsc);
laguna->control = mmio16r(laguna, Control);
laguna->tilectrl2D3D = mmio8r(laguna, TileCtrl2D3D);
vga->vma = vga->vmz = laguna->pci->mem[0].size;
ctlr->flag |= Hlinear;
ctlr->flag |= Fsnarf;
}
static void
init(Vga* vga, Ctlr* ctlr)
{
Mode *mode;
uint16_t x;
int format, interleave, fetches, nointerleave, notile, pagesize, tiles;
Laguna *laguna;
nointerleave = 1;
notile = 1;
pagesize = 0;
mode = vga->mode;
if(vga->f[0] == 0)
vga->f[0] = vga->mode->frequency;
if(vga->f[0] > vga->f[1])
error("%s: invalid pclk - %lud\n", ctlr->name, vga->f[0]);
if(mode->z > 8)
error("%s: depth %d not supported\n", ctlr->name, mode->z);
/*
* VCLK3
*/
clgd54xxclock(vga, ctlr);
vga->misc |= 0x0C;
vga->sequencer[0x1E] = vga->n[0];
vga->sequencer[0x0E] = (vga->d[0]<<1)|vga->p[0];
vga->sequencer[0x07] = 0x00;
if(mode->z == 8)
vga->sequencer[0x07] |= 0x01;
vga->crt[0x14] = 0;
vga->crt[0x17] = 0xC3;
/*
* Overflow bits.
*/
vga->crt[0x1A] = 0x00;
x = mode->ehb>>3;
if(x & 0x40)
vga->crt[0x1A] |= 0x10;
if(x & 0x80)
vga->crt[0x1A] |= 0x20;
if(vga->crt[0x16] & 0x100)
vga->crt[0x1A] |= 0x40;
if(vga->crt[0x16] & 0x200)
vga->crt[0x1A] |= 0x80;
vga->crt[0x1B] = 0x22;
if(vga->crt[0x13] & 0x100)
vga->crt[0x1B] |= 0x10;
vga->crt[0x1D] = 0x00;
if(vga->crt[0x13] & 0x200)
vga->crt[0x1D] |= 0x01;
vga->crt[0x1E] = 0x00;
if(vga->crt[0x10] & 0x400)
vga->crt[0x1E] |= 0x01;
if(vga->crt[0x15] & 0x400)
vga->crt[0x1E] |= 0x02;
if(vga->crt[0x12] & 0x400)
vga->crt[0x1E] |= 0x04;
if(vga->crt[0x06] & 0x400)
vga->crt[0x1E] |= 0x08;
if(vga->crt[0x04] & 0x100)
vga->crt[0x1E] |= 0x10;
if(vga->crt[0x02] & 0x100)
vga->crt[0x1E] |= 0x20;
if(vga->crt[0x01] & 0x100)
vga->crt[0x1E] |= 0x40;
if(vga->crt[0x00] & 0x100)
vga->crt[0x1E] |= 0x80;
vga->graphics[0x0B] = 0x00;
if(vga->vmz > 1024*1024)
vga->graphics[0x0B] |= 0x20;
if(mode->interlace == 'v'){
vga->crt[0x19] = vga->crt[0x00]/2;
vga->crt[0x1A] |= 0x01;
}
if(vga->linear && (ctlr->flag & Hlinear))
ctlr->flag |= Ulinear;
laguna = vga->private;
/*
* Ignore wide tiles for now, this simplifies things.
*/
if(mode->x <= 640)
tiles = 5;
else if(mode->x <= 1024)
tiles = 8;
else if(mode->x <= 1280)
tiles = 10;
else if(mode->x <= 1664)
tiles = 13;
else if(mode->x <= 2048)
tiles = 16;
else if(mode->x <= 2560)
tiles = 20;
else if(mode->x <= 3228)
tiles = 26;
else
tiles = 32;
fetches = tiles; /* -1? */
if(nointerleave)
interleave = 0;
else switch(laguna->mem){
default:
interleave = 0;
break;
case 2:
interleave = 1;
break;
case 4:
case 8:
interleave = 2;
break;
}
if(mode->z == 8)
format = 0;
else if(mode->z == 16)
format = (1<<12)|(2<<9);
else if(mode->z == 24)
format = (2<<12)|(2<<9);
else
format = (2<<12)|(2<<9);
//if(ctlr->flag & Ulinear)
// laguna->vsc |= 0x10000000;
//else
laguna->vsc &= ~0x10000000;
laguna->format = format;
laguna->threshold = (interleave<<14)|(fetches<<8)|0x14;
laguna->tilectrl &= 0x3F;
laguna->tilectrl |= (interleave<<14)|(tiles<<8);
if(!notile)
laguna->tilectrl |= 0x80;
if(pagesize == 1)
laguna->tilectrl |= 0x10;
laguna->tilectrl2D3D = (interleave<<6)|tiles;
laguna->control = 0;
if(notile)
laguna->control |= 0x1000;
if(pagesize == 1)
laguna->control |= 0x0200;
}
static void
load(Vga* vga, Ctlr* ctrl)
{
Laguna *laguna;
vgaxo(Seqx, 0x0E, vga->sequencer[0x0E]);
vgaxo(Seqx, 0x1E, vga->sequencer[0x1E]);
vgaxo(Seqx, 0x07, vga->sequencer[0x07]);
if(vga->mode->interlace == 'v')
vgaxo(Crtx, 0x19, vga->crt[0x19]);
vgaxo(Crtx, 0x1A, vga->crt[0x1A]);
vgaxo(Crtx, 0x1B, vga->crt[0x1B]);
vgaxo(Crtx, 0x1D, vga->crt[0x1D]);
vgaxo(Crtx, 0x1E, vga->crt[0x1E]);
vgaxo(Grx, 0x0B, vga->graphics[0x0B]);
laguna = vga->private;
mmio16w(laguna, Format, laguna->format);
mmio32w(laguna, Vsc, laguna->vsc);
mmio16w(laguna, Threshold, laguna->threshold);
mmio16w(laguna, TileCtrl, laguna->tilectrl);
mmio8w(laguna, TileCtrl2D3D, laguna->tilectrl2D3D);
mmio16w(laguna, Control, laguna->control);
}
static void
dump(Vga* vga, Ctlr* ctlr)
{
int i;
char *name;
Laguna *laguna;
name = ctlr->name;
printitem(name, "Seq06");
for(i = 0x06; i < 0x20; i++)
printreg(vga->sequencer[i]);
printitem(name, "Crt19");
for(i = 0x19; i < 0x20; i++)
printreg(vga->crt[i]);
printitem(name, "Gr09");
for(i = 0x09; i < 0x0C; i++)
printreg(vga->graphics[i]);
laguna = vga->private;
Bprint(&stdout, "\n");
Bprint(&stdout, "%s mem\t\t%d\n", ctlr->name, laguna->mem*1024*1024);
Bprint(&stdout, "%s Format\t\t%uX\n", ctlr->name, laguna->format);
Bprint(&stdout, "%s Threshold\t\t\t%uX\n",
ctlr->name, laguna->threshold);
Bprint(&stdout, "%s TileCtrl\t\t\t%uX\n", ctlr->name, laguna->tilectrl);
Bprint(&stdout, "%s Vsc\t\t%uX\n", ctlr->name, laguna->vsc);
Bprint(&stdout, "%s Control\t\t%uX\n", ctlr->name, laguna->control);
Bprint(&stdout, "%s TileCtrlC2D3D\t\t%uX\n",
ctlr->name, laguna->tilectrl2D3D);
}
Ctlr clgd546x = {
"clgd546x", /* name */
snarf, /* snarf */
0, /* options */
init, /* init */
load, /* load */
dump, /* dump */
};
Ctlr clgd546xhwgc = {
"clgd546xhwgc", /* name */
0, /* snarf */
0, /* options */
0, /* init */
0, /* load */
0, /* dump */
};