#include <u.h>
#include <libc.h>
#include <stdio.h>
#define V3D_SET_FIELD(v, s, m) (((v)<<(s)) & (m))
typedef struct Bo Bo;
struct Bo {
ulong off;
ulong size;
u32int *base;
};
enum {
V3D_HUB_IDENT0 = 0x08>>2,
V3D_HUB_IDENT1 = 0x0c>>2,
V3D_CTL_L2TFLSTA = 0x34>>2,
V3D_CTL_L2TFLEND = 0x38>>2,
V3D_MMU_CTL = 0x1200>>2,
V3D_MMU_CTL_TLB_CLEAR = 1<<2,
V3D_MMU_CTL_TLB_CLEARING = 1<<7,
V3D_MMU_CTL_ENABLE = 1<<0,
V3D_MMU_CTL_PT_INVALID_ENABLE = 1<<16,
V3D_MMU_CTL_PT_INVALID_ABORT = 1<<19,
V3D_MMU_CTL_PT_INVALID_INT = 1<<18,
V3D_MMU_CTL_WRITE_VIOLATION_ABORT = 1<<11,
V3D_MMU_CTL_WRITE_VIOLATION_INT = 1<<10,
V3D_MMU_CTL_CAP_EXCEEDED_ABORT = 1<<26,
V3D_MMU_CTL_CAP_EXCEEDED_INT = 1<<25,
V3D_MMU_ILLEGAL_ADDR = 0x1230>>2,
V3D_MMU_ILLEGAL_ADDR_ENABLE = 1<<31,
V3D_MMUC_CONTROL = 0x1000>>2,
V3D_MMUC_CONTROL_FLUSHING = 1<<2,
V3D_MMUC_CONTROL_FLUSH = 1<<1,
V3D_MMUC_CONTROL_ENABLE = 1<<0,
V3D_MMU_PT_PA_BASE = 0x1204>>2,
V3D_CSD_QUEUED_CFG = 0x904>>2,
V3D_CSD_STATUS = 0x900>>2,
V3D_PTE_WRITEABLE = 1<<29,
V3D_PTE_VALID = 1<<28,
V3D_PAGE_SHIFT = 12,
V3D_PAGE_SIZE = 1<<V3D_PAGE_SHIFT,
V3D_CTL_L2TCACTL = 0x00030>>2,
V3D_L2TCACTL_TMUWCF = 1<<8,
V3D_L2TCACTL_L2TFLS = 1<<0,
V3D_L2TCACTL_FLM_FLUSH = 0,
V3D_L2TCACTL_FLM_CLEAN = 2,
V3D_L2TCACTL_FLM_MASK = 0xFFFFFFFEUL,
V3D_L2TCACTL_FLM_SHIFT = 1,
};
enum {
WgX = 16,
WgY = 1,
WgZ = 1,
Wgsize = WgX * WgY * WgZ,
Wgspersg = 16,
};
/* Example program that uses 1 QPU to initialize buffer from 0...127 */
static uvlong pgm[] = {
0x3d907186bb800000,
0x3d90b186bb800000,
0x3de031827d83a004,
0x3c003180bb802000,
0x3de031807c838002,
0x3c00318138801000,
0x3de031837c83f004,
0x3c003180bb802000,
0x3c00318bb6800000,
0x3c00318cb6809000,
0x3c003186bb815000,
0x3c00318138819000,
0x3de031803c838010,
0x3de071823c83a001,
0x02ffffb3ff009000,
0x3c003186bb800000,
0x3c003186bb800000,
0x3c003186bb800000,
0x3c203186bb800000,
0x3c203186bb800000,
0x3c003186bb800000,
0x3c003186bb800000,
0x3c203186bb800000,
0x3c003186bb800000,
0x3c003186bb800000,
0x3c003186bb800000,
};
static u32int *hub;
static u32int *core;
static u32int *pt;
void
coherence(void)
{
hub[V3D_MMU_CTL] |= V3D_MMU_CTL_TLB_CLEAR;
hub[V3D_MMUC_CONTROL] = V3D_MMUC_CONTROL_FLUSH | V3D_MMUC_CONTROL_ENABLE;
while(hub[V3D_MMU_CTL] & V3D_MMU_CTL_TLB_CLEARING)
;
while(hub[V3D_MMUC_CONTROL] & V3D_MMUC_CONTROL_FLUSHING)
;
}
Bo *
readbo(char *name)
{
int fd;
char buf[100];
Bo *bo = malloc(sizeof(Bo));
sprint(buf, "v3d%s", name);
bo->base = segattach(0, buf, 0, 0);
if(bo->base == (void *)-1)
sysfatal("segattach %s failed: %r", name);
sprint(buf, "#g/v3d%s/ctl", name);
fd = open(buf, OREAD);
if(fd < 0)
sysfatal("open failed: %r");
if(read(fd, buf, sizeof(buf)) <= 0)
sysfatal("read failed: %r");
sscanf(buf, "va %lx %lx fixed %lx", &bo->off, &bo->size, &bo->off);
return bo;
}
void
mapbo(u32int addr, Bo *bo)
{
u32int i;
u32int npages = bo->size >> V3D_PAGE_SHIFT;
u32int *base = &pt[addr >> V3D_PAGE_SHIFT];
u32int off = bo->off >> V3D_PAGE_SHIFT;
for(i = 0; i < npages; i++)
base[i] = V3D_PTE_VALID | V3D_PTE_WRITEABLE | (off + i);
coherence();
}
void
main()
{
Bo *mmu, *code, *bo, *unif;
char buf[32];
int donefd;
hub = segattach(0, "v3d", nil, 0x8000);
if(hub == (void *)-1)
sysfatal("segattach failed: %r");
core = hub + (0x4000>>2);
if(hub[V3D_HUB_IDENT0] != 0x42554856)
sysfatal("videocore fell off");
core[V3D_CTL_L2TFLSTA] = 0;
core[V3D_CTL_L2TFLEND] = ~0;
donefd = open("#β/done", OREAD);
if(donefd < 0)
sysfatal("open failed: %r");
mmu = readbo("mmu");
pt = mmu->base;
code = readbo("code");
bo = readbo("bo");
unif = readbo("unif");
hub[V3D_MMU_PT_PA_BASE] = mmu->off >> V3D_PAGE_SHIFT;
hub[V3D_MMU_CTL] = V3D_MMU_CTL_ENABLE | V3D_MMU_CTL_PT_INVALID_ENABLE | V3D_MMU_CTL_PT_INVALID_ABORT | V3D_MMU_CTL_PT_INVALID_INT | V3D_MMU_CTL_WRITE_VIOLATION_ABORT | V3D_MMU_CTL_WRITE_VIOLATION_INT | V3D_MMU_CTL_CAP_EXCEEDED_ABORT | V3D_MMU_CTL_CAP_EXCEEDED_INT;
hub[V3D_MMU_ILLEGAL_ADDR] = ((mmu->off + 0x400000) >> V3D_PAGE_SHIFT) | V3D_MMU_ILLEGAL_ADDR_ENABLE;
hub[V3D_MMUC_CONTROL] = V3D_MMUC_CONTROL_ENABLE;
coherence();
/* These addresses are chosen arbitrarily for now - we could have done 1:1 as well */
u32int codeaddr = 0x4200<<V3D_PAGE_SHIFT;
mapbo(codeaddr, code);
u32int boaddr = 0x4300<<V3D_PAGE_SHIFT;
mapbo(boaddr, bo);
u32int unifaddr = 0x4400<<V3D_PAGE_SHIFT;
mapbo(unifaddr, unif);
unif->base[0] = boaddr;
unif->base[1] = 128;
memcpy(code->base, pgm, sizeof(pgm));
/* Clear cache beforehand */
core[V3D_CTL_L2TCACTL] = V3D_L2TCACTL_L2TFLS | V3D_SET_FIELD(V3D_L2TCACTL_FLM_FLUSH, V3D_L2TCACTL_FLM_SHIFT, V3D_L2TCACTL_FLM_MASK);
core[V3D_CSD_QUEUED_CFG+1] = WgY << 16;
core[V3D_CSD_QUEUED_CFG+2] = WgZ << 16;
core[V3D_CSD_QUEUED_CFG+3] = ((((Wgspersg * Wgsize + 15) / 16) - 1) << 12) | (Wgspersg << 8) | (Wgsize & 0xff);
core[V3D_CSD_QUEUED_CFG+4] = 0;
core[V3D_CSD_QUEUED_CFG+5] = codeaddr;
core[V3D_CSD_QUEUED_CFG+6] = unifaddr;
core[V3D_CSD_QUEUED_CFG+0] = WgX << 16; /* Kicks off */
/* Barrier */
read(donefd, buf, sizeof(buf));
/* Flush TMU */
core[V3D_CTL_L2TCACTL] = V3D_L2TCACTL_TMUWCF;
while(core[V3D_CTL_L2TCACTL] & V3D_L2TCACTL_TMUWCF)
;
core[V3D_CTL_L2TCACTL] = V3D_L2TCACTL_L2TFLS | V3D_SET_FIELD(V3D_L2TCACTL_FLM_CLEAN, V3D_L2TCACTL_FLM_SHIFT, V3D_L2TCACTL_FLM_MASK);
while(core[V3D_CTL_L2TCACTL] & V3D_L2TCACTL_L2TFLS)
;
for(int i = 0; i < 128; i++){
print("%d ", bo->base[i]);
}
print("\n");
exits(nil);
}
|