702 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*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/nvmem-provider.h>13#include <linux/platform_device.h>14#include <linux/pm_runtime.h>15#include <linux/random.h>16 17#include <soc/tegra/fuse.h>18 19#include "fuse.h"20 21#define FUSE_BEGIN 0x10022 23/* Tegra30 and later */24#define FUSE_VENDOR_CODE 0x10025#define FUSE_FAB_CODE 0x10426#define FUSE_LOT_CODE_0 0x10827#define FUSE_LOT_CODE_1 0x10c28#define FUSE_WAFER_ID 0x11029#define FUSE_X_COORDINATE 0x11430#define FUSE_Y_COORDINATE 0x11831 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 defined(CONFIG_ARCH_TEGRA_241_SOC)43static 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 51static 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 67static 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 89static 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#endif102 103#ifdef CONFIG_ARCH_TEGRA_3x_SOC104static const struct tegra_fuse_info tegra30_fuse_info = {105 .read = tegra30_fuse_read,106 .size = 0x2a4,107 .spare = 0x144,108};109 110const 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#endif118 119#ifdef CONFIG_ARCH_TEGRA_114_SOC120static const struct tegra_fuse_info tegra114_fuse_info = {121 .read = tegra30_fuse_read,122 .size = 0x2a0,123 .spare = 0x180,124};125 126const 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#endif134 135#if defined(CONFIG_ARCH_TEGRA_124_SOC) || defined(CONFIG_ARCH_TEGRA_132_SOC)136static const struct nvmem_cell_info tegra124_fuse_cells[] = {137 {138 .name = "tsensor-cpu1",139 .offset = 0x084,140 .bytes = 4,141 .bit_offset = 0,142 .nbits = 32,143 }, {144 .name = "tsensor-cpu2",145 .offset = 0x088,146 .bytes = 4,147 .bit_offset = 0,148 .nbits = 32,149 }, {150 .name = "tsensor-cpu0",151 .offset = 0x098,152 .bytes = 4,153 .bit_offset = 0,154 .nbits = 32,155 }, {156 .name = "xusb-pad-calibration",157 .offset = 0x0f0,158 .bytes = 4,159 .bit_offset = 0,160 .nbits = 32,161 }, {162 .name = "tsensor-cpu3",163 .offset = 0x12c,164 .bytes = 4,165 .bit_offset = 0,166 .nbits = 32,167 }, {168 .name = "sata-calibration",169 .offset = 0x124,170 .bytes = 4,171 .bit_offset = 0,172 .nbits = 32,173 }, {174 .name = "tsensor-gpu",175 .offset = 0x154,176 .bytes = 4,177 .bit_offset = 0,178 .nbits = 32,179 }, {180 .name = "tsensor-mem0",181 .offset = 0x158,182 .bytes = 4,183 .bit_offset = 0,184 .nbits = 32,185 }, {186 .name = "tsensor-mem1",187 .offset = 0x15c,188 .bytes = 4,189 .bit_offset = 0,190 .nbits = 32,191 }, {192 .name = "tsensor-pllx",193 .offset = 0x160,194 .bytes = 4,195 .bit_offset = 0,196 .nbits = 32,197 }, {198 .name = "tsensor-common",199 .offset = 0x180,200 .bytes = 4,201 .bit_offset = 0,202 .nbits = 32,203 }, {204 .name = "tsensor-realignment",205 .offset = 0x1fc,206 .bytes = 4,207 .bit_offset = 0,208 .nbits = 32,209 },210};211 212static const struct nvmem_cell_lookup tegra124_fuse_lookups[] = {213 {214 .nvmem_name = "fuse",215 .cell_name = "xusb-pad-calibration",216 .dev_id = "7009f000.padctl",217 .con_id = "calibration",218 }, {219 .nvmem_name = "fuse",220 .cell_name = "sata-calibration",221 .dev_id = "70020000.sata",222 .con_id = "calibration",223 }, {224 .nvmem_name = "fuse",225 .cell_name = "tsensor-common",226 .dev_id = "700e2000.thermal-sensor",227 .con_id = "common",228 }, {229 .nvmem_name = "fuse",230 .cell_name = "tsensor-realignment",231 .dev_id = "700e2000.thermal-sensor",232 .con_id = "realignment",233 }, {234 .nvmem_name = "fuse",235 .cell_name = "tsensor-cpu0",236 .dev_id = "700e2000.thermal-sensor",237 .con_id = "cpu0",238 }, {239 .nvmem_name = "fuse",240 .cell_name = "tsensor-cpu1",241 .dev_id = "700e2000.thermal-sensor",242 .con_id = "cpu1",243 }, {244 .nvmem_name = "fuse",245 .cell_name = "tsensor-cpu2",246 .dev_id = "700e2000.thermal-sensor",247 .con_id = "cpu2",248 }, {249 .nvmem_name = "fuse",250 .cell_name = "tsensor-cpu3",251 .dev_id = "700e2000.thermal-sensor",252 .con_id = "cpu3",253 }, {254 .nvmem_name = "fuse",255 .cell_name = "tsensor-mem0",256 .dev_id = "700e2000.thermal-sensor",257 .con_id = "mem0",258 }, {259 .nvmem_name = "fuse",260 .cell_name = "tsensor-mem1",261 .dev_id = "700e2000.thermal-sensor",262 .con_id = "mem1",263 }, {264 .nvmem_name = "fuse",265 .cell_name = "tsensor-gpu",266 .dev_id = "700e2000.thermal-sensor",267 .con_id = "gpu",268 }, {269 .nvmem_name = "fuse",270 .cell_name = "tsensor-pllx",271 .dev_id = "700e2000.thermal-sensor",272 .con_id = "pllx",273 },274};275 276static const struct tegra_fuse_info tegra124_fuse_info = {277 .read = tegra30_fuse_read,278 .size = 0x300,279 .spare = 0x200,280};281 282const struct tegra_fuse_soc tegra124_fuse_soc = {283 .init = tegra30_fuse_init,284 .speedo_init = tegra124_init_speedo_data,285 .info = &tegra124_fuse_info,286 .lookups = tegra124_fuse_lookups,287 .num_lookups = ARRAY_SIZE(tegra124_fuse_lookups),288 .cells = tegra124_fuse_cells,289 .num_cells = ARRAY_SIZE(tegra124_fuse_cells),290 .soc_attr_group = &tegra_soc_attr_group,291 .clk_suspend_on = true,292};293#endif294 295#if defined(CONFIG_ARCH_TEGRA_210_SOC)296static const struct nvmem_cell_info tegra210_fuse_cells[] = {297 {298 .name = "tsensor-cpu1",299 .offset = 0x084,300 .bytes = 4,301 .bit_offset = 0,302 .nbits = 32,303 }, {304 .name = "tsensor-cpu2",305 .offset = 0x088,306 .bytes = 4,307 .bit_offset = 0,308 .nbits = 32,309 }, {310 .name = "tsensor-cpu0",311 .offset = 0x098,312 .bytes = 4,313 .bit_offset = 0,314 .nbits = 32,315 }, {316 .name = "xusb-pad-calibration",317 .offset = 0x0f0,318 .bytes = 4,319 .bit_offset = 0,320 .nbits = 32,321 }, {322 .name = "tsensor-cpu3",323 .offset = 0x12c,324 .bytes = 4,325 .bit_offset = 0,326 .nbits = 32,327 }, {328 .name = "sata-calibration",329 .offset = 0x124,330 .bytes = 4,331 .bit_offset = 0,332 .nbits = 32,333 }, {334 .name = "tsensor-gpu",335 .offset = 0x154,336 .bytes = 4,337 .bit_offset = 0,338 .nbits = 32,339 }, {340 .name = "tsensor-mem0",341 .offset = 0x158,342 .bytes = 4,343 .bit_offset = 0,344 .nbits = 32,345 }, {346 .name = "tsensor-mem1",347 .offset = 0x15c,348 .bytes = 4,349 .bit_offset = 0,350 .nbits = 32,351 }, {352 .name = "tsensor-pllx",353 .offset = 0x160,354 .bytes = 4,355 .bit_offset = 0,356 .nbits = 32,357 }, {358 .name = "tsensor-common",359 .offset = 0x180,360 .bytes = 4,361 .bit_offset = 0,362 .nbits = 32,363 }, {364 .name = "gpu-calibration",365 .offset = 0x204,366 .bytes = 4,367 .bit_offset = 0,368 .nbits = 32,369 }, {370 .name = "xusb-pad-calibration-ext",371 .offset = 0x250,372 .bytes = 4,373 .bit_offset = 0,374 .nbits = 32,375 },376};377 378static const struct nvmem_cell_lookup tegra210_fuse_lookups[] = {379 {380 .nvmem_name = "fuse",381 .cell_name = "tsensor-cpu1",382 .dev_id = "700e2000.thermal-sensor",383 .con_id = "cpu1",384 }, {385 .nvmem_name = "fuse",386 .cell_name = "tsensor-cpu2",387 .dev_id = "700e2000.thermal-sensor",388 .con_id = "cpu2",389 }, {390 .nvmem_name = "fuse",391 .cell_name = "tsensor-cpu0",392 .dev_id = "700e2000.thermal-sensor",393 .con_id = "cpu0",394 }, {395 .nvmem_name = "fuse",396 .cell_name = "xusb-pad-calibration",397 .dev_id = "7009f000.padctl",398 .con_id = "calibration",399 }, {400 .nvmem_name = "fuse",401 .cell_name = "tsensor-cpu3",402 .dev_id = "700e2000.thermal-sensor",403 .con_id = "cpu3",404 }, {405 .nvmem_name = "fuse",406 .cell_name = "sata-calibration",407 .dev_id = "70020000.sata",408 .con_id = "calibration",409 }, {410 .nvmem_name = "fuse",411 .cell_name = "tsensor-gpu",412 .dev_id = "700e2000.thermal-sensor",413 .con_id = "gpu",414 }, {415 .nvmem_name = "fuse",416 .cell_name = "tsensor-mem0",417 .dev_id = "700e2000.thermal-sensor",418 .con_id = "mem0",419 }, {420 .nvmem_name = "fuse",421 .cell_name = "tsensor-mem1",422 .dev_id = "700e2000.thermal-sensor",423 .con_id = "mem1",424 }, {425 .nvmem_name = "fuse",426 .cell_name = "tsensor-pllx",427 .dev_id = "700e2000.thermal-sensor",428 .con_id = "pllx",429 }, {430 .nvmem_name = "fuse",431 .cell_name = "tsensor-common",432 .dev_id = "700e2000.thermal-sensor",433 .con_id = "common",434 }, {435 .nvmem_name = "fuse",436 .cell_name = "gpu-calibration",437 .dev_id = "57000000.gpu",438 .con_id = "calibration",439 }, {440 .nvmem_name = "fuse",441 .cell_name = "xusb-pad-calibration-ext",442 .dev_id = "7009f000.padctl",443 .con_id = "calibration-ext",444 },445};446 447static const struct tegra_fuse_info tegra210_fuse_info = {448 .read = tegra30_fuse_read,449 .size = 0x300,450 .spare = 0x280,451};452 453const struct tegra_fuse_soc tegra210_fuse_soc = {454 .init = tegra30_fuse_init,455 .speedo_init = tegra210_init_speedo_data,456 .info = &tegra210_fuse_info,457 .lookups = tegra210_fuse_lookups,458 .cells = tegra210_fuse_cells,459 .num_cells = ARRAY_SIZE(tegra210_fuse_cells),460 .num_lookups = ARRAY_SIZE(tegra210_fuse_lookups),461 .soc_attr_group = &tegra_soc_attr_group,462 .clk_suspend_on = false,463};464#endif465 466#if defined(CONFIG_ARCH_TEGRA_186_SOC)467static const struct nvmem_cell_info tegra186_fuse_cells[] = {468 {469 .name = "xusb-pad-calibration",470 .offset = 0x0f0,471 .bytes = 4,472 .bit_offset = 0,473 .nbits = 32,474 }, {475 .name = "xusb-pad-calibration-ext",476 .offset = 0x250,477 .bytes = 4,478 .bit_offset = 0,479 .nbits = 32,480 },481};482 483static const struct nvmem_cell_lookup tegra186_fuse_lookups[] = {484 {485 .nvmem_name = "fuse",486 .cell_name = "xusb-pad-calibration",487 .dev_id = "3520000.padctl",488 .con_id = "calibration",489 }, {490 .nvmem_name = "fuse",491 .cell_name = "xusb-pad-calibration-ext",492 .dev_id = "3520000.padctl",493 .con_id = "calibration-ext",494 },495};496 497static const struct nvmem_keepout tegra186_fuse_keepouts[] = {498 { .start = 0x01c, .end = 0x0f0 },499 { .start = 0x138, .end = 0x198 },500 { .start = 0x1d8, .end = 0x250 },501 { .start = 0x280, .end = 0x290 },502 { .start = 0x340, .end = 0x344 }503};504 505static const struct tegra_fuse_info tegra186_fuse_info = {506 .read = tegra30_fuse_read,507 .size = 0x478,508 .spare = 0x280,509};510 511const struct tegra_fuse_soc tegra186_fuse_soc = {512 .init = tegra30_fuse_init,513 .info = &tegra186_fuse_info,514 .lookups = tegra186_fuse_lookups,515 .num_lookups = ARRAY_SIZE(tegra186_fuse_lookups),516 .cells = tegra186_fuse_cells,517 .num_cells = ARRAY_SIZE(tegra186_fuse_cells),518 .keepouts = tegra186_fuse_keepouts,519 .num_keepouts = ARRAY_SIZE(tegra186_fuse_keepouts),520 .soc_attr_group = &tegra_soc_attr_group,521 .clk_suspend_on = false,522};523#endif524 525#if defined(CONFIG_ARCH_TEGRA_194_SOC)526static const struct nvmem_cell_info tegra194_fuse_cells[] = {527 {528 .name = "xusb-pad-calibration",529 .offset = 0x0f0,530 .bytes = 4,531 .bit_offset = 0,532 .nbits = 32,533 }, {534 .name = "gpu-gcplex-config-fuse",535 .offset = 0x1c8,536 .bytes = 4,537 .bit_offset = 0,538 .nbits = 32,539 }, {540 .name = "xusb-pad-calibration-ext",541 .offset = 0x250,542 .bytes = 4,543 .bit_offset = 0,544 .nbits = 32,545 }, {546 .name = "gpu-pdi0",547 .offset = 0x300,548 .bytes = 4,549 .bit_offset = 0,550 .nbits = 32,551 }, {552 .name = "gpu-pdi1",553 .offset = 0x304,554 .bytes = 4,555 .bit_offset = 0,556 .nbits = 32,557 },558};559 560static const struct nvmem_cell_lookup tegra194_fuse_lookups[] = {561 {562 .nvmem_name = "fuse",563 .cell_name = "xusb-pad-calibration",564 .dev_id = "3520000.padctl",565 .con_id = "calibration",566 }, {567 .nvmem_name = "fuse",568 .cell_name = "xusb-pad-calibration-ext",569 .dev_id = "3520000.padctl",570 .con_id = "calibration-ext",571 }, {572 .nvmem_name = "fuse",573 .cell_name = "gpu-gcplex-config-fuse",574 .dev_id = "17000000.gpu",575 .con_id = "gcplex-config-fuse",576 }, {577 .nvmem_name = "fuse",578 .cell_name = "gpu-pdi0",579 .dev_id = "17000000.gpu",580 .con_id = "pdi0",581 }, {582 .nvmem_name = "fuse",583 .cell_name = "gpu-pdi1",584 .dev_id = "17000000.gpu",585 .con_id = "pdi1",586 },587};588 589static const struct nvmem_keepout tegra194_fuse_keepouts[] = {590 { .start = 0x01c, .end = 0x0b8 },591 { .start = 0x12c, .end = 0x198 },592 { .start = 0x1a0, .end = 0x1bc },593 { .start = 0x1d8, .end = 0x250 },594 { .start = 0x270, .end = 0x290 },595 { .start = 0x310, .end = 0x45c }596};597 598static const struct tegra_fuse_info tegra194_fuse_info = {599 .read = tegra30_fuse_read,600 .size = 0x650,601 .spare = 0x280,602};603 604const struct tegra_fuse_soc tegra194_fuse_soc = {605 .init = tegra30_fuse_init,606 .info = &tegra194_fuse_info,607 .lookups = tegra194_fuse_lookups,608 .num_lookups = ARRAY_SIZE(tegra194_fuse_lookups),609 .cells = tegra194_fuse_cells,610 .num_cells = ARRAY_SIZE(tegra194_fuse_cells),611 .keepouts = tegra194_fuse_keepouts,612 .num_keepouts = ARRAY_SIZE(tegra194_fuse_keepouts),613 .soc_attr_group = &tegra194_soc_attr_group,614 .clk_suspend_on = false,615};616#endif617 618#if defined(CONFIG_ARCH_TEGRA_234_SOC)619static const struct nvmem_cell_info tegra234_fuse_cells[] = {620 {621 .name = "xusb-pad-calibration",622 .offset = 0x0f0,623 .bytes = 4,624 .bit_offset = 0,625 .nbits = 32,626 }, {627 .name = "xusb-pad-calibration-ext",628 .offset = 0x250,629 .bytes = 4,630 .bit_offset = 0,631 .nbits = 32,632 },633};634 635static const struct nvmem_cell_lookup tegra234_fuse_lookups[] = {636 {637 .nvmem_name = "fuse",638 .cell_name = "xusb-pad-calibration",639 .dev_id = "3520000.padctl",640 .con_id = "calibration",641 }, {642 .nvmem_name = "fuse",643 .cell_name = "xusb-pad-calibration-ext",644 .dev_id = "3520000.padctl",645 .con_id = "calibration-ext",646 },647};648 649static const struct nvmem_keepout tegra234_fuse_keepouts[] = {650 { .start = 0x01c, .end = 0x0c8 },651 { .start = 0x12c, .end = 0x184 },652 { .start = 0x190, .end = 0x198 },653 { .start = 0x1a0, .end = 0x204 },654 { .start = 0x21c, .end = 0x250 },655 { .start = 0x25c, .end = 0x2f0 },656 { .start = 0x310, .end = 0x3d8 },657 { .start = 0x400, .end = 0x4f0 },658 { .start = 0x4f8, .end = 0x7e8 },659 { .start = 0x8d0, .end = 0x8d8 },660 { .start = 0xacc, .end = 0xf00 }661};662 663static const struct tegra_fuse_info tegra234_fuse_info = {664 .read = tegra30_fuse_read,665 .size = 0xf90,666 .spare = 0x280,667};668 669const struct tegra_fuse_soc tegra234_fuse_soc = {670 .init = tegra30_fuse_init,671 .info = &tegra234_fuse_info,672 .lookups = tegra234_fuse_lookups,673 .num_lookups = ARRAY_SIZE(tegra234_fuse_lookups),674 .cells = tegra234_fuse_cells,675 .num_cells = ARRAY_SIZE(tegra234_fuse_cells),676 .keepouts = tegra234_fuse_keepouts,677 .num_keepouts = ARRAY_SIZE(tegra234_fuse_keepouts),678 .soc_attr_group = &tegra194_soc_attr_group,679 .clk_suspend_on = false,680};681#endif682 683#if defined(CONFIG_ARCH_TEGRA_241_SOC)684static const struct tegra_fuse_info tegra241_fuse_info = {685 .read = tegra30_fuse_read,686 .size = 0x16008,687 .spare = 0xcf0,688};689 690static const struct nvmem_keepout tegra241_fuse_keepouts[] = {691 { .start = 0xc, .end = 0x1600c }692};693 694const struct tegra_fuse_soc tegra241_fuse_soc = {695 .init = tegra30_fuse_init,696 .info = &tegra241_fuse_info,697 .keepouts = tegra241_fuse_keepouts,698 .num_keepouts = ARRAY_SIZE(tegra241_fuse_keepouts),699 .soc_attr_group = &tegra194_soc_attr_group,700};701#endif702