diff mbox

[4/4] radeon: Run engine reclocking during vblank

Message ID 1269284260-12224-4-git-send-email-mjg@redhat.com (mailing list archive)
State New, archived
Headers show

Commit Message

Matthew Garrett March 22, 2010, 6:57 p.m. UTC
None
diff mbox

Patch

diff --git a/drivers/gpu/drm/radeon/r100.c b/drivers/gpu/drm/radeon/r100.c
index 08e22fe..cdd55b2 100644
--- a/drivers/gpu/drm/radeon/r100.c
+++ b/drivers/gpu/drm/radeon/r100.c
@@ -189,11 +189,14 @@  void r100_set_power_state(struct radeon_device *rdev)
 		/* reclocking the engine appears to be ok as long as the engine is idle
 		 * no need for vblank waiting
 		 */
-		if (sclk != rdev->pm.current_sclk) {
-			radeon_set_engine_clock(rdev, sclk);
-			rdev->pm.current_sclk = sclk;
-			DRM_INFO("Setting: e: %d\n", sclk);
-		}
+                if (sclk != rdev->pm.current_sclk) {
+                        if (!rdev->pm.active_crtcs) {
+                                radeon_set_engine_clock(rdev, sclk);
+                                rdev->pm.current_sclk = sclk;
+                        } else {
+                                rdev->pm.new_mclk = sclk;
+                        }
+                }
 
 		/* set memory clock */
 		if (rdev->asic->set_memory_clock && (mclk != rdev->pm.current_mclk)) {
@@ -461,6 +464,7 @@  int r100_irq_process(struct radeon_device *rdev)
 {
 	uint32_t status, msi_rearm;
 	bool queue_hotplug = false;
+	int i = 0;
 
 	/* reset gui idle ack.  the status bit is broken */
 	rdev->irq.gui_idle_acked = false;
@@ -487,24 +491,44 @@  int r100_irq_process(struct radeon_device *rdev)
 		if (status & RADEON_CRTC_VBLANK_STAT) {
 			drm_handle_vblank(rdev->ddev, 0);
 			rdev->pm.vblank_sync = true;
-			if (rdev->pm.new_mclk) {
-				radeon_pm_debug_check_in_vbl(rdev, false);
-				radeon_set_memory_clock(rdev, rdev->pm.new_mclk);
+			if (rdev->pm.new_mclk || rdev->pm.new_sclk) {
+				while (!radeon_pm_debug_check_in_vbl(rdev, false) && i <100) {
+					udelay(1);
+					i++;
+				}
+				if (i==100) {
+					dev_err(rdev->dev, "Failed to sync with vblank\n");
+				} else if (rdev->pm.new_mclk) {
+					radeon_set_memory_clock(rdev, rdev->pm.new_mclk);
+					rdev->pm.current_mclk = rdev->pm.new_mclk;
+				} else if (rdev->pm.new_sclk) {
+					radeon_set_engine_clock(rdev, rdev->pm.new_sclk);
+					rdev->pm.current_sclk = rdev->pm.new_sclk;
+				}
 				radeon_pm_debug_check_in_vbl(rdev, true);
-				rdev->pm.current_mclk = rdev->pm.new_mclk;
-				rdev->pm.new_mclk = 0;
+				rdev->pm.new_mclk = rdev->pm.new_sclk = 0;
 			}
 			wake_up(&rdev->irq.vblank_queue);
 		}
 		if (status & RADEON_CRTC2_VBLANK_STAT) {
 			drm_handle_vblank(rdev->ddev, 1);
 			rdev->pm.vblank_sync = true;
-			if (rdev->pm.new_mclk) {
-				radeon_pm_debug_check_in_vbl(rdev, false);
-				radeon_set_memory_clock(rdev, rdev->pm.new_mclk);
+			if (rdev->pm.new_mclk || rdev->pm.new_sclk) {
+				while (!radeon_pm_debug_check_in_vbl(rdev, false) && i <100) {
+					udelay(1);
+					i++;
+				}
+				if (i==100) {
+					dev_err(rdev->dev, "Failed to sync with vblank\n");
+				} else if (rdev->pm.new_mclk) {
+					radeon_set_memory_clock(rdev, rdev->pm.new_mclk);
+					rdev->pm.current_mclk = rdev->pm.new_mclk;
+				} else if (rdev->pm.new_sclk) {
+					radeon_set_engine_clock(rdev, rdev->pm.new_sclk);
+					rdev->pm.current_sclk = rdev->pm.new_sclk;
+				}
 				radeon_pm_debug_check_in_vbl(rdev, true);
-				rdev->pm.current_mclk = rdev->pm.new_mclk;
-				rdev->pm.new_mclk = 0;
+				rdev->pm.new_mclk = rdev->pm.new_sclk = 0;
 			}
 			wake_up(&rdev->irq.vblank_queue);
 		}
diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c
index a89821b..7bb1163 100644
--- a/drivers/gpu/drm/radeon/r600.c
+++ b/drivers/gpu/drm/radeon/r600.c
@@ -292,9 +292,12 @@  void r600_set_power_state(struct radeon_device *rdev)
 		 * no need for vblank waiting
 		 */
 		if (sclk != rdev->pm.current_sclk) {
-			radeon_set_engine_clock(rdev, sclk);
-			rdev->pm.current_sclk = sclk;
-			DRM_INFO("Setting: e: %d\n", sclk);
+			if (!rdev->pm.active_crtcs) {
+				radeon_set_engine_clock(rdev, sclk);
+				rdev->pm.current_sclk = sclk;
+			} else {
+				rdev->pm.new_mclk = sclk;
+			}
 		}
 
 		/* set memory clock */
@@ -305,10 +308,12 @@  void r600_set_power_state(struct radeon_device *rdev)
 			} else {
 				rdev->pm.new_mclk = mclk;
 			}
-			radeon_sync_with_vblank(rdev);
 			DRM_INFO("Setting: m: %d\n", mclk);
 		}
 
+		if (rdev->pm.new_mclk || rdev->pm.new_sclk)
+			radeon_sync_with_vblank(rdev);
+
 #if 0
 		if (radeon_gui_idle(rdev) &&
 		    (rdev->pm.current_simd_mask != rdev->pm.requested_simd_mask)) {
@@ -2988,6 +2993,7 @@  int r600_irq_process(struct radeon_device *rdev)
 	u32 ring_index, disp_int, disp_int_cont, disp_int_cont2;
 	unsigned long flags;
 	bool queue_hotplug = false;
+	int i = 0;
 
 	DRM_DEBUG("r600_irq_process start: rptr %d, wptr %d\n", rptr, wptr);
 	if (!rdev->ih.enabled)
@@ -3022,12 +3028,22 @@  restart_ih:
 				if (disp_int & LB_D1_VBLANK_INTERRUPT) {
 					drm_handle_vblank(rdev->ddev, 0);
 					rdev->pm.vblank_sync = true;
-					if (rdev->pm.new_mclk) {
-						radeon_pm_debug_check_in_vbl(rdev, false);
-						radeon_set_memory_clock(rdev, rdev->pm.new_mclk);
+					if (rdev->pm.new_mclk || rdev->pm.new_sclk) {
+						while (!radeon_pm_debug_check_in_vbl(rdev, false) && i <100) {
+							udelay(1);
+							i++;
+						}
+						if (i==100) {
+							dev_err(rdev->dev, "Failed to sync with vblank\n");
+						} else if (rdev->pm.new_mclk) {
+							radeon_set_memory_clock(rdev, rdev->pm.new_mclk);
+							rdev->pm.current_mclk = rdev->pm.new_mclk;
+						} else if (rdev->pm.new_sclk) {
+							radeon_set_engine_clock(rdev, rdev->pm.new_sclk);
+							rdev->pm.current_sclk = rdev->pm.new_sclk;
+						}
 						radeon_pm_debug_check_in_vbl(rdev, true);
-						rdev->pm.current_mclk = rdev->pm.new_mclk;
-						rdev->pm.new_mclk = 0;
+						rdev->pm.new_mclk = rdev->pm.new_sclk = 0;
 					}
 					wake_up(&rdev->irq.vblank_queue);
 					disp_int &= ~LB_D1_VBLANK_INTERRUPT;
@@ -3051,12 +3067,22 @@  restart_ih:
 				if (disp_int & LB_D2_VBLANK_INTERRUPT) {
 					drm_handle_vblank(rdev->ddev, 1);
 					rdev->pm.vblank_sync = true;
-					if (rdev->pm.new_mclk) {
-						radeon_pm_debug_check_in_vbl(rdev, false);
-						radeon_set_memory_clock(rdev, rdev->pm.new_mclk);
+					if (rdev->pm.new_mclk || rdev->pm.new_sclk) {
+						while (!radeon_pm_debug_check_in_vbl(rdev, false) && i <100) {
+							udelay(1);
+							i++;
+						}
+						if (i==100) {
+							dev_err(rdev->dev, "Failed to sync with vblank\n");
+						} else if (rdev->pm.new_mclk) {
+							radeon_set_memory_clock(rdev, rdev->pm.new_mclk);
+							rdev->pm.current_mclk = rdev->pm.new_mclk;
+						} else if (rdev->pm.new_sclk) {
+							radeon_set_engine_clock(rdev, rdev->pm.new_sclk);
+							rdev->pm.current_sclk = rdev->pm.new_sclk;
+						}
 						radeon_pm_debug_check_in_vbl(rdev, true);
-						rdev->pm.current_mclk = rdev->pm.new_mclk;
-						rdev->pm.new_mclk = 0;
+						rdev->pm.new_mclk = rdev->pm.new_sclk = 0;
 					}
 					wake_up(&rdev->irq.vblank_queue);
 					disp_int &= ~LB_D2_VBLANK_INTERRUPT;
diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h
index d706974..e3e4afc 100644
--- a/drivers/gpu/drm/radeon/radeon.h
+++ b/drivers/gpu/drm/radeon/radeon.h
@@ -729,6 +729,7 @@  struct radeon_pm {
 	u32                     current_sclk;
 	u32                     current_mclk;
 	u32			new_mclk;
+	u32			new_sclk;
 	u32			*mc_arb_init_values;
 	struct radeon_i2c_chan *i2c_bus;
 	/* r6xx+ only */
diff --git a/drivers/gpu/drm/radeon/radeon_atombios.c b/drivers/gpu/drm/radeon/radeon_atombios.c
index 5b964e2..e68c320 100644
--- a/drivers/gpu/drm/radeon/radeon_atombios.c
+++ b/drivers/gpu/drm/radeon/radeon_atombios.c
@@ -1940,7 +1940,7 @@  void radeon_atom_set_engine_clock(struct radeon_device *rdev,
 
 	args.ulTargetEngineClock = eng_clock;	/* 10 khz */
 
-	atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
+	atom_execute_table_atomic(rdev->mode_info.atom_context, index, (uint32_t *)&args);
 }
 
 void radeon_atom_set_memory_clock(struct radeon_device *rdev,