forked from rubenslte/android_kernel_samsung_msm8226
msm: kgsl: power state cleanup
Clean up kgsl_pwrctrl_sleep() and kgsl_pwrctrl_wake() to make state transistions clearer. Add kgsl_pwrctrl_request_state() and kgsl_pwrctrl_set_state() to make it easier to debug the state machine. CRs-Fixed: 315833 Change-Id: I656ce8bd19feabd4186ef91dc031f8a6c6a7d09a Signed-off-by: Jeremy Gebben <jgebben@codeaurora.org>
This commit is contained in:
+11
-18
@@ -194,7 +194,7 @@ static irqreturn_t adreno_isr(int irq, void *data)
|
||||
|
||||
if (device->requested_state == KGSL_STATE_NONE) {
|
||||
if (device->pwrctrl.nap_allowed == true) {
|
||||
device->requested_state = KGSL_STATE_NAP;
|
||||
kgsl_pwrctrl_request_state(device, KGSL_STATE_NAP);
|
||||
queue_work(device->work_queue, &device->idle_check_ws);
|
||||
} else if (device->pwrscale.policy != NULL) {
|
||||
queue_work(device->work_queue, &device->idle_check_ws);
|
||||
@@ -495,8 +495,7 @@ static int adreno_start(struct kgsl_device *device, unsigned int init_ram)
|
||||
struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
|
||||
int init_reftimestamp = 0x7fffffff;
|
||||
|
||||
device->state = KGSL_STATE_INIT;
|
||||
device->requested_state = KGSL_STATE_NONE;
|
||||
kgsl_pwrctrl_set_state(device, KGSL_STATE_INIT);
|
||||
|
||||
/* Power up the device */
|
||||
kgsl_pwrctrl_enable(device);
|
||||
@@ -716,33 +715,27 @@ done:
|
||||
static int
|
||||
adreno_dump_and_recover(struct kgsl_device *device)
|
||||
{
|
||||
static int recovery;
|
||||
int result = -ETIMEDOUT;
|
||||
|
||||
if (device->state == KGSL_STATE_HUNG)
|
||||
goto done;
|
||||
if (device->state == KGSL_STATE_DUMP_AND_RECOVER && !recovery) {
|
||||
if (device->state == KGSL_STATE_DUMP_AND_RECOVER) {
|
||||
mutex_unlock(&device->mutex);
|
||||
wait_for_completion(&device->recovery_gate);
|
||||
mutex_lock(&device->mutex);
|
||||
if (!(device->state & KGSL_STATE_HUNG))
|
||||
/* recovery success */
|
||||
if (device->state != KGSL_STATE_HUNG)
|
||||
result = 0;
|
||||
} else {
|
||||
kgsl_pwrctrl_set_state(device, KGSL_STATE_DUMP_AND_RECOVER);
|
||||
INIT_COMPLETION(device->recovery_gate);
|
||||
/* Detected a hang - trigger an automatic dump */
|
||||
adreno_postmortem_dump(device, 0);
|
||||
if (!recovery) {
|
||||
recovery = 1;
|
||||
result = adreno_recover_hang(device);
|
||||
if (result)
|
||||
device->state = KGSL_STATE_HUNG;
|
||||
recovery = 0;
|
||||
complete_all(&device->recovery_gate);
|
||||
} else
|
||||
KGSL_DRV_ERR(device,
|
||||
"Cannot recover from another hang while "
|
||||
"recovering from a hang\n");
|
||||
result = adreno_recover_hang(device);
|
||||
if (result)
|
||||
kgsl_pwrctrl_set_state(device, KGSL_STATE_HUNG);
|
||||
else
|
||||
kgsl_pwrctrl_set_state(device, KGSL_STATE_ACTIVE);
|
||||
complete_all(&device->recovery_gate);
|
||||
}
|
||||
done:
|
||||
return result;
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#include "adreno_postmortem.h"
|
||||
#include "adreno_debugfs.h"
|
||||
#include "kgsl_cffdump.h"
|
||||
#include "kgsl_pwrctrl.h"
|
||||
|
||||
#include "a2xx_reg.h"
|
||||
|
||||
@@ -828,11 +829,9 @@ int adreno_postmortem_dump(struct kgsl_device *device, int manual)
|
||||
|
||||
/* Disable the idle timer so we don't get interrupted */
|
||||
del_timer_sync(&device->idle_timer);
|
||||
|
||||
mutex_unlock(&device->mutex);
|
||||
flush_workqueue(device->work_queue);
|
||||
mutex_lock(&device->mutex);
|
||||
adreno_dump(device);
|
||||
|
||||
/* Turn off napping to make sure we have the clocks full
|
||||
attention through the following process */
|
||||
@@ -845,15 +844,7 @@ int adreno_postmortem_dump(struct kgsl_device *device, int manual)
|
||||
/* Disable the irq */
|
||||
kgsl_pwrctrl_irq(device, KGSL_PWRFLAGS_OFF);
|
||||
|
||||
/* If this is not a manual trigger, then set up the
|
||||
state to try to recover */
|
||||
|
||||
if (!manual) {
|
||||
device->state = KGSL_STATE_DUMP_AND_RECOVER;
|
||||
KGSL_PWR_WARN(device,
|
||||
"state -> DUMP_AND_RECOVER, device %d\n",
|
||||
device->id);
|
||||
}
|
||||
adreno_dump(device);
|
||||
|
||||
/* Restore nap mode */
|
||||
device->pwrctrl.nap_allowed = saved_nap;
|
||||
@@ -867,7 +858,7 @@ int adreno_postmortem_dump(struct kgsl_device *device, int manual)
|
||||
kgsl_pwrctrl_irq(device, KGSL_PWRFLAGS_ON);
|
||||
|
||||
/* try to go into a sleep mode until the next event */
|
||||
device->requested_state = KGSL_STATE_SLEEP;
|
||||
kgsl_pwrctrl_request_state(device, KGSL_STATE_SLEEP);
|
||||
kgsl_pwrctrl_sleep(device);
|
||||
}
|
||||
|
||||
|
||||
@@ -393,7 +393,6 @@ void adreno_ringbuffer_stop(struct adreno_ringbuffer *rb)
|
||||
if (rb->flags & KGSL_FLAGS_STARTED) {
|
||||
/* ME_HALT */
|
||||
adreno_regwrite(rb->device, REG_CP_ME_CNTL, 0x10000000);
|
||||
|
||||
rb->flags &= ~KGSL_FLAGS_STARTED;
|
||||
}
|
||||
}
|
||||
|
||||
+11
-20
@@ -302,7 +302,7 @@ static void kgsl_check_idle_locked(struct kgsl_device *device)
|
||||
if (device->pwrctrl.nap_allowed == true &&
|
||||
device->state == KGSL_STATE_ACTIVE &&
|
||||
device->requested_state == KGSL_STATE_NONE) {
|
||||
device->requested_state = KGSL_STATE_NAP;
|
||||
kgsl_pwrctrl_request_state(device, KGSL_STATE_NAP);
|
||||
if (kgsl_pwrctrl_sleep(device) != 0)
|
||||
mod_timer(&device->idle_timer,
|
||||
jiffies +
|
||||
@@ -395,7 +395,7 @@ static int kgsl_suspend_device(struct kgsl_device *device, pm_message_t state)
|
||||
device->pwrctrl.nap_allowed = false;
|
||||
policy_saved = device->pwrscale.policy;
|
||||
device->pwrscale.policy = NULL;
|
||||
device->requested_state = KGSL_STATE_SUSPEND;
|
||||
kgsl_pwrctrl_request_state(device, KGSL_STATE_SUSPEND);
|
||||
/* Make sure no user process is waiting for a timestamp *
|
||||
* before supending */
|
||||
if (device->active_cnt != 0) {
|
||||
@@ -417,22 +417,18 @@ static int kgsl_suspend_device(struct kgsl_device *device, pm_message_t state)
|
||||
INIT_COMPLETION(device->hwaccess_gate);
|
||||
device->ftbl->suspend_context(device);
|
||||
device->ftbl->stop(device);
|
||||
device->state = KGSL_STATE_SUSPEND;
|
||||
KGSL_PWR_WARN(device, "state -> SUSPEND, device %d\n",
|
||||
device->id);
|
||||
kgsl_pwrctrl_set_state(device, KGSL_STATE_SUSPEND);
|
||||
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);
|
||||
kgsl_pwrctrl_set_state(device, KGSL_STATE_SUSPEND);
|
||||
break;
|
||||
default:
|
||||
KGSL_PWR_ERR(device, "suspend fail, device %d\n",
|
||||
device->id);
|
||||
goto end;
|
||||
}
|
||||
device->requested_state = KGSL_STATE_NONE;
|
||||
kgsl_pwrctrl_request_state(device, KGSL_STATE_NONE);
|
||||
device->pwrctrl.nap_allowed = nap_allowed_saved;
|
||||
device->pwrscale.policy = policy_saved;
|
||||
status = 0;
|
||||
@@ -453,14 +449,11 @@ static int kgsl_resume_device(struct kgsl_device *device)
|
||||
KGSL_PWR_WARN(device, "resume start\n");
|
||||
mutex_lock(&device->mutex);
|
||||
if (device->state == KGSL_STATE_SUSPEND) {
|
||||
device->state = KGSL_STATE_SLUMBER;
|
||||
kgsl_pwrctrl_set_state(device, 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;
|
||||
kgsl_pwrctrl_request_state(device, KGSL_STATE_NONE);
|
||||
|
||||
mutex_unlock(&device->mutex);
|
||||
KGSL_PWR_WARN(device, "resume end\n");
|
||||
@@ -505,7 +498,7 @@ void kgsl_early_suspend_driver(struct early_suspend *h)
|
||||
struct kgsl_device, display_off);
|
||||
KGSL_PWR_WARN(device, "early suspend start\n");
|
||||
mutex_lock(&device->mutex);
|
||||
device->requested_state = KGSL_STATE_SLUMBER;
|
||||
kgsl_pwrctrl_request_state(device, KGSL_STATE_SLUMBER);
|
||||
kgsl_pwrctrl_sleep(device);
|
||||
mutex_unlock(&device->mutex);
|
||||
KGSL_PWR_WARN(device, "early suspend end\n");
|
||||
@@ -535,6 +528,7 @@ void kgsl_late_resume_driver(struct early_suspend *h)
|
||||
mutex_lock(&device->mutex);
|
||||
kgsl_pwrctrl_wake(device);
|
||||
device->pwrctrl.restore_slumber = 0;
|
||||
kgsl_pwrctrl_pwrlevel_change(device, KGSL_PWRLEVEL_TURBO);
|
||||
mutex_unlock(&device->mutex);
|
||||
kgsl_check_idle(device);
|
||||
KGSL_PWR_WARN(device, "late resume end\n");
|
||||
@@ -651,8 +645,7 @@ static int kgsl_release(struct inode *inodep, struct file *filep)
|
||||
device->open_count--;
|
||||
if (device->open_count == 0) {
|
||||
result = device->ftbl->stop(device);
|
||||
device->state = KGSL_STATE_INIT;
|
||||
KGSL_PWR_WARN(device, "state -> INIT, device %d\n", device->id);
|
||||
kgsl_pwrctrl_set_state(device, KGSL_STATE_INIT);
|
||||
}
|
||||
/* clean up any to-be-freed entries that belong to this
|
||||
* process and this device
|
||||
@@ -720,9 +713,7 @@ static int kgsl_open(struct inode *inodep, struct file *filep)
|
||||
mutex_unlock(&device->mutex);
|
||||
goto err_putprocess;
|
||||
}
|
||||
device->state = KGSL_STATE_ACTIVE;
|
||||
KGSL_PWR_WARN(device,
|
||||
"state -> ACTIVE, device %d\n", minor);
|
||||
kgsl_pwrctrl_set_state(device, KGSL_STATE_ACTIVE);
|
||||
}
|
||||
device->open_count++;
|
||||
mutex_unlock(&device->mutex);
|
||||
|
||||
+165
-119
@@ -599,6 +599,9 @@ void kgsl_idle_check(struct work_struct *work)
|
||||
{
|
||||
struct kgsl_device *device = container_of(work, struct kgsl_device,
|
||||
idle_check_ws);
|
||||
WARN_ON(device == NULL);
|
||||
if (device == NULL)
|
||||
return;
|
||||
|
||||
mutex_lock(&device->mutex);
|
||||
if (device->state & (KGSL_STATE_ACTIVE | KGSL_STATE_NAP)) {
|
||||
@@ -620,7 +623,7 @@ void kgsl_idle_check(struct work_struct *work)
|
||||
}
|
||||
} else if (device->state & (KGSL_STATE_HUNG |
|
||||
KGSL_STATE_DUMP_AND_RECOVER)) {
|
||||
device->requested_state = KGSL_STATE_NONE;
|
||||
kgsl_pwrctrl_request_state(device, KGSL_STATE_NONE);
|
||||
}
|
||||
|
||||
mutex_unlock(&device->mutex);
|
||||
@@ -632,7 +635,7 @@ void kgsl_timer(unsigned long data)
|
||||
|
||||
KGSL_PWR_INFO(device, "idle timer expired device %d\n", device->id);
|
||||
if (device->requested_state != KGSL_STATE_SUSPEND) {
|
||||
device->requested_state = KGSL_STATE_SLEEP;
|
||||
kgsl_pwrctrl_request_state(device, KGSL_STATE_SLEEP);
|
||||
/* Have work run in a non-interrupt context. */
|
||||
queue_work(device->work_queue, &device->idle_check_ws);
|
||||
}
|
||||
@@ -663,155 +666,182 @@ void kgsl_check_suspended(struct kgsl_device *device)
|
||||
}
|
||||
|
||||
static int
|
||||
_slumber(struct kgsl_device *device)
|
||||
_nap(struct kgsl_device *device)
|
||||
{
|
||||
int status = -EINVAL;
|
||||
if (!device)
|
||||
return -EINVAL;
|
||||
KGSL_PWR_WARN(device, "Slumber start\n");
|
||||
|
||||
device->requested_state = KGSL_STATE_SLUMBER;
|
||||
del_timer(&device->idle_timer);
|
||||
switch (device->state) {
|
||||
case KGSL_STATE_ACTIVE:
|
||||
/* Wait for the device to become idle */
|
||||
device->ftbl->idle(device, KGSL_TIMEOUT_DEFAULT);
|
||||
if (!device->ftbl->isidle(device)) {
|
||||
kgsl_pwrctrl_request_state(device, KGSL_STATE_NONE);
|
||||
return -EBUSY;
|
||||
}
|
||||
kgsl_pwrctrl_irq(device, KGSL_PWRFLAGS_OFF);
|
||||
kgsl_pwrctrl_clk(device, KGSL_PWRFLAGS_OFF);
|
||||
kgsl_pwrctrl_set_state(device, KGSL_STATE_NAP);
|
||||
if (device->idle_wakelock.name)
|
||||
wake_unlock(&device->idle_wakelock);
|
||||
case KGSL_STATE_NAP:
|
||||
case KGSL_STATE_SLEEP:
|
||||
device->ftbl->suspend_context(device);
|
||||
device->ftbl->stop(device);
|
||||
device->state = KGSL_STATE_SLUMBER;
|
||||
device->pwrctrl.restore_slumber = 1;
|
||||
KGSL_PWR_WARN(device, "state -> SLUMBER, device %d\n",
|
||||
device->id);
|
||||
case KGSL_STATE_SLUMBER:
|
||||
break;
|
||||
default:
|
||||
kgsl_pwrctrl_request_state(device, KGSL_STATE_NONE);
|
||||
break;
|
||||
}
|
||||
status = 0;
|
||||
/* Don't set requested state to NONE
|
||||
It's done in kgsl_pwrctrl_sleep*/
|
||||
KGSL_PWR_WARN(device, "Done going to slumber\n");
|
||||
return status;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
_sleep_accounting(struct kgsl_device *device)
|
||||
{
|
||||
kgsl_pwrctrl_busy_time(device, false);
|
||||
device->pwrctrl.busy.start.tv_sec = 0;
|
||||
device->pwrctrl.time = 0;
|
||||
kgsl_pwrscale_sleep(device);
|
||||
}
|
||||
|
||||
static int
|
||||
_sleep(struct kgsl_device *device)
|
||||
{
|
||||
struct kgsl_pwrctrl *pwr = &device->pwrctrl;
|
||||
switch (device->state) {
|
||||
case KGSL_STATE_ACTIVE:
|
||||
if (!device->ftbl->isidle(device)) {
|
||||
kgsl_pwrctrl_request_state(device, KGSL_STATE_NONE);
|
||||
return -EBUSY;
|
||||
}
|
||||
/* fall through */
|
||||
case KGSL_STATE_NAP:
|
||||
kgsl_pwrctrl_irq(device, KGSL_PWRFLAGS_OFF);
|
||||
kgsl_pwrctrl_axi(device, KGSL_PWRFLAGS_OFF);
|
||||
if (pwr->pwrlevels[0].gpu_freq > 0)
|
||||
clk_set_rate(pwr->grp_clks[0],
|
||||
pwr->pwrlevels[pwr->num_pwrlevels - 1].
|
||||
gpu_freq);
|
||||
_sleep_accounting(device);
|
||||
kgsl_pwrctrl_clk(device, KGSL_PWRFLAGS_OFF);
|
||||
kgsl_pwrctrl_set_state(device, KGSL_STATE_SLEEP);
|
||||
if (device->idle_wakelock.name)
|
||||
wake_unlock(&device->idle_wakelock);
|
||||
break;
|
||||
case KGSL_STATE_SLEEP:
|
||||
case KGSL_STATE_SLUMBER:
|
||||
break;
|
||||
default:
|
||||
KGSL_PWR_WARN(device, "unhandled state %x\n",
|
||||
device->state);
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
_slumber(struct kgsl_device *device)
|
||||
{
|
||||
switch (device->state) {
|
||||
case KGSL_STATE_ACTIVE:
|
||||
if (!device->ftbl->isidle(device)) {
|
||||
kgsl_pwrctrl_request_state(device, KGSL_STATE_NONE);
|
||||
device->pwrctrl.restore_slumber = true;
|
||||
return -EBUSY;
|
||||
}
|
||||
/* fall through */
|
||||
case KGSL_STATE_NAP:
|
||||
case KGSL_STATE_SLEEP:
|
||||
del_timer_sync(&device->idle_timer);
|
||||
kgsl_pwrctrl_pwrlevel_change(device, KGSL_PWRLEVEL_NOMINAL);
|
||||
device->ftbl->suspend_context(device);
|
||||
device->ftbl->stop(device);
|
||||
device->pwrctrl.restore_slumber = true;
|
||||
_sleep_accounting(device);
|
||||
kgsl_pwrctrl_set_state(device, KGSL_STATE_SLUMBER);
|
||||
if (device->idle_wakelock.name)
|
||||
wake_unlock(&device->idle_wakelock);
|
||||
break;
|
||||
case KGSL_STATE_SLUMBER:
|
||||
break;
|
||||
default:
|
||||
KGSL_PWR_WARN(device, "unhandled state %x\n",
|
||||
device->state);
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/******************************************************************/
|
||||
/* Caller must hold the device mutex. */
|
||||
int kgsl_pwrctrl_sleep(struct kgsl_device *device)
|
||||
{
|
||||
struct kgsl_pwrctrl *pwr = &device->pwrctrl;
|
||||
int status = 0;
|
||||
KGSL_PWR_INFO(device, "sleep device %d\n", device->id);
|
||||
|
||||
/* Work through the legal state transitions */
|
||||
if ((device->requested_state == KGSL_STATE_NAP)) {
|
||||
switch (device->requested_state) {
|
||||
case KGSL_STATE_NAP:
|
||||
if (device->pwrctrl.restore_slumber) {
|
||||
device->requested_state = KGSL_STATE_NONE;
|
||||
return 0;
|
||||
} else if (device->ftbl->isidle(device))
|
||||
goto nap;
|
||||
} else if (device->requested_state == KGSL_STATE_SLEEP) {
|
||||
if (device->state == KGSL_STATE_NAP ||
|
||||
device->ftbl->isidle(device)) {
|
||||
if (!device->pwrctrl.restore_slumber)
|
||||
goto sleep;
|
||||
else
|
||||
goto slumber;
|
||||
}
|
||||
} else if (device->requested_state == KGSL_STATE_SLUMBER) {
|
||||
if (device->state == KGSL_STATE_INIT)
|
||||
return 0;
|
||||
if (device->ftbl->isidle(device))
|
||||
goto slumber;
|
||||
kgsl_pwrctrl_request_state(device, KGSL_STATE_NONE);
|
||||
break;
|
||||
}
|
||||
status = _nap(device);
|
||||
break;
|
||||
case KGSL_STATE_SLEEP:
|
||||
if (device->pwrctrl.restore_slumber)
|
||||
status = _slumber(device);
|
||||
else
|
||||
device->pwrctrl.restore_slumber = true;
|
||||
status = _sleep(device);
|
||||
break;
|
||||
case KGSL_STATE_SLUMBER:
|
||||
status = _slumber(device);
|
||||
break;
|
||||
default:
|
||||
KGSL_PWR_INFO(device, "bad state request 0x%x\n",
|
||||
device->requested_state);
|
||||
kgsl_pwrctrl_request_state(device, KGSL_STATE_NONE);
|
||||
status = -EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
device->requested_state = KGSL_STATE_NONE;
|
||||
return -EBUSY;
|
||||
|
||||
|
||||
slumber:
|
||||
_slumber(device);
|
||||
|
||||
sleep:
|
||||
kgsl_pwrctrl_irq(device, KGSL_PWRFLAGS_OFF);
|
||||
kgsl_pwrctrl_axi(device, KGSL_PWRFLAGS_OFF);
|
||||
if (pwr->pwrlevels[0].gpu_freq > 0)
|
||||
clk_set_rate(pwr->grp_clks[0],
|
||||
pwr->pwrlevels[pwr->num_pwrlevels - 1].
|
||||
gpu_freq);
|
||||
kgsl_pwrctrl_busy_time(device, false);
|
||||
pwr->busy.start.tv_sec = 0;
|
||||
device->pwrctrl.time = 0;
|
||||
|
||||
kgsl_pwrscale_sleep(device);
|
||||
goto clk_off;
|
||||
|
||||
nap:
|
||||
kgsl_pwrctrl_irq(device, KGSL_PWRFLAGS_OFF);
|
||||
clk_off:
|
||||
kgsl_pwrctrl_clk(device, KGSL_PWRFLAGS_OFF);
|
||||
|
||||
device->state = device->requested_state;
|
||||
device->requested_state = KGSL_STATE_NONE;
|
||||
if (device->idle_wakelock.name)
|
||||
wake_unlock(&device->idle_wakelock);
|
||||
KGSL_PWR_WARN(device, "state -> NAP/SLEEP(%d), device %d\n",
|
||||
device->state, device->id);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(kgsl_pwrctrl_sleep);
|
||||
|
||||
static int
|
||||
_wake_from_slumber(struct kgsl_device *device)
|
||||
{
|
||||
int status = -EINVAL;
|
||||
if (!device)
|
||||
return -EINVAL;
|
||||
|
||||
KGSL_PWR_WARN(device, "wake from slumber start\n");
|
||||
|
||||
device->requested_state = KGSL_STATE_ACTIVE;
|
||||
kgsl_pwrctrl_pwrlevel_change(device, KGSL_PWRLEVEL_NOMINAL);
|
||||
status = device->ftbl->start(device, 0);
|
||||
device->requested_state = KGSL_STATE_NONE;
|
||||
|
||||
KGSL_PWR_WARN(device, "Done waking from slumber\n");
|
||||
return status;
|
||||
}
|
||||
EXPORT_SYMBOL(kgsl_pwrctrl_sleep);
|
||||
|
||||
/******************************************************************/
|
||||
/* Caller must hold the device mutex. */
|
||||
void kgsl_pwrctrl_wake(struct kgsl_device *device)
|
||||
{
|
||||
if (device->state & (KGSL_STATE_SUSPEND | KGSL_STATE_INIT))
|
||||
return;
|
||||
|
||||
if (device->state == KGSL_STATE_SLUMBER)
|
||||
_wake_from_slumber(device);
|
||||
|
||||
if (device->state != KGSL_STATE_NAP) {
|
||||
int status;
|
||||
kgsl_pwrctrl_request_state(device, KGSL_STATE_ACTIVE);
|
||||
switch (device->state) {
|
||||
case KGSL_STATE_SLUMBER:
|
||||
status = device->ftbl->start(device, 0);
|
||||
if (status) {
|
||||
kgsl_pwrctrl_request_state(device, KGSL_STATE_NONE);
|
||||
KGSL_DRV_ERR(device, "start failed %d\n", status);
|
||||
break;
|
||||
}
|
||||
/* fall through */
|
||||
case KGSL_STATE_SLEEP:
|
||||
kgsl_pwrctrl_axi(device, KGSL_PWRFLAGS_ON);
|
||||
kgsl_pwrscale_wake(device);
|
||||
}
|
||||
|
||||
/* Turn on the core clocks */
|
||||
kgsl_pwrctrl_clk(device, KGSL_PWRFLAGS_ON);
|
||||
|
||||
/* Enable state before turning on irq */
|
||||
device->state = KGSL_STATE_ACTIVE;
|
||||
KGSL_PWR_WARN(device, "state -> ACTIVE, device %d\n", device->id);
|
||||
kgsl_pwrctrl_irq(device, KGSL_PWRFLAGS_ON);
|
||||
|
||||
/* Re-enable HW access */
|
||||
mod_timer(&device->idle_timer,
|
||||
/* fall through */
|
||||
case KGSL_STATE_NAP:
|
||||
/* Turn on the core clocks */
|
||||
kgsl_pwrctrl_clk(device, KGSL_PWRFLAGS_ON);
|
||||
/* Enable state before turning on irq */
|
||||
kgsl_pwrctrl_set_state(device, KGSL_STATE_ACTIVE);
|
||||
kgsl_pwrctrl_irq(device, KGSL_PWRFLAGS_ON);
|
||||
/* Re-enable HW access */
|
||||
mod_timer(&device->idle_timer,
|
||||
jiffies + device->pwrctrl.interval_timeout);
|
||||
|
||||
if (device->idle_wakelock.name)
|
||||
wake_lock(&device->idle_wakelock);
|
||||
|
||||
KGSL_PWR_INFO(device, "wake return for device %d\n", device->id);
|
||||
if (device->idle_wakelock.name)
|
||||
wake_lock(&device->idle_wakelock);
|
||||
case KGSL_STATE_ACTIVE:
|
||||
break;
|
||||
default:
|
||||
KGSL_PWR_WARN(device, "unhandled state %x\n",
|
||||
device->state);
|
||||
kgsl_pwrctrl_request_state(device, KGSL_STATE_NONE);
|
||||
break;
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(kgsl_pwrctrl_wake);
|
||||
|
||||
@@ -832,3 +862,19 @@ void kgsl_pwrctrl_disable(struct kgsl_device *device)
|
||||
kgsl_pwrctrl_pwrrail(device, KGSL_PWRFLAGS_OFF);
|
||||
}
|
||||
EXPORT_SYMBOL(kgsl_pwrctrl_disable);
|
||||
|
||||
void kgsl_pwrctrl_set_state(struct kgsl_device *device, unsigned int state)
|
||||
{
|
||||
KGSL_PWR_WARN(device, "%x\n", state);
|
||||
device->state = state;
|
||||
device->requested_state = KGSL_STATE_NONE;
|
||||
}
|
||||
EXPORT_SYMBOL(kgsl_pwrctrl_set_state);
|
||||
|
||||
void kgsl_pwrctrl_request_state(struct kgsl_device *device, unsigned int state)
|
||||
{
|
||||
if (state != KGSL_STATE_NONE && state != device->requested_state)
|
||||
KGSL_PWR_INFO(device, "%x\n", state);
|
||||
device->requested_state = state;
|
||||
}
|
||||
EXPORT_SYMBOL(kgsl_pwrctrl_request_state);
|
||||
|
||||
@@ -77,4 +77,6 @@ static inline unsigned long kgsl_get_clkrate(struct clk *clk)
|
||||
return (clk != NULL) ? clk_get_rate(clk) : 0;
|
||||
}
|
||||
|
||||
void kgsl_pwrctrl_set_state(struct kgsl_device *device, unsigned int state);
|
||||
void kgsl_pwrctrl_request_state(struct kgsl_device *device, unsigned int state);
|
||||
#endif /* __KGSL_PWRCTRL_H */
|
||||
|
||||
@@ -248,7 +248,7 @@ static irqreturn_t z180_isr(int irq, void *data)
|
||||
|
||||
if ((device->pwrctrl.nap_allowed == true) &&
|
||||
(device->requested_state == KGSL_STATE_NONE)) {
|
||||
device->requested_state = KGSL_STATE_NAP;
|
||||
kgsl_pwrctrl_request_state(device, KGSL_STATE_NAP);
|
||||
queue_work(device->work_queue, &device->idle_check_ws);
|
||||
}
|
||||
mod_timer(&device->idle_timer,
|
||||
@@ -553,9 +553,7 @@ static int z180_start(struct kgsl_device *device, unsigned int init_ram)
|
||||
{
|
||||
int status = 0;
|
||||
|
||||
device->state = KGSL_STATE_INIT;
|
||||
device->requested_state = KGSL_STATE_NONE;
|
||||
KGSL_PWR_WARN(device, "state -> INIT, device %d\n", device->id);
|
||||
kgsl_pwrctrl_set_state(device, KGSL_STATE_INIT);
|
||||
|
||||
kgsl_pwrctrl_enable(device);
|
||||
|
||||
@@ -836,8 +834,7 @@ static int z180_wait(struct kgsl_device *device,
|
||||
status = 0;
|
||||
else if (timeout == 0) {
|
||||
status = -ETIMEDOUT;
|
||||
device->state = KGSL_STATE_HUNG;
|
||||
KGSL_PWR_WARN(device, "state -> HUNG, device %d\n", device->id);
|
||||
kgsl_pwrctrl_set_state(device, KGSL_STATE_HUNG);
|
||||
} else
|
||||
status = timeout;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user