1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Copyright (c) 2013-2015, NVIDIA CORPORATION. All rights reserved. 4 */ 5 6 #include <linux/device.h> 7 #include <linux/kernel.h> 8 #include <linux/bug.h> 9 10 #include <soc/tegra/fuse.h> 11 12 #include "fuse.h" 13 14 #define CPU_PROCESS_CORNERS 2 15 #define GPU_PROCESS_CORNERS 2 16 #define SOC_PROCESS_CORNERS 3 17 18 #define FUSE_CPU_SPEEDO_0 0x014 19 #define FUSE_CPU_SPEEDO_1 0x02c 20 #define FUSE_CPU_SPEEDO_2 0x030 21 #define FUSE_SOC_SPEEDO_0 0x034 22 #define FUSE_SOC_SPEEDO_1 0x038 23 #define FUSE_SOC_SPEEDO_2 0x03c 24 #define FUSE_CPU_IDDQ 0x018 25 #define FUSE_SOC_IDDQ 0x040 26 #define FUSE_GPU_IDDQ 0x128 27 #define FUSE_FT_REV 0x028 28 29 enum { 30 THRESHOLD_INDEX_0, 31 THRESHOLD_INDEX_1, 32 THRESHOLD_INDEX_COUNT, 33 }; 34 35 static const u32 __initconst cpu_process_speedos[][CPU_PROCESS_CORNERS] = { 36 { 2119, UINT_MAX }, 37 { 2119, UINT_MAX }, 38 }; 39 40 static const u32 __initconst gpu_process_speedos[][GPU_PROCESS_CORNERS] = { 41 { UINT_MAX, UINT_MAX }, 42 { UINT_MAX, UINT_MAX }, 43 }; 44 45 static const u32 __initconst soc_process_speedos[][SOC_PROCESS_CORNERS] = { 46 { 1950, 2100, UINT_MAX }, 47 { 1950, 2100, UINT_MAX }, 48 }; 49 50 static u8 __init get_speedo_revision(void) 51 { 52 return tegra_fuse_read_spare(4) << 2 | 53 tegra_fuse_read_spare(3) << 1 | 54 tegra_fuse_read_spare(2) << 0; 55 } 56 57 static void __init rev_sku_to_speedo_ids(struct tegra_sku_info *sku_info, 58 u8 speedo_rev, int *threshold) 59 { 60 int sku = sku_info->sku_id; 61 62 /* Assign to default */ 63 sku_info->cpu_speedo_id = 0; 64 sku_info->soc_speedo_id = 0; 65 sku_info->gpu_speedo_id = 0; 66 *threshold = THRESHOLD_INDEX_0; 67 68 if (sku_info->revision >= TEGRA_REVISION_A02) { 69 switch (sku) { 70 case 0x00: /* Engineering SKU */ 71 case 0x01: /* Engineering SKU */ 72 case 0x13: 73 sku_info->cpu_speedo_id = 5; 74 sku_info->gpu_speedo_id = 2; 75 break; 76 77 case 0x07: 78 case 0x17: 79 case 0x1F: 80 sku_info->cpu_speedo_id = 7; 81 sku_info->gpu_speedo_id = 2; 82 break; 83 84 case 0x27: 85 sku_info->cpu_speedo_id = 1; 86 sku_info->gpu_speedo_id = 2; 87 break; 88 89 case 0x83: 90 sku_info->cpu_speedo_id = 3; 91 sku_info->gpu_speedo_id = 3; 92 break; 93 94 case 0x87: 95 sku_info->cpu_speedo_id = 2; 96 sku_info->gpu_speedo_id = 1; 97 break; 98 99 case 0x8F: 100 sku_info->soc_speedo_id = 2; 101 sku_info->cpu_speedo_id = 9; 102 sku_info->gpu_speedo_id = 2; 103 break; 104 105 default: 106 pr_err("Tegra210: unknown revision 2 or newer SKU %#04x\n", sku); 107 /* Using the default for the error case */ 108 break; 109 } 110 } else if (sku == 0x00 || sku == 0x01 || sku == 0x07 || sku == 0x13 || sku == 0x17) { 111 sku_info->gpu_speedo_id = 1; 112 } else { 113 pr_err("Tegra210: unknown SKU %#04x\n", sku); 114 } 115 } 116 117 static int get_process_id(int value, const u32 *speedos, unsigned int num) 118 { 119 unsigned int i; 120 121 for (i = 0; i < num; i++) 122 if (value < speedos[i]) 123 return i; 124 125 return -EINVAL; 126 } 127 128 void __init tegra210_init_speedo_data(struct tegra_sku_info *sku_info) 129 { 130 int cpu_speedo[3], soc_speedo[3]; 131 unsigned int index; 132 u8 speedo_revision; 133 134 BUILD_BUG_ON(ARRAY_SIZE(cpu_process_speedos) != 135 THRESHOLD_INDEX_COUNT); 136 BUILD_BUG_ON(ARRAY_SIZE(gpu_process_speedos) != 137 THRESHOLD_INDEX_COUNT); 138 BUILD_BUG_ON(ARRAY_SIZE(soc_process_speedos) != 139 THRESHOLD_INDEX_COUNT); 140 141 /* Read speedo/IDDQ fuses */ 142 cpu_speedo[0] = tegra_fuse_read_early(FUSE_CPU_SPEEDO_0); 143 cpu_speedo[1] = tegra_fuse_read_early(FUSE_CPU_SPEEDO_1); 144 cpu_speedo[2] = tegra_fuse_read_early(FUSE_CPU_SPEEDO_2); 145 146 soc_speedo[0] = tegra_fuse_read_early(FUSE_SOC_SPEEDO_0); 147 soc_speedo[1] = tegra_fuse_read_early(FUSE_SOC_SPEEDO_1); 148 soc_speedo[2] = tegra_fuse_read_early(FUSE_SOC_SPEEDO_2); 149 150 /* 151 * Determine CPU, GPU and SoC speedo values depending on speedo fusing 152 * revision. Note that GPU speedo value is fused in CPU_SPEEDO_2. 153 */ 154 speedo_revision = get_speedo_revision(); 155 pr_info("Speedo Revision %u\n", speedo_revision); 156 157 if (speedo_revision >= 3) { 158 sku_info->cpu_speedo_value = cpu_speedo[0]; 159 sku_info->gpu_speedo_value = cpu_speedo[2]; 160 sku_info->soc_speedo_value = soc_speedo[0]; 161 } else if (speedo_revision == 2) { 162 sku_info->cpu_speedo_value = (-1938 + (1095 * cpu_speedo[0] / 100)) / 10; 163 sku_info->gpu_speedo_value = (-1662 + (1082 * cpu_speedo[2] / 100)) / 10; 164 sku_info->soc_speedo_value = ( -705 + (1037 * soc_speedo[0] / 100)) / 10; 165 } else { 166 sku_info->cpu_speedo_value = 2100; 167 sku_info->gpu_speedo_value = cpu_speedo[2] - 75; 168 sku_info->soc_speedo_value = 1900; 169 } 170 171 if ((sku_info->cpu_speedo_value <= 0) || 172 (sku_info->gpu_speedo_value <= 0) || 173 (sku_info->soc_speedo_value <= 0)) { 174 WARN(1, "speedo value not fused\n"); 175 return; 176 } 177 178 rev_sku_to_speedo_ids(sku_info, speedo_revision, &index); 179 180 sku_info->gpu_process_id = get_process_id(sku_info->gpu_speedo_value, 181 gpu_process_speedos[index], 182 GPU_PROCESS_CORNERS); 183 184 sku_info->cpu_process_id = get_process_id(sku_info->cpu_speedo_value, 185 cpu_process_speedos[index], 186 CPU_PROCESS_CORNERS); 187 188 sku_info->soc_process_id = get_process_id(sku_info->soc_speedo_value, 189 soc_process_speedos[index], 190 SOC_PROCESS_CORNERS); 191 192 pr_debug("Tegra GPU Speedo ID=%d, Speedo Value=%d\n", 193 sku_info->gpu_speedo_id, sku_info->gpu_speedo_value); 194 } 195