diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c index dea6efcdafa7..e290c41dcf9f 100644 --- a/drivers/gpu/msm/adreno.c +++ b/drivers/gpu/msm/adreno.c @@ -321,23 +321,10 @@ void adreno_fault_detect_stop(struct adreno_device *adreno_dev) adreno_dev->fast_hang_detect = 0; } -/* - * A workqueue callback responsible for actually turning on the GPU after a - * touch event. kgsl_pwrctrl_change_state(ACTIVE) is used without any - * active_count protection to avoid the need to maintain state. Either - * somebody will start using the GPU or the idle timer will fire and put the - * GPU back into slumber. - */ -static void adreno_input_work(struct work_struct *work) +static void adreno_touch_wakeup(struct adreno_device *adreno_dev) { - struct adreno_device *adreno_dev = container_of(work, - struct adreno_device, input_work); struct kgsl_device *device = KGSL_DEVICE(adreno_dev); - mutex_lock(&device->mutex); - - device->flags |= KGSL_FLAG_WAKE_ON_TOUCH; - /* * Don't schedule adreno_start in a high priority workqueue, we are * already in a workqueue which should be sufficient @@ -352,6 +339,29 @@ static void adreno_input_work(struct work_struct *work) */ mod_timer(&device->idle_timer, jiffies + msecs_to_jiffies(adreno_wake_timeout)); + +} + +/* + * A workqueue callback responsible for actually turning on the GPU after a + * touch event. kgsl_pwrctrl_change_state(ACTIVE) is used without any + * active_count protection to avoid the need to maintain state. Either + * somebody will start using the GPU or the idle timer will fire and put the + * GPU back into slumber. + */ +static void adreno_input_work(struct work_struct *work) +{ + struct adreno_device *adreno_dev = container_of(work, + struct adreno_device, input_work); + struct kgsl_device *device = KGSL_DEVICE(adreno_dev); + const struct adreno_power_ops *ops = ADRENO_POWER_OPS(adreno_dev); + + mutex_lock(&device->mutex); + + device->flags |= KGSL_FLAG_WAKE_ON_TOUCH; + + ops->touch_wakeup(adreno_dev); + mutex_unlock(&device->mutex); } @@ -377,6 +387,11 @@ static void adreno_input_event(struct input_handle *handle, unsigned int type, if (device->flags & KGSL_FLAG_WAKE_ON_TOUCH) return; + if (gmu_core_isenabled(device)) { + schedule_work(&adreno_dev->input_work); + return; + } + /* * If the device is in nap, kick the idle timer to make sure that we * don't go into slumber before the first render. If the device is @@ -3841,6 +3856,7 @@ const struct adreno_power_ops adreno_power_operations = { .active_count_put = adreno_pwrctrl_active_count_put, .pm_suspend = adreno_suspend, .pm_resume = adreno_resume, + .touch_wakeup = adreno_touch_wakeup, }; static const struct of_device_id adreno_gmu_match[] = { diff --git a/drivers/gpu/msm/adreno.h b/drivers/gpu/msm/adreno.h index 7b1bf2781dde..090a6ca7c26c 100644 --- a/drivers/gpu/msm/adreno.h +++ b/drivers/gpu/msm/adreno.h @@ -357,6 +357,10 @@ struct adreno_power_ops { int (*pm_suspend)(struct adreno_device *adreno_dev); /** @pm_resume: Target specific function to resume the driver */ void (*pm_resume)(struct adreno_device *adreno_dev); + /** + * @touch_wakeup: Target specific function to start gpu on touch event + */ + void (*touch_wakeup)(struct adreno_device *adreno_dev); }; /** diff --git a/drivers/gpu/msm/adreno_a6xx_gmu.c b/drivers/gpu/msm/adreno_a6xx_gmu.c index 1754a8580881..7a2e94d75dbd 100644 --- a/drivers/gpu/msm/adreno_a6xx_gmu.c +++ b/drivers/gpu/msm/adreno_a6xx_gmu.c @@ -3113,6 +3113,44 @@ static void a6xx_gmu_pm_resume(struct adreno_device *adreno_dev) clear_bit(GMU_PRIV_PM_SUSPEND, &gmu->flags); } +static void a6xx_gmu_touch_wakeup(struct adreno_device *adreno_dev) +{ + struct kgsl_device *device = KGSL_DEVICE(adreno_dev); + struct a6xx_gmu_device *gmu = to_a6xx_gmu(adreno_dev); + int ret; + + /* Do not wake up a suspended device through touch event */ + if (test_bit(GMU_PRIV_PM_SUSPEND, &gmu->flags)) + return; + + if (test_bit(GMU_PRIV_GPU_STARTED, &gmu->flags)) + goto done; + + ret = a6xx_gmu_boot(adreno_dev); + if (ret) + return; + + ret = a6xx_gpu_boot(adreno_dev); + if (ret) + return; + + kgsl_pwrscale_wake(device); + + set_bit(GMU_PRIV_GPU_STARTED, &gmu->flags); + device->state = KGSL_STATE_ACTIVE; + +done: + /* + * When waking up from a touch event we want to stay active long enough + * for the user to send a draw command. The default idle timer timeout + * is shorter than we want so go ahead and push the idle timer out + * further for this special case + */ + mod_timer(&device->idle_timer, jiffies + + msecs_to_jiffies(adreno_wake_timeout)); + +} + const struct adreno_power_ops a6xx_gmu_power_ops = { .first_open = a6xx_gmu_first_open, .last_close = a6xx_gmu_last_close, @@ -3120,6 +3158,7 @@ const struct adreno_power_ops a6xx_gmu_power_ops = { .active_count_put = a6xx_gmu_active_count_put, .pm_suspend = a6xx_gmu_pm_suspend, .pm_resume = a6xx_gmu_pm_resume, + .touch_wakeup = a6xx_gmu_touch_wakeup, }; int a6xx_gmu_device_probe(struct platform_device *pdev, diff --git a/drivers/gpu/msm/adreno_a6xx_rgmu.c b/drivers/gpu/msm/adreno_a6xx_rgmu.c index 2b6b3add062c..8969c6dda4a6 100644 --- a/drivers/gpu/msm/adreno_a6xx_rgmu.c +++ b/drivers/gpu/msm/adreno_a6xx_rgmu.c @@ -881,6 +881,45 @@ static int a6xx_boot(struct adreno_device *adreno_dev) return 0; } +static void a6xx_rgmu_touch_wakeup(struct adreno_device *adreno_dev) +{ + struct kgsl_device *device = KGSL_DEVICE(adreno_dev); + struct a6xx_rgmu_device *rgmu = to_a6xx_rgmu(adreno_dev); + int ret; + + /* Do not wake up a suspended device through touch event */ + if (test_bit(RGMU_PRIV_PM_SUSPEND, &rgmu->flags)) + return; + + if (test_bit(RGMU_PRIV_GPU_STARTED, &rgmu->flags)) + goto done; + + ret = a6xx_rgmu_boot(adreno_dev); + if (ret) + return; + + ret = a6xx_gpu_boot(adreno_dev); + if (ret) + return; + + kgsl_pwrscale_wake(device); + + set_bit(RGMU_PRIV_GPU_STARTED, &rgmu->flags); + + device->state = KGSL_STATE_ACTIVE; + +done: + /* + * When waking up from a touch event we want to stay active long enough + * for the user to send a draw command. The default idle timer timeout + * is shorter than we want so go ahead and push the idle timer out + * further for this special case + */ + mod_timer(&device->idle_timer, jiffies + + msecs_to_jiffies(adreno_wake_timeout)); + +} + static int a6xx_first_boot(struct adreno_device *adreno_dev) { struct kgsl_device *device = KGSL_DEVICE(adreno_dev); @@ -1204,6 +1243,7 @@ const struct adreno_power_ops a6xx_rgmu_power_ops = { .active_count_put = a6xx_rgmu_active_count_put, .pm_suspend = a6xx_rgmu_pm_suspend, .pm_resume = a6xx_rgmu_pm_resume, + .touch_wakeup = a6xx_rgmu_touch_wakeup, }; int a6xx_rgmu_device_probe(struct platform_device *pdev,