Skip to contentSkip to conversation

drm/radeon/dpm: implement force performance levels for rs780

PATCH In review Anthoine Bourgeois 2 participants 3 messages Jul 31, 2013 – Aug 1, 2013

Subsystems (2)
lore
Share & tools
lore
#0 lore raw

PATCH 1/1 drm/radeon/dpm: implement force performance levels for rs780

Allows you to limit the selected power levels via sysfs.

Force the feedback divider to select a power level.

---

drivers/gpu/drm/radeon/radeon_asic.c |  1 +
drivers/gpu/drm/radeon/radeon_asic.h |  2 ++
drivers/gpu/drm/radeon/rs780_dpm.c   | 67 ++++++++++++++++++++++++++++++------
3 files changed, 59 insertions(+), 11 deletions(-)
drivers/gpu/drm/radeon/radeon_asic.c +0 -0
index f8f8b31..437d357 100644
@@ -1272,6 +1272,7 @@ static struct radeon_asic rs780_asic = {
		.get_mclk = &rs780_dpm_get_mclk,
		.print_power_state = &rs780_dpm_print_power_state,
		.debugfs_print_current_performance_level = &rs780_dpm_debugfs_print_current_performance_level,
+		.force_performance_level = &rs780_dpm_force_performance_level,
	},
	.pflip = {
		.pre_page_flip = &rs600_pre_page_flip,
drivers/gpu/drm/radeon/radeon_asic.h +0 -0
index 902479f..09841fc 100644
@@ -437,6 +437,8 @@ void rs780_dpm_print_power_state(struct radeon_device *rdev,
				 struct radeon_ps *ps);
void rs780_dpm_debugfs_print_current_performance_level(struct radeon_device *rdev,
						       struct seq_file *m);

+int rs780_dpm_force_performance_level(struct radeon_device *rdev,
+ enum radeon_dpm_forced_level level);

/* uvd */
int r600_uvd_init(struct radeon_device *rdev);

drivers/gpu/drm/radeon/rs780_dpm.c +0 -0
index d1a1ce7..df58e34 100644
@@ -404,6 +404,27 @@ static void rs780_force_voltage_to_high(struct radeon_device *rdev)
	WREG32_P(GFX_MACRO_BYPASS_CNTL, 0, ~SPLL_BYPASS_CNTL);
}

