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