~ubuntu-branches/ubuntu/trusty/linux-lts-xenial/trusty-proposed

« back to all changes in this revision

Viewing changes to drivers/gpu/drm/amd/powerplay/hwmgr/hwmgr.c

  • Committer: Package Import Robot
  • Author(s): Tim Gardner
  • Date: 2016-03-08 13:26:08 UTC
  • Revision ID: package-import@ubuntu.com-20160308132608-hxh0frngo4vaiqw7
Tags: 4.4.0-12.28~14.04.1
* Miscellaneous Ubuntu changes
  - reconstruct: Work around orig tarball packaging limitiations
    Fixes FTBS

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright 2015 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 "linux/delay.h"
 
24
#include <linux/types.h>
 
25
#include <linux/kernel.h>
 
26
#include <linux/slab.h>
 
27
#include "cgs_common.h"
 
28
#include "power_state.h"
 
29
#include "hwmgr.h"
 
30
#include "pppcielanes.h"
 
31
#include "pp_debug.h"
 
32
#include "ppatomctrl.h"
 
33
 
 
34
extern int cz_hwmgr_init(struct pp_hwmgr *hwmgr);
 
35
extern int tonga_hwmgr_init(struct pp_hwmgr *hwmgr);
 
36
extern int fiji_hwmgr_init(struct pp_hwmgr *hwmgr);
 
37
 
 
38
int hwmgr_init(struct amd_pp_init *pp_init, struct pp_instance *handle)
 
39
{
 
40
        struct pp_hwmgr *hwmgr;
 
41
 
 
42
        if ((handle == NULL) || (pp_init == NULL))
 
43
                return -EINVAL;
 
44
 
 
45
        hwmgr = kzalloc(sizeof(struct pp_hwmgr), GFP_KERNEL);
 
46
        if (hwmgr == NULL)
 
47
                return -ENOMEM;
 
48
 
 
49
        handle->hwmgr = hwmgr;
 
50
        hwmgr->smumgr = handle->smu_mgr;
 
51
        hwmgr->device = pp_init->device;
 
52
        hwmgr->chip_family = pp_init->chip_family;
 
53
        hwmgr->chip_id = pp_init->chip_id;
 
54
        hwmgr->hw_revision = pp_init->rev_id;
 
55
        hwmgr->usec_timeout = AMD_MAX_USEC_TIMEOUT;
 
56
        hwmgr->power_source = PP_PowerSource_AC;
 
57
 
 
58
        switch (hwmgr->chip_family) {
 
59
        case AMD_FAMILY_CZ:
 
60
                cz_hwmgr_init(hwmgr);
 
61
                break;
 
62
        case AMD_FAMILY_VI:
 
63
                switch (hwmgr->chip_id) {
 
64
                case CHIP_TONGA:
 
65
                        tonga_hwmgr_init(hwmgr);
 
66
                        break;
 
67
                case CHIP_FIJI:
 
68
                        fiji_hwmgr_init(hwmgr);
 
69
                        break;
 
70
                default:
 
71
                        return -EINVAL;
 
72
                }
 
73
                break;
 
74
        default:
 
75
                return -EINVAL;
 
76
        }
 
77
 
 
78
        phm_init_dynamic_caps(hwmgr);
 
79
 
 
80
        return 0;
 
81
}
 
82
 
 
83
int hwmgr_fini(struct pp_hwmgr *hwmgr)
 
84
{
 
85
        if (hwmgr == NULL || hwmgr->ps == NULL)
 
86
                return -EINVAL;
 
87
 
 
88
        kfree(hwmgr->ps);
 
89
        kfree(hwmgr);
 
90
        return 0;
 
91
}
 
92
 
 
93
int hw_init_power_state_table(struct pp_hwmgr *hwmgr)
 
