284 lines · c
1// SPDX-License-Identifier: GPL-2.0 or MIT2/* Copyright 2019 Collabora ltd. */3 4#include <linux/clk.h>5#include <linux/devfreq.h>6#include <linux/devfreq_cooling.h>7#include <linux/platform_device.h>8#include <linux/pm_opp.h>9 10#include <drm/drm_managed.h>11 12#include "panthor_devfreq.h"13#include "panthor_device.h"14 15/**16 * struct panthor_devfreq - Device frequency management17 */18struct panthor_devfreq {19 /** @devfreq: devfreq device. */20 struct devfreq *devfreq;21 22 /** @gov_data: Governor data. */23 struct devfreq_simple_ondemand_data gov_data;24 25 /** @busy_time: Busy time. */26 ktime_t busy_time;27 28 /** @idle_time: Idle time. */29 ktime_t idle_time;30 31 /** @time_last_update: Last update time. */32 ktime_t time_last_update;33 34 /** @last_busy_state: True if the GPU was busy last time we updated the state. */35 bool last_busy_state;36 37 /**38 * @lock: Lock used to protect busy_time, idle_time, time_last_update and39 * last_busy_state.40 *41 * These fields can be accessed concurrently by panthor_devfreq_get_dev_status()42 * and panthor_devfreq_record_{busy,idle}().43 */44 spinlock_t lock;45};46 47static void panthor_devfreq_update_utilization(struct panthor_devfreq *pdevfreq)48{49 ktime_t now, last;50 51 now = ktime_get();52 last = pdevfreq->time_last_update;53 54 if (pdevfreq->last_busy_state)55 pdevfreq->busy_time += ktime_sub(now, last);56 else57 pdevfreq->idle_time += ktime_sub(now, last);58 59 pdevfreq->time_last_update = now;60}61 62static int panthor_devfreq_target(struct device *dev, unsigned long *freq,63 u32 flags)64{65 struct dev_pm_opp *opp;66 67 opp = devfreq_recommended_opp(dev, freq, flags);68 if (IS_ERR(opp))69 return PTR_ERR(opp);70 dev_pm_opp_put(opp);71 72 return dev_pm_opp_set_rate(dev, *freq);73}74 75static void panthor_devfreq_reset(struct panthor_devfreq *pdevfreq)76{77 pdevfreq->busy_time = 0;78 pdevfreq->idle_time = 0;79 pdevfreq->time_last_update = ktime_get();80}81 82static int panthor_devfreq_get_dev_status(struct device *dev,83 struct devfreq_dev_status *status)84{85 struct panthor_device *ptdev = dev_get_drvdata(dev);86 struct panthor_devfreq *pdevfreq = ptdev->devfreq;87 unsigned long irqflags;88 89 status->current_frequency = clk_get_rate(ptdev->clks.core);90 91 spin_lock_irqsave(&pdevfreq->lock, irqflags);92 93 panthor_devfreq_update_utilization(pdevfreq);94 95 status->total_time = ktime_to_ns(ktime_add(pdevfreq->busy_time,96 pdevfreq->idle_time));97 98 status->busy_time = ktime_to_ns(pdevfreq->busy_time);99 100 panthor_devfreq_reset(pdevfreq);101 102 spin_unlock_irqrestore(&pdevfreq->lock, irqflags);103 104 drm_dbg(&ptdev->base, "busy %lu total %lu %lu %% freq %lu MHz\n",105 status->busy_time, status->total_time,106 status->busy_time / (status->total_time / 100),107 status->current_frequency / 1000 / 1000);108 109 return 0;110}111 112static struct devfreq_dev_profile panthor_devfreq_profile = {113 .timer = DEVFREQ_TIMER_DELAYED,114 .polling_ms = 50, /* ~3 frames */115 .target = panthor_devfreq_target,116 .get_dev_status = panthor_devfreq_get_dev_status,117};118 119int panthor_devfreq_init(struct panthor_device *ptdev)120{121 /* There's actually 2 regulators (mali and sram), but the OPP core only122 * supports one.123 *124 * We assume the sram regulator is coupled with the mali one and let125 * the coupling logic deal with voltage updates.126 */127 static const char * const reg_names[] = { "mali", NULL };128 struct thermal_cooling_device *cooling;129 struct device *dev = ptdev->base.dev;130 struct panthor_devfreq *pdevfreq;131 struct dev_pm_opp *opp;132 unsigned long cur_freq;133 int ret;134 135 pdevfreq = drmm_kzalloc(&ptdev->base, sizeof(*ptdev->devfreq), GFP_KERNEL);136 if (!pdevfreq)137 return -ENOMEM;138 139 ptdev->devfreq = pdevfreq;140 141 ret = devm_pm_opp_set_regulators(dev, reg_names);142 if (ret) {143 if (ret != -EPROBE_DEFER)144 DRM_DEV_ERROR(dev, "Couldn't set OPP regulators\n");145 146 return ret;147 }148 149 ret = devm_pm_opp_of_add_table(dev);150 if (ret)151 return ret;152 153 spin_lock_init(&pdevfreq->lock);154 155 panthor_devfreq_reset(pdevfreq);156 157 cur_freq = clk_get_rate(ptdev->clks.core);158 159 opp = devfreq_recommended_opp(dev, &cur_freq, 0);160 if (IS_ERR(opp))161 return PTR_ERR(opp);162 163 panthor_devfreq_profile.initial_freq = cur_freq;164 165 /* Regulator coupling only takes care of synchronizing/balancing voltage166 * updates, but the coupled regulator needs to be enabled manually.167 *168 * We use devm_regulator_get_enable_optional() and keep the sram supply169 * enabled until the device is removed, just like we do for the mali170 * supply, which is enabled when dev_pm_opp_set_opp(dev, opp) is called,171 * and disabled when the opp_table is torn down, using the devm action.172 *173 * If we really care about disabling regulators on suspend, we should:174 * - use devm_regulator_get_optional() here175 * - call dev_pm_opp_set_opp(dev, NULL) before leaving this function176 * (this disables the regulator passed to the OPP layer)177 * - call dev_pm_opp_set_opp(dev, NULL) and178 * regulator_disable(ptdev->regulators.sram) in179 * panthor_devfreq_suspend()180 * - call dev_pm_opp_set_opp(dev, default_opp) and181 * regulator_enable(ptdev->regulators.sram) in182 * panthor_devfreq_resume()183 *184 * But without knowing if it's beneficial or not (in term of power185 * consumption), or how much it slows down the suspend/resume steps,186 * let's just keep regulators enabled for the device lifetime.187 */188 ret = devm_regulator_get_enable_optional(dev, "sram");189 if (ret && ret != -ENODEV) {190 if (ret != -EPROBE_DEFER)191 DRM_DEV_ERROR(dev, "Couldn't retrieve/enable sram supply\n");192 return ret;193 }194 195 /*196 * Set the recommend OPP this will enable and configure the regulator197 * if any and will avoid a switch off by regulator_late_cleanup()198 */199 ret = dev_pm_opp_set_opp(dev, opp);200 if (ret) {201 DRM_DEV_ERROR(dev, "Couldn't set recommended OPP\n");202 return ret;203 }204 205 dev_pm_opp_put(opp);206 207 /*208 * Setup default thresholds for the simple_ondemand governor.209 * The values are chosen based on experiments.210 */211 pdevfreq->gov_data.upthreshold = 45;212 pdevfreq->gov_data.downdifferential = 5;213 214 pdevfreq->devfreq = devm_devfreq_add_device(dev, &panthor_devfreq_profile,215 DEVFREQ_GOV_SIMPLE_ONDEMAND,216 &pdevfreq->gov_data);217 if (IS_ERR(pdevfreq->devfreq)) {218 DRM_DEV_ERROR(dev, "Couldn't initialize GPU devfreq\n");219 ret = PTR_ERR(pdevfreq->devfreq);220 pdevfreq->devfreq = NULL;221 return ret;222 }223 224 cooling = devfreq_cooling_em_register(pdevfreq->devfreq, NULL);225 if (IS_ERR(cooling))226 DRM_DEV_INFO(dev, "Failed to register cooling device\n");227 228 return 0;229}230 231int panthor_devfreq_resume(struct panthor_device *ptdev)232{233 struct panthor_devfreq *pdevfreq = ptdev->devfreq;234 235 if (!pdevfreq->devfreq)236 return 0;237 238 panthor_devfreq_reset(pdevfreq);239 240 return devfreq_resume_device(pdevfreq->devfreq);241}242 243int panthor_devfreq_suspend(struct panthor_device *ptdev)244{245 struct panthor_devfreq *pdevfreq = ptdev->devfreq;246 247 if (!pdevfreq->devfreq)248 return 0;249 250 return devfreq_suspend_device(pdevfreq->devfreq);251}252 253void panthor_devfreq_record_busy(struct panthor_device *ptdev)254{255 struct panthor_devfreq *pdevfreq = ptdev->devfreq;256 unsigned long irqflags;257 258 if (!pdevfreq->devfreq)259 return;260 261 spin_lock_irqsave(&pdevfreq->lock, irqflags);262 263 panthor_devfreq_update_utilization(pdevfreq);264 pdevfreq->last_busy_state = true;265 266 spin_unlock_irqrestore(&pdevfreq->lock, irqflags);267}268 269void panthor_devfreq_record_idle(struct panthor_device *ptdev)270{271 struct panthor_devfreq *pdevfreq = ptdev->devfreq;272 unsigned long irqflags;273 274 if (!pdevfreq->devfreq)275 return;276 277 spin_lock_irqsave(&pdevfreq->lock, irqflags);278 279 panthor_devfreq_update_utilization(pdevfreq);280 pdevfreq->last_busy_state = false;281 282 spin_unlock_irqrestore(&pdevfreq->lock, irqflags);283}284