aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlex Deucher <alexdeucher@gmail.com>2010-04-24 14:50:23 -0400
committerDave Airlie <airlied@redhat.com>2010-05-18 04:21:14 -0400
commita424816fb37f894a37585cf86dfdd6b8b1dc681f (patch)
tree7129cac19de9c9f5e008669f832ad2e09a3932d1
parent49e02b7306cb7e01965fe5f41ba0f80085142f6e (diff)
drm/radeon/kms/pm: rework power management
Add two new sysfs attributes: - dynpm - power_state Echoing 0/1 to dynpm disables/enables dynamic power management. The driver scales the sclk dynamically based on the number of queued fences. dynpm only scales sclk dynamically in single head mode. Echoing x.y to power_state selects a static power state (x) and clock mode (y). This allows you to statically select a power state and clock mode. Selecting a static clock mode will disable dynpm. Signed-off-by: Alex Deucher <alexdeucher@gmail.com> Signed-off-by: Dave Airlie <airlied@redhat.com>
-rw-r--r--drivers/gpu/drm/radeon/r100.c66
-rw-r--r--drivers/gpu/drm/radeon/r600.c69
-rw-r--r--drivers/gpu/drm/radeon/radeon.h7
-rw-r--r--drivers/gpu/drm/radeon/radeon_asic.h4
-rw-r--r--drivers/gpu/drm/radeon/radeon_pm.c139
5 files changed, 229 insertions, 56 deletions
diff --git a/drivers/gpu/drm/radeon/r100.c b/drivers/gpu/drm/radeon/r100.c
index 2106ac66eb32..7675827c3a8d 100644
--- a/drivers/gpu/drm/radeon/r100.c
+++ b/drivers/gpu/drm/radeon/r100.c
@@ -145,7 +145,7 @@ void r100_get_power_state(struct radeon_device *rdev,
145 pcie_lanes); 145 pcie_lanes);
146} 146}
147 147
148void r100_set_power_state(struct radeon_device *rdev) 148void r100_set_power_state(struct radeon_device *rdev, bool static_switch)
149{ 149{
150 u32 sclk, mclk; 150 u32 sclk, mclk;
151 151
@@ -167,33 +167,51 @@ void r100_set_power_state(struct radeon_device *rdev)
167 if (rdev->pm.active_crtc_count > 1) 167 if (rdev->pm.active_crtc_count > 1)
168 mclk = rdev->clock.default_mclk; 168 mclk = rdev->clock.default_mclk;
169 169
170 /* set pcie lanes */ 170 /* voltage, pcie lanes, etc.*/
171 /* TODO */ 171 radeon_pm_misc(rdev);
172 172
173 /* set voltage */ 173 if (static_switch) {
174 /* TODO */ 174 radeon_pm_prepare(rdev);
175 175 /* set engine clock */
176 /* set engine clock */ 176 if (sclk != rdev->pm.current_sclk) {
177 if (sclk != rdev->pm.current_sclk) { 177 radeon_set_engine_clock(rdev, sclk);
178 radeon_sync_with_vblank(rdev); 178 rdev->pm.current_sclk = sclk;
179 radeon_pm_debug_check_in_vbl(rdev, false); 179 DRM_INFO("Setting: e: %d\n", sclk);
180 radeon_set_engine_clock(rdev, sclk); 180 }
181 radeon_pm_debug_check_in_vbl(rdev, true); 181#if 0
182 rdev->pm.current_sclk = sclk; 182 /* set memory clock */
183 DRM_INFO("Setting: e: %d\n", sclk); 183 if (rdev->asic->set_memory_clock && (mclk != rdev->pm.current_mclk)) {
184 } 184 radeon_set_memory_clock(rdev, mclk);
185 rdev->pm.current_mclk = mclk;
186 DRM_INFO("Setting: m: %d\n", mclk);
187 }
188#endif
189 radeon_pm_finish(rdev);
190 } else {
191 /* set engine clock */
192 if (sclk != rdev->pm.current_sclk) {
193 radeon_sync_with_vblank(rdev);
194 radeon_pm_debug_check_in_vbl(rdev, false);
195 radeon_set_engine_clock(rdev, sclk);
196 radeon_pm_debug_check_in_vbl(rdev, true);
197 rdev->pm.current_sclk = sclk;
198 DRM_INFO("Setting: e: %d\n", sclk);
199 }
185 200
186#if 0 201#if 0
187 /* set memory clock */ 202 /* set memory clock */
188 if (rdev->asic->set_memory_clock && (mclk != rdev->pm.current_mclk)) { 203 if (rdev->asic->set_memory_clock && (mclk != rdev->pm.current_mclk)) {
189 radeon_sync_with_vblank(rdev); 204 radeon_sync_with_vblank(rdev);
190 radeon_pm_debug_check_in_vbl(rdev, false); 205 radeon_pm_debug_check_in_vbl(rdev, false);
191 radeon_set_memory_clock(rdev, mclk); 206 radeon_pm_prepare(rdev);
192 radeon_pm_debug_check_in_vbl(rdev, true); 207 radeon_set_memory_clock(rdev, mclk);
193 rdev->pm.current_mclk = mclk; 208 radeon_pm_finish(rdev);
194 DRM_INFO("Setting: m: %d\n", mclk); 209 radeon_pm_debug_check_in_vbl(rdev, true);
195 } 210 rdev->pm.current_mclk = mclk;
211 DRM_INFO("Setting: m: %d\n", mclk);
212 }
196#endif 213#endif
214 }
197 215
198 rdev->pm.current_power_state_index = rdev->pm.requested_power_state_index; 216 rdev->pm.current_power_state_index = rdev->pm.requested_power_state_index;
199 rdev->pm.current_clock_mode_index = rdev->pm.requested_clock_mode_index; 217 rdev->pm.current_clock_mode_index = rdev->pm.requested_clock_mode_index;
diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c
index 38f75f54019b..469130994064 100644
--- a/drivers/gpu/drm/radeon/r600.c
+++ b/drivers/gpu/drm/radeon/r600.c
@@ -247,7 +247,7 @@ void r600_get_power_state(struct radeon_device *rdev,
247 pcie_lanes); 247 pcie_lanes);
248} 248}
249 249
250void r600_set_power_state(struct radeon_device *rdev) 250void r600_set_power_state(struct radeon_device *rdev, bool static_switch)
251{ 251{
252 u32 sclk, mclk; 252 u32 sclk, mclk;
253 253
@@ -266,37 +266,52 @@ void r600_set_power_state(struct radeon_device *rdev)
266 clock_info[rdev->pm.requested_clock_mode_index].mclk; 266 clock_info[rdev->pm.requested_clock_mode_index].mclk;
267 if (mclk > rdev->clock.default_mclk) 267 if (mclk > rdev->clock.default_mclk)
268 mclk = rdev->clock.default_mclk; 268 mclk = rdev->clock.default_mclk;
269 /* don't change the mclk with multiple crtcs */
270 if (rdev->pm.active_crtc_count > 1)
271 mclk = rdev->clock.default_mclk;
272
273 /* set pcie lanes */
274 /* TODO */
275 269
276 /* set voltage */ 270 /* voltage, pcie lanes, etc.*/
277 /* TODO */ 271 radeon_pm_misc(rdev);
278 272
279 /* set engine clock */ 273 if (static_switch) {
280 if (sclk != rdev->pm.current_sclk) { 274 radeon_pm_prepare(rdev);
281 radeon_sync_with_vblank(rdev); 275 /* set engine clock */
282 radeon_pm_debug_check_in_vbl(rdev, false); 276 if (sclk != rdev->pm.current_sclk) {
283 radeon_set_engine_clock(rdev, sclk); 277 radeon_set_engine_clock(rdev, sclk);
284 radeon_pm_debug_check_in_vbl(rdev, true); 278 rdev->pm.current_sclk = sclk;
285 rdev->pm.current_sclk = sclk; 279 DRM_INFO("Setting: e: %d\n", sclk);
286 DRM_INFO("Setting: e: %d\n", sclk); 280 }
287 } 281#if 0
282 /* set memory clock */
283 if (rdev->asic->set_memory_clock && (mclk != rdev->pm.current_mclk)) {
284 radeon_set_memory_clock(rdev, mclk);
285 rdev->pm.current_mclk = mclk;
286 DRM_INFO("Setting: m: %d\n", mclk);
287 }
288#endif
289 radeon_pm_finish(rdev);
290 } else {
291 /* set engine clock */
292 if (sclk != rdev->pm.current_sclk) {
293 radeon_sync_with_vblank(rdev);
294 radeon_pm_debug_check_in_vbl(rdev, false);
295 radeon_set_engine_clock(rdev, sclk);
296 radeon_pm_debug_check_in_vbl(rdev, true);
297 rdev->pm.current_sclk = sclk;
298 DRM_INFO("Setting: e: %d\n", sclk);
299 }
288 300
289#if 0 301#if 0
290 /* set memory clock */ 302 /* set memory clock */
291 if (rdev->asic->set_memory_clock && (mclk != rdev->pm.current_mclk)) { 303 if (rdev->asic->set_memory_clock && (mclk != rdev->pm.current_mclk)) {
292 radeon_sync_with_vblank(rdev); 304 radeon_sync_with_vblank(rdev);
293 radeon_pm_debug_check_in_vbl(rdev, false); 305 radeon_pm_debug_check_in_vbl(rdev, false);
294 radeon_set_memory_clock(rdev, mclk); 306 radeon_pm_prepare(rdev);
295 radeon_pm_debug_check_in_vbl(rdev, true); 307 radeon_set_memory_clock(rdev, mclk);
296 rdev->pm.current_mclk = mclk; 308 radeon_pm_finish(rdev);
297 DRM_INFO("Setting: m: %d\n", mclk); 309 radeon_pm_debug_check_in_vbl(rdev, true);
298 } 310 rdev->pm.current_mclk = mclk;
311 DRM_INFO("Setting: m: %d\n", mclk);
312 }
299#endif 313#endif
314 }
300 315
301 rdev->pm.current_power_state_index = rdev->pm.requested_power_state_index; 316 rdev->pm.current_power_state_index = rdev->pm.requested_power_state_index;
302 rdev->pm.current_clock_mode_index = rdev->pm.requested_clock_mode_index; 317 rdev->pm.current_clock_mode_index = rdev->pm.requested_clock_mode_index;
diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h
index 16f0ea78ea9d..cdcf5eaf6714 100644
--- a/drivers/gpu/drm/radeon/radeon.h
+++ b/drivers/gpu/drm/radeon/radeon.h
@@ -814,7 +814,7 @@ struct radeon_asic {
814 void (*ioctl_wait_idle)(struct radeon_device *rdev, struct radeon_bo *bo); 814 void (*ioctl_wait_idle)(struct radeon_device *rdev, struct radeon_bo *bo);
815 bool (*gui_idle)(struct radeon_device *rdev); 815 bool (*gui_idle)(struct radeon_device *rdev);
816 void (*get_power_state)(struct radeon_device *rdev, enum radeon_pm_action action); 816 void (*get_power_state)(struct radeon_device *rdev, enum radeon_pm_action action);
817 void (*set_power_state)(struct radeon_device *rdev); 817 void (*set_power_state)(struct radeon_device *rdev, bool static_switch);
818 void (*pm_misc)(struct radeon_device *rdev); 818 void (*pm_misc)(struct radeon_device *rdev);
819 void (*pm_prepare)(struct radeon_device *rdev); 819 void (*pm_prepare)(struct radeon_device *rdev);
820 void (*pm_finish)(struct radeon_device *rdev); 820 void (*pm_finish)(struct radeon_device *rdev);
@@ -1226,7 +1226,10 @@ static inline void radeon_ring_write(struct radeon_device *rdev, uint32_t v)
1226#define radeon_hpd_set_polarity(rdev, hpd) (rdev)->asic->hpd_set_polarity((rdev), (hpd)) 1226#define radeon_hpd_set_polarity(rdev, hpd) (rdev)->asic->hpd_set_polarity((rdev), (hpd))
1227#define radeon_gui_idle(rdev) (rdev)->asic->gui_idle((rdev)) 1227#define radeon_gui_idle(rdev) (rdev)->asic->gui_idle((rdev))
1228#define radeon_get_power_state(rdev, a) (rdev)->asic->get_power_state((rdev), (a)) 1228#define radeon_get_power_state(rdev, a) (rdev)->asic->get_power_state((rdev), (a))
1229#define radeon_set_power_state(rdev) (rdev)->asic->set_power_state((rdev)) 1229#define radeon_set_power_state(rdev, s) (rdev)->asic->set_power_state((rdev), (s))
1230#define radeon_pm_misc(rdev) (rdev)->asic->pm_misc((rdev))
1231#define radeon_pm_prepare(rdev) (rdev)->asic->pm_prepare((rdev))
1232#define radeon_pm_finish(rdev) (rdev)->asic->pm_finish((rdev))
1230 1233
1231/* Common functions */ 1234/* Common functions */
1232/* AGP */ 1235/* AGP */
diff --git a/drivers/gpu/drm/radeon/radeon_asic.h b/drivers/gpu/drm/radeon/radeon_asic.h
index 378db67ba2d8..8a1278629994 100644
--- a/drivers/gpu/drm/radeon/radeon_asic.h
+++ b/drivers/gpu/drm/radeon/radeon_asic.h
@@ -127,7 +127,7 @@ void r100_enable_bm(struct radeon_device *rdev);
127void r100_set_common_regs(struct radeon_device *rdev); 127void r100_set_common_regs(struct radeon_device *rdev);
128void r100_bm_disable(struct radeon_device *rdev); 128void r100_bm_disable(struct radeon_device *rdev);
129extern bool r100_gui_idle(struct radeon_device *rdev); 129extern bool r100_gui_idle(struct radeon_device *rdev);
130extern void r100_set_power_state(struct radeon_device *rdev); 130extern void r100_set_power_state(struct radeon_device *rdev, bool static_switch);
131extern void r100_get_power_state(struct radeon_device *rdev, 131extern void r100_get_power_state(struct radeon_device *rdev,
132 enum radeon_pm_action action); 132 enum radeon_pm_action action);
133extern void r100_pm_misc(struct radeon_device *rdev); 133extern void r100_pm_misc(struct radeon_device *rdev);
@@ -281,7 +281,7 @@ void r600_hpd_set_polarity(struct radeon_device *rdev,
281 enum radeon_hpd_id hpd); 281 enum radeon_hpd_id hpd);
282extern void r600_ioctl_wait_idle(struct radeon_device *rdev, struct radeon_bo *bo); 282extern void r600_ioctl_wait_idle(struct radeon_device *rdev, struct radeon_bo *bo);
283extern bool r600_gui_idle(struct radeon_device *rdev); 283extern bool r600_gui_idle(struct radeon_device *rdev);
284extern void r600_set_power_state(struct radeon_device *rdev); 284extern void r600_set_power_state(struct radeon_device *rdev, bool static_switch);
285extern void r600_get_power_state(struct radeon_device *rdev, 285extern void r600_get_power_state(struct radeon_device *rdev,
286 enum radeon_pm_action action); 286 enum radeon_pm_action action);
287extern void r600_pm_misc(struct radeon_device *rdev); 287extern void r600_pm_misc(struct radeon_device *rdev);
diff --git a/drivers/gpu/drm/radeon/radeon_pm.c b/drivers/gpu/drm/radeon/radeon_pm.c
index 23b79ebce6c1..c703ae326bc3 100644
--- a/drivers/gpu/drm/radeon/radeon_pm.c
+++ b/drivers/gpu/drm/radeon/radeon_pm.c
@@ -34,6 +34,128 @@ static void radeon_pm_set_clocks(struct radeon_device *rdev);
34static void radeon_pm_idle_work_handler(struct work_struct *work); 34static void radeon_pm_idle_work_handler(struct work_struct *work);
35static int radeon_debugfs_pm_init(struct radeon_device *rdev); 35static int radeon_debugfs_pm_init(struct radeon_device *rdev);
36 36
37static void radeon_pm_set_power_mode_static_locked(struct radeon_device *rdev)
38{
39 mutex_lock(&rdev->cp.mutex);
40
41 /* wait for GPU idle */
42 rdev->pm.gui_idle = false;
43 rdev->irq.gui_idle = true;
44 radeon_irq_set(rdev);
45 wait_event_interruptible_timeout(
46 rdev->irq.idle_queue, rdev->pm.gui_idle,
47 msecs_to_jiffies(RADEON_WAIT_IDLE_TIMEOUT));
48 rdev->irq.gui_idle = false;
49 radeon_irq_set(rdev);
50
51 radeon_set_power_state(rdev, true);
52
53 /* update display watermarks based on new power state */
54 radeon_update_bandwidth_info(rdev);
55 if (rdev->pm.active_crtc_count)
56 radeon_bandwidth_update(rdev);
57
58 mutex_unlock(&rdev->cp.mutex);
59}
60
61static ssize_t radeon_get_power_state_static(struct device *dev,
62 struct device_attribute *attr,
63 char *buf)
64{
65 struct drm_device *ddev = pci_get_drvdata(to_pci_dev(dev));
66 struct radeon_device *rdev = ddev->dev_private;
67
68 return snprintf(buf, PAGE_SIZE, "%d.%d\n", rdev->pm.current_power_state_index,
69 rdev->pm.current_clock_mode_index);
70}
71
72static ssize_t radeon_set_power_state_static(struct device *dev,
73 struct device_attribute *attr,
74 const char *buf,
75 size_t count)
76{
77 struct drm_device *ddev = pci_get_drvdata(to_pci_dev(dev));
78 struct radeon_device *rdev = ddev->dev_private;
79 int ps, cm;
80
81 if (sscanf(buf, "%u.%u", &ps, &cm) != 2) {
82 DRM_ERROR("Invalid power state!\n");
83 return count;
84 }
85
86 mutex_lock(&rdev->pm.mutex);
87 if ((ps >= 0) && (ps < rdev->pm.num_power_states) &&
88 (cm >= 0) && (cm < rdev->pm.power_state[ps].num_clock_modes)) {
89 if ((rdev->pm.active_crtc_count > 1) &&
90 (rdev->pm.power_state[ps].flags & RADEON_PM_SINGLE_DISPLAY_ONLY)) {
91 DRM_ERROR("Invalid power state for multi-head: %d.%d\n", ps, cm);
92 } else {
93 /* disable dynpm */
94 rdev->pm.state = PM_STATE_DISABLED;
95 rdev->pm.planned_action = PM_ACTION_NONE;
96 rdev->pm.requested_power_state_index = ps;
97 rdev->pm.requested_clock_mode_index = cm;
98 radeon_pm_set_power_mode_static_locked(rdev);
99 }
100 } else
101 DRM_ERROR("Invalid power state: %d.%d\n\n", ps, cm);
102 mutex_unlock(&rdev->pm.mutex);
103
104 return count;
105}
106
107static ssize_t radeon_get_dynpm(struct device *dev,
108 struct device_attribute *attr,
109 char *buf)
110{
111 struct drm_device *ddev = pci_get_drvdata(to_pci_dev(dev));
112 struct radeon_device *rdev = ddev->dev_private;
113
114 return snprintf(buf, PAGE_SIZE, "%s\n",
115 (rdev->pm.state == PM_STATE_DISABLED) ? "disabled" : "enabled");
116}
117
118static ssize_t radeon_set_dynpm(struct device *dev,
119 struct device_attribute *attr,
120 const char *buf,
121 size_t count)
122{
123 struct drm_device *ddev = pci_get_drvdata(to_pci_dev(dev));
124 struct radeon_device *rdev = ddev->dev_private;
125 int tmp = simple_strtoul(buf, NULL, 10);
126
127 if (tmp == 0) {
128 /* update power mode info */
129 radeon_pm_compute_clocks(rdev);
130 /* disable dynpm */
131 mutex_lock(&rdev->pm.mutex);
132 rdev->pm.state = PM_STATE_DISABLED;
133 rdev->pm.planned_action = PM_ACTION_NONE;
134 mutex_unlock(&rdev->pm.mutex);
135 DRM_INFO("radeon: dynamic power management disabled\n");
136 } else if (tmp == 1) {
137 if (rdev->pm.num_power_states > 1) {
138 /* enable dynpm */
139 mutex_lock(&rdev->pm.mutex);
140 rdev->pm.state = PM_STATE_PAUSED;
141 rdev->pm.planned_action = PM_ACTION_DEFAULT;
142 radeon_get_power_state(rdev, rdev->pm.planned_action);
143 mutex_unlock(&rdev->pm.mutex);
144 /* update power mode info */
145 radeon_pm_compute_clocks(rdev);
146 DRM_INFO("radeon: dynamic power management enabled\n");
147 } else
148 DRM_ERROR("dynpm not valid on this system\n");
149 } else
150 DRM_ERROR("Invalid setting: %d\n", tmp);
151
152 return count;
153}
154
155static DEVICE_ATTR(power_state, S_IRUGO | S_IWUSR, radeon_get_power_state_static, radeon_set_power_state_static);
156static DEVICE_ATTR(dynpm, S_IRUGO | S_IWUSR, radeon_get_dynpm, radeon_set_dynpm);
157
158
37static const char *pm_state_names[4] = { 159static const char *pm_state_names[4] = {
38 "PM_STATE_DISABLED", 160 "PM_STATE_DISABLED",
39 "PM_STATE_MINIMUM", 161 "PM_STATE_MINIMUM",
@@ -111,6 +233,10 @@ int radeon_pm_init(struct radeon_device *rdev)
111 DRM_ERROR("Failed to register debugfs file for PM!\n"); 233 DRM_ERROR("Failed to register debugfs file for PM!\n");
112 } 234 }
113 235
236 /* where's the best place to put this? */
237 device_create_file(rdev->dev, &dev_attr_power_state);
238 device_create_file(rdev->dev, &dev_attr_dynpm);
239
114 INIT_DELAYED_WORK(&rdev->pm.idle_work, radeon_pm_idle_work_handler); 240 INIT_DELAYED_WORK(&rdev->pm.idle_work, radeon_pm_idle_work_handler);
115 241
116 if ((radeon_dynpm != -1 && radeon_dynpm) && (rdev->pm.num_power_states > 1)) { 242 if ((radeon_dynpm != -1 && radeon_dynpm) && (rdev->pm.num_power_states > 1)) {
@@ -132,8 +258,19 @@ void radeon_pm_fini(struct radeon_device *rdev)
132 rdev->pm.state = PM_STATE_DISABLED; 258 rdev->pm.state = PM_STATE_DISABLED;
133 rdev->pm.planned_action = PM_ACTION_DEFAULT; 259 rdev->pm.planned_action = PM_ACTION_DEFAULT;
134 radeon_pm_set_clocks(rdev); 260 radeon_pm_set_clocks(rdev);
261 } else if ((rdev->pm.current_power_state_index !=
262 rdev->pm.default_power_state_index) ||
263 (rdev->pm.current_clock_mode_index != 0)) {
264 rdev->pm.requested_power_state_index = rdev->pm.default_power_state_index;
265 rdev->pm.requested_clock_mode_index = 0;
266 mutex_lock(&rdev->pm.mutex);
267 radeon_pm_set_power_mode_static_locked(rdev);
268 mutex_unlock(&rdev->pm.mutex);
135 } 269 }
136 270
271 device_remove_file(rdev->dev, &dev_attr_power_state);
272 device_remove_file(rdev->dev, &dev_attr_dynpm);
273
137 if (rdev->pm.i2c_bus) 274 if (rdev->pm.i2c_bus)
138 radeon_i2c_destroy(rdev->pm.i2c_bus); 275 radeon_i2c_destroy(rdev->pm.i2c_bus);
139} 276}
@@ -267,7 +404,7 @@ static void radeon_pm_set_clocks_locked(struct radeon_device *rdev)
267{ 404{
268 /*radeon_fence_wait_last(rdev);*/ 405 /*radeon_fence_wait_last(rdev);*/
269 406
270 radeon_set_power_state(rdev); 407 radeon_set_power_state(rdev, false);
271 rdev->pm.planned_action = PM_ACTION_NONE; 408 rdev->pm.planned_action = PM_ACTION_NONE;
272} 409}
273 410