Commit 67a82dbc authored by Thierry Reding's avatar Thierry Reding

gpu: host1x: Support 40-bit addressing

Tegra186 and later support 40 bits of address space. Additional
registers need to be programmed to store the full 40 bits of push
buffer addresses.

Since command stream gathers can also reside in buffers in a 40-bit
address space, a new variant of the GATHER opcode is also introduced.
It takes two parameters: the first parameter contains the lower 32
bits of the address and the second parameter contains bits 32 to 39.
Signed-off-by: default avatarThierry Reding <treding@nvidia.com>
parent 5a5fccbd
...@@ -68,20 +68,31 @@ static void cdma_timeout_cpu_incr(struct host1x_cdma *cdma, u32 getptr, ...@@ -68,20 +68,31 @@ static void cdma_timeout_cpu_incr(struct host1x_cdma *cdma, u32 getptr,
static void cdma_start(struct host1x_cdma *cdma) static void cdma_start(struct host1x_cdma *cdma)
{ {
struct host1x_channel *ch = cdma_to_channel(cdma); struct host1x_channel *ch = cdma_to_channel(cdma);
u64 start, end;
if (cdma->running) if (cdma->running)
return; return;
cdma->last_pos = cdma->push_buffer.pos; cdma->last_pos = cdma->push_buffer.pos;
start = cdma->push_buffer.dma;
end = start + cdma->push_buffer.size + 4;
host1x_ch_writel(ch, HOST1X_CHANNEL_DMACTRL_DMASTOP, host1x_ch_writel(ch, HOST1X_CHANNEL_DMACTRL_DMASTOP,
HOST1X_CHANNEL_DMACTRL); HOST1X_CHANNEL_DMACTRL);
/* set base, put and end pointer */ /* set base, put and end pointer */
host1x_ch_writel(ch, cdma->push_buffer.dma, HOST1X_CHANNEL_DMASTART); host1x_ch_writel(ch, lower_32_bits(start), HOST1X_CHANNEL_DMASTART);
#if HOST1X_HW >= 6
host1x_ch_writel(ch, upper_32_bits(start), HOST1X_CHANNEL_DMASTART_HI);
#endif
host1x_ch_writel(ch, cdma->push_buffer.pos, HOST1X_CHANNEL_DMAPUT); host1x_ch_writel(ch, cdma->push_buffer.pos, HOST1X_CHANNEL_DMAPUT);
host1x_ch_writel(ch, cdma->push_buffer.dma + cdma->push_buffer.size + 4, #if HOST1X_HW >= 6
HOST1X_CHANNEL_DMAEND); host1x_ch_writel(ch, 0, HOST1X_CHANNEL_DMAPUT_HI);
#endif
host1x_ch_writel(ch, lower_32_bits(end), HOST1X_CHANNEL_DMAEND);
#if HOST1X_HW >= 6
host1x_ch_writel(ch, upper_32_bits(end), HOST1X_CHANNEL_DMAEND_HI);
#endif
/* reset GET */ /* reset GET */
host1x_ch_writel(ch, HOST1X_CHANNEL_DMACTRL_DMASTOP | host1x_ch_writel(ch, HOST1X_CHANNEL_DMACTRL_DMASTOP |
...@@ -104,6 +115,7 @@ static void cdma_timeout_restart(struct host1x_cdma *cdma, u32 getptr) ...@@ -104,6 +115,7 @@ static void cdma_timeout_restart(struct host1x_cdma *cdma, u32 getptr)
{ {
struct host1x *host1x = cdma_to_host1x(cdma); struct host1x *host1x = cdma_to_host1x(cdma);
struct host1x_channel *ch = cdma_to_channel(cdma); struct host1x_channel *ch = cdma_to_channel(cdma);
u64 start, end;
if (cdma->running) if (cdma->running)
return; return;
...@@ -113,10 +125,18 @@ static void cdma_timeout_restart(struct host1x_cdma *cdma, u32 getptr) ...@@ -113,10 +125,18 @@ static void cdma_timeout_restart(struct host1x_cdma *cdma, u32 getptr)
host1x_ch_writel(ch, HOST1X_CHANNEL_DMACTRL_DMASTOP, host1x_ch_writel(ch, HOST1X_CHANNEL_DMACTRL_DMASTOP,
HOST1X_CHANNEL_DMACTRL); HOST1X_CHANNEL_DMACTRL);
start = cdma->push_buffer.dma;
end = start + cdma->push_buffer.size + 4;
/* set base, end pointer (all of memory) */ /* set base, end pointer (all of memory) */
host1x_ch_writel(ch, cdma->push_buffer.dma, HOST1X_CHANNEL_DMASTART); host1x_ch_writel(ch, lower_32_bits(start), HOST1X_CHANNEL_DMASTART);
host1x_ch_writel(ch, cdma->push_buffer.dma + cdma->push_buffer.size, #if HOST1X_HW >= 6
HOST1X_CHANNEL_DMAEND); host1x_ch_writel(ch, upper_32_bits(start), HOST1X_CHANNEL_DMASTART_HI);
#endif
host1x_ch_writel(ch, lower_32_bits(end), HOST1X_CHANNEL_DMAEND);
#if HOST1X_HW >= 6
host1x_ch_writel(ch, upper_32_bits(end), HOST1X_CHANNEL_DMAEND_HI);
#endif
/* set GET, by loading the value in PUT (then reset GET) */ /* set GET, by loading the value in PUT (then reset GET) */
host1x_ch_writel(ch, getptr, HOST1X_CHANNEL_DMAPUT); host1x_ch_writel(ch, getptr, HOST1X_CHANNEL_DMAPUT);
......
...@@ -61,16 +61,38 @@ static void trace_write_gather(struct host1x_cdma *cdma, struct host1x_bo *bo, ...@@ -61,16 +61,38 @@ static void trace_write_gather(struct host1x_cdma *cdma, struct host1x_bo *bo,
static void submit_gathers(struct host1x_job *job) static void submit_gathers(struct host1x_job *job)
{ {
struct host1x_cdma *cdma = &job->channel->cdma; struct host1x_cdma *cdma = &job->channel->cdma;
#if HOST1X_HW < 6
struct device *dev = job->channel->dev;
#endif
unsigned int i; unsigned int i;
for (i = 0; i < job->num_gathers; i++) { for (i = 0; i < job->num_gathers; i++) {
struct host1x_job_gather *g = &job->gathers[i]; struct host1x_job_gather *g = &job->gathers[i];
dma_addr_t addr = g->base + g->offset;
u32 op2, op3;
op2 = lower_32_bits(addr);
op3 = upper_32_bits(addr);
trace_write_gather(cdma, g->bo, g->offset, g->words);
if (op3 != 0) {
#if HOST1X_HW >= 6
u32 op1 = host1x_opcode_gather_wide(g->words);
u32 op4 = HOST1X_OPCODE_NOP;
host1x_cdma_push_wide(cdma, op1, op2, op3, op4);
#else
dev_err(dev, "invalid gather for push buffer %pad\n",
&addr);
continue;
#endif
} else {
u32 op1 = host1x_opcode_gather(g->words); u32 op1 = host1x_opcode_gather(g->words);
u32 op2 = g->base + g->offset;
trace_write_gather(cdma, g->bo, g->offset, op1 & 0xffff);
host1x_cdma_push(cdma, op1, op2); host1x_cdma_push(cdma, op1, op2);
} }
}
} }
static inline void synchronize_syncpt_base(struct host1x_job *job) static inline void synchronize_syncpt_base(struct host1x_job *job)
......
...@@ -138,6 +138,11 @@ static inline u32 host1x_opcode_gather_incr(unsigned offset, unsigned count) ...@@ -138,6 +138,11 @@ static inline u32 host1x_opcode_gather_incr(unsigned offset, unsigned count)
return (6 << 28) | (offset << 16) | BIT(15) | BIT(14) | count; return (6 << 28) | (offset << 16) | BIT(15) | BIT(14) | count;
} }
static inline u32 host1x_opcode_gather_wide(unsigned count)
{
return (12 << 28) | count;
}
#define HOST1X_OPCODE_NOP host1x_opcode_nonincr(0, 0) #define HOST1X_OPCODE_NOP host1x_opcode_nonincr(0, 0)
#endif #endif
...@@ -138,6 +138,11 @@ static inline u32 host1x_opcode_gather_incr(unsigned offset, unsigned count) ...@@ -138,6 +138,11 @@ static inline u32 host1x_opcode_gather_incr(unsigned offset, unsigned count)
return (6 << 28) | (offset << 16) | BIT(15) | BIT(14) | count; return (6 << 28) | (offset << 16) | BIT(15) | BIT(14) | count;
} }
static inline u32 host1x_opcode_gather_wide(unsigned count)
{
return (12 << 28) | count;
}
#define HOST1X_OPCODE_NOP host1x_opcode_nonincr(0, 0) #define HOST1X_OPCODE_NOP host1x_opcode_nonincr(0, 0)
#endif #endif
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment