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 static u32 tegra30_fuse_read_early(struct tegra_fuse *fuse, unsigned int offset) 42 { 43 if (WARN_ON(!fuse->base)) 44 return 0; 45 46 return readl_relaxed(fuse->base + FUSE_BEGIN + offset); 47 } 48 49 static u32 tegra30_fuse_read(struct tegra_fuse *fuse, unsigned int offset) 50 { 51 u32 value; 52 int err; 53 54 err = clk_prepare_enable(fuse->clk); 55 if (err < 0) { 56 dev_err(fuse->dev, "failed to enable FUSE clock: %d\n", err); 57 return 0; 58 } 59 60 value = readl_relaxed(fuse->base + FUSE_BEGIN + offset); 61 62 clk_disable_unprepare(fuse->clk); 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 }; 116 #endif 117 118 #ifdef CONFIG_ARCH_TEGRA_114_SOC 119 static const struct tegra_fuse_info tegra114_fuse_info = { 120 .read = tegra30_fuse_read, 121 .size = 0x2a0, 122 .spare = 0x180, 123 }; 124 125 const struct tegra_fuse_soc tegra114_fuse_soc = { 126 .init = tegra30_fuse_init, 127 .speedo_init = tegra114_init_speedo_data, 128 .info = &tegra114_fuse_info, 129 .soc_attr_group = &tegra_soc_attr_group, 130 }; 131 #endif 132 133 #if defined(CONFIG_ARCH_TEGRA_124_SOC) || defined(CONFIG_ARCH_TEGRA_132_SOC) 134 static const struct nvmem_cell_lookup tegra124_fuse_lookups[] = { 135 { 136 .nvmem_name = "fuse", 137 .cell_name = "xusb-pad-calibration", 138 .dev_id = "7009f000.padctl", 139 .con_id = "calibration", 140 }, { 141 .nvmem_name = "fuse", 142 .cell_name = "sata-calibration", 143 .dev_id = "70020000.sata", 144 .con_id = "calibration", 145 }, { 146 .nvmem_name = "fuse", 147 .cell_name = "tsensor-common", 148 .dev_id = "700e2000.thermal-sensor", 149 .con_id = "common", 150 }, { 151 .nvmem_name = "fuse", 152 .cell_name = "tsensor-realignment", 153 .dev_id = "700e2000.thermal-sensor", 154 .con_id = "realignment", 155 }, { 156 .nvmem_name = "fuse", 157 .cell_name = "tsensor-cpu0", 158 .dev_id = "700e2000.thermal-sensor", 159 .con_id = "cpu0", 160 }, { 161 .nvmem_name = "fuse", 162 .cell_name = "tsensor-cpu1", 163 .dev_id = "700e2000.thermal-sensor", 164 .con_id = "cpu1", 165 }, { 166 .nvmem_name = "fuse", 167 .cell_name = "tsensor-cpu2", 168 .dev_id = "700e2000.thermal-sensor", 169 .con_id = "cpu2", 170 }, { 171 .nvmem_name = "fuse", 172 .cell_name = "tsensor-cpu3", 173 .dev_id = "700e2000.thermal-sensor", 174 .con_id = "cpu3", 175 }, { 176 .nvmem_name = "fuse", 177 .cell_name = "tsensor-mem0", 178 .dev_id = "700e2000.thermal-sensor", 179 .con_id = "mem0", 180 }, { 181 .nvmem_name = "fuse", 182 .cell_name = "tsensor-mem1", 183 .dev_id = "700e2000.thermal-sensor", 184 .con_id = "mem1", 185 }, { 186 .nvmem_name = "fuse", 187 .cell_name = "tsensor-gpu", 188 .dev_id = "700e2000.thermal-sensor", 189 .con_id = "gpu", 190 }, { 191 .nvmem_name = "fuse", 192 .cell_name = "tsensor-pllx", 193 .dev_id = "700e2000.thermal-sensor", 194 .con_id = "pllx", 195 }, 196 }; 197 198 static const struct tegra_fuse_info tegra124_fuse_info = { 199 .read = tegra30_fuse_read, 200 .size = 0x300, 201 .spare = 0x200, 202 }; 203 204 const struct tegra_fuse_soc tegra124_fuse_soc = { 205 .init = tegra30_fuse_init, 206 .speedo_init = tegra124_init_speedo_data, 207 .info = &tegra124_fuse_info, 208 .lookups = tegra124_fuse_lookups, 209 .num_lookups = ARRAY_SIZE(tegra124_fuse_lookups), 210 .soc_attr_group = &tegra_soc_attr_group, 211 }; 212 #endif 213 214 #if defined(CONFIG_ARCH_TEGRA_210_SOC) 215 static const struct nvmem_cell_lookup tegra210_fuse_lookups[] = { 216 { 217 .nvmem_name = "fuse", 218 .cell_name = "tsensor-cpu1", 219 .dev_id = "700e2000.thermal-sensor", 220 .con_id = "cpu1", 221 }, { 222 .nvmem_name = "fuse", 223 .cell_name = "tsensor-cpu2", 224 .dev_id = "700e2000.thermal-sensor", 225 .con_id = "cpu2", 226 }, { 227 .nvmem_name = "fuse", 228 .cell_name = "tsensor-cpu0", 229 .dev_id = "700e2000.thermal-sensor", 230 .con_id = "cpu0", 231 }, { 232 .nvmem_name = "fuse", 233 .cell_name = "xusb-pad-calibration", 234 .dev_id = "7009f000.padctl", 235 .con_id = "calibration", 236 }, { 237 .nvmem_name = "fuse", 238 .cell_name = "tsensor-cpu3", 239 .dev_id = "700e2000.thermal-sensor", 240 .con_id = "cpu3", 241 }, { 242 .nvmem_name = "fuse", 243 .cell_name = "sata-calibration", 244 .dev_id = "70020000.sata", 245 .con_id = "calibration", 246 }, { 247 .nvmem_name = "fuse", 248 .cell_name = "tsensor-gpu", 249 .dev_id = "700e2000.thermal-sensor", 250 .con_id = "gpu", 251 }, { 252 .nvmem_name = "fuse", 253 .cell_name = "tsensor-mem0", 254 .dev_id = "700e2000.thermal-sensor", 255 .con_id = "mem0", 256 }, { 257 .nvmem_name = "fuse", 258 .cell_name = "tsensor-mem1", 259 .dev_id = "700e2000.thermal-sensor", 260 .con_id = "mem1", 261 }, { 262 .nvmem_name = "fuse", 263 .cell_name = "tsensor-pllx", 264 .dev_id = "700e2000.thermal-sensor", 265 .con_id = "pllx", 266 }, { 267 .nvmem_name = "fuse", 268 .cell_name = "tsensor-common", 269 .dev_id = "700e2000.thermal-sensor", 270 .con_id = "common", 271 }, { 272 .nvmem_name = "fuse", 273 .cell_name = "gpu-calibration", 274 .dev_id = "57000000.gpu", 275 .con_id = "calibration", 276 }, { 277 .nvmem_name = "fuse", 278 .cell_name = "xusb-pad-calibration-ext", 279 .dev_id = "7009f000.padctl", 280 .con_id = "calibration-ext", 281 }, 282 }; 283 284 static const struct tegra_fuse_info tegra210_fuse_info = { 285 .read = tegra30_fuse_read, 286 .size = 0x300, 287 .spare = 0x280, 288 }; 289 290 const struct tegra_fuse_soc tegra210_fuse_soc = { 291 .init = tegra30_fuse_init, 292 .speedo_init = tegra210_init_speedo_data, 293 .info = &tegra210_fuse_info, 294 .lookups = tegra210_fuse_lookups, 295 .num_lookups = ARRAY_SIZE(tegra210_fuse_lookups), 296 .soc_attr_group = &tegra_soc_attr_group, 297 }; 298 #endif 299 300 #if defined(CONFIG_ARCH_TEGRA_186_SOC) 301 static const struct nvmem_cell_lookup tegra186_fuse_lookups[] = { 302 { 303 .nvmem_name = "fuse", 304 .cell_name = "xusb-pad-calibration", 305 .dev_id = "3520000.padctl", 306 .con_id = "calibration", 307 }, { 308 .nvmem_name = "fuse", 309 .cell_name = "xusb-pad-calibration-ext", 310 .dev_id = "3520000.padctl", 311 .con_id = "calibration-ext", 312 }, 313 }; 314 315 static const struct tegra_fuse_info tegra186_fuse_info = { 316 .read = tegra30_fuse_read, 317 .size = 0x300, 318 .spare = 0x280, 319 }; 320 321 const struct tegra_fuse_soc tegra186_fuse_soc = { 322 .init = tegra30_fuse_init, 323 .info = &tegra186_fuse_info, 324 .lookups = tegra186_fuse_lookups, 325 .num_lookups = ARRAY_SIZE(tegra186_fuse_lookups), 326 .soc_attr_group = &tegra_soc_attr_group, 327 }; 328 #endif 329 330 #if defined(CONFIG_ARCH_TEGRA_194_SOC) 331 static const struct nvmem_cell_lookup tegra194_fuse_lookups[] = { 332 { 333 .nvmem_name = "fuse", 334 .cell_name = "xusb-pad-calibration", 335 .dev_id = "3520000.padctl", 336 .con_id = "calibration", 337 }, { 338 .nvmem_name = "fuse", 339 .cell_name = "xusb-pad-calibration-ext", 340 .dev_id = "3520000.padctl", 341 .con_id = "calibration-ext", 342 }, 343 }; 344 345 static const struct tegra_fuse_info tegra194_fuse_info = { 346 .read = tegra30_fuse_read, 347 .size = 0x300, 348 .spare = 0x280, 349 }; 350 351 const struct tegra_fuse_soc tegra194_fuse_soc = { 352 .init = tegra30_fuse_init, 353 .info = &tegra194_fuse_info, 354 .lookups = tegra194_fuse_lookups, 355 .num_lookups = ARRAY_SIZE(tegra194_fuse_lookups), 356 .soc_attr_group = &tegra194_soc_attr_group, 357 }; 358 #endif 359 360 #if defined(CONFIG_ARCH_TEGRA_234_SOC) 361 static const struct nvmem_cell_lookup tegra234_fuse_lookups[] = { 362 { 363 .nvmem_name = "fuse", 364 .cell_name = "xusb-pad-calibration", 365 .dev_id = "3520000.padctl", 366 .con_id = "calibration", 367 }, { 368 .nvmem_name = "fuse", 369 .cell_name = "xusb-pad-calibration-ext", 370 .dev_id = "3520000.padctl", 371 .con_id = "calibration-ext", 372 }, 373 }; 374 375 static const struct tegra_fuse_info tegra234_fuse_info = { 376 .read = tegra30_fuse_read, 377 .size = 0x300, 378 .spare = 0x280, 379 }; 380 381 const struct tegra_fuse_soc tegra234_fuse_soc = { 382 .init = tegra30_fuse_init, 383 .info = &tegra234_fuse_info, 384 .lookups = tegra234_fuse_lookups, 385 .num_lookups = ARRAY_SIZE(tegra234_fuse_lookups), 386 .soc_attr_group = &tegra194_soc_attr_group, 387 }; 388 #endif 389