94
{
 
95
        int result;
 
96
        unsigned int i;
 
97
        unsigned int table_entries;
 
98
        struct pp_power_state *state;
 
99
        int size;
 
100
 
 
101
        if (hwmgr->hwmgr_func->get_num_of_pp_table_entries == NULL)
 
102
                return -EINVAL;
 
103
 
 
104
        if (hwmgr->hwmgr_func->get_power_state_size == NULL)
 
105
                return -EINVAL;
 
106
 
 
107
        hwmgr->num_ps = table_entries = hwmgr->hwmgr_func->get_num_of_pp_table_entries(hwmgr);
 
108
 
 
109
        hwmgr->ps_size = size = hwmgr->hwmgr_func->get_power_state_size(hwmgr) +
 
110
                                          sizeof(struct pp_power_state);
 
111
 
 
112
        hwmgr->ps = kzalloc(size * table_entries, GFP_KERNEL);
 
113
 
 
114
        if (hwmgr->ps == NULL)
 
115
                return -ENOMEM;
 
116
 
 
117
        state = hwmgr->ps;
 
118
 
 
119
        for (i = 0; i < table_entries; i++) {
 
120
                result = hwmgr->hwmgr_func->get_pp_table_entry(hwmgr, i, state);
 
121
 
 
122
                if (state->classification.flags & PP_StateClassificationFlag_Boot) {
 
123
                        hwmgr->boot_ps = state;
 
124
                        hwmgr->current_ps = hwmgr->request_ps = state;
 
125
                }
 
126
 
 
127
                state->id = i + 1; /* assigned unique num for every power state id */
 
128
 
 
129
                if (state->classification.flags & PP_StateClassificationFlag_Uvd)
 
130
                        hwmgr->uvd_ps = state;
 
131
                state = (struct pp_power_state *)((unsigned long)state + size);
 
132
        }
 
133
 
 
134
        return 0;
 
135
}
 
136
 
 
137
 
 
138
/**
 
139
 * Returns once the part of the register indicated by the mask has
 
140
 * reached the given value.
 
141
 */
 
142
int phm_wait_on_register(struct pp_hwmgr *hwmgr, uint32_t index,
 
143
                         uint32_t value, uint32_t mask)
 
144
{
 
145
        uint32_t i;
 
146
        uint32_t cur_value;
 
147
 
 
148
        if (hwmgr == NULL || hwmgr->device == NULL) {
 
149
                printk(KERN_ERR "[ powerplay ] Invalid Hardware Manager!");
 
150
                return -EINVAL;
 
151
        }
 
152
 
 
153
        for (i = 0; i < hwmgr->usec_timeout; i++) {
 
154
                cur_value = cgs_read_register(hwmgr->device, index);
 
155
                if ((cur_value & mask) == (value & mask))
 
156
                        break;
 
157
                udelay(1);
 
158
        }
 
159
 
 
160
        /* timeout means wrong logic*/
 
161
        if (i == hwmgr->usec_timeout)
 
162
                return -1;
 
163
        return 0;
 
164
}
 
165
 
 
166
int phm_wait_for_register_unequal(struct pp_hwmgr *hwmgr,
 
167
                                uint32_t index, uint32_t value, uint32_t mask)
 
168
{
 
169
        uint32_t i;
 
170
        uint32_t cur_value;
 
171
 
 
172
        if (hwmgr == NULL || hwmgr->device == NULL) {
 
173
                printk(KERN_ERR "[ powerplay ] Invalid Hardware Manager!");
 
174
                return -EINVAL;
 
175
        }
 
176
 
 
177
        for (i = 0; i < hwmgr->usec_timeout; i++) {
 
178
                cur_value = cgs_read_register(hwmgr->device, index);
 
179
                if ((cur_value & mask) != (value & mask))
 
180
                        break;
 
181
                udelay(1);
 
182
        }
 
183
 
 
184
        /* timeout means wrong logic*/
 
185
        if (i == hwmgr->usec_timeout)
 
186
                return -1;
 
187
        return 0;
 
188
}
 
189
 
 
190
 
 
191
/**
 
192
 * Returns once the part of the register indicated by the mask has
 
193
 * reached the given value.The indirect space is described by giving
 
194
 * the memory-mapped index of the indirect index register.
 
195
 */
 
196
void phm_wait_on_indirect_register(struct pp_hwmgr *hwmgr,
 
197
                                uint32_t indirect_port,
 
198
                                uint32_t index,
 
199
                                uint32_t value,
 
200
                                uint32_t mask)
 
