summaryrefslogtreecommitdiff
path: root/arch/arm/mach-tegra
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/mach-tegra')
-rw-r--r--arch/arm/mach-tegra/Kconfig2
-rw-r--r--arch/arm/mach-tegra/ap.c8
-rw-r--r--arch/arm/mach-tegra/cpu.h1
-rw-r--r--arch/arm/mach-tegra/crypto.c184
-rw-r--r--arch/arm/mach-tegra/fuse.c63
-rw-r--r--arch/arm/mach-tegra/tegra114/Kconfig5
-rw-r--r--arch/arm/mach-tegra/tegra124/bct.c20
-rw-r--r--arch/arm/mach-tegra/tegra20/Kconfig5
-rw-r--r--arch/arm/mach-tegra/tegra20/bct.c20
-rw-r--r--arch/arm/mach-tegra/tegra20/warmboot.c117
-rw-r--r--arch/arm/mach-tegra/tegra30/Kconfig5
-rw-r--r--arch/arm/mach-tegra/tegra30/bct.c20
12 files changed, 177 insertions, 273 deletions
diff --git a/arch/arm/mach-tegra/Kconfig b/arch/arm/mach-tegra/Kconfig
index c3c352eceb1..32cdfebfc01 100644
--- a/arch/arm/mach-tegra/Kconfig
+++ b/arch/arm/mach-tegra/Kconfig
@@ -17,7 +17,9 @@ config TEGRA_CLKRST
config TEGRA_CRYPTO
bool "Tegra AES128 crypto module"
+ select DM_AES
select AES
+ select TEGRA_AES
config TEGRA_GP_PADCTRL
bool
diff --git a/arch/arm/mach-tegra/ap.c b/arch/arm/mach-tegra/ap.c
index f35bdba4d48..a7938ed7910 100644
--- a/arch/arm/mach-tegra/ap.c
+++ b/arch/arm/mach-tegra/ap.c
@@ -37,6 +37,14 @@ int tegra_get_chip(void)
return rev;
}
+u32 tegra_get_major_version(void)
+{
+ struct apb_misc_gp_ctlr *gp =
+ (struct apb_misc_gp_ctlr *)NV_PA_APB_MISC_GP_BASE;
+
+ return (readl(&gp->hidrev) & HIDREV_MAJORPREV_MASK) >> HIDREV_MAJORPREV_SHIFT;
+}
+
int tegra_get_sku_info(void)
{
int sku_id;
diff --git a/arch/arm/mach-tegra/cpu.h b/arch/arm/mach-tegra/cpu.h
index 006aae3d070..5477423f4d0 100644
--- a/arch/arm/mach-tegra/cpu.h
+++ b/arch/arm/mach-tegra/cpu.h
@@ -71,6 +71,7 @@ void powerup_cpu(void);
void reset_A9_cpu(int reset);
void start_cpu(u32 reset_vector);
int tegra_get_chip(void);
+u32 tegra_get_major_version(void);
int tegra_get_sku_info(void);
int tegra_get_chip_sku(void);
void adjust_pllp_out_freqs(void);
diff --git a/arch/arm/mach-tegra/crypto.c b/arch/arm/mach-tegra/crypto.c
index 49e6a45243a..1005c815b36 100644
--- a/arch/arm/mach-tegra/crypto.c
+++ b/arch/arm/mach-tegra/crypto.c
@@ -4,164 +4,68 @@
* (C) Copyright 2010 - 2011 NVIDIA Corporation <www.nvidia.com>
*/
+#include <dm.h>
#include <log.h>
#include <linux/errno.h>
#include <asm/arch-tegra/crypto.h>
#include "uboot_aes.h"
-static u8 zero_key[16];
-
-#define AES_CMAC_CONST_RB 0x87 /* from RFC 4493, Figure 2.2 */
-
-enum security_op {
- SECURITY_SIGN = 1 << 0, /* Sign the data */
- SECURITY_ENCRYPT = 1 << 1, /* Encrypt the data */
- SECURITY_DECRYPT = 1 << 2, /* Dectypt the data */
-};
-
-/**
- * Shift a vector left by one bit
- *
- * \param in Input vector
- * \param out Output vector
- * \param size Length of vector in bytes
- */
-static void left_shift_vector(u8 *in, u8 *out, int size)
+int sign_data_block(u8 *source, unsigned int length, u8 *signature)
{
- int carry = 0;
- int i;
-
- for (i = size - 1; i >= 0; i--) {
- out[i] = (in[i] << 1) | carry;
- carry = in[i] >> 7; /* get most significant bit */
+ struct udevice *dev;
+ int ret;
+
+ /* Only one AES engine should be present */
+ ret = uclass_get_device(UCLASS_AES, 0, &dev);
+ if (ret) {
+ log_err("%s: failed to get tegra_aes: %d\n", __func__, ret);
+ return ret;
}
-}
-
-/**
- * Sign a block of data, putting the result into dst.
- *
- * \param key Input AES key, length AES128_KEY_LENGTH
- * \param key_schedule Expanded key to use
- * \param src Source data of length 'num_aes_blocks' blocks
- * \param dst Destination buffer, length AES128_KEY_LENGTH
- * \param num_aes_blocks Number of AES blocks to encrypt
- */
-static void sign_object(u8 *key, u8 *key_schedule, u8 *src, u8 *dst,
- u32 num_aes_blocks)
-{
- u8 tmp_data[AES128_KEY_LENGTH];
- u8 iv[AES128_KEY_LENGTH] = {0};
- u8 left[AES128_KEY_LENGTH];
- u8 k1[AES128_KEY_LENGTH];
- u8 *cbc_chain_data;
- unsigned int i;
- cbc_chain_data = zero_key; /* Convenient array of 0's for IV */
+ ret = dm_aes_select_key_slot(dev, 128, TEGRA_AES_SLOT_SBK);
+ if (ret)
+ return ret;
- /* compute K1 constant needed by AES-CMAC calculation */
- for (i = 0; i < AES128_KEY_LENGTH; i++)
- tmp_data[i] = 0;
-
- aes_cbc_encrypt_blocks(AES128_KEY_LENGTH, key_schedule, iv,
- tmp_data, left, 1);
-
- left_shift_vector(left, k1, sizeof(left));
-
- if ((left[0] >> 7) != 0) /* get MSB of L */
- k1[AES128_KEY_LENGTH - 1] ^= AES_CMAC_CONST_RB;
-
- /* compute the AES-CMAC value */
- for (i = 0; i < num_aes_blocks; i++) {
- /* Apply the chain data */
- aes_apply_cbc_chain_data(cbc_chain_data, src, tmp_data);
-
- /* for the final block, XOR K1 into the IV */
- if (i == num_aes_blocks - 1)
- aes_apply_cbc_chain_data(tmp_data, k1, tmp_data);
-
- /* encrypt the AES block */
- aes_encrypt(AES128_KEY_LENGTH, tmp_data,
- key_schedule, dst);
-
- debug("sign_obj: block %d of %d\n", i, num_aes_blocks);
-
- /* Update pointers for next loop. */
- cbc_chain_data = dst;
- src += AES128_KEY_LENGTH;
- }
+ return dm_aes_cmac(dev, source, signature,
+ DIV_ROUND_UP(length, AES_BLOCK_LENGTH));
}
-/**
- * Decrypt, encrypt or sign a block of data (depending on security mode).
- *
- * \param key Input AES key, length AES128_KEY_LENGTH
- * \param oper Security operations mask to perform (enum security_op)
- * \param src Source data
- * \param length Size of source data
- * \param sig_dst Destination address for signature, AES128_KEY_LENGTH bytes
- */
-static int tegra_crypto_core(u8 *key, enum security_op oper, u8 *src,
- u32 length, u8 *sig_dst)
+int encrypt_data_block(u8 *source, u8 *dest, unsigned int length)
{
- u32 num_aes_blocks;
- u8 key_schedule[AES128_EXPAND_KEY_LENGTH];
- u8 iv[AES128_KEY_LENGTH] = {0};
-
- debug("%s: length = %d\n", __func__, length);
-
- aes_expand_key(key, AES128_KEY_LENGTH, key_schedule);
-
- num_aes_blocks = (length + AES128_KEY_LENGTH - 1) / AES128_KEY_LENGTH;
-
- if (oper & SECURITY_DECRYPT) {
- /* Perform this in place, resulting in src being decrypted. */
- debug("%s: begin decryption\n", __func__);
- aes_cbc_decrypt_blocks(AES128_KEY_LENGTH, key_schedule, iv, src,
- src, num_aes_blocks);
- debug("%s: end decryption\n", __func__);
- }
-
- if (oper & SECURITY_ENCRYPT) {
- /* Perform this in place, resulting in src being encrypted. */
- debug("%s: begin encryption\n", __func__);
- aes_cbc_encrypt_blocks(AES128_KEY_LENGTH, key_schedule, iv, src,
- src, num_aes_blocks);
- debug("%s: end encryption\n", __func__);
- }
-
- if (oper & SECURITY_SIGN) {
- /* encrypt the data, overwriting the result in signature. */
- debug("%s: begin signing\n", __func__);
- sign_object(key, key_schedule, src, sig_dst, num_aes_blocks);
- debug("%s: end signing\n", __func__);
+ struct udevice *dev;
+ int ret;
+
+ /* Only one AES engine should be present */
+ ret = uclass_get_device(UCLASS_AES, 0, &dev);
+ if (ret) {
+ log_err("%s: failed to get tegra_aes: %d\n", __func__, ret);
+ return ret;
}
- return 0;
-}
+ ret = dm_aes_select_key_slot(dev, 128, TEGRA_AES_SLOT_SBK);
+ if (ret)
+ return ret;
-/**
- * Tegra crypto group
- */
-int sign_data_block(u8 *source, unsigned int length, u8 *signature)
-{
- return tegra_crypto_core(zero_key, SECURITY_SIGN, source,
- length, signature);
+ return dm_aes_cbc_encrypt(dev, (u8 *)AES_ZERO_BLOCK, source, dest,
+ DIV_ROUND_UP(length, AES_BLOCK_LENGTH));
}
-int sign_enc_data_block(u8 *source, unsigned int length, u8 *signature, u8 *key)
+int decrypt_data_block(u8 *source, u8 *dest, unsigned int length)
{
- return tegra_crypto_core(key, SECURITY_SIGN, source,
- length, signature);
-}
+ struct udevice *dev;
+ int ret;
+
+ /* Only one AES engine should be present */
+ ret = uclass_get_device(UCLASS_AES, 0, &dev);
+ if (ret) {
+ log_err("%s: failed to get tegra_aes: %d\n", __func__, ret);
+ return ret;
+ }
-int encrypt_data_block(u8 *source, unsigned int length, u8 *key)
-{
- return tegra_crypto_core(key, SECURITY_ENCRYPT, source,
- length, NULL);
-}
+ ret = dm_aes_select_key_slot(dev, 128, TEGRA_AES_SLOT_SBK);
+ if (ret)
+ return ret;
-int decrypt_data_block(u8 *source, unsigned int length, u8 *key)
-{
- return tegra_crypto_core(key, SECURITY_DECRYPT, source,
- length, NULL);
+ return dm_aes_cbc_decrypt(dev, (u8 *)AES_ZERO_BLOCK, source, dest,
+ DIV_ROUND_UP(length, AES_BLOCK_LENGTH));
}
diff --git a/arch/arm/mach-tegra/fuse.c b/arch/arm/mach-tegra/fuse.c
index e9b5259ac70..abdf6504161 100644
--- a/arch/arm/mach-tegra/fuse.c
+++ b/arch/arm/mach-tegra/fuse.c
@@ -39,7 +39,7 @@ static u32 tegra_fuse_readl(unsigned long offset)
return readl(NV_PA_FUSE_BASE + offset);
}
-static void tegra_fuse_init(void)
+void tegra_fuse_init(void)
{
u32 reg;
@@ -49,8 +49,11 @@ static void tegra_fuse_init(void)
* this bit fuse region will not work.
*/
reg = readl_relaxed(NV_PA_CLK_RST_BASE + 0x48);
- reg |= BIT(28);
- writel(reg, NV_PA_CLK_RST_BASE + 0x48);
+
+ if (reg & BIT(28))
+ return;
+
+ writel(reg | BIT(28), NV_PA_CLK_RST_BASE + 0x48);
clock_enable(PERIPH_ID_FUSE);
udelay(2);
@@ -148,3 +151,57 @@ unsigned long long tegra_chip_uid(void)
return uid;
}
+
+static int tegra_is_production_mode_fuse_set(struct fuse_regs *fuse)
+{
+ return readl(&fuse->production_mode);
+}
+
+static int tegra_is_odm_production_mode_fuse_set(struct fuse_regs *fuse)
+{
+ return readl(&fuse->security_mode);
+}
+
+static int tegra_is_failure_analysis_mode(struct fuse_regs *fuse)
+{
+ return readl(&fuse->fa);
+}
+
+static int tegra_is_sbk_zeroes(struct fuse_regs *fuse)
+{
+ int i;
+
+ for (i = 0; i < 4; i++)
+ if (readl(&fuse->sbk[i]))
+ return 0;
+
+ return 1;
+}
+
+static int tegra_is_production_mode(struct fuse_regs *fuse)
+{
+ if (!tegra_get_major_version())
+ return 1;
+
+ return !tegra_is_failure_analysis_mode(fuse) &&
+ tegra_is_production_mode_fuse_set(fuse);
+}
+
+enum fuse_operating_mode tegra_fuse_get_operation_mode(void)
+{
+ struct fuse_regs *fuse = (struct fuse_regs *)NV_PA_FUSE_BASE;
+
+ tegra_fuse_init();
+
+ if (tegra_is_production_mode(fuse)) {
+ if (!tegra_is_odm_production_mode_fuse_set(fuse))
+ return MODE_PRODUCTION;
+ else
+ if (tegra_is_sbk_zeroes(fuse))
+ return MODE_ODM_PRODUCTION_OPEN;
+ else
+ return MODE_ODM_PRODUCTION_SECURE;
+ }
+
+ return MODE_UNDEFINED;
+}
diff --git a/arch/arm/mach-tegra/tegra114/Kconfig b/arch/arm/mach-tegra/tegra114/Kconfig
index 98f1d0e71c1..43dd59fb113 100644
--- a/arch/arm/mach-tegra/tegra114/Kconfig
+++ b/arch/arm/mach-tegra/tegra114/Kconfig
@@ -8,6 +8,10 @@ config TARGET_DALMORE
bool "NVIDIA Tegra114 Dalmore evaluation board"
select BOARD_LATE_INIT
+config TARGET_SURFACE_2
+ bool "Microsoft Surface 2"
+ select BOARD_LATE_INIT
+
config TARGET_TEGRATAB
bool "NVIDIA Tegra114 TegraTab evaluation board"
select BOARD_LATE_INIT
@@ -22,6 +26,7 @@ config SYS_SOC
default "tegra114"
source "board/nvidia/dalmore/Kconfig"
+source "board/microsoft/surface-2/Kconfig"
source "board/nvidia/tegratab/Kconfig"
source "board/asus/transformer-t114/Kconfig"
diff --git a/arch/arm/mach-tegra/tegra124/bct.c b/arch/arm/mach-tegra/tegra124/bct.c
index 4dc4b7138ab..676b68dc5de 100644
--- a/arch/arm/mach-tegra/tegra124/bct.c
+++ b/arch/arm/mach-tegra/tegra124/bct.c
@@ -9,12 +9,10 @@
#include <vsprintf.h>
#include <linux/string.h>
#include <asm/arch-tegra/crypto.h>
+#include <asm/arch-tegra/fuse.h>
#include "bct.h"
#include "uboot_aes.h"
-/* Device with "sbk burned: false" will expose zero key */
-const u8 nosbk[AES128_KEY_LENGTH] = { 0 };
-
/*
* @param bct boot config table start in RAM
* @param ect bootloader start in RAM
@@ -26,29 +24,25 @@ static int bct_patch(u8 *bct, u8 *ebt, u32 ebt_size)
struct nvboot_config_table *bct_tbl = NULL;
u8 ebt_hash[AES128_KEY_LENGTH] = { 0 };
u8 bct_hash[AES128_KEY_LENGTH] = { 0 };
- u8 sbk[AES128_KEY_LENGTH] = { 0 };
u8 *sbct = bct + UBCT_LENGTH;
bool encrypted;
int ret;
ebt_size = roundup(ebt_size, EBT_ALIGNMENT);
- memcpy(sbk, (u8 *)(bct + UBCT_LENGTH + SBCT_LENGTH),
- NVBOOT_CMAC_AES_HASH_LENGTH * 4);
-
- encrypted = memcmp(&sbk, &nosbk, AES128_KEY_LENGTH);
+ encrypted = tegra_fuse_get_operation_mode() == MODE_ODM_PRODUCTION_SECURE;
if (encrypted) {
- ret = decrypt_data_block(sbct, SBCT_LENGTH, sbk);
+ ret = decrypt_data_block(sbct, sbct, SBCT_LENGTH);
if (ret)
return 1;
- ret = encrypt_data_block(ebt, ebt_size, sbk);
+ ret = encrypt_data_block(ebt, ebt, ebt_size);
if (ret)
return 1;
}
- ret = sign_enc_data_block(ebt, ebt_size, ebt_hash, sbk);
+ ret = sign_data_block(ebt, ebt_size, ebt_hash);
if (ret)
return 1;
@@ -61,12 +55,12 @@ static int bct_patch(u8 *bct, u8 *ebt, u32 ebt_size)
bct_tbl->bootloader[0].length = ebt_size;
if (encrypted) {
- ret = encrypt_data_block(sbct, SBCT_LENGTH, sbk);
+ ret = encrypt_data_block(sbct, sbct, SBCT_LENGTH);
if (ret)
return 1;
}
- ret = sign_enc_data_block(sbct, SBCT_LENGTH, bct_hash, sbk);
+ ret = sign_data_block(sbct, SBCT_LENGTH, bct_hash);
if (ret)
return 1;
diff --git a/arch/arm/mach-tegra/tegra20/Kconfig b/arch/arm/mach-tegra/tegra20/Kconfig
index bedbedade7b..b07b5a15585 100644
--- a/arch/arm/mach-tegra/tegra20/Kconfig
+++ b/arch/arm/mach-tegra/tegra20/Kconfig
@@ -54,6 +54,10 @@ config TARGET_SEABOARD
select TEGRA_LP0
select TEGRA_PMU
+config TARGET_SAMSUNG_N1
+ bool "Samsung Tegra20 N1 board"
+ select BOARD_LATE_INIT
+
config TARGET_STAR
bool "LG Tegra20 Star board"
select BOARD_LATE_INIT
@@ -92,6 +96,7 @@ source "board/compal/paz00/Kconfig"
source "board/acer/picasso/Kconfig"
source "board/avionic-design/plutux/Kconfig"
source "board/nvidia/seaboard/Kconfig"
+source "board/samsung/n1/Kconfig"
source "board/lg/star/Kconfig"
source "board/avionic-design/tec/Kconfig"
source "board/asus/transformer-t20/Kconfig"
diff --git a/arch/arm/mach-tegra/tegra20/bct.c b/arch/arm/mach-tegra/tegra20/bct.c
index 253cb243676..0270cf592c1 100644
--- a/arch/arm/mach-tegra/tegra20/bct.c
+++ b/arch/arm/mach-tegra/tegra20/bct.c
@@ -9,12 +9,10 @@
#include <vsprintf.h>
#include <linux/string.h>
#include <asm/arch-tegra/crypto.h>
+#include <asm/arch-tegra/fuse.h>
#include "bct.h"
#include "uboot_aes.h"
-/* Device with "sbk burned: false" will expose zero key */
-const u8 nosbk[AES128_KEY_LENGTH] = { 0 };
-
/*
* @param bct boot config table start in RAM
* @param ect bootloader start in RAM
@@ -25,7 +23,6 @@ static int bct_patch(u8 *bct, u8 *ebt, u32 ebt_size)
{
struct nvboot_config_table *bct_tbl = NULL;
u8 ebt_hash[AES128_KEY_LENGTH] = { 0 };
- u8 sbk[AES128_KEY_LENGTH] = { 0 };
u8 *bct_hash = bct;
bool encrypted;
int ret;
@@ -34,22 +31,19 @@ static int bct_patch(u8 *bct, u8 *ebt, u32 ebt_size)
ebt_size = roundup(ebt_size, EBT_ALIGNMENT);
- memcpy(sbk, (u8 *)(bct + BCT_LENGTH),
- NVBOOT_CMAC_AES_HASH_LENGTH * 4);
-
- encrypted = memcmp(&sbk, &nosbk, AES128_KEY_LENGTH);
+ encrypted = tegra_fuse_get_operation_mode() == MODE_ODM_PRODUCTION_SECURE;
if (encrypted) {
- ret = decrypt_data_block(bct, BCT_LENGTH, sbk);
+ ret = decrypt_data_block(bct, bct, BCT_LENGTH);
if (ret)
return 1;
- ret = encrypt_data_block(ebt, ebt_size, sbk);
+ ret = encrypt_data_block(ebt, ebt, ebt_size);
if (ret)
return 1;
}
- ret = sign_enc_data_block(ebt, ebt_size, ebt_hash, sbk);
+ ret = sign_data_block(ebt, ebt_size, ebt_hash);
if (ret)
return 1;
@@ -62,12 +56,12 @@ static int bct_patch(u8 *bct, u8 *ebt, u32 ebt_size)
bct_tbl->bootloader[0].length = ebt_size;
if (encrypted) {
- ret = encrypt_data_block(bct, BCT_LENGTH, sbk);
+ ret = encrypt_data_block(bct, bct, BCT_LENGTH);
if (ret)
return 1;
}
- ret = sign_enc_data_block(bct, BCT_LENGTH, bct_hash, sbk);
+ ret = sign_data_block(bct, BCT_LENGTH, bct_hash);
if (ret)
return 1;
diff --git a/arch/arm/mach-tegra/tegra20/warmboot.c b/arch/arm/mach-tegra/tegra20/warmboot.c
index 18034c83a1c..3fd39fe3c1a 100644
--- a/arch/arm/mach-tegra/tegra20/warmboot.c
+++ b/arch/arm/mach-tegra/tegra20/warmboot.c
@@ -19,6 +19,7 @@
#include <asm/arch-tegra/pmc.h>
#include <asm/arch-tegra/fuse.h>
#include <asm/arch-tegra/warmboot.h>
+#include <asm/arch-tegra/crypto.h>
DECLARE_GLOBAL_DATA_PTR;
@@ -182,98 +183,36 @@ int warmboot_save_sdram_params(void)
return 0;
}
-static u32 get_major_version(void)
+static void determine_crypto_options(int *is_encrypted, int *is_signed)
{
- u32 major_id;
- struct apb_misc_gp_ctlr *gp =
- (struct apb_misc_gp_ctlr *)NV_PA_APB_MISC_GP_BASE;
-
- major_id = (readl(&gp->hidrev) & HIDREV_MAJORPREV_MASK) >>
- HIDREV_MAJORPREV_SHIFT;
- 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 = (readl(&gp->hidrev) & HIDREV_CHIPID_MASK) >>
- HIDREV_CHIPID_SHIFT;
- if (chip_id == CHIPID_TEGRA20) {
- 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;
-}
-
-static void determine_crypto_options(int *is_encrypted, int *is_signed,
- int *use_zero_key)
-{
- switch (fuse_get_operation_mode()) {
+ switch (tegra_fuse_get_operation_mode()) {
+ case MODE_ODM_PRODUCTION_SECURE:
+ *is_encrypted = 1;
+ *is_signed = 1;
+ break;
+ case MODE_ODM_PRODUCTION_OPEN:
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)
+static int encrypt_wb_code(u8 *source, u8 *destination, u32 length)
+{
+ source += offsetof(struct wb_header, random_aes_block);
+ destination += offsetof(struct wb_header, random_aes_block);
+ length -= offsetof(struct wb_header, random_aes_block);
+
+ return encrypt_data_block(source, destination, length);
+}
+
+static int sign_wb_code(u32 start, u32 length)
{
int err;
u8 *source; /* Pointer to source */
@@ -295,10 +234,9 @@ int warmboot_prepare_code(u32 seg_address, u32 seg_length)
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);
+ determine_crypto_options(&is_encrypted, &is_signed);
/* Get the actual code limits. */
length = roundup(((u32)wb_end - (u32)wb_start), 16);
@@ -346,18 +284,15 @@ int warmboot_prepare_code(u32 seg_address, u32 seg_length)
dst_header->entry_point = NV_WB_RUN_ADDRESS;
dst_header->code_length = length;
- if (is_encrypted) {
- printf("!!!! Encryption is not supported !!!!\n");
- dst_header->length_insecure = 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_encrypted)
+ encrypt_wb_code((u8 *)wb_start, (u8 *)dst_header,
+ length + sizeof(struct wb_header));
+ 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_insecure,
- use_zero_key);
+ err = sign_wb_code(seg_address, dst_header->length_insecure);
fail:
if (err)
diff --git a/arch/arm/mach-tegra/tegra30/Kconfig b/arch/arm/mach-tegra/tegra30/Kconfig
index b5099ce67fc..4da67b19990 100644
--- a/arch/arm/mach-tegra/tegra30/Kconfig
+++ b/arch/arm/mach-tegra/tegra30/Kconfig
@@ -16,6 +16,10 @@ config TARGET_CARDHU
bool "NVIDIA Tegra30 Cardhu evaluation board"
select BOARD_LATE_INIT
+config TARGET_CHAGALL
+ bool "Pegatron Tegra30 Chagall board"
+ select BOARD_LATE_INIT
+
config TARGET_COLIBRI_T30
bool "Toradex Colibri T30 board"
select BOARD_LATE_INIT
@@ -64,6 +68,7 @@ config SYS_SOC
source "board/toradex/apalis_t30/Kconfig"
source "board/nvidia/beaver/Kconfig"
source "board/nvidia/cardhu/Kconfig"
+source "board/pegatron/chagall/Kconfig"
source "board/toradex/colibri_t30/Kconfig"
source "board/htc/endeavoru/Kconfig"
source "board/asus/grouper/Kconfig"
diff --git a/arch/arm/mach-tegra/tegra30/bct.c b/arch/arm/mach-tegra/tegra30/bct.c
index 398ba1de386..de668214517 100644
--- a/arch/arm/mach-tegra/tegra30/bct.c
+++ b/arch/arm/mach-tegra/tegra30/bct.c
@@ -9,12 +9,10 @@
#include <vsprintf.h>
#include <linux/string.h>
#include <asm/arch-tegra/crypto.h>
+#include <asm/arch-tegra/fuse.h>
#include "bct.h"
#include "uboot_aes.h"
-/* Device with "sbk burned: false" will expose zero key */
-const u8 nosbk[AES128_KEY_LENGTH] = { 0 };
-
/*
* @param bct boot config table start in RAM
* @param ect bootloader start in RAM
@@ -25,7 +23,6 @@ static int bct_patch(u8 *bct, u8 *ebt, u32 ebt_size)
{
struct nvboot_config_table *bct_tbl = NULL;
u8 ebt_hash[AES128_KEY_LENGTH] = { 0 };
- u8 sbk[AES128_KEY_LENGTH] = { 0 };
u8 *bct_hash = bct;
bool encrypted;
int ret;
@@ -34,22 +31,19 @@ static int bct_patch(u8 *bct, u8 *ebt, u32 ebt_size)
ebt_size = roundup(ebt_size, EBT_ALIGNMENT);
- memcpy(sbk, (u8 *)(bct + BCT_LENGTH),
- NVBOOT_CMAC_AES_HASH_LENGTH * 4);
-
- encrypted = memcmp(&sbk, &nosbk, AES128_KEY_LENGTH);
+ encrypted = tegra_fuse_get_operation_mode() == MODE_ODM_PRODUCTION_SECURE;
if (encrypted) {
- ret = decrypt_data_block(bct, BCT_LENGTH, sbk);
+ ret = decrypt_data_block(bct, bct, BCT_LENGTH);
if (ret)
return 1;
- ret = encrypt_data_block(ebt, ebt_size, sbk);
+ ret = encrypt_data_block(ebt, ebt, ebt_size);
if (ret)
return 1;
}
- ret = sign_enc_data_block(ebt, ebt_size, ebt_hash, sbk);
+ ret = sign_data_block(ebt, ebt_size, ebt_hash);
if (ret)
return 1;
@@ -62,12 +56,12 @@ static int bct_patch(u8 *bct, u8 *ebt, u32 ebt_size)
bct_tbl->bootloader[0].length = ebt_size;
if (encrypted) {
- ret = encrypt_data_block(bct, BCT_LENGTH, sbk);
+ ret = encrypt_data_block(bct, bct, BCT_LENGTH);
if (ret)
return 1;
}
- ret = sign_enc_data_block(bct, BCT_LENGTH, bct_hash, sbk);
+ ret = sign_data_block(bct, BCT_LENGTH, bct_hash);
if (ret)
return 1;