plan9fox/sys/src/9/pc/vgahiqvideo.c
cinap_lenrek 4f85115526 kernel: massive pci code rewrite
The new pci code is moved to port/pci.[hc] and shared by
all ports.

Each port has its own PCI controller implementation,
providing the pcicfgrw*() functions for low level pci
config space access. The locking for pcicfgrw*() is now
done by the caller (only port/pci.c).

Device drivers now need to include "../port/pci.h" in
addition to "io.h".

The new code now checks bridge windows and membars,
while enumerating the bus, giving the pc driver a chance
to re-assign them. This is needed because some UEFI
implementations fail to assign the bars for some devices,
so we need to do it outselfs. (See pcireservemem()).

While working on this, it was discovered that the pci
code assimed the smallest I/O bar size is 16 (pcibarsize()),
which is wrong. I/O bars can be as small as 4 bytes.
Bit 1 in an I/O bar is also reserved and should be masked off,
making the port mask: port = bar & ~3;
2020-09-13 20:33:17 +02:00

226 lines
4 KiB
C

#include "u.h"
#include "../port/lib.h"
#include "mem.h"
#include "dat.h"
#include "fns.h"
#include "io.h"
#include "../port/pci.h"
#include "../port/error.h"
#define Image IMAGE
#include <draw.h>
#include <memdraw.h>
#include <cursor.h>
#include "screen.h"
enum {
Xrx = 0x3D6, /* Configuration Extensions Index */
};
static uchar
hiqvideoxi(long port, uchar index)
{
uchar data;
outb(port, index);
data = inb(port+1);
return data;
}
static void
hiqvideoxo(long port, uchar index, uchar data)
{
outb(port, index);
outb(port+1, data);
}
static void
hiqvideolinear(VGAscr*, int, int)
{
}
static void
hiqvideoenable(VGAscr* scr)
{
Pcidev *p;
int vmsize;
/*
* Only once, can't be disabled for now.
*/
if(scr->mmio)
return;
p = scr->pci;
if(p == nil || p->vid != 0x102C)
return;
switch(p->did){
case 0x00C0: /* 69000 HiQVideo */
vmsize = 2*1024*1024;
break;
case 0x00E0: /* 65550 HiQV32 */
case 0x00E4: /* 65554 HiQV32 */
case 0x00E5: /* 65555 HiQV32 */
switch((hiqvideoxi(Xrx, 0x43)>>1) & 0x03){
default:
case 0:
vmsize = 1*1024*1024;
break;
case 1:
vmsize = 2*1024*1024;
break;
}
break;
default:
return;
}
vgalinearpci(scr);
if(scr->paddr)
addvgaseg("hiqvideoscreen", scr->paddr, scr->apsize);
/*
* Find a place for the cursor data in display memory.
* Must be on a 4096-byte boundary.
* scr->mmio holds the virtual address of the cursor
* storage area in the framebuffer region.
*/
scr->storage = vmsize-4096;
scr->mmio = (ulong*)((uchar*)scr->vaddr+scr->storage);
}
static void
hiqvideocurdisable(VGAscr*)
{
hiqvideoxo(Xrx, 0xA0, 0x10);
}
static void
hiqvideocurload(VGAscr* scr, Cursor* curs)
{
uchar *p;
int x, y;
/*
* Disable the cursor.
*/
hiqvideocurdisable(scr);
if(scr->mmio == 0)
return;
p = (uchar*)scr->mmio;
for(y = 0; y < 16; y += 2){
*p++ = ~(curs->clr[2*y]|curs->set[2*y]);
*p++ = ~(curs->clr[2*y+1]|curs->set[2*y+1]);
*p++ = 0xFF;
*p++ = 0xFF;
*p++ = ~(curs->clr[2*y+2]|curs->set[2*y+2]);
*p++ = ~(curs->clr[2*y+3]|curs->set[2*y+3]);
*p++ = 0xFF;
*p++ = 0xFF;
*p++ = curs->set[2*y];
*p++ = curs->set[2*y+1];
*p++ = 0x00;
*p++ = 0x00;
*p++ = curs->set[2*y+2];
*p++ = curs->set[2*y+3];
*p++ = 0x00;
*p++ = 0x00;
}
while(y < 32){
for(x = 0; x < 64; x += 8)
*p++ = 0xFF;
for(x = 0; x < 64; x += 8)
*p++ = 0x00;
y += 2;
}
/*
* Save the cursor hotpoint and enable the cursor.
*/
scr->offset = curs->offset;
hiqvideoxo(Xrx, 0xA0, 0x11);
}
static int
hiqvideocurmove(VGAscr* scr, Point p)
{
int x, y;
if(scr->mmio == 0)
return 1;
if((x = p.x+scr->offset.x) < 0)
x = 0x8000|(-x & 0x07FF);
if((y = p.y+scr->offset.y) < 0)
y = 0x8000|(-y & 0x07FF);
hiqvideoxo(Xrx, 0xA4, x & 0xFF);
hiqvideoxo(Xrx, 0xA5, (x>>8) & 0xFF);
hiqvideoxo(Xrx, 0xA6, y & 0xFF);
hiqvideoxo(Xrx, 0xA7, (y>>8) & 0xFF);
return 0;
}
static void
hiqvideocurenable(VGAscr* scr)
{
uchar xr80;
hiqvideoenable(scr);
if(scr->mmio == 0)
return;
/*
* Disable the cursor.
*/
hiqvideocurdisable(scr);
/*
* Cursor colours.
* Can't call setcolor here as cursor is already locked.
* When done make sure the cursor enable in Xr80 is set.
*/
xr80 = hiqvideoxi(Xrx, 0x80);
hiqvideoxo(Xrx, 0x80, xr80|0x01);
vgao(PaddrW, 0x04);
vgao(Pdata, Pwhite);
vgao(Pdata, Pwhite);
vgao(Pdata, Pwhite);
vgao(Pdata, Pblack);
vgao(Pdata, Pblack);
vgao(Pdata, Pblack);
hiqvideoxo(Xrx, 0x80, xr80|0x10);
hiqvideoxo(Xrx, 0xA2, (scr->storage>>12)<<4);
hiqvideoxo(Xrx, 0xA3, (scr->storage>>16) & 0x3F);
/*
* Load, locate and enable the 32x32 cursor.
* Cursor enable in Xr80 better be set already.
*/
hiqvideocurload(scr, &cursor);
hiqvideocurmove(scr, ZP);
hiqvideoxo(Xrx, 0xA0, 0x11);
}
VGAdev vgahiqvideodev = {
"hiqvideo",
hiqvideoenable, /* enable */
nil, /* disable */
nil, /* page */
hiqvideolinear, /* linear */
};
VGAcur vgahiqvideocur = {
"hiqvideohwgc",
hiqvideocurenable, /* enable */
hiqvideocurdisable, /* disable */
hiqvideocurload, /* load */
hiqvideocurmove, /* move */
};