diff options
author | Thierry Reding <treding@nvidia.com> | 2020-04-03 21:03:15 +0300 |
---|---|---|
committer | Thierry Reding <treding@nvidia.com> | 2020-06-22 14:54:57 +0300 |
commit | 0553d7b204ef48091e76753175d21d0c30b7ae2a (patch) | |
tree | b2ad4e7053be824ff1d5346d3eb4ee2865bf46ce /drivers/memory/tegra/tegra210-emc-table.c | |
parent | 9b9d8632f51f3609dfdfe8efc3c1e4e773c6c385 (diff) | |
download | linux-0553d7b204ef48091e76753175d21d0c30b7ae2a.tar.xz |
memory: tegra: Support derated timings on Tegra210
Derated timings are used to ensure that the memory chips keep operating
correctly at high temperatures. This adds code to support polling of the
chip operating state when high temperatures are measured on the chip and
change the refresh mode accordingly. Under very high temperatures, the
driver will switch to the derated tables to ensure proper operation of
the memory chips.
Signed-off-by: Thierry Reding <treding@nvidia.com>
Diffstat (limited to 'drivers/memory/tegra/tegra210-emc-table.c')
-rw-r--r-- | drivers/memory/tegra/tegra210-emc-table.c | 45 |
1 files changed, 38 insertions, 7 deletions
diff --git a/drivers/memory/tegra/tegra210-emc-table.c b/drivers/memory/tegra/tegra210-emc-table.c index a5ab6e9e743a..3e0598363b87 100644 --- a/drivers/memory/tegra/tegra210-emc-table.c +++ b/drivers/memory/tegra/tegra210-emc-table.c @@ -13,32 +13,63 @@ static int tegra210_emc_table_device_init(struct reserved_mem *rmem, struct device *dev) { struct tegra210_emc *emc = dev_get_drvdata(dev); - unsigned int i; + struct tegra210_emc_timing *timings; + unsigned int i, count = 0; - emc->timings = memremap(rmem->base, rmem->size, MEMREMAP_WB); - if (!emc->timings) { + timings = memremap(rmem->base, rmem->size, MEMREMAP_WB); + if (!timings) { dev_err(dev, "failed to map EMC table\n"); return -ENOMEM; } - emc->num_timings = 0; + count = 0; for (i = 0; i < TEGRA_EMC_MAX_FREQS; i++) { - if (emc->timings[i].revision == 0) + if (timings[i].revision == 0) break; - emc->num_timings++; + count++; } + /* only the nominal and derated tables are expected */ + if (emc->derated) { + dev_warn(dev, "excess EMC table '%s'\n", rmem->name); + goto out; + } + + if (emc->nominal) { + if (count != emc->num_timings) { + dev_warn(dev, "%u derated vs. %u nominal entries\n", + count, emc->num_timings); + memunmap(timings); + return -EINVAL; + } + + emc->derated = timings; + } else { + emc->num_timings = count; + emc->nominal = timings; + } + +out: + /* keep track of which table this is */ + rmem->priv = timings; + return 0; } static void tegra210_emc_table_device_release(struct reserved_mem *rmem, struct device *dev) { + struct tegra210_emc_timing *timings = rmem->priv; struct tegra210_emc *emc = dev_get_drvdata(dev); - memunmap(emc->timings); + if ((emc->nominal && timings != emc->nominal) && + (emc->derated && timings != emc->derated)) + dev_warn(dev, "trying to release unassigned EMC table '%s'\n", + rmem->name); + + memunmap(timings); } static const struct reserved_mem_ops tegra210_emc_table_ops = { |