diff options
author | Stephen Warren <swarren@nvidia.com> | 2013-09-12 18:51:19 -0400 |
---|---|---|
committer | Stephen Warren <swarren@nvidia.com> | 2013-10-18 18:28:06 -0400 |
commit | 3bd1ae57f7bb3bf79487f7cb88f3ee34c7d58a52 (patch) | |
tree | e396dd935b941f39e65ba09b08af1e9b891a2400 /arch/arm/mach-tegra/fuse.c | |
parent | b6bda4e0d23815cb711c16085e03cb23c6d49f21 (diff) |
ARM: tegra: add fuses as device randomness
Various fuses on Tegra include information that's unique to an individual
chip, or a subset of chips. Call add_device_randomness() with this data
to perturb the initial state of the random pool.
Suggested-by: Linus Walleij <linus.walleij@linaro.org>
Signed-off-by: Stephen Warren <swarren@nvidia.com>
Acked-by: Linus Walleij <linus.walleij@linaro.org>
Diffstat (limited to 'arch/arm/mach-tegra/fuse.c')
-rw-r--r-- | arch/arm/mach-tegra/fuse.c | 54 |
1 files changed, 54 insertions, 0 deletions
diff --git a/arch/arm/mach-tegra/fuse.c b/arch/arm/mach-tegra/fuse.c index f3b5d0d7b620..d4639c506622 100644 --- a/arch/arm/mach-tegra/fuse.c +++ b/arch/arm/mach-tegra/fuse.c | |||
@@ -21,14 +21,26 @@ | |||
21 | #include <linux/kernel.h> | 21 | #include <linux/kernel.h> |
22 | #include <linux/io.h> | 22 | #include <linux/io.h> |
23 | #include <linux/export.h> | 23 | #include <linux/export.h> |
24 | #include <linux/random.h> | ||
24 | #include <linux/tegra-soc.h> | 25 | #include <linux/tegra-soc.h> |
25 | 26 | ||
26 | #include "fuse.h" | 27 | #include "fuse.h" |
27 | #include "iomap.h" | 28 | #include "iomap.h" |
28 | #include "apbio.h" | 29 | #include "apbio.h" |
29 | 30 | ||
31 | /* Tegra20 only */ | ||
30 | #define FUSE_UID_LOW 0x108 | 32 | #define FUSE_UID_LOW 0x108 |
31 | #define FUSE_UID_HIGH 0x10c | 33 | #define FUSE_UID_HIGH 0x10c |
34 | |||
35 | /* Tegra30 and later */ | ||
36 | #define FUSE_VENDOR_CODE 0x200 | ||
37 | #define FUSE_FAB_CODE 0x204 | ||
38 | #define FUSE_LOT_CODE_0 0x208 | ||
39 | #define FUSE_LOT_CODE_1 0x20c | ||
40 | #define FUSE_WAFER_ID 0x210 | ||
41 | #define FUSE_X_COORDINATE 0x214 | ||
42 | #define FUSE_Y_COORDINATE 0x218 | ||
43 | |||
32 | #define FUSE_SKU_INFO 0x110 | 44 | #define FUSE_SKU_INFO 0x110 |
33 | 45 | ||
34 | #define TEGRA20_FUSE_SPARE_BIT 0x200 | 46 | #define TEGRA20_FUSE_SPARE_BIT 0x200 |
@@ -112,21 +124,51 @@ u32 tegra_read_chipid(void) | |||
112 | return readl_relaxed(IO_ADDRESS(TEGRA_APB_MISC_BASE) + 0x804); | 124 | return readl_relaxed(IO_ADDRESS(TEGRA_APB_MISC_BASE) + 0x804); |
113 | } | 125 | } |
114 | 126 | ||
127 | static void __init tegra20_fuse_init_randomness(void) | ||
128 | { | ||
129 | u32 randomness[2]; | ||
130 | |||
131 | randomness[0] = tegra_fuse_readl(FUSE_UID_LOW); | ||
132 | randomness[1] = tegra_fuse_readl(FUSE_UID_HIGH); | ||
133 | |||
134 | add_device_randomness(randomness, sizeof(randomness)); | ||
135 | } | ||
136 | |||
137 | /* Applies to Tegra30 or later */ | ||
138 | static void __init tegra30_fuse_init_randomness(void) | ||
139 | { | ||
140 | u32 randomness[7]; | ||
141 | |||
142 | randomness[0] = tegra_fuse_readl(FUSE_VENDOR_CODE); | ||
143 | randomness[1] = tegra_fuse_readl(FUSE_FAB_CODE); | ||
144 | randomness[2] = tegra_fuse_readl(FUSE_LOT_CODE_0); | ||
145 | randomness[3] = tegra_fuse_readl(FUSE_LOT_CODE_1); | ||
146 | randomness[4] = tegra_fuse_readl(FUSE_WAFER_ID); | ||
147 | randomness[5] = tegra_fuse_readl(FUSE_X_COORDINATE); | ||
148 | randomness[6] = tegra_fuse_readl(FUSE_Y_COORDINATE); | ||
149 | |||
150 | add_device_randomness(randomness, sizeof(randomness)); | ||
151 | } | ||
152 | |||
115 | void __init tegra_init_fuse(void) | 153 | void __init tegra_init_fuse(void) |
116 | { | 154 | { |
117 | u32 id; | 155 | u32 id; |
156 | u32 randomness[5]; | ||
118 | 157 | ||
119 | u32 reg = readl(IO_ADDRESS(TEGRA_CLK_RESET_BASE + 0x48)); | 158 | u32 reg = readl(IO_ADDRESS(TEGRA_CLK_RESET_BASE + 0x48)); |
120 | reg |= 1 << 28; | 159 | reg |= 1 << 28; |
121 | writel(reg, IO_ADDRESS(TEGRA_CLK_RESET_BASE + 0x48)); | 160 | writel(reg, IO_ADDRESS(TEGRA_CLK_RESET_BASE + 0x48)); |
122 | 161 | ||
123 | reg = tegra_fuse_readl(FUSE_SKU_INFO); | 162 | reg = tegra_fuse_readl(FUSE_SKU_INFO); |
163 | randomness[0] = reg; | ||
124 | tegra_sku_id = reg & 0xFF; | 164 | tegra_sku_id = reg & 0xFF; |
125 | 165 | ||
126 | reg = tegra_apb_readl(TEGRA_APB_MISC_BASE + STRAP_OPT); | 166 | reg = tegra_apb_readl(TEGRA_APB_MISC_BASE + STRAP_OPT); |
167 | randomness[1] = reg; | ||
127 | tegra_bct_strapping = (reg & RAM_ID_MASK) >> RAM_CODE_SHIFT; | 168 | tegra_bct_strapping = (reg & RAM_ID_MASK) >> RAM_CODE_SHIFT; |
128 | 169 | ||
129 | id = tegra_read_chipid(); | 170 | id = tegra_read_chipid(); |
171 | randomness[2] = id; | ||
130 | tegra_chip_id = (id >> 8) & 0xff; | 172 | tegra_chip_id = (id >> 8) & 0xff; |
131 | 173 | ||
132 | switch (tegra_chip_id) { | 174 | switch (tegra_chip_id) { |
@@ -149,6 +191,18 @@ void __init tegra_init_fuse(void) | |||
149 | 191 | ||
150 | tegra_revision = tegra_get_revision(id); | 192 | tegra_revision = tegra_get_revision(id); |
151 | tegra_init_speedo_data(); | 193 | tegra_init_speedo_data(); |
194 | randomness[3] = (tegra_cpu_process_id << 16) | tegra_core_process_id; | ||
195 | randomness[4] = (tegra_cpu_speedo_id << 16) | tegra_soc_speedo_id; | ||
196 | |||
197 | add_device_randomness(randomness, sizeof(randomness)); | ||
198 | switch (tegra_chip_id) { | ||
199 | case TEGRA20: | ||
200 | tegra20_fuse_init_randomness(); | ||
201 | case TEGRA30: | ||
202 | case TEGRA114: | ||
203 | default: | ||
204 | tegra30_fuse_init_randomness(); | ||
205 | } | ||
152 | 206 | ||
153 | pr_info("Tegra Revision: %s SKU: %d CPU Process: %d Core Process: %d\n", | 207 | pr_info("Tegra Revision: %s SKU: %d CPU Process: %d Core Process: %d\n", |
154 | tegra_revision_name[tegra_revision], | 208 | tegra_revision_name[tegra_revision], |