1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Copyright (c) 2013-2022, 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/pm_runtime.h> 16 #include <linux/random.h> 17 18 #include <soc/tegra/fuse.h> 19 20 #include "fuse.h" 21 22 #define FUSE_BEGIN 0x100 23 24 /* Tegra30 and later */ 25 #define FUSE_VENDOR_CODE 0x100 26 #define FUSE_FAB_CODE 0x104 27 #define FUSE_LOT_CODE_0 0x108 28 #define FUSE_LOT_CODE_1 0x10c 29 #define FUSE_WAFER_ID 0x110 30 #define FUSE_X_COORDINATE 0x114 31 #define FUSE_Y_COORDINATE 0x118 32 33 #define FUSE_HAS_REVISION_INFO BIT(0) 34 35 #if defined(CONFIG_ARCH_TEGRA_3x_SOC) || \ 36 defined(CONFIG_ARCH_TEGRA_114_SOC) || \ 37 defined(CONFIG_ARCH_TEGRA_124_SOC) || \ 38 defined(CONFIG_ARCH_TEGRA_132_SOC) || \ 39 defined(CONFIG_ARCH_TEGRA_210_SOC) || \ 40 defined(CONFIG_ARCH_TEGRA_186_SOC) || \ 41 defined(CONFIG_ARCH_TEGRA_194_SOC) || \ 42 defined(CONFIG_ARCH_TEGRA_234_SOC) 43 static u32 tegra30_fuse_read_early(struct tegra_fuse *fuse, unsigned int offset) 44 { 45 if (WARN_ON(!fuse->base)) 46 return 0; 47 48 return readl_relaxed(fuse->base + FUSE_BEGIN + offset); 49 } 50 51 static u32 tegra30_fuse_read(struct tegra_fuse *fuse, unsigned int offset) 52 { 53 u32 value; 54 int err; 55 56 err = pm_runtime_resume_and_get(fuse->dev); 57 if (err) 58 return 0; 59 60 value = readl_relaxed(fuse->base + FUSE_BEGIN + offset); 61 62 pm_runtime_put(fuse->dev); 63 64 return value; 65 } 66 67 static void __init tegra30_fuse_add_randomness(void) 68 { 69 u32 randomness[12]; 70 71 randomness[0] = tegra_sku_info.sku_id; 72 randomness[1] = tegra_read_straps(); 73 randomness[2] = tegra_read_chipid(); 74 randomness[3] = tegra_sku_info.cpu_process_id << 16; 75 randomness[3] |= tegra_sku_info.soc_process_id; 76 randomness[4] = tegra_sku_info.cpu_speedo_id << 16; 77 randomness[4] |= tegra_sku_info.soc_speedo_id; 78 randomness[5] = tegra_fuse_read_early(FUSE_VENDOR_CODE); 79 randomness[6] = tegra_fuse_read_early(FUSE_FAB_CODE); 80 randomness[7] = tegra_fuse_read_early(FUSE_LOT_CODE_0); 81 randomness[8] = tegra_fuse_read_early(FUSE_LOT_CODE_1); 82 randomness[9] = tegra_fuse_read_early(FUSE_WAFER_ID); 83 randomness[10] = tegra_fuse_read_early(FUSE_X_COORDINATE); 84 randomness[11] = tegra_fuse_read_early(FUSE_Y_COORDINATE); 85 86 add_device_randomness(randomness, sizeof(randomness)); 87 } 88 89 static void __init tegra30_fuse_init(struct tegra_fuse *fuse) 90 { 91 fuse->read_early = tegra30_fuse_read_early; 92 fuse->read = tegra30_fuse_read; 93 94 tegra_init_revision(); 95 96 if (fuse->soc->speedo_init) 97 fuse->soc->speedo_init(&tegra_sku_info); 98 99 tegra30_fuse_add_randomness(); 100 } 101 #endif 102 103 #ifdef CONFIG_ARCH_TEGRA_3x_SOC 104 static const struct tegra_fuse_info tegra30_fuse_info = { 105 .read = tegra30_fuse_read, 106 .size = 0x2a4, 107 .spare = 0x144, 108 }; 109 110 const struct tegra_fuse_soc tegra30_fuse_soc = { 111 .init = tegra30_fuse_init, 112 .speedo_init = tegra30_init_speedo_data, 113 .info = &tegra30_fuse_info, 114 .soc_attr_group = &tegra_soc_attr_group, 115 .clk_suspend_on = false, 116 }; 117 #endif 118 119 #ifdef CONFIG_ARCH_TEGRA_114_SOC 120 static const struct tegra_fuse_info tegra114_fuse_info = { 121 .read = tegra30_fuse_read, 122 .size = 0x2a0, 123 .spare = 0x180, 124 }; 125 126 const struct tegra_fuse_soc tegra114_fuse_soc = { 127 .init = tegra30_fuse_init, 128 .speedo_init = tegra114_init_speedo_data, 129 .info = &tegra114_fuse_info, 130 .soc_attr_group = &tegra_soc_attr_group, 131 .clk_suspend_on = false, 132 }; 133 #endif 134 135 #if defined(CONFIG_ARCH_TEGRA_124_SOC) || defined(CONFIG_ARCH_TEGRA_132_SOC) 136 static const struct nvmem_cell_lookup tegra124_fuse_lookups[] = { 137 { 138 .nvmem_name = "fuse", 139 .cell_name = "xusb-pad-calibration", 140 .dev_id = "7009f000.padctl", 141 .con_id = "calibration", 142 }, { 143 .nvmem_name = "fuse", 144 .cell_name = "sata-calibration", 145 .dev_id = "70020000.sata", 146 .con_id = "calibration", 147 }, { 148 .nvmem_name = "fuse", 149 .cell_name = "tsensor-common", 150 .dev_id = "700e2000.thermal-sensor", 151 .con_id = "common", 152 }, { 153 .nvmem_name = "fuse", 154 .cell_name = "tsensor-realignment", 155 .dev_id = "700e2000.thermal-sensor", 156 .con_id = "realignment", 157 }, { 158 .nvmem_name = "fuse", 159 .cell_name = "tsensor-cpu0", 160 .dev_id = "700e2000.thermal-sensor", 161 .con_id = "cpu0", 162 }, { 163 .nvmem_name = "fuse", 164 .cell_name = "tsensor-cpu1", 165 .dev_id = "700e2000.thermal-sensor", 166 .con_id = "cpu1", 167 }, { 168 .nvmem_name = "fuse", 169 .cell_name = "tsensor-cpu2", 170 .dev_id = "700e2000.thermal-sensor", 171 .con_id = "cpu2", 172 }, { 173 .nvmem_name = "fuse", 174 .cell_name = "tsensor-cpu3", 175 .dev_id = "700e2000.thermal-sensor", 176 .con_id = "cpu3", 177 }, { 178 .nvmem_name = "fuse", 179 .cell_name = "tsensor-mem0", 180 .dev_id = "700e2000.thermal-sensor", 181 .con_id = "mem0", 182 }, { 183 .nvmem_name = "fuse", 184 .cell_name = "tsensor-mem1", 185 .dev_id = "700e2000.thermal-sensor", 186 .con_id = "mem1", 187 }, { 188 .nvmem_name = "fuse", 189 .cell_name = "tsensor-gpu", 190 .dev_id = "700e2000.thermal-sensor", 191 .con_id = "gpu", 192 }, { 193 .nvmem_name = "fuse", 194 .cell_name = "tsensor-pllx", 195 .dev_id = "700e2000.thermal-sensor", 196 .con_id = "pllx", 197 }, 198 }; 199 200 static const struct tegra_fuse_info tegra124_fuse_info = { 201 .read = tegra30_fuse_read, 202 .size = 0x300, 203 .spare = 0x200, 204 }; 205 206 const struct tegra_fuse_soc tegra124_fuse_soc = { 207 .init = tegra30_fuse_init, 208 .speedo_init = tegra124_init_speedo_data, 209 .info = &tegra124_fuse_info, 210 .lookups = tegra124_fuse_lookups, 211 .num_lookups = ARRAY_SIZE(tegra124_fuse_lookups), 212 .soc_attr_group = &tegra_soc_attr_group, 213 .clk_suspend_on = true, 214 }; 215 #endif 216 217 #if defined(CONFIG_ARCH_TEGRA_210_SOC) 218 static const struct nvmem_cell_lookup tegra210_fuse_lookups[] = { 219 { 220 .nvmem_name = "fuse", 221 .cell_name = "tsensor-cpu1", 222 .dev_id = "700e2000.thermal-sensor", 223 .con_id = "cpu1", 224 }, { 225 .nvmem_name = "fuse", 226 .cell_name = "tsensor-cpu2", 227 .dev_id = "700e2000.thermal-sensor", 228 .con_id = "cpu2", 229 }, { 230 .nvmem_name = "fuse", 231 .cell_name = "tsensor-cpu0", 232 .dev_id = "700e2000.thermal-sensor", 233 .con_id = "cpu0", 234 }, { 235 .nvmem_name = "fuse", 236 .cell_name = "xusb-pad-calibration", 237 .dev_id = "7009f000.padctl", 238 .con_id = "calibration", 239 }, { 240 .nvmem_name = "fuse", 241 .cell_name = "tsensor-cpu3", 242 .dev_id = "700e2000.thermal-sensor", 243 .con_id = "cpu3", 244 }, { 245 .nvmem_name = "fuse", 246 .cell_name = "sata-calibration", 247 .dev_id = "70020000.sata", 248 .con_id = "calibration", 249 }, { 250 .nvmem_name = "fuse", 251 .cell_name = "tsensor-gpu", 252 .dev_id = "700e2000.thermal-sensor", 253 .con_id = "gpu", 254 }, { 255 .nvmem_name = "fuse", 256 .cell_name = "tsensor-mem0", 257 .dev_id = "700e2000.thermal-sensor", 258 .con_id = "mem0", 259 }, { 260 .nvmem_name = "fuse", 261 .cell_name = "tsensor-mem1", 262 .dev_id = "700e2000.thermal-sensor", 263 .con_id = "mem1", 264 }, { 265 .nvmem_name = "fuse", 266 .cell_name = "tsensor-pllx", 267 .dev_id = "700e2000.thermal-sensor", 268 .con_id = "pllx", 269 }, { 270 .nvmem_name = "fuse", 271 .cell_name = "tsensor-common", 272 .dev_id = "700e2000.thermal-sensor", 273 .con_id = "common", 274 }, { 275 .nvmem_name = "fuse", 276 .cell_name = "gpu-calibration", 277 .dev_id = "57000000.gpu", 278 .con_id = "calibration", 279 }, { 280 .nvmem_name = "fuse", 281 .cell_name = "xusb-pad-calibration-ext", 282 .dev_id = "7009f000.padctl", 283 .con_id = "calibration-ext", 284 }, 285 }; 286 287 static const struct tegra_fuse_info tegra210_fuse_info = { 288 .read = tegra30_fuse_read, 289 .size = 0x300, 290 .spare = 0x280, 291 }; 292 293 const struct tegra_fuse_soc tegra210_fuse_soc = { 294 .init = tegra30_fuse_init, 295 .speedo_init = tegra210_init_speedo_data, 296 .info = &tegra210_fuse_info, 297 .lookups = tegra210_fuse_lookups, 298 .num_lookups = ARRAY_SIZE(tegra210_fuse_lookups), 299 .soc_attr_group = &tegra_soc_attr_group, 300 .clk_suspend_on = false, 301 }; 302 #endif 303 304 #if defined(CONFIG_ARCH_TEGRA_186_SOC) 305 static const struct nvmem_cell_lookup tegra186_fuse_lookups[] = { 306 { 307 .nvmem_name = "fuse", 308 .cell_name = "xusb-pad-calibration", 309 .dev_id = "3520000.padctl", 310 .con_id = "calibration", 311 }, { 312 .nvmem_name = "fuse", 313 .cell_name = "xusb-pad-calibration-ext", 314 .dev_id = "3520000.padctl", 315 .con_id = "calibration-ext", 316 }, 317 }; 318 319 static const struct tegra_fuse_info tegra186_fuse_info = { 320 .read = tegra30_fuse_read, 321 .size = 0x300, 322 .spare = 0x280, 323 }; 324 325 const struct tegra_fuse_soc tegra186_fuse_soc = { 326 .init = tegra30_fuse_init, 327 .info = &tegra186_fuse_info, 328 .lookups = tegra186_fuse_lookups, 329 .num_lookups = ARRAY_SIZE(tegra186_fuse_lookups), 330 .soc_attr_group = &tegra_soc_attr_group, 331 .clk_suspend_on = false, 332 }; 333 #endif 334 335 #if defined(CONFIG_ARCH_TEGRA_194_SOC) 336 static const struct nvmem_cell_lookup tegra194_fuse_lookups[] = { 337 { 338 .nvmem_name = "fuse", 339 .cell_name = "xusb-pad-calibration", 340 .dev_id = "3520000.padctl", 341 .con_id = "calibration", 342 }, { 343 .nvmem_name = "fuse", 344 .cell_name = "xusb-pad-calibration-ext", 345 .dev_id = "3520000.padctl", 346 .con_id = "calibration-ext", 347 }, { 348 .nvmem_name = "fuse", 349 .cell_name = "gpu-gcplex-config-fuse", 350 .dev_id = "17000000.gpu", 351 .con_id = "gcplex-config-fuse", 352 }, { 353 .nvmem_name = "fuse", 354 .cell_name = "gpu-pdi0", 355 .dev_id = "17000000.gpu", 356 .con_id = "pdi0", 357 }, { 358 .nvmem_name = "fuse", 359 .cell_name = "gpu-pdi1", 360 .dev_id = "17000000.gpu", 361 .con_id = "pdi1", 362 }, 363 }; 364 365 static const struct tegra_fuse_info tegra194_fuse_info = { 366 .read = tegra30_fuse_read, 367 .size = 0x300, 368 .spare = 0x280, 369 }; 370 371 const struct tegra_fuse_soc tegra194_fuse_soc = { 372 .init = tegra30_fuse_init, 373 .info = &tegra194_fuse_info, 374 .lookups = tegra194_fuse_lookups, 375 .num_lookups = ARRAY_SIZE(tegra194_fuse_lookups), 376 .soc_attr_group = &tegra194_soc_attr_group, 377 .clk_suspend_on = false, 378 }; 379 #endif 380 381 #if defined(CONFIG_ARCH_TEGRA_234_SOC) 382 static const struct nvmem_cell_lookup tegra234_fuse_lookups[] = { 383 { 384 .nvmem_name = "fuse", 385 .cell_name = "xusb-pad-calibration", 386 .dev_id = "3520000.padctl", 387 .con_id = "calibration", 388 }, { 389 .nvmem_name = "fuse", 390 .cell_name = "xusb-pad-calibration-ext", 391 .dev_id = "3520000.padctl", 392 .con_id = "calibration-ext", 393 }, 394 }; 395 396 static const struct tegra_fuse_info tegra234_fuse_info = { 397 .read = tegra30_fuse_read, 398 .size = 0x300, 399 .spare = 0x280, 400 }; 401 402 const struct tegra_fuse_soc tegra234_fuse_soc = { 403 .init = tegra30_fuse_init, 404 .info = &tegra234_fuse_info, 405 .lookups = tegra234_fuse_lookups, 406 .num_lookups = ARRAY_SIZE(tegra234_fuse_lookups), 407 .soc_attr_group = &tegra194_soc_attr_group, 408 .clk_suspend_on = false, 409 }; 410 #endif 411