201
{
 
202
        if (hwmgr == NULL || hwmgr->device == NULL) {
 
203
                printk(KERN_ERR "[ powerplay ] Invalid Hardware Manager!");
 
204
                return;
 
205
        }
 
206
 
 
207
        cgs_write_register(hwmgr->device, indirect_port, index);
 
208
        phm_wait_on_register(hwmgr, indirect_port + 1, mask, value);
 
209
}
 
210
 
 
211
void phm_wait_for_indirect_register_unequal(struct pp_hwmgr *hwmgr,
 
212
                                        uint32_t indirect_port,
 
213
                                        uint32_t index,
 
214
                                        uint32_t value,
 
215
                                        uint32_t mask)
 
216
{
 
217
        if (hwmgr == NULL || hwmgr->device == NULL) {
 
218
                printk(KERN_ERR "[ powerplay ] Invalid Hardware Manager!");
 
219
                return;
 
220
        }
 
221
 
 
222
        cgs_write_register(hwmgr->device, indirect_port, index);
 
223
        phm_wait_for_register_unequal(hwmgr, indirect_port + 1,
 
224
                                      value, mask);
 
225
}
 
226
 
 
227
bool phm_cf_want_uvd_power_gating(struct pp_hwmgr *hwmgr)
 
228
{
 
229
        return phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_UVDPowerGating);
 
230
}
 
231
 
 
232
bool phm_cf_want_vce_power_gating(struct pp_hwmgr *hwmgr)
 
233
{
 
234
        return phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_VCEPowerGating);
 
235
}
 
236
 
 
237
 
 
238
int phm_trim_voltage_table(struct pp_atomctrl_voltage_table *vol_table)
 
239
{
 
240
        uint32_t i, j;
 
241
        uint16_t vvalue;
 
242
        bool found = false;
 
243
        struct pp_atomctrl_voltage_table *table;
 
244
 
 
245
        PP_ASSERT_WITH_CODE((NULL != vol_table),
 
246
                        "Voltage Table empty.", return -EINVAL);
 
247
 
 
248
        table = kzalloc(sizeof(struct pp_atomctrl_voltage_table),
 
249
                        GFP_KERNEL);
 
250
 
 
251
        if (NULL == table)
 
252
                return -EINVAL;
 
253
 
 
254
        table->mask_low = vol_table->mask_low;
 
255
        table->phase_delay = vol_table->phase_delay;
 
256
 
 
257
        for (i = 0; i < vol_table->count; i++) {
 
258
                vvalue = vol_table->entries[i].value;
 
259
                found = false;
 
260
 
 
261
                for (j = 0; j < table->count; j++) {
 
262
                        if (vvalue == table->entries[j].value) {
 
263
                                found = true;
 
264
                                break;
 
265
                        }
 
266
                }
 
267
 
 
268
                if (!found) {
 
269
                        table->entries[table->count].value = vvalue;
 
270
                        table->entries[table->count].smio_low =
 
271
                                        vol_table->entries[i].smio_low;
 
272
                        table->count++;
 
273
                }
 
274
        }
 
275
 
 
276
        memcpy(vol_table, table, sizeof(struct pp_atomctrl_voltage_table));
 
277
        kfree(table);
 
278
 
 
279
        return 0;
 
280
}
 
281
 
 
282
int phm_get_svi2_mvdd_voltage_table(struct pp_atomctrl_voltage_table *vol_table,
 
283
                phm_ppt_v1_clock_voltage_dependency_table *dep_table)
 
284
{
 
285
        uint32_t i;
 
286
        int result;
 
287
 
 
288
        PP_ASSERT_WITH_CODE((0 != dep_table->count),
 
289
                        "Voltage Dependency Table empty.", return -EINVAL);
 
290
 
 
291
        PP_ASSERT_WITH_CODE((NULL != vol_table),
 
292
                        "vol_table empty.", return -EINVAL);
 
293
 
 
294
        vol_table->mask_low = 0;
 
295
        vol_table->phase_delay = 0;
 
296
        vol_table->count = dep_table->count;
 
297
 
 
298
        for (i = 0; i < dep_table->count; i++) {
 
299
                vol_table->entries[i].value = dep_table->entries[i].mvdd;
 
300
                vol_table->entries[i].smio_low = 0;
 
301
        }
 
302
 
 
303
        result = phm_trim_voltage_table(vol_table);
 
304
        PP_ASSERT_WITH_CODE((0 == result),
 
305
                        "Failed to trim MVDD table.", return result);
 
306
 
 
307
        return 0;
 
308
}
 
