From: Alex Deucher <alexander.deuc...@amd.com>

This data will be needed for dpm on newer asics.

v2: fix typo in rebase

Signed-off-by: Alex Deucher <alexander.deuc...@amd.com>
---
 drivers/gpu/drm/radeon/r600_dpm.c |  179 +++++++++++++++++++++++++++++++++++++
 drivers/gpu/drm/radeon/r600_dpm.h |    3 +
 drivers/gpu/drm/radeon/radeon.h   |   70 ++++++++++++++
 3 files changed, 252 insertions(+), 0 deletions(-)

diff --git a/drivers/gpu/drm/radeon/r600_dpm.c 
b/drivers/gpu/drm/radeon/r600_dpm.c
index bf396a0..c9f9647 100644
--- a/drivers/gpu/drm/radeon/r600_dpm.c
+++ b/drivers/gpu/drm/radeon/r600_dpm.c
@@ -721,3 +721,182 @@ bool r600_is_internal_thermal_sensor(enum 
radeon_int_thermal_type sensor)
                return false;
        }
 }
+
+union power_info {
+       struct _ATOM_POWERPLAY_INFO info;
+       struct _ATOM_POWERPLAY_INFO_V2 info_2;
+       struct _ATOM_POWERPLAY_INFO_V3 info_3;
+       struct _ATOM_PPLIB_POWERPLAYTABLE pplib;
+       struct _ATOM_PPLIB_POWERPLAYTABLE2 pplib2;
+       struct _ATOM_PPLIB_POWERPLAYTABLE3 pplib3;
+       struct _ATOM_PPLIB_POWERPLAYTABLE4 pplib4;
+       struct _ATOM_PPLIB_POWERPLAYTABLE5 pplib5;
+};
+
+union fan_info {
+       struct _ATOM_PPLIB_FANTABLE fan;
+       struct _ATOM_PPLIB_FANTABLE2 fan2;
+};
+
+static int r600_parse_clk_voltage_dep_table(struct 
radeon_clock_voltage_dependency_table *radeon_table,
+                                           
ATOM_PPLIB_Clock_Voltage_Dependency_Table *atom_table)
+{
+       u32 size = atom_table->ucNumEntries *
+               sizeof(struct radeon_clock_voltage_dependency_entry);
+       int i;
+
+       radeon_table->entries = kzalloc(size, GFP_KERNEL);
+       if (!radeon_table->entries)
+               return -ENOMEM;
+
+       for (i = 0; i < atom_table->ucNumEntries; i++) {
+               radeon_table->entries[i].clk = 
le16_to_cpu(atom_table->entries[i].usClockLow) |
+                       (atom_table->entries[i].ucClockHigh << 16);
+               radeon_table->entries[i].v = 
le16_to_cpu(atom_table->entries[i].usVoltage);
+       }
+       radeon_table->count = atom_table->ucNumEntries;
+
+       return 0;
+}
+
+int r600_parse_extended_power_table(struct radeon_device *rdev)
+{
+       struct radeon_mode_info *mode_info = &rdev->mode_info;
+       union power_info *power_info;
+       union fan_info *fan_info;
+       ATOM_PPLIB_Clock_Voltage_Dependency_Table *dep_table;
+       int index = GetIndexIntoMasterTable(DATA, PowerPlayInfo);
+        u16 data_offset;
+       u8 frev, crev;
+       int ret, i;
+
+       if (!atom_parse_data_header(mode_info->atom_context, index, NULL,
+                                  &frev, &crev, &data_offset))
+               return -EINVAL;
+       power_info = (union power_info *)(mode_info->atom_context->bios + 
data_offset);
+
+       /* fan table */
+       if (power_info->pplib.usTableSize >= sizeof(struct 
_ATOM_PPLIB_POWERPLAYTABLE3)) {
+               if (power_info->pplib3.usFanTableOffset) {
+                       fan_info = (union fan_info 
*)(mode_info->atom_context->bios + data_offset +
+                                                     
le16_to_cpu(power_info->pplib3.usFanTableOffset));
+                       rdev->pm.dpm.fan.t_hyst = fan_info->fan.ucTHyst;
+                       rdev->pm.dpm.fan.t_min = 
le16_to_cpu(fan_info->fan.usTMin);
+                       rdev->pm.dpm.fan.t_med = 
le16_to_cpu(fan_info->fan.usTMed);
+                       rdev->pm.dpm.fan.t_high = 
le16_to_cpu(fan_info->fan.usTHigh);
+                       rdev->pm.dpm.fan.pwm_min = 
le16_to_cpu(fan_info->fan.usPWMMin);
+                       rdev->pm.dpm.fan.pwm_med = 
le16_to_cpu(fan_info->fan.usPWMMed);
+                       rdev->pm.dpm.fan.pwm_high = 
le16_to_cpu(fan_info->fan.usPWMHigh);
+                       if (fan_info->fan.ucFanTableFormat >= 2)
+                               rdev->pm.dpm.fan.t_max = 
le16_to_cpu(fan_info->fan2.usTMax);
+                       else
+                               rdev->pm.dpm.fan.t_max = 10900;
+                       rdev->pm.dpm.fan.cycle_delay = 100000;
+                       rdev->pm.dpm.fan.ucode_fan_control = true;
+               }
+       }
+
+       /* clock dependancy tables */
+       if (power_info->pplib.usTableSize >= sizeof(struct 
_ATOM_PPLIB_POWERPLAYTABLE4)) {
+               if (power_info->pplib4.usVddcDependencyOnSCLKOffset) {
+                       dep_table = (ATOM_PPLIB_Clock_Voltage_Dependency_Table 
*)
+                               (mode_info->atom_context->bios + data_offset +
+                                
le16_to_cpu(power_info->pplib4.usVddcDependencyOnSCLKOffset));
+                       ret = 
r600_parse_clk_voltage_dep_table(&rdev->pm.dpm.dyn_state.vddc_dependency_on_sclk,
+                                                              dep_table);
+                       if (ret)
+                               return ret;
+               }
+               if (power_info->pplib4.usVddciDependencyOnMCLKOffset) {
+                       dep_table = (ATOM_PPLIB_Clock_Voltage_Dependency_Table 
*)
+                               (mode_info->atom_context->bios + data_offset +
+                                
le16_to_cpu(power_info->pplib4.usVddciDependencyOnMCLKOffset));
+                       ret = 
r600_parse_clk_voltage_dep_table(&rdev->pm.dpm.dyn_state.vddci_dependency_on_mclk,
+                                                              dep_table);
+                       if (ret) {
+                               
kfree(rdev->pm.dpm.dyn_state.vddc_dependency_on_sclk.entries);
+                               return ret;
+                       }
+               }
+               if (power_info->pplib4.usVddcDependencyOnMCLKOffset) {
+                       dep_table = (ATOM_PPLIB_Clock_Voltage_Dependency_Table 
*)
+                               (mode_info->atom_context->bios + data_offset +
+                                
le16_to_cpu(power_info->pplib4.usVddcDependencyOnMCLKOffset));
+                       ret = 
r600_parse_clk_voltage_dep_table(&rdev->pm.dpm.dyn_state.vddc_dependency_on_mclk,
+                                                              dep_table);
+                       if (ret) {
+                               
kfree(rdev->pm.dpm.dyn_state.vddc_dependency_on_sclk.entries);
+                               
kfree(rdev->pm.dpm.dyn_state.vddci_dependency_on_mclk.entries);
+                               return ret;
+                       }
+               }
+               if (power_info->pplib4.usMaxClockVoltageOnDCOffset) {
+                       ATOM_PPLIB_Clock_Voltage_Limit_Table *clk_v =
+                               (ATOM_PPLIB_Clock_Voltage_Limit_Table *)
+                               (mode_info->atom_context->bios + data_offset +
+                                
le16_to_cpu(power_info->pplib4.usMaxClockVoltageOnDCOffset));
+                       if (clk_v->ucNumEntries) {
+                               
rdev->pm.dpm.dyn_state.max_clock_voltage_on_dc.sclk =
+                                       
le16_to_cpu(clk_v->entries[0].usSclkLow) |
+                                       (clk_v->entries[0].ucSclkHigh << 16);
+                               
rdev->pm.dpm.dyn_state.max_clock_voltage_on_dc.mclk =
+                                       
le16_to_cpu(clk_v->entries[0].usMclkLow) |
+                                       (clk_v->entries[0].ucMclkHigh << 16);
+                               
rdev->pm.dpm.dyn_state.max_clock_voltage_on_dc.vddc =
+                                       le16_to_cpu(clk_v->entries[0].usVddc);
+                               
rdev->pm.dpm.dyn_state.max_clock_voltage_on_dc.vddci =
+                                       le16_to_cpu(clk_v->entries[0].usVddci);
+                       }
+               }
+       }
+
+       /* cac data */
+       if (power_info->pplib.usTableSize >= sizeof(struct 
_ATOM_PPLIB_POWERPLAYTABLE5)) {
+               rdev->pm.dpm.tdp_limit = 
le32_to_cpu(power_info->pplib5.ulTDPLimit);
+               rdev->pm.dpm.near_tdp_limit = 
le32_to_cpu(power_info->pplib5.ulNearTDPLimit);
+               rdev->pm.dpm.tdp_od_limit = 
le16_to_cpu(power_info->pplib5.usTDPODLimit);
+               if (rdev->pm.dpm.tdp_od_limit)
+                       rdev->pm.dpm.power_control = true;
+               else
+                       rdev->pm.dpm.power_control = false;
+               rdev->pm.dpm.tdp_adjustment = 0;
+               rdev->pm.dpm.sq_ramping_threshold = 
le32_to_cpu(power_info->pplib5.ulSQRampingThreshold);
+               rdev->pm.dpm.cac_leakage = 
le32_to_cpu(power_info->pplib5.ulCACLeakage);
+               rdev->pm.dpm.load_line_slope = 
le16_to_cpu(power_info->pplib5.usLoadLineSlope);
+               if (power_info->pplib5.usCACLeakageTableOffset) {
+                       ATOM_PPLIB_CAC_Leakage_Table *cac_table =
+                               (ATOM_PPLIB_CAC_Leakage_Table *)
+                               (mode_info->atom_context->bios + data_offset +
+                                
le16_to_cpu(power_info->pplib5.usCACLeakageTableOffset));
+                       u32 size = cac_table->ucNumEntries * sizeof(struct 
radeon_cac_leakage_table);
+                       rdev->pm.dpm.dyn_state.cac_leakage_table.entries = 
kzalloc(size, GFP_KERNEL);
+                       if (!rdev->pm.dpm.dyn_state.cac_leakage_table.entries) {
+                               
kfree(rdev->pm.dpm.dyn_state.vddc_dependency_on_sclk.entries);
+                               
kfree(rdev->pm.dpm.dyn_state.vddci_dependency_on_mclk.entries);
+                               
kfree(rdev->pm.dpm.dyn_state.vddc_dependency_on_mclk.entries);
+                               return -ENOMEM;
+                       }
+                       for (i = 0; i < cac_table->ucNumEntries; i++) {
+                               
rdev->pm.dpm.dyn_state.cac_leakage_table.entries[i].vddc =
+                                       
le16_to_cpu(cac_table->entries[i].usVddc);
+                               
rdev->pm.dpm.dyn_state.cac_leakage_table.entries[i].leakage =
+                                       
le32_to_cpu(cac_table->entries[i].ulLeakageValue);
+                       }
+                       rdev->pm.dpm.dyn_state.cac_leakage_table.count = 
cac_table->ucNumEntries;
+               }
+       }
+
+       return 0;
+}
+
+void r600_free_extended_power_table(struct radeon_device *rdev)
+{
+       if (rdev->pm.dpm.dyn_state.vddc_dependency_on_sclk.entries)
+               kfree(rdev->pm.dpm.dyn_state.vddc_dependency_on_sclk.entries);
+       if (rdev->pm.dpm.dyn_state.vddci_dependency_on_mclk.entries)
+               kfree(rdev->pm.dpm.dyn_state.vddci_dependency_on_mclk.entries);
+       if (rdev->pm.dpm.dyn_state.vddc_dependency_on_mclk.entries)
+               kfree(rdev->pm.dpm.dyn_state.vddc_dependency_on_mclk.entries);
+       if (rdev->pm.dpm.dyn_state.cac_leakage_table.entries)
+               kfree(rdev->pm.dpm.dyn_state.cac_leakage_table.entries);
+}
diff --git a/drivers/gpu/drm/radeon/r600_dpm.h 
b/drivers/gpu/drm/radeon/r600_dpm.h
index bd33aa1..c6b9e30 100644
--- a/drivers/gpu/drm/radeon/r600_dpm.h
+++ b/drivers/gpu/drm/radeon/r600_dpm.h
@@ -215,4 +215,7 @@ int r600_set_thermal_temperature_range(struct radeon_device 
*rdev,
                                       int min_temp, int max_temp);
 bool r600_is_internal_thermal_sensor(enum radeon_int_thermal_type sensor);
 
