Merge tag 'gvt-next-2020-11-23' of https://github.com/intel/gvt-linux into drm-intel...
[linux-2.6-microblaze.git] / drivers / memory / tegra / tegra210-emc-table.c
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
12 static 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
54 out:
55         /* keep track of which table this is */
56         rmem->priv = timings;
57
58         return 0;
59 }
60
61 static 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
75 static 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
80 static 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 }
89 RESERVEDMEM_OF_DECLARE(tegra210_emc_table, "nvidia,tegra210-emc-table",
90                        tegra210_emc_table_init);