Commit | Line | Data |
---|---|---|
783c8f4c PDS |
1 | /* |
2 | * Copyright (c) 2013-2014, NVIDIA CORPORATION. All rights reserved. | |
3 | * | |
4 | * This program is free software; you can redistribute it and/or modify it | |
5 | * under the terms and conditions of the GNU General Public License, | |
6 | * version 2, as published by the Free Software Foundation. | |
7 | * | |
8 | * This program is distributed in the hope it will be useful, but WITHOUT | |
9 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
10 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | |
11 | * more details. | |
12 | * | |
13 | * You should have received a copy of the GNU General Public License | |
14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | |
15 | * | |
16 | */ | |
17 | ||
18 | #include <linux/device.h> | |
19 | #include <linux/clk.h> | |
20 | #include <linux/err.h> | |
21 | #include <linux/io.h> | |
22 | #include <linux/kernel.h> | |
23 | #include <linux/of_device.h> | |
24 | #include <linux/of_address.h> | |
25 | #include <linux/platform_device.h> | |
26 | #include <linux/random.h> | |
27 | ||
28 | #include <soc/tegra/fuse.h> | |
29 | ||
30 | #include "fuse.h" | |
31 | ||
32 | #define FUSE_BEGIN 0x100 | |
33 | ||
34 | /* Tegra30 and later */ | |
35 | #define FUSE_VENDOR_CODE 0x100 | |
36 | #define FUSE_FAB_CODE 0x104 | |
37 | #define FUSE_LOT_CODE_0 0x108 | |
38 | #define FUSE_LOT_CODE_1 0x10c | |
39 | #define FUSE_WAFER_ID 0x110 | |
40 | #define FUSE_X_COORDINATE 0x114 | |
41 | #define FUSE_Y_COORDINATE 0x118 | |
42 | ||
43 | #define FUSE_HAS_REVISION_INFO BIT(0) | |
44 | ||
7e939de1 TR |
45 | #if defined(CONFIG_ARCH_TEGRA_3x_SOC) || \ |
46 | defined(CONFIG_ARCH_TEGRA_114_SOC) || \ | |
47 | defined(CONFIG_ARCH_TEGRA_124_SOC) || \ | |
0dc5a0d8 TR |
48 | defined(CONFIG_ARCH_TEGRA_132_SOC) || \ |
49 | defined(CONFIG_ARCH_TEGRA_210_SOC) | |
7e939de1 | 50 | static u32 tegra30_fuse_read_early(struct tegra_fuse *fuse, unsigned int offset) |
783c8f4c | 51 | { |
7e939de1 | 52 | return readl_relaxed(fuse->base + FUSE_BEGIN + offset); |
783c8f4c PDS |
53 | } |
54 | ||
7e939de1 | 55 | static u32 tegra30_fuse_read(struct tegra_fuse *fuse, unsigned int offset) |
783c8f4c | 56 | { |
7e939de1 TR |
57 | u32 value; |
58 | int err; | |
783c8f4c | 59 | |
7e939de1 TR |
60 | err = clk_prepare_enable(fuse->clk); |
61 | if (err < 0) { | |
62 | dev_err(fuse->dev, "failed to enable FUSE clock: %d\n", err); | |
63 | return 0; | |
783c8f4c PDS |
64 | } |
65 | ||
7e939de1 | 66 | value = readl_relaxed(fuse->base + FUSE_BEGIN + offset); |
783c8f4c | 67 | |
7e939de1 | 68 | clk_disable_unprepare(fuse->clk); |
783c8f4c | 69 | |
7e939de1 | 70 | return value; |
783c8f4c | 71 | } |
783c8f4c PDS |
72 | |
73 | static void __init tegra30_fuse_add_randomness(void) | |
74 | { | |
75 | u32 randomness[12]; | |
76 | ||
77 | randomness[0] = tegra_sku_info.sku_id; | |
78 | randomness[1] = tegra_read_straps(); | |
79 | randomness[2] = tegra_read_chipid(); | |
80 | randomness[3] = tegra_sku_info.cpu_process_id << 16; | |
03b3f4c8 | 81 | randomness[3] |= tegra_sku_info.soc_process_id; |
783c8f4c PDS |
82 | randomness[4] = tegra_sku_info.cpu_speedo_id << 16; |
83 | randomness[4] |= tegra_sku_info.soc_speedo_id; | |
7e939de1 TR |
84 | randomness[5] = tegra_fuse_read_early(FUSE_VENDOR_CODE); |
85 | randomness[6] = tegra_fuse_read_early(FUSE_FAB_CODE); | |
86 | randomness[7] = tegra_fuse_read_early(FUSE_LOT_CODE_0); | |
87 | randomness[8] = tegra_fuse_read_early(FUSE_LOT_CODE_1); | |
88 | randomness[9] = tegra_fuse_read_early(FUSE_WAFER_ID); | |
89 | randomness[10] = tegra_fuse_read_early(FUSE_X_COORDINATE); | |
90 | randomness[11] = tegra_fuse_read_early(FUSE_Y_COORDINATE); | |
783c8f4c PDS |
91 | |
92 | add_device_randomness(randomness, sizeof(randomness)); | |
93 | } | |
94 | ||
7e939de1 | 95 | static void __init tegra30_fuse_init(struct tegra_fuse *fuse) |
783c8f4c | 96 | { |
7e939de1 TR |
97 | fuse->read_early = tegra30_fuse_read_early; |
98 | fuse->read = tegra30_fuse_read; | |
783c8f4c | 99 | |
7e939de1 TR |
100 | tegra_init_revision(); |
101 | fuse->soc->speedo_init(&tegra_sku_info); | |
102 | tegra30_fuse_add_randomness(); | |
783c8f4c | 103 | } |
7e939de1 | 104 | #endif |
783c8f4c | 105 | |
7e939de1 TR |
106 | #ifdef CONFIG_ARCH_TEGRA_3x_SOC |
107 | static const struct tegra_fuse_info tegra30_fuse_info = { | |
108 | .read = tegra30_fuse_read, | |
109 | .size = 0x2a4, | |
110 | .spare = 0x144, | |
111 | }; | |
783c8f4c | 112 | |
7e939de1 TR |
113 | const struct tegra_fuse_soc tegra30_fuse_soc = { |
114 | .init = tegra30_fuse_init, | |
115 | .speedo_init = tegra30_init_speedo_data, | |
116 | .info = &tegra30_fuse_info, | |
117 | }; | |
118 | #endif | |
783c8f4c | 119 | |
7e939de1 TR |
120 | #ifdef CONFIG_ARCH_TEGRA_114_SOC |
121 | static const struct tegra_fuse_info tegra114_fuse_info = { | |
122 | .read = tegra30_fuse_read, | |
123 | .size = 0x2a0, | |
b23083a9 | 124 | .spare = 0x180, |
7e939de1 | 125 | }; |
783c8f4c | 126 | |
7e939de1 TR |
127 | const struct tegra_fuse_soc tegra114_fuse_soc = { |
128 | .init = tegra30_fuse_init, | |
129 | .speedo_init = tegra114_init_speedo_data, | |
130 | .info = &tegra114_fuse_info, | |
131 | }; | |
132 | #endif | |
133 | ||
134 | #if defined(CONFIG_ARCH_TEGRA_124_SOC) || defined(CONFIG_ARCH_TEGRA_132_SOC) | |
135 | static const struct tegra_fuse_info tegra124_fuse_info = { | |
136 | .read = tegra30_fuse_read, | |
137 | .size = 0x300, | |
82df0e5e | 138 | .spare = 0x200, |
7e939de1 TR |
139 | }; |
140 | ||
141 | const struct tegra_fuse_soc tegra124_fuse_soc = { | |
142 | .init = tegra30_fuse_init, | |
143 | .speedo_init = tegra124_init_speedo_data, | |
144 | .info = &tegra124_fuse_info, | |
145 | }; | |
146 | #endif | |
0dc5a0d8 TR |
147 | |
148 | #if defined(CONFIG_ARCH_TEGRA_210_SOC) | |
149 | static const struct tegra_fuse_info tegra210_fuse_info = { | |
150 | .read = tegra30_fuse_read, | |
151 | .size = 0x300, | |
1dad36cd | 152 | .spare = 0x280, |
0dc5a0d8 TR |
153 | }; |
154 | ||
155 | const struct tegra_fuse_soc tegra210_fuse_soc = { | |
156 | .init = tegra30_fuse_init, | |
157 | .speedo_init = tegra210_init_speedo_data, | |
158 | .info = &tegra210_fuse_info, | |
159 | }; | |
160 | #endif |