panfrost_devfreq.c (5436B)
1// SPDX-License-Identifier: GPL-2.0 2/* 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 "panfrost_device.h" 11#include "panfrost_devfreq.h" 12 13static void panfrost_devfreq_update_utilization(struct panfrost_devfreq *pfdevfreq) 14{ 15 ktime_t now, last; 16 17 now = ktime_get(); 18 last = pfdevfreq->time_last_update; 19 20 if (pfdevfreq->busy_count > 0) 21 pfdevfreq->busy_time += ktime_sub(now, last); 22 else 23 pfdevfreq->idle_time += ktime_sub(now, last); 24 25 pfdevfreq->time_last_update = now; 26} 27 28static int panfrost_devfreq_target(struct device *dev, unsigned long *freq, 29 u32 flags) 30{ 31 struct dev_pm_opp *opp; 32 33 opp = devfreq_recommended_opp(dev, freq, flags); 34 if (IS_ERR(opp)) 35 return PTR_ERR(opp); 36 dev_pm_opp_put(opp); 37 38 return dev_pm_opp_set_rate(dev, *freq); 39} 40 41static void panfrost_devfreq_reset(struct panfrost_devfreq *pfdevfreq) 42{ 43 pfdevfreq->busy_time = 0; 44 pfdevfreq->idle_time = 0; 45 pfdevfreq->time_last_update = ktime_get(); 46} 47 48static int panfrost_devfreq_get_dev_status(struct device *dev, 49 struct devfreq_dev_status *status) 50{ 51 struct panfrost_device *pfdev = dev_get_drvdata(dev); 52 struct panfrost_devfreq *pfdevfreq = &pfdev->pfdevfreq; 53 unsigned long irqflags; 54 55 status->current_frequency = clk_get_rate(pfdev->clock); 56 57 spin_lock_irqsave(&pfdevfreq->lock, irqflags); 58 59 panfrost_devfreq_update_utilization(pfdevfreq); 60 61 status->total_time = ktime_to_ns(ktime_add(pfdevfreq->busy_time, 62 pfdevfreq->idle_time)); 63 64 status->busy_time = ktime_to_ns(pfdevfreq->busy_time); 65 66 panfrost_devfreq_reset(pfdevfreq); 67 68 spin_unlock_irqrestore(&pfdevfreq->lock, irqflags); 69 70 dev_dbg(pfdev->dev, "busy %lu total %lu %lu %% freq %lu MHz\n", 71 status->busy_time, status->total_time, 72 status->busy_time / (status->total_time / 100), 73 status->current_frequency / 1000 / 1000); 74 75 return 0; 76} 77 78static struct devfreq_dev_profile panfrost_devfreq_profile = { 79 .timer = DEVFREQ_TIMER_DELAYED, 80 .polling_ms = 50, /* ~3 frames */ 81 .target = panfrost_devfreq_target, 82 .get_dev_status = panfrost_devfreq_get_dev_status, 83}; 84 85int panfrost_devfreq_init(struct panfrost_device *pfdev) 86{ 87 int ret; 88 struct dev_pm_opp *opp; 89 unsigned long cur_freq; 90 struct device *dev = &pfdev->pdev->dev; 91 struct devfreq *devfreq; 92 struct thermal_cooling_device *cooling; 93 struct panfrost_devfreq *pfdevfreq = &pfdev->pfdevfreq; 94 95 if (pfdev->comp->num_supplies > 1) { 96 /* 97 * GPUs with more than 1 supply require platform-specific handling: 98 * continue without devfreq 99 */ 100 DRM_DEV_INFO(dev, "More than 1 supply is not supported yet\n"); 101 return 0; 102 } 103 104 ret = devm_pm_opp_set_regulators(dev, pfdev->comp->supply_names, 105 pfdev->comp->num_supplies); 106 if (ret) { 107 /* Continue if the optional regulator is missing */ 108 if (ret != -ENODEV) { 109 if (ret != -EPROBE_DEFER) 110 DRM_DEV_ERROR(dev, "Couldn't set OPP regulators\n"); 111 return ret; 112 } 113 } 114 115 ret = devm_pm_opp_of_add_table(dev); 116 if (ret) { 117 /* Optional, continue without devfreq */ 118 if (ret == -ENODEV) 119 ret = 0; 120 return ret; 121 } 122 pfdevfreq->opp_of_table_added = true; 123 124 spin_lock_init(&pfdevfreq->lock); 125 126 panfrost_devfreq_reset(pfdevfreq); 127 128 cur_freq = clk_get_rate(pfdev->clock); 129 130 opp = devfreq_recommended_opp(dev, &cur_freq, 0); 131 if (IS_ERR(opp)) 132 return PTR_ERR(opp); 133 134 panfrost_devfreq_profile.initial_freq = cur_freq; 135 dev_pm_opp_put(opp); 136 137 /* 138 * Setup default thresholds for the simple_ondemand governor. 139 * The values are chosen based on experiments. 140 */ 141 pfdevfreq->gov_data.upthreshold = 45; 142 pfdevfreq->gov_data.downdifferential = 5; 143 144 devfreq = devm_devfreq_add_device(dev, &panfrost_devfreq_profile, 145 DEVFREQ_GOV_SIMPLE_ONDEMAND, 146 &pfdevfreq->gov_data); 147 if (IS_ERR(devfreq)) { 148 DRM_DEV_ERROR(dev, "Couldn't initialize GPU devfreq\n"); 149 return PTR_ERR(devfreq); 150 } 151 pfdevfreq->devfreq = devfreq; 152 153 cooling = devfreq_cooling_em_register(devfreq, NULL); 154 if (IS_ERR(cooling)) 155 DRM_DEV_INFO(dev, "Failed to register cooling device\n"); 156 else 157 pfdevfreq->cooling = cooling; 158 159 return 0; 160} 161 162void panfrost_devfreq_fini(struct panfrost_device *pfdev) 163{ 164 struct panfrost_devfreq *pfdevfreq = &pfdev->pfdevfreq; 165 166 if (pfdevfreq->cooling) { 167 devfreq_cooling_unregister(pfdevfreq->cooling); 168 pfdevfreq->cooling = NULL; 169 } 170} 171 172void panfrost_devfreq_resume(struct panfrost_device *pfdev) 173{ 174 struct panfrost_devfreq *pfdevfreq = &pfdev->pfdevfreq; 175 176 if (!pfdevfreq->devfreq) 177 return; 178 179 panfrost_devfreq_reset(pfdevfreq); 180 181 devfreq_resume_device(pfdevfreq->devfreq); 182} 183 184void panfrost_devfreq_suspend(struct panfrost_device *pfdev) 185{ 186 struct panfrost_devfreq *pfdevfreq = &pfdev->pfdevfreq; 187 188 if (!pfdevfreq->devfreq) 189 return; 190 191 devfreq_suspend_device(pfdevfreq->devfreq); 192} 193 194void panfrost_devfreq_record_busy(struct panfrost_devfreq *pfdevfreq) 195{ 196 unsigned long irqflags; 197 198 if (!pfdevfreq->devfreq) 199 return; 200 201 spin_lock_irqsave(&pfdevfreq->lock, irqflags); 202 203 panfrost_devfreq_update_utilization(pfdevfreq); 204 205 pfdevfreq->busy_count++; 206 207 spin_unlock_irqrestore(&pfdevfreq->lock, irqflags); 208} 209 210void panfrost_devfreq_record_idle(struct panfrost_devfreq *pfdevfreq) 211{ 212 unsigned long irqflags; 213 214 if (!pfdevfreq->devfreq) 215 return; 216 217 spin_lock_irqsave(&pfdevfreq->lock, irqflags); 218 219 panfrost_devfreq_update_utilization(pfdevfreq); 220 221 WARN_ON(--pfdevfreq->busy_count < 0); 222 223 spin_unlock_irqrestore(&pfdevfreq->lock, irqflags); 224}