Commit | Line | Data |
---|---|---|
10de2114 JL |
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); | |
0553d7b2 TR |
16 | struct tegra210_emc_timing *timings; |
17 | unsigned int i, count = 0; | |
10de2114 | 18 | |
0553d7b2 TR |
19 | timings = memremap(rmem->base, rmem->size, MEMREMAP_WB); |
20 | if (!timings) { | |
10de2114 JL |
21 | dev_err(dev, "failed to map EMC table\n"); |
22 | return -ENOMEM; | |
23 | } | |
24 | ||
0553d7b2 | 25 | count = 0; |
10de2114 JL |
26 | |
27 | for (i = 0; i < TEGRA_EMC_MAX_FREQS; i++) { | |
0553d7b2 | 28 | if (timings[i].revision == 0) |
10de2114 JL |
29 | break; |
30 | ||
0553d7b2 | 31 | count++; |
10de2114 JL |
32 | } |
33 | ||
0553d7b2 TR |
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 | ||
10de2114 JL |
58 | return 0; |
59 | } | |
60 | ||
61 | static void tegra210_emc_table_device_release(struct reserved_mem *rmem, | |
62 | struct device *dev) | |
63 | { | |
0553d7b2 | 64 | struct tegra210_emc_timing *timings = rmem->priv; |
10de2114 JL |
65 | struct tegra210_emc *emc = dev_get_drvdata(dev); |
66 | ||
0553d7b2 TR |
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); | |
10de2114 JL |
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); |