linux/drivers/memory/tegra/tegra186-emc.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * Copyright (C) 2019 NVIDIA CORPORATION.  All rights reserved.
   4 */
   5
   6#include <linux/clk.h>
   7#include <linux/debugfs.h>
   8#include <linux/module.h>
   9#include <linux/mod_devicetable.h>
  10#include <linux/platform_device.h>
  11
  12#include <soc/tegra/bpmp.h>
  13
  14struct tegra186_emc_dvfs {
  15        unsigned long latency;
  16        unsigned long rate;
  17};
  18
  19struct tegra186_emc {
  20        struct tegra_bpmp *bpmp;
  21        struct device *dev;
  22        struct clk *clk;
  23
  24        struct tegra186_emc_dvfs *dvfs;
  25        unsigned int num_dvfs;
  26
  27        struct {
  28                struct dentry *root;
  29                unsigned long min_rate;
  30                unsigned long max_rate;
  31        } debugfs;
  32};
  33
  34/*
  35 * debugfs interface
  36 *
  37 * The memory controller driver exposes some files in debugfs that can be used
  38 * to control the EMC frequency. The top-level directory can be found here:
  39 *
  40 *   /sys/kernel/debug/emc
  41 *
  42 * It contains the following files:
  43 *
  44 *   - available_rates: This file contains a list of valid, space-separated
  45 *     EMC frequencies.
  46 *
  47 *   - min_rate: Writing a value to this file sets the given frequency as the
  48 *       floor of the permitted range. If this is higher than the currently
  49 *       configured EMC frequency, this will cause the frequency to be
  50 *       increased so that it stays within the valid range.
  51 *
  52 *   - max_rate: Similarily to the min_rate file, writing a value to this file
  53 *       sets the given frequency as the ceiling of the permitted range. If
  54 *       the value is lower than the currently configured EMC frequency, this
  55 *       will cause the frequency to be decreased so that it stays within the
  56 *       valid range.
  57 */
  58
  59static bool tegra186_emc_validate_rate(struct tegra186_emc *emc,
  60                                       unsigned long rate)
  61{
  62        unsigned int i;
  63
  64        for (i = 0; i < emc->num_dvfs; i++)
  65                if (rate == emc->dvfs[i].rate)
  66                        return true;
  67
  68        return false;
  69}
  70
  71static int tegra186_emc_debug_available_rates_show(struct seq_file *s,
  72                                                   void *data)
  73{
  74        struct tegra186_emc *emc = s->private;
  75        const char *prefix = "";
  76        unsigned int i;
  77
  78        for (i = 0; i < emc->num_dvfs; i++) {
  79                seq_printf(s, "%s%lu", prefix, emc->dvfs[i].rate);
  80                prefix = " ";
  81        }
  82
  83        seq_puts(s, "\n");
  84
  85        return 0;
  86}
  87
  88static int tegra186_emc_debug_available_rates_open(struct inode *inode,
  89                                                   struct file *file)
  90{
  91        return single_open(file, tegra186_emc_debug_available_rates_show,
  92                           inode->i_private);
  93}
  94
  95static const struct file_operations tegra186_emc_debug_available_rates_fops = {
  96        .open = tegra186_emc_debug_available_rates_open,
  97        .read = seq_read,
  98        .llseek = seq_lseek,
  99        .release = single_release,
 100};
 101
 102static int tegra186_emc_debug_min_rate_get(void *data, u64 *rate)
 103{
 104        struct tegra186_emc *emc = data;
 105
 106        *rate = emc->debugfs.min_rate;
 107
 108        return 0;
 109}
 110
 111static int tegra186_emc_debug_min_rate_set(void *data, u64 rate)
 112{
 113        struct tegra186_emc *emc = data;
 114        int err;
 115
 116        if (!tegra186_emc_validate_rate(emc, rate))
 117                return -EINVAL;
 118
 119        err = clk_set_min_rate(emc->clk, rate);
 120        if (err < 0)
 121                return err;
 122
 123        emc->debugfs.min_rate = rate;
 124
 125        return 0;
 126}
 127
 128DEFINE_DEBUGFS_ATTRIBUTE(tegra186_emc_debug_min_rate_fops,
 129                          tegra186_emc_debug_min_rate_get,
 130                          tegra186_emc_debug_min_rate_set, "%llu\n");
 131
 132static int tegra186_emc_debug_max_rate_get(void *data, u64 *rate)
 133{
 134        struct tegra186_emc *emc = data;
 135
 136        *rate = emc->debugfs.max_rate;
 137
 138        return 0;
 139}
 140
 141static int tegra186_emc_debug_max_rate_set(void *data, u64 rate)
 142{
 143        struct tegra186_emc *emc = data;
 144        int err;
 145
 146        if (!tegra186_emc_validate_rate(emc, rate))
 147                return -EINVAL;
 148
 149        err = clk_set_max_rate(emc->clk, rate);
 150        if (err < 0)
 151                return err;
 152
 153        emc->debugfs.max_rate = rate;
 154
 155        return 0;
 156}
 157
 158DEFINE_DEBUGFS_ATTRIBUTE(tegra186_emc_debug_max_rate_fops,
 159                          tegra186_emc_debug_max_rate_get,
 160                          tegra186_emc_debug_max_rate_set, "%llu\n");
 161
 162static int tegra186_emc_probe(struct platform_device *pdev)
 163{
 164        struct mrq_emc_dvfs_latency_response response;
 165        struct tegra_bpmp_message msg;
 166        struct tegra186_emc *emc;
 167        unsigned int i;
 168        int err;
 169
 170        emc = devm_kzalloc(&pdev->dev, sizeof(*emc), GFP_KERNEL);
 171        if (!emc)
 172                return -ENOMEM;
 173
 174        emc->bpmp = tegra_bpmp_get(&pdev->dev);
 175        if (IS_ERR(emc->bpmp))
 176                return dev_err_probe(&pdev->dev, PTR_ERR(emc->bpmp), "failed to get BPMP\n");
 177
 178        emc->clk = devm_clk_get(&pdev->dev, "emc");
 179        if (IS_ERR(emc->clk)) {
 180                err = PTR_ERR(emc->clk);
 181                dev_err(&pdev->dev, "failed to get EMC clock: %d\n", err);
 182                goto put_bpmp;
 183        }
 184
 185        platform_set_drvdata(pdev, emc);
 186        emc->dev = &pdev->dev;
 187
 188        memset(&msg, 0, sizeof(msg));
 189        msg.mrq = MRQ_EMC_DVFS_LATENCY;
 190        msg.tx.data = NULL;
 191        msg.tx.size = 0;
 192        msg.rx.data = &response;
 193        msg.rx.size = sizeof(response);
 194
 195        err = tegra_bpmp_transfer(emc->bpmp, &msg);
 196        if (err < 0) {
 197                dev_err(&pdev->dev, "failed to EMC DVFS pairs: %d\n", err);
 198                goto put_bpmp;
 199        }
 200
 201        emc->debugfs.min_rate = ULONG_MAX;
 202        emc->debugfs.max_rate = 0;
 203
 204        emc->num_dvfs = response.num_pairs;
 205
 206        emc->dvfs = devm_kmalloc_array(&pdev->dev, emc->num_dvfs,
 207                                       sizeof(*emc->dvfs), GFP_KERNEL);
 208        if (!emc->dvfs) {
 209                err = -ENOMEM;
 210                goto put_bpmp;
 211        }
 212
 213        dev_dbg(&pdev->dev, "%u DVFS pairs:\n", emc->num_dvfs);
 214
 215        for (i = 0; i < emc->num_dvfs; i++) {
 216                emc->dvfs[i].rate = response.pairs[i].freq * 1000;
 217                emc->dvfs[i].latency = response.pairs[i].latency;
 218
 219                if (emc->dvfs[i].rate < emc->debugfs.min_rate)
 220                        emc->debugfs.min_rate = emc->dvfs[i].rate;
 221
 222                if (emc->dvfs[i].rate > emc->debugfs.max_rate)
 223                        emc->debugfs.max_rate = emc->dvfs[i].rate;
 224
 225                dev_dbg(&pdev->dev, "  %2u: %lu Hz -> %lu us\n", i,
 226                        emc->dvfs[i].rate, emc->dvfs[i].latency);
 227        }
 228
 229        err = clk_set_rate_range(emc->clk, emc->debugfs.min_rate,
 230                                 emc->debugfs.max_rate);
 231        if (err < 0) {
 232                dev_err(&pdev->dev,
 233                        "failed to set rate range [%lu-%lu] for %pC\n",
 234                        emc->debugfs.min_rate, emc->debugfs.max_rate,
 235                        emc->clk);
 236                goto put_bpmp;
 237        }
 238
 239        emc->debugfs.root = debugfs_create_dir("emc", NULL);
 240        debugfs_create_file("available_rates", S_IRUGO, emc->debugfs.root,
 241                            emc, &tegra186_emc_debug_available_rates_fops);
 242        debugfs_create_file("min_rate", S_IRUGO | S_IWUSR, emc->debugfs.root,
 243                            emc, &tegra186_emc_debug_min_rate_fops);
 244        debugfs_create_file("max_rate", S_IRUGO | S_IWUSR, emc->debugfs.root,
 245                            emc, &tegra186_emc_debug_max_rate_fops);
 246
 247        return 0;
 248
 249put_bpmp:
 250        tegra_bpmp_put(emc->bpmp);
 251        return err;
 252}
 253
 254static int tegra186_emc_remove(struct platform_device *pdev)
 255{
 256        struct tegra186_emc *emc = platform_get_drvdata(pdev);
 257
 258        debugfs_remove_recursive(emc->debugfs.root);
 259        tegra_bpmp_put(emc->bpmp);
 260
 261        return 0;
 262}
 263
 264static const struct of_device_id tegra186_emc_of_match[] = {
 265#if defined(CONFIG_ARCH_TEGRA_186_SOC)
 266        { .compatible = "nvidia,tegra186-emc" },
 267#endif
 268#if defined(CONFIG_ARCH_TEGRA_194_SOC)
 269        { .compatible = "nvidia,tegra194-emc" },
 270#endif
 271        { /* sentinel */ }
 272};
 273MODULE_DEVICE_TABLE(of, tegra186_emc_of_match);
 274
 275static struct platform_driver tegra186_emc_driver = {
 276        .driver = {
 277                .name = "tegra186-emc",
 278                .of_match_table = tegra186_emc_of_match,
 279                .suppress_bind_attrs = true,
 280        },
 281        .probe = tegra186_emc_probe,
 282        .remove = tegra186_emc_remove,
 283};
 284module_platform_driver(tegra186_emc_driver);
 285
 286MODULE_AUTHOR("Thierry Reding <treding@nvidia.com>");
 287MODULE_DESCRIPTION("NVIDIA Tegra186 External Memory Controller driver");
 288MODULE_LICENSE("GPL v2");
 289