309
 
 
310
int phm_get_svi2_vddci_voltage_table(struct pp_atomctrl_voltage_table *vol_table,
 
311
                phm_ppt_v1_clock_voltage_dependency_table *dep_table)
 
312
{
 
313
        uint32_t i;
 
314
        int result;
 
315
 
 
316
        PP_ASSERT_WITH_CODE((0 != dep_table->count),
 
317
                        "Voltage Dependency Table empty.", return -EINVAL);
 
318
 
 
319
        PP_ASSERT_WITH_CODE((NULL != vol_table),
 
320
                        "vol_table empty.", return -EINVAL);
 
321
 
 
322
        vol_table->mask_low = 0;
 
323
        vol_table->phase_delay = 0;
 
324
        vol_table->count = dep_table->count;
 
325
 
 
326
        for (i = 0; i < dep_table->count; i++) {
 
327
                vol_table->entries[i].value = dep_table->entries[i].vddci;
 
328
                vol_table->entries[i].smio_low = 0;
 
329
        }
 
330
 
 
331
        result = phm_trim_voltage_table(vol_table);
 
332
        PP_ASSERT_WITH_CODE((0 == result),
 
333
                        "Failed to trim VDDCI table.", return result);
 
334
 
 
335
        return 0;
 
336
}
 
337
 
 
338
int phm_get_svi2_vdd_voltage_table(struct pp_atomctrl_voltage_table *vol_table,
 
339
                phm_ppt_v1_voltage_lookup_table *lookup_table)
 
340
{
 
341
        int i = 0;
 
342
 
 
343
        PP_ASSERT_WITH_CODE((0 != lookup_table->count),
 
344
                        "Voltage Lookup Table empty.", return -EINVAL);
 
345
 
 
346
        PP_ASSERT_WITH_CODE((NULL != vol_table),
 
347
                        "vol_table empty.", return -EINVAL);
 
348
 
 
349
        vol_table->mask_low = 0;
 
350
        vol_table->phase_delay = 0;
 
351
 
 
352
        vol_table->count = lookup_table->count;
 
353
 
 
354
        for (i = 0; i < vol_table->count; i++) {
 
355
                vol_table->entries[i].value = lookup_table->entries[i].us_vdd;
 
356
                vol_table->entries[i].smio_low = 0;
 
357
        }
 
358
 
 
359
        return 0;
 
360
}
 
361
 
 
362
void phm_trim_voltage_table_to_fit_state_table(uint32_t max_vol_steps,
 
363
                                struct pp_atomctrl_voltage_table *vol_table)
 
364
{
 
365
        unsigned int i, diff;
 
366
 
 
367
        if (vol_table->count <= max_vol_steps)
 
368
                return;
 
369
 
 
370
        diff = vol_table->count - max_vol_steps;
 
371
 
 
372
        for (i = 0; i < max_vol_steps; i++)
 
373
                vol_table->entries[i] = vol_table->entries[i + diff];
 
374
 
 
375
        vol_table->count = max_vol_steps;
 
376
 
 
377
        return;
 
378
}
 
379
 
 
380
int phm_reset_single_dpm_table(void *table,
 
381
                                uint32_t count, int max)
 
382
{
 
383
        int i;
 
384
 
 
385
        struct vi_dpm_table *dpm_table = (struct vi_dpm_table *)table;
 
386
 
 
387
        PP_ASSERT_WITH_CODE(count <= max,
 
388
                        "Fatal error, can not set up single DPM table entries to exceed max number!",
 
389
                           );
 
390
 
 
391
        dpm_table->count = count;
 
392
        for (i = 0; i < max; i++)
 
393
                dpm_table->dpm_level[i].enabled = false;
 
394
 
 
395
        return 0;
 
396
}
 
