Merge branch 'drm-etnaviv-fixes' of git://git.pengutronix.de/git/lst/linux into drm...
[cascardo/linux.git] / drivers / gpu / drm / amd / amdgpu / ci_dpm.c
index 5ec1f1e..a5c94b4 100644 (file)
@@ -50,7 +50,9 @@
 #include "gmc/gmc_7_1_sh_mask.h"
 
 MODULE_FIRMWARE("radeon/bonaire_smc.bin");
+MODULE_FIRMWARE("radeon/bonaire_k_smc.bin");
 MODULE_FIRMWARE("radeon/hawaii_smc.bin");
+MODULE_FIRMWARE("radeon/hawaii_k_smc.bin");
 
 #define MC_CG_ARB_FREQ_F0           0x0a
 #define MC_CG_ARB_FREQ_F1           0x0b
@@ -84,12 +86,14 @@ static const struct ci_pt_defaults defaults_bonaire_xt =
        { 0x17C, 0x172, 0x180, 0x1BC, 0x1B3, 0x1BD, 0x206, 0x200, 0x203, 0x25D, 0x25A, 0x255, 0x2C3, 0x2C5, 0x2B4 }
 };
 
+#if 0
 static const struct ci_pt_defaults defaults_bonaire_pro =
 {
        1, 0xF, 0xFD, 0x19, 5, 45, 0, 0x65062,
        { 0x8C,  0x23F, 0x244, 0xA6,  0x83,  0x85,  0x86,  0x86,  0x83,  0xDB,  0xDB,  0xDA,  0x67,  0x60,  0x5F  },
        { 0x187, 0x193, 0x193, 0x1C7, 0x1D1, 0x1D1, 0x210, 0x219, 0x219, 0x266, 0x26C, 0x26C, 0x2C9, 0x2CB, 0x2CB }
 };
+#endif
 
 static const struct ci_pt_defaults defaults_saturn_xt =
 {
@@ -98,12 +102,14 @@ static const struct ci_pt_defaults defaults_saturn_xt =
        { 0x187, 0x187, 0x187, 0x1C7, 0x1C7, 0x1C7, 0x210, 0x210, 0x210, 0x266, 0x266, 0x266, 0x2C9, 0x2C9, 0x2C9 }
 };
 
+#if 0
 static const struct ci_pt_defaults defaults_saturn_pro =
 {
        1, 0xF, 0xFD, 0x19, 5, 55, 0, 0x30000,
        { 0x96,  0x21D, 0x23B, 0xA1,  0x85,  0x87,  0x83,  0x84,  0x81,  0xE6,  0xE6,  0xE6,  0x71,  0x6A,  0x6A  },
        { 0x193, 0x19E, 0x19E, 0x1D2, 0x1DC, 0x1DC, 0x21A, 0x223, 0x223, 0x26E, 0x27E, 0x274, 0x2CF, 0x2D2, 0x2D2 }
 };
