Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

soc/tegra: Add efuse driver for Tegra

Implement fuse driver for Tegra20, Tegra30, Tegra114 and Tegra124. This
replaces functionality previously provided in arch/arm/mach-tegra, which
is removed in this patch.

While at it, move the only user of the global tegra_revision variable
over to tegra_sku_info.revision and export tegra_fuse_readl() to allow
drivers to read calibration fuses.

Signed-off-by: Peter De Schrijver <pdeschrijver@nvidia.com>
Signed-off-by: Stephen Warren <swarren@nvidia.com>
Signed-off-by: Thierry Reding <treding@nvidia.com>

authored by

Peter De Schrijver and committed by
Thierry Reding
783c8f4c 35874f36

+1047 -461
+11
Documentation/ABI/testing/sysfs-driver-tegra-fuse
··· 1 + What: /sys/devices/*/<our-device>/fuse 2 + Date: February 2014 3 + Contact: Peter De Schrijver <pdeschrijver@nvidia.com> 4 + Description: read-only access to the efuses on Tegra20, Tegra30, Tegra114 5 + and Tegra124 SoC's from NVIDIA. The efuses contain write once 6 + data programmed at the factory. The data is layed out in 32bit 7 + words in LSB first format. Each bit represents a single value 8 + as decoded from the fuse registers. Bits order/assignment 9 + exactly matches the HW registers, including any unused bits. 10 + Users: any user space application which wants to read the efuses on 11 + Tegra SoC's
-4
arch/arm/mach-tegra/Makefile
··· 2 2 3 3 obj-y += io.o 4 4 obj-y += irq.o 5 - obj-y += fuse.o 6 5 obj-y += pmc.o 7 6 obj-y += flowctrl.o 8 7 obj-y += powergate.o ··· 12 13 obj-y += sleep.o 13 14 obj-y += tegra.o 14 15 obj-$(CONFIG_CPU_IDLE) += cpuidle.o 15 - obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += tegra20_speedo.o 16 16 obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += sleep-tegra20.o 17 17 obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += pm-tegra20.o 18 18 ifeq ($(CONFIG_CPU_IDLE),y) 19 19 obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += cpuidle-tegra20.o 20 20 endif 21 - obj-$(CONFIG_ARCH_TEGRA_3x_SOC) += tegra30_speedo.o 22 21 obj-$(CONFIG_ARCH_TEGRA_3x_SOC) += sleep-tegra30.o 23 22 obj-$(CONFIG_ARCH_TEGRA_3x_SOC) += pm-tegra30.o 24 23 ifeq ($(CONFIG_CPU_IDLE),y) ··· 25 28 obj-$(CONFIG_SMP) += platsmp.o headsmp.o 26 29 obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o 27 30 28 - obj-$(CONFIG_ARCH_TEGRA_114_SOC) += tegra114_speedo.o 29 31 obj-$(CONFIG_ARCH_TEGRA_114_SOC) += sleep-tegra30.o 30 32 obj-$(CONFIG_ARCH_TEGRA_114_SOC) += pm-tegra30.o 31 33 ifeq ($(CONFIG_CPU_IDLE),y)
-260
arch/arm/mach-tegra/fuse.c
··· 1 - /* 2 - * arch/arm/mach-tegra/fuse.c 3 - * 4 - * Copyright (C) 2010 Google, Inc. 5 - * Copyright (c) 2013, NVIDIA CORPORATION. All rights reserved. 6 - * 7 - * Author: 8 - * Colin Cross <ccross@android.com> 9 - * 10 - * This software is licensed under the terms of the GNU General Public 11 - * License version 2, as published by the Free Software Foundation, and 12 - * may be copied, distributed, and modified under those terms. 13 - * 14 - * This program is distributed in the hope that it will be useful, 15 - * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 - * GNU General Public License for more details. 18 - * 19 - */ 20 - 21 - #include <linux/clk.h> 22 - #include <linux/export.h> 23 - #include <linux/io.h> 24 - #include <linux/kernel.h> 25 - #include <linux/random.h> 26 - 27 - #include <soc/tegra/fuse.h> 28 - 29 - #include "apbio.h" 30 - #include "fuse.h" 31 - #include "iomap.h" 32 - 33 - /* Tegra20 only */ 34 - #define FUSE_UID_LOW 0x108 35 - #define FUSE_UID_HIGH 0x10c 36 - 37 - /* Tegra30 and later */ 38 - #define FUSE_VENDOR_CODE 0x200 39 - #define FUSE_FAB_CODE 0x204 40 - #define FUSE_LOT_CODE_0 0x208 41 - #define FUSE_LOT_CODE_1 0x20c 42 - #define FUSE_WAFER_ID 0x210 43 - #define FUSE_X_COORDINATE 0x214 44 - #define FUSE_Y_COORDINATE 0x218 45 - 46 - #define FUSE_SKU_INFO 0x110 47 - 48 - #define TEGRA20_FUSE_SPARE_BIT 0x200 49 - #define TEGRA30_FUSE_SPARE_BIT 0x244 50 - 51 - int tegra_sku_id; 52 - int tegra_cpu_process_id; 53 - int tegra_core_process_id; 54 - int tegra_cpu_speedo_id; /* only exist in Tegra30 and later */ 55 - int tegra_soc_speedo_id; 56 - enum tegra_revision tegra_revision; 57 - 58 - static struct clk *fuse_clk; 59 - static int tegra_fuse_spare_bit; 60 - static void (*tegra_init_speedo_data)(void); 61 - 62 - /* The BCT to use at boot is specified by board straps that can be read 63 - * through a APB misc register and decoded. 2 bits, i.e. 4 possible BCTs. 64 - */ 65 - int tegra_bct_strapping; 66 - 67 - #define STRAP_OPT 0x008 68 - #define GMI_AD0 (1 << 4) 69 - #define GMI_AD1 (1 << 5) 70 - #define RAM_ID_MASK (GMI_AD0 | GMI_AD1) 71 - #define RAM_CODE_SHIFT 4 72 - 73 - static const char *tegra_revision_name[TEGRA_REVISION_MAX] = { 74 - [TEGRA_REVISION_UNKNOWN] = "unknown", 75 - [TEGRA_REVISION_A01] = "A01", 76 - [TEGRA_REVISION_A02] = "A02", 77 - [TEGRA_REVISION_A03] = "A03", 78 - [TEGRA_REVISION_A03p] = "A03 prime", 79 - [TEGRA_REVISION_A04] = "A04", 80 - }; 81 - 82 - static void tegra_fuse_enable_clk(void) 83 - { 84 - if (IS_ERR(fuse_clk)) 85 - fuse_clk = clk_get_sys(NULL, "fuse"); 86 - if (IS_ERR(fuse_clk)) 87 - return; 88 - clk_prepare_enable(fuse_clk); 89 - } 90 - 91 - static void tegra_fuse_disable_clk(void) 92 - { 93 - if (IS_ERR(fuse_clk)) 94 - return; 95 - clk_disable_unprepare(fuse_clk); 96 - } 97 - 98 - u32 tegra_fuse_readl(unsigned long offset) 99 - { 100 - return tegra_apb_readl(TEGRA_FUSE_BASE + offset); 101 - } 102 - 103 - bool tegra_spare_fuse(int bit) 104 - { 105 - bool ret; 106 - 107 - tegra_fuse_enable_clk(); 108 - 109 - ret = tegra_fuse_readl(tegra_fuse_spare_bit + bit * 4); 110 - 111 - tegra_fuse_disable_clk(); 112 - 113 - return ret; 114 - } 115 - 116 - static enum tegra_revision tegra_get_revision(u32 id) 117 - { 118 - u32 minor_rev = (id >> 16) & 0xf; 119 - 120 - switch (minor_rev) { 121 - case 1: 122 - return TEGRA_REVISION_A01; 123 - case 2: 124 - return TEGRA_REVISION_A02; 125 - case 3: 126 - if (tegra_get_chip_id() == TEGRA20 && 127 - (tegra_spare_fuse(18) || tegra_spare_fuse(19))) 128 - return TEGRA_REVISION_A03p; 129 - else 130 - return TEGRA_REVISION_A03; 131 - case 4: 132 - return TEGRA_REVISION_A04; 133 - default: 134 - return TEGRA_REVISION_UNKNOWN; 135 - } 136 - } 137 - 138 - static void tegra_get_process_id(void) 139 - { 140 - u32 reg; 141 - 142 - tegra_fuse_enable_clk(); 143 - 144 - reg = tegra_fuse_readl(tegra_fuse_spare_bit); 145 - tegra_cpu_process_id = (reg >> 6) & 3; 146 - reg = tegra_fuse_readl(tegra_fuse_spare_bit); 147 - tegra_core_process_id = (reg >> 12) & 3; 148 - 149 - tegra_fuse_disable_clk(); 150 - } 151 - 152 - u32 tegra_read_chipid(void) 153 - { 154 - return readl_relaxed(IO_ADDRESS(TEGRA_APB_MISC_BASE) + 0x804); 155 - } 156 - 157 - u8 tegra_get_chip_id(void) 158 - { 159 - u32 id = tegra_read_chipid(); 160 - 161 - return (id >> 8) & 0xff; 162 - } 163 - 164 - static void __init tegra20_fuse_init_randomness(void) 165 - { 166 - u32 randomness[2]; 167 - 168 - randomness[0] = tegra_fuse_readl(FUSE_UID_LOW); 169 - randomness[1] = tegra_fuse_readl(FUSE_UID_HIGH); 170 - 171 - add_device_randomness(randomness, sizeof(randomness)); 172 - } 173 - 174 - /* Applies to Tegra30 or later */ 175 - static void __init tegra30_fuse_init_randomness(void) 176 - { 177 - u32 randomness[7]; 178 - 179 - randomness[0] = tegra_fuse_readl(FUSE_VENDOR_CODE); 180 - randomness[1] = tegra_fuse_readl(FUSE_FAB_CODE); 181 - randomness[2] = tegra_fuse_readl(FUSE_LOT_CODE_0); 182 - randomness[3] = tegra_fuse_readl(FUSE_LOT_CODE_1); 183 - randomness[4] = tegra_fuse_readl(FUSE_WAFER_ID); 184 - randomness[5] = tegra_fuse_readl(FUSE_X_COORDINATE); 185 - randomness[6] = tegra_fuse_readl(FUSE_Y_COORDINATE); 186 - 187 - add_device_randomness(randomness, sizeof(randomness)); 188 - } 189 - 190 - void __init tegra_init_fuse(void) 191 - { 192 - u32 id; 193 - u32 randomness[5]; 194 - u8 chip_id; 195 - 196 - u32 reg = readl(IO_ADDRESS(TEGRA_CLK_RESET_BASE + 0x48)); 197 - reg |= 1 << 28; 198 - writel(reg, IO_ADDRESS(TEGRA_CLK_RESET_BASE + 0x48)); 199 - 200 - /* 201 - * Enable FUSE clock. This needs to be hardcoded because the clock 202 - * subsystem is not active during early boot. 203 - */ 204 - reg = readl(IO_ADDRESS(TEGRA_CLK_RESET_BASE + 0x14)); 205 - reg |= 1 << 7; 206 - writel(reg, IO_ADDRESS(TEGRA_CLK_RESET_BASE + 0x14)); 207 - fuse_clk = ERR_PTR(-EINVAL); 208 - 209 - reg = tegra_fuse_readl(FUSE_SKU_INFO); 210 - randomness[0] = reg; 211 - tegra_sku_id = reg & 0xFF; 212 - 213 - reg = tegra_apb_readl(TEGRA_APB_MISC_BASE + STRAP_OPT); 214 - randomness[1] = reg; 215 - tegra_bct_strapping = (reg & RAM_ID_MASK) >> RAM_CODE_SHIFT; 216 - 217 - id = tegra_read_chipid(); 218 - randomness[2] = id; 219 - chip_id = (id >> 8) & 0xff; 220 - 221 - switch (chip_id) { 222 - case TEGRA20: 223 - tegra_fuse_spare_bit = TEGRA20_FUSE_SPARE_BIT; 224 - tegra_init_speedo_data = &tegra20_init_speedo_data; 225 - break; 226 - case TEGRA30: 227 - tegra_fuse_spare_bit = TEGRA30_FUSE_SPARE_BIT; 228 - tegra_init_speedo_data = &tegra30_init_speedo_data; 229 - break; 230 - case TEGRA114: 231 - tegra_init_speedo_data = &tegra114_init_speedo_data; 232 - break; 233 - default: 234 - pr_warn("Tegra: unknown chip id %d\n", chip_id); 235 - tegra_fuse_spare_bit = TEGRA20_FUSE_SPARE_BIT; 236 - tegra_init_speedo_data = &tegra_get_process_id; 237 - } 238 - 239 - tegra_revision = tegra_get_revision(id); 240 - tegra_init_speedo_data(); 241 - randomness[3] = (tegra_cpu_process_id << 16) | tegra_core_process_id; 242 - randomness[4] = (tegra_cpu_speedo_id << 16) | tegra_soc_speedo_id; 243 - 244 - add_device_randomness(randomness, sizeof(randomness)); 245 - switch (chip_id) { 246 - case TEGRA20: 247 - tegra20_fuse_init_randomness(); 248 - break; 249 - case TEGRA30: 250 - case TEGRA114: 251 - default: 252 - tegra30_fuse_init_randomness(); 253 - break; 254 - } 255 - 256 - pr_info("Tegra Revision: %s SKU: %d CPU Process: %d Core Process: %d\n", 257 - tegra_revision_name[tegra_revision], 258 - tegra_sku_id, tegra_cpu_process_id, 259 - tegra_core_process_id); 260 - }
-60
arch/arm/mach-tegra/fuse.h
··· 1 - /* 2 - * Copyright (C) 2010 Google, Inc. 3 - * Copyright (c) 2013, NVIDIA CORPORATION. All rights reserved. 4 - * 5 - * Author: 6 - * Colin Cross <ccross@android.com> 7 - * 8 - * This software is licensed under the terms of the GNU General Public 9 - * License version 2, as published by the Free Software Foundation, and 10 - * may be copied, distributed, and modified under those terms. 11 - * 12 - * This program is distributed in the hope that it will be useful, 13 - * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 - * GNU General Public License for more details. 16 - * 17 - */ 18 - 19 - #ifndef __MACH_TEGRA_FUSE_H 20 - #define __MACH_TEGRA_FUSE_H 21 - 22 - #define SKU_ID_T20 8 23 - #define SKU_ID_T25SE 20 24 - #define SKU_ID_AP25 23 25 - #define SKU_ID_T25 24 26 - #define SKU_ID_AP25E 27 27 - #define SKU_ID_T25E 28 28 - 29 - #ifndef __ASSEMBLY__ 30 - 31 - extern int tegra_sku_id; 32 - extern int tegra_cpu_process_id; 33 - extern int tegra_core_process_id; 34 - extern int tegra_cpu_speedo_id; /* only exist in Tegra30 and later */ 35 - extern int tegra_soc_speedo_id; 36 - 37 - unsigned long long tegra_chip_uid(void); 38 - bool tegra_spare_fuse(int bit); 39 - u32 tegra_fuse_readl(unsigned long offset); 40 - 41 - #ifdef CONFIG_ARCH_TEGRA_2x_SOC 42 - void tegra20_init_speedo_data(void); 43 - #else 44 - static inline void tegra20_init_speedo_data(void) {} 45 - #endif 46 - 47 - #ifdef CONFIG_ARCH_TEGRA_3x_SOC 48 - void tegra30_init_speedo_data(void); 49 - #else 50 - static inline void tegra30_init_speedo_data(void) {} 51 - #endif 52 - 53 - #ifdef CONFIG_ARCH_TEGRA_114_SOC 54 - void tegra114_init_speedo_data(void); 55 - #else 56 - static inline void tegra114_init_speedo_data(void) {} 57 - #endif 58 - #endif /* __ASSEMBLY__ */ 59 - 60 - #endif
-1
arch/arm/mach-tegra/reset.c
··· 25 25 #include <asm/firmware.h> 26 26 #include <asm/hardware/cache-l2x0.h> 27 27 28 - #include "fuse.h" 29 28 #include "iomap.h" 30 29 #include "irammap.h" 31 30 #include "reset.h"
+2 -1
arch/arm/mach-tegra/tegra.c
··· 104 104 goto out; 105 105 106 106 soc_dev_attr->family = kasprintf(GFP_KERNEL, "Tegra"); 107 - soc_dev_attr->revision = kasprintf(GFP_KERNEL, "%d", tegra_revision); 107 + soc_dev_attr->revision = kasprintf(GFP_KERNEL, "%d", 108 + tegra_sku_info.revision); 108 109 soc_dev_attr->soc_id = kasprintf(GFP_KERNEL, "%u", tegra_get_chip_id()); 109 110 110 111 soc_dev = soc_device_register(soc_dev_attr);
+28 -24
arch/arm/mach-tegra/tegra114_speedo.c drivers/soc/tegra/fuse/speedo-tegra114.c
··· 1 1 /* 2 - * Copyright (c) 2013, NVIDIA CORPORATION. All rights reserved. 2 + * Copyright (c) 2013-2014, NVIDIA CORPORATION. All rights reserved. 3 3 * 4 4 * This program is free software; you can redistribute it and/or modify it 5 5 * under the terms and conditions of the GNU General Public License, ··· 15 15 */ 16 16 17 17 #include <linux/bug.h> 18 + #include <linux/device.h> 18 19 #include <linux/kernel.h> 19 20 20 21 #include <soc/tegra/fuse.h> 21 22 22 23 #include "fuse.h" 23 24 24 - #define CORE_PROCESS_CORNERS_NUM 2 25 - #define CPU_PROCESS_CORNERS_NUM 2 25 + #define CORE_PROCESS_CORNERS 2 26 + #define CPU_PROCESS_CORNERS 2 26 27 27 28 enum { 28 29 THRESHOLD_INDEX_0, ··· 31 30 THRESHOLD_INDEX_COUNT, 32 31 }; 33 32 34 - static const u32 core_process_speedos[][CORE_PROCESS_CORNERS_NUM] = { 33 + static const u32 __initconst core_process_speedos[][CORE_PROCESS_CORNERS] = { 35 34 {1123, UINT_MAX}, 36 35 {0, UINT_MAX}, 37 36 }; 38 37 39 - static const u32 cpu_process_speedos[][CPU_PROCESS_CORNERS_NUM] = { 38 + static const u32 __initconst cpu_process_speedos[][CPU_PROCESS_CORNERS] = { 40 39 {1695, UINT_MAX}, 41 40 {0, UINT_MAX}, 42 41 }; 43 42 44 - static void rev_sku_to_speedo_ids(int rev, int sku, int *threshold) 43 + static void __init rev_sku_to_speedo_ids(struct tegra_sku_info *sku_info, 44 + int *threshold) 45 45 { 46 46 u32 tmp; 47 + u32 sku = sku_info->sku_id; 48 + enum tegra_revision rev = sku_info->revision; 47 49 48 50 switch (sku) { 49 51 case 0x00: 50 52 case 0x10: 51 53 case 0x05: 52 54 case 0x06: 53 - tegra_cpu_speedo_id = 1; 54 - tegra_soc_speedo_id = 0; 55 + sku_info->cpu_speedo_id = 1; 56 + sku_info->soc_speedo_id = 0; 55 57 *threshold = THRESHOLD_INDEX_0; 56 58 break; 57 59 58 60 case 0x03: 59 61 case 0x04: 60 - tegra_cpu_speedo_id = 2; 61 - tegra_soc_speedo_id = 1; 62 + sku_info->cpu_speedo_id = 2; 63 + sku_info->soc_speedo_id = 1; 62 64 *threshold = THRESHOLD_INDEX_1; 63 65 break; 64 66 65 67 default: 66 - pr_err("Tegra114 Unknown SKU %d\n", sku); 67 - tegra_cpu_speedo_id = 0; 68 - tegra_soc_speedo_id = 0; 68 + pr_err("Tegra Unknown SKU %d\n", sku); 69 + sku_info->cpu_speedo_id = 0; 70 + sku_info->soc_speedo_id = 0; 69 71 *threshold = THRESHOLD_INDEX_0; 70 72 break; 71 73 } 72 74 73 75 if (rev == TEGRA_REVISION_A01) { 74 - tmp = tegra_fuse_readl(0x270) << 1; 75 - tmp |= tegra_fuse_readl(0x26c); 76 + tmp = tegra30_fuse_readl(0x270) << 1; 77 + tmp |= tegra30_fuse_readl(0x26c); 76 78 if (!tmp) 77 - tegra_cpu_speedo_id = 0; 79 + sku_info->cpu_speedo_id = 0; 78 80 } 79 81 } 80 82 81 - void tegra114_init_speedo_data(void) 83 + void __init tegra114_init_speedo_data(struct tegra_sku_info *sku_info) 82 84 { 83 85 u32 cpu_speedo_val; 84 86 u32 core_speedo_val; ··· 93 89 BUILD_BUG_ON(ARRAY_SIZE(core_process_speedos) != 94 90 THRESHOLD_INDEX_COUNT); 95 91 96 - rev_sku_to_speedo_ids(tegra_revision, tegra_sku_id, &threshold); 92 + rev_sku_to_speedo_ids(sku_info, &threshold); 97 93 98 - cpu_speedo_val = tegra_fuse_readl(0x12c) + 1024; 99 - core_speedo_val = tegra_fuse_readl(0x134); 94 + cpu_speedo_val = tegra30_fuse_readl(0x12c) + 1024; 95 + core_speedo_val = tegra30_fuse_readl(0x134); 100 96 101 - for (i = 0; i < CPU_PROCESS_CORNERS_NUM; i++) 97 + for (i = 0; i < CPU_PROCESS_CORNERS; i++) 102 98 if (cpu_speedo_val < cpu_process_speedos[threshold][i]) 103 99 break; 104 - tegra_cpu_process_id = i; 100 + sku_info->cpu_process_id = i; 105 101 106 - for (i = 0; i < CORE_PROCESS_CORNERS_NUM; i++) 102 + for (i = 0; i < CORE_PROCESS_CORNERS; i++) 107 103 if (core_speedo_val < core_process_speedos[threshold][i]) 108 104 break; 109 - tegra_core_process_id = i; 105 + sku_info->core_process_id = i; 110 106 }
+20 -21
arch/arm/mach-tegra/tegra20_speedo.c drivers/soc/tegra/fuse/speedo-tegra20.c
··· 1 1 /* 2 - * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved. 2 + * Copyright (c) 2012-2014, NVIDIA CORPORATION. All rights reserved. 3 3 * 4 4 * This program is free software; you can redistribute it and/or modify it 5 5 * under the terms and conditions of the GNU General Public License, ··· 15 15 */ 16 16 17 17 #include <linux/bug.h> 18 + #include <linux/device.h> 18 19 #include <linux/kernel.h> 19 20 20 21 #include <soc/tegra/fuse.h> ··· 50 49 SPEEDO_ID_COUNT, 51 50 }; 52 51 53 - static const u32 cpu_process_speedos[][PROCESS_CORNERS_NUM] = { 52 + static const u32 __initconst cpu_process_speedos[][PROCESS_CORNERS_NUM] = { 54 53 {315, 366, 420, UINT_MAX}, 55 54 {303, 368, 419, UINT_MAX}, 56 55 {316, 331, 383, UINT_MAX}, 57 56 }; 58 57 59 - static const u32 core_process_speedos[][PROCESS_CORNERS_NUM] = { 58 + static const u32 __initconst core_process_speedos[][PROCESS_CORNERS_NUM] = { 60 59 {165, 195, 224, UINT_MAX}, 61 60 {165, 195, 224, UINT_MAX}, 62 61 {165, 195, 224, UINT_MAX}, 63 62 }; 64 63 65 - void tegra20_init_speedo_data(void) 64 + void __init tegra20_init_speedo_data(struct tegra_sku_info *sku_info) 66 65 { 67 66 u32 reg; 68 67 u32 val; ··· 71 70 BUILD_BUG_ON(ARRAY_SIZE(cpu_process_speedos) != SPEEDO_ID_COUNT); 72 71 BUILD_BUG_ON(ARRAY_SIZE(core_process_speedos) != SPEEDO_ID_COUNT); 73 72 74 - if (SPEEDO_ID_SELECT_0(tegra_revision)) 75 - tegra_soc_speedo_id = SPEEDO_ID_0; 76 - else if (SPEEDO_ID_SELECT_1(tegra_sku_id)) 77 - tegra_soc_speedo_id = SPEEDO_ID_1; 73 + if (SPEEDO_ID_SELECT_0(sku_info->revision)) 74 + sku_info->soc_speedo_id = SPEEDO_ID_0; 75 + else if (SPEEDO_ID_SELECT_1(sku_info->sku_id)) 76 + sku_info->soc_speedo_id = SPEEDO_ID_1; 78 77 else 79 - tegra_soc_speedo_id = SPEEDO_ID_2; 78 + sku_info->soc_speedo_id = SPEEDO_ID_2; 80 79 81 80 val = 0; 82 81 for (i = CPU_SPEEDO_MSBIT; i >= CPU_SPEEDO_LSBIT; i--) { 83 - reg = tegra_spare_fuse(i) | 84 - tegra_spare_fuse(i + CPU_SPEEDO_REDUND_OFFS); 82 + reg = tegra20_spare_fuse_early(i) | 83 + tegra20_spare_fuse_early(i + CPU_SPEEDO_REDUND_OFFS); 85 84 val = (val << 1) | (reg & 0x1); 86 85 } 87 86 val = val * SPEEDO_MULT; 88 - pr_debug("%s CPU speedo value %u\n", __func__, val); 87 + pr_debug("Tegra CPU speedo value %u\n", val); 89 88 90 89 for (i = 0; i < (PROCESS_CORNERS_NUM - 1); i++) { 91 - if (val <= cpu_process_speedos[tegra_soc_speedo_id][i]) 90 + if (val <= cpu_process_speedos[sku_info->soc_speedo_id][i]) 92 91 break; 93 92 } 94 - tegra_cpu_process_id = i; 93 + sku_info->cpu_process_id = i; 95 94 96 95 val = 0; 97 96 for (i = CORE_SPEEDO_MSBIT; i >= CORE_SPEEDO_LSBIT; i--) { 98 - reg = tegra_spare_fuse(i) | 99 - tegra_spare_fuse(i + CORE_SPEEDO_REDUND_OFFS); 97 + reg = tegra20_spare_fuse_early(i) | 98 + tegra20_spare_fuse_early(i + CORE_SPEEDO_REDUND_OFFS); 100 99 val = (val << 1) | (reg & 0x1); 101 100 } 102 101 val = val * SPEEDO_MULT; 103 - pr_debug("%s Core speedo value %u\n", __func__, val); 102 + pr_debug("Core speedo value %u\n", val); 104 103 105 104 for (i = 0; i < (PROCESS_CORNERS_NUM - 1); i++) { 106 - if (val <= core_process_speedos[tegra_soc_speedo_id][i]) 105 + if (val <= core_process_speedos[sku_info->soc_speedo_id][i]) 107 106 break; 108 107 } 109 - tegra_core_process_id = i; 110 - 111 - pr_info("Tegra20 Soc Speedo ID %d", tegra_soc_speedo_id); 108 + sku_info->core_process_id = i; 112 109 }
+83 -89
arch/arm/mach-tegra/tegra30_speedo.c drivers/soc/tegra/fuse/speedo-tegra30.c
··· 1 1 /* 2 - * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved. 2 + * Copyright (c) 2012-2014, NVIDIA CORPORATION. All rights reserved. 3 3 * 4 4 * This program is free software; you can redistribute it and/or modify it 5 5 * under the terms and conditions of the GNU General Public License, ··· 15 15 */ 16 16 17 17 #include <linux/bug.h> 18 + #include <linux/device.h> 18 19 #include <linux/kernel.h> 19 20 20 21 #include <soc/tegra/fuse.h> 21 22 22 23 #include "fuse.h" 23 24 24 - #define CORE_PROCESS_CORNERS_NUM 1 25 - #define CPU_PROCESS_CORNERS_NUM 6 25 + #define CORE_PROCESS_CORNERS 1 26 + #define CPU_PROCESS_CORNERS 6 26 27 27 - #define FUSE_SPEEDO_CALIB_0 0x114 28 - #define FUSE_PACKAGE_INFO 0X1FC 29 - #define FUSE_TEST_PROG_VER 0X128 28 + #define FUSE_SPEEDO_CALIB_0 0x14 29 + #define FUSE_PACKAGE_INFO 0XFC 30 + #define FUSE_TEST_PROG_VER 0X28 30 31 31 32 #define G_SPEEDO_BIT_MINUS1 58 32 33 #define G_SPEEDO_BIT_MINUS1_R 59 ··· 54 53 THRESHOLD_INDEX_COUNT, 55 54 }; 56 55 57 - static const u32 core_process_speedos[][CORE_PROCESS_CORNERS_NUM] = { 56 + static const u32 __initconst core_process_speedos[][CORE_PROCESS_CORNERS] = { 58 57 {180}, 59 58 {170}, 60 59 {195}, ··· 69 68 {180}, 70 69 }; 71 70 72 - static const u32 cpu_process_speedos[][CPU_PROCESS_CORNERS_NUM] = { 71 + static const u32 __initconst cpu_process_speedos[][CPU_PROCESS_CORNERS] = { 73 72 {306, 338, 360, 376, UINT_MAX}, 74 73 {295, 336, 358, 375, UINT_MAX}, 75 74 {325, 325, 358, 375, UINT_MAX}, ··· 84 83 {295, 336, 358, 375, 391, UINT_MAX}, 85 84 }; 86 85 87 - static int threshold_index; 88 - static int package_id; 86 + static int threshold_index __initdata; 89 87 90 - static void fuse_speedo_calib(u32 *speedo_g, u32 *speedo_lp) 88 + static void __init fuse_speedo_calib(u32 *speedo_g, u32 *speedo_lp) 91 89 { 92 90 u32 reg; 93 91 int ate_ver; 94 92 int bit_minus1; 95 93 int bit_minus2; 96 94 97 - reg = tegra_fuse_readl(FUSE_SPEEDO_CALIB_0); 95 + reg = tegra30_fuse_readl(FUSE_SPEEDO_CALIB_0); 98 96 99 97 *speedo_lp = (reg & 0xFFFF) * 4; 100 98 *speedo_g = ((reg >> 16) & 0xFFFF) * 4; 101 99 102 - ate_ver = tegra_fuse_readl(FUSE_TEST_PROG_VER); 103 - pr_info("%s: ATE prog ver %d.%d\n", __func__, ate_ver/10, ate_ver%10); 100 + ate_ver = tegra30_fuse_readl(FUSE_TEST_PROG_VER); 101 + pr_debug("Tegra ATE prog ver %d.%d\n", ate_ver/10, ate_ver%10); 104 102 105 103 if (ate_ver >= 26) { 106 - bit_minus1 = tegra_spare_fuse(LP_SPEEDO_BIT_MINUS1); 107 - bit_minus1 |= tegra_spare_fuse(LP_SPEEDO_BIT_MINUS1_R); 108 - bit_minus2 = tegra_spare_fuse(LP_SPEEDO_BIT_MINUS2); 109 - bit_minus2 |= tegra_spare_fuse(LP_SPEEDO_BIT_MINUS2_R); 104 + bit_minus1 = tegra30_spare_fuse(LP_SPEEDO_BIT_MINUS1); 105 + bit_minus1 |= tegra30_spare_fuse(LP_SPEEDO_BIT_MINUS1_R); 106 + bit_minus2 = tegra30_spare_fuse(LP_SPEEDO_BIT_MINUS2); 107 + bit_minus2 |= tegra30_spare_fuse(LP_SPEEDO_BIT_MINUS2_R); 110 108 *speedo_lp |= (bit_minus1 << 1) | bit_minus2; 111 109 112 - bit_minus1 = tegra_spare_fuse(G_SPEEDO_BIT_MINUS1); 113 - bit_minus1 |= tegra_spare_fuse(G_SPEEDO_BIT_MINUS1_R); 114 - bit_minus2 = tegra_spare_fuse(G_SPEEDO_BIT_MINUS2); 115 - bit_minus2 |= tegra_spare_fuse(G_SPEEDO_BIT_MINUS2_R); 110 + bit_minus1 = tegra30_spare_fuse(G_SPEEDO_BIT_MINUS1); 111 + bit_minus1 |= tegra30_spare_fuse(G_SPEEDO_BIT_MINUS1_R); 112 + bit_minus2 = tegra30_spare_fuse(G_SPEEDO_BIT_MINUS2); 113 + bit_minus2 |= tegra30_spare_fuse(G_SPEEDO_BIT_MINUS2_R); 116 114 *speedo_g |= (bit_minus1 << 1) | bit_minus2; 117 115 } else { 118 116 *speedo_lp |= 0x3; ··· 119 119 } 120 120 } 121 121 122 - static void rev_sku_to_speedo_ids(int rev, int sku) 122 + static void __init rev_sku_to_speedo_ids(struct tegra_sku_info *sku_info) 123 123 { 124 - switch (rev) { 124 + int package_id = tegra30_fuse_readl(FUSE_PACKAGE_INFO) & 0x0F; 125 + 126 + switch (sku_info->revision) { 125 127 case TEGRA_REVISION_A01: 126 - tegra_cpu_speedo_id = 0; 127 - tegra_soc_speedo_id = 0; 128 + sku_info->cpu_speedo_id = 0; 129 + sku_info->soc_speedo_id = 0; 128 130 threshold_index = THRESHOLD_INDEX_0; 129 131 break; 130 132 case TEGRA_REVISION_A02: 131 133 case TEGRA_REVISION_A03: 132 - switch (sku) { 134 + switch (sku_info->sku_id) { 133 135 case 0x87: 134 136 case 0x82: 135 - tegra_cpu_speedo_id = 1; 136 - tegra_soc_speedo_id = 1; 137 + sku_info->cpu_speedo_id = 1; 138 + sku_info->soc_speedo_id = 1; 137 139 threshold_index = THRESHOLD_INDEX_1; 138 140 break; 139 141 case 0x81: 140 142 switch (package_id) { 141 143 case 1: 142 - tegra_cpu_speedo_id = 2; 143 - tegra_soc_speedo_id = 2; 144 + sku_info->cpu_speedo_id = 2; 145 + sku_info->soc_speedo_id = 2; 144 146 threshold_index = THRESHOLD_INDEX_2; 145 147 break; 146 148 case 2: 147 - tegra_cpu_speedo_id = 4; 148 - tegra_soc_speedo_id = 1; 149 + sku_info->cpu_speedo_id = 4; 150 + sku_info->soc_speedo_id = 1; 149 151 threshold_index = THRESHOLD_INDEX_7; 150 152 break; 151 153 default: 152 - pr_err("Tegra30: Unknown pkg %d\n", package_id); 153 - BUG(); 154 + pr_err("Tegra Unknown pkg %d\n", package_id); 154 155 break; 155 156 } 156 157 break; 157 158 case 0x80: 158 159 switch (package_id) { 159 160 case 1: 160 - tegra_cpu_speedo_id = 5; 161 - tegra_soc_speedo_id = 2; 161 + sku_info->cpu_speedo_id = 5; 162 + sku_info->soc_speedo_id = 2; 162 163 threshold_index = THRESHOLD_INDEX_8; 163 164 break; 164 165 case 2: 165 - tegra_cpu_speedo_id = 6; 166 - tegra_soc_speedo_id = 2; 166 + sku_info->cpu_speedo_id = 6; 167 + sku_info->soc_speedo_id = 2; 167 168 threshold_index = THRESHOLD_INDEX_9; 168 169 break; 169 170 default: 170 - pr_err("Tegra30: Unknown pkg %d\n", package_id); 171 - BUG(); 171 + pr_err("Tegra Unknown pkg %d\n", package_id); 172 172 break; 173 173 } 174 174 break; 175 175 case 0x83: 176 176 switch (package_id) { 177 177 case 1: 178 - tegra_cpu_speedo_id = 7; 179 - tegra_soc_speedo_id = 1; 178 + sku_info->cpu_speedo_id = 7; 179 + sku_info->soc_speedo_id = 1; 180 180 threshold_index = THRESHOLD_INDEX_10; 181 181 break; 182 182 case 2: 183 - tegra_cpu_speedo_id = 3; 184 - tegra_soc_speedo_id = 2; 183 + sku_info->cpu_speedo_id = 3; 184 + sku_info->soc_speedo_id = 2; 185 185 threshold_index = THRESHOLD_INDEX_3; 186 186 break; 187 187 default: 188 - pr_err("Tegra30: Unknown pkg %d\n", package_id); 189 - BUG(); 188 + pr_err("Tegra Unknown pkg %d\n", package_id); 190 189 break; 191 190 } 192 191 break; 193 192 case 0x8F: 194 - tegra_cpu_speedo_id = 8; 195 - tegra_soc_speedo_id = 1; 193 + sku_info->cpu_speedo_id = 8; 194 + sku_info->soc_speedo_id = 1; 196 195 threshold_index = THRESHOLD_INDEX_11; 197 196 break; 198 197 case 0x08: 199 - tegra_cpu_speedo_id = 1; 200 - tegra_soc_speedo_id = 1; 198 + sku_info->cpu_speedo_id = 1; 199 + sku_info->soc_speedo_id = 1; 201 200 threshold_index = THRESHOLD_INDEX_4; 202 201 break; 203 202 case 0x02: 204 - tegra_cpu_speedo_id = 2; 205 - tegra_soc_speedo_id = 2; 203 + sku_info->cpu_speedo_id = 2; 204 + sku_info->soc_speedo_id = 2; 206 205 threshold_index = THRESHOLD_INDEX_5; 207 206 break; 208 207 case 0x04: 209 - tegra_cpu_speedo_id = 3; 210 - tegra_soc_speedo_id = 2; 208 + sku_info->cpu_speedo_id = 3; 209 + sku_info->soc_speedo_id = 2; 211 210 threshold_index = THRESHOLD_INDEX_6; 212 211 break; 213 212 case 0: 214 213 switch (package_id) { 215 214 case 1: 216 - tegra_cpu_speedo_id = 2; 217 - tegra_soc_speedo_id = 2; 215 + sku_info->cpu_speedo_id = 2; 216 + sku_info->soc_speedo_id = 2; 218 217 threshold_index = THRESHOLD_INDEX_2; 219 218 break; 220 219 case 2: 221 - tegra_cpu_speedo_id = 3; 222 - tegra_soc_speedo_id = 2; 220 + sku_info->cpu_speedo_id = 3; 221 + sku_info->soc_speedo_id = 2; 223 222 threshold_index = THRESHOLD_INDEX_3; 224 223 break; 225 224 default: 226 - pr_err("Tegra30: Unknown pkg %d\n", package_id); 227 - BUG(); 225 + pr_err("Tegra Unknown pkg %d\n", package_id); 228 226 break; 229 227 } 230 228 break; 231 229 default: 232 - pr_warn("Tegra30: Unknown SKU %d\n", sku); 233 - tegra_cpu_speedo_id = 0; 234 - tegra_soc_speedo_id = 0; 230 + pr_warn("Tegra Unknown SKU %d\n", sku_info->sku_id); 231 + sku_info->cpu_speedo_id = 0; 232 + sku_info->soc_speedo_id = 0; 235 233 threshold_index = THRESHOLD_INDEX_0; 236 234 break; 237 235 } 238 236 break; 239 237 default: 240 - pr_warn("Tegra30: Unknown chip rev %d\n", rev); 241 - tegra_cpu_speedo_id = 0; 242 - tegra_soc_speedo_id = 0; 238 + pr_warn("Tegra Unknown chip rev %d\n", sku_info->revision); 239 + sku_info->cpu_speedo_id = 0; 240 + sku_info->soc_speedo_id = 0; 243 241 threshold_index = THRESHOLD_INDEX_0; 244 242 break; 245 243 } 246 244 } 247 245 248 - void tegra30_init_speedo_data(void) 246 + void __init tegra30_init_speedo_data(struct tegra_sku_info *sku_info) 249 247 { 250 248 u32 cpu_speedo_val; 251 249 u32 core_speedo_val; ··· 254 256 BUILD_BUG_ON(ARRAY_SIZE(core_process_speedos) != 255 257 THRESHOLD_INDEX_COUNT); 256 258 257 - package_id = tegra_fuse_readl(FUSE_PACKAGE_INFO) & 0x0F; 258 259 259 - rev_sku_to_speedo_ids(tegra_revision, tegra_sku_id); 260 + rev_sku_to_speedo_ids(sku_info); 260 261 fuse_speedo_calib(&cpu_speedo_val, &core_speedo_val); 261 - pr_debug("%s CPU speedo value %u\n", __func__, cpu_speedo_val); 262 - pr_debug("%s Core speedo value %u\n", __func__, core_speedo_val); 262 + pr_debug("Tegra CPU speedo value %u\n", cpu_speedo_val); 263 + pr_debug("Tegra Core speedo value %u\n", core_speedo_val); 263 264 264 - for (i = 0; i < CPU_PROCESS_CORNERS_NUM; i++) { 265 + for (i = 0; i < CPU_PROCESS_CORNERS; i++) { 265 266 if (cpu_speedo_val < cpu_process_speedos[threshold_index][i]) 266 267 break; 267 268 } 268 - tegra_cpu_process_id = i - 1; 269 + sku_info->cpu_process_id = i - 1; 269 270 270 - if (tegra_cpu_process_id == -1) { 271 - pr_warn("Tegra30: CPU speedo value %3d out of range", 272 - cpu_speedo_val); 273 - tegra_cpu_process_id = 0; 274 - tegra_cpu_speedo_id = 1; 271 + if (sku_info->cpu_process_id == -1) { 272 + pr_warn("Tegra CPU speedo value %3d out of range", 273 + cpu_speedo_val); 274 + sku_info->cpu_process_id = 0; 275 + sku_info->cpu_speedo_id = 1; 275 276 } 276 277 277 - for (i = 0; i < CORE_PROCESS_CORNERS_NUM; i++) { 278 + for (i = 0; i < CORE_PROCESS_CORNERS; i++) { 278 279 if (core_speedo_val < core_process_speedos[threshold_index][i]) 279 280 break; 280 281 } 281 - tegra_core_process_id = i - 1; 282 + sku_info->core_process_id = i - 1; 282 283 283 - if (tegra_core_process_id == -1) { 284 - pr_warn("Tegra30: CORE speedo value %3d out of range", 285 - core_speedo_val); 286 - tegra_core_process_id = 0; 287 - tegra_soc_speedo_id = 1; 284 + if (sku_info->core_process_id == -1) { 285 + pr_warn("Tegra CORE speedo value %3d out of range", 286 + core_speedo_val); 287 + sku_info->core_process_id = 0; 288 + sku_info->soc_speedo_id = 1; 288 289 } 289 - 290 - pr_info("Tegra30: CPU Speedo ID %d, Soc Speedo ID %d", 291 - tegra_cpu_speedo_id, tegra_soc_speedo_id); 292 290 }
+1
drivers/misc/fuse/Makefile
··· 1 + obj-$(CONFIG_ARCH_TEGRA) += tegra/
+1
drivers/soc/Makefile
··· 3 3 # 4 4 5 5 obj-$(CONFIG_ARCH_QCOM) += qcom/ 6 + obj-$(CONFIG_ARCH_TEGRA) += tegra/
+1
drivers/soc/tegra/Makefile
··· 1 + obj-$(CONFIG_ARCH_TEGRA) += fuse/
+8
drivers/soc/tegra/fuse/Makefile
··· 1 + obj-y += fuse-tegra.o 2 + obj-y += fuse-tegra30.o 3 + obj-y += tegra-apbmisc.o 4 + obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += fuse-tegra20.o 5 + obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += speedo-tegra20.o 6 + obj-$(CONFIG_ARCH_TEGRA_3x_SOC) += speedo-tegra30.o 7 + obj-$(CONFIG_ARCH_TEGRA_114_SOC) += speedo-tegra114.o 8 + obj-$(CONFIG_ARCH_TEGRA_124_SOC) += speedo-tegra124.o
+156
drivers/soc/tegra/fuse/fuse-tegra.c
··· 1 + /* 2 + * Copyright (c) 2013-2014, NVIDIA CORPORATION. All rights reserved. 3 + * 4 + * This program is free software; you can redistribute it and/or modify it 5 + * under the terms and conditions of the GNU General Public License, 6 + * version 2, as published by the Free Software Foundation. 7 + * 8 + * This program is distributed in the hope it will be useful, but WITHOUT 9 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 10 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 11 + * more details. 12 + * 13 + * You should have received a copy of the GNU General Public License 14 + * along with this program. If not, see <http://www.gnu.org/licenses/>. 15 + * 16 + */ 17 + 18 + #include <linux/device.h> 19 + #include <linux/kobject.h> 20 + #include <linux/kernel.h> 21 + #include <linux/platform_device.h> 22 + #include <linux/of.h> 23 + #include <linux/of_address.h> 24 + #include <linux/io.h> 25 + 26 + #include <soc/tegra/fuse.h> 27 + 28 + #include "fuse.h" 29 + 30 + static u32 (*fuse_readl)(const unsigned int offset); 31 + static int fuse_size; 32 + struct tegra_sku_info tegra_sku_info; 33 + 34 + static const char *tegra_revision_name[TEGRA_REVISION_MAX] = { 35 + [TEGRA_REVISION_UNKNOWN] = "unknown", 36 + [TEGRA_REVISION_A01] = "A01", 37 + [TEGRA_REVISION_A02] = "A02", 38 + [TEGRA_REVISION_A03] = "A03", 39 + [TEGRA_REVISION_A03p] = "A03 prime", 40 + [TEGRA_REVISION_A04] = "A04", 41 + }; 42 + 43 + static u8 fuse_readb(const unsigned int offset) 44 + { 45 + u32 val; 46 + 47 + val = fuse_readl(round_down(offset, 4)); 48 + val >>= (offset % 4) * 8; 49 + val &= 0xff; 50 + 51 + return val; 52 + } 53 + 54 + static ssize_t fuse_read(struct file *fd, struct kobject *kobj, 55 + struct bin_attribute *attr, char *buf, 56 + loff_t pos, size_t size) 57 + { 58 + int i; 59 + 60 + if (pos < 0 || pos >= fuse_size) 61 + return 0; 62 + 63 + if (size > fuse_size - pos) 64 + size = fuse_size - pos; 65 + 66 + for (i = 0; i < size; i++) 67 + buf[i] = fuse_readb(pos + i); 68 + 69 + return i; 70 + } 71 + 72 + static struct bin_attribute fuse_bin_attr = { 73 + .attr = { .name = "fuse", .mode = S_IRUGO, }, 74 + .read = fuse_read, 75 + }; 76 + 77 + static const struct of_device_id car_match[] __initconst = { 78 + { .compatible = "nvidia,tegra20-car", }, 79 + { .compatible = "nvidia,tegra30-car", }, 80 + { .compatible = "nvidia,tegra114-car", }, 81 + { .compatible = "nvidia,tegra124-car", }, 82 + {}, 83 + }; 84 + 85 + static void tegra_enable_fuse_clk(void __iomem *base) 86 + { 87 + u32 reg; 88 + 89 + reg = readl_relaxed(base + 0x48); 90 + reg |= 1 << 28; 91 + writel(reg, base + 0x48); 92 + 93 + /* 94 + * Enable FUSE clock. This needs to be hardcoded because the clock 95 + * subsystem is not active during early boot. 96 + */ 97 + reg = readl(base + 0x14); 98 + reg |= 1 << 7; 99 + writel(reg, base + 0x14); 100 + } 101 + 102 + int tegra_fuse_readl(unsigned long offset, u32 *value) 103 + { 104 + if (!fuse_readl) 105 + return -EPROBE_DEFER; 106 + 107 + *value = fuse_readl(offset); 108 + 109 + return 0; 110 + } 111 + EXPORT_SYMBOL(tegra_fuse_readl); 112 + 113 + int tegra_fuse_create_sysfs(struct device *dev, int size, 114 + u32 (*readl)(const unsigned int offset)) 115 + { 116 + if (fuse_size) 117 + return -ENODEV; 118 + 119 + fuse_bin_attr.size = size; 120 + fuse_bin_attr.read = fuse_read; 121 + 122 + fuse_size = size; 123 + fuse_readl = readl; 124 + 125 + return device_create_bin_file(dev, &fuse_bin_attr); 126 + } 127 + 128 + void __init tegra_init_fuse(void) 129 + { 130 + struct device_node *np; 131 + void __iomem *car_base; 132 + 133 + tegra_init_apbmisc(); 134 + 135 + np = of_find_matching_node(NULL, car_match); 136 + car_base = of_iomap(np, 0); 137 + if (car_base) { 138 + tegra_enable_fuse_clk(car_base); 139 + iounmap(car_base); 140 + } else { 141 + pr_err("Could not enable fuse clk. ioremap tegra car failed.\n"); 142 + return; 143 + } 144 + 145 + if (tegra_get_chip_id() == TEGRA20) 146 + tegra20_init_fuse_early(); 147 + else 148 + tegra30_init_fuse_early(); 149 + 150 + pr_info("Tegra Revision: %s SKU: %d CPU Process: %d Core Process: %d\n", 151 + tegra_revision_name[tegra_sku_info.revision], 152 + tegra_sku_info.sku_id, tegra_sku_info.cpu_process_id, 153 + tegra_sku_info.core_process_id); 154 + pr_debug("Tegra CPU Speedo ID %d, Soc Speedo ID %d\n", 155 + tegra_sku_info.cpu_speedo_id, tegra_sku_info.soc_speedo_id); 156 + }
+142
drivers/soc/tegra/fuse/fuse-tegra20.c
··· 1 + /* 2 + * Copyright (c) 2013-2014, NVIDIA CORPORATION. All rights reserved. 3 + * 4 + * This program is free software; you can redistribute it and/or modify it 5 + * under the terms and conditions of the GNU General Public License, 6 + * version 2, as published by the Free Software Foundation. 7 + * 8 + * This program is distributed in the hope it will be useful, but WITHOUT 9 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 10 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 11 + * more details. 12 + * 13 + * You should have received a copy of the GNU General Public License 14 + * along with this program. If not, see <http://www.gnu.org/licenses/>. 15 + * 16 + * Based on drivers/misc/eeprom/sunxi_sid.c 17 + */ 18 + 19 + #include <linux/device.h> 20 + #include <linux/clk.h> 21 + #include <linux/err.h> 22 + #include <linux/io.h> 23 + #include <linux/kernel.h> 24 + #include <linux/kobject.h> 25 + #include <linux/of_device.h> 26 + #include <linux/platform_device.h> 27 + #include <linux/random.h> 28 + 29 + #include <soc/tegra/fuse.h> 30 + 31 + #include "fuse.h" 32 + 33 + #define FUSE_BEGIN 0x100 34 + #define FUSE_SIZE 0x1f8 35 + #define FUSE_UID_LOW 0x08 36 + #define FUSE_UID_HIGH 0x0c 37 + 38 + static phys_addr_t fuse_phys; 39 + static struct clk *fuse_clk; 40 + static void __iomem __initdata *fuse_base; 41 + 42 + static u32 tegra20_fuse_readl(const unsigned int offset) 43 + { 44 + int ret; 45 + u32 val; 46 + 47 + clk_prepare_enable(fuse_clk); 48 + 49 + ret = tegra_apb_readl_using_dma(fuse_phys + FUSE_BEGIN + offset, &val); 50 + 51 + clk_disable_unprepare(fuse_clk); 52 + 53 + return (ret < 0) ? 0 : val; 54 + } 55 + 56 + static const struct of_device_id tegra20_fuse_of_match[] = { 57 + { .compatible = "nvidia,tegra20-efuse" }, 58 + {}, 59 + }; 60 + 61 + static int tegra20_fuse_probe(struct platform_device *pdev) 62 + { 63 + struct resource *res; 64 + 65 + fuse_clk = devm_clk_get(&pdev->dev, NULL); 66 + if (IS_ERR(fuse_clk)) { 67 + dev_err(&pdev->dev, "missing clock"); 68 + return PTR_ERR(fuse_clk); 69 + } 70 + 71 + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 72 + if (!res) 73 + return -EINVAL; 74 + fuse_phys = res->start; 75 + 76 + if (tegra_fuse_create_sysfs(&pdev->dev, FUSE_SIZE, tegra20_fuse_readl)) 77 + return -ENODEV; 78 + 79 + dev_dbg(&pdev->dev, "loaded\n"); 80 + 81 + return 0; 82 + } 83 + 84 + static struct platform_driver tegra20_fuse_driver = { 85 + .probe = tegra20_fuse_probe, 86 + .driver = { 87 + .name = "tegra20_fuse", 88 + .owner = THIS_MODULE, 89 + .of_match_table = tegra20_fuse_of_match, 90 + } 91 + }; 92 + 93 + static int __init tegra20_fuse_init(void) 94 + { 95 + return platform_driver_register(&tegra20_fuse_driver); 96 + } 97 + postcore_initcall(tegra20_fuse_init); 98 + 99 + /* Early boot code. This code is called before the devices are created */ 100 + 101 + u32 __init tegra20_fuse_early(const unsigned int offset) 102 + { 103 + return readl_relaxed(fuse_base + FUSE_BEGIN + offset); 104 + } 105 + 106 + bool __init tegra20_spare_fuse_early(int spare_bit) 107 + { 108 + u32 offset = spare_bit * 4; 109 + bool value; 110 + 111 + value = tegra20_fuse_early(offset + 0x100); 112 + 113 + return value; 114 + } 115 + 116 + static void __init tegra20_fuse_add_randomness(void) 117 + { 118 + u32 randomness[7]; 119 + 120 + randomness[0] = tegra_sku_info.sku_id; 121 + randomness[1] = tegra_read_straps(); 122 + randomness[2] = tegra_read_chipid(); 123 + randomness[3] = tegra_sku_info.cpu_process_id << 16; 124 + randomness[3] |= tegra_sku_info.core_process_id; 125 + randomness[4] = tegra_sku_info.cpu_speedo_id << 16; 126 + randomness[4] |= tegra_sku_info.soc_speedo_id; 127 + randomness[5] = tegra20_fuse_early(FUSE_UID_LOW); 128 + randomness[6] = tegra20_fuse_early(FUSE_UID_HIGH); 129 + 130 + add_device_randomness(randomness, sizeof(randomness)); 131 + } 132 + 133 + void __init tegra20_init_fuse_early(void) 134 + { 135 + fuse_base = ioremap(TEGRA_FUSE_BASE, TEGRA_FUSE_SIZE); 136 + 137 + tegra_init_revision(); 138 + tegra20_init_speedo_data(&tegra_sku_info); 139 + tegra20_fuse_add_randomness(); 140 + 141 + iounmap(fuse_base); 142 + }
+224
drivers/soc/tegra/fuse/fuse-tegra30.c
··· 1 + /* 2 + * Copyright (c) 2013-2014, NVIDIA CORPORATION. All rights reserved. 3 + * 4 + * This program is free software; you can redistribute it and/or modify it 5 + * under the terms and conditions of the GNU General Public License, 6 + * version 2, as published by the Free Software Foundation. 7 + * 8 + * This program is distributed in the hope it will be useful, but WITHOUT 9 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 10 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 11 + * more details. 12 + * 13 + * You should have received a copy of the GNU General Public License 14 + * along with this program. If not, see <http://www.gnu.org/licenses/>. 15 + * 16 + */ 17 + 18 + #include <linux/device.h> 19 + #include <linux/clk.h> 20 + #include <linux/err.h> 21 + #include <linux/io.h> 22 + #include <linux/kernel.h> 23 + #include <linux/of_device.h> 24 + #include <linux/of_address.h> 25 + #include <linux/platform_device.h> 26 + #include <linux/random.h> 27 + 28 + #include <soc/tegra/fuse.h> 29 + 30 + #include "fuse.h" 31 + 32 + #define FUSE_BEGIN 0x100 33 + 34 + /* Tegra30 and later */ 35 + #define FUSE_VENDOR_CODE 0x100 36 + #define FUSE_FAB_CODE 0x104 37 + #define FUSE_LOT_CODE_0 0x108 38 + #define FUSE_LOT_CODE_1 0x10c 39 + #define FUSE_WAFER_ID 0x110 40 + #define FUSE_X_COORDINATE 0x114 41 + #define FUSE_Y_COORDINATE 0x118 42 + 43 + #define FUSE_HAS_REVISION_INFO BIT(0) 44 + 45 + enum speedo_idx { 46 + SPEEDO_TEGRA30 = 0, 47 + SPEEDO_TEGRA114, 48 + SPEEDO_TEGRA124, 49 + }; 50 + 51 + struct tegra_fuse_info { 52 + int size; 53 + int spare_bit; 54 + enum speedo_idx speedo_idx; 55 + }; 56 + 57 + static void __iomem *fuse_base; 58 + static struct clk *fuse_clk; 59 + static struct tegra_fuse_info *fuse_info; 60 + 61 + u32 tegra30_fuse_readl(const unsigned int offset) 62 + { 63 + u32 val; 64 + 65 + /* 66 + * early in the boot, the fuse clock will be enabled by 67 + * tegra_init_fuse() 68 + */ 69 + 70 + if (fuse_clk) 71 + clk_prepare_enable(fuse_clk); 72 + 73 + val = readl_relaxed(fuse_base + FUSE_BEGIN + offset); 74 + 75 + if (fuse_clk) 76 + clk_disable_unprepare(fuse_clk); 77 + 78 + return val; 79 + } 80 + 81 + static struct tegra_fuse_info tegra30_info = { 82 + .size = 0x2a4, 83 + .spare_bit = 0x144, 84 + .speedo_idx = SPEEDO_TEGRA30, 85 + }; 86 + 87 + static struct tegra_fuse_info tegra114_info = { 88 + .size = 0x2a0, 89 + .speedo_idx = SPEEDO_TEGRA114, 90 + }; 91 + 92 + static struct tegra_fuse_info tegra124_info = { 93 + .size = 0x300, 94 + .speedo_idx = SPEEDO_TEGRA124, 95 + }; 96 + 97 + static const struct of_device_id tegra30_fuse_of_match[] = { 98 + { .compatible = "nvidia,tegra30-efuse", .data = &tegra30_info }, 99 + { .compatible = "nvidia,tegra114-efuse", .data = &tegra114_info }, 100 + { .compatible = "nvidia,tegra124-efuse", .data = &tegra124_info }, 101 + {}, 102 + }; 103 + 104 + static int tegra30_fuse_probe(struct platform_device *pdev) 105 + { 106 + const struct of_device_id *of_dev_id; 107 + 108 + of_dev_id = of_match_device(tegra30_fuse_of_match, &pdev->dev); 109 + if (!of_dev_id) 110 + return -ENODEV; 111 + 112 + fuse_clk = devm_clk_get(&pdev->dev, NULL); 113 + if (IS_ERR(fuse_clk)) { 114 + dev_err(&pdev->dev, "missing clock"); 115 + return PTR_ERR(fuse_clk); 116 + } 117 + 118 + platform_set_drvdata(pdev, NULL); 119 + 120 + if (tegra_fuse_create_sysfs(&pdev->dev, fuse_info->size, 121 + tegra30_fuse_readl)) 122 + return -ENODEV; 123 + 124 + dev_dbg(&pdev->dev, "loaded\n"); 125 + 126 + return 0; 127 + } 128 + 129 + static struct platform_driver tegra30_fuse_driver = { 130 + .probe = tegra30_fuse_probe, 131 + .driver = { 132 + .name = "tegra_fuse", 133 + .owner = THIS_MODULE, 134 + .of_match_table = tegra30_fuse_of_match, 135 + } 136 + }; 137 + 138 + static int __init tegra30_fuse_init(void) 139 + { 140 + return platform_driver_register(&tegra30_fuse_driver); 141 + } 142 + postcore_initcall(tegra30_fuse_init); 143 + 144 + /* Early boot code. This code is called before the devices are created */ 145 + 146 + typedef void (*speedo_f)(struct tegra_sku_info *sku_info); 147 + 148 + static speedo_f __initdata speedo_tbl[] = { 149 + [SPEEDO_TEGRA30] = tegra30_init_speedo_data, 150 + [SPEEDO_TEGRA114] = tegra114_init_speedo_data, 151 + [SPEEDO_TEGRA124] = tegra124_init_speedo_data, 152 + }; 153 + 154 + static void __init tegra30_fuse_add_randomness(void) 155 + { 156 + u32 randomness[12]; 157 + 158 + randomness[0] = tegra_sku_info.sku_id; 159 + randomness[1] = tegra_read_straps(); 160 + randomness[2] = tegra_read_chipid(); 161 + randomness[3] = tegra_sku_info.cpu_process_id << 16; 162 + randomness[3] |= tegra_sku_info.core_process_id; 163 + randomness[4] = tegra_sku_info.cpu_speedo_id << 16; 164 + randomness[4] |= tegra_sku_info.soc_speedo_id; 165 + randomness[5] = tegra30_fuse_readl(FUSE_VENDOR_CODE); 166 + randomness[6] = tegra30_fuse_readl(FUSE_FAB_CODE); 167 + randomness[7] = tegra30_fuse_readl(FUSE_LOT_CODE_0); 168 + randomness[8] = tegra30_fuse_readl(FUSE_LOT_CODE_1); 169 + randomness[9] = tegra30_fuse_readl(FUSE_WAFER_ID); 170 + randomness[10] = tegra30_fuse_readl(FUSE_X_COORDINATE); 171 + randomness[11] = tegra30_fuse_readl(FUSE_Y_COORDINATE); 172 + 173 + add_device_randomness(randomness, sizeof(randomness)); 174 + } 175 + 176 + static void __init legacy_fuse_init(void) 177 + { 178 + switch (tegra_get_chip_id()) { 179 + case TEGRA30: 180 + fuse_info = &tegra30_info; 181 + break; 182 + case TEGRA114: 183 + fuse_info = &tegra114_info; 184 + break; 185 + case TEGRA124: 186 + fuse_info = &tegra124_info; 187 + break; 188 + default: 189 + return; 190 + } 191 + 192 + fuse_base = ioremap(TEGRA_FUSE_BASE, TEGRA_FUSE_SIZE); 193 + } 194 + 195 + bool __init tegra30_spare_fuse(int spare_bit) 196 + { 197 + u32 offset = fuse_info->spare_bit + spare_bit * 4; 198 + 199 + return tegra30_fuse_readl(offset) & 1; 200 + } 201 + 202 + void __init tegra30_init_fuse_early(void) 203 + { 204 + struct device_node *np; 205 + const struct of_device_id *of_match; 206 + 207 + np = of_find_matching_node_and_match(NULL, tegra30_fuse_of_match, 208 + &of_match); 209 + if (np) { 210 + fuse_base = of_iomap(np, 0); 211 + fuse_info = (struct tegra_fuse_info *)of_match->data; 212 + } else 213 + legacy_fuse_init(); 214 + 215 + if (!fuse_base) { 216 + pr_warn("fuse DT node missing and unknown chip id: 0x%02x\n", 217 + tegra_get_chip_id()); 218 + return; 219 + } 220 + 221 + tegra_init_revision(); 222 + speedo_tbl[fuse_info->speedo_idx](&tegra_sku_info); 223 + tegra30_fuse_add_randomness(); 224 + }
+71
drivers/soc/tegra/fuse/fuse.h
··· 1 + /* 2 + * Copyright (C) 2010 Google, Inc. 3 + * Copyright (c) 2013, NVIDIA CORPORATION. All rights reserved. 4 + * 5 + * Author: 6 + * Colin Cross <ccross@android.com> 7 + * 8 + * This software is licensed under the terms of the GNU General Public 9 + * License version 2, as published by the Free Software Foundation, and 10 + * may be copied, distributed, and modified under those terms. 11 + * 12 + * This program is distributed in the hope that it will be useful, 13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 + * GNU General Public License for more details. 16 + * 17 + */ 18 + 19 + #ifndef __DRIVERS_MISC_TEGRA_FUSE_H 20 + #define __DRIVERS_MISC_TEGRA_FUSE_H 21 + 22 + #define TEGRA_FUSE_BASE 0x7000f800 23 + #define TEGRA_FUSE_SIZE 0x400 24 + 25 + int tegra_fuse_create_sysfs(struct device *dev, int size, 26 + u32 (*readl)(const unsigned int offset)); 27 + 28 + bool tegra30_spare_fuse(int bit); 29 + u32 tegra30_fuse_readl(const unsigned int offset); 30 + void tegra30_init_fuse_early(void); 31 + void tegra_init_revision(void); 32 + void tegra_init_apbmisc(void); 33 + 34 + #ifdef CONFIG_ARCH_TEGRA_2x_SOC 35 + void tegra20_init_speedo_data(struct tegra_sku_info *sku_info); 36 + bool tegra20_spare_fuse_early(int spare_bit); 37 + void tegra20_init_fuse_early(void); 38 + u32 tegra20_fuse_early(const unsigned int offset); 39 + #else 40 + static inline void tegra20_init_speedo_data(struct tegra_sku_info *sku_info) {} 41 + static inline bool tegra20_spare_fuse_early(int spare_bit, void *fuse_base) 42 + { 43 + return false; 44 + } 45 + static inline void tegra20_init_fuse_early(void); 46 + static inline tegra20_fuse_early(const unsigned int offset); 47 + { 48 + return 0; 49 + } 50 + #endif 51 + 52 + 53 + #ifdef CONFIG_ARCH_TEGRA_3x_SOC 54 + void tegra30_init_speedo_data(struct tegra_sku_info *sku_info); 55 + #else 56 + static inline void tegra30_init_speedo_data(struct tegra_sku_info *sku_info) {} 57 + #endif 58 + 59 + #ifdef CONFIG_ARCH_TEGRA_114_SOC 60 + void tegra114_init_speedo_data(struct tegra_sku_info *sku_info); 61 + #else 62 + static inline void tegra114_init_speedo_data(struct tegra_sku_info *sku_info) {} 63 + #endif 64 + 65 + #ifdef CONFIG_ARCH_TEGRA_124_SOC 66 + void tegra124_init_speedo_data(struct tegra_sku_info *sku_info); 67 + #else 68 + static inline void tegra124_init_speedo_data(struct tegra_sku_info *sku_info) {} 69 + #endif 70 + 71 + #endif
+168
drivers/soc/tegra/fuse/speedo-tegra124.c
··· 1 + /* 2 + * Copyright (c) 2013-2014, NVIDIA CORPORATION. All rights reserved. 3 + * 4 + * This program is free software; you can redistribute it and/or modify it 5 + * under the terms and conditions of the GNU General Public License, 6 + * version 2, as published by the Free Software Foundation. 7 + * 8 + * This program is distributed in the hope it will be useful, but WITHOUT 9 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 10 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 11 + * more details. 12 + * 13 + * You should have received a copy of the GNU General Public License 14 + * along with this program. If not, see <http://www.gnu.org/licenses/>. 15 + */ 16 + 17 + #include <linux/device.h> 18 + #include <linux/kernel.h> 19 + #include <linux/bug.h> 20 + 21 + #include <soc/tegra/fuse.h> 22 + 23 + #include "fuse.h" 24 + 25 + #define CPU_PROCESS_CORNERS 2 26 + #define GPU_PROCESS_CORNERS 2 27 + #define CORE_PROCESS_CORNERS 2 28 + 29 + #define FUSE_CPU_SPEEDO_0 0x14 30 + #define FUSE_CPU_SPEEDO_1 0x2c 31 + #define FUSE_CPU_SPEEDO_2 0x30 32 + #define FUSE_SOC_SPEEDO_0 0x34 33 + #define FUSE_SOC_SPEEDO_1 0x38 34 + #define FUSE_SOC_SPEEDO_2 0x3c 35 + #define FUSE_CPU_IDDQ 0x18 36 + #define FUSE_SOC_IDDQ 0x40 37 + #define FUSE_GPU_IDDQ 0x128 38 + #define FUSE_FT_REV 0x28 39 + 40 + enum { 41 + THRESHOLD_INDEX_0, 42 + THRESHOLD_INDEX_1, 43 + THRESHOLD_INDEX_COUNT, 44 + }; 45 + 46 + static const u32 __initconst cpu_process_speedos[][CPU_PROCESS_CORNERS] = { 47 + {2190, UINT_MAX}, 48 + {0, UINT_MAX}, 49 + }; 50 + 51 + static const u32 __initconst gpu_process_speedos[][GPU_PROCESS_CORNERS] = { 52 + {1965, UINT_MAX}, 53 + {0, UINT_MAX}, 54 + }; 55 + 56 + static const u32 __initconst core_process_speedos[][CORE_PROCESS_CORNERS] = { 57 + {2101, UINT_MAX}, 58 + {0, UINT_MAX}, 59 + }; 60 + 61 + static void __init rev_sku_to_speedo_ids(struct tegra_sku_info *sku_info, 62 + int *threshold) 63 + { 64 + int sku = sku_info->sku_id; 65 + 66 + /* Assign to default */ 67 + sku_info->cpu_speedo_id = 0; 68 + sku_info->soc_speedo_id = 0; 69 + sku_info->gpu_speedo_id = 0; 70 + *threshold = THRESHOLD_INDEX_0; 71 + 72 + switch (sku) { 73 + case 0x00: /* Eng sku */ 74 + case 0x0F: 75 + case 0x23: 76 + /* Using the default */ 77 + break; 78 + case 0x83: 79 + sku_info->cpu_speedo_id = 2; 80 + break; 81 + 82 + case 0x1F: 83 + case 0x87: 84 + case 0x27: 85 + sku_info->cpu_speedo_id = 2; 86 + sku_info->soc_speedo_id = 0; 87 + sku_info->gpu_speedo_id = 1; 88 + *threshold = THRESHOLD_INDEX_0; 89 + break; 90 + case 0x81: 91 + case 0x21: 92 + case 0x07: 93 + sku_info->cpu_speedo_id = 1; 94 + sku_info->soc_speedo_id = 1; 95 + sku_info->gpu_speedo_id = 1; 96 + *threshold = THRESHOLD_INDEX_1; 97 + break; 98 + case 0x49: 99 + case 0x4A: 100 + case 0x48: 101 + sku_info->cpu_speedo_id = 4; 102 + sku_info->soc_speedo_id = 2; 103 + sku_info->gpu_speedo_id = 3; 104 + *threshold = THRESHOLD_INDEX_1; 105 + break; 106 + default: 107 + pr_err("Tegra Unknown SKU %d\n", sku); 108 + /* Using the default for the error case */ 109 + break; 110 + } 111 + } 112 + 113 + void __init tegra124_init_speedo_data(struct tegra_sku_info *sku_info) 114 + { 115 + int i, threshold, cpu_speedo_0_value, soc_speedo_0_value; 116 + int cpu_iddq_value, gpu_iddq_value, soc_iddq_value; 117 + 118 + BUILD_BUG_ON(ARRAY_SIZE(cpu_process_speedos) != 119 + THRESHOLD_INDEX_COUNT); 120 + BUILD_BUG_ON(ARRAY_SIZE(gpu_process_speedos) != 121 + THRESHOLD_INDEX_COUNT); 122 + BUILD_BUG_ON(ARRAY_SIZE(core_process_speedos) != 123 + THRESHOLD_INDEX_COUNT); 124 + 125 + cpu_speedo_0_value = tegra30_fuse_readl(FUSE_CPU_SPEEDO_0); 126 + 127 + /* GPU Speedo is stored in CPU_SPEEDO_2 */ 128 + sku_info->gpu_speedo_value = tegra30_fuse_readl(FUSE_CPU_SPEEDO_2); 129 + 130 + soc_speedo_0_value = tegra30_fuse_readl(FUSE_SOC_SPEEDO_0); 131 + 132 + cpu_iddq_value = tegra30_fuse_readl(FUSE_CPU_IDDQ); 133 + soc_iddq_value = tegra30_fuse_readl(FUSE_SOC_IDDQ); 134 + gpu_iddq_value = tegra30_fuse_readl(FUSE_GPU_IDDQ); 135 + 136 + sku_info->cpu_speedo_value = cpu_speedo_0_value; 137 + 138 + if (sku_info->cpu_speedo_value == 0) { 139 + pr_warn("Tegra Warning: Speedo value not fused.\n"); 140 + WARN_ON(1); 141 + return; 142 + } 143 + 144 + rev_sku_to_speedo_ids(sku_info, &threshold); 145 + 146 + sku_info->cpu_iddq_value = tegra30_fuse_readl(FUSE_CPU_IDDQ); 147 + 148 + for (i = 0; i < GPU_PROCESS_CORNERS; i++) 149 + if (sku_info->gpu_speedo_value < 150 + gpu_process_speedos[threshold][i]) 151 + break; 152 + sku_info->gpu_process_id = i; 153 + 154 + for (i = 0; i < CPU_PROCESS_CORNERS; i++) 155 + if (sku_info->cpu_speedo_value < 156 + cpu_process_speedos[threshold][i]) 157 + break; 158 + sku_info->cpu_process_id = i; 159 + 160 + for (i = 0; i < CORE_PROCESS_CORNERS; i++) 161 + if (soc_speedo_0_value < 162 + core_process_speedos[threshold][i]) 163 + break; 164 + sku_info->core_process_id = i; 165 + 166 + pr_debug("Tegra GPU Speedo ID=%d, Speedo Value=%d\n", 167 + sku_info->gpu_speedo_id, sku_info->gpu_speedo_value); 168 + }
+112
drivers/soc/tegra/fuse/tegra-apbmisc.c
··· 1 + /* 2 + * Copyright (c) 2014, NVIDIA CORPORATION. All rights reserved. 3 + * 4 + * This program is free software; you can redistribute it and/or modify it 5 + * under the terms and conditions of the GNU General Public License, 6 + * version 2, as published by the Free Software Foundation. 7 + * 8 + * This program is distributed in the hope it will be useful, but WITHOUT 9 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 10 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 11 + * more details. 12 + * 13 + * You should have received a copy of the GNU General Public License 14 + * along with this program. If not, see <http://www.gnu.org/licenses/>. 15 + * 16 + */ 17 + 18 + #include <linux/kernel.h> 19 + #include <linux/of.h> 20 + #include <linux/of_address.h> 21 + #include <linux/io.h> 22 + 23 + #include <soc/tegra/fuse.h> 24 + 25 + #include "fuse.h" 26 + 27 + #define APBMISC_BASE 0x70000800 28 + #define APBMISC_SIZE 0x64 29 + #define FUSE_SKU_INFO 0x10 30 + 31 + static void __iomem *apbmisc_base; 32 + static void __iomem *strapping_base; 33 + 34 + u32 tegra_read_chipid(void) 35 + { 36 + return readl_relaxed(apbmisc_base + 4); 37 + } 38 + 39 + u8 tegra_get_chip_id(void) 40 + { 41 + u32 id = tegra_read_chipid(); 42 + 43 + return (id >> 8) & 0xff; 44 + } 45 + 46 + u32 tegra_read_straps(void) 47 + { 48 + if (strapping_base) 49 + return readl_relaxed(strapping_base); 50 + else 51 + return 0; 52 + } 53 + 54 + static const struct of_device_id apbmisc_match[] __initconst = { 55 + { .compatible = "nvidia,tegra20-apbmisc", }, 56 + {}, 57 + }; 58 + 59 + void __init tegra_init_revision(void) 60 + { 61 + u32 id, chip_id, minor_rev; 62 + int rev; 63 + 64 + id = tegra_read_chipid(); 65 + chip_id = (id >> 8) & 0xff; 66 + minor_rev = (id >> 16) & 0xf; 67 + 68 + switch (minor_rev) { 69 + case 1: 70 + rev = TEGRA_REVISION_A01; 71 + break; 72 + case 2: 73 + rev = TEGRA_REVISION_A02; 74 + break; 75 + case 3: 76 + if (chip_id == TEGRA20 && (tegra20_spare_fuse_early(18) || 77 + tegra20_spare_fuse_early(19))) 78 + rev = TEGRA_REVISION_A03p; 79 + else 80 + rev = TEGRA_REVISION_A03; 81 + break; 82 + case 4: 83 + rev = TEGRA_REVISION_A04; 84 + break; 85 + default: 86 + rev = TEGRA_REVISION_UNKNOWN; 87 + } 88 + 89 + tegra_sku_info.revision = rev; 90 + 91 + if (chip_id == TEGRA20) 92 + tegra_sku_info.sku_id = tegra20_fuse_early(FUSE_SKU_INFO); 93 + else 94 + tegra_sku_info.sku_id = tegra30_fuse_readl(FUSE_SKU_INFO); 95 + } 96 + 97 + void __init tegra_init_apbmisc(void) 98 + { 99 + struct device_node *np; 100 + 101 + np = of_find_matching_node(NULL, apbmisc_match); 102 + apbmisc_base = of_iomap(np, 0); 103 + if (!apbmisc_base) { 104 + pr_warn("ioremap tegra apbmisc failed. using %08x instead\n", 105 + APBMISC_BASE); 106 + apbmisc_base = ioremap(APBMISC_BASE, APBMISC_SIZE); 107 + } 108 + 109 + strapping_base = of_iomap(np, 1); 110 + if (!strapping_base) 111 + pr_err("ioremap tegra strapping_base failed\n"); 112 + }
+19 -1
include/soc/tegra/fuse.h
··· 22 22 #define TEGRA114 0x35 23 23 #define TEGRA124 0x40 24 24 25 + #define TEGRA_FUSE_SKU_CALIB_0 0xf0 26 + #define TEGRA30_FUSE_SATA_CALIB 0x124 27 + 25 28 #ifndef __ASSEMBLY__ 26 29 27 30 u32 tegra_read_chipid(void); ··· 40 37 TEGRA_REVISION_MAX, 41 38 }; 42 39 40 + struct tegra_sku_info { 41 + int sku_id; 42 + int cpu_process_id; 43 + int cpu_speedo_id; 44 + int cpu_speedo_value; 45 + int cpu_iddq_value; 46 + int core_process_id; 47 + int soc_speedo_id; 48 + int gpu_speedo_id; 49 + int gpu_process_id; 50 + int gpu_speedo_value; 51 + enum tegra_revision revision; 52 + }; 53 + 43 54 u32 tegra_read_straps(void); 44 55 u32 tegra_read_chipid(void); 45 56 void tegra_init_fuse(void); 57 + int tegra_fuse_readl(unsigned long offset, u32 *value); 46 58 47 - extern enum tegra_revision tegra_revision; 59 + extern struct tegra_sku_info tegra_sku_info; 48 60 49 61 #if defined(CONFIG_TEGRA20_APB_DMA) 50 62 int tegra_apb_readl_using_dma(unsigned long offset, u32 *value);