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