summaryrefslogtreecommitdiff
path: root/sys/src/cmd/aux/vga/igfx.c
diff options
context:
space:
mode:
authorcinap_lenrek <cinap_lenrek@felloff.net>2017-11-13 00:48:46 +0100
committercinap_lenrek <cinap_lenrek@felloff.net>2017-11-13 00:48:46 +0100
commitf4880742fd204d538168c8bae11ba2935b2b13d6 (patch)
tree755f520e959e03362fc9f4470c174ef09744868c /sys/src/cmd/aux/vga/igfx.c
parent3356e0e731bb8e0f4c82caebe358fae2c8fc9113 (diff)
igfx: allocate backing memory for framebuffer and hw cursor when not done by bios (from qu7uux)
new approach to graphics memory management: the kernel driver never really cared about the size of stolen memory directly. that was only to figure out the maximum allocation to place the hardware cursor image somewhere at the end of the allocation done by bios. qu7uux's gm965 bios however wont steal enougth memory for his native resolution so we have todo it manually. the userspace igfx driver will figure out how much the bios allocated by looking at the gtt only. then extend the memory by creating a "fixed" physical segment. the kernel driver allocates the memory for the cursor image from normal kernel memory, and just maps it into the gtt at the end of the virtual kernel framebuffer aperture. thanks to qu7uux for the patch.
Diffstat (limited to 'sys/src/cmd/aux/vga/igfx.c')
-rw-r--r--sys/src/cmd/aux/vga/igfx.c73
1 files changed, 73 insertions, 0 deletions
diff --git a/sys/src/cmd/aux/vga/igfx.c b/sys/src/cmd/aux/vga/igfx.c
index cc595c132..48a2a363e 100644
--- a/sys/src/cmd/aux/vga/igfx.c
+++ b/sys/src/cmd/aux/vga/igfx.c
@@ -1593,6 +1593,76 @@ disablepipe(Igfx *igfx, int x)
csr(igfx, igfx->dpllsel[0].a, 8<<(x*4), 0);
}
+void
+checkgtt(Igfx *igfx, Mode *m)
+{
+ int fd, c;
+ ulong n;
+ char buf[64], *fl[5];
+ u32int i, j, pa, nilpte, *gtt;
+
+ if(igfx->mmio == nil)
+ return;
+ gtt = (u32int*)((uchar*)igfx->mmio + igfx->pci->mem[0].size/2);
+ pa = (gtt[0] & ~((1<<12)-1)) + (1<<12) | 1;
+ for(i=1; i<64*1024/4-4; i++, pa+=1<<12)
+ if((gtt[i] & ~((1<<11)-1<<1)) != pa)
+ break;
+ n = m->x * m->y * m->z / 8;
+ if(i<<12 >= n)
+ return;
+
+ /* unmap pages past stolen memory */
+ nilpte = gtt[64*1024/4-5];
+ wr(igfx, 0x2170, 0); /* flush write buffers */
+ for(j=i; j<64*1024/4-5; j++){
+ if((gtt[j] & 1) == 0 || (gtt[j] & ~((1<<11)-1<<1)) == pa)
+ break;
+ pa = gtt[j];
+ gtt[j] = nilpte;
+ }
+ wr(igfx, 0x2170, 0); /* flush write buffers */
+
+ trace("%s: mapping %lud additional bytes for requested mode\n", igfx->ctlr->name, n - (i<<12));
+ snprint(buf, sizeof buf, "#g/igfxtra");
+ if((fd = open(buf, OREAD)) >= 0){
+ close(fd);
+ if(remove(buf) < 0)
+ goto err;
+ }
+ if((fd = create(buf, OREAD, DMDIR|0777)) < 0)
+ goto err;
+ close(fd);
+ strncat(buf, "/ctl", sizeof(buf)-strlen("/ctl"));
+ if((fd = open(buf, ORDWR|OTRUNC)) < 0)
+ goto err;
+ snprint(buf, sizeof buf, "va 0x10000000 %#lux fixed", n - (i<<12));
+ if(write(fd, buf, strlen(buf)) < 0){
+ close(fd);
+ goto err;
+ }
+ seek(fd, 0, 0);
+ if((c = read(fd, buf, sizeof buf)) <= 0){
+ close(fd);
+ goto err;
+ }
+ close(fd);
+ buf[c-1] = 0;
+ if(getfields(buf, fl, nelem(fl), 0, " ") != nelem(fl)
+ || (pa = strtoul(fl[4], nil, 16)) == 0){
+ werrstr("invalid physical base address");
+ goto err;
+ }
+ n >>= 12;
+ wr(igfx, 0x2170, 0); /* flush write buffers */
+ for(; i<n; i++, pa+=1<<12)
+ gtt[i] = pa | 1;
+ wr(igfx, 0x2170, 0); /* flush write buffers */
+ return;
+err:
+ trace("%s: checkgtt: %r\n", igfx->ctlr->name);
+}
+
static void
load(Vga* vga, Ctlr* ctlr)
{
@@ -1638,6 +1708,9 @@ load(Vga* vga, Ctlr* ctlr)
for(x = 0; x < igfx->npipe; x++)
disablepipe(igfx, x);
+ /* check if enough memory has been mapped for requested mode */
+ checkgtt(igfx, vga->mode);
+
if(igfx->type == TypeG45){
/* toggle dsp a on and off (from enable sequence) */
csr(igfx, igfx->pipe[0].conf.a, 3<<18, 0);