drm/radeon/kms: add dpm support for evergreen (v4)

This adds dpm support for evergreen asics.  This includes:
- clockgating
- dynamic engine clock scaling
- dynamic memory clock scaling
- dynamic voltage scaling
- dynamic pcie gen1/gen2 switching (requires additional acpi support)

Set radeon.dpm=1 to enable.

v2: reduce stack usage, rename ulv struct
v3: fix thermal interrupt check notices by Jerome
v4: fix state enable

Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
diff --git a/drivers/gpu/drm/radeon/rv770_dpm.c b/drivers/gpu/drm/radeon/rv770_dpm.c
index 232b2fd..d15e715 100644
--- a/drivers/gpu/drm/radeon/rv770_dpm.c
+++ b/drivers/gpu/drm/radeon/rv770_dpm.c
@@ -27,6 +27,7 @@
 #include "rv770d.h"
 #include "r600_dpm.h"
 #include "rv770_dpm.h"
+#include "cypress_dpm.h"
 #include "atom.h"
 
 #define MC_CG_ARB_FREQ_F0           0x0a
@@ -56,6 +57,13 @@
 	return pi;
 }
 
+struct evergreen_power_info *evergreen_get_pi(struct radeon_device *rdev)
+{
+	struct evergreen_power_info *pi = rdev->pm.dpm.priv;
+
+	return pi;
+}
+
 static void rv770_enable_bif_dynamic_pcie_gen2(struct radeon_device *rdev,
 					       bool enable)
 {
@@ -1806,8 +1814,8 @@
 	}
 }
 
-static int rv770_set_thermal_temperature_range(struct radeon_device *rdev,
-					       int min_temp, int max_temp)
+int rv770_set_thermal_temperature_range(struct radeon_device *rdev,
+					int min_temp, int max_temp)
 {
 	int low_temp = 0 * 1000;
 	int high_temp = 255 * 1000;
@@ -2057,6 +2065,7 @@
 					 union pplib_clock_info *clock_info)
 {
 	struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+	struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
 	struct rv7xx_ps *ps = rv770_get_ps(rps);
 	u32 sclk, mclk;
 	u16 vddc;
@@ -2075,13 +2084,24 @@
 		break;
 	}
 
-	sclk = le16_to_cpu(clock_info->r600.usEngineClockLow);
-	sclk |= clock_info->r600.ucEngineClockHigh << 16;
-	mclk = le16_to_cpu(clock_info->r600.usMemoryClockLow);
-	mclk |= clock_info->r600.ucMemoryClockHigh << 16;
+	if (rdev->family >= CHIP_CEDAR) {
+		sclk = le16_to_cpu(clock_info->evergreen.usEngineClockLow);
+		sclk |= clock_info->evergreen.ucEngineClockHigh << 16;
+		mclk = le16_to_cpu(clock_info->evergreen.usMemoryClockLow);
+		mclk |= clock_info->evergreen.ucMemoryClockHigh << 16;
 
-	pl->vddc = le16_to_cpu(clock_info->r600.usVDDC);
-	pl->flags = le32_to_cpu(clock_info->r600.ulFlags);
+		pl->vddc = le16_to_cpu(clock_info->evergreen.usVDDC);
+		pl->vddci = le16_to_cpu(clock_info->evergreen.usVDDCI);
+		pl->flags = le32_to_cpu(clock_info->evergreen.ulFlags);
+	} else {
+		sclk = le16_to_cpu(clock_info->r600.usEngineClockLow);
+		sclk |= clock_info->r600.ucEngineClockHigh << 16;
+		mclk = le16_to_cpu(clock_info->r600.usMemoryClockLow);
+		mclk |= clock_info->r600.ucMemoryClockHigh << 16;
+
+		pl->vddc = le16_to_cpu(clock_info->r600.usVDDC);
+		pl->flags = le32_to_cpu(clock_info->r600.ulFlags);
+	}
 
 	pl->mclk = mclk;
 	pl->sclk = sclk;
@@ -2094,12 +2114,21 @@
 
 	if (rps->class & ATOM_PPLIB_CLASSIFICATION_ACPI) {
 		pi->acpi_vddc = pl->vddc;
+		if (rdev->family >= CHIP_CEDAR)
+			eg_pi->acpi_vddci = pl->vddci;
 		if (ps->low.flags & ATOM_PPLIB_R600_FLAGS_PCIEGEN2)
 			pi->acpi_pcie_gen2 = true;
 		else
 			pi->acpi_pcie_gen2 = false;
 	}
 
+	if (rps->class2 & ATOM_PPLIB_CLASSIFICATION2_ULV) {
+		if (rdev->family >= CHIP_BARTS) {
+			eg_pi->ulv.supported = true;
+			eg_pi->ulv.pl = pl;
+		}
+	}
+
 	if (pi->min_vddc_in_table > pl->vddc)
 		pi->min_vddc_in_table = pl->vddc;