Loading Documentation/devicetree/bindings/gpu/adreno.txt +6 −0 Original line number Diff line number Diff line Loading @@ -143,6 +143,12 @@ Optional Properties: Specify the name of GPU temperature sensor. This name will be used to get the temperature from the thermal driver API. - qcom,enable-midframe-timer: Boolean. Enables the use of midframe sampling timer. This timer samples the GPU powerstats if the cmdbatch expiry takes longer than the threshold set by KGSL_GOVERNOR_CALL_INTERVAL. Enable only if target has NAP state enabled. GPU Quirks: - qcom,gpu-quirk-two-pass-use-wfi: Signal the GPU to set Set TWOPASSUSEWFI bit in Loading drivers/gpu/msm/adreno_dispatch.c +10 −0 Original line number Diff line number Diff line Loading @@ -604,6 +604,16 @@ static int sendcmd(struct adreno_device *adreno_dev, if (!test_and_set_bit(ADRENO_DISPATCHER_ACTIVE, &dispatcher->priv)) reinit_completion(&dispatcher->idle_gate); /* * We update power stats generally at the expire of * cmdbatch. In cases where the cmdbatch takes a long * time to finish, it will delay power stats update, * in effect it will delay DCVS decision. Start a * timer to update power state on expire of this timer. */ kgsl_pwrscale_midframe_timer_restart(device); } else { kgsl_active_count_put(device); clear_bit(ADRENO_DISPATCHER_POWER, &dispatcher->priv); Loading drivers/gpu/msm/kgsl_pwrctrl.c +5 −0 Original line number Diff line number Diff line Loading @@ -2355,6 +2355,7 @@ static int _init(struct kgsl_device *device) case KGSL_STATE_ACTIVE: kgsl_pwrctrl_irq(device, KGSL_PWRFLAGS_OFF); del_timer_sync(&device->idle_timer); kgsl_pwrscale_midframe_timer_cancel(device); device->ftbl->stop(device); /* fall through */ case KGSL_STATE_AWARE: Loading Loading @@ -2462,6 +2463,7 @@ _aware(struct kgsl_device *device) case KGSL_STATE_ACTIVE: kgsl_pwrctrl_irq(device, KGSL_PWRFLAGS_OFF); del_timer_sync(&device->idle_timer); kgsl_pwrscale_midframe_timer_cancel(device); break; case KGSL_STATE_SLUMBER: status = kgsl_pwrctrl_enable(device); Loading @@ -2486,6 +2488,8 @@ _nap(struct kgsl_device *device) return -EBUSY; } kgsl_pwrscale_midframe_timer_cancel(device); /* * Read HW busy counters before going to NAP state. * The data might be used by power scale governors Loading Loading @@ -2522,6 +2526,7 @@ _slumber(struct kgsl_device *device) /* fall through */ case KGSL_STATE_NAP: del_timer_sync(&device->idle_timer); kgsl_pwrscale_midframe_timer_cancel(device); if (device->pwrctrl.thermal_cycle == CYCLE_ACTIVE) { device->pwrctrl.thermal_cycle = CYCLE_ENABLE; del_timer_sync(&device->pwrctrl.thermal_timer); Loading drivers/gpu/msm/kgsl_pwrscale.c +79 −0 Original line number Diff line number Diff line Loading @@ -13,6 +13,7 @@ #include <linux/export.h> #include <linux/kernel.h> #include <linux/hrtimer.h> #include "kgsl.h" #include "kgsl_pwrscale.h" Loading @@ -37,6 +38,18 @@ static struct kgsl_popp popp_param[POPP_MAX] = { {0, 0}, }; /** * struct kgsl_midframe_info - midframe power stats sampling info * @timer - midframe sampling timer * @timer_check_ws - Updates powerstats on midframe expiry * @device - pointer to kgsl_device */ static struct kgsl_midframe_info { struct hrtimer timer; struct work_struct timer_check_ws; struct kgsl_device *device; } *kgsl_midframe = NULL; static void do_devfreq_suspend(struct work_struct *work); static void do_devfreq_resume(struct work_struct *work); static void do_devfreq_notify(struct work_struct *work); Loading Loading @@ -183,9 +196,57 @@ void kgsl_pwrscale_update(struct kgsl_device *device) if (device->state != KGSL_STATE_SLUMBER) queue_work(device->pwrscale.devfreq_wq, &device->pwrscale.devfreq_notify_ws); kgsl_pwrscale_midframe_timer_restart(device); } EXPORT_SYMBOL(kgsl_pwrscale_update); void kgsl_pwrscale_midframe_timer_restart(struct kgsl_device *device) { if (kgsl_midframe) { WARN_ON(!mutex_is_locked(&device->mutex)); /* If the timer is already running, stop it */ if (hrtimer_active(&kgsl_midframe->timer)) hrtimer_cancel( &kgsl_midframe->timer); hrtimer_start(&kgsl_midframe->timer, ns_to_ktime(KGSL_GOVERNOR_CALL_INTERVAL * NSEC_PER_USEC), HRTIMER_MODE_REL); } } EXPORT_SYMBOL(kgsl_pwrscale_midframe_timer_restart); void kgsl_pwrscale_midframe_timer_cancel(struct kgsl_device *device) { if (kgsl_midframe) { WARN_ON(!mutex_is_locked(&device->mutex)); hrtimer_cancel(&kgsl_midframe->timer); } } EXPORT_SYMBOL(kgsl_pwrscale_midframe_timer_cancel); static void kgsl_pwrscale_midframe_timer_check(struct work_struct *work) { struct kgsl_device *device = kgsl_midframe->device; mutex_lock(&device->mutex); if (device->state == KGSL_STATE_ACTIVE) kgsl_pwrscale_update(device); mutex_unlock(&device->mutex); } static enum hrtimer_restart kgsl_pwrscale_midframe_timer(struct hrtimer *timer) { struct kgsl_device *device = kgsl_midframe->device; queue_work(device->pwrscale.devfreq_wq, &kgsl_midframe->timer_check_ws); return HRTIMER_NORESTART; } /* * kgsl_pwrscale_disable - temporarily disable the governor * @device: The device Loading Loading @@ -852,6 +913,17 @@ int kgsl_pwrscale_init(struct device *dev, const char *governor) data->bin.ctxt_aware_busy_penalty = 12000; } if (of_property_read_bool(device->pdev->dev.of_node, "qcom,enable-midframe-timer")) { kgsl_midframe = kzalloc( sizeof(struct kgsl_midframe_info), GFP_KERNEL); hrtimer_init(&kgsl_midframe->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); kgsl_midframe->timer.function = kgsl_pwrscale_midframe_timer; kgsl_midframe->device = device; } /* * If there is a separate GX power rail, allow * independent modification to its voltage through Loading Loading @@ -900,6 +972,9 @@ int kgsl_pwrscale_init(struct device *dev, const char *governor) INIT_WORK(&pwrscale->devfreq_suspend_ws, do_devfreq_suspend); INIT_WORK(&pwrscale->devfreq_resume_ws, do_devfreq_resume); INIT_WORK(&pwrscale->devfreq_notify_ws, do_devfreq_notify); if (kgsl_midframe) INIT_WORK(&kgsl_midframe->timer_check_ws, kgsl_pwrscale_midframe_timer_check); pwrscale->next_governor_call = ktime_add_us(ktime_get(), KGSL_GOVERNOR_CALL_INTERVAL); Loading Loading @@ -940,9 +1015,13 @@ void kgsl_pwrscale_close(struct kgsl_device *device) pwrscale = &device->pwrscale; if (!pwrscale->devfreqptr) return; kgsl_pwrscale_midframe_timer_cancel(device); flush_workqueue(pwrscale->devfreq_wq); destroy_workqueue(pwrscale->devfreq_wq); devfreq_remove_device(device->pwrscale.devfreqptr); kfree(kgsl_midframe); kgsl_midframe = NULL; device->pwrscale.devfreqptr = NULL; srcu_cleanup_notifier_head(&device->pwrscale.nh); for (i = 0; i < KGSL_PWREVENT_MAX; i++) Loading drivers/gpu/msm/kgsl_pwrscale.h +3 −0 Original line number Diff line number Diff line Loading @@ -122,6 +122,9 @@ void kgsl_pwrscale_busy(struct kgsl_device *device); void kgsl_pwrscale_sleep(struct kgsl_device *device); void kgsl_pwrscale_wake(struct kgsl_device *device); void kgsl_pwrscale_midframe_timer_restart(struct kgsl_device *device); void kgsl_pwrscale_midframe_timer_cancel(struct kgsl_device *device); void kgsl_pwrscale_enable(struct kgsl_device *device); void kgsl_pwrscale_disable(struct kgsl_device *device, bool turbo); Loading Loading
Documentation/devicetree/bindings/gpu/adreno.txt +6 −0 Original line number Diff line number Diff line Loading @@ -143,6 +143,12 @@ Optional Properties: Specify the name of GPU temperature sensor. This name will be used to get the temperature from the thermal driver API. - qcom,enable-midframe-timer: Boolean. Enables the use of midframe sampling timer. This timer samples the GPU powerstats if the cmdbatch expiry takes longer than the threshold set by KGSL_GOVERNOR_CALL_INTERVAL. Enable only if target has NAP state enabled. GPU Quirks: - qcom,gpu-quirk-two-pass-use-wfi: Signal the GPU to set Set TWOPASSUSEWFI bit in Loading
drivers/gpu/msm/adreno_dispatch.c +10 −0 Original line number Diff line number Diff line Loading @@ -604,6 +604,16 @@ static int sendcmd(struct adreno_device *adreno_dev, if (!test_and_set_bit(ADRENO_DISPATCHER_ACTIVE, &dispatcher->priv)) reinit_completion(&dispatcher->idle_gate); /* * We update power stats generally at the expire of * cmdbatch. In cases where the cmdbatch takes a long * time to finish, it will delay power stats update, * in effect it will delay DCVS decision. Start a * timer to update power state on expire of this timer. */ kgsl_pwrscale_midframe_timer_restart(device); } else { kgsl_active_count_put(device); clear_bit(ADRENO_DISPATCHER_POWER, &dispatcher->priv); Loading
drivers/gpu/msm/kgsl_pwrctrl.c +5 −0 Original line number Diff line number Diff line Loading @@ -2355,6 +2355,7 @@ static int _init(struct kgsl_device *device) case KGSL_STATE_ACTIVE: kgsl_pwrctrl_irq(device, KGSL_PWRFLAGS_OFF); del_timer_sync(&device->idle_timer); kgsl_pwrscale_midframe_timer_cancel(device); device->ftbl->stop(device); /* fall through */ case KGSL_STATE_AWARE: Loading Loading @@ -2462,6 +2463,7 @@ _aware(struct kgsl_device *device) case KGSL_STATE_ACTIVE: kgsl_pwrctrl_irq(device, KGSL_PWRFLAGS_OFF); del_timer_sync(&device->idle_timer); kgsl_pwrscale_midframe_timer_cancel(device); break; case KGSL_STATE_SLUMBER: status = kgsl_pwrctrl_enable(device); Loading @@ -2486,6 +2488,8 @@ _nap(struct kgsl_device *device) return -EBUSY; } kgsl_pwrscale_midframe_timer_cancel(device); /* * Read HW busy counters before going to NAP state. * The data might be used by power scale governors Loading Loading @@ -2522,6 +2526,7 @@ _slumber(struct kgsl_device *device) /* fall through */ case KGSL_STATE_NAP: del_timer_sync(&device->idle_timer); kgsl_pwrscale_midframe_timer_cancel(device); if (device->pwrctrl.thermal_cycle == CYCLE_ACTIVE) { device->pwrctrl.thermal_cycle = CYCLE_ENABLE; del_timer_sync(&device->pwrctrl.thermal_timer); Loading
drivers/gpu/msm/kgsl_pwrscale.c +79 −0 Original line number Diff line number Diff line Loading @@ -13,6 +13,7 @@ #include <linux/export.h> #include <linux/kernel.h> #include <linux/hrtimer.h> #include "kgsl.h" #include "kgsl_pwrscale.h" Loading @@ -37,6 +38,18 @@ static struct kgsl_popp popp_param[POPP_MAX] = { {0, 0}, }; /** * struct kgsl_midframe_info - midframe power stats sampling info * @timer - midframe sampling timer * @timer_check_ws - Updates powerstats on midframe expiry * @device - pointer to kgsl_device */ static struct kgsl_midframe_info { struct hrtimer timer; struct work_struct timer_check_ws; struct kgsl_device *device; } *kgsl_midframe = NULL; static void do_devfreq_suspend(struct work_struct *work); static void do_devfreq_resume(struct work_struct *work); static void do_devfreq_notify(struct work_struct *work); Loading Loading @@ -183,9 +196,57 @@ void kgsl_pwrscale_update(struct kgsl_device *device) if (device->state != KGSL_STATE_SLUMBER) queue_work(device->pwrscale.devfreq_wq, &device->pwrscale.devfreq_notify_ws); kgsl_pwrscale_midframe_timer_restart(device); } EXPORT_SYMBOL(kgsl_pwrscale_update); void kgsl_pwrscale_midframe_timer_restart(struct kgsl_device *device) { if (kgsl_midframe) { WARN_ON(!mutex_is_locked(&device->mutex)); /* If the timer is already running, stop it */ if (hrtimer_active(&kgsl_midframe->timer)) hrtimer_cancel( &kgsl_midframe->timer); hrtimer_start(&kgsl_midframe->timer, ns_to_ktime(KGSL_GOVERNOR_CALL_INTERVAL * NSEC_PER_USEC), HRTIMER_MODE_REL); } } EXPORT_SYMBOL(kgsl_pwrscale_midframe_timer_restart); void kgsl_pwrscale_midframe_timer_cancel(struct kgsl_device *device) { if (kgsl_midframe) { WARN_ON(!mutex_is_locked(&device->mutex)); hrtimer_cancel(&kgsl_midframe->timer); } } EXPORT_SYMBOL(kgsl_pwrscale_midframe_timer_cancel); static void kgsl_pwrscale_midframe_timer_check(struct work_struct *work) { struct kgsl_device *device = kgsl_midframe->device; mutex_lock(&device->mutex); if (device->state == KGSL_STATE_ACTIVE) kgsl_pwrscale_update(device); mutex_unlock(&device->mutex); } static enum hrtimer_restart kgsl_pwrscale_midframe_timer(struct hrtimer *timer) { struct kgsl_device *device = kgsl_midframe->device; queue_work(device->pwrscale.devfreq_wq, &kgsl_midframe->timer_check_ws); return HRTIMER_NORESTART; } /* * kgsl_pwrscale_disable - temporarily disable the governor * @device: The device Loading Loading @@ -852,6 +913,17 @@ int kgsl_pwrscale_init(struct device *dev, const char *governor) data->bin.ctxt_aware_busy_penalty = 12000; } if (of_property_read_bool(device->pdev->dev.of_node, "qcom,enable-midframe-timer")) { kgsl_midframe = kzalloc( sizeof(struct kgsl_midframe_info), GFP_KERNEL); hrtimer_init(&kgsl_midframe->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); kgsl_midframe->timer.function = kgsl_pwrscale_midframe_timer; kgsl_midframe->device = device; } /* * If there is a separate GX power rail, allow * independent modification to its voltage through Loading Loading @@ -900,6 +972,9 @@ int kgsl_pwrscale_init(struct device *dev, const char *governor) INIT_WORK(&pwrscale->devfreq_suspend_ws, do_devfreq_suspend); INIT_WORK(&pwrscale->devfreq_resume_ws, do_devfreq_resume); INIT_WORK(&pwrscale->devfreq_notify_ws, do_devfreq_notify); if (kgsl_midframe) INIT_WORK(&kgsl_midframe->timer_check_ws, kgsl_pwrscale_midframe_timer_check); pwrscale->next_governor_call = ktime_add_us(ktime_get(), KGSL_GOVERNOR_CALL_INTERVAL); Loading Loading @@ -940,9 +1015,13 @@ void kgsl_pwrscale_close(struct kgsl_device *device) pwrscale = &device->pwrscale; if (!pwrscale->devfreqptr) return; kgsl_pwrscale_midframe_timer_cancel(device); flush_workqueue(pwrscale->devfreq_wq); destroy_workqueue(pwrscale->devfreq_wq); devfreq_remove_device(device->pwrscale.devfreqptr); kfree(kgsl_midframe); kgsl_midframe = NULL; device->pwrscale.devfreqptr = NULL; srcu_cleanup_notifier_head(&device->pwrscale.nh); for (i = 0; i < KGSL_PWREVENT_MAX; i++) Loading
drivers/gpu/msm/kgsl_pwrscale.h +3 −0 Original line number Diff line number Diff line Loading @@ -122,6 +122,9 @@ void kgsl_pwrscale_busy(struct kgsl_device *device); void kgsl_pwrscale_sleep(struct kgsl_device *device); void kgsl_pwrscale_wake(struct kgsl_device *device); void kgsl_pwrscale_midframe_timer_restart(struct kgsl_device *device); void kgsl_pwrscale_midframe_timer_cancel(struct kgsl_device *device); void kgsl_pwrscale_enable(struct kgsl_device *device); void kgsl_pwrscale_disable(struct kgsl_device *device, bool turbo); Loading