+int r600_parse_extended_power_table(struct radeon_device *rdev);
+void r600_free_extended_power_table(struct radeon_device *rdev);
+
 #endif
diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h
index 3b345cc..5bdb0bd 100644
--- a/drivers/gpu/drm/radeon/radeon.h
+++ b/drivers/gpu/drm/radeon/radeon.h
@@ -1222,6 +1222,66 @@ struct radeon_dpm_thermal {
        bool               high_to_low;
 };
 
+struct radeon_clock_and_voltage_limits {
+       u32 sclk;
+       u32 mclk;
+       u32 vddc;
+       u32 vddci;
+};
+
+struct radeon_clock_array {
+       u32 count;
+       u32 *values;
+};
+
+struct radeon_clock_voltage_dependency_entry {
+       u32 clk;
+       u16 v;
+};
+
+struct radeon_clock_voltage_dependency_table {
+       u32 count;
+       struct radeon_clock_voltage_dependency_entry *entries;
+};
+
+struct radeon_cac_leakage_entry {
+       u16 vddc;
+       u32 leakage;
+};
+
+struct radeon_cac_leakage_table {
+       u32 count;
+       struct radeon_cac_leakage_entry *entries;
+};
+
+struct radeon_dpm_dynamic_state {
+       struct radeon_clock_voltage_dependency_table vddc_dependency_on_sclk;
+       struct radeon_clock_voltage_dependency_table vddci_dependency_on_mclk;
+       struct radeon_clock_voltage_dependency_table vddc_dependency_on_mclk;
+       struct radeon_clock_array valid_sclk_values;
+       struct radeon_clock_array valid_mclk_values;
+       struct radeon_clock_and_voltage_limits max_clock_voltage_on_dc;
+       struct radeon_clock_and_voltage_limits max_clock_voltage_on_ac;
+       u32 mclk_sclk_ratio;
+       u32 sclk_mclk_delta;
+       u16 vddc_vddci_delta;
+       u16 min_vddc_for_pcie_gen2;
+       struct radeon_cac_leakage_table cac_leakage_table;
+};
+
+struct radeon_dpm_fan {
+       u16 t_min;
+       u16 t_med;
+       u16 t_high;
+       u16 pwm_min;
+       u16 pwm_med;
+       u16 pwm_high;
+       u8 t_hyst;
+       u32 cycle_delay;
+       u16 t_max;
+       bool ucode_fan_control;
+};
+
 struct radeon_dpm {
        struct radeon_ps        *ps;
        /* number of valid power states */
@@ -1244,6 +1304,16 @@ struct radeon_dpm {
        int                     new_active_crtc_count;
        u32                     current_active_crtcs;
        int                     current_active_crtc_count;
+       struct radeon_dpm_dynamic_state dyn_state;
+       struct radeon_dpm_fan fan;
+       u32 tdp_limit;
+       u32 near_tdp_limit;
+       u32 sq_ramping_threshold;
+       u32 cac_leakage;
+       u16 tdp_od_limit;
+       u32 tdp_adjustment;
+       u16 load_line_slope;
+       bool power_control;
        /* special states active */
        bool                    thermal_active;
        bool                    uvd_active;
-- 
1.7.7.5

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

Reply via email to