110de2114SJoseph Lo // SPDX-License-Identifier: GPL-2.0
210de2114SJoseph Lo /*
310de2114SJoseph Lo * Copyright (c) 2020, NVIDIA CORPORATION. All rights reserved.
410de2114SJoseph Lo */
510de2114SJoseph Lo
610de2114SJoseph Lo #include <linux/of_reserved_mem.h>
710de2114SJoseph Lo
810de2114SJoseph Lo #include "tegra210-emc.h"
910de2114SJoseph Lo
1010de2114SJoseph Lo #define TEGRA_EMC_MAX_FREQS 16
1110de2114SJoseph Lo
tegra210_emc_table_device_init(struct reserved_mem * rmem,struct device * dev)1210de2114SJoseph Lo static int tegra210_emc_table_device_init(struct reserved_mem *rmem,
1310de2114SJoseph Lo struct device *dev)
1410de2114SJoseph Lo {
1510de2114SJoseph Lo struct tegra210_emc *emc = dev_get_drvdata(dev);
160553d7b2SThierry Reding struct tegra210_emc_timing *timings;
170553d7b2SThierry Reding unsigned int i, count = 0;
1810de2114SJoseph Lo
190553d7b2SThierry Reding timings = memremap(rmem->base, rmem->size, MEMREMAP_WB);
200553d7b2SThierry Reding if (!timings) {
2110de2114SJoseph Lo dev_err(dev, "failed to map EMC table\n");
2210de2114SJoseph Lo return -ENOMEM;
2310de2114SJoseph Lo }
2410de2114SJoseph Lo
2510de2114SJoseph Lo for (i = 0; i < TEGRA_EMC_MAX_FREQS; i++) {
260553d7b2SThierry Reding if (timings[i].revision == 0)
2710de2114SJoseph Lo break;
2810de2114SJoseph Lo
290553d7b2SThierry Reding count++;
3010de2114SJoseph Lo }
3110de2114SJoseph Lo
320553d7b2SThierry Reding /* only the nominal and derated tables are expected */
330553d7b2SThierry Reding if (emc->derated) {
340553d7b2SThierry Reding dev_warn(dev, "excess EMC table '%s'\n", rmem->name);
350553d7b2SThierry Reding goto out;
360553d7b2SThierry Reding }
370553d7b2SThierry Reding
380553d7b2SThierry Reding if (emc->nominal) {
390553d7b2SThierry Reding if (count != emc->num_timings) {
400553d7b2SThierry Reding dev_warn(dev, "%u derated vs. %u nominal entries\n",
410553d7b2SThierry Reding count, emc->num_timings);
420553d7b2SThierry Reding memunmap(timings);
430553d7b2SThierry Reding return -EINVAL;
440553d7b2SThierry Reding }
450553d7b2SThierry Reding
460553d7b2SThierry Reding emc->derated = timings;
470553d7b2SThierry Reding } else {
480553d7b2SThierry Reding emc->num_timings = count;
490553d7b2SThierry Reding emc->nominal = timings;
500553d7b2SThierry Reding }
510553d7b2SThierry Reding
520553d7b2SThierry Reding out:
530553d7b2SThierry Reding /* keep track of which table this is */
540553d7b2SThierry Reding rmem->priv = timings;
550553d7b2SThierry Reding
5610de2114SJoseph Lo return 0;
5710de2114SJoseph Lo }
5810de2114SJoseph Lo
tegra210_emc_table_device_release(struct reserved_mem * rmem,struct device * dev)5910de2114SJoseph Lo static void tegra210_emc_table_device_release(struct reserved_mem *rmem,
6010de2114SJoseph Lo struct device *dev)
6110de2114SJoseph Lo {
620553d7b2SThierry Reding struct tegra210_emc_timing *timings = rmem->priv;
6310de2114SJoseph Lo struct tegra210_emc *emc = dev_get_drvdata(dev);
6410de2114SJoseph Lo
650553d7b2SThierry Reding if ((emc->nominal && timings != emc->nominal) &&
660553d7b2SThierry Reding (emc->derated && timings != emc->derated))
670553d7b2SThierry Reding dev_warn(dev, "trying to release unassigned EMC table '%s'\n",
680553d7b2SThierry Reding rmem->name);
690553d7b2SThierry Reding
700553d7b2SThierry Reding memunmap(timings);
7110de2114SJoseph Lo }
7210de2114SJoseph Lo
7310de2114SJoseph Lo static const struct reserved_mem_ops tegra210_emc_table_ops = {
7410de2114SJoseph Lo .device_init = tegra210_emc_table_device_init,
7510de2114SJoseph Lo .device_release = tegra210_emc_table_device_release,
7610de2114SJoseph Lo };
7710de2114SJoseph Lo
tegra210_emc_table_init(struct reserved_mem * rmem)7810de2114SJoseph Lo static int tegra210_emc_table_init(struct reserved_mem *rmem)
7910de2114SJoseph Lo {
8010de2114SJoseph Lo pr_debug("Tegra210 EMC table at %pa, size %lu bytes\n", &rmem->base,
8110de2114SJoseph Lo (unsigned long)rmem->size);
8210de2114SJoseph Lo
8310de2114SJoseph Lo rmem->ops = &tegra210_emc_table_ops;
8410de2114SJoseph Lo
8510de2114SJoseph Lo return 0;
8610de2114SJoseph Lo }
8710de2114SJoseph Lo RESERVEDMEM_OF_DECLARE(tegra210_emc_table, "nvidia,tegra210-emc-table",
8810de2114SJoseph Lo tegra210_emc_table_init);
89