+static void rs780_force_fbdiv(struct radeon_device *rdev, u32 fb_div)
+{
+ struct igp_ps *current_state = rs780_get_ps(rdev->pm.dpm.current_ps);
+
+ if ((current_state->sclk_low == fb_div) &&
+ (current_state->sclk_high == fb_div))
+ return;
+
+ WREG32_P(GFX_MACRO_BYPASS_CNTL, SPLL_BYPASS_CNTL, ~SPLL_BYPASS_CNTL);
+
+ WREG32_P(FVTHROT_FBDIV_REG2, FORCED_FEEDBACK_DIV(fb_div),
+ ~FORCED_FEEDBACK_DIV_MASK);
+ WREG32_P(FVTHROT_FBDIV_REG1, STARTING_FEEDBACK_DIV(fb_div),
+ ~STARTING_FEEDBACK_DIV_MASK);
+ WREG32_P(FVTHROT_FBDIV_REG1, FORCE_FEEDBACK_DIV, ~FORCE_FEEDBACK_DIV);
+
+ udelay(100);
+
+ WREG32_P(GFX_MACRO_BYPASS_CNTL, 0, ~SPLL_BYPASS_CNTL);
+}
+
static int rs780_set_engine_clock_scaling(struct radeon_device *rdev,
struct radeon_ps *new_ps,
struct radeon_ps *old_ps)
@@ -432,17 +453,7 @@ static int rs780_set_engine_clock_scaling(struct radeon_device *rdev,

	if (ret)
		return ret;

- WREG32_P(GFX_MACRO_BYPASS_CNTL, SPLL_BYPASS_CNTL, ~SPLL_BYPASS_CNTL);
-
- WREG32_P(FVTHROT_FBDIV_REG2, FORCED_FEEDBACK_DIV(max_dividers.fb_div),
- ~FORCED_FEEDBACK_DIV_MASK);
- WREG32_P(FVTHROT_FBDIV_REG1, STARTING_FEEDBACK_DIV(max_dividers.fb_div),
- ~STARTING_FEEDBACK_DIV_MASK);
- WREG32_P(FVTHROT_FBDIV_REG1, FORCE_FEEDBACK_DIV, ~FORCE_FEEDBACK_DIV);
-
- udelay(100);
-
- WREG32_P(GFX_MACRO_BYPASS_CNTL, 0, ~SPLL_BYPASS_CNTL);
+ rs780_force_fbdiv(rdev, max_dividers.fb_div);

	if (max_dividers.fb_div > min_dividers.fb_div) {
		WREG32_P(FVTHROT_FBDIV_REG0,
@@ -986,3 +997,37 @@ void rs780_dpm_debugfs_print_current_performance_level(struct radeon_device *rde
		seq_printf(m, "power level 1    sclk: %u vddc_index: %d\n",
			   ps->sclk_high, ps->max_voltage);
}

+
+int rs780_dpm_force_performance_level(struct radeon_device *rdev,
+ enum radeon_dpm_forced_level level)
+{
+ struct radeon_ps *rps = rdev->pm.dpm.current_ps;
+ struct igp_ps *ps = rs780_get_ps(rps);
+ struct atom_clock_dividers min_dividers, max_dividers;
+ int ret;
+
+ rs780_clk_scaling_enable(rdev, false);
+
+ if (level == RADEON_DPM_FORCED_LEVEL_HIGH) {
+ ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_ENGINE_PLL_PARAM,
+ ps->sclk_high, false, &max_dividers);
+ if (ret)
+ return ret;
+
+ rs780_force_fbdiv(rdev, max_dividers.fb_div);
+ } else if (level == RADEON_DPM_FORCED_LEVEL_LOW) {
+ ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_ENGINE_PLL_PARAM,
+ ps->sclk_low, false, &min_dividers);
+ if (ret)
+ return ret;
+
+ rs780_force_fbdiv(rdev, min_dividers.fb_div);
+ } else {
+ WREG32_P(FVTHROT_FBDIV_REG1, 0, ~FORCE_FEEDBACK_DIV);
+ rs780_clk_scaling_enable(rdev, true);
+ }
+
+ rdev->pm.dpm.forced_level = level;
+
+ return 0;
+}

Signature · 1 line
1.8.1.5
#1 lore raw
Quoted 9 lines

-----Original Message-----
From: Anthoine Bourgeois [mailto:[email protected]]
Sent: Wednesday, July 31, 2013 6:34 PM
To: Deucher, Alexander; Koenig, Christian; Jerome Glisse; Anthoine Bourgeois
Cc: [email protected]
Subject: [PATCH] drm/radeon/dpm: implement force performance levels for rs780

Quoted 3 lines

Allows you to limit the selected power levels via sysfs.

Force the feedback divider to select a power level.

Nice work. A few comments below.

Alex

Quoted 48 lines
---
 drivers/gpu/drm/radeon/radeon_asic.c |  1 +
 drivers/gpu/drm/radeon/radeon_asic.h |  2 ++
 drivers/gpu/drm/radeon/rs780_dpm.c   | 67
++++++++++++++++++++++++++++++------
 3 files changed, 59 insertions(+), 11 deletions(-)
drivers/gpu/drm/radeon/radeon_asic.c +1 -0
index f8f8b31..437d357 100644
@@ -1272,6 +1272,7 @@ static struct radeon_asic rs780_asic = {
 		.get_mclk = &rs780_dpm_get_mclk,
 		.print_power_state = &rs780_dpm_print_power_state,
 		.debugfs_print_current_performance_level =
 &rs780_dpm_debugfs_print_current_performance_level,
+		.force_performance_level =
 &rs780_dpm_force_performance_level,
 	},
drivers/gpu/drm/radeon/radeon_asic.c +0 -0
 	.pflip = {
 		.pre_page_flip = &rs600_pre_page_flip,
drivers/gpu/drm/radeon/radeon_asic.h +2 -0
index 902479f..09841fc 100644
@@ -437,6 +437,8 @@ void rs780_dpm_print_power_state(struct
 radeon_device *rdev,
 				 struct radeon_ps *ps);
 void rs780_dpm_debugfs_print_current_performance_level(struct
 radeon_device *rdev,
 						       struct seq_file *m);
+int rs780_dpm_force_performance_level(struct radeon_device *rdev,
+				      enum radeon_dpm_forced_level level);
 

/* uvd */
int r600_uvd_init(struct radeon_device *rdev);

drivers/gpu/drm/radeon/rs780_dpm.c +0 -0
index d1a1ce7..df58e34 100644
@@ -404,6 +404,27 @@ static void rs780_force_voltage_to_high(struct
 radeon_device *rdev)
 	WREG32_P(GFX_MACRO_BYPASS_CNTL, 0, ~SPLL_BYPASS_CNTL);

drivers/gpu/drm/radeon/rs780_dpm.c static void rs780_force_voltage_to_high(struct · line 415

Quoted 10 lines
drivers/gpu/drm/radeon/rs780_dpm.c +7 -0
 }
 
+static void rs780_force_fbdiv(struct radeon_device *rdev, u32 fb_div)
+{
+	struct igp_ps *current_state = rs780_get_ps(rdev-
 >pm.dpm.current_ps);
+
+	if ((current_state->sclk_low == fb_div) &&
+	    (current_state->sclk_high == fb_div))
+		return;

I'm not quite sure what you are checking here.

Quoted 48 lines
drivers/gpu/drm/radeon/rs780_dpm.c +4 -0
+
+	WREG32_P(GFX_MACRO_BYPASS_CNTL, SPLL_BYPASS_CNTL,
 ~SPLL_BYPASS_CNTL);
+
+	WREG32_P(FVTHROT_FBDIV_REG2,

FORCED_FEEDBACK_DIV(fb_div),

drivers/gpu/drm/radeon/rs780_dpm.c +2 -0
+		 ~FORCED_FEEDBACK_DIV_MASK);
+	WREG32_P(FVTHROT_FBDIV_REG1,

STARTING_FEEDBACK_DIV(fb_div),

drivers/gpu/drm/radeon/rs780_dpm.c +2 -0
+		 ~STARTING_FEEDBACK_DIV_MASK);
+	WREG32_P(FVTHROT_FBDIV_REG1, FORCE_FEEDBACK_DIV,

~FORCE_FEEDBACK_DIV);

drivers/gpu/drm/radeon/rs780_dpm.c +6 -7
+
+	udelay(100);
+
+	WREG32_P(GFX_MACRO_BYPASS_CNTL, 0, ~SPLL_BYPASS_CNTL);
+}
+
 static int rs780_set_engine_clock_scaling(struct radeon_device *rdev,
 					  struct radeon_ps *new_ps,
 					  struct radeon_ps *old_ps)
@@ -432,17 +453,7 @@ static int rs780_set_engine_clock_scaling(struct
 radeon_device *rdev,
 	if (ret)
 		return ret;
 
-	WREG32_P(GFX_MACRO_BYPASS_CNTL, SPLL_BYPASS_CNTL,
 ~SPLL_BYPASS_CNTL);
-
-	WREG32_P(FVTHROT_FBDIV_REG2,
 FORCED_FEEDBACK_DIV(max_dividers.fb_div),
-		 ~FORCED_FEEDBACK_DIV_MASK);
-	WREG32_P(FVTHROT_FBDIV_REG1,
 STARTING_FEEDBACK_DIV(max_dividers.fb_div),
-		 ~STARTING_FEEDBACK_DIV_MASK);
-	WREG32_P(FVTHROT_FBDIV_REG1, FORCE_FEEDBACK_DIV,

~FORCE_FEEDBACK_DIV);

drivers/gpu/drm/radeon/rs780_dpm.c +1 -4
-
-	udelay(100);
-
-	WREG32_P(GFX_MACRO_BYPASS_CNTL, 0, ~SPLL_BYPASS_CNTL);
+	rs780_force_fbdiv(rdev, max_dividers.fb_div);
 
 	if (max_dividers.fb_div > min_dividers.fb_div) {
 		WREG32_P(FVTHROT_FBDIV_REG0,
@@ -986,3 +997,37 @@ void

rs780_dpm_debugfs_print_current_performance_level(struct radeon_device *rde

drivers/gpu/drm/radeon/rs780_dpm.c

Quoted 10 lines
drivers/gpu/drm/radeon/rs780_dpm.c +7 -0
 		seq_printf(m, "power level 1    sclk: %u vddc_index: %d\n",
 			   ps->sclk_high, ps->max_voltage);
 }
+
+int rs780_dpm_force_performance_level(struct radeon_device *rdev,
+				      enum radeon_dpm_forced_level level)
+{
+	struct radeon_ps *rps = rdev->pm.dpm.current_ps;
+	struct igp_ps *ps = rs780_get_ps(rps);
+	struct atom_clock_dividers min_dividers, max_dividers;

You can drop the separate min and max and just use a single dividers struct. Also, You are only forcing the sclk. It would probably also be a good idea to force the voltage levels.

Quoted 35 lines
drivers/gpu/drm/radeon/rs780_dpm.c +6 -0
+	int ret;
+
+	rs780_clk_scaling_enable(rdev, false);
+
+	if (level == RADEON_DPM_FORCED_LEVEL_HIGH) {
+		ret = radeon_atom_get_clock_dividers(rdev,

COMPUTE_ENGINE_PLL_PARAM,

drivers/gpu/drm/radeon/rs780_dpm.c +1 -0
+						     ps->sclk_high, false,

&max_dividers);

drivers/gpu/drm/radeon/rs780_dpm.c +6 -0
+		if (ret)
+			return ret;
+
+		rs780_force_fbdiv(rdev, max_dividers.fb_div);
+	} else if (level == RADEON_DPM_FORCED_LEVEL_LOW) {
+		ret = radeon_atom_get_clock_dividers(rdev,

COMPUTE_ENGINE_PLL_PARAM,

drivers/gpu/drm/radeon/rs780_dpm.c +1 -0
+						     ps->sclk_low, false,

&min_dividers);

drivers/gpu/drm/radeon/rs780_dpm.c +6 -0
+		if (ret)
+			return ret;
+
+		rs780_force_fbdiv(rdev, min_dividers.fb_div);
+	} else {
+		WREG32_P(FVTHROT_FBDIV_REG1, 0,

~FORCE_FEEDBACK_DIV);

drivers/gpu/drm/radeon/rs780_dpm.c +7 -1
+		rs780_clk_scaling_enable(rdev, true);
+	}
+
+	rdev->pm.dpm.forced_level = level;
+
+	return 0;
+}
--

1.8.1.5

#2 lore raw

2013/8/1 Deucher, Alexander <[email protected]>

Quoted 70 lines
Quoted 9 lines

-----Original Message-----
From: Anthoine Bourgeois [mailto:[email protected]]
Sent: Wednesday, July 31, 2013 6:34 PM
To: Deucher, Alexander; Koenig, Christian; Jerome Glisse; Anthoine Bourgeois
Cc: [email protected]
Subject: [PATCH] drm/radeon/dpm: implement force performance levels for rs780

Quoted 3 lines

Allows you to limit the selected power levels via sysfs.

Force the feedback divider to select a power level.

Nice work. A few comments below.

Alex

Quoted 53 lines
---
 drivers/gpu/drm/radeon/radeon_asic.c |  1 +
 drivers/gpu/drm/radeon/radeon_asic.h |  2 ++
 drivers/gpu/drm/radeon/rs780_dpm.c   | 67
++++++++++++++++++++++++++++++------
 3 files changed, 59 insertions(+), 11 deletions(-)
drivers/gpu/drm/radeon/radeon_asic.c +1 -0
index f8f8b31..437d357 100644
@@ -1272,6 +1272,7 @@ static struct radeon_asic rs780_asic = {
              .get_mclk = &rs780_dpm_get_mclk,
              .print_power_state = &rs780_dpm_print_power_state,
              .debugfs_print_current_performance_level =
 &rs780_dpm_debugfs_print_current_performance_level,
+             .force_performance_level =
 &rs780_dpm_force_performance_level,
      },
      .pflip = {
              .pre_page_flip = &rs600_pre_page_flip,
drivers/gpu/drm/radeon/radeon_asic.h +2 -0
index 902479f..09841fc 100644
@@ -437,6 +437,8 @@ void rs780_dpm_print_power_state(struct
 radeon_device *rdev,
                               struct radeon_ps *ps);
 void rs780_dpm_debugfs_print_current_performance_level(struct
 radeon_device *rdev,
                                                     struct seq_file *m);
+int rs780_dpm_force_performance_level(struct radeon_device *rdev,
+                                   enum radeon_dpm_forced_level level);
 

/* uvd */
int r600_uvd_init(struct radeon_device *rdev);

drivers/gpu/drm/radeon/rs780_dpm.c +3 -0
index d1a1ce7..df58e34 100644
@@ -404,6 +404,27 @@ static void rs780_force_voltage_to_high(struct
 radeon_device *rdev)
      WREG32_P(GFX_MACRO_BYPASS_CNTL, 0, ~SPLL_BYPASS_CNTL);
 }
 
+static void rs780_force_fbdiv(struct radeon_device *rdev, u32 fb_div)
+{
+     struct igp_ps *current_state = rs780_get_ps(rdev-
Quoted 8 lines

drivers/gpu/drm/radeon/rs780_dpm.c static void rs780_force_voltage_to_high(struct · line 415

Quoted 5 lines
drivers/gpu/drm/radeon/rs780_dpm.c +4 -0
 >pm.dpm.current_ps);
+
+     if ((current_state->sclk_low == fb_div) &&
+         (current_state->sclk_high == fb_div))
+             return;

I'm not quite sure what you are checking here.

Oh yes, my mistake, fb_div shouldn't be in that condition. In my memory, I just wanted to check that sclk_low is equal to sclk_high. In that case, no need to force the fbdiv because there are the same.

Quoted 54 lines
Quoted 54 lines
drivers/gpu/drm/radeon/rs780_dpm.c +4 -0
+
+     WREG32_P(GFX_MACRO_BYPASS_CNTL, SPLL_BYPASS_CNTL,
 ~SPLL_BYPASS_CNTL);
+
+     WREG32_P(FVTHROT_FBDIV_REG2,

FORCED_FEEDBACK_DIV(fb_div),

drivers/gpu/drm/radeon/rs780_dpm.c +2 -0
+              ~FORCED_FEEDBACK_DIV_MASK);
+     WREG32_P(FVTHROT_FBDIV_REG1,

STARTING_FEEDBACK_DIV(fb_div),

drivers/gpu/drm/radeon/rs780_dpm.c +2 -0
+              ~STARTING_FEEDBACK_DIV_MASK);
+     WREG32_P(FVTHROT_FBDIV_REG1, FORCE_FEEDBACK_DIV,

~FORCE_FEEDBACK_DIV);

drivers/gpu/drm/radeon/rs780_dpm.c +6 -7
+
+     udelay(100);
+
+     WREG32_P(GFX_MACRO_BYPASS_CNTL, 0, ~SPLL_BYPASS_CNTL);
+}
+
 static int rs780_set_engine_clock_scaling(struct radeon_device *rdev,
                                        struct radeon_ps *new_ps,
                                        struct radeon_ps *old_ps)
@@ -432,17 +453,7 @@ static int rs780_set_engine_clock_scaling(struct
 radeon_device *rdev,
      if (ret)
              return ret;
 
-     WREG32_P(GFX_MACRO_BYPASS_CNTL, SPLL_BYPASS_CNTL,
 ~SPLL_BYPASS_CNTL);
-
-     WREG32_P(FVTHROT_FBDIV_REG2,
 FORCED_FEEDBACK_DIV(max_dividers.fb_div),
-              ~FORCED_FEEDBACK_DIV_MASK);
-     WREG32_P(FVTHROT_FBDIV_REG1,
 STARTING_FEEDBACK_DIV(max_dividers.fb_div),
-              ~STARTING_FEEDBACK_DIV_MASK);
-     WREG32_P(FVTHROT_FBDIV_REG1, FORCE_FEEDBACK_DIV,

~FORCE_FEEDBACK_DIV);

drivers/gpu/drm/radeon/rs780_dpm.c +1 -4
-
-     udelay(100);
-
-     WREG32_P(GFX_MACRO_BYPASS_CNTL, 0, ~SPLL_BYPASS_CNTL);
+     rs780_force_fbdiv(rdev, max_dividers.fb_div);
 
      if (max_dividers.fb_div > min_dividers.fb_div) {
              WREG32_P(FVTHROT_FBDIV_REG0,
@@ -986,3 +997,37 @@ void

rs780_dpm_debugfs_print_current_performance_level(struct radeon_device *rde
seq_printf(m, "power level 1 sclk: %u vddc_index: %d\n",
ps->sclk_high, ps->max_voltage);
}

drivers/gpu/drm/radeon/rs780_dpm.c +2 -0
+
+int rs780_dpm_force_performance_level(struct radeon_device *rdev,
Quoted 8 lines

drivers/gpu/drm/radeon/rs780_dpm.c

Quoted 5 lines
drivers/gpu/drm/radeon/rs780_dpm.c +5 -0
+                                   enum radeon_dpm_forced_level level)
+{
+     struct radeon_ps *rps = rdev->pm.dpm.current_ps;
+     struct igp_ps *ps = rs780_get_ps(rps);
+     struct atom_clock_dividers min_dividers, max_dividers;

You can drop the separate min and max and just use a single dividers struct.

OK.

Quoted 4 lines

Also,
You are only forcing the sclk. It would probably also be a good idea to force the voltage levels.

OK, I'm working on it but I can't test it, my board (RS880) doesn't seem to support the voltage scaling. I'll do my best.

Anthoine

Quoted 28 lines
Quoted 28 lines
drivers/gpu/drm/radeon/rs780_dpm.c +6 -0
+     int ret;
+
+     rs780_clk_scaling_enable(rdev, false);
+
+     if (level == RADEON_DPM_FORCED_LEVEL_HIGH) {
+             ret = radeon_atom_get_clock_dividers(rdev,

COMPUTE_ENGINE_PLL_PARAM,
+ ps->sclk_high, false,
&max_dividers);

drivers/gpu/drm/radeon/rs780_dpm.c +6 -0
+             if (ret)
+                     return ret;
+
+             rs780_force_fbdiv(rdev, max_dividers.fb_div);
+     } else if (level == RADEON_DPM_FORCED_LEVEL_LOW) {
+             ret = radeon_atom_get_clock_dividers(rdev,

COMPUTE_ENGINE_PLL_PARAM,
+ ps->sclk_low, false,
&min_dividers);

drivers/gpu/drm/radeon/rs780_dpm.c +6 -0
+             if (ret)
+                     return ret;
+
+             rs780_force_fbdiv(rdev, min_dividers.fb_div);
+     } else {
+             WREG32_P(FVTHROT_FBDIV_REG1, 0,

~FORCE_FEEDBACK_DIV);

drivers/gpu/drm/radeon/rs780_dpm.c +2 -0
+             rs780_clk_scaling_enable(rdev, true);
+     }
Quoted 11 lines
Quoted 8 lines
drivers/gpu/drm/radeon/rs780_dpm.c +5 -1
+
+     rdev->pm.dpm.forced_level = level;
+
+     return 0;
+}
--

1.8.1.5

_______________________________________________
dri-devel mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/dri-devel