summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVarun Wadekar <vwadekar@nvidia.com>2012-01-03 15:04:40 +0530
committerGerrit <chrome-bot@google.com>2012-02-14 22:03:49 -0800
commitf8cc6a4a71cb1ccba84977f0762eefbc960091f4 (patch)
tree0c28785a6fbed4277223d5882d92c7e8ffc5db8d
parentdebacb801479e992807f7e0d81f52932b0d7e9a2 (diff)
arm: tegra2: split LP0 code to help future chips
split the LP0 code for tegra2 into common LP0 code and chip specific warm boot code BUG=chromium-os:23496 TEST=build for Seaboard Change-Id: Ie04bf9ac17482a37afd0f4515dc3aafeb4f48ae7 Signed-off-by: Varun Wadekar <vwadekar@nvidia.com> Reviewed-on: https://gerrit.chromium.org/gerrit/15883
-rw-r--r--arch/arm/cpu/armv7/tegra-common/Makefile1
-rw-r--r--arch/arm/cpu/armv7/tegra-common/ap20.c2
-rw-r--r--arch/arm/cpu/armv7/tegra-common/warmboot.c241
-rw-r--r--arch/arm/cpu/armv7/tegra2/Makefile4
-rw-r--r--arch/arm/cpu/armv7/tegra2/warmboot.c213
-rw-r--r--arch/arm/include/asm/arch-tegra/warmboot.h4
-rw-r--r--board/nvidia/common/Makefile4
-rw-r--r--board/nvidia/common/board.c2
-rw-r--r--include/configs/seaboard.h5
-rw-r--r--include/configs/tegra2-common.h2
10 files changed, 255 insertions, 223 deletions
diff --git a/arch/arm/cpu/armv7/tegra-common/Makefile b/arch/arm/cpu/armv7/tegra-common/Makefile
index 9e8446ef22f..0b43404acf4 100644
--- a/arch/arm/cpu/armv7/tegra-common/Makefile
+++ b/arch/arm/cpu/armv7/tegra-common/Makefile
@@ -33,6 +33,7 @@ LIB = $(obj)libtegra-common.o
SOBJS-y := lowlevel_init.o
COBJS-y := ap20.o board.o clock.o power.o timer.o
COBJS-$(CONFIG_VIDEO_TEGRA) += display.o pwfm.o
+COBJS-$(CONFIG_TEGRA_LP0) += warmboot.o
SOBJS := $(SOBJS-y)
COBJS := $(COBJS-y)
diff --git a/arch/arm/cpu/armv7/tegra-common/ap20.c b/arch/arm/cpu/armv7/tegra-common/ap20.c
index 529ce84860b..517fba30b15 100644
--- a/arch/arm/cpu/armv7/tegra-common/ap20.c
+++ b/arch/arm/cpu/armv7/tegra-common/ap20.c
@@ -559,7 +559,7 @@ void init_pmc_scratch(void)
/* ODMDATA is for kernel use to determine RAM size, LP config, etc. */
writel(CONFIG_SYS_BOARD_ODMDATA, &pmc->pmc_scratch20);
-#ifdef CONFIG_TEGRA2_LP0
+#ifdef CONFIG_TEGRA_LP0
/* save Sdram params to PMC 2, 4, and 24 for WB0 */
warmboot_save_sdram_params();
#endif
diff --git a/arch/arm/cpu/armv7/tegra-common/warmboot.c b/arch/arm/cpu/armv7/tegra-common/warmboot.c
new file mode 100644
index 00000000000..beb7a146edc
--- /dev/null
+++ b/arch/arm/cpu/armv7/tegra-common/warmboot.c
@@ -0,0 +1,241 @@
+/*
+ * (C) Copyright 2010 - 2011
+ * NVIDIA Corporation <www.nvidia.com>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <asm/errno.h>
+
+#include <asm/arch-tegra/ap20.h>
+#include <asm/arch-tegra/fuse.h>
+#include <asm/arch-tegra/bitfield.h>
+#include <asm/arch-tegra/warmboot.h>
+
+#include <asm/arch/gp_padctrl.h>
+
+/*
+ * NOTE: If more than one of the following is enabled, only one of them will
+ * actually be used. RANDOM takes precedence over PATTERN and ZERO, and
+ * PATTERN takes precedence overy ZERO.
+ *
+ * RANDOM_AES_BLOCK_IS_PATTERN is to define a 32-bit PATTERN.
+ */
+#define RANDOM_AES_BLOCK_IS_RANDOM /* to randomize the header */
+#undef RANDOM_AES_BLOCK_IS_PATTERN /* to patternize the header */
+#undef RANDOM_AES_BLOCK_IS_ZERO /* to clear the header */
+
+static u32 get_major_version(void)
+{
+ u32 major_id;
+ struct apb_misc_gp_ctlr *gp =
+ (struct apb_misc_gp_ctlr *)NV_PA_APB_MISC_GP_BASE;
+
+ major_id = bf_readl(HIDREV_MAJORPREV, &gp->hidrev);
+ return major_id;
+}
+
+static int is_production_mode_fuse_set(struct fuse_regs *fuse)
+{
+ return readl(&fuse->production_mode);
+}
+
+static int is_odm_production_mode_fuse_set(struct fuse_regs *fuse)
+{
+ return readl(&fuse->security_mode);
+}
+
+static int is_failure_analysis_mode(struct fuse_regs *fuse)
+{
+ return readl(&fuse->fa);
+}
+
+static int is_odm_production_mode(void)
+{
+ struct fuse_regs *fuse = (struct fuse_regs *)NV_PA_FUSE_BASE;
+
+ if (!is_failure_analysis_mode(fuse) &&
+ is_odm_production_mode_fuse_set(fuse))
+ return 1;
+ else
+ return 0;
+}
+
+static int is_production_mode(void)
+{
+ struct fuse_regs *fuse = (struct fuse_regs *)NV_PA_FUSE_BASE;
+
+ if (get_major_version() == 0)
+ return 1;
+
+ if (!is_failure_analysis_mode(fuse) &&
+ is_production_mode_fuse_set(fuse) &&
+ !is_odm_production_mode_fuse_set(fuse))
+ return 1;
+ else
+ return 0;
+}
+
+static enum fuse_operating_mode fuse_get_operation_mode(void)
+{
+ u32 chip_id;
+ struct apb_misc_gp_ctlr *gp =
+ (struct apb_misc_gp_ctlr *)NV_PA_APB_MISC_GP_BASE;
+
+ chip_id = bf_readl(HIDREV_CHIPID, &gp->hidrev);
+ if (chip_id == CHIPID_TEGRA2) {
+ if (is_odm_production_mode()) {
+ printf("!! odm_production_mode is not supported !!\n");
+ return MODE_UNDEFINED;
+ } else
+ if (is_production_mode())
+ return MODE_PRODUCTION;
+ else
+ return MODE_UNDEFINED;
+ }
+ return MODE_UNDEFINED;
+}
+
+/* Currently, this routine returns a 32-bit all 0 seed. */
+static u32 query_random_seed(void)
+{
+ return 0;
+}
+
+static void determine_crypto_options(int *is_encrypted, int *is_signed,
+ int *use_zero_key)
+{
+ switch (fuse_get_operation_mode()) {
+ case MODE_PRODUCTION:
+ *is_encrypted = 0;
+ *is_signed = 1;
+ *use_zero_key = 1;
+ break;
+ case MODE_UNDEFINED:
+ default:
+ *is_encrypted = 0;
+ *is_signed = 0;
+ *use_zero_key = 0;
+ break;
+ }
+}
+
+static int sign_wb_code(u32 start, u32 length, int use_zero_key)
+{
+ int err;
+ u8 *source; /* Pointer to source */
+ u8 *hash;
+
+ /* Calculate AES block parameters. */
+ source = (u8 *)(start + offsetof(struct wb_header, random_aes_block));
+ length -= offsetof(struct wb_header, random_aes_block);
+ hash = (u8 *)(start + offsetof(struct wb_header, hash));
+ err = sign_data_block(source, length, hash);
+
+ return err;
+}
+
+int warmboot_prepare_code(u32 seg_address, u32 seg_length)
+{
+ int err = 0;
+ u32 length; /* length of the signed/encrypt code */
+ struct wb_header *dst_header; /* Pointer to dest WB header */
+ int is_encrypted; /* Segment is encrypted */
+ int is_signed; /* Segment is signed */
+ int use_zero_key; /* Use key of all zeros */
+
+ /* Determine crypto options. */
+ determine_crypto_options(&is_encrypted, &is_signed, &use_zero_key);
+
+ /* Get the actual code limits. */
+ length = roundup(((u32)wb_end - (u32)wb_start), 16);
+
+ /*
+ * The region specified by seg_address must not be in IRAM and must be
+ * nonzero in length.
+ */
+ if ((seg_length == 0) || (seg_address == 0)) {
+ err = -EFAULT;
+ goto fail;
+ }
+
+ /* Things must be 16-byte aligned. */
+ if ((seg_length & 0xF) || (seg_address & 0xF)) {
+ err = -EINVAL;
+ goto fail;
+ }
+
+ /* Will the code fit? (destination includes wb_header + wb code) */
+ if (seg_length < (length + sizeof(struct wb_header))) {
+ err = -EINVAL;
+ goto fail;
+ }
+
+ dst_header = (struct wb_header *)seg_address;
+ memset((char *)dst_header, 0, sizeof(struct wb_header));
+
+ /* Populate the random_aes_block as requested. */
+ {
+ u32 *aes_block = (u32 *)&(dst_header->random_aes_block);
+ u32 *end = (u32 *)(((u32)aes_block) +
+ sizeof(dst_header->random_aes_block));
+
+ do {
+#if defined(RANDOM_AES_BLOCK_IS_RANDOM)
+ *aes_block++ = query_random_seed();
+#elif defined(RANDOM_AES_BLOCK_IS_PATTERN)
+ *aes_block++ = RANDOM_AES_BLOCK_IS_PATTERN;
+#elif defined(RANDOM_AES_BLOCK_IS_ZERO)
+ *aes_block++ = 0;
+#else
+ printf("None of RANDOM_AES_BLOCK_IS_XXX is defined; ");
+ printf("Default to pattern 0.\n");
+ *aes_block++ = 0;
+#endif
+ } while (aes_block < end);
+ }
+
+ /* Populate the header. */
+ dst_header->length_in_secure = length + sizeof(struct wb_header);
+ dst_header->length_secure = length + sizeof(struct wb_header);
+ dst_header->destination = AP20_WB_RUN_ADDRESS;
+ dst_header->entry_point = AP20_WB_RUN_ADDRESS;
+ dst_header->code_length = length;
+
+ if (is_encrypted) {
+ printf("!!!! Encryption is not supported !!!!\n");
+ dst_header->length_in_secure = 0;
+ err = -EACCES;
+ goto fail;
+ } else
+ /* copy the wb code directly following dst_header. */
+ memcpy((char *)(dst_header+1), (char *)wb_start, length);
+
+ if (is_signed)
+ err = sign_wb_code(seg_address, dst_header->length_in_secure,
+ use_zero_key);
+
+fail:
+ if (err)
+ printf("WB code not copied to LP0 location! (error=%d)\n", err);
+
+ return err;
+}
diff --git a/arch/arm/cpu/armv7/tegra2/Makefile b/arch/arm/cpu/armv7/tegra2/Makefile
index 0c1f989de1d..cb5c2611071 100644
--- a/arch/arm/cpu/armv7/tegra2/Makefile
+++ b/arch/arm/cpu/armv7/tegra2/Makefile
@@ -34,10 +34,8 @@ LIB = $(obj)lib$(SOC).o
SOBJS-y :=
COBJS-y := board.o pinmux.o sys_info.o
-
-COBJS-$(CONFIG_TEGRA2_LP0) += warmboot.o
-COBJS-$(CONFIG_TEGRA2_LP0) += warmboot_avp.o
COBJS-$(CONFIG_VIDEO_TEGRA) += display.o
+COBJS-$(CONFIG_TEGRA2_WARMBOOT) += warmboot.o warmboot_avp.o
SOBJS := $(SOBJS-y)
COBJS := $(COBJS-y)
diff --git a/arch/arm/cpu/armv7/tegra2/warmboot.c b/arch/arm/cpu/armv7/tegra2/warmboot.c
index 69c01d297b1..6cecec3c27b 100644
--- a/arch/arm/cpu/armv7/tegra2/warmboot.c
+++ b/arch/arm/cpu/armv7/tegra2/warmboot.c
@@ -39,10 +39,6 @@
#include <asm/arch/tegra.h>
#include <asm/arch-tegra/warmboot.h>
-#define BCT_OFFSET 0x100 /* BCT starts at 0x100 */
-#define BCT_SDRAM_PARAMS_OFFSET (BCT_OFFSET + 0x88)
-#define SDRAM_PARAMS_BASE (AP20_BASE_PA_SRAM + BCT_SDRAM_PARAMS_OFFSET)
-
union osc_ctrl_reg {
struct {
u32 xoe:1;
@@ -233,212 +229,3 @@ void warmboot_save_sdram_params(void)
scratch24.warmboot_wait = sdram.warm_boot_wait;
writel(scratch24.word, &pmc->pmc_scratch24);
}
-
-/*
- * NOTE: If more than one of the following is enabled, only one of them will
- * actually be used. RANDOM takes precedence over PATTERN and ZERO, and
- * PATTERN takes precedence overy ZERO.
- *
- * RANDOM_AES_BLOCK_IS_PATTERN is to define a 32-bit PATTERN.
- */
-#define RANDOM_AES_BLOCK_IS_RANDOM /* to randomize the header */
-#undef RANDOM_AES_BLOCK_IS_PATTERN /* to patternize the header */
-#undef RANDOM_AES_BLOCK_IS_ZERO /* to clear the header */
-
-static u32 get_major_version(void)
-{
- u32 major_id;
- struct apb_misc_gp_ctlr *gp =
- (struct apb_misc_gp_ctlr *)NV_PA_APB_MISC_GP_BASE;
-
- major_id = bf_readl(HIDREV_MAJORPREV, &gp->hidrev);
- return major_id;
-}
-
-static int is_production_mode_fuse_set(struct fuse_regs *fuse)
-{
- return readl(&fuse->production_mode);
-}
-
-static int is_odm_production_mode_fuse_set(struct fuse_regs *fuse)
-{
- return readl(&fuse->security_mode);
-}
-
-static int is_failure_analysis_mode(struct fuse_regs *fuse)
-{
- return readl(&fuse->fa);
-}
-
-static int ap20_is_odm_production_mode(void)
-{
- struct fuse_regs *fuse = (struct fuse_regs *)NV_PA_FUSE_BASE;
-
- if (!is_failure_analysis_mode(fuse) &&
- is_odm_production_mode_fuse_set(fuse))
- return 1;
- else
- return 0;
-}
-
-static int ap20_is_production_mode(void)
-{
- struct fuse_regs *fuse = (struct fuse_regs *)NV_PA_FUSE_BASE;
-
- if (get_major_version() == 0)
- return 1;
-
- if (!is_failure_analysis_mode(fuse) &&
- is_production_mode_fuse_set(fuse) &&
- !is_odm_production_mode_fuse_set(fuse))
- return 1;
- else
- return 0;
-}
-
-static enum fuse_operating_mode fuse_get_operation_mode(void)
-{
- u32 chip_id;
- struct apb_misc_gp_ctlr *gp =
- (struct apb_misc_gp_ctlr *)NV_PA_APB_MISC_GP_BASE;
-
- chip_id = bf_readl(HIDREV_CHIPID, &gp->hidrev);
- if (chip_id == CHIPID_TEGRA2) {
- if (ap20_is_odm_production_mode()) {
- printf("!! odm_production_mode is not supported !!\n");
- return MODE_UNDEFINED;
- } else
- if (ap20_is_production_mode())
- return MODE_PRODUCTION;
- else
- return MODE_UNDEFINED;
- }
- return MODE_UNDEFINED;
-}
-
-/* Currently, this routine returns a 32-bit all 0 seed. */
-static u32 query_random_seed(void)
-{
- return 0;
-}
-
-static void determine_crypto_options(int *is_encrypted, int *is_signed,
- int *use_zero_key)
-{
- switch (fuse_get_operation_mode()) {
- case MODE_PRODUCTION:
- *is_encrypted = 0;
- *is_signed = 1;
- *use_zero_key = 1;
- break;
- case MODE_UNDEFINED:
- default:
- *is_encrypted = 0;
- *is_signed = 0;
- *use_zero_key = 0;
- break;
- }
-}
-
-static int sign_wb_code(u32 start, u32 length, int use_zero_key)
-{
- int err;
- u8 *source; /* Pointer to source */
- u8 *hash;
-
- /* Calculate AES block parameters. */
- source = (u8 *)(start + offsetof(struct wb_header, random_aes_block));
- length -= offsetof(struct wb_header, random_aes_block);
- hash = (u8 *)(start + offsetof(struct wb_header, hash));
- err = sign_data_block(source, length, hash);
-
- return err;
-}
-
-int warmboot_prepare_code(u32 seg_address, u32 seg_length)
-{
- int err = 0;
- u32 length; /* length of the signed/encrypt code */
- struct wb_header *dst_header; /* Pointer to dest WB header */
- int is_encrypted; /* Segment is encrypted */
- int is_signed; /* Segment is signed */
- int use_zero_key; /* Use key of all zeros */
-
- /* Determine crypto options. */
- determine_crypto_options(&is_encrypted, &is_signed, &use_zero_key);
-
- /* Get the actual code limits. */
- length = roundup(((u32)wb_end - (u32)wb_start), 16);
-
- /*
- * The region specified by seg_address must not be in IRAM and must be
- * nonzero in length.
- */
- if ((seg_length == 0) || (seg_address == 0) ||
- (seg_address >= AP20_BASE_PA_SRAM)) {
- err = -EFAULT;
- goto fail;
- }
-
- /* Things must be 16-byte aligned. */
- if ((seg_length & 0xF) || (seg_address & 0xF)) {
- err = -EINVAL;
- goto fail;
- }
-
- /* Will the code fit? (destination includes wb_header + wb code) */
- if (seg_length < (length + sizeof(struct wb_header))) {
- err = -EINVAL;
- goto fail;
- }
-
- dst_header = (struct wb_header *)seg_address;
- memset((char *)dst_header, 0, sizeof(struct wb_header));
-
- /* Populate the random_aes_block as requested. */
- {
- u32 *aes_block = (u32 *)&(dst_header->random_aes_block);
- u32 *end = (u32 *)(((u32)aes_block) +
- sizeof(dst_header->random_aes_block));
-
- do {
-#if defined(RANDOM_AES_BLOCK_IS_RANDOM)
- *aes_block++ = query_random_seed();
-#elif defined(RANDOM_AES_BLOCK_IS_PATTERN)
- *aes_block++ = RANDOM_AES_BLOCK_IS_PATTERN;
-#elif defined(RANDOM_AES_BLOCK_IS_ZERO)
- *aes_block++ = 0;
-#else
- printf("None of RANDOM_AES_BLOCK_IS_XXX is defined; ");
- printf("Default to pattern 0.\n");
- *aes_block++ = 0;
-#endif
- } while (aes_block < end);
- }
-
- /* Populate the header. */
- dst_header->length_in_secure = length + sizeof(struct wb_header);
- dst_header->length_secure = length + sizeof(struct wb_header);
- dst_header->destination = AP20_WB_RUN_ADDRESS;
- dst_header->entry_point = AP20_WB_RUN_ADDRESS;
- dst_header->code_length = length;
-
- if (is_encrypted) {
- printf("!!!! Encryption is not supported !!!!\n");
- dst_header->length_in_secure = 0;
- err = -EACCES;
- goto fail;
- } else
- /* copy the wb code directly following dst_header. */
- memcpy((char *)(dst_header+1), (char *)wb_start, length);
-
- if (is_signed)
- err = sign_wb_code(seg_address, dst_header->length_in_secure,
- use_zero_key);
-
-fail:
- if (err)
- printf("WB code not copied to LP0 location! (error=%d)\n", err);
-
- return err;
-}
diff --git a/arch/arm/include/asm/arch-tegra/warmboot.h b/arch/arm/include/asm/arch-tegra/warmboot.h
index a47b21ef1a7..c1a9a159299 100644
--- a/arch/arm/include/asm/arch-tegra/warmboot.h
+++ b/arch/arm/include/asm/arch-tegra/warmboot.h
@@ -24,6 +24,10 @@
#ifndef _WARM_BOOT_H_
#define _WARM_BOOT_H_
+#define BCT_OFFSET 0x100 /* BCT starts at 0x100 */
+#define BCT_SDRAM_PARAMS_OFFSET (BCT_OFFSET + 0x88)
+#define SDRAM_PARAMS_BASE (AP20_BASE_PA_SRAM + BCT_SDRAM_PARAMS_OFFSET)
+
/* bit fields definitions for APB_MISC_GP_HIDREV register */
#define HIDREV_MINOPREV_RANGE 19 : 16
#define HIDREV_CHIPID_RANGE 15 : 8
diff --git a/board/nvidia/common/Makefile b/board/nvidia/common/Makefile
index cd821ebb072..48d04b494d5 100644
--- a/board/nvidia/common/Makefile
+++ b/board/nvidia/common/Makefile
@@ -31,8 +31,8 @@ COBJS-$(CONFIG_SPI_UART_SWITCH) += uart-spi-fix.o
COBJS-$(CONFIG_TEGRA_CLOCK_SCALING) += emc.o
COBJS-$(CONFIG_TEGRA_PMU) += pmu.o
COBJS-$(CONFIG_TEGRA_KEYBOARD) += generic_kbc.o
-COBJS-$(CONFIG_TEGRA2_LP0) += crypto/aes_ref.o
-COBJS-$(CONFIG_TEGRA2_LP0) += crypto/crypto.o
+COBJS-$(CONFIG_TEGRA_LP0) += crypto/aes_ref.o
+COBJS-$(CONFIG_TEGRA_LP0) += crypto/crypto.o
COBJS-$(CONFIG_TEGRA2_NAND) += tegra2_nand.o
COBJS := $(COBJS-y)
diff --git a/board/nvidia/common/board.c b/board/nvidia/common/board.c
index 4e517deda86..5cb219b4f92 100644
--- a/board/nvidia/common/board.c
+++ b/board/nvidia/common/board.c
@@ -346,7 +346,7 @@ int board_init(void)
board_emc_init();
#endif
-#ifdef CONFIG_TEGRA2_LP0
+#ifdef CONFIG_TEGRA_LP0
/* prepare the WB code to LP0 location */
warmboot_prepare_code(TEGRA_LP0_ADDR, TEGRA_LP0_SIZE);
#endif
diff --git a/include/configs/seaboard.h b/include/configs/seaboard.h
index 73ceadd10fe..5e68faca3fd 100644
--- a/include/configs/seaboard.h
+++ b/include/configs/seaboard.h
@@ -27,10 +27,11 @@
#include <asm/sizes.h>
-#define CONFIG_TEGRA2_LP0
-
#define CONFIG_SPI_UART_SWITCH
+#define CONFIG_TEGRA_LP0
+#define CONFIG_TEGRA2_WARMBOOT
+
/* High-level configuration options */
#define TEGRA2_SYSMEM "mem=1024M@0M"
#define V_PROMPT "Tegra2 # "
diff --git a/include/configs/tegra2-common.h b/include/configs/tegra2-common.h
index 7dc3d7208f2..22cff46acc4 100644
--- a/include/configs/tegra2-common.h
+++ b/include/configs/tegra2-common.h
@@ -106,7 +106,7 @@
#define CONFIG_SYS_NO_FLASH
-#ifdef CONFIG_TEGRA2_LP0
+#ifdef CONFIG_TEGRA2_WARMBOOT
#define TEGRA_LP0_ADDR 0x1C406000
#define TEGRA_LP0_SIZE 0x2000
#define TEGRA_LP0_VEC \