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