apu: Add support for DSP FIFOs

This commit is contained in:
Jannik Vogel 2018-12-28 08:10:36 +01:00 committed by mborgerson
parent 423b6f57bc
commit 2e660193a0
1 changed files with 156 additions and 0 deletions

View File

@ -55,7 +55,9 @@
#define NV_PAPU_XGSCNT 0x0000200C
#define NV_PAPU_VPVADDR 0x0000202C
#define NV_PAPU_GPSADDR 0x00002040
#define NV_PAPU_GPFADDR 0x00002044
#define NV_PAPU_EPSADDR 0x00002048
#define NV_PAPU_EPFADDR 0x0000204C
#define NV_PAPU_TVL2D 0x00002054
#define NV_PAPU_CVL2D 0x00002058
#define NV_PAPU_NVL2D 0x0000205C
@ -66,7 +68,42 @@
#define NV_PAPU_CVLMP 0x00002070
#define NV_PAPU_NVLMP 0x00002074
#define NV_PAPU_GPSMAXSGE 0x000020D4
#define NV_PAPU_GPFMAXSGE 0x000020D8
#define NV_PAPU_EPSMAXSGE 0x000020DC
#define NV_PAPU_EPFMAXSGE 0x000020E0
/* Each FIFO has the same fields */
#define NV_PAPU_GPOFBASE0 0x00003024
# define NV_PAPU_GPOFBASE0_VALUE 0x00FFFF00
#define NV_PAPU_GPOFEND0 0x00003028
# define NV_PAPU_GPOFEND0_VALUE 0x00FFFF00
#define NV_PAPU_GPOFCUR0 0x0000302C
# define NV_PAPU_GPOFCUR0_VALUE 0x00FFFFFC
#define NV_PAPU_GPOFBASE1 0x00003034
#define NV_PAPU_GPOFEND1 0x00003038
#define NV_PAPU_GPOFCUR1 0x0000303C
#define NV_PAPU_GPOFBASE2 0x00003044
#define NV_PAPU_GPOFEND2 0x00003048
#define NV_PAPU_GPOFCUR2 0x0000304C
#define NV_PAPU_GPOFBASE3 0x00003054
#define NV_PAPU_GPOFEND3 0x00003058
#define NV_PAPU_GPOFCUR3 0x0000305C
/* Fields are same as for the 4 output FIFOs, but only 2 input FIFOs */
#define NV_PAPU_GPIFBASE0 0x00003064
#define NV_PAPU_GPIFEND0 0x00003068
#define NV_PAPU_GPIFCUR0 0x0000306C
#define NV_PAPU_GPIFBASE1 0x00003074
#define NV_PAPU_GPIFEND1 0x00003078
#define NV_PAPU_GPIFCUR1 0x0000307C
/* Fields, strides and count is same as for GP FIFOs */
#define NV_PAPU_EPOFBASE0 0x00004024
#define NV_PAPU_EPOFEND0 0x00004028
#define NV_PAPU_EPOFCUR0 0x0000402C
#define NV_PAPU_EPIFBASE0 0x00004064
#define NV_PAPU_EPIFEND0 0x00004068
#define NV_PAPU_EPIFCUR0 0x0000406C
#define NV_PAPU_GPXMEM 0x00000000
#define NV_PAPU_GPMIXBUF 0x00005000
@ -122,6 +159,11 @@ static const struct {
# define NV_PAVS_VOICE_TAR_PITCH_LINK_NEXT_VOICE_HANDLE 0x0000FFFF
#define GP_OUTPUT_FIFO_COUNT 4
#define GP_INPUT_FIFO_COUNT 2
#define EP_OUTPUT_FIFO_COUNT 4
#define EP_INPUT_FIFO_COUNT 2
#define MCPX_HW_MAX_VOICES 256
@ -473,6 +515,120 @@ static void ep_scratch_rw(void *opaque,
ptr, addr, len, dir);
}
static uint32_t circular_scatter_gather_rw(MCPXAPUState *d,
hwaddr sge_base,
unsigned int max_sge,
uint8_t *ptr,
uint32_t base, uint32_t end,
uint32_t cur,
size_t len,
bool dir)
{
while (len > 0) {
unsigned int bytes_to_copy = end - cur;
if (bytes_to_copy > len) {
bytes_to_copy = len;
}
MCPX_DPRINTF("circular scatter gather %s in range 0x%x - 0x%x at 0x%x of length 0x%x / 0x%lx bytes\n",
dir ? "write" : "read", base, end, cur, bytes_to_copy, len);
assert((cur >= base) && ((cur + bytes_to_copy) <= end));
scatter_gather_rw(d, sge_base, max_sge, ptr, cur, bytes_to_copy, dir);
ptr += bytes_to_copy;
len -= bytes_to_copy;
/* After the first iteration we might have to wrap */
cur += bytes_to_copy;
if (cur >= end) {
assert(cur == end);
cur = base;
}
}
return cur;
}
static void gp_fifo_rw(void *opaque, uint8_t *ptr,
unsigned int index, size_t len,
bool dir)
{
MCPXAPUState *d = opaque;
uint32_t base;
uint32_t end;
hwaddr cur_reg;
if (dir) {
assert(index < GP_OUTPUT_FIFO_COUNT);
base = GET_MASK(d->regs[NV_PAPU_GPOFBASE0 + 0x10 * index],
NV_PAPU_GPOFBASE0_VALUE);
end = GET_MASK(d->regs[NV_PAPU_GPOFEND0 + 0x10 * index],
NV_PAPU_GPOFEND0_VALUE);
cur_reg = NV_PAPU_GPOFCUR0 + 0x10 * index;
} else {
assert(index < GP_INPUT_FIFO_COUNT);
base = GET_MASK(d->regs[NV_PAPU_GPIFBASE0 + 0x10 * index],
NV_PAPU_GPOFBASE0_VALUE);
end = GET_MASK(d->regs[NV_PAPU_GPIFEND0 + 0x10 * index],
NV_PAPU_GPOFEND0_VALUE);
cur_reg = NV_PAPU_GPIFCUR0 + 0x10 * index;
}
uint32_t cur = GET_MASK(d->regs[cur_reg], NV_PAPU_GPOFCUR0_VALUE);
/* DSP hangs if current >= end; but forces current >= base */
assert(cur < end);
if (cur < base) {
cur = base;
}
cur = circular_scatter_gather_rw(d,
d->regs[NV_PAPU_GPFADDR], d->regs[NV_PAPU_GPFMAXSGE],
ptr, base, end, cur, len, dir);
SET_MASK(d->regs[cur_reg], NV_PAPU_GPOFCUR0_VALUE, cur);
}
static void ep_fifo_rw(void *opaque, uint8_t *ptr,
unsigned int index, size_t len,
bool dir)
{
MCPXAPUState *d = opaque;
uint32_t base;
uint32_t end;
hwaddr cur_reg;
if (dir) {
assert(index < EP_OUTPUT_FIFO_COUNT);
base = GET_MASK(d->regs[NV_PAPU_EPOFBASE0 + 0x10 * index],
NV_PAPU_GPOFBASE0_VALUE);
end = GET_MASK(d->regs[NV_PAPU_EPOFEND0 + 0x10 * index],
NV_PAPU_GPOFEND0_VALUE);
cur_reg = NV_PAPU_EPOFCUR0 + 0x10 * index;
} else {
assert(index < EP_INPUT_FIFO_COUNT);
base = GET_MASK(d->regs[NV_PAPU_EPIFBASE0 + 0x10 * index],
NV_PAPU_GPOFBASE0_VALUE);
end = GET_MASK(d->regs[NV_PAPU_EPIFEND0 + 0x10 * index],
NV_PAPU_GPOFEND0_VALUE);
cur_reg = NV_PAPU_EPIFCUR0 + 0x10 * index;
}
uint32_t cur = GET_MASK(d->regs[cur_reg], NV_PAPU_GPOFCUR0_VALUE);
/* DSP hangs if current >= end; but forces current >= base */
assert(cur < end);
if (cur < base) {
cur = base;
}
cur = circular_scatter_gather_rw(d,
d->regs[NV_PAPU_EPFADDR], d->regs[NV_PAPU_EPFMAXSGE],
ptr, base, end, cur, len, dir);
SET_MASK(d->regs[cur_reg], NV_PAPU_GPOFCUR0_VALUE, cur);
}
static void proc_rst_write(DSPState *dsp, uint32_t oldval, uint32_t val)
{
if (!(val & NV_PAPU_GPRST_GPRST) || !(val & NV_PAPU_GPRST_GPDSPRST)) {