diff options
Diffstat (limited to 'common/recipes-kernel/linux/files/0122-drm-amd-powerplay-move-shared-function-of-vi-to-hwmg.patch')
-rw-r--r-- | common/recipes-kernel/linux/files/0122-drm-amd-powerplay-move-shared-function-of-vi-to-hwmg.patch | 488 |
1 files changed, 488 insertions, 0 deletions
diff --git a/common/recipes-kernel/linux/files/0122-drm-amd-powerplay-move-shared-function-of-vi-to-hwmg.patch b/common/recipes-kernel/linux/files/0122-drm-amd-powerplay-move-shared-function-of-vi-to-hwmg.patch new file mode 100644 index 00000000..eaabdeba --- /dev/null +++ b/common/recipes-kernel/linux/files/0122-drm-amd-powerplay-move-shared-function-of-vi-to-hwmg.patch @@ -0,0 +1,488 @@ +From e3a99cfd915c79a5e5026310d39fa37104a66b11 Mon Sep 17 00:00:00 2001 +From: Rex Zhu <Rex.Zhu@amd.com> +Date: Thu, 3 Dec 2015 14:16:01 +0800 +Subject: [PATCH 0122/1110] drm/amd/powerplay: move shared function of vi to + hwmgr. (v2) + +v2: agd: rebase on upstream + +Reviewed-by: Alex Deucher <alexander.deucher@amd.com> +Signed-off-by: Rex Zhu <Rex.Zhu@amd.com> +--- + drivers/gpu/drm/amd/powerplay/hwmgr/fiji_hwmgr.c | 6 - + drivers/gpu/drm/amd/powerplay/hwmgr/hwmgr.c | 336 +++++++++++++++++++++- + drivers/gpu/drm/amd/powerplay/hwmgr/tonga_hwmgr.c | 8 - + drivers/gpu/drm/amd/powerplay/inc/hwmgr.h | 48 +++- + 4 files changed, 379 insertions(+), 19 deletions(-) + +diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/fiji_hwmgr.c b/drivers/gpu/drm/amd/powerplay/hwmgr/fiji_hwmgr.c +index fec0789..94f404c 100644 +--- a/drivers/gpu/drm/amd/powerplay/hwmgr/fiji_hwmgr.c ++++ b/drivers/gpu/drm/amd/powerplay/hwmgr/fiji_hwmgr.c +@@ -91,12 +91,6 @@ enum DPM_EVENT_SRC { + DPM_EVENT_SRC_DIGITAL_OR_EXTERNAL = 4 /* Internal digital or external */ + }; + +-enum DISPLAY_GAP { +- DISPLAY_GAP_VBLANK_OR_WM = 0, /* Wait for vblank or MCHG watermark. */ +- DISPLAY_GAP_VBLANK = 1, /* Wait for vblank. */ +- DISPLAY_GAP_WATERMARK = 2, /* Wait for MCHG watermark. */ +- DISPLAY_GAP_IGNORE = 3 /* Do not wait. */ +-}; + + /* [2.5%,~2.5%] Clock stretched is multiple of 2.5% vs + * not and [Fmin, Fmax, LDO_REFSEL, USE_FOR_LOW_FREQ] +diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/hwmgr.c b/drivers/gpu/drm/amd/powerplay/hwmgr/hwmgr.c +index 618cc4d..ca4554b 100644 +--- a/drivers/gpu/drm/amd/powerplay/hwmgr/hwmgr.c ++++ b/drivers/gpu/drm/amd/powerplay/hwmgr/hwmgr.c +@@ -27,9 +27,12 @@ + #include "cgs_common.h" + #include "power_state.h" + #include "hwmgr.h" +-#include "cz_hwmgr.h" +-#include "tonga_hwmgr.h" ++#include "pppcielanes.h" ++#include "pp_debug.h" ++#include "ppatomctrl.h" + ++extern int cz_hwmgr_init(struct pp_hwmgr *hwmgr); ++extern int tonga_hwmgr_init(struct pp_hwmgr *hwmgr); + extern int fiji_hwmgr_init(struct pp_hwmgr *hwmgr); + + int hwmgr_init(struct amd_pp_init *pp_init, struct pp_instance *handle) +@@ -112,6 +115,7 @@ int hw_init_power_state_table(struct pp_hwmgr *hwmgr) + + for (i = 0; i < table_entries; i++) { + result = hwmgr->hwmgr_func->get_pp_table_entry(hwmgr, i, state); ++ + if (state->classification.flags & PP_StateClassificationFlag_Boot) { + hwmgr->boot_ps = state; + hwmgr->current_ps = hwmgr->request_ps = state; +@@ -226,3 +230,331 @@ bool phm_cf_want_vce_power_gating(struct pp_hwmgr *hwmgr) + { + return phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_VCEPowerGating); + } ++ ++ ++int phm_trim_voltage_table(struct pp_atomctrl_voltage_table *vol_table) ++{ ++ uint32_t i, j; ++ uint16_t vvalue; ++ bool found = false; ++ struct pp_atomctrl_voltage_table *table; ++ ++ PP_ASSERT_WITH_CODE((NULL != vol_table), ++ "Voltage Table empty.", return -EINVAL); ++ ++ table = kzalloc(sizeof(struct pp_atomctrl_voltage_table), ++ GFP_KERNEL); ++ ++ if (NULL == table) ++ return -EINVAL; ++ ++ table->mask_low = vol_table->mask_low; ++ table->phase_delay = vol_table->phase_delay; ++ ++ for (i = 0; i < vol_table->count; i++) { ++ vvalue = vol_table->entries[i].value; ++ found = false; ++ ++ for (j = 0; j < table->count; j++) { ++ if (vvalue == table->entries[j].value) { ++ found = true; ++ break; ++ } ++ } ++ ++ if (!found) { ++ table->entries[table->count].value = vvalue; ++ table->entries[table->count].smio_low = ++ vol_table->entries[i].smio_low; ++ table->count++; ++ } ++ } ++ ++ memcpy(vol_table, table, sizeof(struct pp_atomctrl_voltage_table)); ++ kfree(table); ++ ++ return 0; ++} ++ ++int phm_get_svi2_mvdd_voltage_table(struct pp_atomctrl_voltage_table *vol_table, ++ phm_ppt_v1_clock_voltage_dependency_table *dep_table) ++{ ++ uint32_t i; ++ int result; ++ ++ PP_ASSERT_WITH_CODE((0 != dep_table->count), ++ "Voltage Dependency Table empty.", return -EINVAL); ++ ++ PP_ASSERT_WITH_CODE((NULL != vol_table), ++ "vol_table empty.", return -EINVAL); ++ ++ vol_table->mask_low = 0; ++ vol_table->phase_delay = 0; ++ vol_table->count = dep_table->count; ++ ++ for (i = 0; i < dep_table->count; i++) { ++ vol_table->entries[i].value = dep_table->entries[i].mvdd; ++ vol_table->entries[i].smio_low = 0; ++ } ++ ++ result = phm_trim_voltage_table(vol_table); ++ PP_ASSERT_WITH_CODE((0 == result), ++ "Failed to trim MVDD table.", return result); ++ ++ return 0; ++} ++ ++int phm_get_svi2_vddci_voltage_table(struct pp_atomctrl_voltage_table *vol_table, ++ phm_ppt_v1_clock_voltage_dependency_table *dep_table) ++{ ++ uint32_t i; ++ int result; ++ ++ PP_ASSERT_WITH_CODE((0 != dep_table->count), ++ "Voltage Dependency Table empty.", return -EINVAL); ++ ++ PP_ASSERT_WITH_CODE((NULL != vol_table), ++ "vol_table empty.", return -EINVAL); ++ ++ vol_table->mask_low = 0; ++ vol_table->phase_delay = 0; ++ vol_table->count = dep_table->count; ++ ++ for (i = 0; i < dep_table->count; i++) { ++ vol_table->entries[i].value = dep_table->entries[i].vddci; ++ vol_table->entries[i].smio_low = 0; ++ } ++ ++ result = phm_trim_voltage_table(vol_table); ++ PP_ASSERT_WITH_CODE((0 == result), ++ "Failed to trim VDDCI table.", return result); ++ ++ return 0; ++} ++ ++int phm_get_svi2_vdd_voltage_table(struct pp_atomctrl_voltage_table *vol_table, ++ phm_ppt_v1_voltage_lookup_table *lookup_table) ++{ ++ int i = 0; ++ ++ PP_ASSERT_WITH_CODE((0 != lookup_table->count), ++ "Voltage Lookup Table empty.", return -EINVAL); ++ ++ PP_ASSERT_WITH_CODE((NULL != vol_table), ++ "vol_table empty.", return -EINVAL); ++ ++ vol_table->mask_low = 0; ++ vol_table->phase_delay = 0; ++ ++ vol_table->count = lookup_table->count; ++ ++ for (i = 0; i < vol_table->count; i++) { ++ vol_table->entries[i].value = lookup_table->entries[i].us_vdd; ++ vol_table->entries[i].smio_low = 0; ++ } ++ ++ return 0; ++} ++ ++void phm_trim_voltage_table_to_fit_state_table(uint32_t max_vol_steps, ++ struct pp_atomctrl_voltage_table *vol_table) ++{ ++ unsigned int i, diff; ++ ++ if (vol_table->count <= max_vol_steps) ++ return; ++ ++ diff = vol_table->count - max_vol_steps; ++ ++ for (i = 0; i < max_vol_steps; i++) ++ vol_table->entries[i] = vol_table->entries[i + diff]; ++ ++ vol_table->count = max_vol_steps; ++ ++ return; ++} ++ ++int phm_reset_single_dpm_table(void *table, ++ uint32_t count, int max) ++{ ++ int i; ++ ++ struct vi_dpm_table *dpm_table = (struct vi_dpm_table *)table; ++ ++ PP_ASSERT_WITH_CODE(count <= max, ++ "Fatal error, can not set up single DPM table entries to exceed max number!", ++ ); ++ ++ dpm_table->count = count; ++ for (i = 0; i < max; i++) ++ dpm_table->dpm_level[i].enabled = false; ++ ++ return 0; ++} ++ ++void phm_setup_pcie_table_entry( ++ void *table, ++ uint32_t index, uint32_t pcie_gen, ++ uint32_t pcie_lanes) ++{ ++ struct vi_dpm_table *dpm_table = (struct vi_dpm_table *)table; ++ dpm_table->dpm_level[index].value = pcie_gen; ++ dpm_table->dpm_level[index].param1 = pcie_lanes; ++ dpm_table->dpm_level[index].enabled = 1; ++} ++ ++int32_t phm_get_dpm_level_enable_mask_value(void *table) ++{ ++ int32_t i; ++ int32_t mask = 0; ++ struct vi_dpm_table *dpm_table = (struct vi_dpm_table *)table; ++ ++ for (i = dpm_table->count; i > 0; i--) { ++ mask = mask << 1; ++ if (dpm_table->dpm_level[i - 1].enabled) ++ mask |= 0x1; ++ else ++ mask &= 0xFFFFFFFE; ++ } ++ ++ return mask; ++} ++ ++uint8_t phm_get_voltage_index( ++ struct phm_ppt_v1_voltage_lookup_table *lookup_table, uint16_t voltage) ++{ ++ uint8_t count = (uint8_t) (lookup_table->count); ++ uint8_t i; ++ ++ PP_ASSERT_WITH_CODE((NULL != lookup_table), ++ "Lookup Table empty.", return 0); ++ PP_ASSERT_WITH_CODE((0 != count), ++ "Lookup Table empty.", return 0); ++ ++ for (i = 0; i < lookup_table->count; i++) { ++ /* find first voltage equal or bigger than requested */ ++ if (lookup_table->entries[i].us_vdd >= voltage) ++ return i; ++ } ++ /* voltage is bigger than max voltage in the table */ ++ return i - 1; ++} ++ ++uint16_t phm_find_closest_vddci(struct pp_atomctrl_voltage_table *vddci_table, uint16_t vddci) ++{ ++ uint32_t i; ++ ++ for (i = 0; i < vddci_table->count; i++) { ++ if (vddci_table->entries[i].value >= vddci) ++ return vddci_table->entries[i].value; ++ } ++ ++ PP_ASSERT_WITH_CODE(false, ++ "VDDCI is larger than max VDDCI in VDDCI Voltage Table!", ++ return vddci_table->entries[i].value); ++} ++ ++int phm_find_boot_level(void *table, ++ uint32_t value, uint32_t *boot_level) ++{ ++ int result = -EINVAL; ++ uint32_t i; ++ struct vi_dpm_table *dpm_table = (struct vi_dpm_table *)table; ++ ++ for (i = 0; i < dpm_table->count; i++) { ++ if (value == dpm_table->dpm_level[i].value) { ++ *boot_level = i; ++ result = 0; ++ } ++ } ++ ++ return result; ++} ++ ++int phm_get_sclk_for_voltage_evv(struct pp_hwmgr *hwmgr, ++ phm_ppt_v1_voltage_lookup_table *lookup_table, ++ uint16_t virtual_voltage_id, int32_t *sclk) ++{ ++ uint8_t entryId; ++ uint8_t voltageId; ++ struct phm_ppt_v1_information *table_info = ++ (struct phm_ppt_v1_information *)(hwmgr->pptable); ++ ++ PP_ASSERT_WITH_CODE(lookup_table->count != 0, "Lookup table is empty", return -EINVAL); ++ ++ /* search for leakage voltage ID 0xff01 ~ 0xff08 and sckl */ ++ for (entryId = 0; entryId < table_info->vdd_dep_on_sclk->count; entryId++) { ++ voltageId = table_info->vdd_dep_on_sclk->entries[entryId].vddInd; ++ if (lookup_table->entries[voltageId].us_vdd == virtual_voltage_id) ++ break; ++ } ++ ++ PP_ASSERT_WITH_CODE(entryId < table_info->vdd_dep_on_sclk->count, ++ "Can't find requested voltage id in vdd_dep_on_sclk table!", ++ return -EINVAL; ++ ); ++ ++ *sclk = table_info->vdd_dep_on_sclk->entries[entryId].clk; ++ ++ return 0; ++} ++ ++/** ++ * Initialize Dynamic State Adjustment Rule Settings ++ * ++ * @param hwmgr the address of the powerplay hardware manager. ++ */ ++int phm_initializa_dynamic_state_adjustment_rule_settings(struct pp_hwmgr *hwmgr) ++{ ++ uint32_t table_size; ++ struct phm_clock_voltage_dependency_table *table_clk_vlt; ++ struct phm_ppt_v1_information *pptable_info = (struct phm_ppt_v1_information *)(hwmgr->pptable); ++ ++ /* initialize vddc_dep_on_dal_pwrl table */ ++ table_size = sizeof(uint32_t) + 4 * sizeof(struct phm_clock_voltage_dependency_record); ++ table_clk_vlt = (struct phm_clock_voltage_dependency_table *)kzalloc(table_size, GFP_KERNEL); ++ ++ if (NULL == table_clk_vlt) { ++ printk(KERN_ERR "[ powerplay ] Can not allocate space for vddc_dep_on_dal_pwrl! \n"); ++ return -ENOMEM; ++ } else { ++ table_clk_vlt->count = 4; ++ table_clk_vlt->entries[0].clk = PP_DAL_POWERLEVEL_ULTRALOW; ++ table_clk_vlt->entries[0].v = 0; ++ table_clk_vlt->entries[1].clk = PP_DAL_POWERLEVEL_LOW; ++ table_clk_vlt->entries[1].v = 720; ++ table_clk_vlt->entries[2].clk = PP_DAL_POWERLEVEL_NOMINAL; ++ table_clk_vlt->entries[2].v = 810; ++ table_clk_vlt->entries[3].clk = PP_DAL_POWERLEVEL_PERFORMANCE; ++ table_clk_vlt->entries[3].v = 900; ++ pptable_info->vddc_dep_on_dal_pwrl = table_clk_vlt; ++ hwmgr->dyn_state.vddc_dep_on_dal_pwrl = table_clk_vlt; ++ } ++ ++ return 0; ++} ++ ++int phm_hwmgr_backend_fini(struct pp_hwmgr *hwmgr) ++{ ++ if (NULL != hwmgr->dyn_state.vddc_dep_on_dal_pwrl) { ++ kfree(hwmgr->dyn_state.vddc_dep_on_dal_pwrl); ++ hwmgr->dyn_state.vddc_dep_on_dal_pwrl = NULL; ++ } ++ ++ if (NULL != hwmgr->backend) { ++ kfree(hwmgr->backend); ++ hwmgr->backend = NULL; ++ } ++ ++ return 0; ++} ++ ++uint32_t phm_get_lowest_enabled_level(struct pp_hwmgr *hwmgr, uint32_t mask) ++{ ++ uint32_t level = 0; ++ ++ while (0 == (mask & (1 << level))) ++ level++; ++ ++ return level; ++} +diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/tonga_hwmgr.c b/drivers/gpu/drm/amd/powerplay/hwmgr/tonga_hwmgr.c +index 4ef06ec..a9fb42a 100644 +--- a/drivers/gpu/drm/amd/powerplay/hwmgr/tonga_hwmgr.c ++++ b/drivers/gpu/drm/amd/powerplay/hwmgr/tonga_hwmgr.c +@@ -110,14 +110,6 @@ enum DPM_EVENT_SRC { + }; + typedef enum DPM_EVENT_SRC DPM_EVENT_SRC; + +-enum DISPLAY_GAP { +- DISPLAY_GAP_VBLANK_OR_WM = 0, /* Wait for vblank or MCHG watermark. */ +- DISPLAY_GAP_VBLANK = 1, /* Wait for vblank. */ +- DISPLAY_GAP_WATERMARK = 2, /* Wait for MCHG watermark. (Note that HW may deassert WM in VBI depending on DC_STUTTER_CNTL.) */ +- DISPLAY_GAP_IGNORE = 3 /* Do not wait. */ +-}; +-typedef enum DISPLAY_GAP DISPLAY_GAP; +- + const unsigned long PhwTonga_Magic = (unsigned long)(PHM_VIslands_Magic); + + struct tonga_power_state *cast_phw_tonga_power_state( +diff --git a/drivers/gpu/drm/amd/powerplay/inc/hwmgr.h b/drivers/gpu/drm/amd/powerplay/inc/hwmgr.h +index 238d162..ec871eb 100644 +--- a/drivers/gpu/drm/amd/powerplay/inc/hwmgr.h ++++ b/drivers/gpu/drm/amd/powerplay/inc/hwmgr.h +@@ -29,6 +29,8 @@ + #include "hardwaremanager.h" + #include "pp_power_source.h" + #include "hwmgr_ppt.h" ++#include "ppatomctrl.h" ++#include "hwmgr_ppt.h" + + struct pp_instance; + struct pp_hwmgr; +@@ -36,6 +38,28 @@ struct pp_hw_power_state; + struct pp_power_state; + struct PP_VCEState; + struct phm_fan_speed_info; ++struct pp_atomctrl_voltage_table; ++ ++ ++enum DISPLAY_GAP { ++ DISPLAY_GAP_VBLANK_OR_WM = 0, /* Wait for vblank or MCHG watermark. */ ++ DISPLAY_GAP_VBLANK = 1, /* Wait for vblank. */ ++ DISPLAY_GAP_WATERMARK = 2, /* Wait for MCHG watermark. (Note that HW may deassert WM in VBI depending on DC_STUTTER_CNTL.) */ ++ DISPLAY_GAP_IGNORE = 3 /* Do not wait. */ ++}; ++typedef enum DISPLAY_GAP DISPLAY_GAP; ++ ++ ++struct vi_dpm_level { ++ bool enabled; ++ uint32_t value; ++ uint32_t param1; ++}; ++ ++struct vi_dpm_table { ++ uint32_t count; ++ struct vi_dpm_level dpm_level[1]; ++}; + + enum PP_Result { + PP_Result_TableImmediateExit = 0x13, +@@ -628,9 +652,27 @@ extern void phm_wait_for_indirect_register_unequal( + uint32_t value, + uint32_t mask); + +-bool phm_cf_want_uvd_power_gating(struct pp_hwmgr *hwmgr); +-bool phm_cf_want_vce_power_gating(struct pp_hwmgr *hwmgr); +-bool phm_cf_want_microcode_fan_ctrl(struct pp_hwmgr *hwmgr); ++extern bool phm_cf_want_uvd_power_gating(struct pp_hwmgr *hwmgr); ++extern bool phm_cf_want_vce_power_gating(struct pp_hwmgr *hwmgr); ++extern bool phm_cf_want_microcode_fan_ctrl(struct pp_hwmgr *hwmgr); ++ ++extern int phm_trim_voltage_table(struct pp_atomctrl_voltage_table *vol_table); ++extern int phm_get_svi2_mvdd_voltage_table(struct pp_atomctrl_voltage_table *vol_table, phm_ppt_v1_clock_voltage_dependency_table *dep_table); ++extern int phm_get_svi2_vddci_voltage_table(struct pp_atomctrl_voltage_table *vol_table, phm_ppt_v1_clock_voltage_dependency_table *dep_table); ++extern int phm_get_svi2_vdd_voltage_table(struct pp_atomctrl_voltage_table *vol_table, phm_ppt_v1_voltage_lookup_table *lookup_table); ++extern void phm_trim_voltage_table_to_fit_state_table(uint32_t max_vol_steps, struct pp_atomctrl_voltage_table *vol_table); ++extern int phm_reset_single_dpm_table(void *table, uint32_t count, int max); ++extern void phm_setup_pcie_table_entry(void *table, uint32_t index, uint32_t pcie_gen, uint32_t pcie_lanes); ++extern int32_t phm_get_dpm_level_enable_mask_value(void *table); ++extern uint8_t phm_get_voltage_index(struct phm_ppt_v1_voltage_lookup_table *lookup_table, uint16_t voltage); ++extern uint16_t phm_find_closest_vddci(struct pp_atomctrl_voltage_table *vddci_table, uint16_t vddci); ++extern int phm_find_boot_level(void *table, uint32_t value, uint32_t *boot_level); ++extern int phm_get_sclk_for_voltage_evv(struct pp_hwmgr *hwmgr, phm_ppt_v1_voltage_lookup_table *lookup_table, ++ uint16_t virtual_voltage_id, int32_t *sclk); ++extern int phm_initializa_dynamic_state_adjustment_rule_settings(struct pp_hwmgr *hwmgr); ++extern int phm_hwmgr_backend_fini(struct pp_hwmgr *hwmgr); ++extern uint32_t phm_get_lowest_enabled_level(struct pp_hwmgr *hwmgr, uint32_t mask); ++ + + #define PHM_ENTIRE_REGISTER_MASK 0xFFFFFFFFU + +-- +2.7.4 + |