/* Caller must hold the device mutex. */ int kgsl_pwrctrl_sleep(struct kgsl_device *device) { int status = 0; KGSL_PWR_INFO(device, "sleep device %d\n", device->id); /* Work through the legal state transitions */ switch (device->requested_state) { case KGSL_STATE_NAP: if (device->pwrctrl.restore_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 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; } return status; }
void kgsl_pwrctrl_axi(struct kgsl_device *device, int state) { struct kgsl_pwrctrl *pwr = &device->pwrctrl; if (state == KGSL_PWRFLAGS_OFF) { if (test_and_clear_bit(KGSL_PWRFLAGS_AXI_ON, &pwr->power_flags)) { KGSL_PWR_INFO(device, "axi off, device %d\n", device->id); if (pwr->ebi1_clk) { clk_set_rate(pwr->ebi1_clk, 0); clk_disable(pwr->ebi1_clk); } if (pwr->pcl) msm_bus_scale_client_update_request(pwr->pcl, 0); } } else if (state == KGSL_PWRFLAGS_ON) { if (!test_and_set_bit(KGSL_PWRFLAGS_AXI_ON, &pwr->power_flags)) { KGSL_PWR_INFO(device, "axi on, device %d\n", device->id); if (pwr->ebi1_clk) { clk_enable(pwr->ebi1_clk); clk_set_rate(pwr->ebi1_clk, pwr->pwrlevels[pwr->active_pwrlevel]. bus_freq); } if (pwr->pcl) msm_bus_scale_client_update_request(pwr->pcl, pwr->pwrlevels[pwr->active_pwrlevel]. bus_freq); } } }
void kgsl_pwrctrl_axi(struct kgsl_device *device, int state) { struct kgsl_pwrctrl *pwr = &device->pwrctrl; if (state == KGSL_PWRFLAGS_OFF) { if (test_and_clear_bit(KGSL_PWRFLAGS_AXI_ON, &pwr->power_flags)) { KGSL_PWR_INFO(device, "axi off, device %d\n", device->id); if (pwr->ebi1_clk) { clk_set_rate(pwr->ebi1_clk, 0); clk_disable(pwr->ebi1_clk); } pm_qos_update_requirement(PM_QOS_SYSTEM_BUS_FREQ, "kgsl_3d", PM_QOS_DEFAULT_VALUE); } } else if (state == KGSL_PWRFLAGS_ON) { if (!test_and_set_bit(KGSL_PWRFLAGS_AXI_ON, &pwr->power_flags)) { KGSL_PWR_INFO(device, "axi on, device %d\n", device->id); pm_qos_update_requirement(PM_QOS_SYSTEM_BUS_FREQ, "kgsl_3d", pwr->pwrlevels[pwr->active_pwrlevel]. bus_freq/1000); if (pwr->ebi1_clk) { clk_enable(pwr->ebi1_clk); clk_set_rate(pwr->ebi1_clk, pwr->pwrlevels[pwr->active_pwrlevel]. bus_freq); } } } }
void kgsl_pwrctrl_pwrrail(struct kgsl_device *device, int state) { struct kgsl_pwrctrl *pwr = &device->pwrctrl; if (state == KGSL_PWRFLAGS_OFF) { if (test_and_clear_bit(KGSL_PWRFLAGS_POWER_ON, &pwr->power_flags)) { KGSL_PWR_INFO(device, "power off, device %d\n", device->id); if (internal_pwr_rail_ctl(pwr->pwr_rail, false)) { KGSL_DRV_ERR(device, "call internal_pwr_rail_ctl failed\n"); return; } if (pwr->gpu_reg) regulator_disable(pwr->gpu_reg); } } else if (state == KGSL_PWRFLAGS_ON) { if (!test_and_set_bit(KGSL_PWRFLAGS_POWER_ON, &pwr->power_flags)) { KGSL_PWR_INFO(device, "power on, device %d\n", device->id); if (internal_pwr_rail_ctl(pwr->pwr_rail, true)) { KGSL_PWR_ERR(device, "call internal_pwr_rail_ctl failed\n"); return; } if (pwr->gpu_reg) regulator_enable(pwr->gpu_reg); } } }
void kgsl_pwrctrl_irq(struct kgsl_device *device, int state) { struct kgsl_pwrctrl *pwr = &device->pwrctrl; if (state == KGSL_PWRFLAGS_ON) { if (!test_and_set_bit(KGSL_PWRFLAGS_IRQ_ON, &pwr->power_flags)) { KGSL_PWR_INFO(device, "irq on, device %d\n", device->id); enable_irq(pwr->interrupt_num); device->ftbl->irqctrl(device, 1); } } else if (state == KGSL_PWRFLAGS_OFF) { if (test_and_clear_bit(KGSL_PWRFLAGS_IRQ_ON, &pwr->power_flags)) { KGSL_PWR_INFO(device, "irq off, device %d\n", device->id); device->ftbl->irqctrl(device, 0); if (in_interrupt()) disable_irq_nosync(pwr->interrupt_num); else disable_irq(pwr->interrupt_num); } } }
/* Caller must hold the device mutex. */ void kgsl_pwrctrl_wake(struct kgsl_device *device) { if (device->state == KGSL_STATE_SUSPEND) return; if (device->state != KGSL_STATE_NAP) { 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, jiffies + device->pwrctrl.interval_timeout); wake_lock(&device->idle_wakelock); pm_qos_update_request(&device->pm_qos_req_dma, GPU_SWFI_LATENCY); KGSL_PWR_INFO(device, "wake return for device %d\n", device->id); }
void kgsl_timer(unsigned long data) { struct kgsl_device *device = (struct kgsl_device *) 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; /* Have work run in a non-interrupt context. */ queue_work(device->work_queue, &device->idle_check_ws); } }
void kgsl_pwrctrl_clk(struct kgsl_device *device, int state, int requested_state) { struct kgsl_pwrctrl *pwr = &device->pwrctrl; int i = 0; if (state == KGSL_PWRFLAGS_OFF) { if (test_and_clear_bit(KGSL_PWRFLAGS_CLK_ON, &pwr->power_flags)) { KGSL_PWR_INFO(device, "clocks off, device %d\n", device->id); for (i = KGSL_MAX_CLKS - 1; i > 0; i--) if (pwr->grp_clks[i]) clk_disable(pwr->grp_clks[i]); if ((pwr->pwrlevels[0].gpu_freq > 0) && (requested_state != KGSL_STATE_NAP)) clk_set_rate(pwr->grp_clks[0], pwr->pwrlevels[pwr->num_pwrlevels - 1]. gpu_freq); kgsl_pwrctrl_busy_time(device, true); } } else if (state == KGSL_PWRFLAGS_ON) { if (!test_and_set_bit(KGSL_PWRFLAGS_CLK_ON, &pwr->power_flags)) { KGSL_PWR_INFO(device, "clocks on, device %d\n", device->id); if ((pwr->pwrlevels[0].gpu_freq > 0) && (device->state != KGSL_STATE_NAP)) clk_set_rate(pwr->grp_clks[0], pwr->pwrlevels[pwr->active_pwrlevel]. gpu_freq); /* as last step, enable grp_clk this is to let GPU interrupt to come */ for (i = KGSL_MAX_CLKS - 1; i > 0; i--) if (pwr->grp_clks[i]) clk_enable(pwr->grp_clks[i]); kgsl_pwrctrl_busy_time(device, false); } } }
void kgsl_pwrctrl_pwrrail(struct kgsl_device *device, int state) { struct kgsl_pwrctrl *pwr = &device->pwrctrl; if (state == KGSL_PWRFLAGS_OFF) { if (test_and_clear_bit(KGSL_PWRFLAGS_POWER_ON, &pwr->power_flags)) { KGSL_PWR_INFO(device, "power off, device %d\n", device->id); if (pwr->gpu_reg) regulator_disable(pwr->gpu_reg); } } else if (state == KGSL_PWRFLAGS_ON) { if (!test_and_set_bit(KGSL_PWRFLAGS_POWER_ON, &pwr->power_flags)) { KGSL_PWR_INFO(device, "power on, device %d\n", device->id); if (pwr->gpu_reg) regulator_enable(pwr->gpu_reg); } } }
void kgsl_timer(unsigned long data) { struct kgsl_device *device = (struct kgsl_device *) data; KGSL_PWR_INFO(device, "idle timer expired device %d\n", device->id); if (device->requested_state != KGSL_STATE_SUSPEND) { if (device->pwrctrl.restore_slumber) kgsl_pwrctrl_request_state(device, KGSL_STATE_SLUMBER); else 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); } }
/* Caller must hold the device mutex. */ int kgsl_pwrctrl_sleep(struct kgsl_device *device) { //struct kgsl_pwrctrl *pwr = &device->pwrctrl; KGSL_PWR_INFO(device, "sleep device %d\n", device->id); /* Work through the legal state transitions */ if (device->requested_state == KGSL_STATE_NAP) { 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)) goto sleep; } device->requested_state = KGSL_STATE_NONE; return -EBUSY; sleep: device->ftbl->suspend_context(device); device->ftbl->stop(device); kgsl_pwrctrl_irq(device, KGSL_PWRFLAGS_OFF); kgsl_pwrctrl_axi(device, KGSL_PWRFLAGS_OFF); #if 0 if (pwr->pwrlevels[0].gpu_freq > 0) clk_set_rate(pwr->grp_clks[0], pwr->pwrlevels[pwr->num_pwrlevels - 1]. gpu_freq); #endif 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; wake_unlock(&device->idle_wakelock); pm_qos_update_request(&device->pm_qos_req_dma, PM_QOS_DEFAULT_VALUE); KGSL_PWR_WARN(device, "state -> NAP/SLEEP(%d), device %d\n", device->state, device->id); return 0; }
/* Caller must hold the device mutex. */ int kgsl_pwrctrl_sleep(struct kgsl_device *device) { struct kgsl_pwrctrl *pwr = &device->pwrctrl; KGSL_PWR_INFO(device, "sleep device %d\n", device->id); /* Work through the legal state transitions */ if (device->requested_state == KGSL_STATE_NAP) { 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)) goto sleep; } device->requested_state = KGSL_STATE_NONE; return -EBUSY; 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; wake_unlock(&device->idle_wakelock); // pm_qos_update_request(PM_QOS_CPU_DMA_LATENCY, // PM_QOS_DEFAULT_VALUE); KGSL_PWR_WARN(device, "state -> NAP/SLEEP(%d), device %d\n", device->state, device->id); return 0; }
void kgsl_pwrctrl_close(struct kgsl_device *device) { struct kgsl_pwrctrl *pwr = &device->pwrctrl; int i; KGSL_PWR_INFO(device, "close device %d\n", device->id); unregister_early_suspend(&device->display_off); if (pwr->interrupt_num > 0) { if (pwr->have_irq) { free_irq(pwr->interrupt_num, NULL); pwr->have_irq = 0; } pwr->interrupt_num = 0; } clk_put(pwr->ebi1_clk); if (pwr->pcl) msm_bus_scale_unregister_client(pwr->pcl); pwr->pcl = 0; if (pwr->gpu_reg) { regulator_put(pwr->gpu_reg); pwr->gpu_reg = NULL; } for (i = 1; i < KGSL_MAX_CLKS; i++) if (pwr->grp_clks[i]) { clk_put(pwr->grp_clks[i]); pwr->grp_clks[i] = NULL; } pwr->grp_clks[0] = NULL; pwr->power_flags = 0; }
/* Caller must hold the device mutex. */ void kgsl_pwrctrl_wake(struct kgsl_device *device) { int status; struct adreno_device *adreno_dev = ADRENO_DEVICE(device); if (device->state == KGSL_STATE_SUSPEND) return; if (device->state == KGSL_STATE_SLEEP) { device->requested_state = KGSL_STATE_ACTIVE; status = device->ftbl->start(device, 0); if (status != 0) { KGSL_DRV_ERR(device, "start failed %d\n", status); return; } } if (device->state != KGSL_STATE_NAP) { 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 ts 0x%x\n", device->id, adreno_dev->ringbuffer.timestamp); kgsl_pwrctrl_irq(device, KGSL_PWRFLAGS_ON); /* Re-enable HW access */ mod_timer(&device->idle_timer, jiffies + device->pwrctrl.interval_timeout); wake_lock(&device->idle_wakelock); pm_qos_update_request(&device->pm_qos_req_dma, GPU_SWFI_LATENCY); KGSL_PWR_INFO(device, "wake return for device %d\n", device->id); }
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; }