1/* 2 * Copyright © 2019 Google LLC 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 20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 21 * DEALINGS IN THE SOFTWARE. 22 */ 23#ifndef TU_CS_H 24#define TU_CS_H 25 26#include "tu_private.h" 27 28#include "registers/adreno_pm4.xml.h" 29 30void 31tu_cs_init(struct tu_cs *cs, enum tu_cs_mode mode, uint32_t initial_size); 32 33void 34tu_cs_init_external(struct tu_cs *cs, uint32_t *start, uint32_t *end); 35 36void 37tu_cs_finish(struct tu_device *dev, struct tu_cs *cs); 38 39void 40tu_cs_begin(struct tu_cs *cs); 41 42void 43tu_cs_end(struct tu_cs *cs); 44 45VkResult 46tu_cs_begin_sub_stream(struct tu_device *dev, 47 struct tu_cs *cs, 48 uint32_t size, 49 struct tu_cs *sub_cs); 50 51struct tu_cs_entry 52tu_cs_end_sub_stream(struct tu_cs *cs, struct tu_cs *sub_cs); 53 54VkResult 55tu_cs_reserve_space(struct tu_device *dev, 56 struct tu_cs *cs, 57 uint32_t reserved_size); 58 59void 60tu_cs_reset(struct tu_device *dev, struct tu_cs *cs); 61 62/** 63 * Discard all entries. This allows \a cs to be reused while keeping the 64 * existing BOs and command packets intact. 65 */ 66static inline void 67tu_cs_discard_entries(struct tu_cs *cs) 68{ 69 assert(cs->mode == TU_CS_MODE_GROW); 70 cs->entry_count = 0; 71} 72 73/** 74 * Get the size needed for tu_cs_emit_call. 75 */ 76static inline uint32_t 77tu_cs_get_call_size(const struct tu_cs *cs) 78{ 79 assert(cs->mode == TU_CS_MODE_GROW); 80 /* each CP_INDIRECT_BUFFER needs 4 dwords */ 81 return cs->entry_count * 4; 82} 83 84/** 85 * Assert that we did not exceed the reserved space. 86 */ 87static inline void 88tu_cs_sanity_check(const struct tu_cs *cs) 89{ 90 assert(cs->start <= cs->cur); 91 assert(cs->cur <= cs->reserved_end); 92 assert(cs->reserved_end <= cs->end); 93} 94 95/** 96 * Emit a uint32_t value into a command stream, without boundary checking. 97 */ 98static inline void 99tu_cs_emit(struct tu_cs *cs, uint32_t value) 100{ 101 assert(cs->cur < cs->reserved_end); 102 *cs->cur = value; 103 ++cs->cur; 104} 105 106/** 107 * Emit an array of uint32_t into a command stream, without boundary checking. 108 */ 109static inline void 110tu_cs_emit_array(struct tu_cs *cs, const uint32_t *values, uint32_t length) 111{ 112 assert(cs->cur + length <= cs->reserved_end); 113 memcpy(cs->cur, values, sizeof(uint32_t) * length); 114 cs->cur += length; 115} 116 117static inline unsigned 118tu_odd_parity_bit(unsigned val) 119{ 120 /* See: http://graphics.stanford.edu/~seander/bithacks.html#ParityParallel 121 * note that we want odd parity so 0x6996 is inverted. 122 */ 123 val ^= val >> 16; 124 val ^= val >> 8; 125 val ^= val >> 4; 126 val &= 0xf; 127 return (~0x6996 >> val) & 1; 128} 129 130/** 131 * Emit a type-4 command packet header into a command stream. 132 */ 133static inline void 134tu_cs_emit_pkt4(struct tu_cs *cs, uint16_t regindx, uint16_t cnt) 135{ 136 tu_cs_emit(cs, CP_TYPE4_PKT | cnt | (tu_odd_parity_bit(cnt) << 7) | 137 ((regindx & 0x3ffff) << 8) | 138 ((tu_odd_parity_bit(regindx) << 27))); 139} 140 141/** 142 * Emit a type-7 command packet header into a command stream. 143 */ 144static inline void 145tu_cs_emit_pkt7(struct tu_cs *cs, uint8_t opcode, uint16_t cnt) 146{ 147 tu_cs_emit(cs, CP_TYPE7_PKT | cnt | (tu_odd_parity_bit(cnt) << 15) | 148 ((opcode & 0x7f) << 16) | 149 ((tu_odd_parity_bit(opcode) << 23))); 150} 151 152static inline void 153tu_cs_emit_wfi(struct tu_cs *cs) 154{ 155 tu_cs_emit_pkt7(cs, CP_WAIT_FOR_IDLE, 0); 156} 157 158static inline void 159tu_cs_emit_qw(struct tu_cs *cs, uint64_t value) 160{ 161 tu_cs_emit(cs, (uint32_t) value); 162 tu_cs_emit(cs, (uint32_t) (value >> 32)); 163} 164 165static inline void 166tu_cs_emit_write_reg(struct tu_cs *cs, uint16_t reg, uint32_t value) 167{ 168 tu_cs_emit_pkt4(cs, reg, 1); 169 tu_cs_emit(cs, value); 170} 171 172/** 173 * Emit a CP_INDIRECT_BUFFER command packet. 174 */ 175static inline void 176tu_cs_emit_ib(struct tu_cs *cs, const struct tu_cs_entry *entry) 177{ 178 assert(entry->bo); 179 assert(entry->size && entry->offset + entry->size <= entry->bo->size); 180 assert(entry->size % sizeof(uint32_t) == 0); 181 assert(entry->offset % sizeof(uint32_t) == 0); 182 183 tu_cs_emit_pkt7(cs, CP_INDIRECT_BUFFER, 3); 184 tu_cs_emit_qw(cs, entry->bo->iova + entry->offset); 185 tu_cs_emit(cs, entry->size / sizeof(uint32_t)); 186} 187 188/** 189 * Emit a CP_INDIRECT_BUFFER command packet for each entry in the target 190 * command stream. 191 */ 192static inline void 193tu_cs_emit_call(struct tu_cs *cs, const struct tu_cs *target) 194{ 195 assert(target->mode == TU_CS_MODE_GROW); 196 for (uint32_t i = 0; i < target->entry_count; i++) 197 tu_cs_emit_ib(cs, target->entries + i); 198} 199 200#endif /* TU_CS_H */ 201