diff --git a/drivers/gpu/drm/radeon/ci_dpm.c b/drivers/gpu/drm/radeon/ci_dpm.c index d416bb2..2f66243 100644 --- a/drivers/gpu/drm/radeon/ci_dpm.c +++ b/drivers/gpu/drm/radeon/ci_dpm.c @@ -4582,6 +4582,73 @@ void ci_dpm_post_set_power_state(struct radeon_device *rdev) ci_update_current_ps(rdev, new_ps); } +static ssize_t radeon_get_fan_speed(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + u32 speed, max_speed; + struct drm_device *ddev = dev_get_drvdata(dev); + struct radeon_device *rdev = ddev->dev_private; + + max_speed = RREG32_SMC(FAN_PARAMETERS_INDEX) & FAN_SPEED_MASK; + speed = RREG32_SMC(FAN_SPEED_INDEX) & FAN_SPEED_MASK; + + speed = speed * 100 / max_speed; // get percentage from value + + return snprintf(buf, PAGE_SIZE, "Current fan speed is %i%%\n", speed); +} + +static ssize_t radeon_set_fan_speed(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t count) +{ + u32 speed, max_speed; + u32 tmp; + int ret; + PPSMC_Result smc_result; + struct drm_device *ddev = dev_get_drvdata(dev); + struct radeon_device *rdev = ddev->dev_private; + + if (!ci_is_smc_running(rdev)) + return -EINVAL; + + DRM_INFO("SMC is running, proceeding...\n"); + smc_result = ci_send_msg_to_smc(rdev, PPSMC_MSG_EnableFanControl); + if (smc_result != PPSMC_Result_OK) + ret = -EINVAL; + + ret = kstrtou32(buf, 0, &speed); + if(ret) + return ret; + + if(speed > 100) + return -EINVAL; + + max_speed = RREG32_SMC(FAN_PARAMETERS_INDEX) & FAN_SPEED_MASK; + speed = speed * max_speed / 100; // get real voltage from percentage + + + tmp = RREG32_SMC(FAN_SPEED_INDEX); // get current speed + speed = (tmp & ~FAN_SPEED_MASK) | speed; // replace speed bits (first 8) + + WREG32_SMC(FAN_SPEED_INDEX, speed); + + // XXX: without this line nothing will happen, unknown for now + WREG32_SMC(FAN_MANUAL_OVERRIDE_INDEX, FAN_MANUAL_OVERRIDE_ENABLE); + DRM_INFO("Fan control enabled, proceeding...\n"); + + return count; +} + +static DEVICE_ATTR(power_fan_control, S_IRUGO | S_IWUSR, radeon_get_fan_speed, radeon_set_fan_speed); + +static void ci_dpm_init_files(struct radeon_device *rdev) +{ + int ret = device_create_file(rdev->dev, &dev_attr_power_fan_control); + if (ret) + DRM_ERROR("failed to create device file for fan control\n"); +} void ci_dpm_setup_asic(struct radeon_device *rdev) { @@ -4594,6 +4661,7 @@ void ci_dpm_setup_asic(struct radeon_device *rdev) ci_get_memory_type(rdev); ci_enable_acpi_power_management(rdev); ci_init_sclk_t(rdev); + ci_dpm_init_files(rdev); } int ci_dpm_enable(struct radeon_device *rdev) diff --git a/drivers/gpu/drm/radeon/cikd.h b/drivers/gpu/drm/radeon/cikd.h index 0c6e1b5..2eca6f0 100644 --- a/drivers/gpu/drm/radeon/cikd.h +++ b/drivers/gpu/drm/radeon/cikd.h @@ -52,6 +52,15 @@ # define UvdBootLevel_MASK 0xff000000 # define UvdBootLevel_SHIFT 24 +/* Fan control */ +#define FAN_SPEED_INDEX 0xc0300064 +#define FAN_PARAMETERS_INDEX 0xc0300068 + +#define FAN_MANUAL_OVERRIDE_INDEX 0xc030006c +#define FAN_MANUAL_OVERRIDE_ENABLE 0x50cb0c00 + +#define FAN_SPEED_MASK 0xff + #define FIRMWARE_FLAGS 0x3F800 # define INTERRUPTS_ENABLED (1 << 0) diff --git a/drivers/gpu/drm/radeon/ppsmc.h b/drivers/gpu/drm/radeon/ppsmc.h index 5670b82..53217a6 100644 --- a/drivers/gpu/drm/radeon/ppsmc.h +++ b/drivers/gpu/drm/radeon/ppsmc.h @@ -79,6 +79,7 @@ typedef uint8_t PPSMC_Result; #define PPSMC_MSG_DisableCac ((uint8_t)0x54) #define PPSMC_TDPClampingActive ((uint8_t)0x59) #define PPSMC_TDPClampingInactive ((uint8_t)0x5A) +#define PPSMC_MSG_EnableFanControl ((uint8_t)0x5C) // XXX: find out what's this exactly for #define PPSMC_MSG_NoDisplay ((uint8_t)0x5D) #define PPSMC_MSG_HasDisplay ((uint8_t)0x5E) #define PPSMC_MSG_UVDPowerOFF ((uint8_t)0x60)