summaryrefslogtreecommitdiff
path: root/drivers/memory/tegra/tegra210-emc-table.c
diff options
context:
space:
mode:
authorJoseph Lo <josephl@nvidia.com>2019-05-29 16:21:36 +0800
committerThierry Reding <treding@nvidia.com>2020-06-22 13:54:57 +0200
commit10de21148f7d28c9e918aaee7cede74a7d506e24 (patch)
tree1fbcf76bc4a6a561c49e6c3bcd4ed1bbe2a86d98 /drivers/memory/tegra/tegra210-emc-table.c
parent6cc8823ad3e85207dfb4c93f31dcdb05297d1b42 (diff)
memory: tegra: Add EMC scaling support code for Tegra210
This is the initial patch for Tegra210 EMC frequency scaling. It has the code to program various aspects of the EMC that are standardized, but it does not yet include the specific programming sequence needed for clock scaling. The driver is designed to support LPDDR4 SDRAM. Devices that use LPDDR4 need to perform training of the RAM before it can be used. Firmware will perform this training during early boot and pass a table of supported frequencies to the kernel via device tree. For the frequencies above 800 MHz, periodic retraining is needed to compensate for changes in timing. This periodic training will have to be performed until the frequency drops back to or below 800 MHz. This driver provides helpers used during this runtime retraining that will be used by the sequence specific code in a follow-up patch. Based on work by Peter De Schrijver <pdeschrijver@nvidia.com>. Signed-off-by: Joseph Lo <josephl@nvidia.com> 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.c59
1 files changed, 59 insertions, 0 deletions
diff --git a/drivers/memory/tegra/tegra210-emc-table.c b/drivers/memory/tegra/tegra210-emc-table.c
new file mode 100644
index 000000000000..a5ab6e9e743a
--- /dev/null
+++ b/drivers/memory/tegra/tegra210-emc-table.c
@@ -0,0 +1,59 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2020, NVIDIA CORPORATION. All rights reserved.
+ */
+
+#include <linux/of_reserved_mem.h>
+
+#include "tegra210-emc.h"
+
+#define TEGRA_EMC_MAX_FREQS 16
+
+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;
+
+ emc->timings = memremap(rmem->base, rmem->size, MEMREMAP_WB);
+ if (!emc->timings) {
+ dev_err(dev, "failed to map EMC table\n");
+ return -ENOMEM;
+ }
+
+ emc->num_timings = 0;
+
+ for (i = 0; i < TEGRA_EMC_MAX_FREQS; i++) {
+ if (emc->timings[i].revision == 0)
+ break;
+
+ emc->num_timings++;
+ }
+
+ return 0;
+}
+
+static void tegra210_emc_table_device_release(struct reserved_mem *rmem,
+ struct device *dev)
+{
+ struct tegra210_emc *emc = dev_get_drvdata(dev);
+
+ memunmap(emc->timings);
+}
+
+static const struct reserved_mem_ops tegra210_emc_table_ops = {
+ .device_init = tegra210_emc_table_device_init,
+ .device_release = tegra210_emc_table_device_release,
+};
+
+static int tegra210_emc_table_init(struct reserved_mem *rmem)
+{
+ pr_debug("Tegra210 EMC table at %pa, size %lu bytes\n", &rmem->base,
+ (unsigned long)rmem->size);
+
+ rmem->ops = &tegra210_emc_table_ops;
+
+ return 0;
+}
+RESERVEDMEM_OF_DECLARE(tegra210_emc_table, "nvidia,tegra210-emc-table",
+ tegra210_emc_table_init);