diff options
author | Sonny Jiang <sonny.jiang@amd.com> | 2015-05-28 15:47:53 -0400 |
---|---|---|
committer | Alex Deucher <alexander.deucher@amd.com> | 2015-06-10 11:54:16 -0400 |
commit | b7a0776949a8f9db835ab652b6fa96b6e7d6972d (patch) | |
tree | ee3b6b1779bf9fd680c496553a591bbaf9a00540 | |
parent | b97aab014c6ba6133df1e26bd20c1ad7f50a5bff (diff) |
drm/amdgpu: enable vce powergating
Enable VCE dpm and powergating. VCE dpm dynamically scales the VCE clocks on
demand.
Signed-off-by: Sonny Jiang <sonny.jiang@amd.com>
Reviewed-by: Alex Deucher <alexander.deucher@amd.com>
Reviewed-by: Christian König <christian.koenig@amd.com>
-rw-r--r-- | drivers/gpu/drm/amd/amdgpu/amdgpu.h | 2 | ||||
-rw-r--r-- | drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c | 26 | ||||
-rw-r--r-- | drivers/gpu/drm/amd/amdgpu/cz_dpm.c | 132 | ||||
-rw-r--r-- | drivers/gpu/drm/amd/amdgpu/vi.c | 2 |
4 files changed, 148 insertions, 14 deletions
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h b/drivers/gpu/drm/amd/amdgpu/amdgpu.h index 37aeed7b454d..22866d1c3d69 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h | |||
@@ -1509,6 +1509,7 @@ struct amdgpu_dpm_funcs { | |||
1509 | int (*force_performance_level)(struct amdgpu_device *adev, enum amdgpu_dpm_forced_level level); | 1509 | int (*force_performance_level)(struct amdgpu_device *adev, enum amdgpu_dpm_forced_level level); |
1510 | bool (*vblank_too_short)(struct amdgpu_device *adev); | 1510 | bool (*vblank_too_short)(struct amdgpu_device *adev); |
1511 | void (*powergate_uvd)(struct amdgpu_device *adev, bool gate); | 1511 | void (*powergate_uvd)(struct amdgpu_device *adev, bool gate); |
1512 | void (*powergate_vce)(struct amdgpu_device *adev, bool gate); | ||
1512 | void (*enable_bapm)(struct amdgpu_device *adev, bool enable); | 1513 | void (*enable_bapm)(struct amdgpu_device *adev, bool enable); |
1513 | void (*set_fan_control_mode)(struct amdgpu_device *adev, u32 mode); | 1514 | void (*set_fan_control_mode)(struct amdgpu_device *adev, u32 mode); |
1514 | u32 (*get_fan_control_mode)(struct amdgpu_device *adev); | 1515 | u32 (*get_fan_control_mode)(struct amdgpu_device *adev); |
@@ -2182,6 +2183,7 @@ static inline void amdgpu_ring_write(struct amdgpu_ring *ring, uint32_t v) | |||
2182 | #define amdgpu_dpm_force_performance_level(adev, l) (adev)->pm.funcs->force_performance_level((adev), (l)) | 2183 | #define amdgpu_dpm_force_performance_level(adev, l) (adev)->pm.funcs->force_performance_level((adev), (l)) |
2183 | #define amdgpu_dpm_vblank_too_short(adev) (adev)->pm.funcs->vblank_too_short((adev)) | 2184 | #define amdgpu_dpm_vblank_too_short(adev) (adev)->pm.funcs->vblank_too_short((adev)) |
2184 | #define amdgpu_dpm_powergate_uvd(adev, g) (adev)->pm.funcs->powergate_uvd((adev), (g)) | 2185 | #define amdgpu_dpm_powergate_uvd(adev, g) (adev)->pm.funcs->powergate_uvd((adev), (g)) |
2186 | #define amdgpu_dpm_powergate_vce(adev, g) (adev)->pm.funcs->powergate_vce((adev), (g)) | ||
2185 | #define amdgpu_dpm_enable_bapm(adev, e) (adev)->pm.funcs->enable_bapm((adev), (e)) | 2187 | #define amdgpu_dpm_enable_bapm(adev, e) (adev)->pm.funcs->enable_bapm((adev), (e)) |
2186 | #define amdgpu_dpm_set_fan_control_mode(adev, m) (adev)->pm.funcs->set_fan_control_mode((adev), (m)) | 2188 | #define amdgpu_dpm_set_fan_control_mode(adev, m) (adev)->pm.funcs->set_fan_control_mode((adev), (m)) |
2187 | #define amdgpu_dpm_get_fan_control_mode(adev) (adev)->pm.funcs->get_fan_control_mode((adev)) | 2189 | #define amdgpu_dpm_get_fan_control_mode(adev) (adev)->pm.funcs->get_fan_control_mode((adev)) |
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c index 605a9e42f943..ed13baa7c976 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c | |||
@@ -656,19 +656,27 @@ void amdgpu_dpm_enable_uvd(struct amdgpu_device *adev, bool enable) | |||
656 | 656 | ||
657 | void amdgpu_dpm_enable_vce(struct amdgpu_device *adev, bool enable) | 657 | void amdgpu_dpm_enable_vce(struct amdgpu_device *adev, bool enable) |
658 | { | 658 | { |
659 | if (enable) { | 659 | if (adev->pm.funcs->powergate_vce) { |
660 | mutex_lock(&adev->pm.mutex); | 660 | mutex_lock(&adev->pm.mutex); |
661 | adev->pm.dpm.vce_active = true; | 661 | /* enable/disable VCE */ |
662 | /* XXX select vce level based on ring/task */ | 662 | amdgpu_dpm_powergate_vce(adev, !enable); |
663 | adev->pm.dpm.vce_level = AMDGPU_VCE_LEVEL_AC_ALL; | 663 | |
664 | mutex_unlock(&adev->pm.mutex); | 664 | mutex_unlock(&adev->pm.mutex); |
665 | } else { | 665 | } else { |
666 | mutex_lock(&adev->pm.mutex); | 666 | if (enable) { |
667 | adev->pm.dpm.vce_active = false; | 667 | mutex_lock(&adev->pm.mutex); |
668 | mutex_unlock(&adev->pm.mutex); | 668 | adev->pm.dpm.vce_active = true; |
669 | } | 669 | /* XXX select vce level based on ring/task */ |
670 | adev->pm.dpm.vce_level = AMDGPU_VCE_LEVEL_AC_ALL; | ||
671 | mutex_unlock(&adev->pm.mutex); | ||
672 | } else { | ||
673 | mutex_lock(&adev->pm.mutex); | ||
674 | adev->pm.dpm.vce_active = false; | ||
675 | mutex_unlock(&adev->pm.mutex); | ||
676 | } | ||
670 | 677 | ||
671 | amdgpu_pm_compute_clocks(adev); | 678 | amdgpu_pm_compute_clocks(adev); |
679 | } | ||
672 | } | 680 | } |
673 | 681 | ||
674 | void amdgpu_pm_print_power_states(struct amdgpu_device *adev) | 682 | void amdgpu_pm_print_power_states(struct amdgpu_device *adev) |
diff --git a/drivers/gpu/drm/amd/amdgpu/cz_dpm.c b/drivers/gpu/drm/amd/amdgpu/cz_dpm.c index 131b4733b112..10a387424ff8 100644 --- a/drivers/gpu/drm/amd/amdgpu/cz_dpm.c +++ b/drivers/gpu/drm/amd/amdgpu/cz_dpm.c | |||
@@ -43,6 +43,7 @@ | |||
43 | #include "gfx_v8_0.h" | 43 | #include "gfx_v8_0.h" |
44 | 44 | ||
45 | static void cz_dpm_powergate_uvd(struct amdgpu_device *adev, bool gate); | 45 | static void cz_dpm_powergate_uvd(struct amdgpu_device *adev, bool gate); |
46 | static void cz_dpm_powergate_vce(struct amdgpu_device *adev, bool gate); | ||
46 | 47 | ||
47 | static struct cz_ps *cz_get_ps(struct amdgpu_ps *rps) | 48 | static struct cz_ps *cz_get_ps(struct amdgpu_ps *rps) |
48 | { | 49 | { |
@@ -558,6 +559,7 @@ static int cz_dpm_late_init(void *handle) | |||
558 | 559 | ||
559 | /* powerdown unused blocks for now */ | 560 | /* powerdown unused blocks for now */ |
560 | cz_dpm_powergate_uvd(adev, true); | 561 | cz_dpm_powergate_uvd(adev, true); |
562 | cz_dpm_powergate_vce(adev, true); | ||
561 | 563 | ||
562 | return 0; | 564 | return 0; |
563 | } | 565 | } |
@@ -826,16 +828,16 @@ static void cz_init_vce_limit(struct amdgpu_device *adev) | |||
826 | return; | 828 | return; |
827 | } | 829 | } |
828 | 830 | ||
829 | pi->vce_dpm.soft_min_clk = 0; | 831 | pi->vce_dpm.soft_min_clk = table->entries[0].ecclk; |
830 | pi->vce_dpm.hard_min_clk = 0; | 832 | pi->vce_dpm.hard_min_clk = table->entries[0].ecclk; |
831 | cz_send_msg_to_smc(adev, PPSMC_MSG_GetMaxEclkLevel); | 833 | cz_send_msg_to_smc(adev, PPSMC_MSG_GetMaxEclkLevel); |
832 | level = cz_get_argument(adev); | 834 | level = cz_get_argument(adev); |
833 | if (level < table->count) | 835 | if (level < table->count) |
834 | clock = table->entries[level].evclk; | 836 | clock = table->entries[level].ecclk; |
835 | else { | 837 | else { |
836 | /* future BIOS would fix this error */ | 838 | /* future BIOS would fix this error */ |
837 | DRM_ERROR("Invalid VCE Voltage Dependency table entry.\n"); | 839 | DRM_ERROR("Invalid VCE Voltage Dependency table entry.\n"); |
838 | clock = table->entries[table->count - 1].evclk; | 840 | clock = table->entries[table->count - 1].ecclk; |
839 | } | 841 | } |
840 | 842 | ||
841 | pi->vce_dpm.soft_max_clk = clock; | 843 | pi->vce_dpm.soft_max_clk = clock; |
@@ -1004,6 +1006,36 @@ static uint32_t cz_get_sclk_level(struct amdgpu_device *adev, | |||
1004 | return i; | 1006 | return i; |
1005 | } | 1007 | } |
1006 | 1008 | ||
1009 | static uint32_t cz_get_eclk_level(struct amdgpu_device *adev, | ||
1010 | uint32_t clock, uint16_t msg) | ||
1011 | { | ||
1012 | int i = 0; | ||
1013 | struct amdgpu_vce_clock_voltage_dependency_table *table = | ||
1014 | &adev->pm.dpm.dyn_state.vce_clock_voltage_dependency_table; | ||
1015 | |||
1016 | if (table->count == 0) | ||
1017 | return 0; | ||
1018 | |||
1019 | switch (msg) { | ||
1020 | case PPSMC_MSG_SetEclkSoftMin: | ||
1021 | case PPSMC_MSG_SetEclkHardMin: | ||
1022 | for (i = 0; i < table->count-1; i++) | ||
1023 | if (clock <= table->entries[i].ecclk) | ||
1024 | break; | ||
1025 | break; | ||
1026 | case PPSMC_MSG_SetEclkSoftMax: | ||
1027 | case PPSMC_MSG_SetEclkHardMax: | ||
1028 | for (i = table->count - 1; i > 0; i--) | ||
1029 | if (clock >= table->entries[i].ecclk) | ||
1030 | break; | ||
1031 | break; | ||
1032 | default: | ||
1033 | break; | ||
1034 | } | ||
1035 | |||
1036 | return i; | ||
1037 | } | ||
1038 | |||
1007 | static int cz_program_bootup_state(struct amdgpu_device *adev) | 1039 | static int cz_program_bootup_state(struct amdgpu_device *adev) |
1008 | { | 1040 | { |
1009 | struct cz_power_info *pi = cz_get_pi(adev); | 1041 | struct cz_power_info *pi = cz_get_pi(adev); |
@@ -1285,6 +1317,7 @@ static int cz_dpm_disable(struct amdgpu_device *adev) | |||
1285 | 1317 | ||
1286 | /* powerup blocks */ | 1318 | /* powerup blocks */ |
1287 | cz_dpm_powergate_uvd(adev, false); | 1319 | cz_dpm_powergate_uvd(adev, false); |
1320 | cz_dpm_powergate_vce(adev, false); | ||
1288 | 1321 | ||
1289 | cz_clear_voting_clients(adev); | 1322 | cz_clear_voting_clients(adev); |
1290 | cz_stop_dpm(adev); | 1323 | cz_stop_dpm(adev); |
@@ -1775,6 +1808,96 @@ static void cz_dpm_powergate_uvd(struct amdgpu_device *adev, bool gate) | |||
1775 | } | 1808 | } |
1776 | } | 1809 | } |
1777 | 1810 | ||
1811 | static int cz_enable_vce_dpm(struct amdgpu_device *adev, bool enable) | ||
1812 | { | ||
1813 | struct cz_power_info *pi = cz_get_pi(adev); | ||
1814 | int ret = 0; | ||
1815 | |||
1816 | if (enable && pi->caps_vce_dpm) { | ||
1817 | pi->dpm_flags |= DPMFlags_VCE_Enabled; | ||
1818 | DRM_DEBUG("VCE DPM Enabled.\n"); | ||
1819 | |||
1820 | ret = cz_send_msg_to_smc_with_parameter(adev, | ||
1821 | PPSMC_MSG_EnableAllSmuFeatures, VCE_DPM_MASK); | ||
1822 | |||
1823 | } else { | ||
1824 | pi->dpm_flags &= ~DPMFlags_VCE_Enabled; | ||
1825 | DRM_DEBUG("VCE DPM Stopped\n"); | ||
1826 | |||
1827 | ret = cz_send_msg_to_smc_with_parameter(adev, | ||
1828 | PPSMC_MSG_DisableAllSmuFeatures, VCE_DPM_MASK); | ||
1829 | } | ||
1830 | |||
1831 | return ret; | ||
1832 | } | ||
1833 | |||
1834 | static int cz_update_vce_dpm(struct amdgpu_device *adev) | ||
1835 | { | ||
1836 | struct cz_power_info *pi = cz_get_pi(adev); | ||
1837 | struct amdgpu_vce_clock_voltage_dependency_table *table = | ||
1838 | &adev->pm.dpm.dyn_state.vce_clock_voltage_dependency_table; | ||
1839 | |||
1840 | /* Stable Pstate is enabled and we need to set the VCE DPM to highest level */ | ||
1841 | if (pi->caps_stable_power_state) { | ||
1842 | pi->vce_dpm.hard_min_clk = table->entries[table->count-1].ecclk; | ||
1843 | |||
1844 | } else { /* non-stable p-state cases. without vce.Arbiter.EcclkHardMin */ | ||
1845 | pi->vce_dpm.hard_min_clk = table->entries[0].ecclk; | ||
1846 | } | ||
1847 | |||
1848 | cz_send_msg_to_smc_with_parameter(adev, | ||
1849 | PPSMC_MSG_SetEclkHardMin, | ||
1850 | cz_get_eclk_level(adev, | ||
1851 | pi->vce_dpm.hard_min_clk, | ||
1852 | PPSMC_MSG_SetEclkHardMin)); | ||
1853 | return 0; | ||
1854 | } | ||
1855 | |||
1856 | static void cz_dpm_powergate_vce(struct amdgpu_device *adev, bool gate) | ||
1857 | { | ||
1858 | struct cz_power_info *pi = cz_get_pi(adev); | ||
1859 | |||
1860 | if (pi->caps_vce_pg) { | ||
1861 | if (pi->vce_power_gated != gate) { | ||
1862 | if (gate) { | ||
1863 | /* disable clockgating so we can properly shut down the block */ | ||
1864 | amdgpu_set_clockgating_state(adev, AMD_IP_BLOCK_TYPE_VCE, | ||
1865 | AMD_CG_STATE_UNGATE); | ||
1866 | /* shutdown the VCE block */ | ||
1867 | amdgpu_set_powergating_state(adev, AMD_IP_BLOCK_TYPE_VCE, | ||
1868 | AMD_PG_STATE_GATE); | ||
1869 | |||
1870 | cz_enable_vce_dpm(adev, false); | ||
1871 | /* TODO: to figure out why vce can't be poweroff. */ | ||
1872 | /* cz_send_msg_to_smc(adev, PPSMC_MSG_VCEPowerOFF); */ | ||
1873 | pi->vce_power_gated = true; | ||
1874 | } else { | ||
1875 | cz_send_msg_to_smc(adev, PPSMC_MSG_VCEPowerON); | ||
1876 | pi->vce_power_gated = false; | ||
1877 | |||
1878 | /* re-init the VCE block */ | ||
1879 | amdgpu_set_powergating_state(adev, AMD_IP_BLOCK_TYPE_VCE, | ||
1880 | AMD_PG_STATE_UNGATE); | ||
1881 | /* enable clockgating. hw will dynamically gate/ungate clocks on the fly */ | ||
1882 | amdgpu_set_clockgating_state(adev, AMD_IP_BLOCK_TYPE_VCE, | ||
1883 | AMD_CG_STATE_GATE); | ||
1884 | |||
1885 | cz_update_vce_dpm(adev); | ||
1886 | cz_enable_vce_dpm(adev, true); | ||
1887 | } | ||
1888 | } else { | ||
1889 | if (! pi->vce_power_gated) { | ||
1890 | cz_update_vce_dpm(adev); | ||
1891 | } | ||
1892 | } | ||
1893 | } else { /*pi->caps_vce_pg*/ | ||
1894 | cz_update_vce_dpm(adev); | ||
1895 | cz_enable_vce_dpm(adev, true); | ||
1896 | } | ||
1897 | |||
1898 | return; | ||
1899 | } | ||
1900 | |||
1778 | const struct amd_ip_funcs cz_dpm_ip_funcs = { | 1901 | const struct amd_ip_funcs cz_dpm_ip_funcs = { |
1779 | .early_init = cz_dpm_early_init, | 1902 | .early_init = cz_dpm_early_init, |
1780 | .late_init = cz_dpm_late_init, | 1903 | .late_init = cz_dpm_late_init, |
@@ -1806,6 +1929,7 @@ static const struct amdgpu_dpm_funcs cz_dpm_funcs = { | |||
1806 | .force_performance_level = cz_dpm_force_dpm_level, | 1929 | .force_performance_level = cz_dpm_force_dpm_level, |
1807 | .vblank_too_short = NULL, | 1930 | .vblank_too_short = NULL, |
1808 | .powergate_uvd = cz_dpm_powergate_uvd, | 1931 | .powergate_uvd = cz_dpm_powergate_uvd, |
1932 | .powergate_vce = cz_dpm_powergate_vce, | ||
1809 | }; | 1933 | }; |
1810 | 1934 | ||
1811 | static void cz_dpm_set_funcs(struct amdgpu_device *adev) | 1935 | static void cz_dpm_set_funcs(struct amdgpu_device *adev) |
diff --git a/drivers/gpu/drm/amd/amdgpu/vi.c b/drivers/gpu/drm/amd/amdgpu/vi.c index b71f41412f91..90fc93c2c1d0 100644 --- a/drivers/gpu/drm/amd/amdgpu/vi.c +++ b/drivers/gpu/drm/amd/amdgpu/vi.c | |||
@@ -1263,7 +1263,7 @@ static int vi_common_early_init(void *handle) | |||
1263 | case CHIP_CARRIZO: | 1263 | case CHIP_CARRIZO: |
1264 | adev->has_uvd = true; | 1264 | adev->has_uvd = true; |
1265 | adev->cg_flags = 0; | 1265 | adev->cg_flags = 0; |
1266 | adev->pg_flags = AMDGPU_PG_SUPPORT_UVD; | 1266 | adev->pg_flags = AMDGPU_PG_SUPPORT_UVD | AMDGPU_PG_SUPPORT_VCE; |
1267 | adev->external_rev_id = adev->rev_id + 0x1; | 1267 | adev->external_rev_id = adev->rev_id + 0x1; |
1268 | if (amdgpu_smc_load_fw && smc_enabled) | 1268 | if (amdgpu_smc_load_fw && smc_enabled) |
1269 | adev->firmware.smu_load = true; | 1269 | adev->firmware.smu_load = true; |