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 generic_reg_get(const struct dc_context *ctx, uint32_t addr,
123 		uint8_t shift, uint32_t mask, uint32_t *field_value)
124 {
125 	uint32_t reg_val = dm_read_reg(ctx, addr);
126 	*field_value = get_reg_field_value_ex(reg_val, mask, shift);
127 	return reg_val;
128 }
129 
130 uint32_t generic_reg_get2(const struct dc_context *ctx, uint32_t addr,
131 		uint8_t shift1, uint32_t mask1, uint32_t *field_value1,
132 		uint8_t shift2, uint32_t mask2, uint32_t *field_value2)
133 {
134 	uint32_t reg_val = dm_read_reg(ctx, addr);
135 	*field_value1 = get_reg_field_value_ex(reg_val, mask1, shift1);
136 	*field_value2 = get_reg_field_value_ex(reg_val, mask2, shift2);
137 	return reg_val;
138 }
139 
140 uint32_t generic_reg_get3(const struct dc_context *ctx, uint32_t addr,
141 		uint8_t shift1, uint32_t mask1, uint32_t *field_value1,
142 		uint8_t shift2, uint32_t mask2, uint32_t *field_value2,
143 		uint8_t shift3, uint32_t mask3, uint32_t *field_value3)
144 {
145 	uint32_t reg_val = dm_read_reg(ctx, addr);
146 	*field_value1 = get_reg_field_value_ex(reg_val, mask1, shift1);
147 	*field_value2 = get_reg_field_value_ex(reg_val, mask2, shift2);
148 	*field_value3 = get_reg_field_value_ex(reg_val, mask3, shift3);
149 	return reg_val;
150 }
151 
152 uint32_t generic_reg_get4(const struct dc_context *ctx, uint32_t addr,
153 		uint8_t shift1, uint32_t mask1, uint32_t *field_value1,
154 		uint8_t shift2, uint32_t mask2, uint32_t *field_value2,
155 		uint8_t shift3, uint32_t mask3, uint32_t *field_value3,
156 		uint8_t shift4, uint32_t mask4, uint32_t *field_value4)
157 {
158 	uint32_t reg_val = dm_read_reg(ctx, addr);
159 	*field_value1 = get_reg_field_value_ex(reg_val, mask1, shift1);
160 	*field_value2 = get_reg_field_value_ex(reg_val, mask2, shift2);
161 	*field_value3 = get_reg_field_value_ex(reg_val, mask3, shift3);
162 	*field_value4 = get_reg_field_value_ex(reg_val, mask4, shift4);
163 	return reg_val;
164 }
165 
166 uint32_t generic_reg_get5(const struct dc_context *ctx, uint32_t addr,
167 		uint8_t shift1, uint32_t mask1, uint32_t *field_value1,
168 		uint8_t shift2, uint32_t mask2, uint32_t *field_value2,
169 		uint8_t shift3, uint32_t mask3, uint32_t *field_value3,
170 		uint8_t shift4, uint32_t mask4, uint32_t *field_value4,
171 		uint8_t shift5, uint32_t mask5, uint32_t *field_value5)
172 {
173 	uint32_t reg_val = dm_read_reg(ctx, addr);
174 	*field_value1 = get_reg_field_value_ex(reg_val, mask1, shift1);
175 	*field_value2 = get_reg_field_value_ex(reg_val, mask2, shift2);
176 	*field_value3 = get_reg_field_value_ex(reg_val, mask3, shift3);
177 	*field_value4 = get_reg_field_value_ex(reg_val, mask4, shift4);
178 	*field_value5 = get_reg_field_value_ex(reg_val, mask5, shift5);
179 	return reg_val;
180 }
181 
182 uint32_t generic_reg_get6(const struct dc_context *ctx, uint32_t addr,
183 		uint8_t shift1, uint32_t mask1, uint32_t *field_value1,
184 		uint8_t shift2, uint32_t mask2, uint32_t *field_value2,
185 		uint8_t shift3, uint32_t mask3, uint32_t *field_value3,
186 		uint8_t shift4, uint32_t mask4, uint32_t *field_value4,
187 		uint8_t shift5, uint32_t mask5, uint32_t *field_value5,
188 		uint8_t shift6, uint32_t mask6, uint32_t *field_value6)
189 {
190 	uint32_t reg_val = dm_read_reg(ctx, addr);
191 	*field_value1 = get_reg_field_value_ex(reg_val, mask1, shift1);
192 	*field_value2 = get_reg_field_value_ex(reg_val, mask2, shift2);
193 	*field_value3 = get_reg_field_value_ex(reg_val, mask3, shift3);
194 	*field_value4 = get_reg_field_value_ex(reg_val, mask4, shift4);
195 	*field_value5 = get_reg_field_value_ex(reg_val, mask5, shift5);
196 	*field_value6 = get_reg_field_value_ex(reg_val, mask6, shift6);
197 	return reg_val;
198 }
199 
200 uint32_t generic_reg_get7(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 		uint8_t shift7, uint32_t mask7, uint32_t *field_value7)
208 {
209 	uint32_t reg_val = dm_read_reg(ctx, addr);
210 	*field_value1 = get_reg_field_value_ex(reg_val, mask1, shift1);
211 	*field_value2 = get_reg_field_value_ex(reg_val, mask2, shift2);
212 	*field_value3 = get_reg_field_value_ex(reg_val, mask3, shift3);
213 	*field_value4 = get_reg_field_value_ex(reg_val, mask4, shift4);
214 	*field_value5 = get_reg_field_value_ex(reg_val, mask5, shift5);
215 	*field_value6 = get_reg_field_value_ex(reg_val, mask6, shift6);
216 	*field_value7 = get_reg_field_value_ex(reg_val, mask7, shift7);
217 	return reg_val;
218 }
219 
220 uint32_t generic_reg_get8(const struct dc_context *ctx, uint32_t addr,
221 		uint8_t shift1, uint32_t mask1, uint32_t *field_value1,
222 		uint8_t shift2, uint32_t mask2, uint32_t *field_value2,
223 		uint8_t shift3, uint32_t mask3, uint32_t *field_value3,
224 		uint8_t shift4, uint32_t mask4, uint32_t *field_value4,
225 		uint8_t shift5, uint32_t mask5, uint32_t *field_value5,
226 		uint8_t shift6, uint32_t mask6, uint32_t *field_value6,
227 		uint8_t shift7, uint32_t mask7, uint32_t *field_value7,
228 		uint8_t shift8, uint32_t mask8, uint32_t *field_value8)
229 {
230 	uint32_t reg_val = dm_read_reg(ctx, addr);
231 	*field_value1 = get_reg_field_value_ex(reg_val, mask1, shift1);
232 	*field_value2 = get_reg_field_value_ex(reg_val, mask2, shift2);
233 	*field_value3 = get_reg_field_value_ex(reg_val, mask3, shift3);
234 	*field_value4 = get_reg_field_value_ex(reg_val, mask4, shift4);
235 	*field_value5 = get_reg_field_value_ex(reg_val, mask5, shift5);
236 	*field_value6 = get_reg_field_value_ex(reg_val, mask6, shift6);
237 	*field_value7 = get_reg_field_value_ex(reg_val, mask7, shift7);
238 	*field_value8 = get_reg_field_value_ex(reg_val, mask8, shift8);
239 	return reg_val;
240 }
241 /* note:  va version of this is pretty bad idea, since there is a output parameter pass by pointer
242  * compiler won't be able to check for size match and is prone to stack corruption type of bugs
243 
244 uint32_t generic_reg_get(const struct dc_context *ctx,
245 		uint32_t addr, int n, ...)
246 {
247 	uint32_t shift, mask;
248 	uint32_t *field_value;
249 	uint32_t reg_val;
250 	int i = 0;
251 
252 	reg_val = dm_read_reg(ctx, addr);
253 
254 	va_list ap;
255 	va_start(ap, n);
256 
257 	while (i < n) {
258 		shift = va_arg(ap, uint32_t);
259 		mask = va_arg(ap, uint32_t);
260 		field_value = va_arg(ap, uint32_t *);
261 
262 		*field_value = get_reg_field_value_ex(reg_val, mask, shift);
263 		i++;
264 	}
265 
266 	va_end(ap);
267 
268 	return reg_val;
269 }
270 */
271 
272 uint32_t generic_reg_wait(const struct dc_context *ctx,
273 	uint32_t addr, uint32_t shift, uint32_t mask, uint32_t condition_value,
274 	unsigned int delay_between_poll_us, unsigned int time_out_num_tries,
275 	const char *func_name, int line)
276 {
277 	uint32_t field_value;
278 	uint32_t reg_val;
279 	int i;
280 
281 	/* something is terribly wrong if time out is > 200ms. (5Hz) */
282 	ASSERT(delay_between_poll_us * time_out_num_tries <= 200000);
283 
284 	for (i = 0; i <= time_out_num_tries; i++) {
285 		if (i) {
286 			if (delay_between_poll_us >= 1000)
287 				msleep(delay_between_poll_us/1000);
288 			else if (delay_between_poll_us > 0)
289 				udelay(delay_between_poll_us);
290 		}
291 
292 		reg_val = dm_read_reg(ctx, addr);
293 
294 		field_value = get_reg_field_value_ex(reg_val, mask, shift);
295 
296 		if (field_value == condition_value) {
297 			if (i * delay_between_poll_us > 1000 &&
298 					!IS_FPGA_MAXIMUS_DC(ctx->dce_environment))
299 				DC_LOG_DC("REG_WAIT taking a while: %dms in %s line:%d\n",
300 						delay_between_poll_us * i / 1000,
301 						func_name, line);
302 			return reg_val;
303 		}
304 	}
305 
306 	DC_LOG_WARNING("REG_WAIT timeout %dus * %d tries - %s line:%d\n",
307 			delay_between_poll_us, time_out_num_tries,
308 			func_name, line);
309 
310 	if (!IS_FPGA_MAXIMUS_DC(ctx->dce_environment))
311 		BREAK_TO_DEBUGGER();
312 
313 	return reg_val;
314 }
315 
316 void generic_write_indirect_reg(const struct dc_context *ctx,
317 		uint32_t addr_index, uint32_t addr_data,
318 		uint32_t index, uint32_t data)
319 {
320 	dm_write_reg(ctx, addr_index, index);
321 	dm_write_reg(ctx, addr_data, data);
322 }
323 
324 uint32_t generic_read_indirect_reg(const struct dc_context *ctx,
325 		uint32_t addr_index, uint32_t addr_data,
326 		uint32_t index)
327 {
328 	uint32_t value = 0;
329 
330 	dm_write_reg(ctx, addr_index, index);
331 	value = dm_read_reg(ctx, addr_data);
332 
333 	return value;
334 }
335 
336 
337 uint32_t generic_indirect_reg_update_ex(const struct dc_context *ctx,
338 		uint32_t addr_index, uint32_t addr_data,
339 		uint32_t index, uint32_t reg_val, int n,
340 		uint8_t shift1, uint32_t mask1, uint32_t field_value1,
341 		...)
342 {
343 	uint32_t shift, mask, field_value;
344 	int i = 1;
345 
346 	va_list ap;
347 
348 	va_start(ap, field_value1);
349 
350 	reg_val = set_reg_field_value_ex(reg_val, field_value1, mask1, shift1);
351 
352 	while (i < n) {
353 		shift = va_arg(ap, uint32_t);
354 		mask = va_arg(ap, uint32_t);
355 		field_value = va_arg(ap, uint32_t);
356 
357 		reg_val = set_reg_field_value_ex(reg_val, field_value, mask, shift);
358 		i++;
359 	}
360 
361 	generic_write_indirect_reg(ctx, addr_index, addr_data, index, reg_val);
362 	va_end(ap);
363 
364 	return reg_val;
365 }
366