Implements the second CMDFIFO2 queue for Voodoo 3, fixing BeOS's Voodoo 3/Banshee drivers, fixes #4794.

This commit is contained in:
OBattler
2024-09-04 15:22:24 +02:00
parent 19a27214e7
commit 7b6e5e5ad9
4 changed files with 443 additions and 3 deletions

View File

@@ -408,6 +408,7 @@ typedef struct voodoo_t {
atomic_int cmd_read;
atomic_int cmd_written;
atomic_int cmd_written_fifo;
atomic_int cmd_written_fifo_2;
voodoo_params_t params_buffer[PARAM_SIZE];
atomic_int params_read_idx[4];
@@ -426,7 +427,20 @@ typedef struct voodoo_t {
uint32_t cmdfifo_amax;
int cmdfifo_holecount;
atomic_uint cmd_status;
uint32_t cmdfifo_base_2;
uint32_t cmdfifo_end_2;
uint32_t cmdfifo_size_2;
int cmdfifo_rp_2;
int cmdfifo_ret_addr_2;
int cmdfifo_in_sub_2;
atomic_int cmdfifo_depth_rd_2;
atomic_int cmdfifo_depth_wr_2;
atomic_int cmdfifo_enabled_2;
uint32_t cmdfifo_amin_2;
uint32_t cmdfifo_amax_2;
int cmdfifo_holecount_2;
atomic_uint cmd_status, cmd_status_2;
uint32_t sSetupMode;
vert_t verts[4];

View File

@@ -222,12 +222,12 @@ voodoo_readl(uint32_t addr, void *priv)
{
int fifo_entries = FIFO_ENTRIES;
int swap_count = voodoo->swap_count;
int written = voodoo->cmd_written + voodoo->cmd_written_fifo;
int written = voodoo->cmd_written + voodoo->cmd_written_fifo + voodoo->cmd_written_fifo_2;
int busy = (written - voodoo->cmd_read) || (voodoo->cmdfifo_depth_rd != voodoo->cmdfifo_depth_wr);
if (SLI_ENABLED && voodoo->type != VOODOO_2) {
voodoo_t *voodoo_other = (voodoo == voodoo->set->voodoos[0]) ? voodoo->set->voodoos[1] : voodoo->set->voodoos[0];
int other_written = voodoo_other->cmd_written + voodoo_other->cmd_written_fifo;
int other_written = voodoo_other->cmd_written + voodoo_other->cmd_written_fifo + voodoo->cmd_written_fifo_2;
if (voodoo_other->swap_count > swap_count)
swap_count = voodoo_other->swap_count;

View File

@@ -204,6 +204,17 @@ enum {
cmdFifoDepth0 = 0x44,
cmdHoleCnt0 = 0x48,
cmdBaseAddr1 = 0x50,
cmdBaseSize1 = 0x50 + 0x4,
cmdBump1 = 0x50 + 0x8,
cmdRdPtrL1 = 0x50 + 0xc,
cmdRdPtrH1 = 0x50 + 0x10,
cmdAMin1 = 0x50 + 0x14,
cmdAMax1 = 0x50 + 0x1c,
cmdStatus1 = 0x50 + 0x20,
cmdFifoDepth1 = 0x50 + 0x24,
cmdHoleCnt1 = 0x50 + 0x28,
Agp_agpReqSize = 0x00,
Agp_agpHostAddressLow = 0x04,
Agp_agpHostAddressHigh = 0x08,
@@ -1341,6 +1352,29 @@ banshee_cmd_read(banshee_t *banshee, uint32_t addr)
ret = voodoo->cmdfifo_size;
break;
case cmdBaseAddr1:
ret = voodoo->cmdfifo_base_2 >> 12;
// banshee_log("Read cmdfifo_base %08x\n", ret);
break;
case cmdRdPtrL1:
ret = voodoo->cmdfifo_rp_2;
// banshee_log("Read cmdfifo_rp %08x\n", ret);
break;
case cmdFifoDepth1:
ret = voodoo->cmdfifo_depth_wr_2 - voodoo->cmdfifo_depth_rd_2;
// banshee_log("Read cmdfifo_depth %08x\n", ret);
break;
case cmdStatus1:
ret = voodoo->cmd_status_2;
break;
case cmdBaseSize1:
ret = voodoo->cmdfifo_size_2;
break;
case 0x108:
break;
@@ -1625,6 +1659,45 @@ banshee_cmd_write(banshee_t *banshee, uint32_t addr, uint32_t val)
voodoo->cmdfifo_depth_wr = val & 0xffff;
break;
case cmdBaseAddr1:
voodoo->cmdfifo_base_2 = (val & 0xfff) << 12;
voodoo->cmdfifo_end_2 = voodoo->cmdfifo_base_2 + (((voodoo->cmdfifo_size_2 & 0xff) + 1) << 12);
#if 0
banshee_log("cmdfifo_base=%08x cmdfifo_end=%08x %08x\n", voodoo->cmdfifo_base, voodoo->cmdfifo_end, val);
#endif
break;
case cmdBaseSize1:
voodoo->cmdfifo_size_2 = val;
voodoo->cmdfifo_end_2 = voodoo->cmdfifo_base_2 + (((voodoo->cmdfifo_size_2 & 0xff) + 1) << 12);
voodoo->cmdfifo_enabled_2 = val & 0x100;
if (!voodoo->cmdfifo_enabled_2)
voodoo->cmdfifo_in_sub_2 = 0; /*Not sure exactly when this should be reset*/
#if 0
banshee_log("cmdfifo_base=%08x cmdfifo_end=%08x\n", voodoo->cmdfifo_base, voodoo->cmdfifo_end);
#endif
break;
#if 0
voodoo->cmdfifo_end = ((val >> 16) & 0x3ff) << 12;
banshee_log("CMDFIFO base=%08x end=%08x\n", voodoo->cmdfifo_base, voodoo->cmdfifo_end);
break;
#endif
case cmdRdPtrL1:
voodoo->cmdfifo_rp_2 = val;
break;
case cmdAMin1:
voodoo->cmdfifo_amin_2 = val;
break;
case cmdAMax1:
voodoo->cmdfifo_amax_2 = val;
break;
case cmdFifoDepth1:
voodoo->cmdfifo_depth_rd_2 = 0;
voodoo->cmdfifo_depth_wr_2 = val & 0xffff;
break;
default:
banshee_log("Unknown banshee_cmd_write: addr=%08x val=%08x reg=0x%03x\n", addr, val, addr & 0x1fc);
break;
@@ -2064,6 +2137,60 @@ banshee_write_linear_l(uint32_t addr, uint32_t val, void *priv)
voodoo->cmdfifo_holecount = ((voodoo->cmdfifo_amax - voodoo->cmdfifo_amin) >> 2) - 1;
#if 0
banshee_log("CMDFIFO out of order: amin=%08x amax=%08x holecount=%i\n", voodoo->cmdfifo_amin, voodoo->cmdfifo_amax, voodoo->cmdfifo_holecount);
#endif
}
}
if (voodoo->cmdfifo_enabled_2 && addr >= voodoo->cmdfifo_base_2 && addr < voodoo->cmdfifo_end_2) {
#if 0
banshee_log("CMDFIFO write %08x %08x old amin=%08x amax=%08x hlcnt=%i depth_wr=%i rp=%08x\n", addr, val, voodoo->cmdfifo_amin, voodoo->cmdfifo_amax, voodoo->cmdfifo_holecount, voodoo->cmdfifo_depth_wr, voodoo->cmdfifo_rp);
#endif
if (addr == voodoo->cmdfifo_base_2 && !voodoo->cmdfifo_holecount_2) {
#if 0
if (voodoo->cmdfifo_holecount)
fatal("CMDFIFO reset pointers while outstanding holes\n");
#endif
/*Reset pointers*/
voodoo->cmdfifo_amin_2 = voodoo->cmdfifo_base_2;
voodoo->cmdfifo_amax_2 = voodoo->cmdfifo_base_2;
voodoo->cmdfifo_depth_wr_2++;
voodoo_wake_fifo_thread(voodoo);
} else if (voodoo->cmdfifo_holecount_2) {
#if 0
if ((addr <= voodoo->cmdfifo_amin && voodoo->cmdfifo_amin != -4) || addr >= voodoo->cmdfifo_amax)
fatal("CMDFIFO holecount write outside of amin/amax - amin=%08x amax=%08x holecount=%i\n", voodoo->cmdfifo_amin, voodoo->cmdfifo_amax, voodoo->cmdfifo_holecount);
banshee_log("holecount %i\n", voodoo->cmdfifo_holecount);
#endif
voodoo->cmdfifo_holecount_2--;
if (!voodoo->cmdfifo_holecount_2) {
/*Filled in holes, resume normal operation*/
voodoo->cmdfifo_depth_wr_2 += ((voodoo->cmdfifo_amax_2 - voodoo->cmdfifo_amin_2) >> 2);
voodoo->cmdfifo_amin_2 = voodoo->cmdfifo_amax_2;
voodoo_wake_fifo_thread(voodoo);
#if 0
banshee_log("hole filled! amin=%08x amax=%08x added %i words\n", voodoo->cmdfifo_amin, voodoo->cmdfifo_amax, words_to_add);
#endif
}
} else if (addr == voodoo->cmdfifo_amax_2 + 4) {
/*In-order write*/
voodoo->cmdfifo_amin_2 = addr;
voodoo->cmdfifo_amax_2 = addr;
voodoo->cmdfifo_depth_wr_2++;
voodoo_wake_fifo_thread(voodoo);
} else {
/*Out-of-order write*/
if (addr < voodoo->cmdfifo_amin_2) {
/*Reset back to start. Note that write is still out of order!*/
voodoo->cmdfifo_amin_2 = voodoo->cmdfifo_base_2 - 4;
}
#if 0
else if (addr < voodoo->cmdfifo_amax)
fatal("Out-of-order write really out of order\n");
#endif
voodoo->cmdfifo_amax_2 = addr;
voodoo->cmdfifo_holecount_2 = ((voodoo->cmdfifo_amax_2 - voodoo->cmdfifo_amin_2) >> 2) - 1;
#if 0
banshee_log("CMDFIFO out of order: amin=%08x amax=%08x holecount=%i\n", voodoo->cmdfifo_amin, voodoo->cmdfifo_amax, voodoo->cmdfifo_holecount);
#endif
}
}
@@ -3313,6 +3440,7 @@ banshee_init_common(const device_t *info, char *fn, int has_sgram, int type, int
banshee->voodoo->tex_mem_w[1] = (uint16_t *) banshee->svga.vram;
banshee->voodoo->texture_mask = banshee->svga.vram_mask;
banshee->voodoo->cmd_status = (1 << 28);
banshee->voodoo->cmd_status_2 = (1 << 28);
voodoo_generate_filter_v1(banshee->voodoo);
banshee->vidSerialParallelPort = VIDSERIAL_DDC_DCK_W | VIDSERIAL_DDC_DDA_W;

View File

@@ -188,6 +188,40 @@ cmdfifo_get_f(voodoo_t *voodoo)
return tempif.f;
}
static uint32_t
cmdfifo_get_2(voodoo_t *voodoo)
{
uint32_t val;
if (!voodoo->cmdfifo_in_sub_2) {
while (voodoo->fifo_thread_run && (voodoo->cmdfifo_depth_rd_2 == voodoo->cmdfifo_depth_wr_2)) {
thread_wait_event(voodoo->wake_fifo_thread, -1);
thread_reset_event(voodoo->wake_fifo_thread);
}
}
val = *(uint32_t *) &voodoo->fb_mem[voodoo->cmdfifo_rp_2 & voodoo->fb_mask];
if (!voodoo->cmdfifo_in_sub_2)
voodoo->cmdfifo_depth_rd_2++;
voodoo->cmdfifo_rp_2 += 4;
// voodoo_fifo_log(" CMDFIFO get %08x\n", val);
return val;
}
static inline float
cmdfifo_get_f_2(voodoo_t *voodoo)
{
union {
uint32_t i;
float f;
} tempif;
tempif.i = cmdfifo_get(voodoo);
return tempif.f;
}
enum {
CMDFIFO3_PC_MASK_RGB = (1 << 10),
CMDFIFO3_PC_MASK_ALPHA = (1 << 11),
@@ -283,6 +317,7 @@ voodoo_fifo_thread(void *param)
}
voodoo->cmd_status |= (1 << 24);
voodoo->cmd_status_2 |= (1 << 24);
while (voodoo->cmdfifo_enabled && (voodoo->cmdfifo_depth_rd != voodoo->cmdfifo_depth_wr || voodoo->cmdfifo_in_sub)) {
uint64_t start_time = plat_timer_read();
@@ -545,6 +580,269 @@ voodoo_fifo_thread(void *param)
end_time = plat_timer_read();
voodoo->time += end_time - start_time;
}
while (voodoo->cmdfifo_enabled_2 && (voodoo->cmdfifo_depth_rd_2 != voodoo->cmdfifo_depth_wr_2 || voodoo->cmdfifo_in_sub_2)) {
uint64_t start_time = plat_timer_read();
uint64_t end_time;
uint32_t header = cmdfifo_get_2(voodoo);
uint32_t addr;
uint32_t mask;
int smode;
int num;
int num_verticies;
int v_num;
#if 0
voodoo_fifo_log(" CMDFIFO header %08x at %08x\n", header, voodoo->cmdfifo_rp);
#endif
voodoo->cmd_status_2 &= ~7;
voodoo->cmd_status_2 |= (header & 7);
voodoo->cmd_status_2 |= (1 << 11);
switch (header & 7) {
case 0:
#if 0
voodoo_fifo_log("CMDFIFO0\n");
#endif
voodoo->cmd_status_2 = (voodoo->cmd_status_2 & 0xffff8fff) | (((header >> 3) & 7) << 12);
switch ((header >> 3) & 7) {
case 0: /*NOP*/
break;
case 1: /*JSR*/
#if 0
voodoo_fifo_log("JSR %08x\n", (header >> 4) & 0xfffffc);
#endif
voodoo->cmdfifo_ret_addr_2 = voodoo->cmdfifo_rp_2;
voodoo->cmdfifo_rp_2 = (header >> 4) & 0xfffffc;
voodoo->cmdfifo_in_sub_2 = 1;
break;
case 2: /*RET*/
voodoo->cmdfifo_rp_2 = voodoo->cmdfifo_ret_addr_2;
voodoo->cmdfifo_in_sub_2 = 0;
break;
case 3: /*JMP local frame buffer*/
voodoo->cmdfifo_rp_2 = (header >> 4) & 0xfffffc;
#if 0
voodoo_fifo_log("JMP to %08x %04x\n", voodoo->cmdfifo_rp, header);
#endif
break;
default:
fatal("Bad CMDFIFO0 %08x\n", header);
}
voodoo->cmd_status_2 = (voodoo->cmd_status_2 & ~(1 << 27)) | (voodoo->cmdfifo_in_sub_2 << 27);
break;
case 1:
num = header >> 16;
addr = (header & 0x7ff8) >> 1;
#if 0
voodoo_fifo_log("CMDFIFO1 addr=%08x\n",addr);
#endif
while (num--) {
uint32_t val = cmdfifo_get_2(voodoo);
if ((addr & (1 << 13)) && voodoo->type >= VOODOO_BANSHEE) {
#if 0
if (voodoo->type != VOODOO_BANSHEE)
fatal("CMDFIFO1: Not Banshee\n");
#endif
#if 0
voodoo_fifo_log("CMDFIFO1: write %08x %08x\n", addr, val);
#endif
voodoo_2d_reg_writel(voodoo, addr, val);
} else {
if ((addr & 0x3ff) == SST_triangleCMD || (addr & 0x3ff) == SST_ftriangleCMD || (addr & 0x3ff) == SST_fastfillCMD || (addr & 0x3ff) == SST_nopCMD)
voodoo->cmd_written_fifo_2++;
if (voodoo->type >= VOODOO_BANSHEE && (addr & 0x3ff) == SST_swapbufferCMD)
voodoo->cmd_written_fifo_2++;
voodoo_reg_writel(addr, val, voodoo);
}
if (header & (1 << 15))
addr += 4;
}
break;
case 2:
if (voodoo->type < VOODOO_2)
fatal("CMDFIFO2: Not Voodoo 2\n");
mask = (header >> 3);
addr = 8;
while (mask) {
if (mask & 1) {
uint32_t val = cmdfifo_get_2(voodoo);
voodoo_2d_reg_writel(voodoo, addr, val);
}
addr += 4;
mask >>= 1;
}
break;
case 3:
num = (header >> 29) & 7;
mask = header; //(header >> 10) & 0xff;
smode = (header >> 22) & 0xf;
voodoo_reg_writel(SST_sSetupMode, ((header >> 10) & 0xff) | (smode << 16), voodoo);
num_verticies = (header >> 6) & 0xf;
v_num = 0;
if (((header >> 3) & 7) == 2)
v_num = 1;
#if 0
voodoo_fifo_log("CMDFIFO3: num=%i verts=%i mask=%02x\n", num, num_verticies, (header >> 10) & 0xff);
voodoo_fifo_log("CMDFIFO3 %02x %i\n", (header >> 10), (header >> 3) & 7);
#endif
while (num_verticies--) {
voodoo->verts[3].sVx = cmdfifo_get_f_2(voodoo);
voodoo->verts[3].sVy = cmdfifo_get_f_2(voodoo);
if (mask & CMDFIFO3_PC_MASK_RGB) {
if (header & CMDFIFO3_PC) {
uint32_t val = cmdfifo_get_2(voodoo);
voodoo->verts[3].sBlue = (float) (val & 0xff);
voodoo->verts[3].sGreen = (float) ((val >> 8) & 0xff);
voodoo->verts[3].sRed = (float) ((val >> 16) & 0xff);
voodoo->verts[3].sAlpha = (float) ((val >> 24) & 0xff);
} else {
voodoo->verts[3].sRed = cmdfifo_get_f_2(voodoo);
voodoo->verts[3].sGreen = cmdfifo_get_f_2(voodoo);
voodoo->verts[3].sBlue = cmdfifo_get_f_2(voodoo);
}
}
if ((mask & CMDFIFO3_PC_MASK_ALPHA) && !(header & CMDFIFO3_PC))
voodoo->verts[3].sAlpha = cmdfifo_get_f_2(voodoo);
if (mask & CMDFIFO3_PC_MASK_Z)
voodoo->verts[3].sVz = cmdfifo_get_f_2(voodoo);
if (mask & CMDFIFO3_PC_MASK_Wb)
voodoo->verts[3].sWb = cmdfifo_get_f_2(voodoo);
if (mask & CMDFIFO3_PC_MASK_W0)
voodoo->verts[3].sW0 = cmdfifo_get_f_2(voodoo);
if (mask & CMDFIFO3_PC_MASK_S0_T0) {
voodoo->verts[3].sS0 = cmdfifo_get_f_2(voodoo);
voodoo->verts[3].sT0 = cmdfifo_get_f_2(voodoo);
}
if (mask & CMDFIFO3_PC_MASK_W1)
voodoo->verts[3].sW1 = cmdfifo_get_f_2(voodoo);
if (mask & CMDFIFO3_PC_MASK_S1_T1) {
voodoo->verts[3].sS1 = cmdfifo_get_f_2(voodoo);
voodoo->verts[3].sT1 = cmdfifo_get_f_2(voodoo);
}
if (v_num)
voodoo_reg_writel(SST_sDrawTriCMD, 0, voodoo);
else
voodoo_reg_writel(SST_sBeginTriCMD, 0, voodoo);
v_num++;
if (v_num == 3 && ((header >> 3) & 7) == 0)
v_num = 0;
}
while (num--)
cmdfifo_get_2(voodoo);
break;
case 4:
num = (header >> 29) & 7;
mask = (header >> 15) & 0x3fff;
addr = (header & 0x7ff8) >> 1;
#if 0
voodoo_fifo_log("CMDFIFO4 addr=%08x\n",addr);
#endif
while (mask) {
if (mask & 1) {
uint32_t val = cmdfifo_get_2(voodoo);
if ((addr & (1 << 13)) && voodoo->type >= VOODOO_BANSHEE) {
if (voodoo->type < VOODOO_BANSHEE)
fatal("CMDFIFO1: Not Banshee\n");
#if 0
voodoo_fifo_log("CMDFIFO1: write %08x %08x\n", addr, val);
#endif
voodoo_2d_reg_writel(voodoo, addr, val);
} else {
if ((addr & 0x3ff) == SST_triangleCMD || (addr & 0x3ff) == SST_ftriangleCMD || (addr & 0x3ff) == SST_fastfillCMD || (addr & 0x3ff) == SST_nopCMD)
voodoo->cmd_written_fifo_2++;
if (voodoo->type >= VOODOO_BANSHEE && (addr & 0x3ff) == SST_swapbufferCMD)
voodoo->cmd_written_fifo_2++;
voodoo_reg_writel(addr, val, voodoo);
}
}
addr += 4;
mask >>= 1;
}
while (num--)
cmdfifo_get_2(voodoo);
break;
case 5:
#if 0
if (header & 0x3fc00000)
fatal("CMDFIFO packet 5 has byte disables set %08x\n", header);
#endif
num = (header >> 3) & 0x7ffff;
addr = cmdfifo_get_2(voodoo) & 0xffffff;
if (!num)
num = 1;
#if 0
voodoo_fifo_log("CMDFIFO5 addr=%08x num=%i\n", addr, num);
#endif
switch (header >> 30) {
case 0: /*Linear framebuffer (Banshee)*/
case 1: /*Planar YUV*/
if (voodoo->texture_present[0][(addr & voodoo->texture_mask) >> TEX_DIRTY_SHIFT]) {
#if 0
voodoo_fifo_log("texture_present at %08x %i\n", addr, (addr & voodoo->texture_mask) >> TEX_DIRTY_SHIFT);
#endif
flush_texture_cache(voodoo, addr & voodoo->texture_mask, 0);
}
if (voodoo->texture_present[1][(addr & voodoo->texture_mask) >> TEX_DIRTY_SHIFT]) {
#if 0
voodoo_fifo_log("texture_present at %08x %i\n", addr, (addr & voodoo->texture_mask) >> TEX_DIRTY_SHIFT);
#endif
flush_texture_cache(voodoo, addr & voodoo->texture_mask, 1);
}
while (num--) {
uint32_t val = cmdfifo_get_2(voodoo);
if (addr <= voodoo->fb_mask)
*(uint32_t *) &voodoo->fb_mem[addr] = val;
addr += 4;
}
break;
case 2: /*Framebuffer*/
while (num--) {
uint32_t val = cmdfifo_get_2(voodoo);
voodoo_fb_writel(addr, val, voodoo);
addr += 4;
}
break;
case 3: /*Texture*/
while (num--) {
uint32_t val = cmdfifo_get_2(voodoo);
voodoo_tex_writel(addr, val, voodoo);
addr += 4;
}
break;
default:
fatal("CMDFIFO packet 5 bad space %08x %08x\n", header, voodoo->cmdfifo_rp);
}
break;
default:
fatal("Bad CMDFIFO packet %08x %08x\n", header, voodoo->cmdfifo_rp);
}
end_time = plat_timer_read();
voodoo->time += end_time - start_time;
}
voodoo->voodoo_busy = 0;
}
}