Linux Audio

Check our new training course

Yocto distribution development and maintenance

Need a Yocto distribution for your embedded project?
Loading...
Note: File does not exist in v6.9.4.
  1/*
  2 * Copyright 2018 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#include <linux/pci.h>
 25
 26#include "hwmgr.h"
 27#include "pp_debug.h"
 28#include "ppatomctrl.h"
 29#include "ppsmc.h"
 30#include "atom.h"
 31#include "ivsrcid/thm/irqsrcs_thm_9_0.h"
 32#include "ivsrcid/smuio/irqsrcs_smuio_9_0.h"
 33#include "ivsrcid/ivsrcid_vislands30.h"
 34
 35uint8_t convert_to_vid(uint16_t vddc)
 36{
 37	return (uint8_t) ((6200 - (vddc * VOLTAGE_SCALE)) / 25);
 38}
 39
 40uint16_t convert_to_vddc(uint8_t vid)
 41{
 42	return (uint16_t) ((6200 - (vid * 25)) / VOLTAGE_SCALE);
 43}
 44
 45int phm_copy_clock_limits_array(
 46	struct pp_hwmgr *hwmgr,
 47	uint32_t **pptable_info_array,
 48	const uint32_t *pptable_array,
 49	uint32_t power_saving_clock_count)
 50{
 51	uint32_t array_size, i;
 52	uint32_t *table;
 53
 54	array_size = sizeof(uint32_t) * power_saving_clock_count;
 55	table = kzalloc(array_size, GFP_KERNEL);
 56	if (NULL == table)
 57		return -ENOMEM;
 58
 59	for (i = 0; i < power_saving_clock_count; i++)
 60		table[i] = le32_to_cpu(pptable_array[i]);
 61
 62	*pptable_info_array = table;
 63
 64	return 0;
 65}
 66
 67int phm_copy_overdrive_settings_limits_array(
 68	struct pp_hwmgr *hwmgr,
 69	uint32_t **pptable_info_array,
 70	const uint32_t *pptable_array,
 71	uint32_t od_setting_count)
 72{
 73	uint32_t array_size, i;
 74	uint32_t *table;
 75
 76	array_size = sizeof(uint32_t) * od_setting_count;
 77	table = kzalloc(array_size, GFP_KERNEL);
 78	if (NULL == table)
 79		return -ENOMEM;
 80
 81	for (i = 0; i < od_setting_count; i++)
 82		table[i] = le32_to_cpu(pptable_array[i]);
 83
 84	*pptable_info_array = table;
 85
 86	return 0;
 87}
 88
 89uint32_t phm_set_field_to_u32(u32 offset, u32 original_data, u32 field, u32 size)
 90{
 91	u32 mask = 0;
 92	u32 shift = 0;
 93
 94	shift = (offset % 4) << 3;
 95	if (size == sizeof(uint8_t))
 96		mask = 0xFF << shift;
 97	else if (size == sizeof(uint16_t))
 98		mask = 0xFFFF << shift;
 99
100	original_data &= ~mask;
101	original_data |= (field << shift);
102	return original_data;
103}
104
105/**
106 * Returns once the part of the register indicated by the mask has
107 * reached the given value.
108 */
109int phm_wait_on_register(struct pp_hwmgr *hwmgr, uint32_t index,
110			 uint32_t value, uint32_t mask)
111{
112	uint32_t i;
113	uint32_t cur_value;
114
115	if (hwmgr == NULL || hwmgr->device == NULL) {
116		pr_err("Invalid Hardware Manager!");
117		return -EINVAL;
118	}
119
120	for (i = 0; i < hwmgr->usec_timeout; i++) {
121		cur_value = cgs_read_register(hwmgr->device, index);
122		if ((cur_value & mask) == (value & mask))
123			break;
124		udelay(1);
125	}
126
127	/* timeout means wrong logic*/
128	if (i == hwmgr->usec_timeout)
129		return -1;
130	return 0;
131}
132
133
134/**
135 * Returns once the part of the register indicated by the mask has
136 * reached the given value.The indirect space is described by giving
137 * the memory-mapped index of the indirect index register.
138 */
139int phm_wait_on_indirect_register(struct pp_hwmgr *hwmgr,
140				uint32_t indirect_port,
141				uint32_t index,
142				uint32_t value,
143				uint32_t mask)
144{
145	if (hwmgr == NULL || hwmgr->device == NULL) {
146		pr_err("Invalid Hardware Manager!");
147		return -EINVAL;
148	}
149
150	cgs_write_register(hwmgr->device, indirect_port, index);
151	return phm_wait_on_register(hwmgr, indirect_port + 1, mask, value);
152}
153
154int phm_wait_for_register_unequal(struct pp_hwmgr *hwmgr,
155					uint32_t index,
156					uint32_t value, uint32_t mask)
157{
158	uint32_t i;
159	uint32_t cur_value;
160
161	if (hwmgr == NULL || hwmgr->device == NULL)
162		return -EINVAL;
163
164	for (i = 0; i < hwmgr->usec_timeout; i++) {
165		cur_value = cgs_read_register(hwmgr->device,
166									index);
167		if ((cur_value & mask) != (value & mask))
168			break;
169		udelay(1);
170	}
171
172	/* timeout means wrong logic */
173	if (i == hwmgr->usec_timeout)
174		return -ETIME;
175	return 0;
176}
177
178int phm_wait_for_indirect_register_unequal(struct pp_hwmgr *hwmgr,
179						uint32_t indirect_port,
180						uint32_t index,
181						uint32_t value,
182						uint32_t mask)
183{
184	if (hwmgr == NULL || hwmgr->device == NULL)
185		return -EINVAL;
186
187	cgs_write_register(hwmgr->device, indirect_port, index);
188	return phm_wait_for_register_unequal(hwmgr, indirect_port + 1,
189						value, mask);
190}
191
192bool phm_cf_want_uvd_power_gating(struct pp_hwmgr *hwmgr)
193{
194	return phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_UVDPowerGating);
195}
196
197bool phm_cf_want_vce_power_gating(struct pp_hwmgr *hwmgr)
198{
199	return phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_VCEPowerGating);
200}
201
202
203int phm_trim_voltage_table(struct pp_atomctrl_voltage_table *vol_table)
204{
205	uint32_t i, j;
206	uint16_t vvalue;
207	bool found = false;
208	struct pp_atomctrl_voltage_table *table;
209
210	PP_ASSERT_WITH_CODE((NULL != vol_table),
211			"Voltage Table empty.", return -EINVAL);
212
213	table = kzalloc(sizeof(struct pp_atomctrl_voltage_table),
214			GFP_KERNEL);
215
216	if (NULL == table)
217		return -EINVAL;
218
219	table->mask_low = vol_table->mask_low;
220	table->phase_delay = vol_table->phase_delay;
221
222	for (i = 0; i < vol_table->count; i++) {
223		vvalue = vol_table->entries[i].value;
224		found = false;
225
226		for (j = 0; j < table->count; j++) {
227			if (vvalue == table->entries[j].value) {
228				found = true;
229				break;
230			}
231		}
232
233		if (!found) {
234			table->entries[table->count].value = vvalue;
235			table->entries[table->count].smio_low =
236					vol_table->entries[i].smio_low;
237			table->count++;
238		}
239	}
240
241	memcpy(vol_table, table, sizeof(struct pp_atomctrl_voltage_table));
242	kfree(table);
243	table = NULL;
244	return 0;
245}
246
247int phm_get_svi2_mvdd_voltage_table(struct pp_atomctrl_voltage_table *vol_table,
248		phm_ppt_v1_clock_voltage_dependency_table *dep_table)
249{
250	uint32_t i;
251	int result;
252
253	PP_ASSERT_WITH_CODE((0 != dep_table->count),
254			"Voltage Dependency Table empty.", return -EINVAL);
255
256	PP_ASSERT_WITH_CODE((NULL != vol_table),
257			"vol_table empty.", return -EINVAL);
258
259	vol_table->mask_low = 0;
260	vol_table->phase_delay = 0;
261	vol_table->count = dep_table->count;
262
263	for (i = 0; i < dep_table->count; i++) {
264		vol_table->entries[i].value = dep_table->entries[i].mvdd;
265		vol_table->entries[i].smio_low = 0;
266	}
267
268	result = phm_trim_voltage_table(vol_table);
269	PP_ASSERT_WITH_CODE((0 == result),
270			"Failed to trim MVDD table.", return result);
271
272	return 0;
273}
274
275int phm_get_svi2_vddci_voltage_table(struct pp_atomctrl_voltage_table *vol_table,
276		phm_ppt_v1_clock_voltage_dependency_table *dep_table)
277{
278	uint32_t i;
279	int result;
280
281	PP_ASSERT_WITH_CODE((0 != dep_table->count),
282			"Voltage Dependency Table empty.", return -EINVAL);
283
284	PP_ASSERT_WITH_CODE((NULL != vol_table),
285			"vol_table empty.", return -EINVAL);
286
287	vol_table->mask_low = 0;
288	vol_table->phase_delay = 0;
289	vol_table->count = dep_table->count;
290
291	for (i = 0; i < dep_table->count; i++) {
292		vol_table->entries[i].value = dep_table->entries[i].vddci;
293		vol_table->entries[i].smio_low = 0;
294	}
295
296	result = phm_trim_voltage_table(vol_table);
297	PP_ASSERT_WITH_CODE((0 == result),
298			"Failed to trim VDDCI table.", return result);
299
300	return 0;
301}
302
303int phm_get_svi2_vdd_voltage_table(struct pp_atomctrl_voltage_table *vol_table,
304		phm_ppt_v1_voltage_lookup_table *lookup_table)
305{
306	int i = 0;
307
308	PP_ASSERT_WITH_CODE((0 != lookup_table->count),
309			"Voltage Lookup Table empty.", return -EINVAL);
310
311	PP_ASSERT_WITH_CODE((NULL != vol_table),
312			"vol_table empty.", return -EINVAL);
313
314	vol_table->mask_low = 0;
315	vol_table->phase_delay = 0;
316
317	vol_table->count = lookup_table->count;
318
319	for (i = 0; i < vol_table->count; i++) {
320		vol_table->entries[i].value = lookup_table->entries[i].us_vdd;
321		vol_table->entries[i].smio_low = 0;
322	}
323
324	return 0;
325}
326
327void phm_trim_voltage_table_to_fit_state_table(uint32_t max_vol_steps,
328				struct pp_atomctrl_voltage_table *vol_table)
329{
330	unsigned int i, diff;
331
332	if (vol_table->count <= max_vol_steps)
333		return;
334
335	diff = vol_table->count - max_vol_steps;
336
337	for (i = 0; i < max_vol_steps; i++)
338		vol_table->entries[i] = vol_table->entries[i + diff];
339
340	vol_table->count = max_vol_steps;
341
342	return;
343}
344
345int phm_reset_single_dpm_table(void *table,
346				uint32_t count, int max)
347{
348	int i;
349
350	struct vi_dpm_table *dpm_table = (struct vi_dpm_table *)table;
351
352	dpm_table->count = count > max ? max : count;
353
354	for (i = 0; i < dpm_table->count; i++)
355		dpm_table->dpm_level[i].enabled = false;
356
357	return 0;
358}
359
360void phm_setup_pcie_table_entry(
361	void *table,
362	uint32_t index, uint32_t pcie_gen,
363	uint32_t pcie_lanes)
364{
365	struct vi_dpm_table *dpm_table = (struct vi_dpm_table *)table;
366	dpm_table->dpm_level[index].value = pcie_gen;
367	dpm_table->dpm_level[index].param1 = pcie_lanes;
368	dpm_table->dpm_level[index].enabled = 1;
369}
370
371int32_t phm_get_dpm_level_enable_mask_value(void *table)
372{
373	int32_t i;
374	int32_t mask = 0;
375	struct vi_dpm_table *dpm_table = (struct vi_dpm_table *)table;
376
377	for (i = dpm_table->count; i > 0; i--) {
378		mask = mask << 1;
379		if (dpm_table->dpm_level[i - 1].enabled)
380			mask |= 0x1;
381		else
382			mask &= 0xFFFFFFFE;
383	}
384
385	return mask;
386}
387
388uint8_t phm_get_voltage_index(
389		struct phm_ppt_v1_voltage_lookup_table *lookup_table, uint16_t voltage)
390{
391	uint8_t count = (uint8_t) (lookup_table->count);
392	uint8_t i;
393
394	PP_ASSERT_WITH_CODE((NULL != lookup_table),
395			"Lookup Table empty.", return 0);
396	PP_ASSERT_WITH_CODE((0 != count),
397			"Lookup Table empty.", return 0);
398
399	for (i = 0; i < lookup_table->count; i++) {
400		/* find first voltage equal or bigger than requested */
401		if (lookup_table->entries[i].us_vdd >= voltage)
402			return i;
403	}
404	/* voltage is bigger than max voltage in the table */
405	return i - 1;
406}
407
408uint8_t phm_get_voltage_id(pp_atomctrl_voltage_table *voltage_table,
409		uint32_t voltage)
410{
411	uint8_t count = (uint8_t) (voltage_table->count);
412	uint8_t i = 0;
413
414	PP_ASSERT_WITH_CODE((NULL != voltage_table),
415		"Voltage Table empty.", return 0;);
416	PP_ASSERT_WITH_CODE((0 != count),
417		"Voltage Table empty.", return 0;);
418
419	for (i = 0; i < count; i++) {
420		/* find first voltage bigger than requested */
421		if (voltage_table->entries[i].value >= voltage)
422			return i;
423	}
424
425	/* voltage is bigger than max voltage in the table */
426	return i - 1;
427}
428
429uint16_t phm_find_closest_vddci(struct pp_atomctrl_voltage_table *vddci_table, uint16_t vddci)
430{
431	uint32_t  i;
432
433	for (i = 0; i < vddci_table->count; i++) {
434		if (vddci_table->entries[i].value >= vddci)
435			return vddci_table->entries[i].value;
436	}
437
438	pr_debug("vddci is larger than max value in vddci_table\n");
439	return vddci_table->entries[i-1].value;
440}
441
442int phm_find_boot_level(void *table,
443		uint32_t value, uint32_t *boot_level)
444{
445	int result = -EINVAL;
446	uint32_t i;
447	struct vi_dpm_table *dpm_table = (struct vi_dpm_table *)table;
448
449	for (i = 0; i < dpm_table->count; i++) {
450		if (value == dpm_table->dpm_level[i].value) {
451			*boot_level = i;
452			result = 0;
453		}
454	}
455
456	return result;
457}
458
459int phm_get_sclk_for_voltage_evv(struct pp_hwmgr *hwmgr,
460	phm_ppt_v1_voltage_lookup_table *lookup_table,
461	uint16_t virtual_voltage_id, int32_t *sclk)
462{
463	uint8_t entry_id;
464	uint8_t voltage_id;
465	struct phm_ppt_v1_information *table_info =
466			(struct phm_ppt_v1_information *)(hwmgr->pptable);
467
468	PP_ASSERT_WITH_CODE(lookup_table->count != 0, "Lookup table is empty", return -EINVAL);
469
470	/* search for leakage voltage ID 0xff01 ~ 0xff08 and sckl */
471	for (entry_id = 0; entry_id < table_info->vdd_dep_on_sclk->count; entry_id++) {
472		voltage_id = table_info->vdd_dep_on_sclk->entries[entry_id].vddInd;
473		if (lookup_table->entries[voltage_id].us_vdd == virtual_voltage_id)
474			break;
475	}
476
477	if (entry_id >= table_info->vdd_dep_on_sclk->count) {
478		pr_debug("Can't find requested voltage id in vdd_dep_on_sclk table\n");
479		return -EINVAL;
480	}
481
482	*sclk = table_info->vdd_dep_on_sclk->entries[entry_id].clk;
483
484	return 0;
485}
486
487/**
488 * Initialize Dynamic State Adjustment Rule Settings
489 *
490 * @param    hwmgr  the address of the powerplay hardware manager.
491 */
492int phm_initializa_dynamic_state_adjustment_rule_settings(struct pp_hwmgr *hwmgr)
493{
494	uint32_t table_size;
495	struct phm_clock_voltage_dependency_table *table_clk_vlt;
496	struct phm_ppt_v1_information *pptable_info = (struct phm_ppt_v1_information *)(hwmgr->pptable);
497
498	/* initialize vddc_dep_on_dal_pwrl table */
499	table_size = sizeof(uint32_t) + 4 * sizeof(struct phm_clock_voltage_dependency_record);
500	table_clk_vlt = kzalloc(table_size, GFP_KERNEL);
501
502	if (NULL == table_clk_vlt) {
503		pr_err("Can not allocate space for vddc_dep_on_dal_pwrl! \n");
504		return -ENOMEM;
505	} else {
506		table_clk_vlt->count = 4;
507		table_clk_vlt->entries[0].clk = PP_DAL_POWERLEVEL_ULTRALOW;
508		table_clk_vlt->entries[0].v = 0;
509		table_clk_vlt->entries[1].clk = PP_DAL_POWERLEVEL_LOW;
510		table_clk_vlt->entries[1].v = 720;
511		table_clk_vlt->entries[2].clk = PP_DAL_POWERLEVEL_NOMINAL;
512		table_clk_vlt->entries[2].v = 810;
513		table_clk_vlt->entries[3].clk = PP_DAL_POWERLEVEL_PERFORMANCE;
514		table_clk_vlt->entries[3].v = 900;
515		if (pptable_info != NULL)
516			pptable_info->vddc_dep_on_dal_pwrl = table_clk_vlt;
517		hwmgr->dyn_state.vddc_dep_on_dal_pwrl = table_clk_vlt;
518	}
519
520	return 0;
521}
522
523uint32_t phm_get_lowest_enabled_level(struct pp_hwmgr *hwmgr, uint32_t mask)
524{
525	uint32_t level = 0;
526
527	while (0 == (mask & (1 << level)))
528		level++;
529
530	return level;
531}
532
533void phm_apply_dal_min_voltage_request(struct pp_hwmgr *hwmgr)
534{
535	struct phm_ppt_v1_information *table_info =
536			(struct phm_ppt_v1_information *)hwmgr->pptable;
537	struct phm_clock_voltage_dependency_table *table =
538				table_info->vddc_dep_on_dal_pwrl;
539	struct phm_ppt_v1_clock_voltage_dependency_table *vddc_table;
540	enum PP_DAL_POWERLEVEL dal_power_level = hwmgr->dal_power_level;
541	uint32_t req_vddc = 0, req_volt, i;
542
543	if (!table || table->count <= 0
544		|| dal_power_level < PP_DAL_POWERLEVEL_ULTRALOW
545		|| dal_power_level > PP_DAL_POWERLEVEL_PERFORMANCE)
546		return;
547
548	for (i = 0; i < table->count; i++) {
549		if (dal_power_level == table->entries[i].clk) {
550			req_vddc = table->entries[i].v;
551			break;
552		}
553	}
554
555	vddc_table = table_info->vdd_dep_on_sclk;
556	for (i = 0; i < vddc_table->count; i++) {
557		if (req_vddc <= vddc_table->entries[i].vddc) {
558			req_volt = (((uint32_t)vddc_table->entries[i].vddc) * VOLTAGE_SCALE);
559			smum_send_msg_to_smc_with_parameter(hwmgr,
560					PPSMC_MSG_VddC_Request, req_volt);
561			return;
562		}
563	}
564	pr_err("DAL requested level can not"
565			" found a available voltage in VDDC DPM Table \n");
566}
567
568int phm_get_voltage_evv_on_sclk(struct pp_hwmgr *hwmgr, uint8_t voltage_type,
569				uint32_t sclk, uint16_t id, uint16_t *voltage)
570{
571	uint32_t vol;
572	int ret = 0;
573
574	if (hwmgr->chip_id < CHIP_TONGA) {
575		ret = atomctrl_get_voltage_evv(hwmgr, id, voltage);
576	} else if (hwmgr->chip_id < CHIP_POLARIS10) {
577		ret = atomctrl_get_voltage_evv_on_sclk(hwmgr, voltage_type, sclk, id, voltage);
578		if (*voltage >= 2000 || *voltage == 0)
579			*voltage = 1150;
580	} else {
581		ret = atomctrl_get_voltage_evv_on_sclk_ai(hwmgr, voltage_type, sclk, id, &vol);
582		*voltage = (uint16_t)(vol/100);
583	}
584	return ret;
585}
586
587
588int phm_irq_process(struct amdgpu_device *adev,
589			   struct amdgpu_irq_src *source,
590			   struct amdgpu_iv_entry *entry)
591{
592	uint32_t client_id = entry->client_id;
593	uint32_t src_id = entry->src_id;
594
595	if (client_id == AMDGPU_IRQ_CLIENTID_LEGACY) {
596		if (src_id == VISLANDS30_IV_SRCID_CG_TSS_THERMAL_LOW_TO_HIGH)
597			pr_warn("GPU over temperature range detected on PCIe %d:%d.%d!\n",
598						PCI_BUS_NUM(adev->pdev->devfn),
599						PCI_SLOT(adev->pdev->devfn),
600						PCI_FUNC(adev->pdev->devfn));
601		else if (src_id == VISLANDS30_IV_SRCID_CG_TSS_THERMAL_HIGH_TO_LOW)
602			pr_warn("GPU under temperature range detected on PCIe %d:%d.%d!\n",
603					PCI_BUS_NUM(adev->pdev->devfn),
604					PCI_SLOT(adev->pdev->devfn),
605					PCI_FUNC(adev->pdev->devfn));
606		else if (src_id == VISLANDS30_IV_SRCID_GPIO_19)
607			pr_warn("GPU Critical Temperature Fault detected on PCIe %d:%d.%d!\n",
608					PCI_BUS_NUM(adev->pdev->devfn),
609					PCI_SLOT(adev->pdev->devfn),
610					PCI_FUNC(adev->pdev->devfn));
611	} else if (client_id == SOC15_IH_CLIENTID_THM) {
612		if (src_id == 0)
613			pr_warn("GPU over temperature range detected on PCIe %d:%d.%d!\n",
614						PCI_BUS_NUM(adev->pdev->devfn),
615						PCI_SLOT(adev->pdev->devfn),
616						PCI_FUNC(adev->pdev->devfn));
617		else
618			pr_warn("GPU under temperature range detected on PCIe %d:%d.%d!\n",
619					PCI_BUS_NUM(adev->pdev->devfn),
620					PCI_SLOT(adev->pdev->devfn),
621					PCI_FUNC(adev->pdev->devfn));
622	} else if (client_id == SOC15_IH_CLIENTID_ROM_SMUIO)
623		pr_warn("GPU Critical Temperature Fault detected on PCIe %d:%d.%d!\n",
624				PCI_BUS_NUM(adev->pdev->devfn),
625				PCI_SLOT(adev->pdev->devfn),
626				PCI_FUNC(adev->pdev->devfn));
627
628	return 0;
629}
630
631static const struct amdgpu_irq_src_funcs smu9_irq_funcs = {
632	.process = phm_irq_process,
633};
634
635int smu9_register_irq_handlers(struct pp_hwmgr *hwmgr)
636{
637	struct amdgpu_irq_src *source =
638		kzalloc(sizeof(struct amdgpu_irq_src), GFP_KERNEL);
639
640	if (!source)
641		return -ENOMEM;
642
643	source->funcs = &smu9_irq_funcs;
644
645	amdgpu_irq_add_id((struct amdgpu_device *)(hwmgr->adev),
646			SOC15_IH_CLIENTID_THM,
647			THM_9_0__SRCID__THM_DIG_THERM_L2H,
648			source);
649	amdgpu_irq_add_id((struct amdgpu_device *)(hwmgr->adev),
650			SOC15_IH_CLIENTID_THM,
651			THM_9_0__SRCID__THM_DIG_THERM_H2L,
652			source);
653
654	/* Register CTF(GPIO_19) interrupt */
655	amdgpu_irq_add_id((struct amdgpu_device *)(hwmgr->adev),
656			SOC15_IH_CLIENTID_ROM_SMUIO,
657			SMUIO_9_0__SRCID__SMUIO_GPIO19,
658			source);
659
660	return 0;
661}
662
663void *smu_atom_get_data_table(void *dev, uint32_t table, uint16_t *size,
664						uint8_t *frev, uint8_t *crev)
665{
666	struct amdgpu_device *adev = dev;
667	uint16_t data_start;
668
669	if (amdgpu_atom_parse_data_header(
670		    adev->mode_info.atom_context, table, size,
671		    frev, crev, &data_start))
672		return (uint8_t *)adev->mode_info.atom_context->bios +
673			data_start;
674
675	return NULL;
676}
677
678int smu_get_voltage_dependency_table_ppt_v1(
679			const struct phm_ppt_v1_clock_voltage_dependency_table *allowed_dep_table,
680			struct phm_ppt_v1_clock_voltage_dependency_table *dep_table)
681{
682	uint8_t i = 0;
683	PP_ASSERT_WITH_CODE((0 != allowed_dep_table->count),
684				"Voltage Lookup Table empty",
685				return -EINVAL);
686
687	dep_table->count = allowed_dep_table->count;
688	for (i=0; i<dep_table->count; i++) {
689		dep_table->entries[i].clk = allowed_dep_table->entries[i].clk;
690		dep_table->entries[i].vddInd = allowed_dep_table->entries[i].vddInd;
691		dep_table->entries[i].vdd_offset = allowed_dep_table->entries[i].vdd_offset;
692		dep_table->entries[i].vddc = allowed_dep_table->entries[i].vddc;
693		dep_table->entries[i].vddgfx = allowed_dep_table->entries[i].vddgfx;
694		dep_table->entries[i].vddci = allowed_dep_table->entries[i].vddci;
695		dep_table->entries[i].mvdd = allowed_dep_table->entries[i].mvdd;
696		dep_table->entries[i].phases = allowed_dep_table->entries[i].phases;
697		dep_table->entries[i].cks_enable = allowed_dep_table->entries[i].cks_enable;
698		dep_table->entries[i].cks_voffset = allowed_dep_table->entries[i].cks_voffset;
699	}
700
701	return 0;
702}
703
704int smu_set_watermarks_for_clocks_ranges(void *wt_table,
705		struct dm_pp_wm_sets_with_clock_ranges_soc15 *wm_with_clock_ranges)
706{
707	uint32_t i;
708	struct watermarks *table = wt_table;
709
710	if (!table || !wm_with_clock_ranges)
711		return -EINVAL;
712
713	if (wm_with_clock_ranges->num_wm_dmif_sets > 4 || wm_with_clock_ranges->num_wm_mcif_sets > 4)
714		return -EINVAL;
715
716	for (i = 0; i < wm_with_clock_ranges->num_wm_dmif_sets; i++) {
717		table->WatermarkRow[1][i].MinClock =
718			cpu_to_le16((uint16_t)
719			(wm_with_clock_ranges->wm_dmif_clocks_ranges[i].wm_min_dcfclk_clk_in_khz /
720			1000));
721		table->WatermarkRow[1][i].MaxClock =
722			cpu_to_le16((uint16_t)
723			(wm_with_clock_ranges->wm_dmif_clocks_ranges[i].wm_max_dcfclk_clk_in_khz /
724			1000));
725		table->WatermarkRow[1][i].MinUclk =
726			cpu_to_le16((uint16_t)
727			(wm_with_clock_ranges->wm_dmif_clocks_ranges[i].wm_min_mem_clk_in_khz /
728			1000));
729		table->WatermarkRow[1][i].MaxUclk =
730			cpu_to_le16((uint16_t)
731			(wm_with_clock_ranges->wm_dmif_clocks_ranges[i].wm_max_mem_clk_in_khz /
732			1000));
733		table->WatermarkRow[1][i].WmSetting = (uint8_t)
734				wm_with_clock_ranges->wm_dmif_clocks_ranges[i].wm_set_id;
735	}
736
737	for (i = 0; i < wm_with_clock_ranges->num_wm_mcif_sets; i++) {
738		table->WatermarkRow[0][i].MinClock =
739			cpu_to_le16((uint16_t)
740			(wm_with_clock_ranges->wm_mcif_clocks_ranges[i].wm_min_socclk_clk_in_khz /
741			1000));
742		table->WatermarkRow[0][i].MaxClock =
743			cpu_to_le16((uint16_t)
744			(wm_with_clock_ranges->wm_mcif_clocks_ranges[i].wm_max_socclk_clk_in_khz /
745			1000));
746		table->WatermarkRow[0][i].MinUclk =
747			cpu_to_le16((uint16_t)
748			(wm_with_clock_ranges->wm_mcif_clocks_ranges[i].wm_min_mem_clk_in_khz /
749			1000));
750		table->WatermarkRow[0][i].MaxUclk =
751			cpu_to_le16((uint16_t)
752			(wm_with_clock_ranges->wm_mcif_clocks_ranges[i].wm_max_mem_clk_in_khz /
753			1000));
754		table->WatermarkRow[0][i].WmSetting = (uint8_t)
755				wm_with_clock_ranges->wm_mcif_clocks_ranges[i].wm_set_id;
756	}
757	return 0;
758}