1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Copyright (c) 2013-2014, NVIDIA CORPORATION. All rights reserved. 4 */ 5 6 #include <linux/device.h> 7 #include <linux/clk.h> 8 #include <linux/err.h> 9 #include <linux/io.h> 10 #include <linux/kernel.h> 11 #include <linux/nvmem-consumer.h> 12 #include <linux/of_device.h> 13 #include <linux/of_address.h> 14 #include <linux/platform_device.h> 15 #include <linux/random.h> 16 17 #include <soc/tegra/fuse.h> 18 19 #include "fuse.h" 20 21 #define FUSE_BEGIN 0x100 22 23 /* Tegra30 and later */ 24 #define FUSE_VENDOR_CODE 0x100 25 #define FUSE_FAB_CODE 0x104 26 #define FUSE_LOT_CODE_0 0x108 27 #define FUSE_LOT_CODE_1 0x10c 28 #define FUSE_WAFER_ID 0x110 29 #define FUSE_X_COORDINATE 0x114 30 #define FUSE_Y_COORDINATE 0x118 31 32 #define FUSE_HAS_REVISION_INFO BIT(0) 33 34 #if defined(CONFIG_ARCH_TEGRA_3x_SOC) || \ 35 defined(CONFIG_ARCH_TEGRA_114_SOC) || \ 36 defined(CONFIG_ARCH_TEGRA_124_SOC) || \ 37 defined(CONFIG_ARCH_TEGRA_132_SOC) || \ 38 defined(CONFIG_ARCH_TEGRA_210_SOC) || \ 39 defined(CONFIG_ARCH_TEGRA_186_SOC) 40 static u32 tegra30_fuse_read_early(struct tegra_fuse *fuse, unsigned int offset) 41 { 42 if (WARN_ON(!fuse->base)) 43 return 0; 44 45 return readl_relaxed(fuse->base + FUSE_BEGIN + offset); 46 } 47 48 static u32 tegra30_fuse_read(struct tegra_fuse *fuse, unsigned int offset) 49 { 50 u32 value; 51 int err; 52 53 err = clk_prepare_enable(fuse->clk); 54 if (err < 0) { 55 dev_err(fuse->dev, "failed to enable FUSE clock: %d\n", err); 56 return 0; 57 } 58 59 value = readl_relaxed(fuse->base + FUSE_BEGIN + offset); 60 61 clk_disable_unprepare(fuse->clk); 62 63 return value; 64 } 65 66 static void __init tegra30_fuse_add_randomness(void) 67 { 68 u32 randomness[12]; 69 70 randomness[0] = tegra_sku_info.sku_id; 71 randomness[1] = tegra_read_straps(); 72 randomness[2] = tegra_read_chipid(); 73 randomness[3] = tegra_sku_info.cpu_process_id << 16; 74 randomness[3] |= tegra_sku_info.soc_process_id; 75 randomness[4] = tegra_sku_info.cpu_speedo_id << 16; 76 randomness[4] |= tegra_sku_info.soc_speedo_id; 77 randomness[5] = tegra_fuse_read_early(FUSE_VENDOR_CODE); 78 randomness[6] = tegra_fuse_read_early(FUSE_FAB_CODE); 79 randomness[7] = tegra_fuse_read_early(FUSE_LOT_CODE_0); 80 randomness[8] = tegra_fuse_read_early(FUSE_LOT_CODE_1); 81 randomness[9] = tegra_fuse_read_early(FUSE_WAFER_ID); 82 randomness[10] = tegra_fuse_read_early(FUSE_X_COORDINATE); 83 randomness[11] = tegra_fuse_read_early(FUSE_Y_COORDINATE); 84 85 add_device_randomness(randomness, sizeof(randomness)); 86 } 87 88 static void __init tegra30_fuse_init(struct tegra_fuse *fuse) 89 { 90 fuse->read_early = tegra30_fuse_read_early; 91 fuse->read = tegra30_fuse_read; 92 93 tegra_init_revision(); 94 95 if (fuse->soc->speedo_init) 96 fuse->soc->speedo_init(&tegra_sku_info); 97 98 tegra30_fuse_add_randomness(); 99 } 100 #endif 101 102 #ifdef CONFIG_ARCH_TEGRA_3x_SOC 103 static const struct tegra_fuse_info tegra30_fuse_info = { 104 .read = tegra30_fuse_read, 105 .size = 0x2a4, 106 .spare = 0x144, 107 }; 108 109 const struct tegra_fuse_soc tegra30_fuse_soc = { 110 .init = tegra30_fuse_init, 111 .speedo_init = tegra30_init_speedo_data, 112 .info = &tegra30_fuse_info, 113 }; 114 #endif 115 116 #ifdef CONFIG_ARCH_TEGRA_114_SOC 117 static const struct tegra_fuse_info tegra114_fuse_info = { 118 .read = tegra30_fuse_read, 119 .size = 0x2a0, 120 .spare = 0x180, 121 }; 122 123 const struct tegra_fuse_soc tegra114_fuse_soc = { 124 .init = tegra30_fuse_init, 125 .speedo_init = tegra114_init_speedo_data, 126 .info = &tegra114_fuse_info, 127 }; 128 #endif 129 130 #if defined(CONFIG_ARCH_TEGRA_124_SOC) || defined(CONFIG_ARCH_TEGRA_132_SOC) 131 static const struct nvmem_cell_lookup tegra124_fuse_lookups[] = { 132 { 133 .nvmem_name = "fuse", 134 .cell_name = "xusb-pad-calibration", 135 .dev_id = "7009f000.padctl", 136 .con_id = "calibration", 137 }, { 138 .nvmem_name = "fuse", 139 .cell_name = "sata-calibration", 140 .dev_id = "70020000.sata", 141 .con_id = "calibration", 142 }, { 143 .nvmem_name = "fuse", 144 .cell_name = "tsensor-common", 145 .dev_id = "700e2000.thermal-sensor", 146 .con_id = "common", 147 }, { 148 .nvmem_name = "fuse", 149 .cell_name = "tsensor-realignment", 150 .dev_id = "700e2000.thermal-sensor", 151 .con_id = "realignment", 152 }, { 153 .nvmem_name = "fuse", 154 .cell_name = "tsensor-cpu0", 155 .dev_id = "700e2000.thermal-sensor", 156 .con_id = "cpu0", 157 }, { 158 .nvmem_name = "fuse", 159 .cell_name = "tsensor-cpu1", 160 .dev_id = "700e2000.thermal-sensor", 161 .con_id = "cpu1", 162 }, { 163 .nvmem_name = "fuse", 164 .cell_name = "tsensor-cpu2", 165 .dev_id = "700e2000.thermal-sensor", 166 .con_id = "cpu2", 167 }, { 168 .nvmem_name = "fuse", 169 .cell_name = "tsensor-cpu3", 170 .dev_id = "700e2000.thermal-sensor", 171 .con_id = "cpu3", 172 }, { 173 .nvmem_name = "fuse", 174 .cell_name = "tsensor-mem0", 175 .dev_id = "700e2000.thermal-sensor", 176 .con_id = "mem0", 177 }, { 178 .nvmem_name = "fuse", 179 .cell_name = "tsensor-mem1", 180 .dev_id = "700e2000.thermal-sensor", 181 .con_id = "mem1", 182 }, { 183 .nvmem_name = "fuse", 184 .cell_name = "tsensor-gpu", 185 .dev_id = "700e2000.thermal-sensor", 186 .con_id = "gpu", 187 }, { 188 .nvmem_name = "fuse", 189 .cell_name = "tsensor-pllx", 190 .dev_id = "700e2000.thermal-sensor", 191 .con_id = "pllx", 192 }, 193 }; 194 195 static const struct tegra_fuse_info tegra124_fuse_info = { 196 .read = tegra30_fuse_read, 197 .size = 0x300, 198 .spare = 0x200, 199 }; 200 201 const struct tegra_fuse_soc tegra124_fuse_soc = { 202 .init = tegra30_fuse_init, 203 .speedo_init = tegra124_init_speedo_data, 204 .info = &tegra124_fuse_info, 205 .lookups = tegra124_fuse_lookups, 206 .num_lookups = ARRAY_SIZE(tegra124_fuse_lookups), 207 }; 208 #endif 209 210 #if defined(CONFIG_ARCH_TEGRA_210_SOC) 211 static const struct nvmem_cell_lookup tegra210_fuse_lookups[] = { 212 { 213 .nvmem_name = "fuse", 214 .cell_name = "tsensor-cpu1", 215 .dev_id = "700e2000.thermal-sensor", 216 .con_id = "cpu1", 217 }, { 218 .nvmem_name = "fuse", 219 .cell_name = "tsensor-cpu2", 220 .dev_id = "700e2000.thermal-sensor", 221 .con_id = "cpu2", 222 }, { 223 .nvmem_name = "fuse", 224 .cell_name = "tsensor-cpu0", 225 .dev_id = "700e2000.thermal-sensor", 226 .con_id = "cpu0", 227 }, { 228 .nvmem_name = "fuse", 229 .cell_name = "xusb-pad-calibration", 230 .dev_id = "7009f000.padctl", 231 .con_id = "calibration", 232 }, { 233 .nvmem_name = "fuse", 234 .cell_name = "tsensor-cpu3", 235 .dev_id = "700e2000.thermal-sensor", 236 .con_id = "cpu3", 237 }, { 238 .nvmem_name = "fuse", 239 .cell_name = "sata-calibration", 240 .dev_id = "70020000.sata", 241 .con_id = "calibration", 242 }, { 243 .nvmem_name = "fuse", 244 .cell_name = "tsensor-gpu", 245 .dev_id = "700e2000.thermal-sensor", 246 .con_id = "gpu", 247 }, { 248 .nvmem_name = "fuse", 249 .cell_name = "tsensor-mem0", 250 .dev_id = "700e2000.thermal-sensor", 251 .con_id = "mem0", 252 }, { 253 .nvmem_name = "fuse", 254 .cell_name = "tsensor-mem1", 255 .dev_id = "700e2000.thermal-sensor", 256 .con_id = "mem1", 257 }, { 258 .nvmem_name = "fuse", 259 .cell_name = "tsensor-pllx", 260 .dev_id = "700e2000.thermal-sensor", 261 .con_id = "pllx", 262 }, { 263 .nvmem_name = "fuse", 264 .cell_name = "tsensor-common", 265 .dev_id = "700e2000.thermal-sensor", 266 .con_id = "common", 267 }, { 268 .nvmem_name = "fuse", 269 .cell_name = "gpu-calibration", 270 .dev_id = "57000000.gpu", 271 .con_id = "calibration", 272 }, { 273 .nvmem_name = "fuse", 274 .cell_name = "xusb-pad-calibration-ext", 275 .dev_id = "7009f000.padctl", 276 .con_id = "calibration-ext", 277 }, 278 }; 279 280 static const struct tegra_fuse_info tegra210_fuse_info = { 281 .read = tegra30_fuse_read, 282 .size = 0x300, 283 .spare = 0x280, 284 }; 285 286 const struct tegra_fuse_soc tegra210_fuse_soc = { 287 .init = tegra30_fuse_init, 288 .speedo_init = tegra210_init_speedo_data, 289 .info = &tegra210_fuse_info, 290 .lookups = tegra210_fuse_lookups, 291 .num_lookups = ARRAY_SIZE(tegra210_fuse_lookups), 292 }; 293 #endif 294 295 #if defined(CONFIG_ARCH_TEGRA_186_SOC) 296 static const struct nvmem_cell_lookup tegra186_fuse_lookups[] = { 297 { 298 .nvmem_name = "fuse", 299 .cell_name = "xusb-pad-calibration", 300 .dev_id = "3520000.padctl", 301 .con_id = "calibration", 302 }, { 303 .nvmem_name = "fuse", 304 .cell_name = "xusb-pad-calibration-ext", 305 .dev_id = "3520000.padctl", 306 .con_id = "calibration-ext", 307 }, 308 }; 309 310 static const struct tegra_fuse_info tegra186_fuse_info = { 311 .read = tegra30_fuse_read, 312 .size = 0x300, 313 .spare = 0x280, 314 }; 315 316 const struct tegra_fuse_soc tegra186_fuse_soc = { 317 .init = tegra30_fuse_init, 318 .info = &tegra186_fuse_info, 319 .lookups = tegra186_fuse_lookups, 320 .num_lookups = ARRAY_SIZE(tegra186_fuse_lookups), 321 }; 322 #endif 323