Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Linux/drivers/gpu/drm/lima/   (Open Source Betriebssystem Version 6.17.9©)  Datei vom 24.10.2025 mit Größe 5 kB image not shown  

Quelle  lima_devfreq.c   Sprache: C

 
// SPDX-License-Identifier: GPL-2.0
/*
 * Copyright 2020 Martin Blumenstingl <martin.blumenstingl@googlemail.com>
 *
 * Based on panfrost_devfreq.c:
 *   Copyright 2019 Collabora ltd.
 */

#include <linux/clk.h>
#include <linux/devfreq.h>
#include <linux/devfreq_cooling.h>
#include <linux/device.h>
#include <linux/platform_device.h>
#include <linux/pm_opp.h>
#include <linux/property.h>

#include "lima_device.h"
#include "lima_devfreq.h"

static void lima_devfreq_update_utilization(struct lima_devfreq *devfreq)
{
 ktime_t now, last;

 now = ktime_get();
 last = devfreq->time_last_update;

 if (devfreq->busy_count > 0)
  devfreq->busy_time += ktime_sub(now, last);
 else
  devfreq->idle_time += ktime_sub(now, last);

 devfreq->time_last_update = now;
}

static int lima_devfreq_target(struct device *dev, unsigned long *freq,
          u32 flags)
{
 struct dev_pm_opp *opp;

 opp = devfreq_recommended_opp(dev, freq, flags);
 if (IS_ERR(opp))
  return PTR_ERR(opp);
 dev_pm_opp_put(opp);

 return dev_pm_opp_set_rate(dev, *freq);
}

static void lima_devfreq_reset(struct lima_devfreq *devfreq)
{
 devfreq->busy_time = 0;
 devfreq->idle_time = 0;
 devfreq->time_last_update = ktime_get();
}

static int lima_devfreq_get_dev_status(struct device *dev,
           struct devfreq_dev_status *status)
{
 struct lima_device *ldev = dev_get_drvdata(dev);
 struct lima_devfreq *devfreq = &ldev->devfreq;
 unsigned long irqflags;

 status->current_frequency = clk_get_rate(ldev->clk_gpu);

 spin_lock_irqsave(&devfreq->lock, irqflags);

 lima_devfreq_update_utilization(devfreq);

 status->total_time = ktime_to_ns(ktime_add(devfreq->busy_time,
         devfreq->idle_time));
 status->busy_time = ktime_to_ns(devfreq->busy_time);

 lima_devfreq_reset(devfreq);

 spin_unlock_irqrestore(&devfreq->lock, irqflags);

 dev_dbg(ldev->dev, "busy %lu total %lu %lu %% freq %lu MHz\n",
  status->busy_time, status->total_time,
  status->busy_time / (status->total_time / 100),
  status->current_frequency / 1000 / 1000);

 return 0;
}

static struct devfreq_dev_profile lima_devfreq_profile = {
 .timer = DEVFREQ_TIMER_DELAYED,
 .polling_ms = 50, /* ~3 frames */
 .target = lima_devfreq_target,
 .get_dev_status = lima_devfreq_get_dev_status,
};

void lima_devfreq_fini(struct lima_device *ldev)
{
 struct lima_devfreq *devfreq = &ldev->devfreq;

 if (devfreq->cooling) {
  devfreq_cooling_unregister(devfreq->cooling);
  devfreq->cooling = NULL;
 }

 if (devfreq->devfreq) {
  devm_devfreq_remove_device(ldev->dev, devfreq->devfreq);
  devfreq->devfreq = NULL;
 }
}

int lima_devfreq_init(struct lima_device *ldev)
{
 struct thermal_cooling_device *cooling;
 struct device *dev = ldev->dev;
 struct devfreq *devfreq;
 struct lima_devfreq *ldevfreq = &ldev->devfreq;
 struct dev_pm_opp *opp;
 unsigned long cur_freq;
 int ret;
 const char *regulator_names[] = { "mali", NULL };

 if (!device_property_present(dev, "operating-points-v2"))
  /* Optional, continue without devfreq */
  return 0;

 spin_lock_init(&ldevfreq->lock);

 /*
 * clkname is set separately so it is not affected by the optional
 * regulator setting which may return error.
 */

 ret = devm_pm_opp_set_clkname(dev, "core");
 if (ret)
  return ret;

 ret = devm_pm_opp_set_regulators(dev, regulator_names);
 if (ret) {
  /* Continue if the optional regulator is missing */
  if (ret != -ENODEV)
   return ret;
 }

 ret = devm_pm_opp_of_add_table(dev);
 if (ret)
  return ret;

 lima_devfreq_reset(ldevfreq);

 cur_freq = clk_get_rate(ldev->clk_gpu);

 opp = devfreq_recommended_opp(dev, &cur_freq, 0);
 if (IS_ERR(opp))
  return PTR_ERR(opp);

 lima_devfreq_profile.initial_freq = cur_freq;
 dev_pm_opp_put(opp);

 /*
 * Setup default thresholds for the simple_ondemand governor.
 * The values are chosen based on experiments.
 */

 ldevfreq->gov_data.upthreshold = 30;
 ldevfreq->gov_data.downdifferential = 5;

 devfreq = devm_devfreq_add_device(dev, &lima_devfreq_profile,
       DEVFREQ_GOV_SIMPLE_ONDEMAND,
       &ldevfreq->gov_data);
 if (IS_ERR(devfreq)) {
  dev_err(dev, "Couldn't initialize GPU devfreq\n");
  return PTR_ERR(devfreq);
 }

 ldevfreq->devfreq = devfreq;

 cooling = of_devfreq_cooling_register(dev->of_node, devfreq);
 if (IS_ERR(cooling))
  dev_info(dev, "Failed to register cooling device\n");
 else
  ldevfreq->cooling = cooling;

 return 0;
}

void lima_devfreq_record_busy(struct lima_devfreq *devfreq)
{
 unsigned long irqflags;

 if (!devfreq->devfreq)
  return;

 spin_lock_irqsave(&devfreq->lock, irqflags);

 lima_devfreq_update_utilization(devfreq);

 devfreq->busy_count++;

 spin_unlock_irqrestore(&devfreq->lock, irqflags);
}

void lima_devfreq_record_idle(struct lima_devfreq *devfreq)
{
 unsigned long irqflags;

 if (!devfreq->devfreq)
  return;

 spin_lock_irqsave(&devfreq->lock, irqflags);

 lima_devfreq_update_utilization(devfreq);

 WARN_ON(--devfreq->busy_count < 0);

 spin_unlock_irqrestore(&devfreq->lock, irqflags);
}

int lima_devfreq_resume(struct lima_devfreq *devfreq)
{
 unsigned long irqflags;

 if (!devfreq->devfreq)
  return 0;

 spin_lock_irqsave(&devfreq->lock, irqflags);

 lima_devfreq_reset(devfreq);

 spin_unlock_irqrestore(&devfreq->lock, irqflags);

 return devfreq_resume_device(devfreq->devfreq);
}

int lima_devfreq_suspend(struct lima_devfreq *devfreq)
{
 if (!devfreq->devfreq)
  return 0;

 return devfreq_suspend_device(devfreq->devfreq);
}

Messung V0.5
C=94 H=97 G=95

¤ Dauer der Verarbeitung: 0.3 Sekunden  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.