Commit 4a6369e9 authored by Alex Deucher's avatar Alex Deucher
Browse files

drm/radeon/kms: add dpm support for rv6xx (v3)



This adds dpm support for rv6xx asics.  This includes:
- clockgating
- dynamic engine clock scaling
- dynamic memory clock scaling
- dynamic voltage scaling
- dynamic pcie gen1/gen2 switching

Set radeon.dpm=1 to enable.

v2: remove duplicate line
v3: fix thermal interrupt check noticed by Jerome

Signed-off-by: default avatarAlex Deucher <alexander.deucher@amd.com>
Reviewed-by: default avatarChristian König <christian.koenig@amd.com>
parent 9d67006e
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -77,7 +77,7 @@ radeon-y += radeon_device.o radeon_asic.o radeon_kms.o \
	evergreen_hdmi.o radeon_trace_points.o ni.o cayman_blit_shaders.o \
	atombios_encoders.o radeon_semaphore.o radeon_sa.o atombios_i2c.o si.o \
	si_blit_shaders.o radeon_prime.o radeon_uvd.o cik.o cik_blit_shaders.o \
	r600_dpm.o rs780_dpm.o
	r600_dpm.o rs780_dpm.o rv6xx_dpm.o

radeon-$(CONFIG_COMPAT) += radeon_ioc32.o
radeon-$(CONFIG_VGA_SWITCHEROO) += radeon_atpx_handler.o
+27 −0
Original line number Diff line number Diff line
@@ -3998,6 +3998,7 @@ int r600_irq_set(struct radeon_device *rdev)
	u32 hdmi0, hdmi1;
	u32 d1grph = 0, d2grph = 0;
	u32 dma_cntl;
	u32 thermal_int = 0;

	if (!rdev->irq.installed) {
		WARN(1, "Can't enable IRQ/MSI because no handler is installed\n");
@@ -4032,8 +4033,18 @@ int r600_irq_set(struct radeon_device *rdev)
		hdmi0 = RREG32(HDMI0_AUDIO_PACKET_CONTROL) & ~HDMI0_AZ_FORMAT_WTRIG_MASK;
		hdmi1 = RREG32(HDMI1_AUDIO_PACKET_CONTROL) & ~HDMI0_AZ_FORMAT_WTRIG_MASK;
	}

	dma_cntl = RREG32(DMA_CNTL) & ~TRAP_ENABLE;

	if ((rdev->family > CHIP_R600) && (rdev->family < CHIP_RV770)) {
		thermal_int = RREG32(CG_THERMAL_INT) &
			~(THERM_INT_MASK_HIGH | THERM_INT_MASK_LOW);
		if (rdev->irq.dpm_thermal) {
			DRM_DEBUG("dpm thermal\n");
			thermal_int |= THERM_INT_MASK_HIGH | THERM_INT_MASK_LOW;
		}
	}

	if (atomic_read(&rdev->irq.ring_int[RADEON_RING_TYPE_GFX_INDEX])) {
		DRM_DEBUG("r600_irq_set: sw int\n");
		cp_int_cntl |= RB_INT_ENABLE;
@@ -4115,6 +4126,9 @@ int r600_irq_set(struct radeon_device *rdev)
		WREG32(HDMI0_AUDIO_PACKET_CONTROL, hdmi0);
		WREG32(HDMI1_AUDIO_PACKET_CONTROL, hdmi1);
	}
	if ((rdev->family > CHIP_R600) && (rdev->family < CHIP_RV770)) {
		WREG32(CG_THERMAL_INT, thermal_int);
	}

	return 0;
}
@@ -4306,6 +4320,7 @@ int r600_irq_process(struct radeon_device *rdev)
	u32 ring_index;
	bool queue_hotplug = false;
	bool queue_hdmi = false;
	bool queue_thermal = false;

	if (!rdev->ih.enabled || rdev->shutdown)
		return IRQ_NONE;
@@ -4473,6 +4488,16 @@ int r600_irq_process(struct radeon_device *rdev)
			DRM_DEBUG("IH: DMA trap\n");
			radeon_fence_process(rdev, R600_RING_TYPE_DMA_INDEX);
			break;
		case 230: /* thermal low to high */
			DRM_DEBUG("IH: thermal low to high\n");
			rdev->pm.dpm.thermal.high_to_low = false;
			queue_thermal = true;
			break;
		case 231: /* thermal high to low */
			DRM_DEBUG("IH: thermal high to low\n");
			rdev->pm.dpm.thermal.high_to_low = true;
			queue_thermal = true;
			break;
		case 233: /* GUI IDLE */
			DRM_DEBUG("IH: GUI idle\n");
			break;
