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 }; 115 #endif 116 117 #ifdef CONFIG_ARCH_TEGRA_114_SOC 118 static const struct tegra_fuse_info tegra114_fuse_info = { 119 .read = tegra30_fuse_read, 120 .size = 0x2a0, 121 .spare = 0x180, 122 }; 123 124 const struct tegra_fuse_soc tegra114_fuse_soc = { 125 .init = tegra30_fuse_init, 126 .speedo_init = tegra114_init_speedo_data, 127 .info = &tegra114_fuse_info, 128 }; 129 #endif 130 131 #if defined(CONFIG_ARCH_TEGRA_124_SOC) || defined(CONFIG_ARCH_TEGRA_132_SOC) 132 static const struct nvmem_cell_lookup tegra124_fuse_lookups[] = { 133 { 134 .nvmem_name = "fuse", 135 .cell_name = "xusb-pad-calibration", 136 .dev_id = "7009f000.padctl", 137 .con_id = "calibration", 138 }, { 139 .nvmem_name = "fuse", 140 .cell_name = "sata-calibration", 141 .dev_id = "70020000.sata", 142 .con_id = "calibration", 143 }, { 144 .nvmem_name = "fuse", 145 .cell_name = "tsensor-common", 146 .dev_id = "700e2000.thermal-sensor", 147 .con_id = "common", 148 }, { 149 .nvmem_name = "fuse", 150 .cell_name = "tsensor-realignment", 151 .dev_id = "700e2000.thermal-sensor", 152 .con_id = "realignment", 153 }, { 154 .nvmem_name = "fuse", 155 .cell_name = "tsensor-cpu0", 156 .dev_id = "700e2000.thermal-sensor", 157 .con_id = "cpu0", 158 }, { 159 .nvmem_name = "fuse", 160 .cell_name = "tsensor-cpu1", 161 .dev_id = "700e2000.thermal-sensor", 162 .con_id = "cpu1", 163 }, { 164 .nvmem_name = "fuse", 165 .cell_name = "tsensor-cpu2", 166 .dev_id = "700e2000.thermal-sensor", 167 .con_id = "cpu2", 168 }, { 169 .nvmem_name = "fuse", 170 .cell_name = "tsensor-cpu3", 171 .dev_id = "700e2000.thermal-sensor", 172 .con_id = "cpu3", 173 }, { 174 .nvmem_name = "fuse", 175 .cell_name = "tsensor-mem0", 176 .dev_id = "700e2000.thermal-sensor", 177 .con_id = "mem0", 178 }, { 179 .nvmem_name = "fuse", 180 .cell_name = "tsensor-mem1", 181 .dev_id = "700e2000.thermal-sensor", 182 .con_id = "mem1", 183 }, { 184 .nvmem_name = "fuse", 185 .cell_name = "tsensor-gpu", 186 .dev_id = "700e2000.thermal-sensor", 187 .con_id = "gpu", 188 }, { 189 .nvmem_name = "fuse", 190 .cell_name = "tsensor-pllx", 191 .dev_id = "700e2000.thermal-sensor", 192 .con_id = "pllx", 193 }, 194 }; 195 196 static const struct tegra_fuse_info tegra124_fuse_info = { 197 .read = tegra30_fuse_read, 198 .size = 0x300, 199 .spare = 0x200, 200 }; 201 202 const struct tegra_fuse_soc tegra124_fuse_soc = { 203 .init = tegra30_fuse_init, 204 .speedo_init = tegra124_init_speedo_data, 205 .info = &tegra124_fuse_info, 206 .lookups = tegra124_fuse_lookups, 207 .num_lookups = ARRAY_SIZE(tegra124_fuse_lookups), 208 }; 209 #endif 210 211 #if defined(CONFIG_ARCH_TEGRA_210_SOC) 212 static const struct nvmem_cell_lookup tegra210_fuse_lookups[] = { 213 { 214 .nvmem_name = "fuse", 215 .cell_name = "tsensor-cpu1", 216 .dev_id = "700e2000.thermal-sensor", 217 .con_id = "cpu1", 218 }, { 219 .nvmem_name = "fuse", 220 .cell_name = "tsensor-cpu2", 221 .dev_id = "700e2000.thermal-sensor", 222 .con_id = "cpu2", 223 }, { 224 .nvmem_name = "fuse", 225 .cell_name = "tsensor-cpu0", 226 .dev_id = "700e2000.thermal-sensor", 227 .con_id = "cpu0", 228 }, { 229 .nvmem_name = "fuse", 230 .cell_name = "xusb-pad-calibration", 231 .dev_id = "7009f000.padctl", 232 .con_id = "calibration", 233 }, { 234 .nvmem_name = "fuse", 235 .cell_name = "tsensor-cpu3", 236 .dev_id = "700e2000.thermal-sensor", 237 .con_id = "cpu3", 238 }, { 239 .nvmem_name = "fuse", 240 .cell_name = "sata-calibration", 241 .dev_id = "70020000.sata", 242 .con_id = "calibration", 243 }, { 244 .nvmem_name = "fuse", 245 .cell_name = "tsensor-gpu", 246 .dev_id = "700e2000.thermal-sensor", 247 .con_id = "gpu", 248 }, { 249 .nvmem_name = "fuse", 250 .cell_name = "tsensor-mem0", 251 .dev_id = "700e2000.thermal-sensor", 252 .con_id = "mem0", 253 }, { 254 .nvmem_name = "fuse", 255 .cell_name = "tsensor-mem1", 256 .dev_id = "700e2000.thermal-sensor", 257 .con_id = "mem1", 258 }, { 259 .nvmem_name = "fuse", 260 .cell_name = "tsensor-pllx", 261 .dev_id = "700e2000.thermal-sensor", 262 .con_id = "pllx", 263 }, { 264 .nvmem_name = "fuse", 265 .cell_name = "tsensor-common", 266 .dev_id = "700e2000.thermal-sensor", 267 .con_id = "common", 268 }, { 269 .nvmem_name = "fuse", 270 .cell_name = "gpu-calibration", 271 .dev_id = "57000000.gpu", 272 .con_id = "calibration", 273 }, { 274 .nvmem_name = "fuse", 275 .cell_name = "xusb-pad-calibration-ext", 276 .dev_id = "7009f000.padctl", 277 .con_id = "calibration-ext", 278 }, 279 }; 280 281 static const struct tegra_fuse_info tegra210_fuse_info = { 282 .read = tegra30_fuse_read, 283 .size = 0x300, 284 .spare = 0x280, 285 }; 286 287 const struct tegra_fuse_soc tegra210_fuse_soc = { 288 .init = tegra30_fuse_init, 289 .speedo_init = tegra210_init_speedo_data, 290 .info = &tegra210_fuse_info, 291 .lookups = tegra210_fuse_lookups, 292 .num_lookups = ARRAY_SIZE(tegra210_fuse_lookups), 293 }; 294 #endif 295 296 #if defined(CONFIG_ARCH_TEGRA_186_SOC) 297 static const struct nvmem_cell_lookup tegra186_fuse_lookups[] = { 298 { 299 .nvmem_name = "fuse", 300 .cell_name = "xusb-pad-calibration", 301 .dev_id = "3520000.padctl", 302 .con_id = "calibration", 303 }, { 304 .nvmem_name = "fuse", 305 .cell_name = "xusb-pad-calibration-ext", 306 .dev_id = "3520000.padctl", 307 .con_id = "calibration-ext", 308 }, 309 }; 310 311 static const struct tegra_fuse_info tegra186_fuse_info = { 312 .read = tegra30_fuse_read, 313 .size = 0x300, 314 .spare = 0x280, 315 }; 316 317 const struct tegra_fuse_soc tegra186_fuse_soc = { 318 .init = tegra30_fuse_init, 319 .info = &tegra186_fuse_info, 320 .lookups = tegra186_fuse_lookups, 321 .num_lookups = ARRAY_SIZE(tegra186_fuse_lookups), 322 }; 323 #endif 324 325 #if defined(CONFIG_ARCH_TEGRA_194_SOC) 326 static const struct nvmem_cell_lookup tegra194_fuse_lookups[] = { 327 { 328 .nvmem_name = "fuse", 329 .cell_name = "xusb-pad-calibration", 330 .dev_id = "3520000.padctl", 331 .con_id = "calibration", 332 }, { 333 .nvmem_name = "fuse", 334 .cell_name = "xusb-pad-calibration-ext", 335 .dev_id = "3520000.padctl", 336 .con_id = "calibration-ext", 337 }, 338 }; 339 340 static const struct tegra_fuse_info tegra194_fuse_info = { 341 .read = tegra30_fuse_read, 342 .size = 0x300, 343 .spare = 0x280, 344 }; 345 346 const struct tegra_fuse_soc tegra194_fuse_soc = { 347 .init = tegra30_fuse_init, 348 .info = &tegra194_fuse_info, 349 .lookups = tegra194_fuse_lookups, 350 .num_lookups = ARRAY_SIZE(tegra194_fuse_lookups), 351 }; 352 #endif 353