aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/radeon/r600.c
diff options
context:
space:
mode:
authorAlex Deucher <alexdeucher@gmail.com>2010-04-22 14:03:55 -0400
committerDave Airlie <airlied@redhat.com>2010-05-18 04:20:58 -0400
commita48b9b4edb8bb87deb13b9f088a595cf71457b69 (patch)
tree2cfe4156f911042a6c3943ee98503d452941dd92 /drivers/gpu/drm/radeon/r600.c
parentbae6b5627387a950a8faf366d6027bd0a7a93078 (diff)
drm/radeon/kms/pm: add asic specific callbacks for getting power state (v2)
This also simplifies the code and enables reclocking with multiple heads active by tracking whether the power states are single or multi-head capable. Eventually, we will want to select a power state based on external factors (AC/DC state, user selection, etc.). (v2) Update for evergreen Signed-off-by: Alex Deucher <alexdeucher@gmail.com> Signed-off-by: Dave Airlie <airlied@redhat.com>
Diffstat (limited to 'drivers/gpu/drm/radeon/r600.c')
-rw-r--r--drivers/gpu/drm/radeon/r600.c217
1 files changed, 191 insertions, 26 deletions
diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c
index c2d1946535ab..cc2797949ee5 100644
--- a/drivers/gpu/drm/radeon/r600.c
+++ b/drivers/gpu/drm/radeon/r600.c
@@ -92,41 +92,206 @@ void r600_gpu_init(struct radeon_device *rdev);
92void r600_fini(struct radeon_device *rdev); 92void r600_fini(struct radeon_device *rdev);
93void r600_irq_disable(struct radeon_device *rdev); 93void r600_irq_disable(struct radeon_device *rdev);
94 94
95void r600_set_power_state(struct radeon_device *rdev) 95void r600_get_power_state(struct radeon_device *rdev,
96 enum radeon_pm_action action)
96{ 97{
97 /* if *_clock_mode are the same, *_power_state are as well */ 98 int i;
98 if (rdev->pm.requested_clock_mode == rdev->pm.current_clock_mode) 99
99 return; 100 rdev->pm.can_upclock = true;
101 rdev->pm.can_downclock = true;
102
103 /* power state array is low to high, default is first */
104 if ((rdev->flags & RADEON_IS_IGP) || (rdev->family == CHIP_R600)) {
105 int min_power_state_index = 0;
106
107 if (rdev->pm.num_power_states > 2)
108 min_power_state_index = 1;
109
110 switch (action) {
111 case PM_ACTION_MINIMUM:
112 rdev->pm.requested_power_state_index = min_power_state_index;
113 rdev->pm.requested_clock_mode_index = 0;
114 rdev->pm.can_downclock = false;
115 break;
116 case PM_ACTION_DOWNCLOCK:
117 if (rdev->pm.current_power_state_index == min_power_state_index) {
118 rdev->pm.requested_power_state_index = rdev->pm.current_power_state_index;
119 rdev->pm.can_downclock = false;
120 } else {
121 if (rdev->pm.active_crtc_count > 1) {
122 for (i = 0; i < rdev->pm.num_power_states; i++) {
123 if (rdev->pm.power_state[i].flags & RADEON_PM_SINGLE_DISPLAY_ONLY)
124 continue;
125 else if (i >= rdev->pm.current_power_state_index) {
126 rdev->pm.requested_power_state_index =
127 rdev->pm.current_power_state_index;
128 break;
129 } else {
130 rdev->pm.requested_power_state_index = i;
131 break;
132 }
133 }
134 } else
135 rdev->pm.requested_power_state_index =
136 rdev->pm.current_power_state_index - 1;
137 }
138 rdev->pm.requested_clock_mode_index = 0;
139 break;
140 case PM_ACTION_UPCLOCK:
141 if (rdev->pm.current_power_state_index == (rdev->pm.num_power_states - 1)) {
142 rdev->pm.requested_power_state_index = rdev->pm.current_power_state_index;
143 rdev->pm.can_upclock = false;
144 } else {
145 if (rdev->pm.active_crtc_count > 1) {
146 for (i = (rdev->pm.num_power_states - 1); i >= 0; i--) {
147 if (rdev->pm.power_state[i].flags & RADEON_PM_SINGLE_DISPLAY_ONLY)
148 continue;
149 else if (i <= rdev->pm.current_power_state_index) {
150 rdev->pm.requested_power_state_index =
151 rdev->pm.current_power_state_index;
152 break;
153 } else {
154 rdev->pm.requested_power_state_index = i;
155 break;
156 }
157 }
158 } else
159 rdev->pm.requested_power_state_index =
160 rdev->pm.current_power_state_index + 1;
161 }
162 rdev->pm.requested_clock_mode_index = 0;
163 break;
164 case PM_ACTION_NONE:
165 default:
166 DRM_ERROR("Requested mode for not defined action\n");
167 return;
168 }
169 } else {
170 /* XXX select a power state based on AC/DC, single/dualhead, etc. */
171 /* for now just select the first power state and switch between clock modes */
172 /* power state array is low to high, default is first (0) */
173 if (rdev->pm.active_crtc_count > 1) {
174 rdev->pm.requested_power_state_index = -1;
175 /* start at 1 as we don't want the default mode */
176 for (i = 1; i < rdev->pm.num_power_states; i++) {
177 if (rdev->pm.power_state[i].flags & RADEON_PM_SINGLE_DISPLAY_ONLY)
178 continue;
179 else if ((rdev->pm.power_state[i].type == POWER_STATE_TYPE_PERFORMANCE) ||
180 (rdev->pm.power_state[i].type == POWER_STATE_TYPE_BATTERY)) {
181 rdev->pm.requested_power_state_index = i;
182 break;
183 }
184 }
185 /* if nothing selected, grab the default state. */
186 if (rdev->pm.requested_power_state_index == -1)
187 rdev->pm.requested_power_state_index = 0;
188 } else
189 rdev->pm.requested_power_state_index = 1;
190
191 switch (action) {
192 case PM_ACTION_MINIMUM:
193 rdev->pm.requested_clock_mode_index = 0;
194 rdev->pm.can_downclock = false;
195 break;
196 case PM_ACTION_DOWNCLOCK:
197 if (rdev->pm.requested_power_state_index == rdev->pm.current_power_state_index) {
198 if (rdev->pm.current_clock_mode_index == 0) {
199 rdev->pm.requested_clock_mode_index = 0;
200 rdev->pm.can_downclock = false;
201 } else
202 rdev->pm.requested_clock_mode_index =
203 rdev->pm.current_clock_mode_index - 1;
204 } else {
205 rdev->pm.requested_clock_mode_index = 0;
206 rdev->pm.can_downclock = false;
207 }
208 break;
209 case PM_ACTION_UPCLOCK:
210 if (rdev->pm.requested_power_state_index == rdev->pm.current_power_state_index) {
211 if (rdev->pm.current_clock_mode_index ==
212 (rdev->pm.power_state[rdev->pm.requested_power_state_index].num_clock_modes - 1)) {
213 rdev->pm.requested_clock_mode_index = rdev->pm.current_clock_mode_index;
214 rdev->pm.can_upclock = false;
215 } else
216 rdev->pm.requested_clock_mode_index =
217 rdev->pm.current_clock_mode_index + 1;
218 } else {
219 rdev->pm.requested_clock_mode_index =
220 rdev->pm.power_state[rdev->pm.requested_power_state_index].num_clock_modes - 1;
221 rdev->pm.can_upclock = false;
222 }
223 break;
224 case PM_ACTION_NONE:
225 default:
226 DRM_ERROR("Requested mode for not defined action\n");
227 return;
228 }
229 }
100 230
101 DRM_INFO("Setting: e: %d m: %d p: %d\n", 231 DRM_INFO("Requested: e: %d m: %d p: %d\n",
102 rdev->pm.requested_clock_mode->sclk, 232 rdev->pm.power_state[rdev->pm.requested_power_state_index].
103 rdev->pm.requested_clock_mode->mclk, 233 clock_info[rdev->pm.requested_clock_mode_index].sclk,
104 rdev->pm.requested_power_state->non_clock_info.pcie_lanes); 234 rdev->pm.power_state[rdev->pm.requested_power_state_index].
235 clock_info[rdev->pm.requested_clock_mode_index].mclk,
236 rdev->pm.power_state[rdev->pm.requested_power_state_index].
237 non_clock_info.pcie_lanes);
238}
105 239
106 /* set pcie lanes */ 240void r600_set_power_state(struct radeon_device *rdev)
107 /* TODO */ 241{
242 u32 sclk, mclk;
108 243
109 /* set voltage */ 244 if ((rdev->pm.requested_clock_mode_index == rdev->pm.current_clock_mode_index) &&
110 /* TODO */ 245 (rdev->pm.requested_power_state_index == rdev->pm.current_power_state_index))
246 return;
111 247
112 /* set engine clock */ 248 if (radeon_gui_idle(rdev)) {
113 radeon_sync_with_vblank(rdev); 249
114 radeon_pm_debug_check_in_vbl(rdev, false); 250 sclk = rdev->pm.power_state[rdev->pm.requested_power_state_index].
115 radeon_set_engine_clock(rdev, rdev->pm.requested_clock_mode->sclk); 251 clock_info[rdev->pm.requested_clock_mode_index].sclk;
116 radeon_pm_debug_check_in_vbl(rdev, true); 252 if (sclk > rdev->clock.default_sclk)
253 sclk = rdev->clock.default_sclk;
254
255 mclk = rdev->pm.power_state[rdev->pm.requested_power_state_index].
256 clock_info[rdev->pm.requested_clock_mode_index].mclk;
257 if (mclk > rdev->clock.default_mclk)
258 mclk = rdev->clock.default_mclk;
259 /* don't change the mclk with multiple crtcs */
260 if (rdev->pm.active_crtc_count > 1)
261 mclk = rdev->clock.default_mclk;
262
263 /* set pcie lanes */
264 /* TODO */
265
266 /* set voltage */
267 /* TODO */
268
269 /* set engine clock */
270 if (sclk != rdev->pm.current_sclk) {
271 radeon_sync_with_vblank(rdev);
272 radeon_pm_debug_check_in_vbl(rdev, false);
273 radeon_set_engine_clock(rdev, sclk);
274 radeon_pm_debug_check_in_vbl(rdev, true);
275 rdev->pm.current_sclk = sclk;
276 DRM_INFO("Setting: e: %d\n", sclk);
277 }
117 278
118#if 0 279#if 0
119 /* set memory clock */ 280 /* set memory clock */
120 if (rdev->asic->set_memory_clock) { 281 if (rdev->asic->set_memory_clock && (mclk != rdev->pm.current_mclk)) {
121 radeon_sync_with_vblank(rdev); 282 radeon_sync_with_vblank(rdev);
122 radeon_pm_debug_check_in_vbl(rdev, false); 283 radeon_pm_debug_check_in_vbl(rdev, false);
123 radeon_set_memory_clock(rdev, rdev->pm.requested_clock_mode->mclk); 284 radeon_set_memory_clock(rdev, mclk);
124 radeon_pm_debug_check_in_vbl(rdev, true); 285 radeon_pm_debug_check_in_vbl(rdev, true);
125 } 286 rdev->pm.current_mclk = mclk;
287 DRM_INFO("Setting: m: %d\n", mclk);
288 }
126#endif 289#endif
127 290
128 rdev->pm.current_power_state = rdev->pm.requested_power_state; 291 rdev->pm.current_power_state_index = rdev->pm.requested_power_state_index;
129 rdev->pm.current_clock_mode = rdev->pm.requested_clock_mode; 292 rdev->pm.current_clock_mode_index = rdev->pm.requested_clock_mode_index;
293 } else
294 DRM_INFO("GUI not idle!!!\n");
130} 295}
131 296
132bool r600_gui_idle(struct radeon_device *rdev) 297bool r600_gui_idle(struct radeon_device *rdev)