397
 
 
398
void phm_setup_pcie_table_entry(
 
399
        void *table,
 
400
        uint32_t index, uint32_t pcie_gen,
 
401
        uint32_t pcie_lanes)
 
402
{
 
403
        struct vi_dpm_table *dpm_table = (struct vi_dpm_table *)table;
 
404
        dpm_table->dpm_level[index].value = pcie_gen;
 
405
        dpm_table->dpm_level[index].param1 = pcie_lanes;
 
406
        dpm_table->dpm_level[index].enabled = 1;
 
407
}
 
408
 
 
409
int32_t phm_get_dpm_level_enable_mask_value(void *table)
 
410
{
 
411
        int32_t i;
 
412
        int32_t mask = 0;
 
413
        struct vi_dpm_table *dpm_table = (struct vi_dpm_table *)table;
 
414
 
 
415
        for (i = dpm_table->count; i > 0; i--) {
 
416
                mask = mask << 1;
 
417
                if (dpm_table->dpm_level[i - 1].enabled)
 
418
                        mask |= 0x1;
 
419
                else
 
420
                        mask &= 0xFFFFFFFE;
 
421
        }
 
422
 
 
423
        return mask;
 
424
}
 
425
 
 
426
uint8_t phm_get_voltage_index(
 
427
                struct phm_ppt_v1_voltage_lookup_table *lookup_table, uint16_t voltage)
 
428
{
 
429
        uint8_t count = (uint8_t) (lookup_table->count);
 
430
        uint8_t i;
 
431
 
 
432
        PP_ASSERT_WITH_CODE((NULL != lookup_table),
 
433
                        "Lookup Table empty.", return 0);
 
434
        PP_ASSERT_WITH_CODE((0 != count),
 
435
                        "Lookup Table empty.", return 0);
 
436
 
 
437
        for (i = 0; i < lookup_table->count; i++) {
 
438
                /* find first voltage equal or bigger than requested */
 
439
                if (lookup_table->entries[i].us_vdd >= voltage)
 
440
                        return i;
 
441
        }
 
442
        /* voltage is bigger than max voltage in the table */
 
443
        return i - 1;
 
444
}
 
445
 
 
446
uint16_t phm_find_closest_vddci(struct pp_atomctrl_voltage_table *vddci_table, uint16_t vddci)
 
447
{
 
448
        uint32_t  i;
 
449
 
 
450
        for (i = 0; i < vddci_table->count; i++) {
 
451
                if (vddci_table->entries[i].value >= vddci)
 
452
                        return vddci_table->entries[i].value;
 
453
        }
 
454
 
 
455
        PP_ASSERT_WITH_CODE(false,
 
456
                        "VDDCI is larger than max VDDCI in VDDCI Voltage Table!",
 
457
                        return vddci_table->entries[i].value);
 
458
}
 
459
 
 
460
int phm_find_boot_level(void *table,
 
461
                uint32_t value, uint32_t *boot_level)
 
462
{
 
463
        int result = -EINVAL;
 
464
        uint32_t i;
 
465
        struct vi_dpm_table *dpm_table = (struct vi_dpm_table *)table;
 
466
 
 
467
        for (i = 0; i < dpm_table->count; i++) {
 
468
                if (value == dpm_table->dpm_level[i].value) {
 
469
                        *boot_level = i;
 
470
                        result = 0;
 
471
                }
 
472
        }
 
473
 
 
474
        return result;
 
475
}
 
476
 
 
477
int phm_get_sclk_for_voltage_evv(struct pp_hwmgr *hwmgr,
 
478
        phm_ppt_v1_voltage_lookup_table *lookup_table,
 
479
        uint16_t virtual_voltage_id, int32_t *sclk)
 
