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 switch (sku) { 69 case 0x00: /* Engineering SKU */ 70 case 0x01: /* Engineering SKU */ 71 case 0x07: 72 case 0x17: 73 case 0x27: 74 if (speedo_rev >= 2) 75 sku_info->gpu_speedo_id = 1; 76 break; 77 78 case 0x13: 79 if (speedo_rev >= 2) 80 sku_info->gpu_speedo_id = 1; 81 82 sku_info->cpu_speedo_id = 1; 83 break; 84 85 default: 86 pr_err("Tegra210: unknown SKU %#04x\n", sku); 87 /* Using the default for the error case */ 88 break; 89 } 90 } 91 92 static int get_process_id(int value, const u32 *speedos, unsigned int num) 93 { 94 unsigned int i; 95 96 for (i = 0; i < num; i++) 97 if (value < speedos[i]) 98 return i; 99 100 return -EINVAL; 101 } 102 103 void __init tegra210_init_speedo_data(struct tegra_sku_info *sku_info) 104 { 105 int cpu_speedo[3], soc_speedo[3]; 106 unsigned int index; 107 u8 speedo_revision; 108 109 BUILD_BUG_ON(ARRAY_SIZE(cpu_process_speedos) != 110 THRESHOLD_INDEX_COUNT); 111 BUILD_BUG_ON(ARRAY_SIZE(gpu_process_speedos) != 112 THRESHOLD_INDEX_COUNT); 113 BUILD_BUG_ON(ARRAY_SIZE(soc_process_speedos) != 114 THRESHOLD_INDEX_COUNT); 115 116 /* Read speedo/IDDQ fuses */ 117 cpu_speedo[0] = tegra_fuse_read_early(FUSE_CPU_SPEEDO_0); 118 cpu_speedo[1] = tegra_fuse_read_early(FUSE_CPU_SPEEDO_1); 119 cpu_speedo[2] = tegra_fuse_read_early(FUSE_CPU_SPEEDO_2); 120 121 soc_speedo[0] = tegra_fuse_read_early(FUSE_SOC_SPEEDO_0); 122 soc_speedo[1] = tegra_fuse_read_early(FUSE_SOC_SPEEDO_1); 123 soc_speedo[2] = tegra_fuse_read_early(FUSE_SOC_SPEEDO_2); 124 125 /* 126 * Determine CPU, GPU and SoC speedo values depending on speedo fusing 127 * revision. Note that GPU speedo value is fused in CPU_SPEEDO_2. 128 */ 129 speedo_revision = get_speedo_revision(); 130 pr_info("Speedo Revision %u\n", speedo_revision); 131 132 if (speedo_revision >= 3) { 133 sku_info->cpu_speedo_value = cpu_speedo[0]; 134 sku_info->gpu_speedo_value = cpu_speedo[2]; 135 sku_info->soc_speedo_value = soc_speedo[0]; 136 } else if (speedo_revision == 2) { 137 sku_info->cpu_speedo_value = (-1938 + (1095 * cpu_speedo[0] / 100)) / 10; 138 sku_info->gpu_speedo_value = (-1662 + (1082 * cpu_speedo[2] / 100)) / 10; 139 sku_info->soc_speedo_value = ( -705 + (1037 * soc_speedo[0] / 100)) / 10; 140 } else { 141 sku_info->cpu_speedo_value = 2100; 142 sku_info->gpu_speedo_value = cpu_speedo[2] - 75; 143 sku_info->soc_speedo_value = 1900; 144 } 145 146 if ((sku_info->cpu_speedo_value <= 0) || 147 (sku_info->gpu_speedo_value <= 0) || 148 (sku_info->soc_speedo_value <= 0)) { 149 WARN(1, "speedo value not fused\n"); 150 return; 151 } 152 153 rev_sku_to_speedo_ids(sku_info, speedo_revision, &index); 154 155 sku_info->gpu_process_id = get_process_id(sku_info->gpu_speedo_value, 156 gpu_process_speedos[index], 157 GPU_PROCESS_CORNERS); 158 159 sku_info->cpu_process_id = get_process_id(sku_info->cpu_speedo_value, 160 cpu_process_speedos[index], 161 CPU_PROCESS_CORNERS); 162 163 sku_info->soc_process_id = get_process_id(sku_info->soc_speedo_value, 164 soc_process_speedos[index], 165 SOC_PROCESS_CORNERS); 166 167 pr_debug("Tegra GPU Speedo ID=%d, Speedo Value=%d\n", 168 sku_info->gpu_speedo_id, sku_info->gpu_speedo_value); 169 } 170