mirror of
				https://github.com/smaeul/u-boot.git
				synced 2025-10-31 03:58:17 +00:00 
			
		
		
		
	As part of bringing the master branch back in to next, we need to allow for all of these changes to exist here. Reported-by: Jonas Karlman <jonas@kwiboo.se> Signed-off-by: Tom Rini <trini@konsulko.com>
		
			
				
	
	
		
			151 lines
		
	
	
		
			3.7 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			151 lines
		
	
	
		
			3.7 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| // SPDX-License-Identifier: GPL-2.0+
 | |
| /*
 | |
|  *  (C) Copyright 2012-2013
 | |
|  *  NVIDIA Corporation <www.nvidia.com>
 | |
|  *
 | |
|  *  (C) Copyright 2022
 | |
|  *  Svyatoslav Ryhel <clamor95@gmail.com>
 | |
|  */
 | |
| 
 | |
| #include <linux/delay.h>
 | |
| #include <asm/io.h>
 | |
| 
 | |
| #include <asm/arch/tegra.h>
 | |
| #include <asm/arch/gp_padctrl.h>
 | |
| #include <asm/arch/clock.h>
 | |
| #include <asm/arch-tegra/fuse.h>
 | |
| 
 | |
| #include "cpu.h"
 | |
| 
 | |
| #define FUSE_UID_LOW		0x108
 | |
| #define FUSE_UID_HIGH		0x10c
 | |
| 
 | |
| #define FUSE_VENDOR_CODE	0x200
 | |
| #define FUSE_FAB_CODE		0x204
 | |
| #define FUSE_LOT_CODE_0		0x208
 | |
| #define FUSE_LOT_CODE_1		0x20c
 | |
| #define FUSE_WAFER_ID		0x210
 | |
| #define FUSE_X_COORDINATE	0x214
 | |
| #define FUSE_Y_COORDINATE	0x218
 | |
| 
 | |
| #define FUSE_VENDOR_CODE_MASK	0xf
 | |
| #define FUSE_FAB_CODE_MASK	0x3f
 | |
| #define FUSE_WAFER_ID_MASK	0x3f
 | |
| #define FUSE_X_COORDINATE_MASK	0x1ff
 | |
| #define FUSE_Y_COORDINATE_MASK	0x1ff
 | |
| 
 | |
| static u32 tegra_fuse_readl(unsigned long offset)
 | |
| {
 | |
| 	return readl(NV_PA_FUSE_BASE + offset);
 | |
| }
 | |
| 
 | |
| static void tegra_fuse_init(void)
 | |
| {
 | |
| 	u32 reg;
 | |
| 
 | |
| 	/*
 | |
| 	 * Performed by downstream and is not
 | |
| 	 * documented by TRM. Whithout setting
 | |
| 	 * this bit fuse region will not work.
 | |
| 	 */
 | |
| 	reg = readl_relaxed(NV_PA_CLK_RST_BASE + 0x48);
 | |
| 	reg |= BIT(28);
 | |
| 	writel(reg, NV_PA_CLK_RST_BASE + 0x48);
 | |
| 
 | |
| 	clock_enable(PERIPH_ID_FUSE);
 | |
| 	udelay(2);
 | |
| 	reset_set_enable(PERIPH_ID_FUSE, 0);
 | |
| }
 | |
| 
 | |
| unsigned long long tegra_chip_uid(void)
 | |
| {
 | |
| 	u64 uid = 0ull;
 | |
| 	u32 reg;
 | |
| 	u32 cid;
 | |
| 	u32 vendor;
 | |
| 	u32 fab;
 | |
| 	u32 lot;
 | |
| 	u32 wafer;
 | |
| 	u32 x;
 | |
| 	u32 y;
 | |
| 	u32 i;
 | |
| 
 | |
| 	tegra_fuse_init();
 | |
| 
 | |
| 	/* 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
 | |
| 		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
 | |
| 	*/
 | |
| 
 | |
| 	switch (tegra_get_chip()) {
 | |
| 	case CHIPID_TEGRA20:
 | |
| 		/* T20 has simple calculation */
 | |
| 		return ((unsigned long long)tegra_fuse_readl(FUSE_UID_HIGH) << 32ull) |
 | |
| 			(unsigned long long)tegra_fuse_readl(FUSE_UID_LOW);
 | |
| 	case CHIPID_TEGRA30:
 | |
| 		/* T30 chip id is 0 */
 | |
| 		cid = 0;
 | |
| 		break;
 | |
| 	case CHIPID_TEGRA114:
 | |
| 		/* T11x chip id is 1 */
 | |
| 		cid = 1;
 | |
| 		break;
 | |
| 	case CHIPID_TEGRA124:
 | |
| 		/* T12x chip id is 3 */
 | |
| 		cid = 3;
 | |
| 		break;
 | |
| 	case CHIPID_TEGRA210:
 | |
| 		/* T210 chip id is 5 */
 | |
| 		cid = 5;
 | |
| 	default:
 | |
| 		return 0;
 | |
| 	}
 | |
| 
 | |
| 	vendor = tegra_fuse_readl(FUSE_VENDOR_CODE) & FUSE_VENDOR_CODE_MASK;
 | |
| 	fab = tegra_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 = tegra_fuse_readl(FUSE_LOT_CODE_0) << 2;
 | |
| 
 | |
| 	for (i = 0; i < 5; ++i) {
 | |
| 		u32 digit = (reg & 0xFC000000) >> 26;
 | |
| 		lot *= 36;
 | |
| 		lot += digit;
 | |
| 		reg <<= 6;
 | |
| 	}
 | |
| 
 | |
| 	wafer = tegra_fuse_readl(FUSE_WAFER_ID) & FUSE_WAFER_ID_MASK;
 | |
| 	x = tegra_fuse_readl(FUSE_X_COORDINATE) & FUSE_X_COORDINATE_MASK;
 | |
| 	y = tegra_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);
 | |
| 
 | |
| 	return uid;
 | |
| }
 |