msm: kgsl: suspend device when the display does off
This change saves leakage current when the display is
off. In scenerios where a user is listening to an mp3
this feature stops the GPU as soon as the display goes
off. The GPU is started again when the display comes
back. The feature also avoids the GPU resuming when a
email sync happens while the device is suspended.
The change also disables NAP when the display is off.
It wakes 3d core to process user space requests when in
slumber
Change-Id: I65d17e937079a27b14d08be0a975d7ecf80b18ab
CRs-fixed: 316579
Signed-off-by: Suman Tatiraju <sumant@codeaurora.org>
diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c
index c6fceaa..e84d473 100644
--- a/drivers/gpu/msm/kgsl.c
+++ b/drivers/gpu/msm/kgsl.c
@@ -348,6 +348,12 @@
KGSL_PWR_WARN(device, "state -> SUSPEND, device %d\n",
device->id);
break;
+ case KGSL_STATE_SLUMBER:
+ INIT_COMPLETION(device->hwaccess_gate);
+ device->state = KGSL_STATE_SUSPEND;
+ KGSL_PWR_WARN(device, "state -> SUSPEND, device %d\n",
+ device->id);
+ break;
default:
KGSL_PWR_ERR(device, "suspend fail, device %d\n",
device->id);
@@ -374,28 +380,16 @@
KGSL_PWR_WARN(device, "resume start\n");
mutex_lock(&device->mutex);
if (device->state == KGSL_STATE_SUSPEND) {
- device->requested_state = KGSL_STATE_ACTIVE;
- kgsl_pwrctrl_pwrlevel_change(device, KGSL_PWRLEVEL_NOMINAL);
- status = device->ftbl->start(device, 0);
- if (status == 0) {
- device->state = KGSL_STATE_ACTIVE;
- KGSL_PWR_WARN(device,
- "state -> ACTIVE, device %d\n",
- device->id);
- } else {
- KGSL_PWR_ERR(device,
- "resume failed, device %d\n",
- device->id);
- device->state = KGSL_STATE_INIT;
- goto end;
- }
+ device->state = KGSL_STATE_SLUMBER;
+ status = 0;
+ KGSL_PWR_WARN(device,
+ "state -> SLUMBER, device %d\n",
+ device->id);
complete_all(&device->hwaccess_gate);
}
device->requested_state = KGSL_STATE_NONE;
-end:
mutex_unlock(&device->mutex);
- kgsl_check_idle(device);
KGSL_PWR_WARN(device, "resume end\n");
return status;
}
@@ -436,9 +430,12 @@
{
struct kgsl_device *device = container_of(h,
struct kgsl_device, display_off);
+ KGSL_PWR_WARN(device, "early suspend start\n");
mutex_lock(&device->mutex);
- kgsl_pwrctrl_pwrlevel_change(device, KGSL_PWRLEVEL_NOMINAL);
+ device->requested_state = KGSL_STATE_SLUMBER;
+ kgsl_pwrctrl_sleep(device);
mutex_unlock(&device->mutex);
+ KGSL_PWR_WARN(device, "early suspend end\n");
}
EXPORT_SYMBOL(kgsl_early_suspend_driver);
@@ -461,9 +458,13 @@
{
struct kgsl_device *device = container_of(h,
struct kgsl_device, display_off);
+ KGSL_PWR_WARN(device, "late resume start\n");
mutex_lock(&device->mutex);
- kgsl_pwrctrl_pwrlevel_change(device, KGSL_PWRLEVEL_TURBO);
+ kgsl_pwrctrl_wake(device);
+ device->pwrctrl.restore_slumber = 0;
mutex_unlock(&device->mutex);
+ kgsl_check_idle(device);
+ KGSL_PWR_WARN(device, "late resume end\n");
}
EXPORT_SYMBOL(kgsl_late_resume_driver);