drm/radeon: add radeon_atom_get_clock_dividers helper
authorChristian König <deathsimple@vodafone.de>
Mon, 8 Apr 2013 10:41:31 +0000 (12:41 +0200)
committerAlex Deucher <alexander.deucher@amd.com>
Tue, 9 Apr 2013 14:31:35 +0000 (10:31 -0400)
Signed-off-by: Christian König <christian.koenig@amd.com>
Reviewed-by: Jerome Glisse <jglisse@redhat.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
drivers/gpu/drm/radeon/radeon.h
drivers/gpu/drm/radeon/radeon_atombios.c
drivers/gpu/drm/radeon/radeon_mode.h

index ac614a4..fb1780a 100644 (file)
@@ -206,6 +206,11 @@ void radeon_pm_suspend(struct radeon_device *rdev);
 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);
+int radeon_atom_get_clock_dividers(struct radeon_device *rdev,
+                                  u8 clock_type,
+                                  u32 clock,
+                                  bool strobe_mode,
+                                  struct atom_clock_dividers *dividers);
 void radeon_atom_set_voltage(struct radeon_device *rdev, u16 voltage_level, u8 voltage_type);
 void rs690_pm_info(struct radeon_device *rdev);
 extern int rv6xx_get_temp(struct radeon_device *rdev);
index f22eb57..8c1779c 100644 (file)
@@ -2654,6 +2654,113 @@ void radeon_atombios_get_power_modes(struct radeon_device *rdev)
                rdev->pm.current_vddc = 0;
 }
 
