gpu: host1x: Support 40-bit addressing
authorThierry Reding <treding@nvidia.com>
Fri, 1 Feb 2019 13:28:25 +0000 (14:28 +0100)
committerThierry Reding <treding@nvidia.com>
Thu, 7 Feb 2019 17:28:35 +0000 (18:28 +0100)
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: Thierry Reding <treding@nvidia.com>
drivers/gpu/host1x/hw/cdma_hw.c
drivers/gpu/host1x/hw/channel_hw.c
drivers/gpu/host1x/hw/host1x06_hardware.h
drivers/gpu/host1x/hw/host1x07_hardware.h

index ce320534cbed39aa3fc06aa1473a9187ed671e62..485aef5761af68a4052d7ac80342d2b2b3dc0b34 100644 (file)
@@ -68,20 +68,31 @@ static void cdma_timeout_cpu_incr(struct host1x_cdma *cdma, u32 getptr,
 static void cdma_start(struct host1x_cdma *cdma)
 {
        struct host1x_channel *ch = cdma_to_channel(cdma);
+       u64 start, end;
 
        if (cdma->running)
                return;
 
        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_CHANNEL_DMACTRL);
 
        /* 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.dma + cdma->push_buffer.size + 4,
-                        HOST1X_CHANNEL_DMAEND);
+#if HOST1X_HW >= 6
+       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 */
        host1x_ch_writel(ch, HOST1X_CHANNEL_DMACTRL_DMASTOP |
@@ -104,6 +115,7 @@ static void cdma_timeout_restart(struct host1x_cdma *cdma, u32 getptr)
 {
        struct host1x *host1x = cdma_to_host1x(cdma);
        struct host1x_channel *ch = cdma_to_channel(cdma);
+       u64 start, end;
 
        if (cdma->running)
                return;
@@ -113,10 +125,18 @@ static void cdma_timeout_restart(struct host1x_cdma *cdma, u32 getptr)
        host1x_ch_writel(ch, HOST1X_CHANNEL_DMACTRL_DMASTOP,
                         HOST1X_CHANNEL_DMACTRL);
 
+       start = cdma->push_buffer.dma;
+       end = start + cdma->push_buffer.size + 4;
+
        /* set base, end pointer (all of memory) */
-       host1x_ch_writel(ch, cdma->push_buffer.dma, HOST1X_CHANNEL_DMASTART);
-       host1x_ch_writel(ch, cdma->push_buffer.dma + cdma->push_buffer.size,
-                        HOST1X_CHANNEL_DMAEND);
+       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, 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) */
        host1x_ch_writel(ch, getptr, HOST1X_CHANNEL_DMAPUT);
index 3067af4452cddf632497a7cf18bb25ef3b7c7f97..27101c04a8272668988ce5be66dfc584068f8a60 100644 (file)
@@ -61,15 +61,37 @@ static void trace_write_gather(struct host1x_cdma *cdma, struct host1x_bo *bo,
 static void submit_gathers(struct host1x_job *job)
 {
        struct host1x_cdma *cdma = &job->channel->cdma;
+#if HOST1X_HW < 6
+       struct device *dev = job->channel->dev;
+#endif
        unsigned int i;
 
        for (i = 0; i < job->num_gathers; i++) {
                struct host1x_job_gather *g = &job->gathers[i];
-               u32 op1 = host1x_opcode_gather(g->words);
-               u32 op2 = g->base + g->offset;
+               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;
 
-               trace_write_gather(cdma, g->bo, g->offset, op1 & 0xffff);
-               host1x_cdma_push(cdma, op1, op2);
+                       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);
+
+                       host1x_cdma_push(cdma, op1, op2);
+               }
        }
 }
 
index eab753b91f2403bc7e6363c4c12e3bd587361bb9..dd37b10c8d043391b5ab49dd0dfe977fb6ce62c7 100644 (file)
@@ -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;
 }
 
+static inline u32 host1x_opcode_gather_wide(unsigned count)
+{
+       return (12 << 28) | count;
+}
+
 #define HOST1X_OPCODE_NOP host1x_opcode_nonincr(0, 0)
 
 #endif
index a79f57dc87bbf1c2ce01239bd4956baf0a0f0c79..9f6da4ee54435087b2031a43a62c9d3bb965222b 100644 (file)
@@ -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;
 }
 
+static inline u32 host1x_opcode_gather_wide(unsigned count)
+{
+       return (12 << 28) | count;
+}
+
 #define HOST1X_OPCODE_NOP host1x_opcode_nonincr(0, 0)
 
 #endif