@@ -4489,6 +4514,8 @@ int r600_irq_process(struct radeon_device *rdev)
		schedule_work(&rdev->hotplug_work);
	if (queue_hdmi)
		schedule_work(&rdev->audio_work);
	if (queue_thermal && rdev->pm.dpm_enabled)
		schedule_work(&rdev->pm.dpm.thermal.work);
	rdev->ih.rptr = rptr;
	WREG32(IH_RB_RPTR, rdev->ih.rptr);
	atomic_set(&rdev->ih.lock, 0);
+45 −0
Original line number Diff line number Diff line
@@ -676,3 +676,48 @@ bool r600_is_uvd_state(u32 class, u32 class2)
		return true;
	return false;
}

int r600_set_thermal_temperature_range(struct radeon_device *rdev,
				       int min_temp, int max_temp)
{
	int low_temp = 0 * 1000;
	int high_temp = 255 * 1000;

	if (low_temp < min_temp)
		low_temp = min_temp;
	if (high_temp > max_temp)
		high_temp = max_temp;
	if (high_temp < low_temp) {
		DRM_ERROR("invalid thermal range: %d - %d\n", low_temp, high_temp);
		return -EINVAL;
	}

	WREG32_P(CG_THERMAL_INT, DIG_THERM_INTH(high_temp / 1000), ~DIG_THERM_INTH_MASK);
	WREG32_P(CG_THERMAL_INT, DIG_THERM_INTL(low_temp / 1000), ~DIG_THERM_INTL_MASK);
	WREG32_P(CG_THERMAL_CTRL, DIG_THERM_DPM(high_temp / 1000), ~DIG_THERM_DPM_MASK);

	rdev->pm.dpm.thermal.min_temp = low_temp;
	rdev->pm.dpm.thermal.max_temp = high_temp;

	return 0;
}

bool r600_is_internal_thermal_sensor(enum radeon_int_thermal_type sensor)
{
	switch (sensor) {
	case THERMAL_TYPE_RV6XX:
	case THERMAL_TYPE_RV770:
	case THERMAL_TYPE_EVERGREEN:
	case THERMAL_TYPE_SUMO:
	case THERMAL_TYPE_NI:
		return true;
	case THERMAL_TYPE_ADT7473_WITH_INTERNAL:
	case THERMAL_TYPE_EMC2103_WITH_INTERNAL:
		return false; /* need special handling */
	case THERMAL_TYPE_NONE:
	case THERMAL_TYPE_EXTERNAL:
	case THERMAL_TYPE_EXTERNAL_GPIO:
	default:
		return false;
	}
}
+8 −0
Original line number Diff line number Diff line
@@ -92,6 +92,10 @@
#define R600_PM_NUMBER_OF_VOLTAGE_LEVELS 4
#define R600_PM_NUMBER_OF_ACTIVITY_LEVELS 3

/* XXX are these ok? */
#define R600_TEMP_RANGE_MIN (90 * 1000)
#define R600_TEMP_RANGE_MAX (120 * 1000)

enum r600_power_level {
	R600_POWER_LEVEL_LOW = 0,
	R600_POWER_LEVEL_MEDIUM = 1,
@@ -207,4 +211,8 @@ void r600_wait_for_power_level(struct radeon_device *rdev,
void r600_start_dpm(struct radeon_device *rdev);
void r600_stop_dpm(struct radeon_device *rdev);

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);

#endif
+13 −0
Original line number Diff line number Diff line
@@ -302,10 +302,23 @@
#define	GRBM_SOFT_RESET					0x8020
#define		SOFT_RESET_CP					(1<<0)

#define	CG_THERMAL_CTRL					0x7F0
#define		DIG_THERM_DPM(x)			((x) << 12)
#define		DIG_THERM_DPM_MASK			0x000FF000
#define		DIG_THERM_DPM_SHIFT			12
#define	CG_THERMAL_STATUS				0x7F4
#define		ASIC_T(x)			        ((x) << 0)
#define		ASIC_T_MASK			        0x1FF
#define		ASIC_T_SHIFT			        0
#define	CG_THERMAL_INT					0x7F8
#define		DIG_THERM_INTH(x)			((x) << 8)
#define		DIG_THERM_INTH_MASK			0x0000FF00
#define		DIG_THERM_INTH_SHIFT			8
#define		DIG_THERM_INTL(x)			((x) << 16)
#define		DIG_THERM_INTL_MASK			0x00FF0000
#define		DIG_THERM_INTL_SHIFT			16
#define 	THERM_INT_MASK_HIGH			(1 << 24)
#define 	THERM_INT_MASK_LOW			(1 << 25)

#define	HDP_HOST_PATH_CNTL				0x2C00
#define	HDP_NONSURFACE_BASE				0x2C04
Loading