• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2017 Rob Clark <robdclark@gmail.com>
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a
5  * copy of this software and associated documentation files (the "Software"),
6  * to deal in the Software without restriction, including without limitation
7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8  * and/or sell copies of the Software, and to permit persons to whom the
9  * Software is furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice (including the next
12  * paragraph) shall be included in all copies or substantial portions of the
13  * Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21  * SOFTWARE.
22  */
23 
24 #ifndef _AFUC_H_
25 #define _AFUC_H_
26 
27 #include <stdbool.h>
28 
29 #include "util/macros.h"
30 
31 /*
32 TODO kernel debugfs to inject packet into rb for easier experimentation.  It
33 should trigger reloading pfp/me and resetting gpu..
34 
35 Actually maybe it should be flag on submit ioctl to be able to deal w/ relocs,
36 should be restricted to CAP_ADMIN and probably compile option too (default=n).
37 if flag set, copy cmdstream bo contents into RB instead of IB'ing to it from
38 RB.
39  */
40 
41 typedef enum {
42    OPC_NOP,
43 
44 #define ALU(name) \
45    OPC_##name, \
46    OPC_##name##I,
47    ALU(ADD)   /* add immediate */
48    ALU(ADDHI) /* add immediate (hi 32b of 64b) */
49    ALU(SUB)   /* subtract immediate */
50    ALU(SUBHI) /* subtract immediate (hi 32b of 64b) */
51    ALU(AND)   /* AND immediate */
52    ALU(OR)    /* OR immediate */
53    ALU(XOR)   /* XOR immediate */
54    ALU(NOT)   /* bitwise not of immed (src1 ignored) */
55    ALU(SHL)   /* shift-left immediate */
56    ALU(USHR)  /* unsigned shift right by immediate */
57    ALU(ISHR)  /* signed shift right by immediate */
58    ALU(ROT)   /* rotate left (left shift with wrap-around) */
59    ALU(MUL8)  /* 8bit multiply by immediate */
60    ALU(MIN)
61    ALU(MAX)
62    ALU(CMP)   /* compare src to immed */
63    ALU(BIC)   /* AND with second source negated */
64    OPC_SETBIT, /* Set or clear a bit dynamically */
65    OPC_MOVI,  /* move immediate */
66    OPC_SETBITI, /* Set a bit */
67    OPC_CLRBIT, /* Clear a bit */
68    OPC_UBFX, /* Unsigned BitField eXtract */
69    OPC_BFI,  /* BitField Insert */
70 #undef ALU
71 
72    /* Return the most-significant bit of src2, or 0 if src2 == 0 (the
73     * same as if src2 == 1). src1 is ignored. Note that this overlaps
74     * with STORE, so it can only be used with the two-source encoding.
75     */
76    OPC_MSB,
77 
78    /* These seem something to do with setting some external state..
79     * doesn't seem to map *directly* to registers, but I guess that
80     * is where things end up.  For example, this sequence in the
81     * CP_INDIRECT_BUFFER handler:
82     *
83     *     mov $02, $data   ; low 32b of IB target address
84     *     mov $03, $data   ; high 32b of IB target
85     *     mov $04, $data   ; IB size in dwords
86     *     breq $04, 0x0, #l23 (#69, 04a2)
87     *     and $05, $18, 0x0003
88     *     shl $05, $05, 0x0002
89     *     cwrite $02, [$05 + 0x0b0], 0x8
90     *     cwrite $03, [$05 + 0x0b1], 0x8
91     *     cwrite $04, [$05 + 0x0b2], 0x8
92     *
93     * Note that CP_IB1/2_BASE_LO/HI/BUFSZ in 0x0b1f->0xb21 (IB1) and
94     * 0x0b22->0x0b24 (IB2).  Presumably $05 ends up w/ different value
95     * for RB->IB1 vs IB1->IB2.
96     */
97    OPC_CWRITE,
98    OPC_CREAD,
99 
100    /* A6xx added new opcodes that let you read/write directly to memory (and
101     * bypass the IOMMU?).
102     */
103    OPC_STORE,
104    OPC_LOAD,
105 
106    /* A6xx added new opcodes that let you read/write the state of the
107     * SQE processor itself, like the call stack. This is mostly used by
108     * preemption but is also used to set the preempt routine entrypoint.
109     */
110    OPC_SREAD,
111    OPC_SWRITE,
112 
113    OPC_BRNEI,         /* relative branch (if $src != immed) */
114    OPC_BREQI,         /* relative branch (if $src == immed) */
115    OPC_BRNEB,         /* relative branch (if bit not set) */
116    OPC_BREQB,         /* relative branch (if bit is set) */
117    OPC_RET,           /* return */
118    OPC_IRET,          /* return from preemption interrupt handler */
119    OPC_CALL,          /* "function" call */
120    OPC_WAITIN,        /* wait for input (ie. wait for WPTR to advance) */
121    OPC_PREEMPTLEAVE,  /* try to leave preemption */
122    OPC_SETSECURE,     /* switch secure mode on/off */
123 
124    /* pseudo-opcodes without an actual encoding */
125    OPC_BREQ,
126    OPC_BRNE,
127    OPC_JUMP,
128    OPC_RAW_LITERAL,
129 } afuc_opc;
130 
131 /**
132  * Special GPR registers:
133  *
134  * Notes:  (applicable to a6xx, double check a5xx)
135  *
136  *   0x1d:
137  *      $addr:    writes configure GPU reg address to read/write
138  *                (does not respect CP_PROTECT)
139  *      $memdata: reads from FIFO filled based on MEM_READ_DWORDS/
140  *                MEM_READ_ADDR
141  *   0x1e: (note different mnemonic for src vs dst)
142  *      $usraddr: writes configure GPU reg address to read/write,
143  *                respecting CP_PROTECT
144  *      $regdata: reads from FIFO filled based on REG_READ_DWORDS/
145  *                REG_READ_ADDR
146  *   0x1f:
147  *      $data:    reads from from pm4 input stream
148  *      $data:    writes to stream configured by write to $addr
149  *                or $usraddr
150  */
151 typedef enum {
152    REG_REM     = 0x1c,
153    REG_MEMDATA = 0x1d,  /* when used as src */
154    REG_ADDR    = 0x1d,  /* when used as dst */
155    REG_REGDATA = 0x1e,  /* when used as src */
156    REG_USRADDR = 0x1e,  /* when used as dst */
157    REG_DATA    = 0x1f,
158 } afuc_reg;
159 
160 struct afuc_instr {
161    afuc_opc opc;
162 
163    uint8_t dst;
164    uint8_t src1;
165    uint8_t src2;
166    uint32_t immed;
167    uint8_t shift;
168    uint8_t bit;
169    uint8_t xmov;
170    uint8_t sds;
171    uint32_t literal;
172    int offset;
173    const char *label;
174 
175    bool has_immed : 1;
176    bool has_shift : 1;
177    bool has_bit : 1;
178    bool is_literal : 1;
179    bool rep : 1;
180    bool preincrement : 1;
181 };
182 
183 void print_control_reg(uint32_t id);
184 void print_sqe_reg(uint32_t id);
185 void print_pipe_reg(uint32_t id);
186 
187 #endif /* _AFUC_H_ */
188