+#endif
 
 static const struct ci_pt_config_reg didt_config_ci[] =
 {
@@ -736,19 +742,19 @@ static int ci_enable_didt(struct amdgpu_device *adev, bool enable)
 
        if (pi->caps_sq_ramping || pi->caps_db_ramping ||
            pi->caps_td_ramping || pi->caps_tcp_ramping) {
-               gfx_v7_0_enter_rlc_safe_mode(adev);
+               adev->gfx.rlc.funcs->enter_safe_mode(adev);
 
                if (enable) {
                        ret = ci_program_pt_config_registers(adev, didt_config_ci);
                        if (ret) {
-                               gfx_v7_0_exit_rlc_safe_mode(adev);
+                               adev->gfx.rlc.funcs->exit_safe_mode(adev);
                                return ret;
                        }
                }
 
                ci_do_enable_didt(adev, enable);
 
-               gfx_v7_0_exit_rlc_safe_mode(adev);
+               adev->gfx.rlc.funcs->exit_safe_mode(adev);
        }
 
        return 0;
@@ -3030,7 +3036,7 @@ static int ci_populate_single_memory_level(struct amdgpu_device *adev,
 
        if (pi->mclk_stutter_mode_threshold &&
            (memory_clock <= pi->mclk_stutter_mode_threshold) &&
-           (pi->uvd_enabled == false) &&
+           (!pi->uvd_enabled) &&
            (RREG32(mmDPG_PIPE_STUTTER_CONTROL) & DPG_PIPE_STUTTER_CONTROL__STUTTER_ENABLE_MASK) &&
            (adev->pm.dpm.new_active_crtc_count <= 2))
                memory_level->StutterEnable = true;
@@ -3636,6 +3642,10 @@ static int ci_setup_default_dpm_tables(struct amdgpu_device *adev)
 
        ci_setup_default_pcie_tables(adev);
 
+       /* save a copy of the default DPM table */
+       memcpy(&(pi->golden_dpm_table), &(pi->dpm_table),
+                       sizeof(struct ci_dpm_table));
+
        return 0;
 }
 
@@ -5754,13 +5764,22 @@ static int ci_dpm_init_microcode(struct amdgpu_device *adev)
 
        switch (adev->asic_type) {
        case CHIP_BONAIRE:
-               chip_name = "bonaire";
+               if ((adev->pdev->revision == 0x80) ||
+                   (adev->pdev->revision == 0x81) ||
+                   (adev->pdev->device == 0x665f))
+                       chip_name = "bonaire_k";
+               else
+                       chip_name = "bonaire";
                break;
        case CHIP_HAWAII:
-               chip_name = "hawaii";
+               if (adev->pdev->revision == 0x80)
+                       chip_name = "hawaii_k";
+               else
+                       chip_name = "hawaii";
                break;
        case CHIP_KAVERI:
        case CHIP_KABINI:
+       case CHIP_MULLINS:
        default: BUG();
        }
 
@@ -6404,6 +6423,186 @@ static int ci_dpm_set_powergating_state(void *handle,
        return 0;
 }
 
+static int ci_dpm_print_clock_levels(struct amdgpu_device *adev,
+               enum pp_clock_type type, char *buf)
+{
+       struct ci_power_info *pi = ci_get_pi(adev);
+       struct ci_single_dpm_table *sclk_table = &pi->dpm_table.sclk_table;
+       struct ci_single_dpm_table *mclk_table = &pi->dpm_table.mclk_table;
+       struct ci_single_dpm_table *pcie_table = &pi->dpm_table.pcie_speed_table;
+
+       int i, now, size = 0;
+       uint32_t clock, pcie_speed;
+
+       switch (type) {
+       case PP_SCLK:
+               amdgpu_ci_send_msg_to_smc(adev, PPSMC_MSG_API_GetSclkFrequency);
+               clock = RREG32(mmSMC_MSG_ARG_0);
+
+               for (i = 0; i < sclk_table->count; i++) {
+                       if (clock > sclk_table->dpm_levels[i].value)
+                               continue;
+                       break;
+               }
+               now = i;
+
+               for (i = 0; i < sclk_table->count; i++)
+                       size += sprintf(buf + size, "%d: %uMhz %s\n",
+                                       i, sclk_table->dpm_levels[i].value / 100,
+                                       (i == now) ? "*" : "");
+               break;
+       case PP_MCLK:
+               amdgpu_ci_send_msg_to_smc(adev, PPSMC_MSG_API_GetMclkFrequency);
+               clock = RREG32(mmSMC_MSG_ARG_0);
+
+               for (i = 0; i < mclk_table->count; i++) {
+                       if (clock > mclk_table->dpm_levels[i].value)
+                               continue;
+                       break;
+               }
+               now = i;
+
+               for (i = 0; i < mclk_table->count; i++)
+                       size += sprintf(buf + size, "%d: %uMhz %s\n",
+                                       i, mclk_table->dpm_levels[i].value / 100,
+                                       (i == now) ? "*" : "");
+               break;
+       case PP_PCIE:
+               pcie_speed = ci_get_current_pcie_speed(adev);
+               for (i = 0; i < pcie_table->count; i++) {
+                       if (pcie_speed != pcie_table->dpm_levels[i].value)
+                               continue;
+                       break;
+               }
+               now = i;
+
+               for (i = 0; i < pcie_table->count; i++)
+                       size += sprintf(buf + size, "%d: %s %s\n", i,
+                                       (pcie_table->dpm_levels[i].value == 0) ? "2.5GB, x1" :
+                                       (pcie_table->dpm_levels[i].value == 1) ? "5.0GB, x16" :
+                                       (pcie_table->dpm_levels[i].value == 2) ? "8.0GB, x16" : "",
+                                       (i == now) ? "*" : "");
+               break;
+       default:
+               break;
+       }
+
+       return size;
+}
+
+static int ci_dpm_force_clock_level(struct amdgpu_device *adev,
+               enum pp_clock_type type, uint32_t mask)
+{
+       struct ci_power_info *pi = ci_get_pi(adev);
+
+       if (adev->pm.dpm.forced_level
+                       != AMDGPU_DPM_FORCED_LEVEL_MANUAL)
+               return -EINVAL;
+
+       switch (type) {
+       case PP_SCLK:
+               if (!pi->sclk_dpm_key_disabled)
+                       amdgpu_ci_send_msg_to_smc_with_parameter(adev,
+                                       PPSMC_MSG_SCLKDPM_SetEnabledMask,
+                                       pi->dpm_level_enable_mask.sclk_dpm_enable_mask & mask);
+               break;
+
+       case PP_MCLK:
+               if (!pi->mclk_dpm_key_disabled)
+                       amdgpu_ci_send_msg_to_smc_with_parameter(adev,
+                                       PPSMC_MSG_MCLKDPM_SetEnabledMask,
+                                       pi->dpm_level_enable_mask.mclk_dpm_enable_mask & mask);
+               break;
+
+       case PP_PCIE:
+       {
+               uint32_t tmp = mask & pi->dpm_level_enable_mask.pcie_dpm_enable_mask;
+               uint32_t level = 0;
+
+               while (tmp >>= 1)
+                       level++;
+
+               if (!pi->pcie_dpm_key_disabled)
+                       amdgpu_ci_send_msg_to_smc_with_parameter(adev,
+                                       PPSMC_MSG_PCIeDPM_ForceLevel,
+                                       level);
+               break;
+       }
+       default:
+               break;
+       }
+
+       return 0;
+}
+
+static int ci_dpm_get_sclk_od(struct amdgpu_device *adev)
+{
+       struct ci_power_info *pi = ci_get_pi(adev);
+       struct ci_single_dpm_table *sclk_table = &(pi->dpm_table.sclk_table);
+       struct ci_single_dpm_table *golden_sclk_table =
+                       &(pi->golden_dpm_table.sclk_table);
+       int value;
+
+       value = (sclk_table->dpm_levels[sclk_table->count - 1].value -
+                       golden_sclk_table->dpm_levels[golden_sclk_table->count - 1].value) *
+                       100 /
+                       golden_sclk_table->dpm_levels[golden_sclk_table->count - 1].value;
+
+       return value;
+}
+
+static int ci_dpm_set_sclk_od(struct amdgpu_device *adev, uint32_t value)
+{
+       struct ci_power_info *pi = ci_get_pi(adev);
+       struct ci_ps *ps = ci_get_ps(adev->pm.dpm.requested_ps);
+       struct ci_single_dpm_table *golden_sclk_table =
+                       &(pi->golden_dpm_table.sclk_table);
+
+       if (value > 20)
+               value = 20;
+
+       ps->performance_levels[ps->performance_level_count - 1].sclk =
+                       golden_sclk_table->dpm_levels[golden_sclk_table->count - 1].value *
+                       value / 100 +
+                       golden_sclk_table->dpm_levels[golden_sclk_table->count - 1].value;
+
+       return 0;
+}
+
+static int ci_dpm_get_mclk_od(struct amdgpu_device *adev)
+{
+       struct ci_power_info *pi = ci_get_pi(adev);
+       struct ci_single_dpm_table *mclk_table = &(pi->dpm_table.mclk_table);
+       struct ci_single_dpm_table *golden_mclk_table =
+                       &(pi->golden_dpm_table.mclk_table);
+       int value;
+
+       value = (mclk_table->dpm_levels[mclk_table->count - 1].value -
+                       golden_mclk_table->dpm_levels[golden_mclk_table->count - 1].value) *
+                       100 /
+                       golden_mclk_table->dpm_levels[golden_mclk_table->count - 1].value;
+
+       return value;
+}
+
+static int ci_dpm_set_mclk_od(struct amdgpu_device *adev, uint32_t value)
+{
+       struct ci_power_info *pi = ci_get_pi(adev);
+       struct ci_ps *ps = ci_get_ps(adev->pm.dpm.requested_ps);
+       struct ci_single_dpm_table *golden_mclk_table =
+                       &(pi->golden_dpm_table.mclk_table);
+
+       if (value > 20)
+               value = 20;
+
+       ps->performance_levels[ps->performance_level_count - 1].mclk =
+                       golden_mclk_table->dpm_levels[golden_mclk_table->count - 1].value *
+                       value / 100 +
+                       golden_mclk_table->dpm_levels[golden_mclk_table->count - 1].value;
+
+       return 0;
+}
+
 const struct amd_ip_funcs ci_dpm_ip_funcs = {
        .name = "ci_dpm",
        .early_init = ci_dpm_early_init,
@@ -6438,6 +6637,12 @@ static const struct amdgpu_dpm_funcs ci_dpm_funcs = {
        .get_fan_control_mode = &ci_dpm_get_fan_control_mode,
        .set_fan_speed_percent = &ci_dpm_set_fan_speed_percent,
        .get_fan_speed_percent = &ci_dpm_get_fan_speed_percent,
+       .print_clock_levels = ci_dpm_print_clock_levels,
+       .force_clock_level = ci_dpm_force_clock_level,
+       .get_sclk_od = ci_dpm_get_sclk_od,
+       .set_sclk_od = ci_dpm_set_sclk_od,
+       .get_mclk_od = ci_dpm_get_mclk_od,
+       .set_mclk_od = ci_dpm_set_mclk_od,
 };
 
 static void ci_dpm_set_dpm_funcs(struct amdgpu_device *adev)