blob: 6f575ec2dfdb7f0b33f6d91ba946db837bb5e259 [file] [log] [blame]
Jeremy Gebbenb7bc9552012-01-09 13:32:49 -07001/* Copyright (c) 2010-2012, Code Aurora Forum. All rights reserved.
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 */
13#include <linux/interrupt.h>
14#include <mach/msm_iomap.h>
15#include <mach/msm_bus.h>
16
17#include "kgsl.h"
18#include "kgsl_pwrscale.h"
19#include "kgsl_device.h"
Jeremy Gebbenb50f3312011-12-16 08:58:33 -070020#include "kgsl_trace.h"
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070021
Jeremy Gebbenb46f4152011-10-14 14:27:00 -060022#define KGSL_PWRFLAGS_POWER_ON 0
23#define KGSL_PWRFLAGS_CLK_ON 1
24#define KGSL_PWRFLAGS_AXI_ON 2
25#define KGSL_PWRFLAGS_IRQ_ON 3
26
Lucille Sylvester10297892012-02-27 13:54:47 -070027#define GPU_SWFI_LATENCY 3
Suman Tatiraju7fe62a32011-07-14 16:40:37 -070028#define UPDATE_BUSY_VAL 1000000
29#define UPDATE_BUSY 50
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070030
Lucille Sylvesterdce84cd2011-10-12 14:15:37 -060031struct clk_pair {
32 const char *name;
33 uint map;
34};
35
36struct clk_pair clks[KGSL_MAX_CLKS] = {
37 {
38 .name = "src_clk",
39 .map = KGSL_CLK_SRC,
40 },
41 {
42 .name = "core_clk",
43 .map = KGSL_CLK_CORE,
44 },
45 {
46 .name = "iface_clk",
47 .map = KGSL_CLK_IFACE,
48 },
49 {
50 .name = "mem_clk",
51 .map = KGSL_CLK_MEM,
52 },
53 {
54 .name = "mem_iface_clk",
55 .map = KGSL_CLK_MEM_IFACE,
56 },
57};
58
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070059void kgsl_pwrctrl_pwrlevel_change(struct kgsl_device *device,
60 unsigned int new_level)
61{
62 struct kgsl_pwrctrl *pwr = &device->pwrctrl;
63 if (new_level < (pwr->num_pwrlevels - 1) &&
64 new_level >= pwr->thermal_pwrlevel &&
65 new_level != pwr->active_pwrlevel) {
Jeremy Gebbenb50f3312011-12-16 08:58:33 -070066 struct kgsl_pwrlevel *pwrlevel = &pwr->pwrlevels[new_level];
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070067 pwr->active_pwrlevel = new_level;
Lucille Sylvestercd42c822011-09-08 17:37:26 -060068 if ((test_bit(KGSL_PWRFLAGS_CLK_ON, &pwr->power_flags)) ||
Kedar Joshic11d0982012-02-07 10:59:49 +053069 (device->state == KGSL_STATE_NAP)) {
70 /*
71 * On some platforms, instability is caused on
72 * changing clock freq when the core is busy.
73 * Idle the gpu core before changing the clock freq.
74 */
75 if (pwr->idle_needed == true)
76 device->ftbl->idle(device,
77 KGSL_TIMEOUT_DEFAULT);
Jeremy Gebbenb50f3312011-12-16 08:58:33 -070078 clk_set_rate(pwr->grp_clks[0], pwrlevel->gpu_freq);
Kedar Joshic11d0982012-02-07 10:59:49 +053079 }
Lucille Sylvester622927a2011-08-10 14:42:25 -060080 if (test_bit(KGSL_PWRFLAGS_AXI_ON, &pwr->power_flags)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070081 if (pwr->pcl)
82 msm_bus_scale_client_update_request(pwr->pcl,
Jeremy Gebbenb50f3312011-12-16 08:58:33 -070083 pwrlevel->bus_freq);
Lucille Sylvester622927a2011-08-10 14:42:25 -060084 else if (pwr->ebi1_clk)
Jeremy Gebbenb50f3312011-12-16 08:58:33 -070085 clk_set_rate(pwr->ebi1_clk, pwrlevel->bus_freq);
Lucille Sylvester622927a2011-08-10 14:42:25 -060086 }
Jeremy Gebbenb50f3312011-12-16 08:58:33 -070087 trace_kgsl_pwrlevel(device, pwr->active_pwrlevel,
88 pwrlevel->gpu_freq);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070089 }
90}
91EXPORT_SYMBOL(kgsl_pwrctrl_pwrlevel_change);
92
93static int __gpuclk_store(int max, struct device *dev,
94 struct device_attribute *attr,
95 const char *buf, size_t count)
96{ int ret, i, delta = 5000000;
97 unsigned long val;
98 struct kgsl_device *device = kgsl_device_from_dev(dev);
Jordan Crouse6c2992a2011-08-08 17:00:06 -060099 struct kgsl_pwrctrl *pwr;
100
101 if (device == NULL)
102 return 0;
103 pwr = &device->pwrctrl;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700104
105 ret = sscanf(buf, "%ld", &val);
106 if (ret != 1)
107 return count;
108
109 mutex_lock(&device->mutex);
110 for (i = 0; i < pwr->num_pwrlevels; i++) {
111 if (abs(pwr->pwrlevels[i].gpu_freq - val) < delta) {
112 if (max)
113 pwr->thermal_pwrlevel = i;
114 break;
115 }
116 }
117
118 if (i == pwr->num_pwrlevels)
119 goto done;
120
121 /*
122 * If the current or requested clock speed is greater than the
123 * thermal limit, bump down immediately.
124 */
125
126 if (pwr->pwrlevels[pwr->active_pwrlevel].gpu_freq >
127 pwr->pwrlevels[pwr->thermal_pwrlevel].gpu_freq)
128 kgsl_pwrctrl_pwrlevel_change(device, pwr->thermal_pwrlevel);
129 else if (!max)
130 kgsl_pwrctrl_pwrlevel_change(device, i);
131
132done:
133 mutex_unlock(&device->mutex);
134 return count;
135}
136
137static int kgsl_pwrctrl_max_gpuclk_store(struct device *dev,
138 struct device_attribute *attr,
139 const char *buf, size_t count)
140{
141 return __gpuclk_store(1, dev, attr, buf, count);
142}
143
144static int kgsl_pwrctrl_max_gpuclk_show(struct device *dev,
145 struct device_attribute *attr,
146 char *buf)
147{
148 struct kgsl_device *device = kgsl_device_from_dev(dev);
Jordan Crouse6c2992a2011-08-08 17:00:06 -0600149 struct kgsl_pwrctrl *pwr;
150 if (device == NULL)
151 return 0;
152 pwr = &device->pwrctrl;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700153 return snprintf(buf, PAGE_SIZE, "%d\n",
154 pwr->pwrlevels[pwr->thermal_pwrlevel].gpu_freq);
155}
156
157static int kgsl_pwrctrl_gpuclk_store(struct device *dev,
158 struct device_attribute *attr,
159 const char *buf, size_t count)
160{
161 return __gpuclk_store(0, dev, attr, buf, count);
162}
163
164static int kgsl_pwrctrl_gpuclk_show(struct device *dev,
165 struct device_attribute *attr,
166 char *buf)
167{
168 struct kgsl_device *device = kgsl_device_from_dev(dev);
Jordan Crouse6c2992a2011-08-08 17:00:06 -0600169 struct kgsl_pwrctrl *pwr;
170 if (device == NULL)
171 return 0;
172 pwr = &device->pwrctrl;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700173 return snprintf(buf, PAGE_SIZE, "%d\n",
174 pwr->pwrlevels[pwr->active_pwrlevel].gpu_freq);
175}
176
177static int kgsl_pwrctrl_pwrnap_store(struct device *dev,
178 struct device_attribute *attr,
179 const char *buf, size_t count)
180{
181 char temp[20];
182 unsigned long val;
183 struct kgsl_device *device = kgsl_device_from_dev(dev);
Jordan Crouse6c2992a2011-08-08 17:00:06 -0600184 struct kgsl_pwrctrl *pwr;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700185 int rc;
186
Jordan Crouse6c2992a2011-08-08 17:00:06 -0600187 if (device == NULL)
188 return 0;
189 pwr = &device->pwrctrl;
190
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700191 snprintf(temp, sizeof(temp), "%.*s",
192 (int)min(count, sizeof(temp) - 1), buf);
193 rc = strict_strtoul(temp, 0, &val);
194 if (rc)
195 return rc;
196
197 mutex_lock(&device->mutex);
198
199 if (val == 1)
200 pwr->nap_allowed = true;
201 else if (val == 0)
202 pwr->nap_allowed = false;
203
204 mutex_unlock(&device->mutex);
205
206 return count;
207}
208
209static int kgsl_pwrctrl_pwrnap_show(struct device *dev,
210 struct device_attribute *attr,
211 char *buf)
212{
213 struct kgsl_device *device = kgsl_device_from_dev(dev);
Jordan Crouse6c2992a2011-08-08 17:00:06 -0600214 if (device == NULL)
215 return 0;
216 return snprintf(buf, PAGE_SIZE, "%d\n", device->pwrctrl.nap_allowed);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700217}
218
219
220static int kgsl_pwrctrl_idle_timer_store(struct device *dev,
221 struct device_attribute *attr,
222 const char *buf, size_t count)
223{
224 char temp[20];
225 unsigned long val;
226 struct kgsl_device *device = kgsl_device_from_dev(dev);
Jordan Crouse6c2992a2011-08-08 17:00:06 -0600227 struct kgsl_pwrctrl *pwr;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700228 const long div = 1000/HZ;
229 static unsigned int org_interval_timeout = 1;
230 int rc;
231
Jordan Crouse6c2992a2011-08-08 17:00:06 -0600232 if (device == NULL)
233 return 0;
234 pwr = &device->pwrctrl;
235
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700236 snprintf(temp, sizeof(temp), "%.*s",
237 (int)min(count, sizeof(temp) - 1), buf);
238 rc = strict_strtoul(temp, 0, &val);
239 if (rc)
240 return rc;
241
242 if (org_interval_timeout == 1)
243 org_interval_timeout = pwr->interval_timeout;
244
245 mutex_lock(&device->mutex);
246
247 /* Let the timeout be requested in ms, but convert to jiffies. */
248 val /= div;
249 if (val >= org_interval_timeout)
250 pwr->interval_timeout = val;
251
252 mutex_unlock(&device->mutex);
253
254 return count;
255}
256
257static int kgsl_pwrctrl_idle_timer_show(struct device *dev,
258 struct device_attribute *attr,
259 char *buf)
260{
261 struct kgsl_device *device = kgsl_device_from_dev(dev);
Jordan Crouse6c2992a2011-08-08 17:00:06 -0600262 if (device == NULL)
263 return 0;
264 return snprintf(buf, PAGE_SIZE, "%d\n",
265 device->pwrctrl.interval_timeout);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700266}
267
Suman Tatiraju7fe62a32011-07-14 16:40:37 -0700268static int kgsl_pwrctrl_gpubusy_show(struct device *dev,
269 struct device_attribute *attr,
270 char *buf)
271{
272 int ret;
273 struct kgsl_device *device = kgsl_device_from_dev(dev);
274 struct kgsl_busy *b = &device->pwrctrl.busy;
275 ret = snprintf(buf, 17, "%7d %7d\n",
276 b->on_time_old, b->time_old);
277 if (!test_bit(KGSL_PWRFLAGS_AXI_ON, &device->pwrctrl.power_flags)) {
278 b->on_time_old = 0;
279 b->time_old = 0;
280 }
281 return ret;
282}
283
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700284DEVICE_ATTR(gpuclk, 0644, kgsl_pwrctrl_gpuclk_show, kgsl_pwrctrl_gpuclk_store);
285DEVICE_ATTR(max_gpuclk, 0644, kgsl_pwrctrl_max_gpuclk_show,
286 kgsl_pwrctrl_max_gpuclk_store);
Praveena Pachipulusu263467d2011-12-22 18:07:16 +0530287DEVICE_ATTR(pwrnap, 0664, kgsl_pwrctrl_pwrnap_show, kgsl_pwrctrl_pwrnap_store);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700288DEVICE_ATTR(idle_timer, 0644, kgsl_pwrctrl_idle_timer_show,
289 kgsl_pwrctrl_idle_timer_store);
Suman Tatiraju7fe62a32011-07-14 16:40:37 -0700290DEVICE_ATTR(gpubusy, 0644, kgsl_pwrctrl_gpubusy_show,
291 NULL);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700292
293static const struct device_attribute *pwrctrl_attr_list[] = {
294 &dev_attr_gpuclk,
295 &dev_attr_max_gpuclk,
296 &dev_attr_pwrnap,
297 &dev_attr_idle_timer,
Suman Tatiraju7fe62a32011-07-14 16:40:37 -0700298 &dev_attr_gpubusy,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700299 NULL
300};
301
302int kgsl_pwrctrl_init_sysfs(struct kgsl_device *device)
303{
304 return kgsl_create_device_sysfs_files(device->dev, pwrctrl_attr_list);
305}
306
307void kgsl_pwrctrl_uninit_sysfs(struct kgsl_device *device)
308{
309 kgsl_remove_device_sysfs_files(device->dev, pwrctrl_attr_list);
310}
311
Suman Tatiraju7fe62a32011-07-14 16:40:37 -0700312/* Track the amount of time the gpu is on vs the total system time. *
313 * Regularly update the percentage of busy time displayed by sysfs. */
314static void kgsl_pwrctrl_busy_time(struct kgsl_device *device, bool on_time)
315{
316 struct kgsl_busy *b = &device->pwrctrl.busy;
317 int elapsed;
318 if (b->start.tv_sec == 0)
319 do_gettimeofday(&(b->start));
320 do_gettimeofday(&(b->stop));
321 elapsed = (b->stop.tv_sec - b->start.tv_sec) * 1000000;
322 elapsed += b->stop.tv_usec - b->start.tv_usec;
323 b->time += elapsed;
324 if (on_time)
325 b->on_time += elapsed;
326 /* Update the output regularly and reset the counters. */
327 if ((b->time > UPDATE_BUSY_VAL) ||
328 !test_bit(KGSL_PWRFLAGS_AXI_ON, &device->pwrctrl.power_flags)) {
329 b->on_time_old = b->on_time;
330 b->time_old = b->time;
331 b->on_time = 0;
332 b->time = 0;
333 }
334 do_gettimeofday(&(b->start));
335}
336
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700337void kgsl_pwrctrl_clk(struct kgsl_device *device, int state)
338{
339 struct kgsl_pwrctrl *pwr = &device->pwrctrl;
340 int i = 0;
341 if (state == KGSL_PWRFLAGS_OFF) {
342 if (test_and_clear_bit(KGSL_PWRFLAGS_CLK_ON,
343 &pwr->power_flags)) {
Jeremy Gebbenb50f3312011-12-16 08:58:33 -0700344 trace_kgsl_clk(device, state);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700345 for (i = KGSL_MAX_CLKS - 1; i > 0; i--)
346 if (pwr->grp_clks[i])
347 clk_disable(pwr->grp_clks[i]);
348 if ((pwr->pwrlevels[0].gpu_freq > 0) &&
349 (device->requested_state != KGSL_STATE_NAP))
350 clk_set_rate(pwr->grp_clks[0],
351 pwr->pwrlevels[pwr->num_pwrlevels - 1].
352 gpu_freq);
Suman Tatiraju7fe62a32011-07-14 16:40:37 -0700353 kgsl_pwrctrl_busy_time(device, true);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700354 }
355 } else if (state == KGSL_PWRFLAGS_ON) {
356 if (!test_and_set_bit(KGSL_PWRFLAGS_CLK_ON,
357 &pwr->power_flags)) {
Jeremy Gebbenb50f3312011-12-16 08:58:33 -0700358 trace_kgsl_clk(device, state);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700359 if ((pwr->pwrlevels[0].gpu_freq > 0) &&
360 (device->state != KGSL_STATE_NAP))
361 clk_set_rate(pwr->grp_clks[0],
362 pwr->pwrlevels[pwr->active_pwrlevel].
363 gpu_freq);
364
365 /* as last step, enable grp_clk
366 this is to let GPU interrupt to come */
367 for (i = KGSL_MAX_CLKS - 1; i > 0; i--)
368 if (pwr->grp_clks[i])
369 clk_enable(pwr->grp_clks[i]);
Suman Tatiraju7fe62a32011-07-14 16:40:37 -0700370 kgsl_pwrctrl_busy_time(device, false);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700371 }
372 }
373}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700374
375void kgsl_pwrctrl_axi(struct kgsl_device *device, int state)
376{
377 struct kgsl_pwrctrl *pwr = &device->pwrctrl;
378
379 if (state == KGSL_PWRFLAGS_OFF) {
380 if (test_and_clear_bit(KGSL_PWRFLAGS_AXI_ON,
381 &pwr->power_flags)) {
Jeremy Gebbenb50f3312011-12-16 08:58:33 -0700382 trace_kgsl_bus(device, state);
Lynus Vaz5a641cc2011-09-15 14:43:40 +0530383 if (pwr->ebi1_clk) {
384 clk_set_rate(pwr->ebi1_clk, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700385 clk_disable(pwr->ebi1_clk);
Lynus Vaz5a641cc2011-09-15 14:43:40 +0530386 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700387 if (pwr->pcl)
388 msm_bus_scale_client_update_request(pwr->pcl,
389 0);
390 }
391 } else if (state == KGSL_PWRFLAGS_ON) {
392 if (!test_and_set_bit(KGSL_PWRFLAGS_AXI_ON,
393 &pwr->power_flags)) {
Jeremy Gebbenb50f3312011-12-16 08:58:33 -0700394 trace_kgsl_bus(device, state);
Lynus Vaz5a641cc2011-09-15 14:43:40 +0530395 if (pwr->ebi1_clk) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700396 clk_enable(pwr->ebi1_clk);
Lynus Vaz5a641cc2011-09-15 14:43:40 +0530397 clk_set_rate(pwr->ebi1_clk,
398 pwr->pwrlevels[pwr->active_pwrlevel].
399 bus_freq);
400 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700401 if (pwr->pcl)
402 msm_bus_scale_client_update_request(pwr->pcl,
403 pwr->pwrlevels[pwr->active_pwrlevel].
404 bus_freq);
405 }
406 }
407}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700408
409void kgsl_pwrctrl_pwrrail(struct kgsl_device *device, int state)
410{
411 struct kgsl_pwrctrl *pwr = &device->pwrctrl;
412
413 if (state == KGSL_PWRFLAGS_OFF) {
414 if (test_and_clear_bit(KGSL_PWRFLAGS_POWER_ON,
415 &pwr->power_flags)) {
Jeremy Gebbenb50f3312011-12-16 08:58:33 -0700416 trace_kgsl_rail(device, state);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700417 if (pwr->gpu_reg)
418 regulator_disable(pwr->gpu_reg);
419 }
420 } else if (state == KGSL_PWRFLAGS_ON) {
421 if (!test_and_set_bit(KGSL_PWRFLAGS_POWER_ON,
422 &pwr->power_flags)) {
Jeremy Gebbenb50f3312011-12-16 08:58:33 -0700423 trace_kgsl_rail(device, state);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700424 if (pwr->gpu_reg)
425 regulator_enable(pwr->gpu_reg);
426 }
427 }
428}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700429
430void kgsl_pwrctrl_irq(struct kgsl_device *device, int state)
431{
432 struct kgsl_pwrctrl *pwr = &device->pwrctrl;
433
434 if (state == KGSL_PWRFLAGS_ON) {
435 if (!test_and_set_bit(KGSL_PWRFLAGS_IRQ_ON,
436 &pwr->power_flags)) {
Jeremy Gebbenb50f3312011-12-16 08:58:33 -0700437 trace_kgsl_irq(device, state);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700438 enable_irq(pwr->interrupt_num);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700439 }
440 } else if (state == KGSL_PWRFLAGS_OFF) {
441 if (test_and_clear_bit(KGSL_PWRFLAGS_IRQ_ON,
442 &pwr->power_flags)) {
Jeremy Gebbenb50f3312011-12-16 08:58:33 -0700443 trace_kgsl_irq(device, state);
Jordan Crouseb58e61b2011-08-08 13:25:36 -0600444 if (in_interrupt())
445 disable_irq_nosync(pwr->interrupt_num);
446 else
447 disable_irq(pwr->interrupt_num);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700448 }
449 }
450}
451EXPORT_SYMBOL(kgsl_pwrctrl_irq);
452
453int kgsl_pwrctrl_init(struct kgsl_device *device)
454{
455 int i, result = 0;
456 struct clk *clk;
457 struct platform_device *pdev =
458 container_of(device->parentdev, struct platform_device, dev);
459 struct kgsl_pwrctrl *pwr = &device->pwrctrl;
Lucille Sylvesterdce84cd2011-10-12 14:15:37 -0600460 struct kgsl_device_platform_data *pdata = pdev->dev.platform_data;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700461
462 /*acquire clocks */
Lucille Sylvesterdce84cd2011-10-12 14:15:37 -0600463 for (i = 0; i < KGSL_MAX_CLKS; i++) {
464 if (pdata->clk_map & clks[i].map) {
465 clk = clk_get(&pdev->dev, clks[i].name);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700466 if (IS_ERR(clk))
467 goto clk_err;
468 pwr->grp_clks[i] = clk;
469 }
470 }
471 /* Make sure we have a source clk for freq setting */
Lucille Sylvesterdce84cd2011-10-12 14:15:37 -0600472 if (pwr->grp_clks[0] == NULL)
473 pwr->grp_clks[0] = pwr->grp_clks[1];
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700474
475 /* put the AXI bus into asynchronous mode with the graphics cores */
Lucille Sylvesterdce84cd2011-10-12 14:15:37 -0600476 if (pdata->set_grp_async != NULL)
477 pdata->set_grp_async();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700478
Lucille Sylvesterdce84cd2011-10-12 14:15:37 -0600479 if (pdata->num_levels > KGSL_MAX_PWRLEVELS) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700480 KGSL_PWR_ERR(device, "invalid power level count: %d\n",
Lucille Sylvesterdce84cd2011-10-12 14:15:37 -0600481 pdata->num_levels);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700482 result = -EINVAL;
483 goto done;
484 }
Lucille Sylvesterdce84cd2011-10-12 14:15:37 -0600485 pwr->num_pwrlevels = pdata->num_levels;
486 pwr->active_pwrlevel = pdata->init_level;
487 for (i = 0; i < pdata->num_levels; i++) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700488 pwr->pwrlevels[i].gpu_freq =
Lucille Sylvesterdce84cd2011-10-12 14:15:37 -0600489 (pdata->pwrlevel[i].gpu_freq > 0) ?
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700490 clk_round_rate(pwr->grp_clks[0],
Lucille Sylvesterdce84cd2011-10-12 14:15:37 -0600491 pdata->pwrlevel[i].
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700492 gpu_freq) : 0;
493 pwr->pwrlevels[i].bus_freq =
Lucille Sylvesterdce84cd2011-10-12 14:15:37 -0600494 pdata->pwrlevel[i].bus_freq;
Lucille Sylvester596d4c22011-10-19 18:04:01 -0600495 pwr->pwrlevels[i].io_fraction =
Lucille Sylvesterdce84cd2011-10-12 14:15:37 -0600496 pdata->pwrlevel[i].io_fraction;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700497 }
498 /* Do not set_rate for targets in sync with AXI */
499 if (pwr->pwrlevels[0].gpu_freq > 0)
500 clk_set_rate(pwr->grp_clks[0], pwr->
501 pwrlevels[pwr->num_pwrlevels - 1].gpu_freq);
502
503 pwr->gpu_reg = regulator_get(NULL, pwr->regulator_name);
504 if (IS_ERR(pwr->gpu_reg))
505 pwr->gpu_reg = NULL;
506
507 pwr->power_flags = 0;
508
Lucille Sylvesterdce84cd2011-10-12 14:15:37 -0600509 pwr->nap_allowed = pdata->nap_allowed;
Kedar Joshic11d0982012-02-07 10:59:49 +0530510 pwr->idle_needed = pdata->idle_needed;
Lucille Sylvesterdce84cd2011-10-12 14:15:37 -0600511 pwr->interval_timeout = pdata->idle_timeout;
Matt Wagantall9dc01632011-08-17 18:55:04 -0700512 pwr->ebi1_clk = clk_get(&pdev->dev, "bus_clk");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700513 if (IS_ERR(pwr->ebi1_clk))
514 pwr->ebi1_clk = NULL;
515 else
516 clk_set_rate(pwr->ebi1_clk,
517 pwr->pwrlevels[pwr->active_pwrlevel].
518 bus_freq);
Lucille Sylvesterdce84cd2011-10-12 14:15:37 -0600519 if (pdata->bus_scale_table != NULL) {
520 pwr->pcl = msm_bus_scale_register_client(pdata->
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700521 bus_scale_table);
522 if (!pwr->pcl) {
523 KGSL_PWR_ERR(device,
524 "msm_bus_scale_register_client failed: "
525 "id %d table %p", device->id,
Lucille Sylvesterdce84cd2011-10-12 14:15:37 -0600526 pdata->bus_scale_table);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700527 result = -EINVAL;
528 goto done;
529 }
530 }
531
532 /*acquire interrupt */
533 pwr->interrupt_num =
534 platform_get_irq_byname(pdev, pwr->irq_name);
535
536 if (pwr->interrupt_num <= 0) {
537 KGSL_PWR_ERR(device, "platform_get_irq_byname failed: %d\n",
538 pwr->interrupt_num);
539 result = -EINVAL;
540 goto done;
541 }
542
543 register_early_suspend(&device->display_off);
544 return result;
545
546clk_err:
547 result = PTR_ERR(clk);
548 KGSL_PWR_ERR(device, "clk_get(%s) failed: %d\n",
Lucille Sylvesterdce84cd2011-10-12 14:15:37 -0600549 clks[i].name, result);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700550
551done:
552 return result;
553}
554
555void kgsl_pwrctrl_close(struct kgsl_device *device)
556{
557 struct kgsl_pwrctrl *pwr = &device->pwrctrl;
558 int i;
559
560 KGSL_PWR_INFO(device, "close device %d\n", device->id);
561
562 unregister_early_suspend(&device->display_off);
563
564 if (pwr->interrupt_num > 0) {
565 if (pwr->have_irq) {
566 free_irq(pwr->interrupt_num, NULL);
567 pwr->have_irq = 0;
568 }
569 pwr->interrupt_num = 0;
570 }
571
572 clk_put(pwr->ebi1_clk);
573
574 if (pwr->pcl)
575 msm_bus_scale_unregister_client(pwr->pcl);
576
577 pwr->pcl = 0;
578
579 if (pwr->gpu_reg) {
580 regulator_put(pwr->gpu_reg);
581 pwr->gpu_reg = NULL;
582 }
583
584 for (i = 1; i < KGSL_MAX_CLKS; i++)
585 if (pwr->grp_clks[i]) {
586 clk_put(pwr->grp_clks[i]);
587 pwr->grp_clks[i] = NULL;
588 }
589
590 pwr->grp_clks[0] = NULL;
591 pwr->power_flags = 0;
592}
593
594void kgsl_idle_check(struct work_struct *work)
595{
596 struct kgsl_device *device = container_of(work, struct kgsl_device,
597 idle_check_ws);
Jeremy Gebben388c2972011-12-16 09:05:07 -0700598 WARN_ON(device == NULL);
599 if (device == NULL)
600 return;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700601
602 mutex_lock(&device->mutex);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700603 if (device->state & (KGSL_STATE_ACTIVE | KGSL_STATE_NAP)) {
Lucille Sylvester6e362412011-12-09 16:21:42 -0700604 kgsl_pwrscale_idle(device);
Lucille Sylvesterc4af3552011-10-27 11:44:24 -0600605
Suman Tatiraju7fe62a32011-07-14 16:40:37 -0700606 if (kgsl_pwrctrl_sleep(device) != 0) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700607 mod_timer(&device->idle_timer,
608 jiffies +
609 device->pwrctrl.interval_timeout);
Suman Tatiraju7fe62a32011-07-14 16:40:37 -0700610 /* If the GPU has been too busy to sleep, make sure *
611 * that is acurately reflected in the % busy numbers. */
612 device->pwrctrl.busy.no_nap_cnt++;
613 if (device->pwrctrl.busy.no_nap_cnt > UPDATE_BUSY) {
614 kgsl_pwrctrl_busy_time(device, true);
615 device->pwrctrl.busy.no_nap_cnt = 0;
616 }
617 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700618 } else if (device->state & (KGSL_STATE_HUNG |
619 KGSL_STATE_DUMP_AND_RECOVER)) {
Jeremy Gebben388c2972011-12-16 09:05:07 -0700620 kgsl_pwrctrl_request_state(device, KGSL_STATE_NONE);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700621 }
622
623 mutex_unlock(&device->mutex);
624}
625
626void kgsl_timer(unsigned long data)
627{
628 struct kgsl_device *device = (struct kgsl_device *) data;
629
630 KGSL_PWR_INFO(device, "idle timer expired device %d\n", device->id);
Anoop Kumar Yerukala03ba25f2012-01-23 17:32:02 +0530631 if (device->requested_state != KGSL_STATE_SUSPEND) {
Lucille Sylvestera985adf2012-01-16 11:11:55 -0700632 if (device->pwrctrl.restore_slumber)
633 kgsl_pwrctrl_request_state(device, KGSL_STATE_SLUMBER);
634 else
635 kgsl_pwrctrl_request_state(device, KGSL_STATE_SLEEP);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700636 /* Have work run in a non-interrupt context. */
637 queue_work(device->work_queue, &device->idle_check_ws);
638 }
639}
640
641void kgsl_pre_hwaccess(struct kgsl_device *device)
642{
643 BUG_ON(!mutex_is_locked(&device->mutex));
Lucille Sylvester8b803e92012-01-12 15:19:55 -0700644 switch (device->state) {
645 case KGSL_STATE_ACTIVE:
646 return;
647 case KGSL_STATE_NAP:
648 case KGSL_STATE_SLEEP:
649 case KGSL_STATE_SLUMBER:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700650 kgsl_pwrctrl_wake(device);
Lucille Sylvester8b803e92012-01-12 15:19:55 -0700651 break;
652 case KGSL_STATE_SUSPEND:
653 kgsl_check_suspended(device);
654 break;
655 case KGSL_STATE_INIT:
656 case KGSL_STATE_HUNG:
657 case KGSL_STATE_DUMP_AND_RECOVER:
658 if (test_bit(KGSL_PWRFLAGS_CLK_ON,
659 &device->pwrctrl.power_flags))
660 break;
661 else
662 KGSL_PWR_ERR(device,
663 "hw access while clocks off from state %d\n",
664 device->state);
665 break;
666 default:
667 KGSL_PWR_ERR(device, "hw access while in unknown state %d\n",
668 device->state);
669 break;
670 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700671}
672EXPORT_SYMBOL(kgsl_pre_hwaccess);
673
674void kgsl_check_suspended(struct kgsl_device *device)
675{
676 if (device->requested_state == KGSL_STATE_SUSPEND ||
677 device->state == KGSL_STATE_SUSPEND) {
678 mutex_unlock(&device->mutex);
679 wait_for_completion(&device->hwaccess_gate);
680 mutex_lock(&device->mutex);
Suman Tatiraju24569022011-10-27 11:11:12 -0700681 } else if (device->state == KGSL_STATE_DUMP_AND_RECOVER) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700682 mutex_unlock(&device->mutex);
683 wait_for_completion(&device->recovery_gate);
684 mutex_lock(&device->mutex);
Suman Tatiraju24569022011-10-27 11:11:12 -0700685 } else if (device->state == KGSL_STATE_SLUMBER)
686 kgsl_pwrctrl_wake(device);
687}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700688
Suman Tatiraju24569022011-10-27 11:11:12 -0700689static int
Jeremy Gebben388c2972011-12-16 09:05:07 -0700690_nap(struct kgsl_device *device)
Suman Tatiraju24569022011-10-27 11:11:12 -0700691{
Suman Tatiraju24569022011-10-27 11:11:12 -0700692 switch (device->state) {
693 case KGSL_STATE_ACTIVE:
Jeremy Gebben388c2972011-12-16 09:05:07 -0700694 if (!device->ftbl->isidle(device)) {
695 kgsl_pwrctrl_request_state(device, KGSL_STATE_NONE);
696 return -EBUSY;
697 }
698 kgsl_pwrctrl_irq(device, KGSL_PWRFLAGS_OFF);
699 kgsl_pwrctrl_clk(device, KGSL_PWRFLAGS_OFF);
Suman Tatiraju9b6110b2012-04-02 13:17:00 -0700700 kgsl_pwrctrl_set_state(device, device->requested_state);
Jeremy Gebben388c2972011-12-16 09:05:07 -0700701 if (device->idle_wakelock.name)
702 wake_unlock(&device->idle_wakelock);
Suman Tatiraju24569022011-10-27 11:11:12 -0700703 case KGSL_STATE_NAP:
704 case KGSL_STATE_SLEEP:
Jeremy Gebben388c2972011-12-16 09:05:07 -0700705 case KGSL_STATE_SLUMBER:
Suman Tatiraju24569022011-10-27 11:11:12 -0700706 break;
707 default:
Jeremy Gebben388c2972011-12-16 09:05:07 -0700708 kgsl_pwrctrl_request_state(device, KGSL_STATE_NONE);
Suman Tatiraju24569022011-10-27 11:11:12 -0700709 break;
710 }
Jeremy Gebben388c2972011-12-16 09:05:07 -0700711 return 0;
712}
713
714static void
715_sleep_accounting(struct kgsl_device *device)
716{
717 kgsl_pwrctrl_busy_time(device, false);
718 device->pwrctrl.busy.start.tv_sec = 0;
719 device->pwrctrl.time = 0;
720 kgsl_pwrscale_sleep(device);
721}
722
723static int
724_sleep(struct kgsl_device *device)
725{
726 struct kgsl_pwrctrl *pwr = &device->pwrctrl;
727 switch (device->state) {
728 case KGSL_STATE_ACTIVE:
729 if (!device->ftbl->isidle(device)) {
730 kgsl_pwrctrl_request_state(device, KGSL_STATE_NONE);
731 return -EBUSY;
732 }
733 /* fall through */
734 case KGSL_STATE_NAP:
735 kgsl_pwrctrl_irq(device, KGSL_PWRFLAGS_OFF);
736 kgsl_pwrctrl_axi(device, KGSL_PWRFLAGS_OFF);
737 if (pwr->pwrlevels[0].gpu_freq > 0)
738 clk_set_rate(pwr->grp_clks[0],
739 pwr->pwrlevels[pwr->num_pwrlevels - 1].
740 gpu_freq);
741 _sleep_accounting(device);
742 kgsl_pwrctrl_clk(device, KGSL_PWRFLAGS_OFF);
743 kgsl_pwrctrl_set_state(device, KGSL_STATE_SLEEP);
Lucille Sylvester10297892012-02-27 13:54:47 -0700744 wake_unlock(&device->idle_wakelock);
745 pm_qos_update_request(&device->pm_qos_req_dma,
746 PM_QOS_DEFAULT_VALUE);
Jeremy Gebben388c2972011-12-16 09:05:07 -0700747 break;
748 case KGSL_STATE_SLEEP:
749 case KGSL_STATE_SLUMBER:
750 break;
751 default:
Jeremy Gebbenb50f3312011-12-16 08:58:33 -0700752 KGSL_PWR_WARN(device, "unhandled state %s\n",
753 kgsl_pwrstate_to_str(device->state));
Jeremy Gebben388c2972011-12-16 09:05:07 -0700754 break;
755 }
756 return 0;
757}
758
759static int
760_slumber(struct kgsl_device *device)
761{
762 switch (device->state) {
763 case KGSL_STATE_ACTIVE:
764 if (!device->ftbl->isidle(device)) {
765 kgsl_pwrctrl_request_state(device, KGSL_STATE_NONE);
766 device->pwrctrl.restore_slumber = true;
767 return -EBUSY;
768 }
769 /* fall through */
770 case KGSL_STATE_NAP:
771 case KGSL_STATE_SLEEP:
772 del_timer_sync(&device->idle_timer);
773 kgsl_pwrctrl_pwrlevel_change(device, KGSL_PWRLEVEL_NOMINAL);
Suman Tatiraju3005cdd2012-03-19 14:38:11 -0700774 device->pwrctrl.restore_slumber = true;
Jeremy Gebben388c2972011-12-16 09:05:07 -0700775 device->ftbl->suspend_context(device);
776 device->ftbl->stop(device);
Jeremy Gebben388c2972011-12-16 09:05:07 -0700777 _sleep_accounting(device);
778 kgsl_pwrctrl_set_state(device, KGSL_STATE_SLUMBER);
779 if (device->idle_wakelock.name)
780 wake_unlock(&device->idle_wakelock);
Suman Tatiraju3005cdd2012-03-19 14:38:11 -0700781 pm_qos_update_request(&device->pm_qos_req_dma,
782 PM_QOS_DEFAULT_VALUE);
Jeremy Gebben388c2972011-12-16 09:05:07 -0700783 break;
784 case KGSL_STATE_SLUMBER:
785 break;
786 default:
Jeremy Gebbenb50f3312011-12-16 08:58:33 -0700787 KGSL_PWR_WARN(device, "unhandled state %s\n",
788 kgsl_pwrstate_to_str(device->state));
Jeremy Gebben388c2972011-12-16 09:05:07 -0700789 break;
790 }
791 return 0;
Suman Tatiraju24569022011-10-27 11:11:12 -0700792}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700793
794/******************************************************************/
795/* Caller must hold the device mutex. */
796int kgsl_pwrctrl_sleep(struct kgsl_device *device)
797{
Jeremy Gebben388c2972011-12-16 09:05:07 -0700798 int status = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700799 KGSL_PWR_INFO(device, "sleep device %d\n", device->id);
800
801 /* Work through the legal state transitions */
Jeremy Gebben388c2972011-12-16 09:05:07 -0700802 switch (device->requested_state) {
803 case KGSL_STATE_NAP:
Jeremy Gebben388c2972011-12-16 09:05:07 -0700804 status = _nap(device);
805 break;
806 case KGSL_STATE_SLEEP:
Lucille Sylvestera985adf2012-01-16 11:11:55 -0700807 status = _sleep(device);
Jeremy Gebben388c2972011-12-16 09:05:07 -0700808 break;
809 case KGSL_STATE_SLUMBER:
810 status = _slumber(device);
811 break;
812 default:
813 KGSL_PWR_INFO(device, "bad state request 0x%x\n",
814 device->requested_state);
815 kgsl_pwrctrl_request_state(device, KGSL_STATE_NONE);
816 status = -EINVAL;
817 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700818 }
Suman Tatiraju24569022011-10-27 11:11:12 -0700819 return status;
820}
Jeremy Gebben388c2972011-12-16 09:05:07 -0700821EXPORT_SYMBOL(kgsl_pwrctrl_sleep);
Suman Tatiraju24569022011-10-27 11:11:12 -0700822
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700823/******************************************************************/
824/* Caller must hold the device mutex. */
825void kgsl_pwrctrl_wake(struct kgsl_device *device)
826{
Jeremy Gebben388c2972011-12-16 09:05:07 -0700827 int status;
828 kgsl_pwrctrl_request_state(device, KGSL_STATE_ACTIVE);
829 switch (device->state) {
830 case KGSL_STATE_SLUMBER:
831 status = device->ftbl->start(device, 0);
832 if (status) {
833 kgsl_pwrctrl_request_state(device, KGSL_STATE_NONE);
834 KGSL_DRV_ERR(device, "start failed %d\n", status);
835 break;
836 }
837 /* fall through */
838 case KGSL_STATE_SLEEP:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700839 kgsl_pwrctrl_axi(device, KGSL_PWRFLAGS_ON);
840 kgsl_pwrscale_wake(device);
Jeremy Gebben388c2972011-12-16 09:05:07 -0700841 /* fall through */
842 case KGSL_STATE_NAP:
843 /* Turn on the core clocks */
844 kgsl_pwrctrl_clk(device, KGSL_PWRFLAGS_ON);
845 /* Enable state before turning on irq */
846 kgsl_pwrctrl_set_state(device, KGSL_STATE_ACTIVE);
847 kgsl_pwrctrl_irq(device, KGSL_PWRFLAGS_ON);
848 /* Re-enable HW access */
849 mod_timer(&device->idle_timer,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700850 jiffies + device->pwrctrl.interval_timeout);
Lucille Sylvester10297892012-02-27 13:54:47 -0700851 wake_lock(&device->idle_wakelock);
Suman Tatiraju3005cdd2012-03-19 14:38:11 -0700852 if (device->pwrctrl.restore_slumber == false)
853 pm_qos_update_request(&device->pm_qos_req_dma,
854 GPU_SWFI_LATENCY);
Jeremy Gebben388c2972011-12-16 09:05:07 -0700855 case KGSL_STATE_ACTIVE:
856 break;
857 default:
Jeremy Gebbenb50f3312011-12-16 08:58:33 -0700858 KGSL_PWR_WARN(device, "unhandled state %s\n",
859 kgsl_pwrstate_to_str(device->state));
Jeremy Gebben388c2972011-12-16 09:05:07 -0700860 kgsl_pwrctrl_request_state(device, KGSL_STATE_NONE);
861 break;
862 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700863}
864EXPORT_SYMBOL(kgsl_pwrctrl_wake);
865
866void kgsl_pwrctrl_enable(struct kgsl_device *device)
867{
868 /* Order pwrrail/clk sequence based upon platform */
869 kgsl_pwrctrl_pwrrail(device, KGSL_PWRFLAGS_ON);
870 kgsl_pwrctrl_clk(device, KGSL_PWRFLAGS_ON);
871 kgsl_pwrctrl_axi(device, KGSL_PWRFLAGS_ON);
872}
873EXPORT_SYMBOL(kgsl_pwrctrl_enable);
874
875void kgsl_pwrctrl_disable(struct kgsl_device *device)
876{
877 /* Order pwrrail/clk sequence based upon platform */
878 kgsl_pwrctrl_axi(device, KGSL_PWRFLAGS_OFF);
879 kgsl_pwrctrl_clk(device, KGSL_PWRFLAGS_OFF);
880 kgsl_pwrctrl_pwrrail(device, KGSL_PWRFLAGS_OFF);
881}
882EXPORT_SYMBOL(kgsl_pwrctrl_disable);
Jeremy Gebben388c2972011-12-16 09:05:07 -0700883
884void kgsl_pwrctrl_set_state(struct kgsl_device *device, unsigned int state)
885{
Jeremy Gebbenb50f3312011-12-16 08:58:33 -0700886 trace_kgsl_pwr_set_state(device, state);
Jeremy Gebben388c2972011-12-16 09:05:07 -0700887 device->state = state;
888 device->requested_state = KGSL_STATE_NONE;
889}
890EXPORT_SYMBOL(kgsl_pwrctrl_set_state);
891
892void kgsl_pwrctrl_request_state(struct kgsl_device *device, unsigned int state)
893{
894 if (state != KGSL_STATE_NONE && state != device->requested_state)
Jeremy Gebbenb50f3312011-12-16 08:58:33 -0700895 trace_kgsl_pwr_request_state(device, state);
Jeremy Gebben388c2972011-12-16 09:05:07 -0700896 device->requested_state = state;
897}
898EXPORT_SYMBOL(kgsl_pwrctrl_request_state);
Jeremy Gebbenb50f3312011-12-16 08:58:33 -0700899
900const char *kgsl_pwrstate_to_str(unsigned int state)
901{
902 switch (state) {
903 case KGSL_STATE_NONE:
904 return "NONE";
905 case KGSL_STATE_INIT:
906 return "INIT";
907 case KGSL_STATE_ACTIVE:
908 return "ACTIVE";
909 case KGSL_STATE_NAP:
910 return "NAP";
911 case KGSL_STATE_SLEEP:
912 return "SLEEP";
913 case KGSL_STATE_SUSPEND:
914 return "SUSPEND";
915 case KGSL_STATE_HUNG:
916 return "HUNG";
917 case KGSL_STATE_DUMP_AND_RECOVER:
918 return "DNR";
919 case KGSL_STATE_SLUMBER:
920 return "SLUMBER";
921 default:
922 break;
923 }
924 return "UNKNOWN";
925}
926EXPORT_SYMBOL(kgsl_pwrstate_to_str);
927