diff --git a/drivers/clk/tegra/clk-tegra124-dfll-fcpu.c b/drivers/clk/tegra/clk-tegra124-dfll-fcpu.c index 9fa203e2e75d..c6fd0413127d 100644 --- a/drivers/clk/tegra/clk-tegra124-dfll-fcpu.c +++ b/drivers/clk/tegra/clk-tegra124-dfll-fcpu.c @@ -593,6 +593,12 @@ static struct cvb_table tegra210b01_cpu_cvb_tables[] = { .tune_high_min_millivolts = 850, } }, + { + .speedo_id = 3, + .process_id = -1, + .max_millivolts = 1120, + CPUB01_CVB_TABLE, + }, { .speedo_id = 2, .process_id = 1, diff --git a/drivers/soc/tegra/fuse/fuse-tegra.c b/drivers/soc/tegra/fuse/fuse-tegra.c index d27667283846..ffa325c40bf5 100644 --- a/drivers/soc/tegra/fuse/fuse-tegra.c +++ b/drivers/soc/tegra/fuse/fuse-tegra.c @@ -25,7 +25,12 @@ #include "fuse.h" -struct tegra_sku_info tegra_sku_info; +struct tegra_sku_info tegra_sku_info = { + .cpu_iddq_value = -ENOTSUPP, + .gpu_iddq_value = -ENOTSUPP, + .soc_iddq_value = -ENOTSUPP, + .speedo_rev = -ENOTSUPP, +}; EXPORT_SYMBOL(tegra_sku_info); static const char *tegra_revision_name[TEGRA_REVISION_MAX] = { @@ -117,7 +122,7 @@ static void tegra_fuse_restore(void *base) static void tegra_fuse_print_sku_info(struct tegra_sku_info *tegra_sku_info) { - pr_info("Tegra Revision: %s SKU: %d CPU Process: %d SoC Process: %d\n", + pr_info("Tegra Revision: %s SKU: 0x%x CPU Process: %d SoC Process: %d\n", tegra_revision_name[tegra_sku_info->revision], tegra_sku_info->sku_id, tegra_sku_info->cpu_process_id, tegra_sku_info->soc_process_id); @@ -366,6 +371,33 @@ int tegra_fuse_readl(unsigned long offset, u32 *value) } EXPORT_SYMBOL(tegra_fuse_readl); +int tegra_fuse_get_cpu_iddq(void) +{ + if (!fuse->soc || !fuse->base) + return -ENODEV; + + return tegra_sku_info.cpu_iddq_value; +} +EXPORT_SYMBOL(tegra_fuse_get_cpu_iddq); + +int tegra_fuse_get_gpu_iddq(void) +{ + if (!fuse->soc || !fuse->base) + return -ENODEV; + + return tegra_sku_info.gpu_iddq_value; +} +EXPORT_SYMBOL(tegra_fuse_get_gpu_iddq); + +int tegra_fuse_get_soc_iddq(void) +{ + if (!fuse->soc || !fuse->base) + return -ENODEV; + + return tegra_sku_info.soc_iddq_value; +} +EXPORT_SYMBOL(tegra_fuse_get_soc_iddq); + static void tegra_enable_fuse_clk(void __iomem *base) { u32 reg; diff --git a/drivers/soc/tegra/fuse/speedo-tegra124.c b/drivers/soc/tegra/fuse/speedo-tegra124.c index 5b1ee28e4272..8fe24796e549 100644 --- a/drivers/soc/tegra/fuse/speedo-tegra124.c +++ b/drivers/soc/tegra/fuse/speedo-tegra124.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2013-2014, NVIDIA CORPORATION. All rights reserved. + * Copyright (c) 2013-2016, NVIDIA CORPORATION. All rights reserved. */ #include @@ -111,6 +111,16 @@ void __init tegra124_init_speedo_data(struct tegra_sku_info *sku_info) THRESHOLD_INDEX_COUNT); sku_info->cpu_speedo_value = tegra_fuse_read_early(FUSE_CPU_SPEEDO_0); + + /* GPU Speedo is stored in CPU_SPEEDO_2 */ + sku_info->gpu_speedo_value = tegra_fuse_read_early(FUSE_CPU_SPEEDO_2); + + soc_speedo_0_value = tegra_fuse_read_early(FUSE_SOC_SPEEDO_0); + + sku_info->cpu_iddq_value = tegra_fuse_read_early(FUSE_CPU_IDDQ); + sku_info->soc_iddq_value = tegra_fuse_read_early(FUSE_SOC_IDDQ); + sku_info->gpu_iddq_value = tegra_fuse_read_early(FUSE_GPU_IDDQ); + if (sku_info->cpu_speedo_value == 0) { pr_warn("Tegra Warning: Speedo value not fused.\n"); WARN_ON(1); @@ -123,8 +133,6 @@ void __init tegra124_init_speedo_data(struct tegra_sku_info *sku_info) rev_sku_to_speedo_ids(sku_info, &threshold); - sku_info->cpu_iddq_value = tegra_fuse_read_early(FUSE_CPU_IDDQ); - for (i = 0; i < GPU_PROCESS_CORNERS; i++) if (sku_info->gpu_speedo_value < gpu_process_speedos[threshold][i]) diff --git a/drivers/soc/tegra/fuse/speedo-tegra210.c b/drivers/soc/tegra/fuse/speedo-tegra210.c index 06c2bcbee573..246bbdbd22f3 100644 --- a/drivers/soc/tegra/fuse/speedo-tegra210.c +++ b/drivers/soc/tegra/fuse/speedo-tegra210.c @@ -1,11 +1,12 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2013-2015, NVIDIA CORPORATION. All rights reserved. + * Copyright (c) 2013-2017, NVIDIA CORPORATION. All rights reserved. */ #include #include #include +#include #include @@ -29,22 +30,26 @@ enum { THRESHOLD_INDEX_0, THRESHOLD_INDEX_1, + THRESHOLD_INDEX_2, THRESHOLD_INDEX_COUNT, }; static const u32 __initconst cpu_process_speedos[][CPU_PROCESS_CORNERS] = { { 2119, UINT_MAX }, { 2119, UINT_MAX }, + { 1650, UINT_MAX }, }; static const u32 __initconst gpu_process_speedos[][GPU_PROCESS_CORNERS] = { { UINT_MAX, UINT_MAX }, { UINT_MAX, UINT_MAX }, + { UINT_MAX, UINT_MAX }, }; static const u32 __initconst soc_process_speedos[][SOC_PROCESS_CORNERS] = { - { 1950, 2100, UINT_MAX }, - { 1950, 2100, UINT_MAX }, + { 1950, 2073, UINT_MAX }, + { UINT_MAX, UINT_MAX, UINT_MAX }, + { 1598, 1709, UINT_MAX }, }; static u8 __init get_speedo_revision(void) @@ -54,66 +59,154 @@ static u8 __init get_speedo_revision(void) tegra_fuse_read_spare(2) << 0; } -static void __init rev_sku_to_speedo_ids(struct tegra_sku_info *sku_info, - u8 speedo_rev, int *threshold) +static void __init rev_t210sku_to_speedo_ids(struct tegra_sku_info *sku_info, + u8 speedo_rev, int *threshold) { int sku = sku_info->sku_id; + int rev = sku_info->revision; + bool a02 = (rev != TEGRA_REVISION_A01) && + (rev != TEGRA_REVISION_UNKNOWN); + bool vcm31_sku = false; + bool always_on = false; /* Assign to default */ sku_info->cpu_speedo_id = 0; sku_info->soc_speedo_id = 0; sku_info->gpu_speedo_id = 0; + sku_info->ucm = TEGRA_UCM1; *threshold = THRESHOLD_INDEX_0; +#ifdef CONFIG_OF + vcm31_sku = of_property_read_bool(of_chosen, "nvidia,t210-vcm31-sku"); + always_on = of_property_read_bool(of_chosen, + "nvidia,tegra-always-on-personality"); +#endif - if (sku_info->revision >= TEGRA_REVISION_A02) { - switch (sku) { - case 0x00: /* Engineering SKU */ - case 0x01: /* Engineering SKU */ - case 0x13: + switch (sku) { + case 0x00: /* Engineering SKU */ + case 0x01: /* Engineering SKU */ + case 0x13: + if (a02) { sku_info->cpu_speedo_id = 5; sku_info->gpu_speedo_id = 2; break; - - case 0x07: - case 0x17: - case 0x1F: + } + /* fall through for a01 */ + fallthrough; + case 0x07: + case 0x17: + case 0x1F: + if (vcm31_sku && sku == 0x17) { + sku_info->cpu_speedo_id = 4; + sku_info->soc_speedo_id = 1; + sku_info->gpu_speedo_id = 4; + *threshold = THRESHOLD_INDEX_1; + break; + } + if (a02) { sku_info->cpu_speedo_id = 7; sku_info->gpu_speedo_id = 2; + if (always_on) { + sku_info->cpu_speedo_id = 8; + sku_info->ucm = TEGRA_UCM2; + } break; - - case 0x27: + } + /* fall through for a01 */ + fallthrough; + case 0x27: + if (a02) { sku_info->cpu_speedo_id = 1; sku_info->gpu_speedo_id = 2; break; - - case 0x83: + } + sku_info->gpu_speedo_id = 1; + break; + case 0x57: + sku_info->cpu_speedo_id = 4; + sku_info->soc_speedo_id = 1; + sku_info->gpu_speedo_id = 4; + *threshold = THRESHOLD_INDEX_1; + break; + case 0x83: + if (a02) { sku_info->cpu_speedo_id = 3; sku_info->gpu_speedo_id = 3; break; - - case 0x87: + } + /* fall through for a01 */ + fallthrough; + case 0x87: + if (a02) { sku_info->cpu_speedo_id = 2; sku_info->gpu_speedo_id = 1; break; - - case 0x8F: - sku_info->soc_speedo_id = 2; + } + /* fall through for a01 */ + fallthrough; + case 0x8F: + if (a02 && always_on) { sku_info->cpu_speedo_id = 9; sku_info->gpu_speedo_id = 2; - break; - - default: - pr_err("Tegra210: unknown revision 2 or newer SKU %#04x\n", sku); - /* Using the default for the error case */ + sku_info->ucm = TEGRA_UCM2; break; } - } else if (sku == 0x00 || sku == 0x01 || sku == 0x07 || sku == 0x13 || sku == 0x17) { - sku_info->gpu_speedo_id = 1; - } else { - pr_err("Tegra210: unknown SKU %#04x\n", sku); + fallthrough; + default: + pr_err("Tegra210: invalid combination of SKU/revision/mode:\n"); + pr_err("Tegra210: SKU %#04x, rev %d, vcm31 %d, always_on %d\n", + sku, rev, vcm31_sku, always_on); + /* Using the default for the error case */ + break; } } +static void __init rev_t210b01sku_to_speedo_ids(struct tegra_sku_info *sku_info, + u8 speedo_rev, int *threshold) +{ + int sku = sku_info->sku_id; + int rev = sku_info->revision; + + /* Assign to default */ + sku_info->cpu_speedo_id = 0; + sku_info->soc_speedo_id = 0; + sku_info->gpu_speedo_id = 1; /* T210b01 GPC PLL default NA mode */ + sku_info->ucm = TEGRA_UCM1; + *threshold = THRESHOLD_INDEX_2; + + switch (sku) { + case 0x00: /* Engineering SKU */ + case 0x01: /* Engineering SKU */ + case 0x83: + break; + case 0x87: + sku_info->cpu_speedo_id = 3; + break; + default: + pr_err("Tegra210b01: invalid combination of SKU/revision/mode:\n"); + pr_err("Tegra210b01: SKU %#04x, rev %d\n", sku, rev); + /* Using the default for the error case */ + break; + } +} + +static bool __init is_t210b01_sku(struct tegra_sku_info *sku_info) +{ + u8 chip = tegra_get_chip_id(); + if (chip == TEGRA210 && sku_info->revision == TEGRA_REVISION_B01) + return true; + + return false; +} + +static void __init rev_sku_to_speedo_ids(struct tegra_sku_info *sku_info, + u8 speedo_rev, int *threshold) +{ + if (is_t210b01_sku(sku_info)) + rev_t210b01sku_to_speedo_ids(sku_info, speedo_rev, threshold); + else + rev_t210sku_to_speedo_ids(sku_info, speedo_rev, threshold); +} + static int get_process_id(int value, const u32 *speedos, unsigned int num) { unsigned int i; @@ -129,7 +222,7 @@ void __init tegra210_init_speedo_data(struct tegra_sku_info *sku_info) { int cpu_speedo[3], soc_speedo[3]; unsigned int index; - u8 speedo_revision; + u8 speedo_revision = 0; BUILD_BUG_ON(ARRAY_SIZE(cpu_process_speedos) != THRESHOLD_INDEX_COUNT); @@ -145,27 +238,40 @@ void __init tegra210_init_speedo_data(struct tegra_sku_info *sku_info) soc_speedo[0] = tegra_fuse_read_early(FUSE_SOC_SPEEDO_0); soc_speedo[1] = tegra_fuse_read_early(FUSE_SOC_SPEEDO_1); - soc_speedo[2] = tegra_fuse_read_early(FUSE_SOC_SPEEDO_2); + soc_speedo[2] = tegra_fuse_read_early(FUSE_CPU_SPEEDO_2); + + sku_info->cpu_iddq_value = tegra_fuse_read_early(FUSE_CPU_IDDQ) * 4; + sku_info->soc_iddq_value = tegra_fuse_read_early(FUSE_SOC_IDDQ) * 4; + sku_info->gpu_iddq_value = tegra_fuse_read_early(FUSE_GPU_IDDQ) * 5; /* * Determine CPU, GPU and SoC speedo values depending on speedo fusing * revision. Note that GPU speedo value is fused in CPU_SPEEDO_2. */ speedo_revision = get_speedo_revision(); - pr_info("Speedo Revision %u\n", speedo_revision); + sku_info->speedo_rev = speedo_revision; - if (speedo_revision >= 3) { + if (is_t210b01_sku(sku_info)) { sku_info->cpu_speedo_value = cpu_speedo[0]; sku_info->gpu_speedo_value = cpu_speedo[2]; sku_info->soc_speedo_value = soc_speedo[0]; - } else if (speedo_revision == 2) { - sku_info->cpu_speedo_value = (-1938 + (1095 * cpu_speedo[0] / 100)) / 10; - sku_info->gpu_speedo_value = (-1662 + (1082 * cpu_speedo[2] / 100)) / 10; - sku_info->soc_speedo_value = ( -705 + (1037 * soc_speedo[0] / 100)) / 10; } else { - sku_info->cpu_speedo_value = 2100; - sku_info->gpu_speedo_value = cpu_speedo[2] - 75; - sku_info->soc_speedo_value = 1900; + if (speedo_revision >= 3) { + sku_info->cpu_speedo_value = cpu_speedo[0]; + sku_info->gpu_speedo_value = cpu_speedo[2]; + sku_info->soc_speedo_value = soc_speedo[0]; + } else if (speedo_revision == 2) { + sku_info->cpu_speedo_value = + (-1938 + (1095 * cpu_speedo[0] / 100)) / 10; + sku_info->gpu_speedo_value = + (-1662 + (1082 * cpu_speedo[2] / 100)) / 10; + sku_info->soc_speedo_value = + (-705 + (1037 * soc_speedo[0] / 100)) / 10; + } else { + sku_info->cpu_speedo_value = 2100; + sku_info->gpu_speedo_value = cpu_speedo[2] - 75; + sku_info->soc_speedo_value = 1900; + } } if ((sku_info->cpu_speedo_value <= 0) || @@ -189,6 +295,13 @@ void __init tegra210_init_speedo_data(struct tegra_sku_info *sku_info) soc_process_speedos[index], SOC_PROCESS_CORNERS); - pr_debug("Tegra GPU Speedo ID=%d, Speedo Value=%d\n", - sku_info->gpu_speedo_id, sku_info->gpu_speedo_value); + pr_info("Tegra Speedo/IDDQ fuse revision %u\n", speedo_revision); + pr_info("Tegra: CPU Speedo ID %d, SoC Speedo ID %d, GPU Speedo ID %d\n", + sku_info->cpu_speedo_id, sku_info->soc_speedo_id, sku_info->gpu_speedo_id); + pr_info("Tegra: CPU Process ID %d, SoC Process ID %d, GPU Process ID %d\n", + sku_info->cpu_process_id, sku_info->soc_process_id, sku_info->gpu_process_id); + pr_info("Tegra: CPU Speedo Value %d, SoC Speedo Value %d, GPU Speedo Value %d\n", + sku_info->cpu_speedo_value, sku_info->soc_speedo_value, sku_info->gpu_speedo_value); + pr_info("Tegra: CPU IDDQ Value %d, SoC IDDQ Value %d, GPU IDDQ Value %d\n", + sku_info->cpu_iddq_value, sku_info->soc_iddq_value, sku_info->gpu_iddq_value); } diff --git a/drivers/soc/tegra/fuse/tegra-apbmisc.c b/drivers/soc/tegra/fuse/tegra-apbmisc.c index e2ca5d55fd31..017d7897496e 100644 --- a/drivers/soc/tegra/fuse/tegra-apbmisc.c +++ b/drivers/soc/tegra/fuse/tegra-apbmisc.c @@ -133,30 +133,35 @@ static const struct of_device_id apbmisc_match[] __initconst = { void __init tegra_init_revision(void) { - u8 chip_id, minor_rev; + u8 chip_id, major_rev, minor_rev; chip_id = tegra_get_chip_id(); + major_rev = tegra_get_major_rev(); minor_rev = tegra_get_minor_rev(); - switch (minor_rev) { - case 1: - tegra_sku_info.revision = TEGRA_REVISION_A01; - break; - case 2: - tegra_sku_info.revision = TEGRA_REVISION_A02; - break; - case 3: - if (chip_id == TEGRA20 && (tegra_fuse_read_spare(18) || - tegra_fuse_read_spare(19))) - tegra_sku_info.revision = TEGRA_REVISION_A03p; - else - tegra_sku_info.revision = TEGRA_REVISION_A03; - break; - case 4: - tegra_sku_info.revision = TEGRA_REVISION_A04; - break; - default: - tegra_sku_info.revision = TEGRA_REVISION_UNKNOWN; + if (major_rev > 1) { + tegra_sku_info.revision = TEGRA_REVISION_B01; + } else { + switch (minor_rev) { + case 1: + tegra_sku_info.revision = TEGRA_REVISION_A01; + break; + case 2: + tegra_sku_info.revision = TEGRA_REVISION_A02; + break; + case 3: + if (chip_id == TEGRA20 && (tegra_fuse_read_spare(18) || + tegra_fuse_read_spare(19))) + tegra_sku_info.revision = TEGRA_REVISION_A03p; + else + tegra_sku_info.revision = TEGRA_REVISION_A03; + break; + case 4: + tegra_sku_info.revision = TEGRA_REVISION_A04; + break; + default: + tegra_sku_info.revision = TEGRA_REVISION_UNKNOWN; + } } tegra_sku_info.sku_id = tegra_fuse_read_early(FUSE_SKU_INFO); diff --git a/include/soc/tegra/fuse.h b/include/soc/tegra/fuse.h index 8f421b9f7585..41bffb990f9b 100644 --- a/include/soc/tegra/fuse.h +++ b/include/soc/tegra/fuse.h @@ -33,6 +33,7 @@ enum tegra_revision { TEGRA_REVISION_A03, TEGRA_REVISION_A03p, TEGRA_REVISION_A04, + TEGRA_REVISION_B01, TEGRA_REVISION_MAX, }; @@ -50,6 +51,11 @@ enum tegra_platform { TEGRA_PLATFORM_MAX, }; +enum tegra_ucm { + TEGRA_UCM1 = 0, + TEGRA_UCM2, +}; + struct tegra_sku_info { int sku_id; int cpu_process_id; @@ -59,11 +65,17 @@ struct tegra_sku_info { int soc_process_id; int soc_speedo_id; int soc_speedo_value; + int soc_iddq_value; int gpu_process_id; int gpu_speedo_id; int gpu_speedo_value; + int gpu_iddq_value; enum tegra_revision revision; enum tegra_platform platform; + + enum tegra_ucm ucm; + + int speedo_rev; }; #ifdef CONFIG_ARCH_TEGRA @@ -71,6 +83,9 @@ extern struct tegra_sku_info tegra_sku_info; u32 tegra_read_straps(void); u32 tegra_read_ram_code(void); int tegra_fuse_readl(unsigned long offset, u32 *value); +int tegra_fuse_get_cpu_iddq(void); +int tegra_fuse_get_gpu_iddq(void); +int tegra_fuse_get_soc_iddq(void); u32 tegra_read_chipid(void); u8 tegra_get_chip_id(void); u8 tegra_get_platform(void); @@ -94,6 +109,21 @@ static inline int tegra_fuse_readl(unsigned long offset, u32 *value) return -ENODEV; } +static inline int tegra_fuse_get_cpu_iddq(void) +{ + return -ENODEV; +} + +static inline int tegra_fuse_get_gpu_iddq(void) +{ + return -ENODEV; +} + +static inline int tegra_fuse_get_soc_iddq(void) +{ + return -ENODEV; +} + static inline u32 tegra_read_chipid(void) { return 0;