Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * Copyright 2020 Martin Blumenstingl <martin.blumenstingl@googlemail.com>
0004  *
0005  * Based on panfrost_devfreq.c:
0006  *   Copyright 2019 Collabora ltd.
0007  */
0008 #include <linux/clk.h>
0009 #include <linux/devfreq.h>
0010 #include <linux/devfreq_cooling.h>
0011 #include <linux/device.h>
0012 #include <linux/platform_device.h>
0013 #include <linux/pm_opp.h>
0014 #include <linux/property.h>
0015 
0016 #include "lima_device.h"
0017 #include "lima_devfreq.h"
0018 
0019 static void lima_devfreq_update_utilization(struct lima_devfreq *devfreq)
0020 {
0021     ktime_t now, last;
0022 
0023     now = ktime_get();
0024     last = devfreq->time_last_update;
0025 
0026     if (devfreq->busy_count > 0)
0027         devfreq->busy_time += ktime_sub(now, last);
0028     else
0029         devfreq->idle_time += ktime_sub(now, last);
0030 
0031     devfreq->time_last_update = now;
0032 }
0033 
0034 static int lima_devfreq_target(struct device *dev, unsigned long *freq,
0035                    u32 flags)
0036 {
0037     struct dev_pm_opp *opp;
0038 
0039     opp = devfreq_recommended_opp(dev, freq, flags);
0040     if (IS_ERR(opp))
0041         return PTR_ERR(opp);
0042     dev_pm_opp_put(opp);
0043 
0044     return dev_pm_opp_set_rate(dev, *freq);
0045 }
0046 
0047 static void lima_devfreq_reset(struct lima_devfreq *devfreq)
0048 {
0049     devfreq->busy_time = 0;
0050     devfreq->idle_time = 0;
0051     devfreq->time_last_update = ktime_get();
0052 }
0053 
0054 static int lima_devfreq_get_dev_status(struct device *dev,
0055                        struct devfreq_dev_status *status)
0056 {
0057     struct lima_device *ldev = dev_get_drvdata(dev);
0058     struct lima_devfreq *devfreq = &ldev->devfreq;
0059     unsigned long irqflags;
0060 
0061     status->current_frequency = clk_get_rate(ldev->clk_gpu);
0062 
0063     spin_lock_irqsave(&devfreq->lock, irqflags);
0064 
0065     lima_devfreq_update_utilization(devfreq);
0066 
0067     status->total_time = ktime_to_ns(ktime_add(devfreq->busy_time,
0068                            devfreq->idle_time));
0069     status->busy_time = ktime_to_ns(devfreq->busy_time);
0070 
0071     lima_devfreq_reset(devfreq);
0072 
0073     spin_unlock_irqrestore(&devfreq->lock, irqflags);
0074 
0075     dev_dbg(ldev->dev, "busy %lu total %lu %lu %% freq %lu MHz\n",
0076         status->busy_time, status->total_time,
0077         status->busy_time / (status->total_time / 100),
0078         status->current_frequency / 1000 / 1000);
0079 
0080     return 0;
0081 }
0082 
0083 static struct devfreq_dev_profile lima_devfreq_profile = {
0084     .timer = DEVFREQ_TIMER_DELAYED,
0085     .polling_ms = 50, /* ~3 frames */
0086     .target = lima_devfreq_target,
0087     .get_dev_status = lima_devfreq_get_dev_status,
0088 };
0089 
0090 void lima_devfreq_fini(struct lima_device *ldev)
0091 {
0092     struct lima_devfreq *devfreq = &ldev->devfreq;
0093 
0094     if (devfreq->cooling) {
0095         devfreq_cooling_unregister(devfreq->cooling);
0096         devfreq->cooling = NULL;
0097     }
0098 
0099     if (devfreq->devfreq) {
0100         devm_devfreq_remove_device(ldev->dev, devfreq->devfreq);
0101         devfreq->devfreq = NULL;
0102     }
0103 }
0104 
0105 int lima_devfreq_init(struct lima_device *ldev)
0106 {
0107     struct thermal_cooling_device *cooling;
0108     struct device *dev = ldev->dev;
0109     struct devfreq *devfreq;
0110     struct lima_devfreq *ldevfreq = &ldev->devfreq;
0111     struct dev_pm_opp *opp;
0112     unsigned long cur_freq;
0113     int ret;
0114     const char *regulator_names[] = { "mali", NULL };
0115     const char *clk_names[] = { "core", NULL };
0116     struct dev_pm_opp_config config = {
0117         .regulator_names = regulator_names,
0118         .clk_names = clk_names,
0119     };
0120 
0121     if (!device_property_present(dev, "operating-points-v2"))
0122         /* Optional, continue without devfreq */
0123         return 0;
0124 
0125     spin_lock_init(&ldevfreq->lock);
0126 
0127     ret = devm_pm_opp_set_config(dev, &config);
0128     if (ret) {
0129         /* Continue if the optional regulator is missing */
0130         if (ret != -ENODEV)
0131             return ret;
0132     }
0133 
0134     ret = devm_pm_opp_of_add_table(dev);
0135     if (ret)
0136         return ret;
0137 
0138     lima_devfreq_reset(ldevfreq);
0139 
0140     cur_freq = clk_get_rate(ldev->clk_gpu);
0141 
0142     opp = devfreq_recommended_opp(dev, &cur_freq, 0);
0143     if (IS_ERR(opp))
0144         return PTR_ERR(opp);
0145 
0146     lima_devfreq_profile.initial_freq = cur_freq;
0147     dev_pm_opp_put(opp);
0148 
0149     /*
0150      * Setup default thresholds for the simple_ondemand governor.
0151      * The values are chosen based on experiments.
0152      */
0153     ldevfreq->gov_data.upthreshold = 30;
0154     ldevfreq->gov_data.downdifferential = 5;
0155 
0156     devfreq = devm_devfreq_add_device(dev, &lima_devfreq_profile,
0157                       DEVFREQ_GOV_SIMPLE_ONDEMAND,
0158                       &ldevfreq->gov_data);
0159     if (IS_ERR(devfreq)) {
0160         dev_err(dev, "Couldn't initialize GPU devfreq\n");
0161         return PTR_ERR(devfreq);
0162     }
0163 
0164     ldevfreq->devfreq = devfreq;
0165 
0166     cooling = of_devfreq_cooling_register(dev->of_node, devfreq);
0167     if (IS_ERR(cooling))
0168         dev_info(dev, "Failed to register cooling device\n");
0169     else
0170         ldevfreq->cooling = cooling;
0171 
0172     return 0;
0173 }
0174 
0175 void lima_devfreq_record_busy(struct lima_devfreq *devfreq)
0176 {
0177     unsigned long irqflags;
0178 
0179     if (!devfreq->devfreq)
0180         return;
0181 
0182     spin_lock_irqsave(&devfreq->lock, irqflags);
0183 
0184     lima_devfreq_update_utilization(devfreq);
0185 
0186     devfreq->busy_count++;
0187 
0188     spin_unlock_irqrestore(&devfreq->lock, irqflags);
0189 }
0190 
0191 void lima_devfreq_record_idle(struct lima_devfreq *devfreq)
0192 {
0193     unsigned long irqflags;
0194 
0195     if (!devfreq->devfreq)
0196         return;
0197 
0198     spin_lock_irqsave(&devfreq->lock, irqflags);
0199 
0200     lima_devfreq_update_utilization(devfreq);
0201 
0202     WARN_ON(--devfreq->busy_count < 0);
0203 
0204     spin_unlock_irqrestore(&devfreq->lock, irqflags);
0205 }
0206 
0207 int lima_devfreq_resume(struct lima_devfreq *devfreq)
0208 {
0209     unsigned long irqflags;
0210 
0211     if (!devfreq->devfreq)
0212         return 0;
0213 
0214     spin_lock_irqsave(&devfreq->lock, irqflags);
0215 
0216     lima_devfreq_reset(devfreq);
0217 
0218     spin_unlock_irqrestore(&devfreq->lock, irqflags);
0219 
0220     return devfreq_resume_device(devfreq->devfreq);
0221 }
0222 
0223 int lima_devfreq_suspend(struct lima_devfreq *devfreq)
0224 {
0225     if (!devfreq->devfreq)
0226         return 0;
0227 
0228     return devfreq_suspend_device(devfreq->devfreq);
0229 }