480
{
 
481
        uint8_t entryId;
 
482
        uint8_t voltageId;
 
483
        struct phm_ppt_v1_information *table_info =
 
484
                        (struct phm_ppt_v1_information *)(hwmgr->pptable);
 
485
 
 
486
        PP_ASSERT_WITH_CODE(lookup_table->count != 0, "Lookup table is empty", return -EINVAL);
 
487
 
 
488
        /* search for leakage voltage ID 0xff01 ~ 0xff08 and sckl */
 
489
        for (entryId = 0; entryId < table_info->vdd_dep_on_sclk->count; entryId++) {
 
490
                voltageId = table_info->vdd_dep_on_sclk->entries[entryId].vddInd;
 
491
                if (lookup_table->entries[voltageId].us_vdd == virtual_voltage_id)
 
492
                        break;
 
493
        }
 
494
 
 
495
        PP_ASSERT_WITH_CODE(entryId < table_info->vdd_dep_on_sclk->count,
 
496
                        "Can't find requested voltage id in vdd_dep_on_sclk table!",
 
497
                        return -EINVAL;
 
498
                        );
 
499
 
 
500
        *sclk = table_info->vdd_dep_on_sclk->entries[entryId].clk;
 
501
 
 
502
        return 0;
 
503
}
 
504
 
 
505
/**
 
506
 * Initialize Dynamic State Adjustment Rule Settings
 
507
 *
 
508
 * @param    hwmgr  the address of the powerplay hardware manager.
 
509
 */
 
510
int phm_initializa_dynamic_state_adjustment_rule_settings(struct pp_hwmgr *hwmgr)
 
511
{
 
512
        uint32_t table_size;
 
513
        struct phm_clock_voltage_dependency_table *table_clk_vlt;
 
514
        struct phm_ppt_v1_information *pptable_info = (struct phm_ppt_v1_information *)(hwmgr->pptable);
 
515
 
 
516
        /* initialize vddc_dep_on_dal_pwrl table */
 
517
        table_size = sizeof(uint32_t) + 4 * sizeof(struct phm_clock_voltage_dependency_record);
 
518
        table_clk_vlt = (struct phm_clock_voltage_dependency_table *)kzalloc(table_size, GFP_KERNEL);
 
519
 
 
520
        if (NULL == table_clk_vlt) {
 
521
                printk(KERN_ERR "[ powerplay ] Can not allocate space for vddc_dep_on_dal_pwrl! \n");
 
522
                return -ENOMEM;
 
523
        } else {
 
524
                table_clk_vlt->count = 4;
 
525
                table_clk_vlt->entries[0].clk = PP_DAL_POWERLEVEL_ULTRALOW;
 
526
                table_clk_vlt->entries[0].v = 0;
 
527
                table_clk_vlt->entries[1].clk = PP_DAL_POWERLEVEL_LOW;
 
528
                table_clk_vlt->entries[1].v = 720;
 
529
                table_clk_vlt->entries[2].clk = PP_DAL_POWERLEVEL_NOMINAL;
 
530
                table_clk_vlt->entries[2].v = 810;
 
531
                table_clk_vlt->entries[3].clk = PP_DAL_POWERLEVEL_PERFORMANCE;
 
532
                table_clk_vlt->entries[3].v = 900;
 
533
                pptable_info->vddc_dep_on_dal_pwrl = table_clk_vlt;
 
534
                hwmgr->dyn_state.vddc_dep_on_dal_pwrl = table_clk_vlt;
 
535
        }
 
536
 
 
537
        return 0;
 
538
}
 
539
 
 
540
int phm_hwmgr_backend_fini(struct pp_hwmgr *hwmgr)
 
541
{
 
542
        if (NULL != hwmgr->dyn_state.vddc_dep_on_dal_pwrl) {
 
543
                kfree(hwmgr->dyn_state.vddc_dep_on_dal_pwrl);
 
544
                hwmgr->dyn_state.vddc_dep_on_dal_pwrl = NULL;
 
545
        }
 
546
 
 
547
        if (NULL != hwmgr->backend) {
 
548
                kfree(hwmgr->backend);
 
549
                hwmgr->backend = NULL;
 
550
        }
 
551
 
 
552
        return 0;
 
553
}
 
554
 
 
555
uint32_t phm_get_lowest_enabled_level(struct pp_hwmgr *hwmgr, uint32_t mask)
 
556
{
 
557
        uint32_t level = 0;
 
558
 
 
559
        while (0 == (mask & (1 << level)))
 
560
                level++;
 
561
 
 
562
        return level;
 
563
}