18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Copyright (c) 2012-2014, NVIDIA CORPORATION.  All rights reserved.
48c2ecf20Sopenharmony_ci */
58c2ecf20Sopenharmony_ci
68c2ecf20Sopenharmony_ci#include <linux/bug.h>
78c2ecf20Sopenharmony_ci#include <linux/device.h>
88c2ecf20Sopenharmony_ci#include <linux/kernel.h>
98c2ecf20Sopenharmony_ci
108c2ecf20Sopenharmony_ci#include <soc/tegra/fuse.h>
118c2ecf20Sopenharmony_ci
128c2ecf20Sopenharmony_ci#include "fuse.h"
138c2ecf20Sopenharmony_ci
148c2ecf20Sopenharmony_ci#define CPU_SPEEDO_LSBIT		20
158c2ecf20Sopenharmony_ci#define CPU_SPEEDO_MSBIT		29
168c2ecf20Sopenharmony_ci#define CPU_SPEEDO_REDUND_LSBIT		30
178c2ecf20Sopenharmony_ci#define CPU_SPEEDO_REDUND_MSBIT		39
188c2ecf20Sopenharmony_ci#define CPU_SPEEDO_REDUND_OFFS	(CPU_SPEEDO_REDUND_MSBIT - CPU_SPEEDO_MSBIT)
198c2ecf20Sopenharmony_ci
208c2ecf20Sopenharmony_ci#define SOC_SPEEDO_LSBIT		40
218c2ecf20Sopenharmony_ci#define SOC_SPEEDO_MSBIT		47
228c2ecf20Sopenharmony_ci#define SOC_SPEEDO_REDUND_LSBIT		48
238c2ecf20Sopenharmony_ci#define SOC_SPEEDO_REDUND_MSBIT		55
248c2ecf20Sopenharmony_ci#define SOC_SPEEDO_REDUND_OFFS	(SOC_SPEEDO_REDUND_MSBIT - SOC_SPEEDO_MSBIT)
258c2ecf20Sopenharmony_ci
268c2ecf20Sopenharmony_ci#define SPEEDO_MULT			4
278c2ecf20Sopenharmony_ci
288c2ecf20Sopenharmony_ci#define PROCESS_CORNERS_NUM		4
298c2ecf20Sopenharmony_ci
308c2ecf20Sopenharmony_ci#define SPEEDO_ID_SELECT_0(rev)		((rev) <= 2)
318c2ecf20Sopenharmony_ci#define SPEEDO_ID_SELECT_1(sku)		\
328c2ecf20Sopenharmony_ci	(((sku) != 20) && ((sku) != 23) && ((sku) != 24) && \
338c2ecf20Sopenharmony_ci	 ((sku) != 27) && ((sku) != 28))
348c2ecf20Sopenharmony_ci
358c2ecf20Sopenharmony_cienum {
368c2ecf20Sopenharmony_ci	SPEEDO_ID_0,
378c2ecf20Sopenharmony_ci	SPEEDO_ID_1,
388c2ecf20Sopenharmony_ci	SPEEDO_ID_2,
398c2ecf20Sopenharmony_ci	SPEEDO_ID_COUNT,
408c2ecf20Sopenharmony_ci};
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_cistatic const u32 __initconst cpu_process_speedos[][PROCESS_CORNERS_NUM] = {
438c2ecf20Sopenharmony_ci	{315, 366, 420, UINT_MAX},
448c2ecf20Sopenharmony_ci	{303, 368, 419, UINT_MAX},
458c2ecf20Sopenharmony_ci	{316, 331, 383, UINT_MAX},
468c2ecf20Sopenharmony_ci};
478c2ecf20Sopenharmony_ci
488c2ecf20Sopenharmony_cistatic const u32 __initconst soc_process_speedos[][PROCESS_CORNERS_NUM] = {
498c2ecf20Sopenharmony_ci	{165, 195, 224, UINT_MAX},
508c2ecf20Sopenharmony_ci	{165, 195, 224, UINT_MAX},
518c2ecf20Sopenharmony_ci	{165, 195, 224, UINT_MAX},
528c2ecf20Sopenharmony_ci};
538c2ecf20Sopenharmony_ci
548c2ecf20Sopenharmony_civoid __init tegra20_init_speedo_data(struct tegra_sku_info *sku_info)
558c2ecf20Sopenharmony_ci{
568c2ecf20Sopenharmony_ci	u32 reg;
578c2ecf20Sopenharmony_ci	u32 val;
588c2ecf20Sopenharmony_ci	int i;
598c2ecf20Sopenharmony_ci
608c2ecf20Sopenharmony_ci	BUILD_BUG_ON(ARRAY_SIZE(cpu_process_speedos) != SPEEDO_ID_COUNT);
618c2ecf20Sopenharmony_ci	BUILD_BUG_ON(ARRAY_SIZE(soc_process_speedos) != SPEEDO_ID_COUNT);
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_ci	if (SPEEDO_ID_SELECT_0(sku_info->revision))
648c2ecf20Sopenharmony_ci		sku_info->soc_speedo_id = SPEEDO_ID_0;
658c2ecf20Sopenharmony_ci	else if (SPEEDO_ID_SELECT_1(sku_info->sku_id))
668c2ecf20Sopenharmony_ci		sku_info->soc_speedo_id = SPEEDO_ID_1;
678c2ecf20Sopenharmony_ci	else
688c2ecf20Sopenharmony_ci		sku_info->soc_speedo_id = SPEEDO_ID_2;
698c2ecf20Sopenharmony_ci
708c2ecf20Sopenharmony_ci	val = 0;
718c2ecf20Sopenharmony_ci	for (i = CPU_SPEEDO_MSBIT; i >= CPU_SPEEDO_LSBIT; i--) {
728c2ecf20Sopenharmony_ci		reg = tegra_fuse_read_spare(i) |
738c2ecf20Sopenharmony_ci			tegra_fuse_read_spare(i + CPU_SPEEDO_REDUND_OFFS);
748c2ecf20Sopenharmony_ci		val = (val << 1) | (reg & 0x1);
758c2ecf20Sopenharmony_ci	}
768c2ecf20Sopenharmony_ci	val = val * SPEEDO_MULT;
778c2ecf20Sopenharmony_ci	pr_debug("Tegra CPU speedo value %u\n", val);
788c2ecf20Sopenharmony_ci
798c2ecf20Sopenharmony_ci	for (i = 0; i < (PROCESS_CORNERS_NUM - 1); i++) {
808c2ecf20Sopenharmony_ci		if (val <= cpu_process_speedos[sku_info->soc_speedo_id][i])
818c2ecf20Sopenharmony_ci			break;
828c2ecf20Sopenharmony_ci	}
838c2ecf20Sopenharmony_ci	sku_info->cpu_process_id = i;
848c2ecf20Sopenharmony_ci
858c2ecf20Sopenharmony_ci	val = 0;
868c2ecf20Sopenharmony_ci	for (i = SOC_SPEEDO_MSBIT; i >= SOC_SPEEDO_LSBIT; i--) {
878c2ecf20Sopenharmony_ci		reg = tegra_fuse_read_spare(i) |
888c2ecf20Sopenharmony_ci			tegra_fuse_read_spare(i + SOC_SPEEDO_REDUND_OFFS);
898c2ecf20Sopenharmony_ci		val = (val << 1) | (reg & 0x1);
908c2ecf20Sopenharmony_ci	}
918c2ecf20Sopenharmony_ci	val = val * SPEEDO_MULT;
928c2ecf20Sopenharmony_ci	pr_debug("Core speedo value %u\n", val);
938c2ecf20Sopenharmony_ci
948c2ecf20Sopenharmony_ci	for (i = 0; i < (PROCESS_CORNERS_NUM - 1); i++) {
958c2ecf20Sopenharmony_ci		if (val <= soc_process_speedos[sku_info->soc_speedo_id][i])
968c2ecf20Sopenharmony_ci			break;
978c2ecf20Sopenharmony_ci	}
988c2ecf20Sopenharmony_ci	sku_info->soc_process_id = i;
998c2ecf20Sopenharmony_ci}
100