From 306a7f9139318a28063282a15b9f9ebacf09c9b9 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Thu, 17 Jul 2014 13:17:24 +0200 Subject: ARM: tegra: Move includes to include/soc/tegra In order to not clutter the include/linux directory with SoC specific headers, move the Tegra-specific headers out into a separate directory. Signed-off-by: Thierry Reding --- arch/arm/mach-tegra/fuse.c | 3 ++- arch/arm/mach-tegra/pmc.c | 3 ++- arch/arm/mach-tegra/powergate.c | 3 ++- 3 files changed, 6 insertions(+), 3 deletions(-) (limited to 'arch/arm/mach-tegra') diff --git a/arch/arm/mach-tegra/fuse.c b/arch/arm/mach-tegra/fuse.c index c9ac23b385b..930fef86122 100644 --- a/arch/arm/mach-tegra/fuse.c +++ b/arch/arm/mach-tegra/fuse.c @@ -23,7 +23,8 @@ #include #include #include -#include + +#include #include "fuse.h" #include "iomap.h" diff --git a/arch/arm/mach-tegra/pmc.c b/arch/arm/mach-tegra/pmc.c index 7c7123e7557..0f457801eac 100644 --- a/arch/arm/mach-tegra/pmc.c +++ b/arch/arm/mach-tegra/pmc.c @@ -20,7 +20,8 @@ #include #include #include -#include + +#include #include "flowctrl.h" #include "fuse.h" diff --git a/arch/arm/mach-tegra/powergate.c b/arch/arm/mach-tegra/powergate.c index 4cefc5cd6be..7b148bc6c99 100644 --- a/arch/arm/mach-tegra/powergate.c +++ b/arch/arm/mach-tegra/powergate.c @@ -29,7 +29,8 @@ #include #include #include -#include + +#include #include "fuse.h" #include "iomap.h" -- cgit v1.2.3-70-g09d2 From a0524acc94c91c72c2968a76eddc6f3afe82f9f2 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Fri, 11 Jul 2014 09:44:49 +0200 Subject: ARM: tegra: Sort includes alphabetically If these aren't sorted alphabetically, then the logical choice is to append new ones, however that creates a lot of potential for conflicts because every change will then add new includes in the same location. Signed-off-by: Thierry Reding --- arch/arm/mach-tegra/apbio.c | 12 ++++++------ arch/arm/mach-tegra/board-paz00.c | 3 ++- arch/arm/mach-tegra/cpuidle-tegra114.c | 10 +++++----- arch/arm/mach-tegra/cpuidle-tegra20.c | 16 ++++++++-------- arch/arm/mach-tegra/cpuidle-tegra30.c | 10 +++++----- arch/arm/mach-tegra/flowctrl.c | 4 ++-- arch/arm/mach-tegra/fuse.c | 8 ++++---- arch/arm/mach-tegra/hotplug.c | 3 ++- arch/arm/mach-tegra/io.c | 8 ++++---- arch/arm/mach-tegra/irq.c | 8 ++++---- arch/arm/mach-tegra/platsmp.c | 20 ++++++++++---------- arch/arm/mach-tegra/pm-tegra20.c | 1 + arch/arm/mach-tegra/pm-tegra30.c | 1 + arch/arm/mach-tegra/pm.c | 22 +++++++++++----------- arch/arm/mach-tegra/pmc.c | 2 +- arch/arm/mach-tegra/powergate.c | 4 ++-- arch/arm/mach-tegra/reset-handler.S | 4 ++-- arch/arm/mach-tegra/reset.c | 8 ++++---- arch/arm/mach-tegra/sleep-tegra30.S | 6 +++--- arch/arm/mach-tegra/tegra.c | 18 +++++++++--------- arch/arm/mach-tegra/tegra114_speedo.c | 2 +- arch/arm/mach-tegra/tegra20_speedo.c | 2 +- arch/arm/mach-tegra/tegra30_speedo.c | 2 +- 23 files changed, 89 insertions(+), 85 deletions(-) (limited to 'arch/arm/mach-tegra') diff --git a/arch/arm/mach-tegra/apbio.c b/arch/arm/mach-tegra/apbio.c index bc471973cf0..5f9647b3f81 100644 --- a/arch/arm/mach-tegra/apbio.c +++ b/arch/arm/mach-tegra/apbio.c @@ -13,15 +13,15 @@ * */ -#include -#include -#include +#include #include #include -#include -#include -#include +#include +#include #include +#include +#include +#include #include "apbio.h" #include "iomap.h" diff --git a/arch/arm/mach-tegra/board-paz00.c b/arch/arm/mach-tegra/board-paz00.c index 9c6029ba526..bb4782a3271 100644 --- a/arch/arm/mach-tegra/board-paz00.c +++ b/arch/arm/mach-tegra/board-paz00.c @@ -17,9 +17,10 @@ * */ -#include #include +#include #include + #include "board.h" static struct rfkill_gpio_platform_data wifi_rfkill_platform_data = { diff --git a/arch/arm/mach-tegra/cpuidle-tegra114.c b/arch/arm/mach-tegra/cpuidle-tegra114.c index b5fb7c110c6..e3ebdce3e71 100644 --- a/arch/arm/mach-tegra/cpuidle-tegra114.c +++ b/arch/arm/mach-tegra/cpuidle-tegra114.c @@ -14,16 +14,16 @@ * along with this program. If not, see . */ -#include -#include +#include +#include #include #include -#include -#include +#include +#include #include -#include #include +#include #include "pm.h" #include "sleep.h" diff --git a/arch/arm/mach-tegra/cpuidle-tegra20.c b/arch/arm/mach-tegra/cpuidle-tegra20.c index b82dcaee2ef..b30bf5cba65 100644 --- a/arch/arm/mach-tegra/cpuidle-tegra20.c +++ b/arch/arm/mach-tegra/cpuidle-tegra20.c @@ -19,23 +19,23 @@ * more details. */ -#include -#include +#include +#include #include #include -#include -#include +#include +#include #include #include -#include #include +#include -#include "pm.h" -#include "sleep.h" +#include "flowctrl.h" #include "iomap.h" #include "irq.h" -#include "flowctrl.h" +#include "pm.h" +#include "sleep.h" #ifdef CONFIG_PM_SLEEP static bool abort_flag; diff --git a/arch/arm/mach-tegra/cpuidle-tegra30.c b/arch/arm/mach-tegra/cpuidle-tegra30.c index ed2a2a7bae4..35561274f6c 100644 --- a/arch/arm/mach-tegra/cpuidle-tegra30.c +++ b/arch/arm/mach-tegra/cpuidle-tegra30.c @@ -19,17 +19,17 @@ * more details. */ -#include -#include +#include +#include #include #include -#include -#include +#include +#include #include #include -#include #include +#include #include "pm.h" #include "sleep.h" diff --git a/arch/arm/mach-tegra/flowctrl.c b/arch/arm/mach-tegra/flowctrl.c index ce8ab8abf06..fde581d7839 100644 --- a/arch/arm/mach-tegra/flowctrl.c +++ b/arch/arm/mach-tegra/flowctrl.c @@ -18,10 +18,10 @@ * along with this program. If not, see . */ +#include #include -#include #include -#include +#include #include "flowctrl.h" #include "iomap.h" diff --git a/arch/arm/mach-tegra/fuse.c b/arch/arm/mach-tegra/fuse.c index 930fef86122..af283039e37 100644 --- a/arch/arm/mach-tegra/fuse.c +++ b/arch/arm/mach-tegra/fuse.c @@ -18,17 +18,17 @@ * */ -#include -#include +#include #include +#include +#include #include -#include #include +#include "apbio.h" #include "fuse.h" #include "iomap.h" -#include "apbio.h" /* Tegra20 only */ #define FUSE_UID_LOW 0x108 diff --git a/arch/arm/mach-tegra/hotplug.c b/arch/arm/mach-tegra/hotplug.c index ff26af26bd0..7842b252dda 100644 --- a/arch/arm/mach-tegra/hotplug.c +++ b/arch/arm/mach-tegra/hotplug.c @@ -7,9 +7,10 @@ * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ + +#include #include #include -#include #include diff --git a/arch/arm/mach-tegra/io.c b/arch/arm/mach-tegra/io.c index bb9c9c29d18..352de159d2c 100644 --- a/arch/arm/mach-tegra/io.c +++ b/arch/arm/mach-tegra/io.c @@ -18,14 +18,14 @@ * */ -#include -#include #include -#include #include +#include +#include +#include -#include #include +#include #include "board.h" #include "iomap.h" diff --git a/arch/arm/mach-tegra/irq.c b/arch/arm/mach-tegra/irq.c index 1a74d562dca..da7be13aecc 100644 --- a/arch/arm/mach-tegra/irq.c +++ b/arch/arm/mach-tegra/irq.c @@ -17,14 +17,14 @@ * */ -#include #include #include -#include #include -#include -#include #include +#include +#include +#include +#include #include #include "board.h" diff --git a/arch/arm/mach-tegra/platsmp.c b/arch/arm/mach-tegra/platsmp.c index 929d1046e2b..c403edd0fcc 100644 --- a/arch/arm/mach-tegra/platsmp.c +++ b/arch/arm/mach-tegra/platsmp.c @@ -11,27 +11,27 @@ * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ -#include -#include + +#include #include #include +#include +#include +#include #include #include -#include -#include #include #include -#include #include - -#include "fuse.h" -#include "flowctrl.h" -#include "reset.h" -#include "pmc.h" +#include #include "common.h" +#include "flowctrl.h" +#include "fuse.h" #include "iomap.h" +#include "pmc.h" +#include "reset.h" static cpumask_t tegra_cpu_init_mask; diff --git a/arch/arm/mach-tegra/pm-tegra20.c b/arch/arm/mach-tegra/pm-tegra20.c index d65e1d78640..39ac2b723f2 100644 --- a/arch/arm/mach-tegra/pm-tegra20.c +++ b/arch/arm/mach-tegra/pm-tegra20.c @@ -13,6 +13,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ + #include #include "pm.h" diff --git a/arch/arm/mach-tegra/pm-tegra30.c b/arch/arm/mach-tegra/pm-tegra30.c index 8fa326d6ff1..46cc19de991 100644 --- a/arch/arm/mach-tegra/pm-tegra30.c +++ b/arch/arm/mach-tegra/pm-tegra30.c @@ -13,6 +13,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ + #include #include "pm.h" diff --git a/arch/arm/mach-tegra/pm.c b/arch/arm/mach-tegra/pm.c index f55b05a29b5..ae4826e4317 100644 --- a/arch/arm/mach-tegra/pm.c +++ b/arch/arm/mach-tegra/pm.c @@ -16,30 +16,30 @@ * along with this program. If not, see . */ -#include -#include -#include +#include #include -#include #include -#include +#include #include +#include +#include #include -#include +#include +#include -#include #include -#include #include #include +#include +#include #include -#include "iomap.h" -#include "reset.h" #include "flowctrl.h" #include "fuse.h" -#include "pm.h" +#include "iomap.h" #include "pmc.h" +#include "pm.h" +#include "reset.h" #include "sleep.h" #ifdef CONFIG_PM_SLEEP diff --git a/arch/arm/mach-tegra/pmc.c b/arch/arm/mach-tegra/pmc.c index 0f457801eac..a602f6c76b1 100644 --- a/arch/arm/mach-tegra/pmc.c +++ b/arch/arm/mach-tegra/pmc.c @@ -15,9 +15,9 @@ * */ -#include #include #include +#include #include #include diff --git a/arch/arm/mach-tegra/powergate.c b/arch/arm/mach-tegra/powergate.c index 7b148bc6c99..c12044de629 100644 --- a/arch/arm/mach-tegra/powergate.c +++ b/arch/arm/mach-tegra/powergate.c @@ -17,18 +17,18 @@ * */ -#include #include +#include #include #include #include #include #include #include +#include #include #include #include -#include #include diff --git a/arch/arm/mach-tegra/reset-handler.S b/arch/arm/mach-tegra/reset-handler.S index 578d4d1ad64..d916c84487a 100644 --- a/arch/arm/mach-tegra/reset-handler.S +++ b/arch/arm/mach-tegra/reset-handler.S @@ -14,11 +14,11 @@ * along with this program. If not, see . */ -#include #include +#include -#include #include +#include #include "flowctrl.h" #include "fuse.h" diff --git a/arch/arm/mach-tegra/reset.c b/arch/arm/mach-tegra/reset.c index 146fe8e0ae7..b90507922a8 100644 --- a/arch/arm/mach-tegra/reset.c +++ b/arch/arm/mach-tegra/reset.c @@ -14,20 +14,20 @@ * */ +#include +#include #include #include -#include -#include #include -#include #include +#include +#include "fuse.h" #include "iomap.h" #include "irammap.h" #include "reset.h" #include "sleep.h" -#include "fuse.h" #define TEGRA_IRAM_RESET_BASE (TEGRA_IRAM_BASE + \ TEGRA_IRAM_RESET_HANDLER_OFFSET) diff --git a/arch/arm/mach-tegra/sleep-tegra30.S b/arch/arm/mach-tegra/sleep-tegra30.S index b16d4a57fa5..e240b875183 100644 --- a/arch/arm/mach-tegra/sleep-tegra30.S +++ b/arch/arm/mach-tegra/sleep-tegra30.S @@ -16,14 +16,14 @@ #include -#include #include +#include #include -#include "irammap.h" +#include "flowctrl.h" #include "fuse.h" +#include "irammap.h" #include "sleep.h" -#include "flowctrl.h" #define EMC_CFG 0xc #define EMC_ADR_CFG 0x10 diff --git a/arch/arm/mach-tegra/tegra.c b/arch/arm/mach-tegra/tegra.c index 15ac9fcc96b..7a9f3028904 100644 --- a/arch/arm/mach-tegra/tegra.c +++ b/arch/arm/mach-tegra/tegra.c @@ -16,29 +16,29 @@ * */ -#include -#include -#include -#include #include +#include #include +#include +#include +#include #include -#include +#include #include #include +#include #include #include -#include +#include +#include #include #include #include -#include -#include #include -#include #include #include +#include #include #include diff --git a/arch/arm/mach-tegra/tegra114_speedo.c b/arch/arm/mach-tegra/tegra114_speedo.c index 5218d4853cd..86eca17e528 100644 --- a/arch/arm/mach-tegra/tegra114_speedo.c +++ b/arch/arm/mach-tegra/tegra114_speedo.c @@ -14,8 +14,8 @@ * along with this program. If not, see . */ -#include #include +#include #include "fuse.h" diff --git a/arch/arm/mach-tegra/tegra20_speedo.c b/arch/arm/mach-tegra/tegra20_speedo.c index fa6eb570623..dcd29a0b018 100644 --- a/arch/arm/mach-tegra/tegra20_speedo.c +++ b/arch/arm/mach-tegra/tegra20_speedo.c @@ -14,8 +14,8 @@ * along with this program. If not, see . */ -#include #include +#include #include "fuse.h" diff --git a/arch/arm/mach-tegra/tegra30_speedo.c b/arch/arm/mach-tegra/tegra30_speedo.c index 125cb16424a..7c0038326cf 100644 --- a/arch/arm/mach-tegra/tegra30_speedo.c +++ b/arch/arm/mach-tegra/tegra30_speedo.c @@ -14,8 +14,8 @@ * along with this program. If not, see . */ -#include #include +#include #include "fuse.h" -- cgit v1.2.3-70-g09d2 From 304664eab93f9e95a8d28fbd9702ede88bb10cc5 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Fri, 11 Jul 2014 09:52:41 +0200 Subject: ARM: tegra: Use a function to get the chip ID Instead of using a simple variable access to get at the Tegra chip ID, use a function so that we can run additional code. This can be used to determine where the chip ID is being accessed without being available. That in turn will be handy for resolving boot sequence dependencies in order to convert more code to regular initcalls rather than a sequence fixed by Tegra SoC setup code. Signed-off-by: Thierry Reding --- arch/arm/mach-tegra/cpuidle.c | 7 ++++--- arch/arm/mach-tegra/flowctrl.c | 7 ++++--- arch/arm/mach-tegra/fuse.c | 19 +++++++++++++------ arch/arm/mach-tegra/fuse.h | 6 ------ arch/arm/mach-tegra/hotplug.c | 11 ++++++----- arch/arm/mach-tegra/platsmp.c | 11 ++++++----- arch/arm/mach-tegra/pm.c | 11 ++++++----- arch/arm/mach-tegra/pmc.c | 4 ++-- arch/arm/mach-tegra/powergate.c | 8 ++++---- arch/arm/mach-tegra/reset-handler.S | 3 ++- arch/arm/mach-tegra/reset.c | 4 +++- arch/arm/mach-tegra/sleep-tegra30.S | 3 ++- arch/arm/mach-tegra/tegra.c | 4 +++- include/soc/tegra/fuse.h | 10 ++++++++++ 14 files changed, 65 insertions(+), 43 deletions(-) (limited to 'arch/arm/mach-tegra') diff --git a/arch/arm/mach-tegra/cpuidle.c b/arch/arm/mach-tegra/cpuidle.c index 7bc5d8d667f..316563141ad 100644 --- a/arch/arm/mach-tegra/cpuidle.c +++ b/arch/arm/mach-tegra/cpuidle.c @@ -24,12 +24,13 @@ #include #include -#include "fuse.h" +#include + #include "cpuidle.h" void __init tegra_cpuidle_init(void) { - switch (tegra_chip_id) { + switch (tegra_get_chip_id()) { case TEGRA20: if (IS_ENABLED(CONFIG_ARCH_TEGRA_2x_SOC)) tegra20_cpuidle_init(); @@ -49,7 +50,7 @@ void __init tegra_cpuidle_init(void) void tegra_cpuidle_pcie_irqs_in_use(void) { - switch (tegra_chip_id) { + switch (tegra_get_chip_id()) { case TEGRA20: if (IS_ENABLED(CONFIG_ARCH_TEGRA_2x_SOC)) tegra20_cpuidle_pcie_irqs_in_use(); diff --git a/arch/arm/mach-tegra/flowctrl.c b/arch/arm/mach-tegra/flowctrl.c index fde581d7839..ec55d1de1b5 100644 --- a/arch/arm/mach-tegra/flowctrl.c +++ b/arch/arm/mach-tegra/flowctrl.c @@ -23,9 +23,10 @@ #include #include +#include + #include "flowctrl.h" #include "iomap.h" -#include "fuse.h" static u8 flowctrl_offset_halt_cpu[] = { FLOW_CTRL_HALT_CPU0_EVENTS, @@ -76,7 +77,7 @@ void flowctrl_cpu_suspend_enter(unsigned int cpuid) int i; reg = flowctrl_read_cpu_csr(cpuid); - switch (tegra_chip_id) { + switch (tegra_get_chip_id()) { case TEGRA20: /* clear wfe bitmap */ reg &= ~TEGRA20_FLOW_CTRL_CSR_WFE_BITMAP; @@ -117,7 +118,7 @@ void flowctrl_cpu_suspend_exit(unsigned int cpuid) /* Disable powergating via flow controller for CPU0 */ reg = flowctrl_read_cpu_csr(cpuid); - switch (tegra_chip_id) { + switch (tegra_get_chip_id()) { case TEGRA20: /* clear wfe bitmap */ reg &= ~TEGRA20_FLOW_CTRL_CSR_WFE_BITMAP; diff --git a/arch/arm/mach-tegra/fuse.c b/arch/arm/mach-tegra/fuse.c index af283039e37..b22e76a4096 100644 --- a/arch/arm/mach-tegra/fuse.c +++ b/arch/arm/mach-tegra/fuse.c @@ -51,7 +51,6 @@ int tegra_sku_id; int tegra_cpu_process_id; int tegra_core_process_id; -int tegra_chip_id; int tegra_cpu_speedo_id; /* only exist in Tegra30 and later */ int tegra_soc_speedo_id; enum tegra_revision tegra_revision; @@ -124,7 +123,7 @@ static enum tegra_revision tegra_get_revision(u32 id) case 2: return TEGRA_REVISION_A02; case 3: - if (tegra_chip_id == TEGRA20 && + if (tegra_get_chip_id() == TEGRA20 && (tegra_spare_fuse(18) || tegra_spare_fuse(19))) return TEGRA_REVISION_A03p; else @@ -155,6 +154,13 @@ u32 tegra_read_chipid(void) return readl_relaxed(IO_ADDRESS(TEGRA_APB_MISC_BASE) + 0x804); } +u8 tegra_get_chip_id(void) +{ + u32 id = tegra_read_chipid(); + + return (id >> 8) & 0xff; +} + static void __init tegra20_fuse_init_randomness(void) { u32 randomness[2]; @@ -185,6 +191,7 @@ void __init tegra_init_fuse(void) { u32 id; u32 randomness[5]; + u8 chip_id; u32 reg = readl(IO_ADDRESS(TEGRA_CLK_RESET_BASE + 0x48)); reg |= 1 << 28; @@ -209,9 +216,9 @@ void __init tegra_init_fuse(void) id = tegra_read_chipid(); randomness[2] = id; - tegra_chip_id = (id >> 8) & 0xff; + chip_id = (id >> 8) & 0xff; - switch (tegra_chip_id) { + switch (chip_id) { case TEGRA20: tegra_fuse_spare_bit = TEGRA20_FUSE_SPARE_BIT; tegra_init_speedo_data = &tegra20_init_speedo_data; @@ -224,7 +231,7 @@ void __init tegra_init_fuse(void) tegra_init_speedo_data = &tegra114_init_speedo_data; break; default: - pr_warn("Tegra: unknown chip id %d\n", tegra_chip_id); + pr_warn("Tegra: unknown chip id %d\n", chip_id); tegra_fuse_spare_bit = TEGRA20_FUSE_SPARE_BIT; tegra_init_speedo_data = &tegra_get_process_id; } @@ -235,7 +242,7 @@ void __init tegra_init_fuse(void) randomness[4] = (tegra_cpu_speedo_id << 16) | tegra_soc_speedo_id; add_device_randomness(randomness, sizeof(randomness)); - switch (tegra_chip_id) { + switch (chip_id) { case TEGRA20: tegra20_fuse_init_randomness(); break; diff --git a/arch/arm/mach-tegra/fuse.h b/arch/arm/mach-tegra/fuse.h index c01d04785d6..7a08b4b70c8 100644 --- a/arch/arm/mach-tegra/fuse.h +++ b/arch/arm/mach-tegra/fuse.h @@ -26,11 +26,6 @@ #define SKU_ID_AP25E 27 #define SKU_ID_T25E 28 -#define TEGRA20 0x20 -#define TEGRA30 0x30 -#define TEGRA114 0x35 -#define TEGRA124 0x40 - #ifndef __ASSEMBLY__ enum tegra_revision { TEGRA_REVISION_UNKNOWN = 0, @@ -45,7 +40,6 @@ enum tegra_revision { extern int tegra_sku_id; extern int tegra_cpu_process_id; extern int tegra_core_process_id; -extern int tegra_chip_id; extern int tegra_cpu_speedo_id; /* only exist in Tegra30 and later */ extern int tegra_soc_speedo_id; extern enum tegra_revision tegra_revision; diff --git a/arch/arm/mach-tegra/hotplug.c b/arch/arm/mach-tegra/hotplug.c index 7842b252dda..d60339c996c 100644 --- a/arch/arm/mach-tegra/hotplug.c +++ b/arch/arm/mach-tegra/hotplug.c @@ -12,9 +12,10 @@ #include #include +#include + #include -#include "fuse.h" #include "sleep.h" static void (*tegra_hotplug_shutdown)(void); @@ -52,12 +53,12 @@ void __init tegra_hotplug_init(void) if (!IS_ENABLED(CONFIG_HOTPLUG_CPU)) return; - if (IS_ENABLED(CONFIG_ARCH_TEGRA_2x_SOC) && tegra_chip_id == TEGRA20) + if (IS_ENABLED(CONFIG_ARCH_TEGRA_2x_SOC) && tegra_get_chip_id() == TEGRA20) tegra_hotplug_shutdown = tegra20_hotplug_shutdown; - if (IS_ENABLED(CONFIG_ARCH_TEGRA_3x_SOC) && tegra_chip_id == TEGRA30) + if (IS_ENABLED(CONFIG_ARCH_TEGRA_3x_SOC) && tegra_get_chip_id() == TEGRA30) tegra_hotplug_shutdown = tegra30_hotplug_shutdown; - if (IS_ENABLED(CONFIG_ARCH_TEGRA_114_SOC) && tegra_chip_id == TEGRA114) + if (IS_ENABLED(CONFIG_ARCH_TEGRA_114_SOC) && tegra_get_chip_id() == TEGRA114) tegra_hotplug_shutdown = tegra30_hotplug_shutdown; - if (IS_ENABLED(CONFIG_ARCH_TEGRA_124_SOC) && tegra_chip_id == TEGRA124) + if (IS_ENABLED(CONFIG_ARCH_TEGRA_124_SOC) && tegra_get_chip_id() == TEGRA124) tegra_hotplug_shutdown = tegra30_hotplug_shutdown; } diff --git a/arch/arm/mach-tegra/platsmp.c b/arch/arm/mach-tegra/platsmp.c index c403edd0fcc..0466a145b50 100644 --- a/arch/arm/mach-tegra/platsmp.c +++ b/arch/arm/mach-tegra/platsmp.c @@ -21,6 +21,8 @@ #include #include +#include + #include #include #include @@ -28,7 +30,6 @@ #include "common.h" #include "flowctrl.h" -#include "fuse.h" #include "iomap.h" #include "pmc.h" #include "reset.h" @@ -170,13 +171,13 @@ static int tegra114_boot_secondary(unsigned int cpu, struct task_struct *idle) static int tegra_boot_secondary(unsigned int cpu, struct task_struct *idle) { - if (IS_ENABLED(CONFIG_ARCH_TEGRA_2x_SOC) && tegra_chip_id == TEGRA20) + if (IS_ENABLED(CONFIG_ARCH_TEGRA_2x_SOC) && tegra_get_chip_id() == TEGRA20) return tegra20_boot_secondary(cpu, idle); - if (IS_ENABLED(CONFIG_ARCH_TEGRA_3x_SOC) && tegra_chip_id == TEGRA30) + if (IS_ENABLED(CONFIG_ARCH_TEGRA_3x_SOC) && tegra_get_chip_id() == TEGRA30) return tegra30_boot_secondary(cpu, idle); - if (IS_ENABLED(CONFIG_ARCH_TEGRA_114_SOC) && tegra_chip_id == TEGRA114) + if (IS_ENABLED(CONFIG_ARCH_TEGRA_114_SOC) && tegra_get_chip_id() == TEGRA114) return tegra114_boot_secondary(cpu, idle); - if (IS_ENABLED(CONFIG_ARCH_TEGRA_124_SOC) && tegra_chip_id == TEGRA124) + if (IS_ENABLED(CONFIG_ARCH_TEGRA_124_SOC) && tegra_get_chip_id() == TEGRA124) return tegra114_boot_secondary(cpu, idle); return -EINVAL; diff --git a/arch/arm/mach-tegra/pm.c b/arch/arm/mach-tegra/pm.c index ae4826e4317..94db3b6664d 100644 --- a/arch/arm/mach-tegra/pm.c +++ b/arch/arm/mach-tegra/pm.c @@ -27,6 +27,8 @@ #include #include +#include + #include #include #include @@ -35,7 +37,6 @@ #include #include "flowctrl.h" -#include "fuse.h" #include "iomap.h" #include "pmc.h" #include "pm.h" @@ -53,7 +54,7 @@ static int (*tegra_sleep_func)(unsigned long v2p); static void tegra_tear_down_cpu_init(void) { - switch (tegra_chip_id) { + switch (tegra_get_chip_id()) { case TEGRA20: if (IS_ENABLED(CONFIG_ARCH_TEGRA_2x_SOC)) tegra_tear_down_cpu = tegra20_tear_down_cpu; @@ -143,7 +144,7 @@ bool tegra_set_cpu_in_lp2(void) if ((phy_cpu_id == 0) && cpumask_equal(cpu_lp2_mask, cpu_online_mask)) last_cpu = true; - else if (tegra_chip_id == TEGRA20 && phy_cpu_id == 1) + else if (tegra_get_chip_id() == TEGRA20 && phy_cpu_id == 1) tegra20_cpu_set_resettable_soon(); spin_unlock(&tegra_lp2_lock); @@ -212,7 +213,7 @@ static int tegra_sleep_core(unsigned long v2p) */ static bool tegra_lp1_iram_hook(void) { - switch (tegra_chip_id) { + switch (tegra_get_chip_id()) { case TEGRA20: if (IS_ENABLED(CONFIG_ARCH_TEGRA_2x_SOC)) tegra20_lp1_iram_hook(); @@ -242,7 +243,7 @@ static bool tegra_lp1_iram_hook(void) static bool tegra_sleep_core_init(void) { - switch (tegra_chip_id) { + switch (tegra_get_chip_id()) { case TEGRA20: if (IS_ENABLED(CONFIG_ARCH_TEGRA_2x_SOC)) tegra20_sleep_core_init(); diff --git a/arch/arm/mach-tegra/pmc.c b/arch/arm/mach-tegra/pmc.c index a602f6c76b1..69df18090c8 100644 --- a/arch/arm/mach-tegra/pmc.c +++ b/arch/arm/mach-tegra/pmc.c @@ -21,10 +21,10 @@ #include #include +#include #include #include "flowctrl.h" -#include "fuse.h" #include "pm.h" #include "pmc.h" #include "sleep.h" @@ -252,7 +252,7 @@ void tegra_pmc_pm_set(enum tegra_suspend_mode mode) reg |= TEGRA_POWER_CPU_PWRREQ_OE; reg &= ~TEGRA_POWER_EFFECT_LP0; - switch (tegra_chip_id) { + switch (tegra_get_chip_id()) { case TEGRA20: case TEGRA30: break; diff --git a/arch/arm/mach-tegra/powergate.c b/arch/arm/mach-tegra/powergate.c index c12044de629..0a14b863843 100644 --- a/arch/arm/mach-tegra/powergate.c +++ b/arch/arm/mach-tegra/powergate.c @@ -30,9 +30,9 @@ #include #include +#include #include -#include "fuse.h" #include "iomap.h" #define DPD_SAMPLE 0x020 @@ -158,7 +158,7 @@ int tegra_powergate_remove_clamping(int id) * The Tegra124 GPU has a separate register (with different semantics) * to remove clamps. */ - if (tegra_chip_id == TEGRA124) { + if (tegra_get_chip_id() == TEGRA124) { if (id == TEGRA_POWERGATE_3D) { pmc_write(0, GPU_RG_CNTRL); return 0; @@ -228,7 +228,7 @@ int tegra_cpu_powergate_id(int cpuid) int __init tegra_powergate_init(void) { - switch (tegra_chip_id) { + switch (tegra_get_chip_id()) { case TEGRA20: tegra_num_powerdomains = 7; break; @@ -369,7 +369,7 @@ int __init tegra_powergate_debugfs_init(void) { struct dentry *d; - switch (tegra_chip_id) { + switch (tegra_get_chip_id()) { case TEGRA20: powergate_name = powergate_name_t20; break; diff --git a/arch/arm/mach-tegra/reset-handler.S b/arch/arm/mach-tegra/reset-handler.S index d916c84487a..7b2baab0f0b 100644 --- a/arch/arm/mach-tegra/reset-handler.S +++ b/arch/arm/mach-tegra/reset-handler.S @@ -17,11 +17,12 @@ #include #include +#include + #include #include #include "flowctrl.h" -#include "fuse.h" #include "iomap.h" #include "reset.h" #include "sleep.h" diff --git a/arch/arm/mach-tegra/reset.c b/arch/arm/mach-tegra/reset.c index b90507922a8..f94fdf89d45 100644 --- a/arch/arm/mach-tegra/reset.c +++ b/arch/arm/mach-tegra/reset.c @@ -19,6 +19,8 @@ #include #include +#include + #include #include #include @@ -53,7 +55,7 @@ static void __init tegra_cpu_reset_handler_set(const u32 reset_address) * Prevent further modifications to the physical reset vector. * NOTE: Has no effect on chips prior to Tegra30. */ - if (tegra_chip_id != TEGRA20) { + if (tegra_get_chip_id() != TEGRA20) { reg = readl(sb_ctrl); reg |= 2; writel(reg, sb_ctrl); diff --git a/arch/arm/mach-tegra/sleep-tegra30.S b/arch/arm/mach-tegra/sleep-tegra30.S index e240b875183..8ea699b8e3c 100644 --- a/arch/arm/mach-tegra/sleep-tegra30.S +++ b/arch/arm/mach-tegra/sleep-tegra30.S @@ -16,12 +16,13 @@ #include +#include + #include #include #include #include "flowctrl.h" -#include "fuse.h" #include "irammap.h" #include "sleep.h" diff --git a/arch/arm/mach-tegra/tegra.c b/arch/arm/mach-tegra/tegra.c index 7a9f3028904..8be25c41249 100644 --- a/arch/arm/mach-tegra/tegra.c +++ b/arch/arm/mach-tegra/tegra.c @@ -35,6 +35,8 @@ #include #include +#include + #include #include #include @@ -104,7 +106,7 @@ static void __init tegra_dt_init(void) soc_dev_attr->family = kasprintf(GFP_KERNEL, "Tegra"); soc_dev_attr->revision = kasprintf(GFP_KERNEL, "%d", tegra_revision); - soc_dev_attr->soc_id = kasprintf(GFP_KERNEL, "%d", tegra_chip_id); + soc_dev_attr->soc_id = kasprintf(GFP_KERNEL, "%u", tegra_get_chip_id()); soc_dev = soc_device_register(soc_dev_attr); if (IS_ERR(soc_dev)) { diff --git a/include/soc/tegra/fuse.h b/include/soc/tegra/fuse.h index 85f555c89ad..0e03f104fbf 100644 --- a/include/soc/tegra/fuse.h +++ b/include/soc/tegra/fuse.h @@ -17,6 +17,16 @@ #ifndef __SOC_TEGRA_FUSE_H__ #define __SOC_TEGRA_FUSE_H__ +#define TEGRA20 0x20 +#define TEGRA30 0x30 +#define TEGRA114 0x35 +#define TEGRA124 0x40 + +#ifndef __ASSEMBLY__ + u32 tegra_read_chipid(void); +u8 tegra_get_chip_id(void); + +#endif /* __ASSEMBLY__ */ #endif /* __SOC_TEGRA_FUSE_H__ */ -- cgit v1.2.3-70-g09d2 From 3f394f80645bf0c38a30042ba605c71663331035 Mon Sep 17 00:00:00 2001 From: Peter De Schrijver Date: Thu, 12 Jun 2014 18:36:35 +0300 Subject: ARM: tegra: export apb dma readl/writel Export APB DMA readl and writel. These are needed because we can't access the fuses directly on Tegra20 without potentially causing a system hang. Also have the APB DMA readl and writel return an error in case of a read failure instead of just returning zero or ignore write failures. Signed-off-by: Peter De Schrijver Signed-off-by: Stephen Warren Signed-off-by: Thierry Reding --- arch/arm/mach-tegra/apbio.c | 51 +++++++++++++++++++++++++++------------------ include/soc/tegra/fuse.h | 14 +++++++++++++ 2 files changed, 45 insertions(+), 20 deletions(-) (limited to 'arch/arm/mach-tegra') diff --git a/arch/arm/mach-tegra/apbio.c b/arch/arm/mach-tegra/apbio.c index 5f9647b3f81..f2488722c79 100644 --- a/arch/arm/mach-tegra/apbio.c +++ b/arch/arm/mach-tegra/apbio.c @@ -32,8 +32,8 @@ static u32 *tegra_apb_bb; static dma_addr_t tegra_apb_bb_phys; static DECLARE_COMPLETION(tegra_apb_wait); -static u32 tegra_apb_readl_direct(unsigned long offset); -static void tegra_apb_writel_direct(u32 value, unsigned long offset); +static int tegra_apb_readl_direct(unsigned long offset, u32 *value); +static int tegra_apb_writel_direct(u32 value, unsigned long offset); static struct dma_chan *tegra_apb_dma_chan; static struct dma_slave_config dma_sconfig; @@ -128,58 +128,64 @@ static int do_dma_transfer(unsigned long apb_add, return 0; } -static u32 tegra_apb_readl_using_dma(unsigned long offset) +int tegra_apb_readl_using_dma(unsigned long offset, u32 *value) { int ret; if (!tegra_apb_dma_chan && !tegra_apb_dma_init()) - return tegra_apb_readl_direct(offset); + return tegra_apb_readl_direct(offset, value); mutex_lock(&tegra_apb_dma_lock); ret = do_dma_transfer(offset, DMA_DEV_TO_MEM); - if (ret < 0) { + if (ret < 0) pr_err("error in reading offset 0x%08lx using dma\n", offset); - *(u32 *)tegra_apb_bb = 0; - } + else + *value = *tegra_apb_bb; + mutex_unlock(&tegra_apb_dma_lock); - return *((u32 *)tegra_apb_bb); + + return ret; } -static void tegra_apb_writel_using_dma(u32 value, unsigned long offset) +int tegra_apb_writel_using_dma(u32 value, unsigned long offset) { int ret; - if (!tegra_apb_dma_chan && !tegra_apb_dma_init()) { - tegra_apb_writel_direct(value, offset); - return; - } + if (!tegra_apb_dma_chan && !tegra_apb_dma_init()) + return tegra_apb_writel_direct(value, offset); mutex_lock(&tegra_apb_dma_lock); *((u32 *)tegra_apb_bb) = value; ret = do_dma_transfer(offset, DMA_MEM_TO_DEV); + mutex_unlock(&tegra_apb_dma_lock); if (ret < 0) pr_err("error in writing offset 0x%08lx using dma\n", offset); - mutex_unlock(&tegra_apb_dma_lock); + + return ret; } #else #define tegra_apb_readl_using_dma tegra_apb_readl_direct #define tegra_apb_writel_using_dma tegra_apb_writel_direct #endif -typedef u32 (*apbio_read_fptr)(unsigned long offset); -typedef void (*apbio_write_fptr)(u32 value, unsigned long offset); +typedef int (*apbio_read_fptr)(unsigned long offset, u32 *value); +typedef int (*apbio_write_fptr)(u32 value, unsigned long offset); static apbio_read_fptr apbio_read; static apbio_write_fptr apbio_write; -static u32 tegra_apb_readl_direct(unsigned long offset) +static int tegra_apb_readl_direct(unsigned long offset, u32 *value) { - return readl(IO_ADDRESS(offset)); + *value = readl(IO_ADDRESS(offset)); + + return 0; } -static void tegra_apb_writel_direct(u32 value, unsigned long offset) +static int tegra_apb_writel_direct(u32 value, unsigned long offset) { writel(value, IO_ADDRESS(offset)); + + return 0; } void tegra_apb_io_init(void) @@ -197,7 +203,12 @@ void tegra_apb_io_init(void) u32 tegra_apb_readl(unsigned long offset) { - return apbio_read(offset); + u32 val; + + if (apbio_read(offset, &val) < 0) + return 0; + else + return val; } void tegra_apb_writel(u32 value, unsigned long offset) diff --git a/include/soc/tegra/fuse.h b/include/soc/tegra/fuse.h index 0e03f104fbf..a43a750dd0a 100644 --- a/include/soc/tegra/fuse.h +++ b/include/soc/tegra/fuse.h @@ -27,6 +27,20 @@ u32 tegra_read_chipid(void); u8 tegra_get_chip_id(void); +#if defined(CONFIG_TEGRA20_APB_DMA) +int tegra_apb_readl_using_dma(unsigned long offset, u32 *value); +int tegra_apb_writel_using_dma(u32 value, unsigned long offset); +#else +static inline int tegra_apb_readl_using_dma(unsigned long offset, u32 *value) +{ + return -EINVAL; +} +static inline int tegra_apb_writel_using_dma(u32 value, unsigned long offset) +{ + return -EINVAL; +} +#endif /* CONFIG_TEGRA20_APB_DMA */ + #endif /* __ASSEMBLY__ */ #endif /* __SOC_TEGRA_FUSE_H__ */ -- cgit v1.2.3-70-g09d2 From 35874f3617b38e0c1f72163407c41d554a8f5939 Mon Sep 17 00:00:00 2001 From: Peter De Schrijver Date: Thu, 12 Jun 2014 18:36:36 +0300 Subject: ARM: tegra: move fuse exports to soc/tegra/fuse.h All fuse related functionality will move to a driver in the following patches. To prepare for this, export all the required functionality in a global header file and move all users of fuse.h to soc/tegra/fuse.h. While we're at it, remove tegra_bct_strapping, as its only user was removed in Commit a7cbe92cef27 ("ARM: tegra: remove tegra EMC scaling driver"). Signed-off-by: Peter De Schrijver Signed-off-by: Stephen Warren Signed-off-by: Thierry Reding --- arch/arm/mach-tegra/fuse.h | 13 ------------- arch/arm/mach-tegra/tegra.c | 1 - arch/arm/mach-tegra/tegra114_speedo.c | 2 ++ arch/arm/mach-tegra/tegra20_speedo.c | 2 ++ arch/arm/mach-tegra/tegra30_speedo.c | 2 ++ include/soc/tegra/fuse.h | 16 ++++++++++++++++ 6 files changed, 22 insertions(+), 14 deletions(-) (limited to 'arch/arm/mach-tegra') diff --git a/arch/arm/mach-tegra/fuse.h b/arch/arm/mach-tegra/fuse.h index 7a08b4b70c8..48a48861c19 100644 --- a/arch/arm/mach-tegra/fuse.h +++ b/arch/arm/mach-tegra/fuse.h @@ -27,27 +27,14 @@ #define SKU_ID_T25E 28 #ifndef __ASSEMBLY__ -enum tegra_revision { - TEGRA_REVISION_UNKNOWN = 0, - TEGRA_REVISION_A01, - TEGRA_REVISION_A02, - TEGRA_REVISION_A03, - TEGRA_REVISION_A03p, - TEGRA_REVISION_A04, - TEGRA_REVISION_MAX, -}; extern int tegra_sku_id; extern int tegra_cpu_process_id; extern int tegra_core_process_id; extern int tegra_cpu_speedo_id; /* only exist in Tegra30 and later */ extern int tegra_soc_speedo_id; -extern enum tegra_revision tegra_revision; - -extern int tegra_bct_strapping; unsigned long long tegra_chip_uid(void); -void tegra_init_fuse(void); bool tegra_spare_fuse(int bit); u32 tegra_fuse_readl(unsigned long offset); diff --git a/arch/arm/mach-tegra/tegra.c b/arch/arm/mach-tegra/tegra.c index 8be25c41249..a359931c595 100644 --- a/arch/arm/mach-tegra/tegra.c +++ b/arch/arm/mach-tegra/tegra.c @@ -48,7 +48,6 @@ #include "board.h" #include "common.h" #include "cpuidle.h" -#include "fuse.h" #include "iomap.h" #include "irq.h" #include "pmc.h" diff --git a/arch/arm/mach-tegra/tegra114_speedo.c b/arch/arm/mach-tegra/tegra114_speedo.c index 86eca17e528..d0a6d5925f5 100644 --- a/arch/arm/mach-tegra/tegra114_speedo.c +++ b/arch/arm/mach-tegra/tegra114_speedo.c @@ -17,6 +17,8 @@ #include #include +#include + #include "fuse.h" #define CORE_PROCESS_CORNERS_NUM 2 diff --git a/arch/arm/mach-tegra/tegra20_speedo.c b/arch/arm/mach-tegra/tegra20_speedo.c index dcd29a0b018..2907cf8de2b 100644 --- a/arch/arm/mach-tegra/tegra20_speedo.c +++ b/arch/arm/mach-tegra/tegra20_speedo.c @@ -17,6 +17,8 @@ #include #include +#include + #include "fuse.h" #define CPU_SPEEDO_LSBIT 20 diff --git a/arch/arm/mach-tegra/tegra30_speedo.c b/arch/arm/mach-tegra/tegra30_speedo.c index 7c0038326cf..6f6102cd1e6 100644 --- a/arch/arm/mach-tegra/tegra30_speedo.c +++ b/arch/arm/mach-tegra/tegra30_speedo.c @@ -17,6 +17,8 @@ #include #include +#include + #include "fuse.h" #define CORE_PROCESS_CORNERS_NUM 1 diff --git a/include/soc/tegra/fuse.h b/include/soc/tegra/fuse.h index a43a750dd0a..822eb348e10 100644 --- a/include/soc/tegra/fuse.h +++ b/include/soc/tegra/fuse.h @@ -27,6 +27,22 @@ u32 tegra_read_chipid(void); u8 tegra_get_chip_id(void); +enum tegra_revision { + TEGRA_REVISION_UNKNOWN = 0, + TEGRA_REVISION_A01, + TEGRA_REVISION_A02, + TEGRA_REVISION_A03, + TEGRA_REVISION_A03p, + TEGRA_REVISION_A04, + TEGRA_REVISION_MAX, +}; + +u32 tegra_read_straps(void); +u32 tegra_read_chipid(void); +void tegra_init_fuse(void); + +extern enum tegra_revision tegra_revision; + #if defined(CONFIG_TEGRA20_APB_DMA) int tegra_apb_readl_using_dma(unsigned long offset, u32 *value); int tegra_apb_writel_using_dma(u32 value, unsigned long offset); -- cgit v1.2.3-70-g09d2 From 783c8f4c84451bc444e314a71b447239c6ef6fd9 Mon Sep 17 00:00:00 2001 From: Peter De Schrijver Date: Thu, 12 Jun 2014 18:36:37 +0300 Subject: soc/tegra: Add efuse driver for Tegra Implement fuse driver for Tegra20, Tegra30, Tegra114 and Tegra124. This replaces functionality previously provided in arch/arm/mach-tegra, which is removed in this patch. While at it, move the only user of the global tegra_revision variable over to tegra_sku_info.revision and export tegra_fuse_readl() to allow drivers to read calibration fuses. Signed-off-by: Peter De Schrijver Signed-off-by: Stephen Warren Signed-off-by: Thierry Reding --- Documentation/ABI/testing/sysfs-driver-tegra-fuse | 11 + arch/arm/mach-tegra/Makefile | 4 - arch/arm/mach-tegra/fuse.c | 260 ------------------- arch/arm/mach-tegra/fuse.h | 60 ----- arch/arm/mach-tegra/reset.c | 1 - arch/arm/mach-tegra/tegra.c | 3 +- arch/arm/mach-tegra/tegra114_speedo.c | 106 -------- arch/arm/mach-tegra/tegra20_speedo.c | 111 -------- arch/arm/mach-tegra/tegra30_speedo.c | 294 ---------------------- drivers/misc/fuse/Makefile | 1 + drivers/soc/Makefile | 1 + drivers/soc/tegra/Makefile | 1 + drivers/soc/tegra/fuse/Makefile | 8 + drivers/soc/tegra/fuse/fuse-tegra.c | 156 ++++++++++++ drivers/soc/tegra/fuse/fuse-tegra20.c | 142 +++++++++++ drivers/soc/tegra/fuse/fuse-tegra30.c | 224 +++++++++++++++++ drivers/soc/tegra/fuse/fuse.h | 71 ++++++ drivers/soc/tegra/fuse/speedo-tegra114.c | 110 ++++++++ drivers/soc/tegra/fuse/speedo-tegra124.c | 168 +++++++++++++ drivers/soc/tegra/fuse/speedo-tegra20.c | 110 ++++++++ drivers/soc/tegra/fuse/speedo-tegra30.c | 288 +++++++++++++++++++++ drivers/soc/tegra/fuse/tegra-apbmisc.c | 112 +++++++++ include/soc/tegra/fuse.h | 20 +- 23 files changed, 1424 insertions(+), 838 deletions(-) create mode 100644 Documentation/ABI/testing/sysfs-driver-tegra-fuse delete mode 100644 arch/arm/mach-tegra/fuse.c delete mode 100644 arch/arm/mach-tegra/fuse.h delete mode 100644 arch/arm/mach-tegra/tegra114_speedo.c delete mode 100644 arch/arm/mach-tegra/tegra20_speedo.c delete mode 100644 arch/arm/mach-tegra/tegra30_speedo.c create mode 100644 drivers/misc/fuse/Makefile create mode 100644 drivers/soc/tegra/Makefile create mode 100644 drivers/soc/tegra/fuse/Makefile create mode 100644 drivers/soc/tegra/fuse/fuse-tegra.c create mode 100644 drivers/soc/tegra/fuse/fuse-tegra20.c create mode 100644 drivers/soc/tegra/fuse/fuse-tegra30.c create mode 100644 drivers/soc/tegra/fuse/fuse.h create mode 100644 drivers/soc/tegra/fuse/speedo-tegra114.c create mode 100644 drivers/soc/tegra/fuse/speedo-tegra124.c create mode 100644 drivers/soc/tegra/fuse/speedo-tegra20.c create mode 100644 drivers/soc/tegra/fuse/speedo-tegra30.c create mode 100644 drivers/soc/tegra/fuse/tegra-apbmisc.c (limited to 'arch/arm/mach-tegra') diff --git a/Documentation/ABI/testing/sysfs-driver-tegra-fuse b/Documentation/ABI/testing/sysfs-driver-tegra-fuse new file mode 100644 index 00000000000..69f5af63265 --- /dev/null +++ b/Documentation/ABI/testing/sysfs-driver-tegra-fuse @@ -0,0 +1,11 @@ +What: /sys/devices/*//fuse +Date: February 2014 +Contact: Peter De Schrijver +Description: read-only access to the efuses on Tegra20, Tegra30, Tegra114 + and Tegra124 SoC's from NVIDIA. The efuses contain write once + data programmed at the factory. The data is layed out in 32bit + words in LSB first format. Each bit represents a single value + as decoded from the fuse registers. Bits order/assignment + exactly matches the HW registers, including any unused bits. +Users: any user space application which wants to read the efuses on + Tegra SoC's diff --git a/arch/arm/mach-tegra/Makefile b/arch/arm/mach-tegra/Makefile index 6fbfbb77dcd..e8601bb56f9 100644 --- a/arch/arm/mach-tegra/Makefile +++ b/arch/arm/mach-tegra/Makefile @@ -2,7 +2,6 @@ asflags-y += -march=armv7-a obj-y += io.o obj-y += irq.o -obj-y += fuse.o obj-y += pmc.o obj-y += flowctrl.o obj-y += powergate.o @@ -13,13 +12,11 @@ obj-y += reset-handler.o obj-y += sleep.o obj-y += tegra.o obj-$(CONFIG_CPU_IDLE) += cpuidle.o -obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += tegra20_speedo.o obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += sleep-tegra20.o obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += pm-tegra20.o ifeq ($(CONFIG_CPU_IDLE),y) obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += cpuidle-tegra20.o endif -obj-$(CONFIG_ARCH_TEGRA_3x_SOC) += tegra30_speedo.o obj-$(CONFIG_ARCH_TEGRA_3x_SOC) += sleep-tegra30.o obj-$(CONFIG_ARCH_TEGRA_3x_SOC) += pm-tegra30.o ifeq ($(CONFIG_CPU_IDLE),y) @@ -28,7 +25,6 @@ endif obj-$(CONFIG_SMP) += platsmp.o headsmp.o obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o -obj-$(CONFIG_ARCH_TEGRA_114_SOC) += tegra114_speedo.o obj-$(CONFIG_ARCH_TEGRA_114_SOC) += sleep-tegra30.o obj-$(CONFIG_ARCH_TEGRA_114_SOC) += pm-tegra30.o ifeq ($(CONFIG_CPU_IDLE),y) diff --git a/arch/arm/mach-tegra/fuse.c b/arch/arm/mach-tegra/fuse.c deleted file mode 100644 index b22e76a4096..00000000000 --- a/arch/arm/mach-tegra/fuse.c +++ /dev/null @@ -1,260 +0,0 @@ -/* - * arch/arm/mach-tegra/fuse.c - * - * Copyright (C) 2010 Google, Inc. - * Copyright (c) 2013, NVIDIA CORPORATION. All rights reserved. - * - * Author: - * Colin Cross - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * This program is distributed in the hope that 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. - * - */ - -#include -#include -#include -#include -#include - -#include - -#include "apbio.h" -#include "fuse.h" -#include "iomap.h" - -/* Tegra20 only */ -#define FUSE_UID_LOW 0x108 -#define FUSE_UID_HIGH 0x10c - -/* Tegra30 and later */ -#define FUSE_VENDOR_CODE 0x200 -#define FUSE_FAB_CODE 0x204 -#define FUSE_LOT_CODE_0 0x208 -#define FUSE_LOT_CODE_1 0x20c -#define FUSE_WAFER_ID 0x210 -#define FUSE_X_COORDINATE 0x214 -#define FUSE_Y_COORDINATE 0x218 - -#define FUSE_SKU_INFO 0x110 - -#define TEGRA20_FUSE_SPARE_BIT 0x200 -#define TEGRA30_FUSE_SPARE_BIT 0x244 - -int tegra_sku_id; -int tegra_cpu_process_id; -int tegra_core_process_id; -int tegra_cpu_speedo_id; /* only exist in Tegra30 and later */ -int tegra_soc_speedo_id; -enum tegra_revision tegra_revision; - -static struct clk *fuse_clk; -static int tegra_fuse_spare_bit; -static void (*tegra_init_speedo_data)(void); - -/* The BCT to use at boot is specified by board straps that can be read - * through a APB misc register and decoded. 2 bits, i.e. 4 possible BCTs. - */ -int tegra_bct_strapping; - -#define STRAP_OPT 0x008 -#define GMI_AD0 (1 << 4) -#define GMI_AD1 (1 << 5) -#define RAM_ID_MASK (GMI_AD0 | GMI_AD1) -#define RAM_CODE_SHIFT 4 - -static const char *tegra_revision_name[TEGRA_REVISION_MAX] = { - [TEGRA_REVISION_UNKNOWN] = "unknown", - [TEGRA_REVISION_A01] = "A01", - [TEGRA_REVISION_A02] = "A02", - [TEGRA_REVISION_A03] = "A03", - [TEGRA_REVISION_A03p] = "A03 prime", - [TEGRA_REVISION_A04] = "A04", -}; - -static void tegra_fuse_enable_clk(void) -{ - if (IS_ERR(fuse_clk)) - fuse_clk = clk_get_sys(NULL, "fuse"); - if (IS_ERR(fuse_clk)) - return; - clk_prepare_enable(fuse_clk); -} - -static void tegra_fuse_disable_clk(void) -{ - if (IS_ERR(fuse_clk)) - return; - clk_disable_unprepare(fuse_clk); -} - -u32 tegra_fuse_readl(unsigned long offset) -{ - return tegra_apb_readl(TEGRA_FUSE_BASE + offset); -} - -bool tegra_spare_fuse(int bit) -{ - bool ret; - - tegra_fuse_enable_clk(); - - ret = tegra_fuse_readl(tegra_fuse_spare_bit + bit * 4); - - tegra_fuse_disable_clk(); - - return ret; -} - -static enum tegra_revision tegra_get_revision(u32 id) -{ - u32 minor_rev = (id >> 16) & 0xf; - - switch (minor_rev) { - case 1: - return TEGRA_REVISION_A01; - case 2: - return TEGRA_REVISION_A02; - case 3: - if (tegra_get_chip_id() == TEGRA20 && - (tegra_spare_fuse(18) || tegra_spare_fuse(19))) - return TEGRA_REVISION_A03p; - else - return TEGRA_REVISION_A03; - case 4: - return TEGRA_REVISION_A04; - default: - return TEGRA_REVISION_UNKNOWN; - } -} - -static void tegra_get_process_id(void) -{ - u32 reg; - - tegra_fuse_enable_clk(); - - reg = tegra_fuse_readl(tegra_fuse_spare_bit); - tegra_cpu_process_id = (reg >> 6) & 3; - reg = tegra_fuse_readl(tegra_fuse_spare_bit); - tegra_core_process_id = (reg >> 12) & 3; - - tegra_fuse_disable_clk(); -} - -u32 tegra_read_chipid(void) -{ - return readl_relaxed(IO_ADDRESS(TEGRA_APB_MISC_BASE) + 0x804); -} - -u8 tegra_get_chip_id(void) -{ - u32 id = tegra_read_chipid(); - - return (id >> 8) & 0xff; -} - -static void __init tegra20_fuse_init_randomness(void) -{ - u32 randomness[2]; - - randomness[0] = tegra_fuse_readl(FUSE_UID_LOW); - randomness[1] = tegra_fuse_readl(FUSE_UID_HIGH); - - add_device_randomness(randomness, sizeof(randomness)); -} - -/* Applies to Tegra30 or later */ -static void __init tegra30_fuse_init_randomness(void) -{ - u32 randomness[7]; - - randomness[0] = tegra_fuse_readl(FUSE_VENDOR_CODE); - randomness[1] = tegra_fuse_readl(FUSE_FAB_CODE); - randomness[2] = tegra_fuse_readl(FUSE_LOT_CODE_0); - randomness[3] = tegra_fuse_readl(FUSE_LOT_CODE_1); - randomness[4] = tegra_fuse_readl(FUSE_WAFER_ID); - randomness[5] = tegra_fuse_readl(FUSE_X_COORDINATE); - randomness[6] = tegra_fuse_readl(FUSE_Y_COORDINATE); - - add_device_randomness(randomness, sizeof(randomness)); -} - -void __init tegra_init_fuse(void) -{ - u32 id; - u32 randomness[5]; - u8 chip_id; - - u32 reg = readl(IO_ADDRESS(TEGRA_CLK_RESET_BASE + 0x48)); - reg |= 1 << 28; - writel(reg, IO_ADDRESS(TEGRA_CLK_RESET_BASE + 0x48)); - - /* - * Enable FUSE clock. This needs to be hardcoded because the clock - * subsystem is not active during early boot. - */ - reg = readl(IO_ADDRESS(TEGRA_CLK_RESET_BASE + 0x14)); - reg |= 1 << 7; - writel(reg, IO_ADDRESS(TEGRA_CLK_RESET_BASE + 0x14)); - fuse_clk = ERR_PTR(-EINVAL); - - reg = tegra_fuse_readl(FUSE_SKU_INFO); - randomness[0] = reg; - tegra_sku_id = reg & 0xFF; - - reg = tegra_apb_readl(TEGRA_APB_MISC_BASE + STRAP_OPT); - randomness[1] = reg; - tegra_bct_strapping = (reg & RAM_ID_MASK) >> RAM_CODE_SHIFT; - - id = tegra_read_chipid(); - randomness[2] = id; - chip_id = (id >> 8) & 0xff; - - switch (chip_id) { - case TEGRA20: - tegra_fuse_spare_bit = TEGRA20_FUSE_SPARE_BIT; - tegra_init_speedo_data = &tegra20_init_speedo_data; - break; - case TEGRA30: - tegra_fuse_spare_bit = TEGRA30_FUSE_SPARE_BIT; - tegra_init_speedo_data = &tegra30_init_speedo_data; - break; - case TEGRA114: - tegra_init_speedo_data = &tegra114_init_speedo_data; - break; - default: - pr_warn("Tegra: unknown chip id %d\n", chip_id); - tegra_fuse_spare_bit = TEGRA20_FUSE_SPARE_BIT; - tegra_init_speedo_data = &tegra_get_process_id; - } - - tegra_revision = tegra_get_revision(id); - tegra_init_speedo_data(); - randomness[3] = (tegra_cpu_process_id << 16) | tegra_core_process_id; - randomness[4] = (tegra_cpu_speedo_id << 16) | tegra_soc_speedo_id; - - add_device_randomness(randomness, sizeof(randomness)); - switch (chip_id) { - case TEGRA20: - tegra20_fuse_init_randomness(); - break; - case TEGRA30: - case TEGRA114: - default: - tegra30_fuse_init_randomness(); - break; - } - - pr_info("Tegra Revision: %s SKU: %d CPU Process: %d Core Process: %d\n", - tegra_revision_name[tegra_revision], - tegra_sku_id, tegra_cpu_process_id, - tegra_core_process_id); -} diff --git a/arch/arm/mach-tegra/fuse.h b/arch/arm/mach-tegra/fuse.h deleted file mode 100644 index 48a48861c19..00000000000 --- a/arch/arm/mach-tegra/fuse.h +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright (C) 2010 Google, Inc. - * Copyright (c) 2013, NVIDIA CORPORATION. All rights reserved. - * - * Author: - * Colin Cross - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * This program is distributed in the hope that 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. - * - */ - -#ifndef __MACH_TEGRA_FUSE_H -#define __MACH_TEGRA_FUSE_H - -#define SKU_ID_T20 8 -#define SKU_ID_T25SE 20 -#define SKU_ID_AP25 23 -#define SKU_ID_T25 24 -#define SKU_ID_AP25E 27 -#define SKU_ID_T25E 28 - -#ifndef __ASSEMBLY__ - -extern int tegra_sku_id; -extern int tegra_cpu_process_id; -extern int tegra_core_process_id; -extern int tegra_cpu_speedo_id; /* only exist in Tegra30 and later */ -extern int tegra_soc_speedo_id; - -unsigned long long tegra_chip_uid(void); -bool tegra_spare_fuse(int bit); -u32 tegra_fuse_readl(unsigned long offset); - -#ifdef CONFIG_ARCH_TEGRA_2x_SOC -void tegra20_init_speedo_data(void); -#else -static inline void tegra20_init_speedo_data(void) {} -#endif - -#ifdef CONFIG_ARCH_TEGRA_3x_SOC -void tegra30_init_speedo_data(void); -#else -static inline void tegra30_init_speedo_data(void) {} -#endif - -#ifdef CONFIG_ARCH_TEGRA_114_SOC -void tegra114_init_speedo_data(void); -#else -static inline void tegra114_init_speedo_data(void) {} -#endif -#endif /* __ASSEMBLY__ */ - -#endif diff --git a/arch/arm/mach-tegra/reset.c b/arch/arm/mach-tegra/reset.c index f94fdf89d45..5377495d41b 100644 --- a/arch/arm/mach-tegra/reset.c +++ b/arch/arm/mach-tegra/reset.c @@ -25,7 +25,6 @@ #include #include -#include "fuse.h" #include "iomap.h" #include "irammap.h" #include "reset.h" diff --git a/arch/arm/mach-tegra/tegra.c b/arch/arm/mach-tegra/tegra.c index a359931c595..c0faae8c082 100644 --- a/arch/arm/mach-tegra/tegra.c +++ b/arch/arm/mach-tegra/tegra.c @@ -104,7 +104,8 @@ static void __init tegra_dt_init(void) goto out; soc_dev_attr->family = kasprintf(GFP_KERNEL, "Tegra"); - soc_dev_attr->revision = kasprintf(GFP_KERNEL, "%d", tegra_revision); + soc_dev_attr->revision = kasprintf(GFP_KERNEL, "%d", + tegra_sku_info.revision); soc_dev_attr->soc_id = kasprintf(GFP_KERNEL, "%u", tegra_get_chip_id()); soc_dev = soc_device_register(soc_dev_attr); diff --git a/arch/arm/mach-tegra/tegra114_speedo.c b/arch/arm/mach-tegra/tegra114_speedo.c deleted file mode 100644 index d0a6d5925f5..00000000000 --- a/arch/arm/mach-tegra/tegra114_speedo.c +++ /dev/null @@ -1,106 +0,0 @@ -/* - * Copyright (c) 2013, 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 . - */ - -#include -#include - -#include - -#include "fuse.h" - -#define CORE_PROCESS_CORNERS_NUM 2 -#define CPU_PROCESS_CORNERS_NUM 2 - -enum { - THRESHOLD_INDEX_0, - THRESHOLD_INDEX_1, - THRESHOLD_INDEX_COUNT, -}; - -static const u32 core_process_speedos[][CORE_PROCESS_CORNERS_NUM] = { - {1123, UINT_MAX}, - {0, UINT_MAX}, -}; - -static const u32 cpu_process_speedos[][CPU_PROCESS_CORNERS_NUM] = { - {1695, UINT_MAX}, - {0, UINT_MAX}, -}; - -static void rev_sku_to_speedo_ids(int rev, int sku, int *threshold) -{ - u32 tmp; - - switch (sku) { - case 0x00: - case 0x10: - case 0x05: - case 0x06: - tegra_cpu_speedo_id = 1; - tegra_soc_speedo_id = 0; - *threshold = THRESHOLD_INDEX_0; - break; - - case 0x03: - case 0x04: - tegra_cpu_speedo_id = 2; - tegra_soc_speedo_id = 1; - *threshold = THRESHOLD_INDEX_1; - break; - - default: - pr_err("Tegra114 Unknown SKU %d\n", sku); - tegra_cpu_speedo_id = 0; - tegra_soc_speedo_id = 0; - *threshold = THRESHOLD_INDEX_0; - break; - } - - if (rev == TEGRA_REVISION_A01) { - tmp = tegra_fuse_readl(0x270) << 1; - tmp |= tegra_fuse_readl(0x26c); - if (!tmp) - tegra_cpu_speedo_id = 0; - } -} - -void tegra114_init_speedo_data(void) -{ - u32 cpu_speedo_val; - u32 core_speedo_val; - int threshold; - int i; - - BUILD_BUG_ON(ARRAY_SIZE(cpu_process_speedos) != - THRESHOLD_INDEX_COUNT); - BUILD_BUG_ON(ARRAY_SIZE(core_process_speedos) != - THRESHOLD_INDEX_COUNT); - - rev_sku_to_speedo_ids(tegra_revision, tegra_sku_id, &threshold); - - cpu_speedo_val = tegra_fuse_readl(0x12c) + 1024; - core_speedo_val = tegra_fuse_readl(0x134); - - for (i = 0; i < CPU_PROCESS_CORNERS_NUM; i++) - if (cpu_speedo_val < cpu_process_speedos[threshold][i]) - break; - tegra_cpu_process_id = i; - - for (i = 0; i < CORE_PROCESS_CORNERS_NUM; i++) - if (core_speedo_val < core_process_speedos[threshold][i]) - break; - tegra_core_process_id = i; -} diff --git a/arch/arm/mach-tegra/tegra20_speedo.c b/arch/arm/mach-tegra/tegra20_speedo.c deleted file mode 100644 index 2907cf8de2b..00000000000 --- a/arch/arm/mach-tegra/tegra20_speedo.c +++ /dev/null @@ -1,111 +0,0 @@ -/* - * 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 . - */ - -#include -#include - -#include - -#include "fuse.h" - -#define CPU_SPEEDO_LSBIT 20 -#define CPU_SPEEDO_MSBIT 29 -#define CPU_SPEEDO_REDUND_LSBIT 30 -#define CPU_SPEEDO_REDUND_MSBIT 39 -#define CPU_SPEEDO_REDUND_OFFS (CPU_SPEEDO_REDUND_MSBIT - CPU_SPEEDO_MSBIT) - -#define CORE_SPEEDO_LSBIT 40 -#define CORE_SPEEDO_MSBIT 47 -#define CORE_SPEEDO_REDUND_LSBIT 48 -#define CORE_SPEEDO_REDUND_MSBIT 55 -#define CORE_SPEEDO_REDUND_OFFS (CORE_SPEEDO_REDUND_MSBIT - CORE_SPEEDO_MSBIT) - -#define SPEEDO_MULT 4 - -#define PROCESS_CORNERS_NUM 4 - -#define SPEEDO_ID_SELECT_0(rev) ((rev) <= 2) -#define SPEEDO_ID_SELECT_1(sku) \ - (((sku) != 20) && ((sku) != 23) && ((sku) != 24) && \ - ((sku) != 27) && ((sku) != 28)) - -enum { - SPEEDO_ID_0, - SPEEDO_ID_1, - SPEEDO_ID_2, - SPEEDO_ID_COUNT, -}; - -static const u32 cpu_process_speedos[][PROCESS_CORNERS_NUM] = { - {315, 366, 420, UINT_MAX}, - {303, 368, 419, UINT_MAX}, - {316, 331, 383, UINT_MAX}, -}; - -static const u32 core_process_speedos[][PROCESS_CORNERS_NUM] = { - {165, 195, 224, UINT_MAX}, - {165, 195, 224, UINT_MAX}, - {165, 195, 224, UINT_MAX}, -}; - -void tegra20_init_speedo_data(void) -{ - u32 reg; - u32 val; - int i; - - BUILD_BUG_ON(ARRAY_SIZE(cpu_process_speedos) != SPEEDO_ID_COUNT); - BUILD_BUG_ON(ARRAY_SIZE(core_process_speedos) != SPEEDO_ID_COUNT); - - if (SPEEDO_ID_SELECT_0(tegra_revision)) - tegra_soc_speedo_id = SPEEDO_ID_0; - else if (SPEEDO_ID_SELECT_1(tegra_sku_id)) - tegra_soc_speedo_id = SPEEDO_ID_1; - else - tegra_soc_speedo_id = SPEEDO_ID_2; - - val = 0; - for (i = CPU_SPEEDO_MSBIT; i >= CPU_SPEEDO_LSBIT; i--) { - reg = tegra_spare_fuse(i) | - tegra_spare_fuse(i + CPU_SPEEDO_REDUND_OFFS); - val = (val << 1) | (reg & 0x1); - } - val = val * SPEEDO_MULT; - pr_debug("%s CPU speedo value %u\n", __func__, val); - - for (i = 0; i < (PROCESS_CORNERS_NUM - 1); i++) { - if (val <= cpu_process_speedos[tegra_soc_speedo_id][i]) - break; - } - tegra_cpu_process_id = i; - - val = 0; - for (i = CORE_SPEEDO_MSBIT; i >= CORE_SPEEDO_LSBIT; i--) { - reg = tegra_spare_fuse(i) | - tegra_spare_fuse(i + CORE_SPEEDO_REDUND_OFFS); - val = (val << 1) | (reg & 0x1); - } - val = val * SPEEDO_MULT; - pr_debug("%s Core speedo value %u\n", __func__, val); - - for (i = 0; i < (PROCESS_CORNERS_NUM - 1); i++) { - if (val <= core_process_speedos[tegra_soc_speedo_id][i]) - break; - } - tegra_core_process_id = i; - - pr_info("Tegra20 Soc Speedo ID %d", tegra_soc_speedo_id); -} diff --git a/arch/arm/mach-tegra/tegra30_speedo.c b/arch/arm/mach-tegra/tegra30_speedo.c deleted file mode 100644 index 6f6102cd1e6..00000000000 --- a/arch/arm/mach-tegra/tegra30_speedo.c +++ /dev/null @@ -1,294 +0,0 @@ -/* - * 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 . - */ - -#include -#include - -#include - -#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); -} diff --git a/drivers/misc/fuse/Makefile b/drivers/misc/fuse/Makefile new file mode 100644 index 00000000000..0679c4febc8 --- /dev/null +++ b/drivers/misc/fuse/Makefile @@ -0,0 +1 @@ +obj-$(CONFIG_ARCH_TEGRA) += tegra/ diff --git a/drivers/soc/Makefile b/drivers/soc/Makefile index 0f7c44793b2..3b1b95d932d 100644 --- a/drivers/soc/Makefile +++ b/drivers/soc/Makefile @@ -3,3 +3,4 @@ # obj-$(CONFIG_ARCH_QCOM) += qcom/ +obj-$(CONFIG_ARCH_TEGRA) += tegra/ diff --git a/drivers/soc/tegra/Makefile b/drivers/soc/tegra/Makefile new file mode 100644 index 00000000000..236600f91bb --- /dev/null +++ b/drivers/soc/tegra/Makefile @@ -0,0 +1 @@ +obj-$(CONFIG_ARCH_TEGRA) += fuse/ diff --git a/drivers/soc/tegra/fuse/Makefile b/drivers/soc/tegra/fuse/Makefile new file mode 100644 index 00000000000..3af357da91f --- /dev/null +++ b/drivers/soc/tegra/fuse/Makefile @@ -0,0 +1,8 @@ +obj-y += fuse-tegra.o +obj-y += fuse-tegra30.o +obj-y += tegra-apbmisc.o +obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += fuse-tegra20.o +obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += speedo-tegra20.o +obj-$(CONFIG_ARCH_TEGRA_3x_SOC) += speedo-tegra30.o +obj-$(CONFIG_ARCH_TEGRA_114_SOC) += speedo-tegra114.o +obj-$(CONFIG_ARCH_TEGRA_124_SOC) += speedo-tegra124.o diff --git a/drivers/soc/tegra/fuse/fuse-tegra.c b/drivers/soc/tegra/fuse/fuse-tegra.c new file mode 100644 index 00000000000..03742edcfe8 --- /dev/null +++ b/drivers/soc/tegra/fuse/fuse-tegra.c @@ -0,0 +1,156 @@ +/* + * Copyright (c) 2013-2014, 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 . + * + */ + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "fuse.h" + +static u32 (*fuse_readl)(const unsigned int offset); +static int fuse_size; +struct tegra_sku_info tegra_sku_info; + +static const char *tegra_revision_name[TEGRA_REVISION_MAX] = { + [TEGRA_REVISION_UNKNOWN] = "unknown", + [TEGRA_REVISION_A01] = "A01", + [TEGRA_REVISION_A02] = "A02", + [TEGRA_REVISION_A03] = "A03", + [TEGRA_REVISION_A03p] = "A03 prime", + [TEGRA_REVISION_A04] = "A04", +}; + +static u8 fuse_readb(const unsigned int offset) +{ + u32 val; + + val = fuse_readl(round_down(offset, 4)); + val >>= (offset % 4) * 8; + val &= 0xff; + + return val; +} + +static ssize_t fuse_read(struct file *fd, struct kobject *kobj, + struct bin_attribute *attr, char *buf, + loff_t pos, size_t size) +{ + int i; + + if (pos < 0 || pos >= fuse_size) + return 0; + + if (size > fuse_size - pos) + size = fuse_size - pos; + + for (i = 0; i < size; i++) + buf[i] = fuse_readb(pos + i); + + return i; +} + +static struct bin_attribute fuse_bin_attr = { + .attr = { .name = "fuse", .mode = S_IRUGO, }, + .read = fuse_read, +}; + +static const struct of_device_id car_match[] __initconst = { + { .compatible = "nvidia,tegra20-car", }, + { .compatible = "nvidia,tegra30-car", }, + { .compatible = "nvidia,tegra114-car", }, + { .compatible = "nvidia,tegra124-car", }, + {}, +}; + +static void tegra_enable_fuse_clk(void __iomem *base) +{ + u32 reg; + + reg = readl_relaxed(base + 0x48); + reg |= 1 << 28; + writel(reg, base + 0x48); + + /* + * Enable FUSE clock. This needs to be hardcoded because the clock + * subsystem is not active during early boot. + */ + reg = readl(base + 0x14); + reg |= 1 << 7; + writel(reg, base + 0x14); +} + +int tegra_fuse_readl(unsigned long offset, u32 *value) +{ + if (!fuse_readl) + return -EPROBE_DEFER; + + *value = fuse_readl(offset); + + return 0; +} +EXPORT_SYMBOL(tegra_fuse_readl); + +int tegra_fuse_create_sysfs(struct device *dev, int size, + u32 (*readl)(const unsigned int offset)) +{ + if (fuse_size) + return -ENODEV; + + fuse_bin_attr.size = size; + fuse_bin_attr.read = fuse_read; + + fuse_size = size; + fuse_readl = readl; + + return device_create_bin_file(dev, &fuse_bin_attr); +} + +void __init tegra_init_fuse(void) +{ + struct device_node *np; + void __iomem *car_base; + + tegra_init_apbmisc(); + + np = of_find_matching_node(NULL, car_match); + car_base = of_iomap(np, 0); + if (car_base) { + tegra_enable_fuse_clk(car_base); + iounmap(car_base); + } else { + pr_err("Could not enable fuse clk. ioremap tegra car failed.\n"); + return; + } + + if (tegra_get_chip_id() == TEGRA20) + tegra20_init_fuse_early(); + else + tegra30_init_fuse_early(); + + pr_info("Tegra Revision: %s SKU: %d CPU Process: %d Core Process: %d\n", + tegra_revision_name[tegra_sku_info.revision], + tegra_sku_info.sku_id, tegra_sku_info.cpu_process_id, + tegra_sku_info.core_process_id); + pr_debug("Tegra CPU Speedo ID %d, Soc Speedo ID %d\n", + tegra_sku_info.cpu_speedo_id, tegra_sku_info.soc_speedo_id); +} diff --git a/drivers/soc/tegra/fuse/fuse-tegra20.c b/drivers/soc/tegra/fuse/fuse-tegra20.c new file mode 100644 index 00000000000..7a9d0e04549 --- /dev/null +++ b/drivers/soc/tegra/fuse/fuse-tegra20.c @@ -0,0 +1,142 @@ +/* + * Copyright (c) 2013-2014, 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 . + * + * Based on drivers/misc/eeprom/sunxi_sid.c + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "fuse.h" + +#define FUSE_BEGIN 0x100 +#define FUSE_SIZE 0x1f8 +#define FUSE_UID_LOW 0x08 +#define FUSE_UID_HIGH 0x0c + +static phys_addr_t fuse_phys; +static struct clk *fuse_clk; +static void __iomem __initdata *fuse_base; + +static u32 tegra20_fuse_readl(const unsigned int offset) +{ + int ret; + u32 val; + + clk_prepare_enable(fuse_clk); + + ret = tegra_apb_readl_using_dma(fuse_phys + FUSE_BEGIN + offset, &val); + + clk_disable_unprepare(fuse_clk); + + return (ret < 0) ? 0 : val; +} + +static const struct of_device_id tegra20_fuse_of_match[] = { + { .compatible = "nvidia,tegra20-efuse" }, + {}, +}; + +static int tegra20_fuse_probe(struct platform_device *pdev) +{ + struct resource *res; + + fuse_clk = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(fuse_clk)) { + dev_err(&pdev->dev, "missing clock"); + return PTR_ERR(fuse_clk); + } + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) + return -EINVAL; + fuse_phys = res->start; + + if (tegra_fuse_create_sysfs(&pdev->dev, FUSE_SIZE, tegra20_fuse_readl)) + return -ENODEV; + + dev_dbg(&pdev->dev, "loaded\n"); + + return 0; +} + +static struct platform_driver tegra20_fuse_driver = { + .probe = tegra20_fuse_probe, + .driver = { + .name = "tegra20_fuse", + .owner = THIS_MODULE, + .of_match_table = tegra20_fuse_of_match, + } +}; + +static int __init tegra20_fuse_init(void) +{ + return platform_driver_register(&tegra20_fuse_driver); +} +postcore_initcall(tegra20_fuse_init); + +/* Early boot code. This code is called before the devices are created */ + +u32 __init tegra20_fuse_early(const unsigned int offset) +{ + return readl_relaxed(fuse_base + FUSE_BEGIN + offset); +} + +bool __init tegra20_spare_fuse_early(int spare_bit) +{ + u32 offset = spare_bit * 4; + bool value; + + value = tegra20_fuse_early(offset + 0x100); + + return value; +} + +static void __init tegra20_fuse_add_randomness(void) +{ + u32 randomness[7]; + + randomness[0] = tegra_sku_info.sku_id; + randomness[1] = tegra_read_straps(); + randomness[2] = tegra_read_chipid(); + randomness[3] = tegra_sku_info.cpu_process_id << 16; + randomness[3] |= tegra_sku_info.core_process_id; + randomness[4] = tegra_sku_info.cpu_speedo_id << 16; + randomness[4] |= tegra_sku_info.soc_speedo_id; + randomness[5] = tegra20_fuse_early(FUSE_UID_LOW); + randomness[6] = tegra20_fuse_early(FUSE_UID_HIGH); + + add_device_randomness(randomness, sizeof(randomness)); +} + +void __init tegra20_init_fuse_early(void) +{ + fuse_base = ioremap(TEGRA_FUSE_BASE, TEGRA_FUSE_SIZE); + + tegra_init_revision(); + tegra20_init_speedo_data(&tegra_sku_info); + tegra20_fuse_add_randomness(); + + iounmap(fuse_base); +} diff --git a/drivers/soc/tegra/fuse/fuse-tegra30.c b/drivers/soc/tegra/fuse/fuse-tegra30.c new file mode 100644 index 00000000000..5999cf34ab7 --- /dev/null +++ b/drivers/soc/tegra/fuse/fuse-tegra30.c @@ -0,0 +1,224 @@ +/* + * Copyright (c) 2013-2014, 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 . + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "fuse.h" + +#define FUSE_BEGIN 0x100 + +/* Tegra30 and later */ +#define FUSE_VENDOR_CODE 0x100 +#define FUSE_FAB_CODE 0x104 +#define FUSE_LOT_CODE_0 0x108 +#define FUSE_LOT_CODE_1 0x10c +#define FUSE_WAFER_ID 0x110 +#define FUSE_X_COORDINATE 0x114 +#define FUSE_Y_COORDINATE 0x118 + +#define FUSE_HAS_REVISION_INFO BIT(0) + +enum speedo_idx { + SPEEDO_TEGRA30 = 0, + SPEEDO_TEGRA114, + SPEEDO_TEGRA124, +}; + +struct tegra_fuse_info { + int size; + int spare_bit; + enum speedo_idx speedo_idx; +}; + +static void __iomem *fuse_base; +static struct clk *fuse_clk; +static struct tegra_fuse_info *fuse_info; + +u32 tegra30_fuse_readl(const unsigned int offset) +{ + u32 val; + + /* + * early in the boot, the fuse clock will be enabled by + * tegra_init_fuse() + */ + + if (fuse_clk) + clk_prepare_enable(fuse_clk); + + val = readl_relaxed(fuse_base + FUSE_BEGIN + offset); + + if (fuse_clk) + clk_disable_unprepare(fuse_clk); + + return val; +} + +static struct tegra_fuse_info tegra30_info = { + .size = 0x2a4, + .spare_bit = 0x144, + .speedo_idx = SPEEDO_TEGRA30, +}; + +static struct tegra_fuse_info tegra114_info = { + .size = 0x2a0, + .speedo_idx = SPEEDO_TEGRA114, +}; + +static struct tegra_fuse_info tegra124_info = { + .size = 0x300, + .speedo_idx = SPEEDO_TEGRA124, +}; + +static const struct of_device_id tegra30_fuse_of_match[] = { + { .compatible = "nvidia,tegra30-efuse", .data = &tegra30_info }, + { .compatible = "nvidia,tegra114-efuse", .data = &tegra114_info }, + { .compatible = "nvidia,tegra124-efuse", .data = &tegra124_info }, + {}, +}; + +static int tegra30_fuse_probe(struct platform_device *pdev) +{ + const struct of_device_id *of_dev_id; + + of_dev_id = of_match_device(tegra30_fuse_of_match, &pdev->dev); + if (!of_dev_id) + return -ENODEV; + + fuse_clk = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(fuse_clk)) { + dev_err(&pdev->dev, "missing clock"); + return PTR_ERR(fuse_clk); + } + + platform_set_drvdata(pdev, NULL); + + if (tegra_fuse_create_sysfs(&pdev->dev, fuse_info->size, + tegra30_fuse_readl)) + return -ENODEV; + + dev_dbg(&pdev->dev, "loaded\n"); + + return 0; +} + +static struct platform_driver tegra30_fuse_driver = { + .probe = tegra30_fuse_probe, + .driver = { + .name = "tegra_fuse", + .owner = THIS_MODULE, + .of_match_table = tegra30_fuse_of_match, + } +}; + +static int __init tegra30_fuse_init(void) +{ + return platform_driver_register(&tegra30_fuse_driver); +} +postcore_initcall(tegra30_fuse_init); + +/* Early boot code. This code is called before the devices are created */ + +typedef void (*speedo_f)(struct tegra_sku_info *sku_info); + +static speedo_f __initdata speedo_tbl[] = { + [SPEEDO_TEGRA30] = tegra30_init_speedo_data, + [SPEEDO_TEGRA114] = tegra114_init_speedo_data, + [SPEEDO_TEGRA124] = tegra124_init_speedo_data, +}; + +static void __init tegra30_fuse_add_randomness(void) +{ + u32 randomness[12]; + + randomness[0] = tegra_sku_info.sku_id; + randomness[1] = tegra_read_straps(); + randomness[2] = tegra_read_chipid(); + randomness[3] = tegra_sku_info.cpu_process_id << 16; + randomness[3] |= tegra_sku_info.core_process_id; + randomness[4] = tegra_sku_info.cpu_speedo_id << 16; + randomness[4] |= tegra_sku_info.soc_speedo_id; + randomness[5] = tegra30_fuse_readl(FUSE_VENDOR_CODE); + randomness[6] = tegra30_fuse_readl(FUSE_FAB_CODE); + randomness[7] = tegra30_fuse_readl(FUSE_LOT_CODE_0); + randomness[8] = tegra30_fuse_readl(FUSE_LOT_CODE_1); + randomness[9] = tegra30_fuse_readl(FUSE_WAFER_ID); + randomness[10] = tegra30_fuse_readl(FUSE_X_COORDINATE); + randomness[11] = tegra30_fuse_readl(FUSE_Y_COORDINATE); + + add_device_randomness(randomness, sizeof(randomness)); +} + +static void __init legacy_fuse_init(void) +{ + switch (tegra_get_chip_id()) { + case TEGRA30: + fuse_info = &tegra30_info; + break; + case TEGRA114: + fuse_info = &tegra114_info; + break; + case TEGRA124: + fuse_info = &tegra124_info; + break; + default: + return; + } + + fuse_base = ioremap(TEGRA_FUSE_BASE, TEGRA_FUSE_SIZE); +} + +bool __init tegra30_spare_fuse(int spare_bit) +{ + u32 offset = fuse_info->spare_bit + spare_bit * 4; + + return tegra30_fuse_readl(offset) & 1; +} + +void __init tegra30_init_fuse_early(void) +{ + struct device_node *np; + const struct of_device_id *of_match; + + np = of_find_matching_node_and_match(NULL, tegra30_fuse_of_match, + &of_match); + if (np) { + fuse_base = of_iomap(np, 0); + fuse_info = (struct tegra_fuse_info *)of_match->data; + } else + legacy_fuse_init(); + + if (!fuse_base) { + pr_warn("fuse DT node missing and unknown chip id: 0x%02x\n", + tegra_get_chip_id()); + return; + } + + tegra_init_revision(); + speedo_tbl[fuse_info->speedo_idx](&tegra_sku_info); + tegra30_fuse_add_randomness(); +} diff --git a/drivers/soc/tegra/fuse/fuse.h b/drivers/soc/tegra/fuse/fuse.h new file mode 100644 index 00000000000..b3442770df0 --- /dev/null +++ b/drivers/soc/tegra/fuse/fuse.h @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2010 Google, Inc. + * Copyright (c) 2013, NVIDIA CORPORATION. All rights reserved. + * + * Author: + * Colin Cross + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that 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. + * + */ + +#ifndef __DRIVERS_MISC_TEGRA_FUSE_H +#define __DRIVERS_MISC_TEGRA_FUSE_H + +#define TEGRA_FUSE_BASE 0x7000f800 +#define TEGRA_FUSE_SIZE 0x400 + +int tegra_fuse_create_sysfs(struct device *dev, int size, + u32 (*readl)(const unsigned int offset)); + +bool tegra30_spare_fuse(int bit); +u32 tegra30_fuse_readl(const unsigned int offset); +void tegra30_init_fuse_early(void); +void tegra_init_revision(void); +void tegra_init_apbmisc(void); + +#ifdef CONFIG_ARCH_TEGRA_2x_SOC +void tegra20_init_speedo_data(struct tegra_sku_info *sku_info); +bool tegra20_spare_fuse_early(int spare_bit); +void tegra20_init_fuse_early(void); +u32 tegra20_fuse_early(const unsigned int offset); +#else +static inline void tegra20_init_speedo_data(struct tegra_sku_info *sku_info) {} +static inline bool tegra20_spare_fuse_early(int spare_bit, void *fuse_base) +{ + return false; +} +static inline void tegra20_init_fuse_early(void); +static inline tegra20_fuse_early(const unsigned int offset); +{ + return 0; +} +#endif + + +#ifdef CONFIG_ARCH_TEGRA_3x_SOC +void tegra30_init_speedo_data(struct tegra_sku_info *sku_info); +#else +static inline void tegra30_init_speedo_data(struct tegra_sku_info *sku_info) {} +#endif + +#ifdef CONFIG_ARCH_TEGRA_114_SOC +void tegra114_init_speedo_data(struct tegra_sku_info *sku_info); +#else +static inline void tegra114_init_speedo_data(struct tegra_sku_info *sku_info) {} +#endif + +#ifdef CONFIG_ARCH_TEGRA_124_SOC +void tegra124_init_speedo_data(struct tegra_sku_info *sku_info); +#else +static inline void tegra124_init_speedo_data(struct tegra_sku_info *sku_info) {} +#endif + +#endif diff --git a/drivers/soc/tegra/fuse/speedo-tegra114.c b/drivers/soc/tegra/fuse/speedo-tegra114.c new file mode 100644 index 00000000000..2a6ca036f09 --- /dev/null +++ b/drivers/soc/tegra/fuse/speedo-tegra114.c @@ -0,0 +1,110 @@ +/* + * Copyright (c) 2013-2014, 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 . + */ + +#include +#include +#include + +#include + +#include "fuse.h" + +#define CORE_PROCESS_CORNERS 2 +#define CPU_PROCESS_CORNERS 2 + +enum { + THRESHOLD_INDEX_0, + THRESHOLD_INDEX_1, + THRESHOLD_INDEX_COUNT, +}; + +static const u32 __initconst core_process_speedos[][CORE_PROCESS_CORNERS] = { + {1123, UINT_MAX}, + {0, UINT_MAX}, +}; + +static const u32 __initconst cpu_process_speedos[][CPU_PROCESS_CORNERS] = { + {1695, UINT_MAX}, + {0, UINT_MAX}, +}; + +static void __init rev_sku_to_speedo_ids(struct tegra_sku_info *sku_info, + int *threshold) +{ + u32 tmp; + u32 sku = sku_info->sku_id; + enum tegra_revision rev = sku_info->revision; + + switch (sku) { + case 0x00: + case 0x10: + case 0x05: + case 0x06: + sku_info->cpu_speedo_id = 1; + sku_info->soc_speedo_id = 0; + *threshold = THRESHOLD_INDEX_0; + break; + + case 0x03: + case 0x04: + sku_info->cpu_speedo_id = 2; + sku_info->soc_speedo_id = 1; + *threshold = THRESHOLD_INDEX_1; + break; + + default: + pr_err("Tegra Unknown SKU %d\n", sku); + sku_info->cpu_speedo_id = 0; + sku_info->soc_speedo_id = 0; + *threshold = THRESHOLD_INDEX_0; + break; + } + + if (rev == TEGRA_REVISION_A01) { + tmp = tegra30_fuse_readl(0x270) << 1; + tmp |= tegra30_fuse_readl(0x26c); + if (!tmp) + sku_info->cpu_speedo_id = 0; + } +} + +void __init tegra114_init_speedo_data(struct tegra_sku_info *sku_info) +{ + u32 cpu_speedo_val; + u32 core_speedo_val; + int threshold; + int i; + + BUILD_BUG_ON(ARRAY_SIZE(cpu_process_speedos) != + THRESHOLD_INDEX_COUNT); + BUILD_BUG_ON(ARRAY_SIZE(core_process_speedos) != + THRESHOLD_INDEX_COUNT); + + rev_sku_to_speedo_ids(sku_info, &threshold); + + cpu_speedo_val = tegra30_fuse_readl(0x12c) + 1024; + core_speedo_val = tegra30_fuse_readl(0x134); + + for (i = 0; i < CPU_PROCESS_CORNERS; i++) + if (cpu_speedo_val < cpu_process_speedos[threshold][i]) + break; + sku_info->cpu_process_id = i; + + for (i = 0; i < CORE_PROCESS_CORNERS; i++) + if (core_speedo_val < core_process_speedos[threshold][i]) + break; + sku_info->core_process_id = i; +} diff --git a/drivers/soc/tegra/fuse/speedo-tegra124.c b/drivers/soc/tegra/fuse/speedo-tegra124.c new file mode 100644 index 00000000000..46362387d97 --- /dev/null +++ b/drivers/soc/tegra/fuse/speedo-tegra124.c @@ -0,0 +1,168 @@ +/* + * Copyright (c) 2013-2014, 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 . + */ + +#include +#include +#include + +#include + +#include "fuse.h" + +#define CPU_PROCESS_CORNERS 2 +#define GPU_PROCESS_CORNERS 2 +#define CORE_PROCESS_CORNERS 2 + +#define FUSE_CPU_SPEEDO_0 0x14 +#define FUSE_CPU_SPEEDO_1 0x2c +#define FUSE_CPU_SPEEDO_2 0x30 +#define FUSE_SOC_SPEEDO_0 0x34 +#define FUSE_SOC_SPEEDO_1 0x38 +#define FUSE_SOC_SPEEDO_2 0x3c +#define FUSE_CPU_IDDQ 0x18 +#define FUSE_SOC_IDDQ 0x40 +#define FUSE_GPU_IDDQ 0x128 +#define FUSE_FT_REV 0x28 + +enum { + THRESHOLD_INDEX_0, + THRESHOLD_INDEX_1, + THRESHOLD_INDEX_COUNT, +}; + +static const u32 __initconst cpu_process_speedos[][CPU_PROCESS_CORNERS] = { + {2190, UINT_MAX}, + {0, UINT_MAX}, +}; + +static const u32 __initconst gpu_process_speedos[][GPU_PROCESS_CORNERS] = { + {1965, UINT_MAX}, + {0, UINT_MAX}, +}; + +static const u32 __initconst core_process_speedos[][CORE_PROCESS_CORNERS] = { + {2101, UINT_MAX}, + {0, UINT_MAX}, +}; + +static void __init rev_sku_to_speedo_ids(struct tegra_sku_info *sku_info, + int *threshold) +{ + int sku = sku_info->sku_id; + + /* Assign to default */ + sku_info->cpu_speedo_id = 0; + sku_info->soc_speedo_id = 0; + sku_info->gpu_speedo_id = 0; + *threshold = THRESHOLD_INDEX_0; + + switch (sku) { + case 0x00: /* Eng sku */ + case 0x0F: + case 0x23: + /* Using the default */ + break; + case 0x83: + sku_info->cpu_speedo_id = 2; + break; + + case 0x1F: + case 0x87: + case 0x27: + sku_info->cpu_speedo_id = 2; + sku_info->soc_speedo_id = 0; + sku_info->gpu_speedo_id = 1; + *threshold = THRESHOLD_INDEX_0; + break; + case 0x81: + case 0x21: + case 0x07: + sku_info->cpu_speedo_id = 1; + sku_info->soc_speedo_id = 1; + sku_info->gpu_speedo_id = 1; + *threshold = THRESHOLD_INDEX_1; + break; + case 0x49: + case 0x4A: + case 0x48: + sku_info->cpu_speedo_id = 4; + sku_info->soc_speedo_id = 2; + sku_info->gpu_speedo_id = 3; + *threshold = THRESHOLD_INDEX_1; + break; + default: + pr_err("Tegra Unknown SKU %d\n", sku); + /* Using the default for the error case */ + break; + } +} + +void __init tegra124_init_speedo_data(struct tegra_sku_info *sku_info) +{ + int i, threshold, cpu_speedo_0_value, soc_speedo_0_value; + int cpu_iddq_value, gpu_iddq_value, soc_iddq_value; + + BUILD_BUG_ON(ARRAY_SIZE(cpu_process_speedos) != + THRESHOLD_INDEX_COUNT); + BUILD_BUG_ON(ARRAY_SIZE(gpu_process_speedos) != + THRESHOLD_INDEX_COUNT); + BUILD_BUG_ON(ARRAY_SIZE(core_process_speedos) != + THRESHOLD_INDEX_COUNT); + + cpu_speedo_0_value = tegra30_fuse_readl(FUSE_CPU_SPEEDO_0); + + /* GPU Speedo is stored in CPU_SPEEDO_2 */ + sku_info->gpu_speedo_value = tegra30_fuse_readl(FUSE_CPU_SPEEDO_2); + + soc_speedo_0_value = tegra30_fuse_readl(FUSE_SOC_SPEEDO_0); + + cpu_iddq_value = tegra30_fuse_readl(FUSE_CPU_IDDQ); + soc_iddq_value = tegra30_fuse_readl(FUSE_SOC_IDDQ); + gpu_iddq_value = tegra30_fuse_readl(FUSE_GPU_IDDQ); + + sku_info->cpu_speedo_value = cpu_speedo_0_value; + + if (sku_info->cpu_speedo_value == 0) { + pr_warn("Tegra Warning: Speedo value not fused.\n"); + WARN_ON(1); + return; + } + + rev_sku_to_speedo_ids(sku_info, &threshold); + + sku_info->cpu_iddq_value = tegra30_fuse_readl(FUSE_CPU_IDDQ); + + for (i = 0; i < GPU_PROCESS_CORNERS; i++) + if (sku_info->gpu_speedo_value < + gpu_process_speedos[threshold][i]) + break; + sku_info->gpu_process_id = i; + + for (i = 0; i < CPU_PROCESS_CORNERS; i++) + if (sku_info->cpu_speedo_value < + cpu_process_speedos[threshold][i]) + break; + sku_info->cpu_process_id = i; + + for (i = 0; i < CORE_PROCESS_CORNERS; i++) + if (soc_speedo_0_value < + core_process_speedos[threshold][i]) + break; + sku_info->core_process_id = i; + + pr_debug("Tegra GPU Speedo ID=%d, Speedo Value=%d\n", + sku_info->gpu_speedo_id, sku_info->gpu_speedo_value); +} diff --git a/drivers/soc/tegra/fuse/speedo-tegra20.c b/drivers/soc/tegra/fuse/speedo-tegra20.c new file mode 100644 index 00000000000..eff1b63f330 --- /dev/null +++ b/drivers/soc/tegra/fuse/speedo-tegra20.c @@ -0,0 +1,110 @@ +/* + * Copyright (c) 2012-2014, 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 . + */ + +#include +#include +#include + +#include + +#include "fuse.h" + +#define CPU_SPEEDO_LSBIT 20 +#define CPU_SPEEDO_MSBIT 29 +#define CPU_SPEEDO_REDUND_LSBIT 30 +#define CPU_SPEEDO_REDUND_MSBIT 39 +#define CPU_SPEEDO_REDUND_OFFS (CPU_SPEEDO_REDUND_MSBIT - CPU_SPEEDO_MSBIT) + +#define CORE_SPEEDO_LSBIT 40 +#define CORE_SPEEDO_MSBIT 47 +#define CORE_SPEEDO_REDUND_LSBIT 48 +#define CORE_SPEEDO_REDUND_MSBIT 55 +#define CORE_SPEEDO_REDUND_OFFS (CORE_SPEEDO_REDUND_MSBIT - CORE_SPEEDO_MSBIT) + +#define SPEEDO_MULT 4 + +#define PROCESS_CORNERS_NUM 4 + +#define SPEEDO_ID_SELECT_0(rev) ((rev) <= 2) +#define SPEEDO_ID_SELECT_1(sku) \ + (((sku) != 20) && ((sku) != 23) && ((sku) != 24) && \ + ((sku) != 27) && ((sku) != 28)) + +enum { + SPEEDO_ID_0, + SPEEDO_ID_1, + SPEEDO_ID_2, + SPEEDO_ID_COUNT, +}; + +static const u32 __initconst cpu_process_speedos[][PROCESS_CORNERS_NUM] = { + {315, 366, 420, UINT_MAX}, + {303, 368, 419, UINT_MAX}, + {316, 331, 383, UINT_MAX}, +}; + +static const u32 __initconst core_process_speedos[][PROCESS_CORNERS_NUM] = { + {165, 195, 224, UINT_MAX}, + {165, 195, 224, UINT_MAX}, + {165, 195, 224, UINT_MAX}, +}; + +void __init tegra20_init_speedo_data(struct tegra_sku_info *sku_info) +{ + u32 reg; + u32 val; + int i; + + BUILD_BUG_ON(ARRAY_SIZE(cpu_process_speedos) != SPEEDO_ID_COUNT); + BUILD_BUG_ON(ARRAY_SIZE(core_process_speedos) != SPEEDO_ID_COUNT); + + if (SPEEDO_ID_SELECT_0(sku_info->revision)) + sku_info->soc_speedo_id = SPEEDO_ID_0; + else if (SPEEDO_ID_SELECT_1(sku_info->sku_id)) + sku_info->soc_speedo_id = SPEEDO_ID_1; + else + sku_info->soc_speedo_id = SPEEDO_ID_2; + + val = 0; + for (i = CPU_SPEEDO_MSBIT; i >= CPU_SPEEDO_LSBIT; i--) { + reg = tegra20_spare_fuse_early(i) | + tegra20_spare_fuse_early(i + CPU_SPEEDO_REDUND_OFFS); + val = (val << 1) | (reg & 0x1); + } + val = val * SPEEDO_MULT; + pr_debug("Tegra CPU speedo value %u\n", val); + + for (i = 0; i < (PROCESS_CORNERS_NUM - 1); i++) { + if (val <= cpu_process_speedos[sku_info->soc_speedo_id][i]) + break; + } + sku_info->cpu_process_id = i; + + val = 0; + for (i = CORE_SPEEDO_MSBIT; i >= CORE_SPEEDO_LSBIT; i--) { + reg = tegra20_spare_fuse_early(i) | + tegra20_spare_fuse_early(i + CORE_SPEEDO_REDUND_OFFS); + val = (val << 1) | (reg & 0x1); + } + val = val * SPEEDO_MULT; + pr_debug("Core speedo value %u\n", val); + + for (i = 0; i < (PROCESS_CORNERS_NUM - 1); i++) { + if (val <= core_process_speedos[sku_info->soc_speedo_id][i]) + break; + } + sku_info->core_process_id = i; +} diff --git a/drivers/soc/tegra/fuse/speedo-tegra30.c b/drivers/soc/tegra/fuse/speedo-tegra30.c new file mode 100644 index 00000000000..b17f0dcdfeb --- /dev/null +++ b/drivers/soc/tegra/fuse/speedo-tegra30.c @@ -0,0 +1,288 @@ +/* + * Copyright (c) 2012-2014, 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 . + */ + +#include +#include +#include + +#include + +#include "fuse.h" + +#define CORE_PROCESS_CORNERS 1 +#define CPU_PROCESS_CORNERS 6 + +#define FUSE_SPEEDO_CALIB_0 0x14 +#define FUSE_PACKAGE_INFO 0XFC +#define FUSE_TEST_PROG_VER 0X28 + +#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 __initconst core_process_speedos[][CORE_PROCESS_CORNERS] = { + {180}, + {170}, + {195}, + {180}, + {168}, + {192}, + {180}, + {170}, + {195}, + {180}, + {180}, + {180}, +}; + +static const u32 __initconst cpu_process_speedos[][CPU_PROCESS_CORNERS] = { + {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 __initdata; + +static void __init fuse_speedo_calib(u32 *speedo_g, u32 *speedo_lp) +{ + u32 reg; + int ate_ver; + int bit_minus1; + int bit_minus2; + + reg = tegra30_fuse_readl(FUSE_SPEEDO_CALIB_0); + + *speedo_lp = (reg & 0xFFFF) * 4; + *speedo_g = ((reg >> 16) & 0xFFFF) * 4; + + ate_ver = tegra30_fuse_readl(FUSE_TEST_PROG_VER); + pr_debug("Tegra ATE prog ver %d.%d\n", ate_ver/10, ate_ver%10); + + if (ate_ver >= 26) { + bit_minus1 = tegra30_spare_fuse(LP_SPEEDO_BIT_MINUS1); + bit_minus1 |= tegra30_spare_fuse(LP_SPEEDO_BIT_MINUS1_R); + bit_minus2 = tegra30_spare_fuse(LP_SPEEDO_BIT_MINUS2); + bit_minus2 |= tegra30_spare_fuse(LP_SPEEDO_BIT_MINUS2_R); + *speedo_lp |= (bit_minus1 << 1) | bit_minus2; + + bit_minus1 = tegra30_spare_fuse(G_SPEEDO_BIT_MINUS1); + bit_minus1 |= tegra30_spare_fuse(G_SPEEDO_BIT_MINUS1_R); + bit_minus2 = tegra30_spare_fuse(G_SPEEDO_BIT_MINUS2); + bit_minus2 |= tegra30_spare_fuse(G_SPEEDO_BIT_MINUS2_R); + *speedo_g |= (bit_minus1 << 1) | bit_minus2; + } else { + *speedo_lp |= 0x3; + *speedo_g |= 0x3; + } +} + +static void __init rev_sku_to_speedo_ids(struct tegra_sku_info *sku_info) +{ + int package_id = tegra30_fuse_readl(FUSE_PACKAGE_INFO) & 0x0F; + + switch (sku_info->revision) { + case TEGRA_REVISION_A01: + sku_info->cpu_speedo_id = 0; + sku_info->soc_speedo_id = 0; + threshold_index = THRESHOLD_INDEX_0; + break; + case TEGRA_REVISION_A02: + case TEGRA_REVISION_A03: + switch (sku_info->sku_id) { + case 0x87: + case 0x82: + sku_info->cpu_speedo_id = 1; + sku_info->soc_speedo_id = 1; + threshold_index = THRESHOLD_INDEX_1; + break; + case 0x81: + switch (package_id) { + case 1: + sku_info->cpu_speedo_id = 2; + sku_info->soc_speedo_id = 2; + threshold_index = THRESHOLD_INDEX_2; + break; + case 2: + sku_info->cpu_speedo_id = 4; + sku_info->soc_speedo_id = 1; + threshold_index = THRESHOLD_INDEX_7; + break; + default: + pr_err("Tegra Unknown pkg %d\n", package_id); + break; + } + break; + case 0x80: + switch (package_id) { + case 1: + sku_info->cpu_speedo_id = 5; + sku_info->soc_speedo_id = 2; + threshold_index = THRESHOLD_INDEX_8; + break; + case 2: + sku_info->cpu_speedo_id = 6; + sku_info->soc_speedo_id = 2; + threshold_index = THRESHOLD_INDEX_9; + break; + default: + pr_err("Tegra Unknown pkg %d\n", package_id); + break; + } + break; + case 0x83: + switch (package_id) { + case 1: + sku_info->cpu_speedo_id = 7; + sku_info->soc_speedo_id = 1; + threshold_index = THRESHOLD_INDEX_10; + break; + case 2: + sku_info->cpu_speedo_id = 3; + sku_info->soc_speedo_id = 2; + threshold_index = THRESHOLD_INDEX_3; + break; + default: + pr_err("Tegra Unknown pkg %d\n", package_id); + break; + } + break; + case 0x8F: + sku_info->cpu_speedo_id = 8; + sku_info->soc_speedo_id = 1; + threshold_index = THRESHOLD_INDEX_11; + break; + case 0x08: + sku_info->cpu_speedo_id = 1; + sku_info->soc_speedo_id = 1; + threshold_index = THRESHOLD_INDEX_4; + break; + case 0x02: + sku_info->cpu_speedo_id = 2; + sku_info->soc_speedo_id = 2; + threshold_index = THRESHOLD_INDEX_5; + break; + case 0x04: + sku_info->cpu_speedo_id = 3; + sku_info->soc_speedo_id = 2; + threshold_index = THRESHOLD_INDEX_6; + break; + case 0: + switch (package_id) { + case 1: + sku_info->cpu_speedo_id = 2; + sku_info->soc_speedo_id = 2; + threshold_index = THRESHOLD_INDEX_2; + break; + case 2: + sku_info->cpu_speedo_id = 3; + sku_info->soc_speedo_id = 2; + threshold_index = THRESHOLD_INDEX_3; + break; + default: + pr_err("Tegra Unknown pkg %d\n", package_id); + break; + } + break; + default: + pr_warn("Tegra Unknown SKU %d\n", sku_info->sku_id); + sku_info->cpu_speedo_id = 0; + sku_info->soc_speedo_id = 0; + threshold_index = THRESHOLD_INDEX_0; + break; + } + break; + default: + pr_warn("Tegra Unknown chip rev %d\n", sku_info->revision); + sku_info->cpu_speedo_id = 0; + sku_info->soc_speedo_id = 0; + threshold_index = THRESHOLD_INDEX_0; + break; + } +} + +void __init tegra30_init_speedo_data(struct tegra_sku_info *sku_info) +{ + 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); + + + rev_sku_to_speedo_ids(sku_info); + fuse_speedo_calib(&cpu_speedo_val, &core_speedo_val); + pr_debug("Tegra CPU speedo value %u\n", cpu_speedo_val); + pr_debug("Tegra Core speedo value %u\n", core_speedo_val); + + for (i = 0; i < CPU_PROCESS_CORNERS; i++) { + if (cpu_speedo_val < cpu_process_speedos[threshold_index][i]) + break; + } + sku_info->cpu_process_id = i - 1; + + if (sku_info->cpu_process_id == -1) { + pr_warn("Tegra CPU speedo value %3d out of range", + cpu_speedo_val); + sku_info->cpu_process_id = 0; + sku_info->cpu_speedo_id = 1; + } + + for (i = 0; i < CORE_PROCESS_CORNERS; i++) { + if (core_speedo_val < core_process_speedos[threshold_index][i]) + break; + } + sku_info->core_process_id = i - 1; + + if (sku_info->core_process_id == -1) { + pr_warn("Tegra CORE speedo value %3d out of range", + core_speedo_val); + sku_info->core_process_id = 0; + sku_info->soc_speedo_id = 1; + } +} diff --git a/drivers/soc/tegra/fuse/tegra-apbmisc.c b/drivers/soc/tegra/fuse/tegra-apbmisc.c new file mode 100644 index 00000000000..bfc1d54ac4a --- /dev/null +++ b/drivers/soc/tegra/fuse/tegra-apbmisc.c @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2014, 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 . + * + */ + +#include +#include +#include +#include + +#include + +#include "fuse.h" + +#define APBMISC_BASE 0x70000800 +#define APBMISC_SIZE 0x64 +#define FUSE_SKU_INFO 0x10 + +static void __iomem *apbmisc_base; +static void __iomem *strapping_base; + +u32 tegra_read_chipid(void) +{ + return readl_relaxed(apbmisc_base + 4); +} + +u8 tegra_get_chip_id(void) +{ + u32 id = tegra_read_chipid(); + + return (id >> 8) & 0xff; +} + +u32 tegra_read_straps(void) +{ + if (strapping_base) + return readl_relaxed(strapping_base); + else + return 0; +} + +static const struct of_device_id apbmisc_match[] __initconst = { + { .compatible = "nvidia,tegra20-apbmisc", }, + {}, +}; + +void __init tegra_init_revision(void) +{ + u32 id, chip_id, minor_rev; + int rev; + + id = tegra_read_chipid(); + chip_id = (id >> 8) & 0xff; + minor_rev = (id >> 16) & 0xf; + + switch (minor_rev) { + case 1: + rev = TEGRA_REVISION_A01; + break; + case 2: + rev = TEGRA_REVISION_A02; + break; + case 3: + if (chip_id == TEGRA20 && (tegra20_spare_fuse_early(18) || + tegra20_spare_fuse_early(19))) + rev = TEGRA_REVISION_A03p; + else + rev = TEGRA_REVISION_A03; + break; + case 4: + rev = TEGRA_REVISION_A04; + break; + default: + rev = TEGRA_REVISION_UNKNOWN; + } + + tegra_sku_info.revision = rev; + + if (chip_id == TEGRA20) + tegra_sku_info.sku_id = tegra20_fuse_early(FUSE_SKU_INFO); + else + tegra_sku_info.sku_id = tegra30_fuse_readl(FUSE_SKU_INFO); +} + +void __init tegra_init_apbmisc(void) +{ + struct device_node *np; + + np = of_find_matching_node(NULL, apbmisc_match); + apbmisc_base = of_iomap(np, 0); + if (!apbmisc_base) { + pr_warn("ioremap tegra apbmisc failed. using %08x instead\n", + APBMISC_BASE); + apbmisc_base = ioremap(APBMISC_BASE, APBMISC_SIZE); + } + + strapping_base = of_iomap(np, 1); + if (!strapping_base) + pr_err("ioremap tegra strapping_base failed\n"); +} diff --git a/include/soc/tegra/fuse.h b/include/soc/tegra/fuse.h index 822eb348e10..51ac804deba 100644 --- a/include/soc/tegra/fuse.h +++ b/include/soc/tegra/fuse.h @@ -22,6 +22,9 @@ #define TEGRA114 0x35 #define TEGRA124 0x40 +#define TEGRA_FUSE_SKU_CALIB_0 0xf0 +#define TEGRA30_FUSE_SATA_CALIB 0x124 + #ifndef __ASSEMBLY__ u32 tegra_read_chipid(void); @@ -37,11 +40,26 @@ enum tegra_revision { TEGRA_REVISION_MAX, }; +struct tegra_sku_info { + int sku_id; + int cpu_process_id; + int cpu_speedo_id; + int cpu_speedo_value; + int cpu_iddq_value; + int core_process_id; + int soc_speedo_id; + int gpu_speedo_id; + int gpu_process_id; + int gpu_speedo_value; + enum tegra_revision revision; +}; + u32 tegra_read_straps(void); u32 tegra_read_chipid(void); void tegra_init_fuse(void); +int tegra_fuse_readl(unsigned long offset, u32 *value); -extern enum tegra_revision tegra_revision; +extern struct tegra_sku_info tegra_sku_info; #if defined(CONFIG_TEGRA20_APB_DMA) int tegra_apb_readl_using_dma(unsigned long offset, u32 *value); -- cgit v1.2.3-70-g09d2 From 0d827a4343b596b71a1741328c4e5687ce654e19 Mon Sep 17 00:00:00 2001 From: Peter De Schrijver Date: Thu, 12 Jun 2014 18:36:40 +0300 Subject: soc/tegra: fuse: move APB DMA into Tegra20 fuse driver The Tegra20 fuse driver is the only user of tegra_apb_readl_using_dma(). Therefore we can simply the code by incorporating the APB DMA handling into the driver directly. tegra_apb_writel_using_dma() is dropped because there are no users. Signed-off-by: Peter De Schrijver Signed-off-by: Stephen Warren Signed-off-by: Thierry Reding --- arch/arm/mach-tegra/Makefile | 1 - arch/arm/mach-tegra/apbio.c | 217 ---------------------------------- arch/arm/mach-tegra/apbio.h | 22 ---- arch/arm/mach-tegra/tegra.c | 2 - drivers/soc/tegra/fuse/fuse-tegra20.c | 79 ++++++++++++- include/soc/tegra/fuse.h | 14 --- 6 files changed, 76 insertions(+), 259 deletions(-) delete mode 100644 arch/arm/mach-tegra/apbio.c delete mode 100644 arch/arm/mach-tegra/apbio.h (limited to 'arch/arm/mach-tegra') diff --git a/arch/arm/mach-tegra/Makefile b/arch/arm/mach-tegra/Makefile index e8601bb56f9..c303b55de22 100644 --- a/arch/arm/mach-tegra/Makefile +++ b/arch/arm/mach-tegra/Makefile @@ -5,7 +5,6 @@ obj-y += irq.o obj-y += pmc.o obj-y += flowctrl.o obj-y += powergate.o -obj-y += apbio.o obj-y += pm.o obj-y += reset.o obj-y += reset-handler.o diff --git a/arch/arm/mach-tegra/apbio.c b/arch/arm/mach-tegra/apbio.c deleted file mode 100644 index f2488722c79..00000000000 --- a/arch/arm/mach-tegra/apbio.c +++ /dev/null @@ -1,217 +0,0 @@ -/* - * Copyright (C) 2010 NVIDIA Corporation. - * Copyright (C) 2010 Google, Inc. - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * This program is distributed in the hope that 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. - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "apbio.h" -#include "iomap.h" - -#if defined(CONFIG_TEGRA20_APB_DMA) -static DEFINE_MUTEX(tegra_apb_dma_lock); -static u32 *tegra_apb_bb; -static dma_addr_t tegra_apb_bb_phys; -static DECLARE_COMPLETION(tegra_apb_wait); - -static int tegra_apb_readl_direct(unsigned long offset, u32 *value); -static int tegra_apb_writel_direct(u32 value, unsigned long offset); - -static struct dma_chan *tegra_apb_dma_chan; -static struct dma_slave_config dma_sconfig; - -static bool tegra_apb_dma_init(void) -{ - dma_cap_mask_t mask; - - mutex_lock(&tegra_apb_dma_lock); - - /* Check to see if we raced to setup */ - if (tegra_apb_dma_chan) - goto skip_init; - - dma_cap_zero(mask); - dma_cap_set(DMA_SLAVE, mask); - tegra_apb_dma_chan = dma_request_channel(mask, NULL, NULL); - if (!tegra_apb_dma_chan) { - /* - * This is common until the device is probed, so don't - * shout about it. - */ - pr_debug("%s: can not allocate dma channel\n", __func__); - goto err_dma_alloc; - } - - tegra_apb_bb = dma_alloc_coherent(NULL, sizeof(u32), - &tegra_apb_bb_phys, GFP_KERNEL); - if (!tegra_apb_bb) { - pr_err("%s: can not allocate bounce buffer\n", __func__); - goto err_buff_alloc; - } - - dma_sconfig.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; - dma_sconfig.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; - dma_sconfig.src_maxburst = 1; - dma_sconfig.dst_maxburst = 1; - -skip_init: - mutex_unlock(&tegra_apb_dma_lock); - return true; - -err_buff_alloc: - dma_release_channel(tegra_apb_dma_chan); - tegra_apb_dma_chan = NULL; - -err_dma_alloc: - mutex_unlock(&tegra_apb_dma_lock); - return false; -} - -static void apb_dma_complete(void *args) -{ - complete(&tegra_apb_wait); -} - -static int do_dma_transfer(unsigned long apb_add, - enum dma_transfer_direction dir) -{ - struct dma_async_tx_descriptor *dma_desc; - int ret; - - if (dir == DMA_DEV_TO_MEM) - dma_sconfig.src_addr = apb_add; - else - dma_sconfig.dst_addr = apb_add; - - ret = dmaengine_slave_config(tegra_apb_dma_chan, &dma_sconfig); - if (ret) - return ret; - - dma_desc = dmaengine_prep_slave_single(tegra_apb_dma_chan, - tegra_apb_bb_phys, sizeof(u32), dir, - DMA_PREP_INTERRUPT | DMA_CTRL_ACK); - if (!dma_desc) - return -EINVAL; - - dma_desc->callback = apb_dma_complete; - dma_desc->callback_param = NULL; - - reinit_completion(&tegra_apb_wait); - - dmaengine_submit(dma_desc); - dma_async_issue_pending(tegra_apb_dma_chan); - ret = wait_for_completion_timeout(&tegra_apb_wait, - msecs_to_jiffies(50)); - - if (WARN(ret == 0, "apb read dma timed out")) { - dmaengine_terminate_all(tegra_apb_dma_chan); - return -EFAULT; - } - return 0; -} - -int tegra_apb_readl_using_dma(unsigned long offset, u32 *value) -{ - int ret; - - if (!tegra_apb_dma_chan && !tegra_apb_dma_init()) - return tegra_apb_readl_direct(offset, value); - - mutex_lock(&tegra_apb_dma_lock); - ret = do_dma_transfer(offset, DMA_DEV_TO_MEM); - if (ret < 0) - pr_err("error in reading offset 0x%08lx using dma\n", offset); - else - *value = *tegra_apb_bb; - - mutex_unlock(&tegra_apb_dma_lock); - - return ret; -} - -int tegra_apb_writel_using_dma(u32 value, unsigned long offset) -{ - int ret; - - if (!tegra_apb_dma_chan && !tegra_apb_dma_init()) - return tegra_apb_writel_direct(value, offset); - - mutex_lock(&tegra_apb_dma_lock); - *((u32 *)tegra_apb_bb) = value; - ret = do_dma_transfer(offset, DMA_MEM_TO_DEV); - mutex_unlock(&tegra_apb_dma_lock); - if (ret < 0) - pr_err("error in writing offset 0x%08lx using dma\n", offset); - - return ret; -} -#else -#define tegra_apb_readl_using_dma tegra_apb_readl_direct -#define tegra_apb_writel_using_dma tegra_apb_writel_direct -#endif - -typedef int (*apbio_read_fptr)(unsigned long offset, u32 *value); -typedef int (*apbio_write_fptr)(u32 value, unsigned long offset); - -static apbio_read_fptr apbio_read; -static apbio_write_fptr apbio_write; - -static int tegra_apb_readl_direct(unsigned long offset, u32 *value) -{ - *value = readl(IO_ADDRESS(offset)); - - return 0; -} - -static int tegra_apb_writel_direct(u32 value, unsigned long offset) -{ - writel(value, IO_ADDRESS(offset)); - - return 0; -} - -void tegra_apb_io_init(void) -{ - /* Need to use dma only when it is Tegra20 based platform */ - if (of_machine_is_compatible("nvidia,tegra20") || - !of_have_populated_dt()) { - apbio_read = tegra_apb_readl_using_dma; - apbio_write = tegra_apb_writel_using_dma; - } else { - apbio_read = tegra_apb_readl_direct; - apbio_write = tegra_apb_writel_direct; - } -} - -u32 tegra_apb_readl(unsigned long offset) -{ - u32 val; - - if (apbio_read(offset, &val) < 0) - return 0; - else - return val; -} - -void tegra_apb_writel(u32 value, unsigned long offset) -{ - apbio_write(value, offset); -} diff --git a/arch/arm/mach-tegra/apbio.h b/arch/arm/mach-tegra/apbio.h deleted file mode 100644 index f05d71c303c..00000000000 --- a/arch/arm/mach-tegra/apbio.h +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright (C) 2010 NVIDIA Corporation. - * Copyright (C) 2010 Google, Inc. - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * This program is distributed in the hope that 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. - * - */ - -#ifndef __MACH_TEGRA_APBIO_H -#define __MACH_TEGRA_APBIO_H - -void tegra_apb_io_init(void); -u32 tegra_apb_readl(unsigned long offset); -void tegra_apb_writel(u32 value, unsigned long offset); -#endif diff --git a/arch/arm/mach-tegra/tegra.c b/arch/arm/mach-tegra/tegra.c index c0faae8c082..6ccbc8ca1db 100644 --- a/arch/arm/mach-tegra/tegra.c +++ b/arch/arm/mach-tegra/tegra.c @@ -44,7 +44,6 @@ #include #include -#include "apbio.h" #include "board.h" #include "common.h" #include "cpuidle.h" @@ -74,7 +73,6 @@ u32 tegra_uart_config[3] = { static void __init tegra_init_early(void) { of_register_trusted_foundations(); - tegra_apb_io_init(); tegra_init_fuse(); tegra_cpu_reset_handler_init(); tegra_powergate_init(); diff --git a/drivers/soc/tegra/fuse/fuse-tegra20.c b/drivers/soc/tegra/fuse/fuse-tegra20.c index 7a9d0e04549..7cb63ab6aac 100644 --- a/drivers/soc/tegra/fuse/fuse-tegra20.c +++ b/drivers/soc/tegra/fuse/fuse-tegra20.c @@ -18,6 +18,9 @@ #include #include +#include +#include +#include #include #include #include @@ -39,18 +42,58 @@ static phys_addr_t fuse_phys; static struct clk *fuse_clk; static void __iomem __initdata *fuse_base; +static DEFINE_MUTEX(apb_dma_lock); +static DECLARE_COMPLETION(apb_dma_wait); +static struct dma_chan *apb_dma_chan; +static struct dma_slave_config dma_sconfig; +static u32 *apb_buffer; +static dma_addr_t apb_buffer_phys; + +static void apb_dma_complete(void *args) +{ + complete(&apb_dma_wait); +} + static u32 tegra20_fuse_readl(const unsigned int offset) { int ret; - u32 val; + u32 val = 0; + struct dma_async_tx_descriptor *dma_desc; + + mutex_lock(&apb_dma_lock); + + dma_sconfig.src_addr = fuse_phys + FUSE_BEGIN + offset; + ret = dmaengine_slave_config(apb_dma_chan, &dma_sconfig); + if (ret) + goto out; + + dma_desc = dmaengine_prep_slave_single(apb_dma_chan, apb_buffer_phys, + sizeof(u32), DMA_DEV_TO_MEM, + DMA_PREP_INTERRUPT | DMA_CTRL_ACK); + if (!dma_desc) + goto out; + + dma_desc->callback = apb_dma_complete; + dma_desc->callback_param = NULL; + + reinit_completion(&apb_dma_wait); clk_prepare_enable(fuse_clk); - ret = tegra_apb_readl_using_dma(fuse_phys + FUSE_BEGIN + offset, &val); + dmaengine_submit(dma_desc); + dma_async_issue_pending(apb_dma_chan); + ret = wait_for_completion_timeout(&apb_dma_wait, msecs_to_jiffies(50)); + + if (WARN(ret == 0, "apb read dma timed out")) + dmaengine_terminate_all(apb_dma_chan); + else + val = *apb_buffer; clk_disable_unprepare(fuse_clk); +out: + mutex_unlock(&apb_dma_lock); - return (ret < 0) ? 0 : val; + return val; } static const struct of_device_id tegra20_fuse_of_match[] = { @@ -58,9 +101,35 @@ static const struct of_device_id tegra20_fuse_of_match[] = { {}, }; +static int apb_dma_init(void) +{ + dma_cap_mask_t mask; + + dma_cap_zero(mask); + dma_cap_set(DMA_SLAVE, mask); + apb_dma_chan = dma_request_channel(mask, NULL, NULL); + if (!apb_dma_chan) + return -EPROBE_DEFER; + + apb_buffer = dma_alloc_coherent(NULL, sizeof(u32), &apb_buffer_phys, + GFP_KERNEL); + if (!apb_buffer) { + dma_release_channel(apb_dma_chan); + return -ENOMEM; + } + + dma_sconfig.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; + dma_sconfig.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; + dma_sconfig.src_maxburst = 1; + dma_sconfig.dst_maxburst = 1; + + return 0; +} + static int tegra20_fuse_probe(struct platform_device *pdev) { struct resource *res; + int err; fuse_clk = devm_clk_get(&pdev->dev, NULL); if (IS_ERR(fuse_clk)) { @@ -73,6 +142,10 @@ static int tegra20_fuse_probe(struct platform_device *pdev) return -EINVAL; fuse_phys = res->start; + err = apb_dma_init(); + if (err) + return err; + if (tegra_fuse_create_sysfs(&pdev->dev, FUSE_SIZE, tegra20_fuse_readl)) return -ENODEV; diff --git a/include/soc/tegra/fuse.h b/include/soc/tegra/fuse.h index 51ac804deba..738712d75cf 100644 --- a/include/soc/tegra/fuse.h +++ b/include/soc/tegra/fuse.h @@ -61,20 +61,6 @@ int tegra_fuse_readl(unsigned long offset, u32 *value); extern struct tegra_sku_info tegra_sku_info; -#if defined(CONFIG_TEGRA20_APB_DMA) -int tegra_apb_readl_using_dma(unsigned long offset, u32 *value); -int tegra_apb_writel_using_dma(u32 value, unsigned long offset); -#else -static inline int tegra_apb_readl_using_dma(unsigned long offset, u32 *value) -{ - return -EINVAL; -} -static inline int tegra_apb_writel_using_dma(u32 value, unsigned long offset) -{ - return -EINVAL; -} -#endif /* CONFIG_TEGRA20_APB_DMA */ - #endif /* __ASSEMBLY__ */ #endif /* __SOC_TEGRA_FUSE_H__ */ -- cgit v1.2.3-70-g09d2