Linux Audio

Check our new training course

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