1/*
2 * Copyright 2013 Advanced Micro Devices, Inc.
3 * All Rights Reserved.
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the "Software"),
7 * to deal in the Software without restriction, including without limitation
8 * on the rights to use, copy, modify, merge, publish, distribute, sub
9 * license, and/or sell copies of the Software, and to permit persons to whom
10 * the Software is furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice (including the next
13 * paragraph) shall be included in all copies or substantial portions of the
14 * Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
20 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
21 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
22 * USE OR OTHER DEALINGS IN THE SOFTWARE.
23 */
24
25/**
26 * This file contains helpers for writing commands to commands streams.
27 */
28
29#ifndef SI_BUILD_PM4_H
30#define SI_BUILD_PM4_H
31
32#include "si_pipe.h"
33#include "sid.h"
34
35static inline void radeon_set_config_reg_seq(struct radeon_cmdbuf *cs, unsigned reg, unsigned num)
36{
37	assert(reg < SI_CONTEXT_REG_OFFSET);
38	assert(cs->current.cdw + 2 + num <= cs->current.max_dw);
39	radeon_emit(cs, PKT3(PKT3_SET_CONFIG_REG, num, 0));
40	radeon_emit(cs, (reg - SI_CONFIG_REG_OFFSET) >> 2);
41}
42
43static inline void radeon_set_config_reg(struct radeon_cmdbuf *cs, unsigned reg, unsigned value)
44{
45	radeon_set_config_reg_seq(cs, reg, 1);
46	radeon_emit(cs, value);
47}
48
49static inline void radeon_set_context_reg_seq(struct radeon_cmdbuf *cs, unsigned reg, unsigned num)
50{
51	assert(reg >= SI_CONTEXT_REG_OFFSET);
52	assert(cs->current.cdw + 2 + num <= cs->current.max_dw);
53	radeon_emit(cs, PKT3(PKT3_SET_CONTEXT_REG, num, 0));
54	radeon_emit(cs, (reg - SI_CONTEXT_REG_OFFSET) >> 2);
55}
56
57static inline void radeon_set_context_reg(struct radeon_cmdbuf *cs, unsigned reg, unsigned value)
58{
59	radeon_set_context_reg_seq(cs, reg, 1);
60	radeon_emit(cs, value);
61}
62
63static inline void radeon_set_context_reg_idx(struct radeon_cmdbuf *cs,
64					      unsigned reg, unsigned idx,
65					      unsigned value)
66{
67	assert(reg >= SI_CONTEXT_REG_OFFSET);
68	assert(cs->current.cdw + 3 <= cs->current.max_dw);
69	radeon_emit(cs, PKT3(PKT3_SET_CONTEXT_REG, 1, 0));
70	radeon_emit(cs, (reg - SI_CONTEXT_REG_OFFSET) >> 2 | (idx << 28));
71	radeon_emit(cs, value);
72}
73
74static inline void radeon_set_sh_reg_seq(struct radeon_cmdbuf *cs, unsigned reg, unsigned num)
75{
76	assert(reg >= SI_SH_REG_OFFSET && reg < SI_SH_REG_END);
77	assert(cs->current.cdw + 2 + num <= cs->current.max_dw);
78	radeon_emit(cs, PKT3(PKT3_SET_SH_REG, num, 0));
79	radeon_emit(cs, (reg - SI_SH_REG_OFFSET) >> 2);
80}
81
82static inline void radeon_set_sh_reg(struct radeon_cmdbuf *cs, unsigned reg, unsigned value)
83{
84	radeon_set_sh_reg_seq(cs, reg, 1);
85	radeon_emit(cs, value);
86}
87
88static inline void radeon_set_uconfig_reg_seq(struct radeon_cmdbuf *cs, unsigned reg, unsigned num)
89{
90	assert(reg >= CIK_UCONFIG_REG_OFFSET && reg < CIK_UCONFIG_REG_END);
91	assert(cs->current.cdw + 2 + num <= cs->current.max_dw);
92	radeon_emit(cs, PKT3(PKT3_SET_UCONFIG_REG, num, 0));
93	radeon_emit(cs, (reg - CIK_UCONFIG_REG_OFFSET) >> 2);
94}
95
96static inline void radeon_set_uconfig_reg(struct radeon_cmdbuf *cs, unsigned reg, unsigned value)
97{
98	radeon_set_uconfig_reg_seq(cs, reg, 1);
99	radeon_emit(cs, value);
100}
101
102static inline void radeon_set_uconfig_reg_idx(struct radeon_cmdbuf *cs,
103					      struct si_screen *screen,
104					      unsigned reg, unsigned idx,
105					      unsigned value)
106{
107	assert(reg >= CIK_UCONFIG_REG_OFFSET && reg < CIK_UCONFIG_REG_END);
108	assert(cs->current.cdw + 3 <= cs->current.max_dw);
109	assert(idx != 0);
110	unsigned opcode = PKT3_SET_UCONFIG_REG_INDEX;
111	if (screen->info.chip_class < GFX9 ||
112	    (screen->info.chip_class == GFX9 && screen->info.me_fw_version < 26))
113		opcode = PKT3_SET_UCONFIG_REG;
114	radeon_emit(cs, PKT3(opcode, 1, 0));
115	radeon_emit(cs, (reg - CIK_UCONFIG_REG_OFFSET) >> 2 | (idx << 28));
116	radeon_emit(cs, value);
117}
118
119/* Emit PKT3_SET_CONTEXT_REG if the register value is different. */
120static inline void radeon_opt_set_context_reg(struct si_context *sctx, unsigned offset,
121					      enum si_tracked_reg reg, unsigned value)
122{
123	struct radeon_cmdbuf *cs = sctx->gfx_cs;
124
125	if (((sctx->tracked_regs.reg_saved >> reg) & 0x1) != 0x1 ||
126	    sctx->tracked_regs.reg_value[reg] != value) {
127		radeon_set_context_reg(cs, offset, value);
128
129		sctx->tracked_regs.reg_saved |= 0x1ull << reg;
130		sctx->tracked_regs.reg_value[reg] = value;
131	}
132}
133
134/**
135 * Set 2 consecutive registers if any registers value is different.
136 * @param offset        starting register offset
137 * @param value1        is written to first register
138 * @param value2        is written to second register
139 */
140static inline void radeon_opt_set_context_reg2(struct si_context *sctx, unsigned offset,
141					       enum si_tracked_reg reg, unsigned value1,
142					       unsigned value2)
143{
144	struct radeon_cmdbuf *cs = sctx->gfx_cs;
145
146	if (((sctx->tracked_regs.reg_saved >> reg) & 0x3) != 0x3 ||
147	    sctx->tracked_regs.reg_value[reg] != value1 ||
148	    sctx->tracked_regs.reg_value[reg+1] != value2) {
149		radeon_set_context_reg_seq(cs, offset, 2);
150		radeon_emit(cs, value1);
151		radeon_emit(cs, value2);
152
153		sctx->tracked_regs.reg_value[reg] = value1;
154		sctx->tracked_regs.reg_value[reg+1] = value2;
155		sctx->tracked_regs.reg_saved |= 0x3ull << reg;
156	}
157}
158
159/**
160 * Set 3 consecutive registers if any registers value is different.
161 */
162static inline void radeon_opt_set_context_reg3(struct si_context *sctx, unsigned offset,
163					       enum si_tracked_reg reg, unsigned value1,
164					       unsigned value2, unsigned value3)
165{
166	struct radeon_cmdbuf *cs = sctx->gfx_cs;
167
168	if (((sctx->tracked_regs.reg_saved >> reg) & 0x7) != 0x7 ||
169	    sctx->tracked_regs.reg_value[reg] != value1 ||
170	    sctx->tracked_regs.reg_value[reg+1] != value2 ||
171	    sctx->tracked_regs.reg_value[reg+2] != value3) {
172		radeon_set_context_reg_seq(cs, offset, 3);
173		radeon_emit(cs, value1);
174		radeon_emit(cs, value2);
175		radeon_emit(cs, value3);
176
177		sctx->tracked_regs.reg_value[reg] = value1;
178		sctx->tracked_regs.reg_value[reg+1] = value2;
179		sctx->tracked_regs.reg_value[reg+2] = value3;
180		sctx->tracked_regs.reg_saved |= 0x7ull << reg;
181	}
182}
183
184/**
185 * Set 4 consecutive registers if any registers value is different.
186 */
187static inline void radeon_opt_set_context_reg4(struct si_context *sctx, unsigned offset,
188					       enum si_tracked_reg reg, unsigned value1,
189					       unsigned value2, unsigned value3,
190					       unsigned value4)
191{
192	struct radeon_cmdbuf *cs = sctx->gfx_cs;
193
194	if (((sctx->tracked_regs.reg_saved >> reg) & 0xf) != 0xf ||
195	    sctx->tracked_regs.reg_value[reg] != value1 ||
196	    sctx->tracked_regs.reg_value[reg+1] != value2 ||
197	    sctx->tracked_regs.reg_value[reg+2] != value3 ||
198	    sctx->tracked_regs.reg_value[reg+3] != value4) {
199		radeon_set_context_reg_seq(cs, offset, 4);
200		radeon_emit(cs, value1);
201		radeon_emit(cs, value2);
202		radeon_emit(cs, value3);
203		radeon_emit(cs, value4);
204
205		sctx->tracked_regs.reg_value[reg] = value1;
206		sctx->tracked_regs.reg_value[reg+1] = value2;
207		sctx->tracked_regs.reg_value[reg+2] = value3;
208		sctx->tracked_regs.reg_value[reg+3] = value4;
209		sctx->tracked_regs.reg_saved |= 0xfull << reg;
210	}
211}
212
213/**
214 * Set consecutive registers if any registers value is different.
215 */
216static inline void radeon_opt_set_context_regn(struct si_context *sctx, unsigned offset,
217					       unsigned *value, unsigned *saved_val,
218					       unsigned num)
219{
220	struct radeon_cmdbuf *cs = sctx->gfx_cs;
221	int i, j;
222
223	for (i = 0; i < num; i++) {
224		if (saved_val[i] != value[i]) {
225			radeon_set_context_reg_seq(cs, offset, num);
226			for (j = 0; j < num; j++)
227				radeon_emit(cs, value[j]);
228
229			memcpy(saved_val, value, sizeof(uint32_t) * num);
230			break;
231		}
232	}
233}
234
235#endif
236