drm/radeon/kms: handle special cases for vddc
authorAlex Deucher <alexdeucher@gmail.com>
Thu, 23 Jun 2011 16:19:32 +0000 (12:19 -0400)
committerDave Airlie <airlied@redhat.com>
Fri, 24 Jun 2011 01:11:53 +0000 (11:11 +1000)
A voltage value of 0xff01 requires that the driver
look up the max voltage for the board based using the
atom SetVoltage command table.

Setting the proper voltage should fix stability on
some newer asics.

Signed-off-by: Alex Deucher <alexdeucher@gmail.com>
Signed-off-by: Dave Airlie <airlied@redhat.com>
drivers/gpu/drm/radeon/radeon.h
drivers/gpu/drm/radeon/radeon_atombios.c

index 27f4557..ef0e0e0 100644 (file)
@@ -179,6 +179,7 @@ void radeon_pm_resume(struct radeon_device *rdev);
 void radeon_combios_get_power_modes(struct radeon_device *rdev);
 void radeon_atombios_get_power_modes(struct radeon_device *rdev);
 void radeon_atom_set_voltage(struct radeon_device *rdev, u16 voltage_level, u8 voltage_type);
+int radeon_atom_get_max_vddc(struct radeon_device *rdev, u16 *voltage);
 void rs690_pm_info(struct radeon_device *rdev);
 extern int rv6xx_get_temp(struct radeon_device *rdev);
 extern int rv770_get_temp(struct radeon_device *rdev);
index 1e725d9..bf2b615 100644 (file)
@@ -2320,6 +2320,14 @@ static bool radeon_atombios_parse_pplib_clock_info(struct radeon_device *rdev,
                        le16_to_cpu(clock_info->r600.usVDDC);
        }
 
+       /* patch up vddc if necessary */
+       if (rdev->pm.power_state[state_index].clock_info[mode_index].voltage.voltage == 0xff01) {
+               u16 vddc;
+
+               if (radeon_atom_get_max_vddc(rdev, &vddc) == 0)
+                       rdev->pm.power_state[state_index].clock_info[mode_index].voltage.voltage = vddc;
+       }
+
        if (rdev->flags & RADEON_IS_IGP) {
                /* skip invalid modes */
                if (rdev->pm.power_state[state_index].clock_info[mode_index].sclk == 0)
@@ -2630,7 +2638,35 @@ void radeon_atom_set_voltage(struct radeon_device *rdev, u16 voltage_level, u8 v
        atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
 }
 
+int radeon_atom_get_max_vddc(struct radeon_device *rdev,
+                            u16 *voltage)
+{
+       union set_voltage args;
+       int index = GetIndexIntoMasterTable(COMMAND, SetVoltage);
+       u8 frev, crev;
+
+       if (!atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, &crev))
+               return -EINVAL;
+
+       switch (crev) {
+       case 1:
+               return -EINVAL;
+       case 2:
+               args.v2.ucVoltageType = SET_VOLTAGE_GET_MAX_VOLTAGE;
+               args.v2.ucVoltageMode = 0;
+               args.v2.usVoltageLevel = 0;
+
+               atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
+
+               *voltage = le16_to_cpu(args.v2.usVoltageLevel);
+               break;
+       default:
+               DRM_ERROR("Unknown table version %d, %d\n", frev, crev);
+               return -EINVAL;
+       }
 
+       return 0;
+}
 
 void radeon_atom_initialize_bios_scratch_regs(struct drm_device *dev)
 {