1 /*
2  * Copyright 2017 Advanced Micro Devices, Inc.
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 shall be included in
12  * all copies or substantial portions of the Software.
13  *
14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
17  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20  * OTHER DEALINGS IN THE SOFTWARE.
21  *
22  */
23 /*
24  * dc_helper.c
25  *
26  *  Created on: Aug 30, 2016
27  *      Author: agrodzov
28  */
29 #include "dm_services.h"
30 #include <stdarg.h>
31 
32 struct dc_reg_value_masks {
33 	uint32_t value;
34 	uint32_t mask;
35 };
36 
37 struct dc_reg_sequence {
38 	uint32_t addr;
39 	struct dc_reg_value_masks value_masks;
40 };
41 
42 static inline void set_reg_field_value_masks(
43 	struct dc_reg_value_masks *field_value_mask,
44 	uint32_t value,
45 	uint32_t mask,
46 	uint8_t shift)
47 {
48 	ASSERT(mask != 0);
49 
50 	field_value_mask->value = (field_value_mask->value & ~mask) | (mask & (value << shift));
51 	field_value_mask->mask = field_value_mask->mask | mask;
52 }
53 
54 static void set_reg_field_values(struct dc_reg_value_masks *field_value_mask,
55 		uint32_t addr, int n,
56 		uint8_t shift1, uint32_t mask1, uint32_t field_value1,
57 		va_list ap)
58 {
59 	uint32_t shift, mask, field_value;
60 	int i = 1;
61 
62 	/* gather all bits value/mask getting updated in this register */
63 	set_reg_field_value_masks(field_value_mask,
64 			field_value1, mask1, shift1);
65 
66 	while (i < n) {
67 		shift = va_arg(ap, uint32_t);
68 		mask = va_arg(ap, uint32_t);
69 		field_value = va_arg(ap, uint32_t);
70 
71 		set_reg_field_value_masks(field_value_mask,
72 				field_value, mask, shift);
73 		i++;
74 	}
75 }
76 
77 uint32_t generic_reg_update_ex(const struct dc_context *ctx,
78 		uint32_t addr, int n,
79 		uint8_t shift1, uint32_t mask1, uint32_t field_value1,
80 		...)
81 {
82 	struct dc_reg_value_masks field_value_mask = {0};
83 	uint32_t reg_val;
84 	va_list ap;
85 
86 	va_start(ap, field_value1);
87 
88 	set_reg_field_values(&field_value_mask, addr, n, shift1, mask1,
89 			field_value1, ap);
90 
91 	va_end(ap);
92 
93 	/* mmio write directly */
94 	reg_val = dm_read_reg(ctx, addr);
95 	reg_val = (reg_val & ~field_value_mask.mask) | field_value_mask.value;
96 	dm_write_reg(ctx, addr, reg_val);
97 	return reg_val;
98 }
99 
100 uint32_t generic_reg_set_ex(const struct dc_context *ctx,
101 		uint32_t addr, uint32_t reg_val, int n,
102 		uint8_t shift1, uint32_t mask1, uint32_t field_value1,
103 		...)
104 {
105 	struct dc_reg_value_masks field_value_mask = {0};
106 	va_list ap;
107 
108 	va_start(ap, field_value1);
109 
110 	set_reg_field_values(&field_value_mask, addr, n, shift1, mask1,
111 			field_value1, ap);
112 
113 	va_end(ap);
114 
115 
116 	/* mmio write directly */
117 	reg_val = (reg_val & ~field_value_mask.mask) | field_value_mask.value;
118 	dm_write_reg(ctx, addr, reg_val);
119 	return reg_val;
120 }
121 
122 uint32_t dm_read_reg_func(
123 	const struct dc_context *ctx,
124 	uint32_t address,
125 	const char *func_name)
126 {
127 	uint32_t value;
128 #ifdef DM_CHECK_ADDR_0
129 	if (address == 0) {
130 		DC_ERR("invalid register read; address = 0\n");
131 		return 0;
132 	}
133 #endif
134 	value = cgs_read_register(ctx->cgs_device, address);
135 	trace_amdgpu_dc_rreg(&ctx->perf_trace->read_count, address, value);
136 
137 	return value;
138 }
139 
140 uint32_t generic_reg_get(const struct dc_context *ctx, uint32_t addr,
141 		uint8_t shift, uint32_t mask, uint32_t *field_value)
142 {
143 	uint32_t reg_val = dm_read_reg(ctx, addr);
144 	*field_value = get_reg_field_value_ex(reg_val, mask, shift);
145 	return reg_val;
146 }
147 
148 uint32_t generic_reg_get2(const struct dc_context *ctx, uint32_t addr,
149 		uint8_t shift1, uint32_t mask1, uint32_t *field_value1,
150 		uint8_t shift2, uint32_t mask2, uint32_t *field_value2)
151 {
152 	uint32_t reg_val = dm_read_reg(ctx, addr);
153 	*field_value1 = get_reg_field_value_ex(reg_val, mask1, shift1);
154 	*field_value2 = get_reg_field_value_ex(reg_val, mask2, shift2);
155 	return reg_val;
156 }
157 
158 uint32_t generic_reg_get3(const struct dc_context *ctx, uint32_t addr,
159 		uint8_t shift1, uint32_t mask1, uint32_t *field_value1,
160 		uint8_t shift2, uint32_t mask2, uint32_t *field_value2,
161 		uint8_t shift3, uint32_t mask3, uint32_t *field_value3)
162 {
163 	uint32_t reg_val = dm_read_reg(ctx, addr);
164 	*field_value1 = get_reg_field_value_ex(reg_val, mask1, shift1);
165 	*field_value2 = get_reg_field_value_ex(reg_val, mask2, shift2);
166 	*field_value3 = get_reg_field_value_ex(reg_val, mask3, shift3);
167 	return reg_val;
168 }
169 
170 uint32_t generic_reg_get4(const struct dc_context *ctx, uint32_t addr,
171 		uint8_t shift1, uint32_t mask1, uint32_t *field_value1,
172 		uint8_t shift2, uint32_t mask2, uint32_t *field_value2,
173 		uint8_t shift3, uint32_t mask3, uint32_t *field_value3,
174 		uint8_t shift4, uint32_t mask4, uint32_t *field_value4)
175 {
176 	uint32_t reg_val = dm_read_reg(ctx, addr);
177 	*field_value1 = get_reg_field_value_ex(reg_val, mask1, shift1);
178 	*field_value2 = get_reg_field_value_ex(reg_val, mask2, shift2);
179 	*field_value3 = get_reg_field_value_ex(reg_val, mask3, shift3);
180 	*field_value4 = get_reg_field_value_ex(reg_val, mask4, shift4);
181 	return reg_val;
182 }
183 
184 uint32_t generic_reg_get5(const struct dc_context *ctx, uint32_t addr,
185 		uint8_t shift1, uint32_t mask1, uint32_t *field_value1,
186 		uint8_t shift2, uint32_t mask2, uint32_t *field_value2,
187 		uint8_t shift3, uint32_t mask3, uint32_t *field_value3,
188 		uint8_t shift4, uint32_t mask4, uint32_t *field_value4,
189 		uint8_t shift5, uint32_t mask5, uint32_t *field_value5)
190 {
191 	uint32_t reg_val = dm_read_reg(ctx, addr);
192 	*field_value1 = get_reg_field_value_ex(reg_val, mask1, shift1);
193 	*field_value2 = get_reg_field_value_ex(reg_val, mask2, shift2);
194 	*field_value3 = get_reg_field_value_ex(reg_val, mask3, shift3);
195 	*field_value4 = get_reg_field_value_ex(reg_val, mask4, shift4);
196 	*field_value5 = get_reg_field_value_ex(reg_val, mask5, shift5);
197 	return reg_val;
198 }
199 
200 uint32_t generic_reg_get6(const struct dc_context *ctx, uint32_t addr,
201 		uint8_t shift1, uint32_t mask1, uint32_t *field_value1,
202 		uint8_t shift2, uint32_t mask2, uint32_t *field_value2,
203 		uint8_t shift3, uint32_t mask3, uint32_t *field_value3,
204 		uint8_t shift4, uint32_t mask4, uint32_t *field_value4,
205 		uint8_t shift5, uint32_t mask5, uint32_t *field_value5,
206 		uint8_t shift6, uint32_t mask6, uint32_t *field_value6)
207 {
208 	uint32_t reg_val = dm_read_reg(ctx, addr);
209 	*field_value1 = get_reg_field_value_ex(reg_val, mask1, shift1);
210 	*field_value2 = get_reg_field_value_ex(reg_val, mask2, shift2);
211 	*field_value3 = get_reg_field_value_ex(reg_val, mask3, shift3);
212 	*field_value4 = get_reg_field_value_ex(reg_val, mask4, shift4);
213 	*field_value5 = get_reg_field_value_ex(reg_val, mask5, shift5);
214 	*field_value6 = get_reg_field_value_ex(reg_val, mask6, shift6);
215 	return reg_val;
216 }
217 
218 uint32_t generic_reg_get7(const struct dc_context *ctx, uint32_t addr,
219 		uint8_t shift1, uint32_t mask1, uint32_t *field_value1,
220 		uint8_t shift2, uint32_t mask2, uint32_t *field_value2,
221 		uint8_t shift3, uint32_t mask3, uint32_t *field_value3,
222 		uint8_t shift4, uint32_t mask4, uint32_t *field_value4,
223 		uint8_t shift5, uint32_t mask5, uint32_t *field_value5,
224 		uint8_t shift6, uint32_t mask6, uint32_t *field_value6,
225 		uint8_t shift7, uint32_t mask7, uint32_t *field_value7)
226 {
227 	uint32_t reg_val = dm_read_reg(ctx, addr);
228 	*field_value1 = get_reg_field_value_ex(reg_val, mask1, shift1);
229 	*field_value2 = get_reg_field_value_ex(reg_val, mask2, shift2);
230 	*field_value3 = get_reg_field_value_ex(reg_val, mask3, shift3);
231 	*field_value4 = get_reg_field_value_ex(reg_val, mask4, shift4);
232 	*field_value5 = get_reg_field_value_ex(reg_val, mask5, shift5);
233 	*field_value6 = get_reg_field_value_ex(reg_val, mask6, shift6);
234 	*field_value7 = get_reg_field_value_ex(reg_val, mask7, shift7);
235 	return reg_val;
236 }
237 
238 uint32_t generic_reg_get8(const struct dc_context *ctx, uint32_t addr,
239 		uint8_t shift1, uint32_t mask1, uint32_t *field_value1,
240 		uint8_t shift2, uint32_t mask2, uint32_t *field_value2,
241 		uint8_t shift3, uint32_t mask3, uint32_t *field_value3,
242 		uint8_t shift4, uint32_t mask4, uint32_t *field_value4,
243 		uint8_t shift5, uint32_t mask5, uint32_t *field_value5,
244 		uint8_t shift6, uint32_t mask6, uint32_t *field_value6,
245 		uint8_t shift7, uint32_t mask7, uint32_t *field_value7,
246 		uint8_t shift8, uint32_t mask8, uint32_t *field_value8)
247 {
248 	uint32_t reg_val = dm_read_reg(ctx, addr);
249 	*field_value1 = get_reg_field_value_ex(reg_val, mask1, shift1);
250 	*field_value2 = get_reg_field_value_ex(reg_val, mask2, shift2);
251 	*field_value3 = get_reg_field_value_ex(reg_val, mask3, shift3);
252 	*field_value4 = get_reg_field_value_ex(reg_val, mask4, shift4);
253 	*field_value5 = get_reg_field_value_ex(reg_val, mask5, shift5);
254 	*field_value6 = get_reg_field_value_ex(reg_val, mask6, shift6);
255 	*field_value7 = get_reg_field_value_ex(reg_val, mask7, shift7);
256 	*field_value8 = get_reg_field_value_ex(reg_val, mask8, shift8);
257 	return reg_val;
258 }
259 /* note:  va version of this is pretty bad idea, since there is a output parameter pass by pointer
260  * compiler won't be able to check for size match and is prone to stack corruption type of bugs
261 
262 uint32_t generic_reg_get(const struct dc_context *ctx,
263 		uint32_t addr, int n, ...)
264 {
265 	uint32_t shift, mask;
266 	uint32_t *field_value;
267 	uint32_t reg_val;
268 	int i = 0;
269 
270 	reg_val = dm_read_reg(ctx, addr);
271 
272 	va_list ap;
273 	va_start(ap, n);
274 
275 	while (i < n) {
276 		shift = va_arg(ap, uint32_t);
277 		mask = va_arg(ap, uint32_t);
278 		field_value = va_arg(ap, uint32_t *);
279 
280 		*field_value = get_reg_field_value_ex(reg_val, mask, shift);
281 		i++;
282 	}
283 
284 	va_end(ap);
285 
286 	return reg_val;
287 }
288 */
289 
290 void generic_reg_wait(const struct dc_context *ctx,
291 	uint32_t addr, uint32_t shift, uint32_t mask, uint32_t condition_value,
292 	unsigned int delay_between_poll_us, unsigned int time_out_num_tries,
293 	const char *func_name, int line)
294 {
295 	uint32_t field_value;
296 	uint32_t reg_val;
297 	int i;
298 
299 	/* something is terribly wrong if time out is > 200ms. (5Hz) */
300 	ASSERT(delay_between_poll_us * time_out_num_tries <= 200000);
301 
302 	for (i = 0; i <= time_out_num_tries; i++) {
303 		if (i) {
304 			if (delay_between_poll_us >= 1000)
305 				msleep(delay_between_poll_us/1000);
306 			else if (delay_between_poll_us > 0)
307 				udelay(delay_between_poll_us);
308 		}
309 
310 		reg_val = dm_read_reg(ctx, addr);
311 
312 		field_value = get_reg_field_value_ex(reg_val, mask, shift);
313 
314 		if (field_value == condition_value) {
315 			if (i * delay_between_poll_us > 1000 &&
316 					!IS_FPGA_MAXIMUS_DC(ctx->dce_environment))
317 				DC_LOG_DC("REG_WAIT taking a while: %dms in %s line:%d\n",
318 						delay_between_poll_us * i / 1000,
319 						func_name, line);
320 			return;
321 		}
322 	}
323 
324 	DC_LOG_WARNING("REG_WAIT timeout %dus * %d tries - %s line:%d\n",
325 			delay_between_poll_us, time_out_num_tries,
326 			func_name, line);
327 
328 	if (!IS_FPGA_MAXIMUS_DC(ctx->dce_environment))
329 		BREAK_TO_DEBUGGER();
330 }
331 
332 void generic_write_indirect_reg(const struct dc_context *ctx,
333 		uint32_t addr_index, uint32_t addr_data,
334 		uint32_t index, uint32_t data)
335 {
336 	dm_write_reg(ctx, addr_index, index);
337 	dm_write_reg(ctx, addr_data, data);
338 }
339 
340 uint32_t generic_read_indirect_reg(const struct dc_context *ctx,
341 		uint32_t addr_index, uint32_t addr_data,
342 		uint32_t index)
343 {
344 	uint32_t value = 0;
345 
346 	dm_write_reg(ctx, addr_index, index);
347 	value = dm_read_reg(ctx, addr_data);
348 
349 	return value;
350 }
351 
352 
353 uint32_t generic_indirect_reg_update_ex(const struct dc_context *ctx,
354 		uint32_t addr_index, uint32_t addr_data,
355 		uint32_t index, uint32_t reg_val, int n,
356 		uint8_t shift1, uint32_t mask1, uint32_t field_value1,
357 		...)
358 {
359 	uint32_t shift, mask, field_value;
360 	int i = 1;
361 
362 	va_list ap;
363 
364 	va_start(ap, field_value1);
365 
366 	reg_val = set_reg_field_value_ex(reg_val, field_value1, mask1, shift1);
367 
368 	while (i < n) {
369 		shift = va_arg(ap, uint32_t);
370 		mask = va_arg(ap, uint32_t);
371 		field_value = va_arg(ap, uint32_t);
372 
373 		reg_val = set_reg_field_value_ex(reg_val, field_value, mask, shift);
374 		i++;
375 	}
376 
377 	generic_write_indirect_reg(ctx, addr_index, addr_data, index, reg_val);
378 	va_end(ap);
379 
380 	return reg_val;
381 }
382