linux/drivers/memory/tegra/tegra210-emc-table.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * Copyright (c) 2020, NVIDIA CORPORATION.  All rights reserved.
   4 */
   5
   6#include <linux/of_reserved_mem.h>
   7
   8#include "tegra210-emc.h"
   9
  10#define TEGRA_EMC_MAX_FREQS             16
  11
  12static int tegra210_emc_table_device_init(struct reserved_mem *rmem,
  13                                          struct device *dev)
  14{
  15        struct tegra210_emc *emc = dev_get_drvdata(dev);
  16        struct tegra210_emc_timing *timings;
  17        unsigned int i, count = 0;
  18
  19        timings = memremap(rmem->base, rmem->size, MEMREMAP_WB);
  20        if (!timings) {
  21                dev_err(dev, "failed to map EMC table\n");
  22                return -ENOMEM;
  23        }
  24
  25        count = 0;
  26
  27        for (i = 0; i < TEGRA_EMC_MAX_FREQS; i++) {
  28                if (timings[i].revision == 0)
  29                        break;
  30
  31                count++;
  32        }
  33
  34        /* only the nominal and derated tables are expected */
  35        if (emc->derated) {
  36                dev_warn(dev, "excess EMC table '%s'\n", rmem->name);
  37                goto out;
  38        }
  39
  40        if (emc->nominal) {
  41                if (count != emc->num_timings) {
  42                        dev_warn(dev, "%u derated vs. %u nominal entries\n",
  43                                 count, emc->num_timings);
  44                        memunmap(timings);
  45                        return -EINVAL;
  46                }
  47
  48                emc->derated = timings;
  49        } else {
  50                emc->num_timings = count;
  51                emc->nominal = timings;
  52        }
  53
  54out:
  55        /* keep track of which table this is */
  56        rmem->priv = timings;
  57
  58        return 0;
  59}
  60
  61static void tegra210_emc_table_device_release(struct reserved_mem *rmem,
  62                                              struct device *dev)
  63{
  64        struct tegra210_emc_timing *timings = rmem->priv;
  65        struct tegra210_emc *emc = dev_get_drvdata(dev);
  66
  67        if ((emc->nominal && timings != emc->nominal) &&
  68            (emc->derated && timings != emc->derated))
  69                dev_warn(dev, "trying to release unassigned EMC table '%s'\n",
  70                         rmem->name);
  71
  72        memunmap(timings);
  73}
  74
  75static const struct reserved_mem_ops tegra210_emc_table_ops = {
  76        .device_init = tegra210_emc_table_device_init,
  77        .device_release = tegra210_emc_table_device_release,
  78};
  79
  80static int tegra210_emc_table_init(struct reserved_mem *rmem)
  81{
  82        pr_debug("Tegra210 EMC table at %pa, size %lu bytes\n", &rmem->base,
  83                 (unsigned long)rmem->size);
  84
  85        rmem->ops = &tegra210_emc_table_ops;
  86
  87        return 0;
  88}
  89RESERVEDMEM_OF_DECLARE(tegra210_emc_table, "nvidia,tegra210-emc-table",
  90                       tegra210_emc_table_init);
  91