+union get_clock_dividers {
+       struct _COMPUTE_MEMORY_ENGINE_PLL_PARAMETERS v1;
+       struct _COMPUTE_MEMORY_ENGINE_PLL_PARAMETERS_V2 v2;
+       struct _COMPUTE_MEMORY_ENGINE_PLL_PARAMETERS_V3 v3;
+       struct _COMPUTE_MEMORY_ENGINE_PLL_PARAMETERS_V4 v4;
+       struct _COMPUTE_MEMORY_ENGINE_PLL_PARAMETERS_V5 v5;
+};
+
+int radeon_atom_get_clock_dividers(struct radeon_device *rdev,
+                                  u8 clock_type,
+                                  u32 clock,
+                                  bool strobe_mode,
+                                  struct atom_clock_dividers *dividers)
+{
+       union get_clock_dividers args;
+       int index = GetIndexIntoMasterTable(COMMAND, ComputeMemoryEnginePLL);
+       u8 frev, crev;
+
+       memset(&args, 0, sizeof(args));
+       memset(dividers, 0, sizeof(struct atom_clock_dividers));
+
+       if (!atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, &crev))
+               return -EINVAL;
+
+       switch (crev) {
+       case 1:
+               /* r4xx, r5xx */
+               args.v1.ucAction = clock_type;
+               args.v1.ulClock = cpu_to_le32(clock);   /* 10 khz */
+
+               atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
+
+               dividers->post_div = args.v1.ucPostDiv;
+               dividers->fb_div = args.v1.ucFbDiv;
+               dividers->enable_post_div = true;
+               break;
+       case 2:
+       case 3:
+               /* r6xx, r7xx, evergreen, ni */
+               if (rdev->family <= CHIP_RV770) {
+                       args.v2.ucAction = clock_type;
+                       args.v2.ulClock = cpu_to_le32(clock);   /* 10 khz */
+
+                       atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
+
+                       dividers->post_div = args.v2.ucPostDiv;
+                       dividers->fb_div = le16_to_cpu(args.v2.usFbDiv);
+                       dividers->ref_div = args.v2.ucAction;
+                       if (rdev->family == CHIP_RV770) {
+                               dividers->enable_post_div = (le32_to_cpu(args.v2.ulClock) & (1 << 24)) ?
+                                       true : false;
+                               dividers->vco_mode = (le32_to_cpu(args.v2.ulClock) & (1 << 25)) ? 1 : 0;
+                       } else
+                               dividers->enable_post_div = (dividers->fb_div & 1) ? true : false;
+               } else {
+                       if (clock_type == COMPUTE_ENGINE_PLL_PARAM) {
+                               args.v3.ulClock.ulComputeClockFlag = clock_type;
+                               args.v3.ulClock.ulClockFreq = cpu_to_le32(clock);       /* 10 khz */
+
+                               atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
+
+                               dividers->post_div = args.v3.ucPostDiv;
+                               dividers->enable_post_div = (args.v3.ucCntlFlag &
+                                                            ATOM_PLL_CNTL_FLAG_PLL_POST_DIV_EN) ? true : false;
+                               dividers->enable_dithen = (args.v3.ucCntlFlag &
+                                                          ATOM_PLL_CNTL_FLAG_FRACTION_DISABLE) ? false : true;
+                               dividers->fb_div = le16_to_cpu(args.v3.ulFbDiv.usFbDiv);
+                               dividers->frac_fb_div = le16_to_cpu(args.v3.ulFbDiv.usFbDivFrac);
+                               dividers->ref_div = args.v3.ucRefDiv;
+                               dividers->vco_mode = (args.v3.ucCntlFlag &
+                                                     ATOM_PLL_CNTL_FLAG_MPLL_VCO_MODE) ? 1 : 0;
+                       } else {
+                               args.v5.ulClock.ulComputeClockFlag = clock_type;
+                               args.v5.ulClock.ulClockFreq = cpu_to_le32(clock);       /* 10 khz */
+                               if (strobe_mode)
+                                       args.v5.ucInputFlag = ATOM_PLL_INPUT_FLAG_PLL_STROBE_MODE_EN;
+
+                               atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
+
+                               dividers->post_div = args.v5.ucPostDiv;
+                               dividers->enable_post_div = (args.v5.ucCntlFlag &
+                                                            ATOM_PLL_CNTL_FLAG_PLL_POST_DIV_EN) ? true : false;
+                               dividers->enable_dithen = (args.v5.ucCntlFlag &
+                                                          ATOM_PLL_CNTL_FLAG_FRACTION_DISABLE) ? false : true;
+                               dividers->whole_fb_div = le16_to_cpu(args.v5.ulFbDiv.usFbDiv);
+                               dividers->frac_fb_div = le16_to_cpu(args.v5.ulFbDiv.usFbDivFrac);
+                               dividers->ref_div = args.v5.ucRefDiv;
+                               dividers->vco_mode = (args.v5.ucCntlFlag &
+                                                     ATOM_PLL_CNTL_FLAG_MPLL_VCO_MODE) ? 1 : 0;
+                       }
+               }
+               break;
+       case 4:
+               /* fusion */
+               args.v4.ulClock = cpu_to_le32(clock);   /* 10 khz */
+
+               atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
+
+               dividers->post_div = args.v4.ucPostDiv;
+               dividers->real_clock = le32_to_cpu(args.v4.ulClock);
+               break;
+       default:
+               return -EINVAL;
+       }
+       return 0;
+}
+
 void radeon_atom_set_clock_gating(struct radeon_device *rdev, int enable)
 {
        DYNAMIC_CLOCK_GATING_PS_ALLOCATION args;
index 4003f5a..44e579e 100644 (file)
@@ -492,6 +492,29 @@ struct radeon_framebuffer {
 #define ENCODER_MODE_IS_DP(em) (((em) == ATOM_ENCODER_MODE_DP) || \
                                ((em) == ATOM_ENCODER_MODE_DP_MST))
 
+struct atom_clock_dividers {
+       u32 post_div;
+       union {
+               struct {
+#ifdef __BIG_ENDIAN
+                       u32 reserved : 6;
+                       u32 whole_fb_div : 12;
+                       u32 frac_fb_div : 14;
+#else
+                       u32 frac_fb_div : 14;
+                       u32 whole_fb_div : 12;
+                       u32 reserved : 6;
+#endif
+               };
+               u32 fb_div;
+       };
+       u32 ref_div;
+       bool enable_post_div;
+       bool enable_dithen;
+       u32 vco_mode;
+       u32 real_clock;
+};
+
 extern enum radeon_tv_std
 radeon_combios_get_tv_info(struct radeon_device *rdev);
 extern enum radeon_tv_std