summaryrefslogtreecommitdiff
path: root/arch/arm/mach-tegra/fuse.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/mach-tegra/fuse.c')
-rw-r--r--arch/arm/mach-tegra/fuse.c102
1 files changed, 101 insertions, 1 deletions
diff --git a/arch/arm/mach-tegra/fuse.c b/arch/arm/mach-tegra/fuse.c
index 1aa393c18323..dad92e4b365f 100644
--- a/arch/arm/mach-tegra/fuse.c
+++ b/arch/arm/mach-tegra/fuse.c
@@ -25,10 +25,26 @@
#include "fuse.h"
#include "apbio.h"
+#define FUSE_SKU_INFO 0x110
+#if defined(CONFIG_ARCH_TEGRA_2x_SOC)
#define FUSE_UID_LOW 0x108
#define FUSE_UID_HIGH 0x10c
-#define FUSE_SKU_INFO 0x110
#define FUSE_SPARE_BIT 0x200
+#elif defined(CONFIG_ARCH_TEGRA_3x_SOC)
+#define FUSE_VENDOR_CODE 0x200
+#define FUSE_VENDOR_CODE_MASK 0xf
+#define FUSE_FAB_CODE 0x204
+#define FUSE_FAB_CODE_MASK 0x3f
+#define FUSE_LOT_CODE_0 0x208
+#define FUSE_LOT_CODE_1 0x20c
+#define FUSE_WAFER_ID 0x210
+#define FUSE_WAFER_ID_MASK 0x3f
+#define FUSE_X_COORDINATE 0x214
+#define FUSE_X_COORDINATE_MASK 0x1ff
+#define FUSE_Y_COORDINATE 0x218
+#define FUSE_Y_COORDINATE_MASK 0x1ff
+#define FUSE_SPARE_BIT 0x244
+#endif
static const char *tegra_revision_name[TEGRA_REVISION_MAX] = {
[TEGRA_REVISION_UNKNOWN] = "unknown",
@@ -67,11 +83,95 @@ void tegra_init_fuse(void)
unsigned long long tegra_chip_uid(void)
{
+#if defined(CONFIG_ARCH_TEGRA_2x_SOC)
unsigned long long lo, hi;
lo = tegra_fuse_readl(FUSE_UID_LOW);
hi = tegra_fuse_readl(FUSE_UID_HIGH);
return (hi << 32ull) | lo;
+#else
+ u64 uid = 0ull;
+#if 0 // !!!FIXME!!! FOR SOME REASON THIS IS GENERATING BAD CODE .......................................
+ u32 reg;
+ u32 cid;
+ u32 vendor;
+ u32 fab;
+ u32 lot;
+ u32 wafer;
+ u32 x;
+ u32 y;
+ u32 i;
+
+ /* This used to be so much easier in prior chips. Unfortunately, there
+ is no one-stop shopping for the unique id anymore. It must be
+ constructed from various bits of information burned into the fuses
+ during the manufacturing process. The 64-bit unique id is formed
+ by concatenating several bit fields. The notation used for the
+ various fields is <fieldname:size_in_bits> with the UID composed
+ thusly:
+
+ <CID:4><VENDOR:4><FAB:6><LOT:26><WAFER:6><X:9><Y:9>
+
+ Where:
+
+ Field Bits Position Data
+ ------- ---- -------- ----------------------------------------
+ CID 4 60 Chip id (encoded as zero for T30)
+ VENDOR 4 56 Vendor code
+ FAB 6 50 FAB code
+ LOT 26 24 Lot code (5-digit base-36-coded-decimal,
+ re-encoded to 26 bits binary)
+ WAFER 6 18 Wafer id
+ X 9 9 Wafer X-coordinate
+ Y 9 0 Wafer Y-coordinate
+ ------- ----
+ Total 64
+ */
+
+ /* Get the chip id and encode each chip variant as a unique value. */
+ reg = readl(IO_TO_VIRT(TEGRA_APB_MISC_BASE + 0x804));
+ reg = (reg >> 8) && 0xFF;
+
+ switch (reg) {
+ case 0x30:
+ cid = 0;
+ break;
+
+ default:
+ BUG();
+ break;
+ }
+
+ vendor = fuse_readl(FUSE_VENDOR_CODE) & FUSE_VENDOR_CODE_MASK;
+ fab = fuse_readl(FUSE_FAB_CODE) & FUSE_FAB_CODE_MASK;
+
+ /* Lot code must be re-encoded from a 5 digit base-36 'BCD' number
+ to a binary number. */
+ lot = 0;
+ reg = fuse_readl(FUSE_LOT_CODE_1) << 2;
+
+ for (i = 0; i < 5; ++i) {
+ u32 digit = (reg & 0xFC000000) >> 26;
+ BUG_ON(digit >= 36);
+ lot *= 36;
+ lot += digit;
+ reg <<= 6;
+ }
+
+ wafer = fuse_readl(FUSE_WAFER_ID) & FUSE_WAFER_ID_MASK;
+ x = fuse_readl(FUSE_X_COORDINATE) & FUSE_X_COORDINATE_MASK;
+ y = fuse_readl(FUSE_Y_COORDINATE) & FUSE_Y_COORDINATE_MASK;
+
+ uid = ((unsigned long long)cid << 60ull)
+ | ((unsigned long long)vendor << 56ull)
+ | ((unsigned long long)fab << 50ull)
+ | ((unsigned long long)lot << 24ull)
+ | ((unsigned long long)wafer << 18ull)
+ | ((unsigned long long)x << 9ull)
+ | ((unsigned long long)y << 0ull);
+#endif
+ return uid;
+#endif
}
unsigned int tegra_spare_fuse(int bit)