root/drivers/devfreq/tegra20-devfreq.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. tegra_devfreq_target
  2. tegra_devfreq_get_dev_status
  3. tegra_get_memory_controller
  4. tegra_devfreq_probe
  5. tegra_devfreq_remove

   1 // SPDX-License-Identifier: GPL-2.0
   2 /*
   3  * NVIDIA Tegra20 devfreq driver
   4  *
   5  * Copyright (C) 2019 GRATE-DRIVER project
   6  */
   7 
   8 #include <linux/clk.h>
   9 #include <linux/devfreq.h>
  10 #include <linux/io.h>
  11 #include <linux/kernel.h>
  12 #include <linux/module.h>
  13 #include <linux/of_device.h>
  14 #include <linux/platform_device.h>
  15 #include <linux/pm_opp.h>
  16 #include <linux/slab.h>
  17 
  18 #include <soc/tegra/mc.h>
  19 
  20 #include "governor.h"
  21 
  22 #define MC_STAT_CONTROL                         0x90
  23 #define MC_STAT_EMC_CLOCK_LIMIT                 0xa0
  24 #define MC_STAT_EMC_CLOCKS                      0xa4
  25 #define MC_STAT_EMC_CONTROL                     0xa8
  26 #define MC_STAT_EMC_COUNT                       0xb8
  27 
  28 #define EMC_GATHER_CLEAR                        (1 << 8)
  29 #define EMC_GATHER_ENABLE                       (3 << 8)
  30 
  31 struct tegra_devfreq {
  32         struct devfreq *devfreq;
  33         struct clk *emc_clock;
  34         void __iomem *regs;
  35 };
  36 
  37 static int tegra_devfreq_target(struct device *dev, unsigned long *freq,
  38                                 u32 flags)
  39 {
  40         struct tegra_devfreq *tegra = dev_get_drvdata(dev);
  41         struct devfreq *devfreq = tegra->devfreq;
  42         struct dev_pm_opp *opp;
  43         unsigned long rate;
  44         int err;
  45 
  46         opp = devfreq_recommended_opp(dev, freq, flags);
  47         if (IS_ERR(opp))
  48                 return PTR_ERR(opp);
  49 
  50         rate = dev_pm_opp_get_freq(opp);
  51         dev_pm_opp_put(opp);
  52 
  53         err = clk_set_min_rate(tegra->emc_clock, rate);
  54         if (err)
  55                 return err;
  56 
  57         err = clk_set_rate(tegra->emc_clock, 0);
  58         if (err)
  59                 goto restore_min_rate;
  60 
  61         return 0;
  62 
  63 restore_min_rate:
  64         clk_set_min_rate(tegra->emc_clock, devfreq->previous_freq);
  65 
  66         return err;
  67 }
  68 
  69 static int tegra_devfreq_get_dev_status(struct device *dev,
  70                                         struct devfreq_dev_status *stat)
  71 {
  72         struct tegra_devfreq *tegra = dev_get_drvdata(dev);
  73 
  74         /*
  75          * EMC_COUNT returns number of memory events, that number is lower
  76          * than the number of clocks. Conversion ratio of 1/8 results in a
  77          * bit higher bandwidth than actually needed, it is good enough for
  78          * the time being because drivers don't support requesting minimum
  79          * needed memory bandwidth yet.
  80          *
  81          * TODO: adjust the ratio value once relevant drivers will support
  82          * memory bandwidth management.
  83          */
  84         stat->busy_time = readl_relaxed(tegra->regs + MC_STAT_EMC_COUNT);
  85         stat->total_time = readl_relaxed(tegra->regs + MC_STAT_EMC_CLOCKS) / 8;
  86         stat->current_frequency = clk_get_rate(tegra->emc_clock);
  87 
  88         writel_relaxed(EMC_GATHER_CLEAR, tegra->regs + MC_STAT_CONTROL);
  89         writel_relaxed(EMC_GATHER_ENABLE, tegra->regs + MC_STAT_CONTROL);
  90 
  91         return 0;
  92 }
  93 
  94 static struct devfreq_dev_profile tegra_devfreq_profile = {
  95         .polling_ms     = 500,
  96         .target         = tegra_devfreq_target,
  97         .get_dev_status = tegra_devfreq_get_dev_status,
  98 };
  99 
 100 static struct tegra_mc *tegra_get_memory_controller(void)
 101 {
 102         struct platform_device *pdev;
 103         struct device_node *np;
 104         struct tegra_mc *mc;
 105 
 106         np = of_find_compatible_node(NULL, NULL, "nvidia,tegra20-mc-gart");
 107         if (!np)
 108                 return ERR_PTR(-ENOENT);
 109 
 110         pdev = of_find_device_by_node(np);
 111         of_node_put(np);
 112         if (!pdev)
 113                 return ERR_PTR(-ENODEV);
 114 
 115         mc = platform_get_drvdata(pdev);
 116         if (!mc)
 117                 return ERR_PTR(-EPROBE_DEFER);
 118 
 119         return mc;
 120 }
 121 
 122 static int tegra_devfreq_probe(struct platform_device *pdev)
 123 {
 124         struct tegra_devfreq *tegra;
 125         struct tegra_mc *mc;
 126         unsigned long max_rate;
 127         unsigned long rate;
 128         int err;
 129 
 130         mc = tegra_get_memory_controller();
 131         if (IS_ERR(mc)) {
 132                 err = PTR_ERR(mc);
 133                 dev_err(&pdev->dev, "failed to get memory controller: %d\n",
 134                         err);
 135                 return err;
 136         }
 137 
 138         tegra = devm_kzalloc(&pdev->dev, sizeof(*tegra), GFP_KERNEL);
 139         if (!tegra)
 140                 return -ENOMEM;
 141 
 142         /* EMC is a system-critical clock that is always enabled */
 143         tegra->emc_clock = devm_clk_get(&pdev->dev, "emc");
 144         if (IS_ERR(tegra->emc_clock)) {
 145                 err = PTR_ERR(tegra->emc_clock);
 146                 dev_err(&pdev->dev, "failed to get emc clock: %d\n", err);
 147                 return err;
 148         }
 149 
 150         tegra->regs = mc->regs;
 151 
 152         max_rate = clk_round_rate(tegra->emc_clock, ULONG_MAX);
 153 
 154         for (rate = 0; rate <= max_rate; rate++) {
 155                 rate = clk_round_rate(tegra->emc_clock, rate);
 156 
 157                 err = dev_pm_opp_add(&pdev->dev, rate, 0);
 158                 if (err) {
 159                         dev_err(&pdev->dev, "failed to add opp: %d\n", err);
 160                         goto remove_opps;
 161                 }
 162         }
 163 
 164         /*
 165          * Reset statistic gathers state, select global bandwidth for the
 166          * statistics collection mode and set clocks counter saturation
 167          * limit to maximum.
 168          */
 169         writel_relaxed(0x00000000, tegra->regs + MC_STAT_CONTROL);
 170         writel_relaxed(0x00000000, tegra->regs + MC_STAT_EMC_CONTROL);
 171         writel_relaxed(0xffffffff, tegra->regs + MC_STAT_EMC_CLOCK_LIMIT);
 172 
 173         platform_set_drvdata(pdev, tegra);
 174 
 175         tegra->devfreq = devfreq_add_device(&pdev->dev, &tegra_devfreq_profile,
 176                                             DEVFREQ_GOV_SIMPLE_ONDEMAND, NULL);
 177         if (IS_ERR(tegra->devfreq)) {
 178                 err = PTR_ERR(tegra->devfreq);
 179                 goto remove_opps;
 180         }
 181 
 182         return 0;
 183 
 184 remove_opps:
 185         dev_pm_opp_remove_all_dynamic(&pdev->dev);
 186 
 187         return err;
 188 }
 189 
 190 static int tegra_devfreq_remove(struct platform_device *pdev)
 191 {
 192         struct tegra_devfreq *tegra = platform_get_drvdata(pdev);
 193 
 194         devfreq_remove_device(tegra->devfreq);
 195         dev_pm_opp_remove_all_dynamic(&pdev->dev);
 196 
 197         return 0;
 198 }
 199 
 200 static struct platform_driver tegra_devfreq_driver = {
 201         .probe          = tegra_devfreq_probe,
 202         .remove         = tegra_devfreq_remove,
 203         .driver         = {
 204                 .name   = "tegra20-devfreq",
 205         },
 206 };
 207 module_platform_driver(tegra_devfreq_driver);
 208 
 209 MODULE_ALIAS("platform:tegra20-devfreq");
 210 MODULE_AUTHOR("Dmitry Osipenko <digetx@gmail.com>");
 211 MODULE_DESCRIPTION("NVIDIA Tegra20 devfreq driver");
 212 MODULE_LICENSE("GPL v2");

/* [<][>][^][v][top][bottom][index][help] */