The PM4_STAT register largely mirrors the flags of the GUI_STAT register. The exception is that the low bits of PM4_STAT reflect the remaining slots in the CCE FIFO instead of the GUI FIFO.
This implements a very incomplete set of common flags (MICRO_BUSY and GUI_ACTIVE) and the PM4_STAT register. Signed-off-by: Chad Jablonski <[email protected]> --- hw/display/ati.c | 16 +++++++++++++++- hw/display/ati_cce.c | 38 ++++++++++++++++++++++++++++++++++++++ hw/display/ati_cce.h | 3 +++ hw/display/ati_regs.h | 1 + 4 files changed, 57 insertions(+), 1 deletion(-) diff --git a/hw/display/ati.c b/hw/display/ati.c index e7ba202bbd..df3b727b27 100644 --- a/hw/display/ati.c +++ b/hw/display/ati.c @@ -276,6 +276,16 @@ static inline uint64_t ati_reg_read_offs(uint32_t reg, int offs, } } +static uint32_t ati_common_stat(ATIVGAState *s) +{ + /* TODO: This is _very_ naive. It will evolve. */ + uint32_t micro_busy = ati_cce_micro_busy(&s->cce.cur_packet) ? + MICRO_BUSY : 0; + /* GUI_ACTIVE is the OR of all other status flags */ + uint32_t gui_active = micro_busy ? GUI_ACTIVE : 0; + return gui_active | micro_busy; +} + static uint64_t ati_mm_read(void *opaque, hwaddr addr, unsigned int size) { ATIVGAState *s = opaque; @@ -383,7 +393,7 @@ static uint64_t ati_mm_read(void *opaque, hwaddr addr, unsigned int size) break; case RBBM_STATUS: case GUI_STAT: - val = 64; /* free CMDFIFO entries */ + val = ati_common_stat(s) | 64; /* free CMDFIFO entries */ break; case CRTC_H_TOTAL_DISP: val = s->regs.crtc_h_total_disp; @@ -568,6 +578,10 @@ static uint64_t ati_mm_read(void *opaque, hwaddr addr, unsigned int size) case PM4_MICRO_CNTL: val = s->cce.freerun ? PM4_MICRO_FREERUN : 0; break; + case PM4_STAT: { + val = ati_common_stat(s) | ati_cce_fifo_cnt(&s->cce); + break; + } default: break; } diff --git a/hw/display/ati_cce.c b/hw/display/ati_cce.c index 62a88a54df..3d35b0e857 100644 --- a/hw/display/ati_cce.c +++ b/hw/display/ati_cce.c @@ -11,6 +11,24 @@ #include "ati_int.h" #include "trace.h" +static uint32_t +ati_cce_fifo_max(uint8_t mode) +{ + switch (mode) { + case PM4_BUFFER_CNTL_NONPM4...PM4_BUFFER_CNTL_192BM: + return 192; + case PM4_BUFFER_CNTL_128PIO_64INDBM...PM4_BUFFER_CNTL_128BM_64INDBM: + return 128; + case PM4_BUFFER_CNTL_64PIO_128INDBM...PM4_BUFFER_CNTL_64PIO_64VCBM_64INDBM: + /* fall through */ + case PM4_BUFFER_CNTL_64PIO_64VCPIO_64INPIO: + return 64; + default: + /* Undocumented but testing shows this returns 192 otherwise */ + return 192; + } +} + static inline uint32_t ati_cce_data_packets_remaining(const ATIPM4PacketState *p) { @@ -154,3 +172,23 @@ ati_cce_receive_data(ATIVGAState *s, uint32_t data) } ati_cce_process_packet_data(s, data); } + +bool +ati_cce_micro_busy(const ATIPM4PacketState *p) +{ + uint32_t remaining = ati_cce_data_packets_remaining(p); + if (remaining > 0) { + return true; + } + return false; +} + +uint32_t +ati_cce_fifo_cnt(const ATICCEState *c) +{ + /* + * This should return the available slots. Given that commands are + * processed immediately this returns the fifo max for now. + */ + return ati_cce_fifo_max(c->buffer_mode); +} diff --git a/hw/display/ati_cce.h b/hw/display/ati_cce.h index b6ad21f47e..12aede6ecc 100644 --- a/hw/display/ati_cce.h +++ b/hw/display/ati_cce.h @@ -85,4 +85,7 @@ typedef struct ATICCEState { } ATICCEState; void ati_cce_receive_data(ATIVGAState *s, uint32_t data); +bool ati_cce_micro_busy(const ATIPM4PacketState *p); +uint32_t ati_cce_fifo_cnt(const ATICCEState *c); + #endif /* ATI_CCE_H */ diff --git a/hw/display/ati_regs.h b/hw/display/ati_regs.h index 190b99184c..66f7e3f518 100644 --- a/hw/display/ati_regs.h +++ b/hw/display/ati_regs.h @@ -289,6 +289,7 @@ /* CONSTANTS */ #define GUI_ACTIVE 0x80000000 +#define MICRO_BUSY 0x00020000 #define ENGINE_IDLE 0x0 #define PLL_WR_EN 0x00000080 -- 2.51.2
