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