293 lines
		
	
	
	
		
			7 KiB
			
		
	
	
	
		
			C
		
	
	
	
	
	
		
		
			
		
	
	
			293 lines
		
	
	
	
		
			7 KiB
			
		
	
	
	
		
			C
		
	
	
	
	
	
| 
								 | 
							
								/*
							 | 
						||
| 
								 | 
							
								 * Copyright (c) 2012, NVIDIA CORPORATION.  All rights reserved.
							 | 
						||
| 
								 | 
							
								 *
							 | 
						||
| 
								 | 
							
								 * This program is free software; you can redistribute it and/or modify it
							 | 
						||
| 
								 | 
							
								 * under the terms and conditions of the GNU General Public License,
							 | 
						||
| 
								 | 
							
								 * version 2, as published by the Free Software Foundation.
							 | 
						||
| 
								 | 
							
								 *
							 | 
						||
| 
								 | 
							
								 * This program is distributed in the hope it will be useful, but WITHOUT
							 | 
						||
| 
								 | 
							
								 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
							 | 
						||
| 
								 | 
							
								 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
							 | 
						||
| 
								 | 
							
								 * more details.
							 | 
						||
| 
								 | 
							
								 *
							 | 
						||
| 
								 | 
							
								 * You should have received a copy of the GNU General Public License
							 | 
						||
| 
								 | 
							
								 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#include <linux/kernel.h>
							 | 
						||
| 
								 | 
							
								#include <linux/bug.h>
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#include "fuse.h"
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#define CORE_PROCESS_CORNERS_NUM	1
							 | 
						||
| 
								 | 
							
								#define CPU_PROCESS_CORNERS_NUM		6
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#define FUSE_SPEEDO_CALIB_0	0x114
							 | 
						||
| 
								 | 
							
								#define FUSE_PACKAGE_INFO	0X1FC
							 | 
						||
| 
								 | 
							
								#define FUSE_TEST_PROG_VER	0X128
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#define G_SPEEDO_BIT_MINUS1	58
							 | 
						||
| 
								 | 
							
								#define G_SPEEDO_BIT_MINUS1_R	59
							 | 
						||
| 
								 | 
							
								#define G_SPEEDO_BIT_MINUS2	60
							 | 
						||
| 
								 | 
							
								#define G_SPEEDO_BIT_MINUS2_R	61
							 | 
						||
| 
								 | 
							
								#define LP_SPEEDO_BIT_MINUS1	62
							 | 
						||
| 
								 | 
							
								#define LP_SPEEDO_BIT_MINUS1_R	63
							 | 
						||
| 
								 | 
							
								#define LP_SPEEDO_BIT_MINUS2	64
							 | 
						||
| 
								 | 
							
								#define LP_SPEEDO_BIT_MINUS2_R	65
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								enum {
							 | 
						||
| 
								 | 
							
									THRESHOLD_INDEX_0,
							 | 
						||
| 
								 | 
							
									THRESHOLD_INDEX_1,
							 | 
						||
| 
								 | 
							
									THRESHOLD_INDEX_2,
							 | 
						||
| 
								 | 
							
									THRESHOLD_INDEX_3,
							 | 
						||
| 
								 | 
							
									THRESHOLD_INDEX_4,
							 | 
						||
| 
								 | 
							
									THRESHOLD_INDEX_5,
							 | 
						||
| 
								 | 
							
									THRESHOLD_INDEX_6,
							 | 
						||
| 
								 | 
							
									THRESHOLD_INDEX_7,
							 | 
						||
| 
								 | 
							
									THRESHOLD_INDEX_8,
							 | 
						||
| 
								 | 
							
									THRESHOLD_INDEX_9,
							 | 
						||
| 
								 | 
							
									THRESHOLD_INDEX_10,
							 | 
						||
| 
								 | 
							
									THRESHOLD_INDEX_11,
							 | 
						||
| 
								 | 
							
									THRESHOLD_INDEX_COUNT,
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								static const u32 core_process_speedos[][CORE_PROCESS_CORNERS_NUM] = {
							 | 
						||
| 
								 | 
							
									{180},
							 | 
						||
| 
								 | 
							
									{170},
							 | 
						||
| 
								 | 
							
									{195},
							 | 
						||
| 
								 | 
							
									{180},
							 | 
						||
| 
								 | 
							
									{168},
							 | 
						||
| 
								 | 
							
									{192},
							 | 
						||
| 
								 | 
							
									{180},
							 | 
						||
| 
								 | 
							
									{170},
							 | 
						||
| 
								 | 
							
									{195},
							 | 
						||
| 
								 | 
							
									{180},
							 | 
						||
| 
								 | 
							
									{180},
							 | 
						||
| 
								 | 
							
									{180},
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								static const u32 cpu_process_speedos[][CPU_PROCESS_CORNERS_NUM] = {
							 | 
						||
| 
								 | 
							
									{306, 338, 360, 376, UINT_MAX},
							 | 
						||
| 
								 | 
							
									{295, 336, 358, 375, UINT_MAX},
							 | 
						||
| 
								 | 
							
									{325, 325, 358, 375, UINT_MAX},
							 | 
						||
| 
								 | 
							
									{325, 325, 358, 375, UINT_MAX},
							 | 
						||
| 
								 | 
							
									{292, 324, 348, 364, UINT_MAX},
							 | 
						||
| 
								 | 
							
									{324, 324, 348, 364, UINT_MAX},
							 | 
						||
| 
								 | 
							
									{324, 324, 348, 364, UINT_MAX},
							 | 
						||
| 
								 | 
							
									{295, 336, 358, 375, UINT_MAX},
							 | 
						||
| 
								 | 
							
									{358, 358, 358, 358, 397, UINT_MAX},
							 | 
						||
| 
								 | 
							
									{364, 364, 364, 364, 397, UINT_MAX},
							 | 
						||
| 
								 | 
							
									{295, 336, 358, 375, 391, UINT_MAX},
							 | 
						||
| 
								 | 
							
									{295, 336, 358, 375, 391, UINT_MAX},
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								static int threshold_index;
							 | 
						||
| 
								 | 
							
								static int package_id;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								static void fuse_speedo_calib(u32 *speedo_g, u32 *speedo_lp)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									u32 reg;
							 | 
						||
| 
								 | 
							
									int ate_ver;
							 | 
						||
| 
								 | 
							
									int bit_minus1;
							 | 
						||
| 
								 | 
							
									int bit_minus2;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									reg = tegra_fuse_readl(FUSE_SPEEDO_CALIB_0);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									*speedo_lp = (reg & 0xFFFF) * 4;
							 | 
						||
| 
								 | 
							
									*speedo_g = ((reg >> 16) & 0xFFFF) * 4;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									ate_ver = tegra_fuse_readl(FUSE_TEST_PROG_VER);
							 | 
						||
| 
								 | 
							
									pr_info("%s: ATE prog ver %d.%d\n", __func__, ate_ver/10, ate_ver%10);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									if (ate_ver >= 26) {
							 | 
						||
| 
								 | 
							
										bit_minus1 = tegra_spare_fuse(LP_SPEEDO_BIT_MINUS1);
							 | 
						||
| 
								 | 
							
										bit_minus1 |= tegra_spare_fuse(LP_SPEEDO_BIT_MINUS1_R);
							 | 
						||
| 
								 | 
							
										bit_minus2 = tegra_spare_fuse(LP_SPEEDO_BIT_MINUS2);
							 | 
						||
| 
								 | 
							
										bit_minus2 |= tegra_spare_fuse(LP_SPEEDO_BIT_MINUS2_R);
							 | 
						||
| 
								 | 
							
										*speedo_lp |= (bit_minus1 << 1) | bit_minus2;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										bit_minus1 = tegra_spare_fuse(G_SPEEDO_BIT_MINUS1);
							 | 
						||
| 
								 | 
							
										bit_minus1 |= tegra_spare_fuse(G_SPEEDO_BIT_MINUS1_R);
							 | 
						||
| 
								 | 
							
										bit_minus2 = tegra_spare_fuse(G_SPEEDO_BIT_MINUS2);
							 | 
						||
| 
								 | 
							
										bit_minus2 |= tegra_spare_fuse(G_SPEEDO_BIT_MINUS2_R);
							 | 
						||
| 
								 | 
							
										*speedo_g |= (bit_minus1 << 1) | bit_minus2;
							 | 
						||
| 
								 | 
							
									} else {
							 | 
						||
| 
								 | 
							
										*speedo_lp |= 0x3;
							 | 
						||
| 
								 | 
							
										*speedo_g |= 0x3;
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								static void rev_sku_to_speedo_ids(int rev, int sku)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									switch (rev) {
							 | 
						||
| 
								 | 
							
									case TEGRA_REVISION_A01:
							 | 
						||
| 
								 | 
							
										tegra_cpu_speedo_id = 0;
							 | 
						||
| 
								 | 
							
										tegra_soc_speedo_id = 0;
							 | 
						||
| 
								 | 
							
										threshold_index = THRESHOLD_INDEX_0;
							 | 
						||
| 
								 | 
							
										break;
							 | 
						||
| 
								 | 
							
									case TEGRA_REVISION_A02:
							 | 
						||
| 
								 | 
							
									case TEGRA_REVISION_A03:
							 | 
						||
| 
								 | 
							
										switch (sku) {
							 | 
						||
| 
								 | 
							
										case 0x87:
							 | 
						||
| 
								 | 
							
										case 0x82:
							 | 
						||
| 
								 | 
							
											tegra_cpu_speedo_id = 1;
							 | 
						||
| 
								 | 
							
											tegra_soc_speedo_id = 1;
							 | 
						||
| 
								 | 
							
											threshold_index = THRESHOLD_INDEX_1;
							 | 
						||
| 
								 | 
							
											break;
							 | 
						||
| 
								 | 
							
										case 0x81:
							 | 
						||
| 
								 | 
							
											switch (package_id) {
							 | 
						||
| 
								 | 
							
											case 1:
							 | 
						||
| 
								 | 
							
												tegra_cpu_speedo_id = 2;
							 | 
						||
| 
								 | 
							
												tegra_soc_speedo_id = 2;
							 | 
						||
| 
								 | 
							
												threshold_index = THRESHOLD_INDEX_2;
							 | 
						||
| 
								 | 
							
												break;
							 | 
						||
| 
								 | 
							
											case 2:
							 | 
						||
| 
								 | 
							
												tegra_cpu_speedo_id = 4;
							 | 
						||
| 
								 | 
							
												tegra_soc_speedo_id = 1;
							 | 
						||
| 
								 | 
							
												threshold_index = THRESHOLD_INDEX_7;
							 | 
						||
| 
								 | 
							
												break;
							 | 
						||
| 
								 | 
							
											default:
							 | 
						||
| 
								 | 
							
												pr_err("Tegra30: Unknown pkg %d\n", package_id);
							 | 
						||
| 
								 | 
							
												BUG();
							 | 
						||
| 
								 | 
							
												break;
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
											break;
							 | 
						||
| 
								 | 
							
										case 0x80:
							 | 
						||
| 
								 | 
							
											switch (package_id) {
							 | 
						||
| 
								 | 
							
											case 1:
							 | 
						||
| 
								 | 
							
												tegra_cpu_speedo_id = 5;
							 | 
						||
| 
								 | 
							
												tegra_soc_speedo_id = 2;
							 | 
						||
| 
								 | 
							
												threshold_index = THRESHOLD_INDEX_8;
							 | 
						||
| 
								 | 
							
												break;
							 | 
						||
| 
								 | 
							
											case 2:
							 | 
						||
| 
								 | 
							
												tegra_cpu_speedo_id = 6;
							 | 
						||
| 
								 | 
							
												tegra_soc_speedo_id = 2;
							 | 
						||
| 
								 | 
							
												threshold_index = THRESHOLD_INDEX_9;
							 | 
						||
| 
								 | 
							
												break;
							 | 
						||
| 
								 | 
							
											default:
							 | 
						||
| 
								 | 
							
												pr_err("Tegra30: Unknown pkg %d\n", package_id);
							 | 
						||
| 
								 | 
							
												BUG();
							 | 
						||
| 
								 | 
							
												break;
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
											break;
							 | 
						||
| 
								 | 
							
										case 0x83:
							 | 
						||
| 
								 | 
							
											switch (package_id) {
							 | 
						||
| 
								 | 
							
											case 1:
							 | 
						||
| 
								 | 
							
												tegra_cpu_speedo_id = 7;
							 | 
						||
| 
								 | 
							
												tegra_soc_speedo_id = 1;
							 | 
						||
| 
								 | 
							
												threshold_index = THRESHOLD_INDEX_10;
							 | 
						||
| 
								 | 
							
												break;
							 | 
						||
| 
								 | 
							
											case 2:
							 | 
						||
| 
								 | 
							
												tegra_cpu_speedo_id = 3;
							 | 
						||
| 
								 | 
							
												tegra_soc_speedo_id = 2;
							 | 
						||
| 
								 | 
							
												threshold_index = THRESHOLD_INDEX_3;
							 | 
						||
| 
								 | 
							
												break;
							 | 
						||
| 
								 | 
							
											default:
							 | 
						||
| 
								 | 
							
												pr_err("Tegra30: Unknown pkg %d\n", package_id);
							 | 
						||
| 
								 | 
							
												BUG();
							 | 
						||
| 
								 | 
							
												break;
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
											break;
							 | 
						||
| 
								 | 
							
										case 0x8F:
							 | 
						||
| 
								 | 
							
											tegra_cpu_speedo_id = 8;
							 | 
						||
| 
								 | 
							
											tegra_soc_speedo_id = 1;
							 | 
						||
| 
								 | 
							
											threshold_index = THRESHOLD_INDEX_11;
							 | 
						||
| 
								 | 
							
											break;
							 | 
						||
| 
								 | 
							
										case 0x08:
							 | 
						||
| 
								 | 
							
											tegra_cpu_speedo_id = 1;
							 | 
						||
| 
								 | 
							
											tegra_soc_speedo_id = 1;
							 | 
						||
| 
								 | 
							
											threshold_index = THRESHOLD_INDEX_4;
							 | 
						||
| 
								 | 
							
											break;
							 | 
						||
| 
								 | 
							
										case 0x02:
							 | 
						||
| 
								 | 
							
											tegra_cpu_speedo_id = 2;
							 | 
						||
| 
								 | 
							
											tegra_soc_speedo_id = 2;
							 | 
						||
| 
								 | 
							
											threshold_index = THRESHOLD_INDEX_5;
							 | 
						||
| 
								 | 
							
											break;
							 | 
						||
| 
								 | 
							
										case 0x04:
							 | 
						||
| 
								 | 
							
											tegra_cpu_speedo_id = 3;
							 | 
						||
| 
								 | 
							
											tegra_soc_speedo_id = 2;
							 | 
						||
| 
								 | 
							
											threshold_index = THRESHOLD_INDEX_6;
							 | 
						||
| 
								 | 
							
											break;
							 | 
						||
| 
								 | 
							
										case 0:
							 | 
						||
| 
								 | 
							
											switch (package_id) {
							 | 
						||
| 
								 | 
							
											case 1:
							 | 
						||
| 
								 | 
							
												tegra_cpu_speedo_id = 2;
							 | 
						||
| 
								 | 
							
												tegra_soc_speedo_id = 2;
							 | 
						||
| 
								 | 
							
												threshold_index = THRESHOLD_INDEX_2;
							 | 
						||
| 
								 | 
							
												break;
							 | 
						||
| 
								 | 
							
											case 2:
							 | 
						||
| 
								 | 
							
												tegra_cpu_speedo_id = 3;
							 | 
						||
| 
								 | 
							
												tegra_soc_speedo_id = 2;
							 | 
						||
| 
								 | 
							
												threshold_index = THRESHOLD_INDEX_3;
							 | 
						||
| 
								 | 
							
												break;
							 | 
						||
| 
								 | 
							
											default:
							 | 
						||
| 
								 | 
							
												pr_err("Tegra30: Unknown pkg %d\n", package_id);
							 | 
						||
| 
								 | 
							
												BUG();
							 | 
						||
| 
								 | 
							
												break;
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
											break;
							 | 
						||
| 
								 | 
							
										default:
							 | 
						||
| 
								 | 
							
											pr_warn("Tegra30: Unknown SKU %d\n", sku);
							 | 
						||
| 
								 | 
							
											tegra_cpu_speedo_id = 0;
							 | 
						||
| 
								 | 
							
											tegra_soc_speedo_id = 0;
							 | 
						||
| 
								 | 
							
											threshold_index = THRESHOLD_INDEX_0;
							 | 
						||
| 
								 | 
							
											break;
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
										break;
							 | 
						||
| 
								 | 
							
									default:
							 | 
						||
| 
								 | 
							
										pr_warn("Tegra30: Unknown chip rev %d\n", rev);
							 | 
						||
| 
								 | 
							
										tegra_cpu_speedo_id = 0;
							 | 
						||
| 
								 | 
							
										tegra_soc_speedo_id = 0;
							 | 
						||
| 
								 | 
							
										threshold_index = THRESHOLD_INDEX_0;
							 | 
						||
| 
								 | 
							
										break;
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								void tegra30_init_speedo_data(void)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									u32 cpu_speedo_val;
							 | 
						||
| 
								 | 
							
									u32 core_speedo_val;
							 | 
						||
| 
								 | 
							
									int i;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									BUILD_BUG_ON(ARRAY_SIZE(cpu_process_speedos) !=
							 | 
						||
| 
								 | 
							
											THRESHOLD_INDEX_COUNT);
							 | 
						||
| 
								 | 
							
									BUILD_BUG_ON(ARRAY_SIZE(core_process_speedos) !=
							 | 
						||
| 
								 | 
							
											THRESHOLD_INDEX_COUNT);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									package_id = tegra_fuse_readl(FUSE_PACKAGE_INFO) & 0x0F;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									rev_sku_to_speedo_ids(tegra_revision, tegra_sku_id);
							 | 
						||
| 
								 | 
							
									fuse_speedo_calib(&cpu_speedo_val, &core_speedo_val);
							 | 
						||
| 
								 | 
							
									pr_debug("%s CPU speedo value %u\n", __func__, cpu_speedo_val);
							 | 
						||
| 
								 | 
							
									pr_debug("%s Core speedo value %u\n", __func__, core_speedo_val);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									for (i = 0; i < CPU_PROCESS_CORNERS_NUM; i++) {
							 | 
						||
| 
								 | 
							
										if (cpu_speedo_val < cpu_process_speedos[threshold_index][i])
							 | 
						||
| 
								 | 
							
											break;
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									tegra_cpu_process_id = i - 1;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									if (tegra_cpu_process_id == -1) {
							 | 
						||
| 
								 | 
							
										pr_warn("Tegra30: CPU speedo value %3d out of range",
							 | 
						||
| 
								 | 
							
										       cpu_speedo_val);
							 | 
						||
| 
								 | 
							
										tegra_cpu_process_id = 0;
							 | 
						||
| 
								 | 
							
										tegra_cpu_speedo_id = 1;
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									for (i = 0; i < CORE_PROCESS_CORNERS_NUM; i++) {
							 | 
						||
| 
								 | 
							
										if (core_speedo_val < core_process_speedos[threshold_index][i])
							 | 
						||
| 
								 | 
							
											break;
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									tegra_core_process_id = i - 1;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									if (tegra_core_process_id == -1) {
							 | 
						||
| 
								 | 
							
										pr_warn("Tegra30: CORE speedo value %3d out of range",
							 | 
						||
| 
								 | 
							
										       core_speedo_val);
							 | 
						||
| 
								 | 
							
										tegra_core_process_id = 0;
							 | 
						||
| 
								 | 
							
										tegra_soc_speedo_id = 1;
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									pr_info("Tegra30: CPU Speedo ID %d, Soc Speedo ID %d",
							 | 
						||
| 
								 | 
							
										tegra_cpu_speedo_id, tegra_soc_speedo_id);
							 | 
						||
| 
								 | 
							
								}
							 |