aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README1
-rw-r--r--arch/arm/cpu/tegra-common/Makefile3
-rw-r--r--arch/arm/cpu/tegra-common/crypto.c230
-rw-r--r--arch/arm/cpu/tegra-common/crypto.h36
-rw-r--r--arch/arm/cpu/tegra-common/t1x4_warmboot.c407
-rw-r--r--arch/arm/cpu/tegra124-common/Makefile5
-rw-r--r--arch/arm/cpu/tegra124-common/warmboot.c48
-rw-r--r--arch/arm/cpu/tegra124-common/warmboot_avp.c374
-rw-r--r--arch/arm/cpu/tegra124-common/warmboot_avp.h32
-rw-r--r--arch/arm/include/asm/arch-tegra/ap.h1
-rw-r--r--arch/arm/include/asm/arch-tegra/clk_rst.h51
-rw-r--r--arch/arm/include/asm/arch-tegra/sdram_param.h344
-rw-r--r--arch/arm/include/asm/arch-tegra/warmboot.h102
-rw-r--r--arch/arm/include/asm/arch-tegra124/wb_param.h598
-rw-r--r--board/nvidia/common/board.c158
-rw-r--r--board/nvidia/jetson-tk1/jetson-tk1.c39
-rw-r--r--board/nvidia/jetson-tk1/pinmux-config-jetson-tk1.h3
-rw-r--r--common/cmd_bootm.c276
-rw-r--r--common/cmd_fastboot.c2
-rw-r--r--drivers/mmc/tegra_mmc.c8
-rw-r--r--drivers/usb/gadget/f_fastboot.c50
-rw-r--r--include/android_image.h3
-rw-r--r--include/command.h7
-rw-r--r--include/config_distro_bootcmd.h19
-rw-r--r--include/configs/jetson-tk1.h59
-rw-r--r--include/configs/tegra-common-post.h12
-rw-r--r--include/configs/tegra-common-usb-gadget.h6
-rw-r--r--include/configs/tegra-common.h2
-rw-r--r--include/configs/tegra124-common.h6
29 files changed, 2874 insertions, 8 deletions
diff --git a/README b/README
index 46def0086b..36f0eb5ae8 100644
--- a/README
+++ b/README
@@ -964,6 +964,7 @@ The following options need to be configured:
CONFIG_CMD_BEDBUG * Include BedBug Debugger
CONFIG_CMD_BMP * BMP support
CONFIG_CMD_BSP * Board specific commands
+ CONFIG_CMD_BOOTAI * Android bootimg support
CONFIG_CMD_BOOTD bootd
CONFIG_CMD_BOOTI * ARM64 Linux kernel Image support
CONFIG_CMD_CACHE * icache, dcache
diff --git a/arch/arm/cpu/tegra-common/Makefile b/arch/arm/cpu/tegra-common/Makefile
index a18c318739..0ba12738a7 100644
--- a/arch/arm/cpu/tegra-common/Makefile
+++ b/arch/arm/cpu/tegra-common/Makefile
@@ -11,7 +11,10 @@ obj-y += ap.o
obj-y += board.o
obj-y += cache.o
obj-y += clock.o
+obj-$(CONFIG_TEGRA_LP0) += crypto.o
obj-y += lowlevel_init.o
obj-y += pinmux-common.o
obj-$(CONFIG_DISPLAY_CPUINFO) += sys_info.o
obj-$(CONFIG_TEGRA124) += vpr.o
+obj-$(CONFIG_TEGRA124_LP0) += t1x4_warmboot.o
+
diff --git a/arch/arm/cpu/tegra-common/crypto.c b/arch/arm/cpu/tegra-common/crypto.c
new file mode 100644
index 0000000000..5f0b240e27
--- /dev/null
+++ b/arch/arm/cpu/tegra-common/crypto.c
@@ -0,0 +1,230 @@
+/*
+ * Copyright (c) 2011 The Chromium OS Authors.
+ * (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/errno.h>
+#include "crypto.h"
+#include "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 */
+};
+
+static void debug_print_vector(char *name, u32 num_bytes, u8 *data)
+{
+ u32 i;
+
+ debug("%s [%d] @0x%08x", name, num_bytes, (u32)data);
+ for (i = 0; i < num_bytes; i++) {
+ if (i % 16 == 0)
+ debug(" = ");
+ debug("%02x", data[i]);
+ if ((i+1) % 16 != 0)
+ debug(" ");
+ }
+ debug("\n");
+}
+
+/**
+ * Apply chain data to the destination using EOR
+ *
+ * Each array is of length AES_AES_KEY_LENGTH.
+ *
+ * \param cbc_chain_data Chain data
+ * \param src Source data
+ * \param dst Destination data, which is modified here
+ */
+static void apply_cbc_chain_data(u8 *cbc_chain_data, u8 *src, u8 *dst)
+{
+ int i;
+
+ for (i = 0; i < 16; i++)
+ *dst++ = *src++ ^ *cbc_chain_data++;
+}
+
+/**
+ * Encrypt some data with AES.
+ *
+ * \param key_schedule Expanded key to use
+ * \param src Source data to encrypt
+ * \param dst Destination buffer
+ * \param num_aes_blocks Number of AES blocks to encrypt
+ */
+static void encrypt_object(u8 *key_schedule, u8 *src, u8 *dst,
+ u32 num_aes_blocks)
+{
+ u8 tmp_data[AES_KEY_LENGTH];
+ u8 *cbc_chain_data;
+ u32 i;
+
+ cbc_chain_data = zero_key; /* Convenient array of 0's for IV */
+
+ for (i = 0; i < num_aes_blocks; i++) {
+ debug("encrypt_object: block %d of %d\n", i, num_aes_blocks);
+ debug_print_vector("AES Src", AES_KEY_LENGTH, src);
+
+ /* Apply the chain data */
+ apply_cbc_chain_data(cbc_chain_data, src, tmp_data);
+ debug_print_vector("AES Xor", AES_KEY_LENGTH, tmp_data);
+
+ /* encrypt the AES block */
+ aes_encrypt(tmp_data, key_schedule, dst);
+ debug_print_vector("AES Dst", AES_KEY_LENGTH, dst);
+
+ /* Update pointers for next loop. */
+ cbc_chain_data = dst;
+ src += AES_KEY_LENGTH;
+ dst += AES_KEY_LENGTH;
+ }
+}
+
+/**
+ * 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 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 */
+ }
+}
+
+/**
+ * Sign a block of data, putting the result into dst.
+ *
+ * \param key Input AES key, length AES_KEY_LENGTH
+ * \param key_schedule Expanded key to use
+ * \param src Source data of length 'num_aes_blocks' blocks
+ * \param dst Destination buffer, length AES_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[AES_KEY_LENGTH];
+ u8 left[AES_KEY_LENGTH];
+ u8 k1[AES_KEY_LENGTH];
+ u8 *cbc_chain_data;
+ unsigned i;
+
+ cbc_chain_data = zero_key; /* Convenient array of 0's for IV */
+
+ /* compute K1 constant needed by AES-CMAC calculation */
+ for (i = 0; i < AES_KEY_LENGTH; i++)
+ tmp_data[i] = 0;
+
+ encrypt_object(key_schedule, tmp_data, left, 1);
+ debug_print_vector("AES(key, nonce)", AES_KEY_LENGTH, left);
+
+ left_shift_vector(left, k1, sizeof(left));
+ debug_print_vector("L", AES_KEY_LENGTH, left);
+
+ if ((left[0] >> 7) != 0) /* get MSB of L */
+ k1[AES_KEY_LENGTH-1] ^= AES_CMAC_CONST_RB;
+ debug_print_vector("K1", AES_KEY_LENGTH, k1);
+
+ /* compute the AES-CMAC value */
+ for (i = 0; i < num_aes_blocks; i++) {
+ /* Apply the chain data */
+ 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)
+ apply_cbc_chain_data(tmp_data, k1, tmp_data);
+
+ /* encrypt the AES block */
+ aes_encrypt(tmp_data, key_schedule, dst);
+
+ debug("sign_obj: block %d of %d\n", i, num_aes_blocks);
+ debug_print_vector("AES-CMAC Src", AES_KEY_LENGTH, src);
+ debug_print_vector("AES-CMAC Xor", AES_KEY_LENGTH, tmp_data);
+ debug_print_vector("AES-CMAC Dst", AES_KEY_LENGTH, dst);
+
+ /* Update pointers for next loop. */
+ cbc_chain_data = dst;
+ src += AES_KEY_LENGTH;
+ }
+
+ debug_print_vector("AES-CMAC Hash", AES_KEY_LENGTH, dst);
+}
+
+/**
+ * Encrypt and sign a block of data (depending on security mode).
+ *
+ * \param key Input AES key, length AES_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, AES_KEY_LENGTH bytes
+ */
+static int encrypt_and_sign(u8 *key, enum security_op oper, u8 *src,
+ u32 length, u8 *sig_dst)
+{
+ u32 num_aes_blocks;
+ u8 key_schedule[AES_EXPAND_KEY_LENGTH];
+
+ debug("encrypt_and_sign: length = %d\n", length);
+ debug_print_vector("AES key", AES_KEY_LENGTH, key);
+
+ /*
+ * The only need for a key is for signing/checksum purposes, so
+ * if not encrypting, expand a key of 0s.
+ */
+ aes_expand_key(oper & SECURITY_ENCRYPT ? key : zero_key, key_schedule);
+
+ num_aes_blocks = (length + AES_KEY_LENGTH - 1) / AES_KEY_LENGTH;
+
+ if (oper & SECURITY_ENCRYPT) {
+ /* Perform this in place, resulting in src being encrypted. */
+ debug("encrypt_and_sign: begin encryption\n");
+ encrypt_object(key_schedule, src, src, num_aes_blocks);
+ debug("encrypt_and_sign: end encryption\n");
+ }
+
+ if (oper & SECURITY_SIGN) {
+ /* encrypt the data, overwriting the result in signature. */
+ debug("encrypt_and_sign: begin signing\n");
+ sign_object(key, key_schedule, src, sig_dst, num_aes_blocks);
+ debug("encrypt_and_sign: end signing\n");
+ }
+
+ return 0;
+}
+
+int sign_data_block(u8 *source, unsigned length, u8 *signature)
+{
+ return encrypt_and_sign(zero_key, SECURITY_SIGN, source,
+ length, signature);
+}
diff --git a/arch/arm/cpu/tegra-common/crypto.h b/arch/arm/cpu/tegra-common/crypto.h
new file mode 100644
index 0000000000..aff67e77b0
--- /dev/null
+++ b/arch/arm/cpu/tegra-common/crypto.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2011 The Chromium OS Authors.
+ * (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
+ */
+
+#ifndef _CRYPTO_H_
+#define _CRYPTO_H_
+
+/**
+ * Sign a block of data
+ *
+ * \param source Source data
+ * \param length Size of source data
+ * \param signature Destination address for signature, AES_KEY_LENGTH bytes
+ */
+int sign_data_block(u8 *source, unsigned length, u8 *signature);
+
+#endif /* #ifndef _CRYPTO_H_ */
diff --git a/arch/arm/cpu/tegra-common/t1x4_warmboot.c b/arch/arm/cpu/tegra-common/t1x4_warmboot.c
new file mode 100644
index 0000000000..049fb0383f
--- /dev/null
+++ b/arch/arm/cpu/tegra-common/t1x4_warmboot.c
@@ -0,0 +1,407 @@
+/*
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <asm/errno.h>
+#include <asm/arch-tegra/ap.h>
+#include <asm/arch-tegra/clk_rst.h>
+#include <asm/arch/clock.h>
+#include <asm/arch-tegra/pmc.h>
+#include <asm/arch/pinmux.h>
+#include <asm/arch/tegra.h>
+#include <asm/arch-tegra/fuse.h>
+#include <asm/arch/gp_padctrl.h>
+#include <asm/arch-tegra/warmboot.h>
+#include <asm/arch-tegra/sdram_param.h>
+#include <asm/arch/wb_param.h>
+
+/*
+ * do_encode():
+ *
+ * sdram->dst.dst_bit = (sdram->src.op1_bits > sdram->src.op2_bits);
+ * where src, dst, dst_bit, op1_bits, op2_bits are specified in encode_fields.
+ *
+ * @param encode pointer to struct encode_fields to specify all needed
+ * fields to do encoding
+ * @param sdram pointer to struct sdram_params for SDRAM parameters
+ */
+void do_encode(struct encode_fields *encode, struct sdram_params *sdram)
+{
+ u32 val, op1, op2;
+
+ val = readl((char *)sdram + encode->src_offset);
+ debug("%s: sdram[%#x] => %#x\n", __func__, encode->src_offset, val);
+ op1 = val >> encode->op1_shift;
+ op1 &= encode->op1_mask;
+ op2 = val >> encode->op2_shift;
+ op2 &= encode->op2_mask;
+
+ val = readl((char *)sdram + encode->dst_offset);
+ val &= ~(1 << encode->dst_shift);
+ if (op1 > op2)
+ val |= (1 << encode->dst_shift);
+ debug("%s: sdram[%#x] <= %#x\n", __func__, encode->dst_offset, val);
+ writel(val, (char *)sdram + encode->dst_offset);
+}
+
+/*
+ * do_encode_list(): call do_encode() for each encode in encode_list
+ *
+ * @param encode_list pointer to struct encode_fields which contains list of
+ * pointers of encode
+ * @param num_list # of pointers of struct encode_fields in encode_list
+ * @param sdram pointer to struct sdram_params for SDRAM parameters
+ */
+void do_encode_list(struct encode_fields *encode_list, u32 num_list,
+ struct sdram_params *sdram)
+{
+ struct encode_fields *encode;
+ u32 i;
+
+ for (i = 0, encode = encode_list; i < num_list; ++i, ++encode)
+ do_encode(encode, sdram);
+}
+
+/*
+ * do_pack():
+ *
+ * PMC.dst_offset.dst_bits = src_type.src_offset.src_bits;
+ *
+ * src_type, src_offset, src_bits, dst_offset, and dst_bits are specified
+ * in pack_fields.
+ *
+ * src_type can be SDRAM, PLLM registers, or CONSTant.
+ * The destination is always PMC registers.
+ *
+ * @param pack pointer to struct pack_fields to specify all needed
+ * fields to do packing
+ * @param sdram pointer to struct sdram_params for SDRAM parameters
+ */
+void do_pack(struct pack_fields *pack, struct sdram_params *sdram)
+{
+ u32 val, offset, type, reg;
+ struct clk_rst_ctlr *clkrst = (struct clk_rst_ctlr *)NV_PA_CLK_RST_BASE;
+
+ offset = pack->src_offset;
+ type = pack->src_type;
+
+ switch (type) {
+ case TYPE_SDRAM:
+ val = readl((char *)sdram + offset);
+ break;
+ case TYPE_PLLM:
+ val = readl((char *)&clkrst->crc_pll[CLOCK_ID_MEMORY]
+ + offset);
+ break;
+ case TYPE_CONST:
+ val = offset;
+ break;
+ default:
+ debug("src_type (%u) is not supported\n", type);
+ return;
+ }
+
+ val >>= pack->src_shift;
+ val &= pack->src_mask;
+ val <<= pack->dst_shift;
+
+ reg = readl(NV_PA_PMC_BASE + pack->dst_offset);
+ reg &= ~(pack->dst_mask << pack->dst_shift);
+ reg |= val;
+ writel(reg, NV_PA_PMC_BASE + pack->dst_offset);
+}
+
+/*
+ * do_pack_list() : call do_pack() for each pack in pack_list.
+ *
+ * @param pack_list pointer to struct pack_fields which contains list of
+ * pointers of pack
+ * @param num_list # of pointers of struct pack_fields in pack_list
+ * @param sdram pointer to struct sdram_params for SDRAM parameters
+ */
+void do_pack_list(struct pack_fields *pack_list, u32 num_list,
+ struct sdram_params *sdram)
+{
+ struct pack_fields *pack;
+ u32 i;
+
+ for (pack = pack_list, i = 0; i < num_list; ++i, ++pack)
+ do_pack(pack, sdram);
+}
+
+/*
+ * t1x4_wb_save_sdram_params():
+ *
+ * save sdram parameters to scratch registers so sdram parameters can be
+ * restored when system resumes from LP0.
+ *
+ * common routine for both T114 and T124 SOCs, but based on each SOC's
+ * encode_list and pack_lists (defined in wb_param.h)
+ *
+ * @param sdram pointer to struct sdram_params for SDRAM parameters
+ * @return 0 always
+ */
+int t1x4_wb_save_sdram_params(struct sdram_params *sdram)
+{
+ /* encode BIT6_GT_BIT7 bits in sdram.swizzle_rank_byte_encode */
+ do_encode_list(encode_list, ARRAY_SIZE(encode_list), sdram);
+
+ do_pack_list(pack_list_1, ARRAY_SIZE(pack_list_1), sdram);
+
+ if (sdram->memory_type == MEMORY_TYPE_LPDDR2)
+ do_pack_list(pack_list_lpddr2, ARRAY_SIZE(pack_list_lpddr2),
+ sdram);
+ else if (sdram->memory_type == MEMORY_TYPE_DDR3)
+ do_pack_list(pack_list_ddr3, ARRAY_SIZE(pack_list_ddr3),
+ sdram);
+
+ do_pack_list(pack_list_2, ARRAY_SIZE(pack_list_2), sdram);
+
+ return 0;
+}
+
+/*
+ * 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.
+ */
+#undef RANDOM_AES_BLOCK_IS_RANDOM /* to randomize the header */
+#undef RANDOM_AES_BLOCK_IS_PATTERN /* to patternize the header */
+#define 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 = (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 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(u32 tegra_id)
+{
+ 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);
+ chip_id = (chip_id & HIDREV_CHIPID_MASK) >> HIDREV_CHIPID_SHIFT;
+ if (chip_id == tegra_id) {
+ 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_PREPRODUCTION;
+ }
+ }
+ return MODE_UNDEFINED;
+}
+
+#if defined(RANDOM_AES_BLOCK_IS_RANDOM)
+/* Currently, this routine returns a 32-bit all 0 seed. */
+static u32 query_random_seed(void)
+{
+ return 0;
+}
+#endif
+
+static void determine_crypto_options(u32 tegra_id, int *is_encrypted,
+ int *is_signed, int *use_zero_key)
+{
+ switch (fuse_get_operation_mode(tegra_id)) {
+ case MODE_PREPRODUCTION:
+ 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_signature.hash));
+ err = sign_data_block(source, length, hash);
+
+ return err;
+}
+
+/*
+ * t1x4_wb_prepare_code():
+ *
+ * prepare WB code, which will be executed by AVP when system resumes from LP0.
+ *
+ * common routine for both T114 and T124 SOCs, except the caller must pass the
+ * T114 or T124 chip ID for checking.
+ *
+ * @param tegra_id SOC ID: CHIPID_TEGRA114 or CHIPID_TEGRA124
+ * @param seg_address address where the WB code to be stored
+ * @param seg_length # of bytes allocated to store the WB code
+ * @return 0 if success
+ * !0 (error code) if failed
+ */
+int t1x4_wb_prepare_code(u32 tegra_id, 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(tegra_id, &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 >= NV_PA_BASE_SRAM) &&
+ (seg_address < (NV_PA_BASE_SRAM + NV_PA_BASE_SRAM_SIZE)))) {
+ 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_insecure = length + sizeof(struct wb_header);
+ dst_header->length_secure = length + sizeof(struct wb_header);
+ dst_header->destination = NV_WB_RUN_ADDRESS;
+ 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_signed)
+ err = sign_wb_code(seg_address, dst_header->length_insecure,
+ 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/tegra124-common/Makefile b/arch/arm/cpu/tegra124-common/Makefile
index ff77992b33..4e8cfc5947 100644
--- a/arch/arm/cpu/tegra124-common/Makefile
+++ b/arch/arm/cpu/tegra124-common/Makefile
@@ -5,6 +5,11 @@
# SPDX-License-Identifier: GPL-2.0+
#
+# The AVP is ARMv4T architecture so we must use special compiler
+# flags for any startup files it might use.
+CFLAGS_warmboot_avp.o += -march=armv4t
+
obj-y += clock.o
obj-y += funcmux.o
obj-y += pinmux.o
+obj-$(CONFIG_TEGRA_LP0) += warmboot.o warmboot_avp.o
diff --git a/arch/arm/cpu/tegra124-common/warmboot.c b/arch/arm/cpu/tegra124-common/warmboot.c
new file mode 100644
index 0000000000..fa10f5888b
--- /dev/null
+++ b/arch/arm/cpu/tegra124-common/warmboot.c
@@ -0,0 +1,48 @@
+/*
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <asm/arch-tegra/ap.h>
+#include <asm/arch/gp_padctrl.h>
+#include <asm/arch/clock.h>
+#include <asm/arch-tegra/pmc.h>
+#include <asm/arch-tegra/warmboot.h>
+#include <asm/arch-tegra/sdram_param.h>
+
+int warmboot_save_sdram_params(void)
+{
+ u32 ram_code;
+ struct sdram_params sdram;
+ struct pmc_ctlr *pmc = (struct pmc_ctlr *)NV_PA_PMC_BASE;
+
+ /* get ram code that is used as index to array _params in BCT */
+ ram_code = (readl(&pmc->pmc_strap_opt_a) & STRAP_OPT_A_RAM_CODE_MASK)
+ >> STRAP_OPT_A_RAM_CODE_SHIFT;
+ /* ram_code[1:0] selects SDRAM configuration set within the BCT */
+ ram_code &= 3;
+
+ memcpy(&sdram,
+ (char *)((struct sdram_params *)SDRAM_PARAMS_BASE + ram_code),
+ sizeof(sdram));
+
+ return t1x4_wb_save_sdram_params(&sdram);
+}
+
+int warmboot_prepare_code(u32 seg_address, u32 seg_length)
+{
+ return t1x4_wb_prepare_code(CHIPID_TEGRA124, seg_address, seg_length);
+}
diff --git a/arch/arm/cpu/tegra124-common/warmboot_avp.c b/arch/arm/cpu/tegra124-common/warmboot_avp.c
new file mode 100644
index 0000000000..bde67eb784
--- /dev/null
+++ b/arch/arm/cpu/tegra124-common/warmboot_avp.c
@@ -0,0 +1,374 @@
+/*
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <asm/arch-tegra/ap.h>
+#include <asm/arch-tegra124/mc.h>
+#include <asm/arch-tegra/clk_rst.h>
+#include <asm/arch/clock.h>
+#include <asm/arch-tegra/pmc.h>
+#include <asm/arch/tegra.h>
+#include <asm/arch/flow.h>
+#include <asm/arch-tegra/warmboot.h>
+#include <asm/arch/sysctr.h>
+#include "warmboot_avp.h"
+
+void wb_start(void)
+{
+ struct pmc_ctlr *pmc = (struct pmc_ctlr *)NV_PA_PMC_BASE;
+ struct flow_ctlr *flow = (struct flow_ctlr *)NV_PA_FLOW_BASE;
+ struct clk_rst_ctlr *clkrst = (struct clk_rst_ctlr *)NV_PA_CLK_RST_BASE;
+ struct sysctr_ctlr *sysctr = (struct sysctr_ctlr *)NV_PA_TSC_BASE;
+ struct mc_ctlr *mc = (struct mc_ctlr *)NV_PA_MC_BASE;
+ u32 reg;
+ u32 reg_1;
+ u32 reg_saved;
+ u32 divm;
+ u32 divn;
+ u32 cpcon, lfcon;
+
+ /* Are we running where we're supposed to be? */
+ asm volatile (
+ "adr %0, wb_start;" /* reg: wb_start address */
+ : "=r"(reg) /* output */
+ /* no input, no clobber list */
+ );
+
+ if (reg != NV_WB_RUN_ADDRESS)
+ goto do_reset;
+
+ /* Are we running with AVP? */
+ if (readl(NV_PA_PG_UP_BASE + PG_UP_TAG_0) != PG_UP_TAG_AVP)
+ goto do_reset;
+
+ /*
+ * Read oscillator drive strength from OSC_EDPD_OVER.XOFS and copy
+ * to OSC_CTRL.XOFS and set XOE
+ */
+ reg = readl(&pmc->pmc_osc_edpd_over);
+ reg &= PMC_XOFS_MASK;
+ reg >>= PMC_XOFS_SHIFT;
+
+ reg_1 = readl(&clkrst->crc_osc_ctrl);
+ reg_1 &= ~(OSC_XOE_MASK | OSC_XOFS_MASK);
+
+ reg <<= OSC_XOFS_SHIFT;
+ reg |= OSC_XOE_ENABLE;
+ reg |= reg_1;
+ writel(reg, &clkrst->crc_osc_ctrl);
+
+ /*
+ * Find out which CPU (slow or fast) to wake up. The default setting
+ * in flow controller is to wake up GCPU
+ */
+ reg = readl(&pmc->pmc_scratch4);
+ if (reg & CPU_WAKEUP_CLUSTER) {
+ reg = readl(&flow->cluster_control);
+ reg |= ACTIVE_LP;
+ writel(reg, &flow->cluster_control);
+ }
+
+ /* Program SUPER_CCLK_DIVIDER */
+ reg = SUPER_CDIV_ENB_ENABLE;
+ writel(reg, &clkrst->crc_super_cclk_div);
+
+ /* Enable the CoreSight clock */
+ reg = CLK_ENB_CSITE;
+ writel(reg, &clkrst->crc_clk_enb_ex[TEGRA_DEV_U].set);
+
+ /*
+ * De-assert CoreSight reset.
+ * NOTE: We're leaving the CoreSight clock on the oscillator for
+ * now. It will be restored to its original clock source
+ * when the CPU-side restoration code runs.
+ */
+ reg = SWR_CSITE_RST;
+ writel(reg, &clkrst->crc_rst_dev_ex[TEGRA_DEV_U].clr);
+
+ /* Find out the current osc frequency */
+ reg = readl(&clkrst->crc_osc_ctrl);
+ reg >>= OSC_CTRL_OSC_FREQ_SHIFT;
+
+ /* Find out the PLL-U value to use */
+ if ((reg == OSC_FREQ_OSC12) || (reg == OSC_FREQ_OSC48)) {
+ divm = 0x0c;
+ divn = 0x3c0;
+ cpcon = 0x0c;
+ lfcon = 0x02;
+ } else if (reg == OSC_FREQ_OSC16P8) {
+ divm = 0x07;
+ divn = 0x190;
+ cpcon = 0x05;
+ lfcon = 0x02;
+ } else if ((reg == OSC_FREQ_OSC19P2) || (reg == OSC_FREQ_OSC38P4)) {
+ divm = 0x04;
+ divn = 0xc8;
+ cpcon = 0x03;
+ lfcon = 0x02;
+ } else if (reg == OSC_FREQ_OSC26) {
+ divm = 0x1a;
+ divn = 0x3c0;
+ cpcon = 0x0c;
+ lfcon = 0x02;
+ } else {
+ /*
+ * Unused code in OSC_FREQ is mapped to 13MHz - use 13MHz as
+ * default settings.
+ */
+ divm = 0x0d;
+ divn = 0x3c0;
+ cpcon = 0x0c;
+ lfcon = 0x02;
+ }
+
+ /* Program PLL-U */
+ reg = PLLU_BYPASS_ENABLE | PLLU_OVERRIDE_ENABLE | (divn << 8) |
+ (divm << 0);
+ writel(reg, &clkrst->crc_pll[CLOCK_ID_USB].pll_base);
+ reg_1 = (cpcon << 8) | (lfcon << 4);
+ writel(reg_1, &clkrst->crc_pll[CLOCK_ID_USB].pll_misc);
+
+ /* Enable PLL-U */
+ reg &= ~PLLU_BYPASS_ENABLE;
+ reg |= PLLU_ENABLE_ENABLE;
+ writel(reg, &clkrst->crc_pll[CLOCK_ID_USB].pll_base);
+ reg_1 |= PLLU_LOCK_ENABLE_ENABLE;
+ writel(reg_1, &clkrst->crc_pll[CLOCK_ID_USB].pll_misc);
+
+ /*
+ * Set the CPU reset vector. pmc_scratch41 contains the physical
+ * address of the CPU-side restoration code.
+ */
+ reg = readl(&pmc->pmc_scratch41);
+ writel(reg, EXCEP_VECTOR_CPU_RESET_VECTOR);
+
+ /* Select CPU complex clock source. */
+ writel(CCLK_PLLP_BURST_POLICY, &clkrst->crc_cclk_brst_pol);
+
+ /* Set MSELECT clock source to PLL_P with 1:4 divider */
+ reg = MSELECT_CLK_SRC_PLLP_OUT0 | MSELECT_CLK_DIVISOR_6;
+ writel(reg,
+ &clkrst->crc_clk_src_vw[PERIPHC_MSELECT - PERIPHC_VW_FIRST]);
+
+ /* Enable clock to MSELECT */
+ reg = SET_CLK_ENB_MSELECT_ENABLE;
+ writel(reg, &clkrst->crc_clk_enb_ex_vw[TEGRA_DEV_V].set);
+
+ /* Bring MSELECT out of reset, after 2 microsecond wait */
+ reg = readl(NV_PA_TMRUS_BASE);
+ while (1) {
+ if (readl(NV_PA_TMRUS_BASE) > (reg + 2))
+ break;
+ }
+
+ reg = SET_CLK_ENB_MSELECT_ENABLE;
+ writel(reg, &clkrst->crc_rst_dev_ex_vw[TEGRA_DEV_V].clr);
+
+ /* Disable PLLX, since it is not used as CPU clock source */
+ reg = readl(&clkrst->crc_pll_simple[SIMPLE_PLLX].pll_base);
+ reg &= ~(PLLX_BASE_PLLX_ENABLE);
+ writel(reg, &clkrst->crc_pll_simple[SIMPLE_PLLX].pll_base);
+
+ /* Set CAR2PMC_CPU_ACK_WIDTH to 408 */
+ reg = readl(&clkrst->crc_cpu_softrst_ctrl2);
+ reg |= CAR2PMC_CPU_ACK_WIDTH_408;
+ writel(reg, &clkrst->crc_cpu_softrst_ctrl2);
+
+ /* Enable the CPU complex clock */
+ reg = CLK_ENB_CPU;
+ writel(reg, &clkrst->crc_clk_enb_ex[TEGRA_DEV_L].set);
+
+ reg = SET_CLK_ENB_CPUG_ENABLE | SET_CLK_ENB_CPULP_ENABLE;
+ writel(reg, &clkrst->crc_clk_enb_ex_vw[TEGRA_DEV_V].set);
+
+ /* Take non-cpu of G and LP cluster OUT of reset */
+ reg = CLR_NONCPURESET;
+ writel(reg, &clkrst->crc_rst_cpulp_cmplx_clr);
+ writel(reg, &clkrst->crc_rst_cpug_cmplx_clr);
+
+ /* Clear software controlled reset of slow cluster */
+ reg = CLR_CPURESET0 | CLR_DBGRESET0 | CLR_CORERESET0 | CLR_CXRESET0;
+ writel(reg, &clkrst->crc_rst_cpulp_cmplx_clr);
+
+ /* Clear software controlled reset of fast cluster */
+ reg = CLR_CPURESET0 | CLR_DBGRESET0 | CLR_CORERESET0 | CLR_CXRESET0 |
+ CLR_CPURESET1 | CLR_DBGRESET1 | CLR_CORERESET1 | CLR_CXRESET1 |
+ CLR_CPURESET2 | CLR_DBGRESET2 | CLR_CORERESET2 | CLR_CXRESET2 |
+ CLR_CPURESET3 | CLR_DBGRESET3 | CLR_CORERESET3 | CLR_CXRESET3;
+ writel(reg, &clkrst->crc_rst_cpug_cmplx_clr);
+
+ /* Initialize System Counter (TSC) with osc frequency */
+ /* Find out the current osc frequency */
+ reg = readl(&clkrst->crc_osc_ctrl);
+ reg >>= OSC_CTRL_OSC_FREQ_SHIFT;
+
+ if (reg == OSC_FREQ_OSC12)
+ reg_1 = 12000000;
+ else if (reg == OSC_FREQ_OSC48)
+ reg_1 = 48000000;
+ else if (reg == OSC_FREQ_OSC16P8)
+ reg_1 = 16800000;
+ else if (reg == OSC_FREQ_OSC19P2)
+ reg_1 = 19200000;
+ else if (reg == OSC_FREQ_OSC38P4)
+ reg_1 = 38400000;
+ else if (reg == OSC_FREQ_OSC26)
+ reg_1 = 26000000;
+ else
+ reg_1 = 13000000;
+
+ /* write frequency (in reg_1) to SYSCTR0_CNTFID0 */
+ writel(reg_1, &sysctr->cntfid0);
+ /* enable the TSC */
+ reg = readl(&sysctr->cntcr);
+ reg |= TSC_CNTCR_ENABLE | TSC_CNTCR_HDBG;
+ writel(reg, &sysctr->cntcr);
+
+ /* disable VPR */
+ writel(0x00000000, &mc->mc_video_protect_size_mb);
+ writel(0x00000001, &mc->mc_video_protect_reg_ctrl);
+ /* read them back to make sure write operation completed */
+ reg = readl(&mc->mc_video_protect_size_mb);
+ reg = readl(&mc->mc_video_protect_reg_ctrl);
+
+ /*
+ * Reprogram PMC_CPUPWRGOOD_TIMER register:
+ *
+ * Kernel prepares PMC_CPUPWRGOOD_TIMER based on 32768Hz clock.
+ * Note that PMC_CPUPWRGOOD_TIMER is running at pclk.
+ *
+ * Need to reprogram PMC_CPUPWRGOOD_TIMER based on the current pclk,
+ * which is @408Mhz (pclk = sclk = pllp_out0) after reset.
+ *
+ * So, just multiply a factor = (408M/32K) to PMC_CPUPWRGOOD_TIMER.
+ *
+ * Save the original PMC_CPUPWRGOOD_TIMER register, need to restore
+ * it after CPU is powered up.
+ */
+ reg = readl(&pmc->pmc_cpupwrgood_timer);
+ reg_saved = reg;
+
+ reg *= (408000000 / 32768);
+ writel(reg, &pmc->pmc_cpupwrgood_timer);
+
+ /* Find out which cluster (slow or fast) to power on */
+ reg = readl(&pmc->pmc_scratch4);
+ if (reg & CPU_WAKEUP_CLUSTER) {
+ /* Power up the slow cluster non-CPU partition. */
+ reg = PWRGATE_STATUS_C1NC_ENABLE;
+ reg_1 = PWRGATE_TOGGLE_PARTID_C1NC | PWRGATE_TOGGLE_START;
+ if (!(readl(&pmc->pmc_pwrgate_status) & reg)) {
+ /* partition is not on, turn it on */
+ writel(reg_1, &pmc->pmc_pwrgate_toggle);
+
+ /* wait until the partition is powered on */
+ while (!(readl(&pmc->pmc_pwrgate_status) & reg))
+ ;
+
+ /* wait until clamp is off */
+ while (readl(&pmc->pmc_clamp_status) & reg)
+ ;
+ }
+
+ reg = PWRGATE_STATUS_CELP_ENABLE;
+ reg_1 = PWRGATE_TOGGLE_PARTID_CELP | PWRGATE_TOGGLE_START;
+ if (!(readl(&pmc->pmc_pwrgate_status) & reg)) {
+ /* partition is not on, turn it on */
+ writel(reg_1, &pmc->pmc_pwrgate_toggle);
+
+ /* wait until the partition is powered on */
+ while (!(readl(&pmc->pmc_pwrgate_status) & reg))
+ ;
+
+ /* wait until clamp is off */
+ while (readl(&pmc->pmc_clamp_status) & reg)
+ ;
+ }
+ } else {
+ /* FastCPU */
+ reg = PWRGATE_STATUS_CRAIL_ENABLE;
+ reg_1 = PWRGATE_TOGGLE_PARTID_CRAIL | PWRGATE_TOGGLE_START;
+ if (!(readl(&pmc->pmc_pwrgate_status) & reg)) {
+ /* partition is not on, turn it on */
+ writel(reg_1, &pmc->pmc_pwrgate_toggle);
+
+ /* wait until the partition is powered on */
+ while (!(readl(&pmc->pmc_pwrgate_status) & reg))
+ ;
+
+ /* wait until clamp is off */
+ while (readl(&pmc->pmc_clamp_status) & reg)
+ ;
+ }
+
+ reg = PWRGATE_STATUS_C0NC_ENABLE;
+ reg_1 = PWRGATE_TOGGLE_PARTID_C0NC | PWRGATE_TOGGLE_START;
+ if (!(readl(&pmc->pmc_pwrgate_status) & reg)) {
+ /* partition is not on, turn it on */
+ writel(reg_1, &pmc->pmc_pwrgate_toggle);
+
+ /* wait until the partition is powered on */
+ while (!(readl(&pmc->pmc_pwrgate_status) & reg))
+ ;
+
+ /* wait until clamp is off */
+ while (readl(&pmc->pmc_clamp_status) & reg)
+ ;
+ }
+
+ reg = PWRGATE_STATUS_CE0_ENABLE;
+ reg_1 = PWRGATE_TOGGLE_PARTID_CE0 | PWRGATE_TOGGLE_START;
+ if (!(readl(&pmc->pmc_pwrgate_status) & reg)) {
+ /* partition is not on, turn it on */
+ writel(reg_1, &pmc->pmc_pwrgate_toggle);
+
+ /* wait until the partition is powered on */
+ while (!(readl(&pmc->pmc_pwrgate_status) & reg))
+ ;
+
+ /* wait until clamp is off */
+ while (readl(&pmc->pmc_clamp_status) & reg)
+ ;
+ }
+ }
+
+ /* give I/O signals time to stable */
+ reg = 20 | EVENT_MSEC | EVENT_MODE_STOP;
+ writel(reg, &flow->halt_cop_events);
+
+ /* restore the original PMC_CPUPWRGOOD_TIMER register */
+ writel(reg_saved, &pmc->pmc_cpupwrgood_timer);
+
+avp_halt:
+ reg = EVENT_MODE_STOP | EVENT_JTAG;
+ writel(reg, &flow->halt_cop_events);
+ goto avp_halt;
+
+do_reset:
+ writel(SWR_TRIG_SYS_RST, &clkrst->crc_rst_dev[TEGRA_DEV_L]);
+
+ while (1)
+ ;
+}
+
+/*
+ * wb_end() is a dummy function, and must be directly following wb_start(),
+ * and is used to calculate the size of wb_start().
+ */
+void wb_end(void)
+{
+}
diff --git a/arch/arm/cpu/tegra124-common/warmboot_avp.h b/arch/arm/cpu/tegra124-common/warmboot_avp.h
new file mode 100644
index 0000000000..05ce949718
--- /dev/null
+++ b/arch/arm/cpu/tegra124-common/warmboot_avp.h
@@ -0,0 +1,32 @@
+/*
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _TEGRA124_WARMBOOT_AVP_H_
+#define _TEGRA124_WARMBOOT_AVP_H_
+
+/* CRC_CCLK_BURST_POLICY_0 0x20 */
+#define CCLK_PLLP_BURST_POLICY 0x20004444
+
+/* CRC_CLK_SOURCE_MSELECT_0, 0x3b4 */
+#define MSELECT_CLK_DIVISOR_6 6
+
+/* PMC_SCRATCH4 bit 31 defines which Cluster suspends (1 = LP Cluster) */
+#define CPU_WAKEUP_CLUSTER (1 << 31)
+
+/* CPU_SOFTRST_CTRL2_0, 0x388 */
+#define CAR2PMC_CPU_ACK_WIDTH_408 408
+
+#endif /* _TEGRA124_WARMBOOT_AVP_H_ */
diff --git a/arch/arm/include/asm/arch-tegra/ap.h b/arch/arm/include/asm/arch-tegra/ap.h
index 5c8be94d97..7c04461dce 100644
--- a/arch/arm/include/asm/arch-tegra/ap.h
+++ b/arch/arm/include/asm/arch-tegra/ap.h
@@ -28,6 +28,7 @@
/* AP base physical address of internal SRAM */
#define NV_PA_BASE_SRAM 0x40000000
+#define NV_PA_BASE_SRAM_SIZE 0x20000
#define EXCEP_VECTOR_CPU_RESET_VECTOR (NV_PA_EVP_BASE + 0x100)
#define CSITE_CPU_DBG0_LAR (NV_PA_CSITE_BASE + 0x10FB0)
diff --git a/arch/arm/include/asm/arch-tegra/clk_rst.h b/arch/arm/include/asm/arch-tegra/clk_rst.h
index 7d28e16f1c..b92f728c3d 100644
--- a/arch/arm/include/asm/arch-tegra/clk_rst.h
+++ b/arch/arm/include/asm/arch-tegra/clk_rst.h
@@ -208,6 +208,26 @@ struct clk_rst_ctlr {
uint crc_clk_src_x[TEGRA_CLK_SOURCES_X]; /* XUSB, etc, 0x600-0x678 */
};
+#define TEGRA_DEV_L 0
+#define TEGRA_DEV_H 1
+#define TEGRA_DEV_U 2
+#define TEGRA_DEV_V 0
+#define TEGRA_DEV_W 1
+
+#define SIMPLE_PLLX (CLOCK_ID_XCPU - CLOCK_ID_FIRST_SIMPLE)
+
+/* Bits to enable/reset modules */
+#define CLK_ENB_CPU (1 << 0)
+#define SWR_TRIG_SYS_RST (1 << 2)
+#define SWR_CSITE_RST (1 << 9)
+#define CLK_ENB_CSITE (1 << 9)
+
+/* CRC_SUPER_CCLK_DIVIDER_0 0x24 */
+#define SUPER_CDIV_ENB_ENABLE (1 << 31)
+
+/* CLK_RST_CONTROLLER_MISC_CLK_ENB 0x48 */
+#define EN_PPSB_STOPCLK (1 << 0)
+
/* CLK_RST_CONTROLLER_CLK_CPU_CMPLX_0 */
#define CPU3_CLK_STP_SHIFT 11
#define CPU2_CLK_STP_SHIFT 10
@@ -215,6 +235,17 @@ struct clk_rst_ctlr {
#define CPU0_CLK_STP_SHIFT 8
#define CPU0_CLK_STP_MASK (1U << CPU0_CLK_STP_SHIFT)
+/* CRC_OSC_CTRL_0 0x50 */
+#define OSC_CTRL_OSC_FREQ (0xf << 28)
+#define OSC_CTRL_OSC_FREQ_SHIFT 28
+#define OSC_FREQ_OSC13 0 /* 13.0MHz */
+#define OSC_FREQ_OSC19P2 4 /* 19.2MHz */
+#define OSC_FREQ_OSC12 8 /* 12.0MHz */
+#define OSC_FREQ_OSC26 12 /* 26.0MHz */
+#define OSC_FREQ_OSC16P8 1 /* 16.8MHz */
+#define OSC_FREQ_OSC38P4 5 /* 38.4MHz */
+#define OSC_FREQ_OSC48 9 /* 48.0MHz */
+
/* CLK_RST_CONTROLLER_PLLx_BASE_0 */
#define PLL_BYPASS_SHIFT 31
#define PLL_BYPASS_MASK (1U << PLL_BYPASS_SHIFT)
@@ -290,6 +321,26 @@ enum {
#define PLLP_OUT4_RSTN_EN (0 << 16)
#define PLLP_OUT4_CLKEN (1 << 17)
+/* CRC_PLLP_MISC_0 0xac */
+#define PLLP_MISC_PLLP_CPCON_8 (8 << 8)
+#define PLLP_MISC_PLLP_LOCK_ENABLE (1 << 18)
+
+/* CRC_PLLU_BASE_0 0xc0 */
+#define PLLU_BYPASS_ENABLE (1 << 31)
+#define PLLU_ENABLE_ENABLE (1 << 30)
+#define PLLU_REF_DIS_REF_DISABLE (1 << 29)
+#define PLLU_OVERRIDE_ENABLE (1 << 24)
+
+/* CRC_PLLU_MISC_0 0xcc */
+#define PLLU_LOCK_ENABLE_ENABLE (1 << 22)
+
+/* PLLX_BASE_0 0xe0 */
+#define PLLX_BASE_PLLX_ENABLE (1 << 30)
+
+/* CLK_RST_CONTROLLER_PLLX_MISC_3 */
+#define PLLX_IDDQ_SHIFT 3
+#define PLLX_IDDQ_MASK (1U << PLLX_IDDQ_SHIFT)
+
/* CLK_RST_CONTROLLER_UTMIP_PLL_CFG1_0 */
#define PLLU_POWERDOWN (1 << 16)
#define PLL_ENABLE_POWERDOWN (1 << 14)
diff --git a/arch/arm/include/asm/arch-tegra/sdram_param.h b/arch/arm/include/asm/arch-tegra/sdram_param.h
new file mode 100644
index 0000000000..fd115bcefc
--- /dev/null
+++ b/arch/arm/include/asm/arch-tegra/sdram_param.h
@@ -0,0 +1,344 @@
+/*
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _TEGRA124_SDRAM_PARAM_H_
+#define _TEGRA124_SDRAM_PARAM_H_
+
+/* define SDRAM parameters offset in BCT */
+#define BCT_SDRAM_PARAMS_OFFSET 0x8f8
+#define SDRAM_PARAMS_BASE (NV_PA_BASE_SRAM + BCT_SDRAM_PARAMS_OFFSET)
+
+enum memory_type {
+ MEMORY_TYPE_NONE = 0,
+ MEMORY_TYPE_LPDDR2,
+ MEMORY_TYPE_DDR3,
+};
+
+/**
+ * Defines the SDRAM parameter structure
+ */
+struct sdram_params {
+ enum memory_type memory_type;
+ u32 pllm_input_divider;
+ u32 pllm_feedback_divider;
+ u32 pllm_stable_time;
+ u32 pllm_setup_control;
+ u32 pllm_select_div2;
+ u32 pllm_pdl_shift_ph45;
+ u32 pllm_pdl_shift_ph90;
+ u32 pllm_pdl_shift_ph135;
+ u32 pllm_kcp;
+ u32 pllm_kvco;
+ u32 emc_bct_spare0;
+ u32 emc_bct_spare1;
+ u32 emc_bct_spare2;
+ u32 emc_bct_spare3;
+ u32 emc_bct_spare4;
+ u32 emc_bct_spare5;
+ u32 emc_bct_spare6;
+ u32 emc_bct_spare7;
+ u32 emc_bct_spare8;
+ u32 emc_bct_spare9;
+ u32 emc_bct_spare10;
+ u32 emc_bct_spare11;
+ u32 emc_clock_source;
+ u32 emc_auto_cal_interval;
+ u32 emc_auto_cal_config;
+ u32 emc_auto_cal_config2;
+ u32 emc_auto_cal_config3;
+ u32 emc_auto_cal_wait;
+ u32 emc_adr_cfg;
+ u32 emc_pin_program_wait;
+ u32 emc_pin_extra_wait;
+ u32 emc_timing_control_wait;
+ u32 emc_rc;
+ u32 emc_rfc;
+ u32 emc_rfc_slr;
+ u32 emc_ras;
+ u32 emc_rp;
+ u32 emc_r2r;
+ u32 emc_w2w;
+ u32 emc_r2w;
+ u32 emc_w2r;
+ u32 emc_r2p;
+ u32 emc_w2p;
+ u32 emc_rd_rcd;
+ u32 emc_wr_rcd;
+ u32 emc_rdr;
+ u32 emc_rext;
+ u32 emc_wext;
+ u32 emc_wdv;
+ u32 emc_wdv_mask;
+ u32 emc_quse;
+ u32 emc_quse_width;
+ u32 emc_ibdly;
+ u32 emc_einput;
+ u32 emc_einput_duration;
+ u32 emc_puterm_extra;
+ u32 emc_puterm_width;
+ u32 emc_puterm_adj;
+ u32 emc_cdb_cntl1;
+ u32 emc_cdb_cntl2;
+ u32 emc_cdb_cntl3;
+ u32 emc_qrst;
+ u32 emc_qsafe;
+ u32 emc_rdv;
+ u32 emc_rdv_mask;
+ u32 emc_qpop;
+ u32 emc_ctt;
+ u32 emc_ctt_duration;
+ u32 emc_refresh;
+ u32 emc_burst_refresh_num;
+ u32 emc_pre_refresh_req_cnt;
+ u32 emc_pdex2wr;
+ u32 emc_pdex2rd;
+ u32 emc_pchg2pden;
+ u32 emc_act2pden;
+ u32 emc_ar2pden;
+ u32 emc_rw2pden;
+ u32 emc_txsr;
+ u32 emc_txsrdll;
+ u32 emc_tcke;
+ u32 emc_tckesr;
+ u32 emc_tpd;
+ u32 emc_tfaw;
+ u32 emc_trpab;
+ u32 emc_tclkstable;
+ u32 emc_tclkstop;
+ u32 emc_trefbw;
+ u32 emc_fbio_cfg5;
+ u32 emc_fbio_cfg6;
+ u32 emc_fbio_spare;
+ u32 emc_cfg_rsv;
+ u32 emc_mrs;
+ u32 emc_emrs;
+ u32 emc_emrs2;
+ u32 emc_emrs3;
+ u32 emc_mrw1;
+ u32 emc_mrw2;
+ u32 emc_mrw3;
+ u32 emc_mrw4;
+ u32 emc_mrw_extra;
+ u32 emc_warmboot_mrw_extra;
+ u32 emc_warmboot_extra_modereg_write_en;
+ u32 emc_extra_modereg_write_enable;
+ u32 emc_mrw_reset_command;
+ u32 emc_mrw_reset_ninit_wait;
+ u32 emc_mrs_wait_cnt;
+ u32 emc_mrs_wait_cnt2;
+ u32 emc_cfg;
+ u32 emc_cfg2;
+ u32 emc_cfg_pipe;
+ u32 emc_dbg;
+ u32 emc_cmdq;
+ u32 emc_mc2emcq;
+ u32 emc_dyn_self_ref_control;
+ u32 ahb_arb_xbar_ctrl_mem_init_done;
+ u32 emc_cfg_dig_dll;
+ u32 emc_cfg_dig_dll_period;
+ u32 emc_dev_select;
+ u32 emc_sel_dpd_ctrl;
+ u32 emc_dll_xform_dqs0;
+ u32 emc_dll_xform_dqs1;
+ u32 emc_dll_xform_dqs2;
+ u32 emc_dll_xform_dqs3;
+ u32 emc_dll_xform_dqs4;
+ u32 emc_dll_xform_dqs5;
+ u32 emc_dll_xform_dqs6;
+ u32 emc_dll_xform_dqs7;
+ u32 emc_dll_xform_dqs8;
+ u32 emc_dll_xform_dqs9;
+ u32 emc_dll_xform_dqs10;
+ u32 emc_dll_xform_dqs11;
+ u32 emc_dll_xform_dqs12;
+ u32 emc_dll_xform_dqs13;
+ u32 emc_dll_xform_dqs14;
+ u32 emc_dll_xform_dqs15;
+ u32 emc_dll_xform_quse0;
+ u32 emc_dll_xform_quse1;
+ u32 emc_dll_xform_quse2;
+ u32 emc_dll_xform_quse3;
+ u32 emc_dll_xform_quse4;
+ u32 emc_dll_xform_quse5;
+ u32 emc_dll_xform_quse6;
+ u32 emc_dll_xform_quse7;
+ u32 emc_dll_xform_addr0;
+ u32 emc_dll_xform_addr1;
+ u32 emc_dll_xform_addr2;
+ u32 emc_dll_xform_addr3;
+ u32 emc_dll_xform_addr4;
+ u32 emc_dll_xform_addr5;
+ u32 emc_dll_xform_quse8;
+ u32 emc_dll_xform_quse9;
+ u32 emc_dll_xform_quse10;
+ u32 emc_dll_xform_quse11;
+ u32 emc_dll_xform_quse12;
+ u32 emc_dll_xform_quse13;
+ u32 emc_dll_xform_quse14;
+ u32 emc_dll_xform_quse15;
+ u32 emc_dli_trim_txdqs0;
+ u32 emc_dli_trim_txdqs1;
+ u32 emc_dli_trim_txdqs2;
+ u32 emc_dli_trim_txdqs3;
+ u32 emc_dli_trim_txdqs4;
+ u32 emc_dli_trim_txdqs5;
+ u32 emc_dli_trim_txdqs6;
+ u32 emc_dli_trim_txdqs7;
+ u32 emc_dli_trim_txdqs8;
+ u32 emc_dli_trim_txdqs9;
+ u32 emc_dli_trim_txdqs10;
+ u32 emc_dli_trim_txdqs11;
+ u32 emc_dli_trim_txdqs12;
+ u32 emc_dli_trim_txdqs13;
+ u32 emc_dli_trim_txdqs14;
+ u32 emc_dli_trim_txdqs15;
+ u32 emc_dll_xform_dq0;
+ u32 emc_dll_xform_dq1;
+ u32 emc_dll_xform_dq2;
+ u32 emc_dll_xform_dq3;
+ u32 emc_dll_xform_dq4;
+ u32 emc_dll_xform_dq5;
+ u32 emc_dll_xform_dq6;
+ u32 emc_dll_xform_dq7;
+ u32 warmboot_wait;
+ u32 emc_ctt_term_ctrl;
+ u32 emc_odt_write;
+ u32 emc_odt_read;
+ u32 emc_zcal_interval;
+ u32 emc_zcal_wait_cnt;
+ u32 emc_zcal_mrw_cmd;
+ u32 emc_mrs_rest_dll;
+ u32 emc_zcal_init_dev0;
+ u32 emc_zcal_init_dev1;
+ u32 emc_zcal_init_wait;
+ u32 emc_zcal_warmcoldboot_enables;
+ u32 emc_mrw_lpddr2_zcal_warmboot;
+ u32 emc_zq_cal_ddr3_warmboot;
+ u32 emc_zcal_warmboot_wait;
+ u32 emc_mrs_warmboot_enable;
+ u32 emc_mrs_reset_dll_wait;
+ u32 emc_mrs_extra;
+ u32 emc_warmboot_mrs_extra;
+ u32 emc_emrs_ddr2_dll_enable;
+ u32 emc_mrs_ddr2_dll_reset;
+ u32 emc_emrs_ddr2_ocd_calib;
+ u32 emc_ddr2_wait;
+ u32 emc_clken_override;
+ u32 mc_dis_extra_snap_levels;
+ u32 emc_extra_refresh_num;
+ u32 emc_clken_override_all_warmboot;
+ u32 mc_clken_override_all_warmboot;
+ u32 emc_cfg_dig_dll_period_warmboot;
+ u32 pmc_vddp_sel;
+ u32 pmc_vddp_sel_wait;
+ u32 pmc_ddr_pwr;
+ u32 pmc_ddr_cfg;
+ u32 pmc_io_dpd3_req;
+ u32 pmc_io_dpd3_req_wait;
+ u32 pmc_reg_short;
+ u32 pmc_no_iopower;
+ u32 pmc_por_dpd_ctrl_wait;
+ u32 emc_xm2cmdpadctrl;
+ u32 emc_xm2cmdpadctrl2;
+ u32 emc_xm2cmdpadctrl3;
+ u32 emc_xm2cmdpadctrl4;
+ u32 emc_xm2cmdpadctrl5;
+ u32 emc_xm2dqspadctrl;
+ u32 emc_xm2dqspadctrl2;
+ u32 emc_xm2dqspadctrl3;
+ u32 emc_xm2dqspadctrl4;
+ u32 emc_xm2dqspadctrl5;
+ u32 emc_xm2dqspadctrl6;
+ u32 emc_xm2dqpadctrl;
+ u32 emc_xm2dqpadctrl2;
+ u32 emc_xm2dqpadctrl3;
+ u32 emc_xm2clkpadctrl;
+ u32 emc_xm2clkpadctrl2;
+ u32 emc_xm2comppadctrl;
+ u32 emc_xm2vttgenpadctrl;
+ u32 emc_xm2vttgenpadctrl2;
+ u32 emc_xm2vttgenpadctrl3;
+ u32 emc_acpd_control;
+ u32 emc_swizzle_rank0_byte_cfg;
+ u32 emc_swizzle_rank0_byte0;
+ u32 emc_swizzle_rank0_byte1;
+ u32 emc_swizzle_rank0_byte2;
+ u32 emc_swizzle_rank0_byte3;
+ u32 emc_swizzle_rank1_byte_cfg;
+ u32 emc_swizzle_rank1_byte0;
+ u32 emc_swizzle_rank1_byte1;
+ u32 emc_swizzle_rank1_byte2;
+ u32 emc_swizzle_rank1_byte3;
+ u32 emc_dsr_vttgen_drv;
+ u32 emc_txdsrvttgen;
+ u32 emc_bgbias_ctl0;
+ u32 mc_emem_adr_cfg;
+ u32 mc_emem_adr_cfg_dev0;
+ u32 mc_emem_adr_cfg_dev1;
+ u32 mc_emem_adr_cfg_bank_mask0;
+ u32 mc_emem_adr_cfg_bank_mask1;
+ u32 mc_emem_adr_cfg_bank_mask2;
+ u32 mc_emem_adr_cfg_bank_swizzle3;
+ u32 mc_emem_cfg;
+ u32 mc_emem_arb_cfg;
+ u32 mc_emem_arb_outstanding_req;
+ u32 mc_emem_arb_timing_rcd;
+ u32 mc_emem_arb_timing_rp;
+ u32 mc_emem_arb_timing_rc;
+ u32 mc_emem_arb_timing_ras;
+ u32 mc_emem_arb_timing_faw;
+ u32 mc_emem_arb_timing_rrd;
+ u32 mc_emem_arb_timing_rap2pre;
+ u32 mc_emem_arb_timing_wap2pre;
+ u32 mc_emem_arb_timing_r2r;
+ u32 mc_emem_arb_timing_w2w;
+ u32 mc_emem_arb_timing_r2w;
+ u32 mc_emem_arb_timing_w2r;
+ u32 mc_emem_arb_da_turns;
+ u32 mc_emem_arb_da_covers;
+ u32 mc_emem_arb_misc0;
+ u32 mc_emem_arb_misc1;
+ u32 mc_emem_arb_ring1_throttle;
+ u32 mc_emem_arb_override;
+ u32 mc_emem_arb_override1;
+ u32 mc_emem_arb_rsv;
+ u32 mc_clken_override;
+ u32 mc_stat_control;
+ u32 mc_display_snap_ring;
+ u32 mc_video_protect_bom;
+ u32 mc_video_protect_bom_adr_hi;
+ u32 mc_video_protect_size_mb;
+ u32 mc_video_protect_vpr_override;
+ u32 mc_video_protect_vpr_override1;
+ u32 mc_video_protect_gpu_override0;
+ u32 mc_video_protect_gpu_override1;
+ u32 mc_sec_carveout_bom;
+ u32 mc_sec_carveout_adr_hi;
+ u32 mc_sec_carveout_size_mb;
+ u32 mc_video_protect_write_access;
+ u32 mc_sec_carveout_protect_write_access;
+ u32 emc_ca_training_enable;
+ u32 emc_ca_training_timing_cntl1;
+ u32 emc_ca_training_timing_cntl2;
+ u32 swizzle_rank_byte_encode;
+ u32 bootrom_patch_control;
+ u32 bootrom_patch_data;
+ u32 mc_mts_carveout_bom;
+ u32 mc_mts_carveout_adr_hi;
+ u32 mc_mts_carveout_size_mb;
+ u32 mc_mts_carveout_reg_ctrl;
+};
+#endif /* _TEGRA124_SDRAM_PARAM_H_ */
diff --git a/arch/arm/include/asm/arch-tegra/warmboot.h b/arch/arm/include/asm/arch-tegra/warmboot.h
index 2e66e0f23b..6b37b60c68 100644
--- a/arch/arm/include/asm/arch-tegra/warmboot.h
+++ b/arch/arm/include/asm/arch-tegra/warmboot.h
@@ -8,11 +8,14 @@
#ifndef _WARM_BOOT_H_
#define _WARM_BOOT_H_
+#include <asm/arch-tegra/sdram_param.h>
+
#define STRAP_OPT_A_RAM_CODE_SHIFT 4
#define STRAP_OPT_A_RAM_CODE_MASK (0xf << STRAP_OPT_A_RAM_CODE_SHIFT)
/* Defines the supported operating modes */
enum fuse_operating_mode {
+ MODE_PREPRODUCTION = 2,
MODE_PRODUCTION = 3,
MODE_UNDEFINED,
};
@@ -39,7 +42,15 @@ struct hash {
struct wb_header {
u32 length_insecure; /* length of the code header */
u32 reserved[3];
+#ifdef CONFIG_TEGRA124
+ u32 modules[64]; /* RsaKeyModulus */
+ struct {
+ struct hash hash; /* hash of header+code, starts next field */
+ u32 signature[64]; /* The RSA-PSS signature*/
+ } hash_signature;
+#else
struct hash hash; /* hash of header+code, starts next field*/
+#endif
struct hash random_aes_block; /* a data block to aid security. */
u32 length_secure; /* length of the code header */
u32 destination; /* destination address to put the wb code */
@@ -118,6 +129,83 @@ union scratch3_reg {
u32 word;
};
+enum field_type {
+ TYPE_SDRAM,
+ TYPE_PLLM,
+ TYPE_CONST,
+ TYPE_COUNT,
+};
+
+#define sdram_offset(member) offsetof(struct sdram_params, member)
+#define pmc_offset(member) offsetof(struct pmc_ctlr, member)
+#define pllm_offset(member) offsetof(struct clk_pllm, member)
+
+struct encode_fields {
+ u32 src_offset;
+ u32 op1_mask;
+ u32 op1_shift;
+ u32 op2_mask;
+ u32 op2_shift;
+ u32 dst_offset;
+ u32 dst_shift;
+};
+
+/*
+ * encode: set dst_off.dst_bit to 1 if (src_off.op1_bits > src_off.op2_bits)
+ * else set dst_off.dst_bit to 0.
+ */
+#define encode(src_off, op1_bits, op2_bits, dst_off, dst_bit) \
+ { \
+ .src_offset = src_off, \
+ .op1_mask = 0xfffffffful >> \
+ (31 - ((1 ? op1_bits) - (0 ? op1_bits))), \
+ .op1_shift = 0 ? op1_bits, \
+ .op2_mask = 0xfffffffful >> \
+ (31 - ((1 ? op2_bits) - (0 ? op2_bits))), \
+ .op2_shift = 0 ? op2_bits, \
+ .dst_offset = dst_off, \
+ .dst_shift = dst_bit, \
+ }
+
+struct pack_fields {
+ enum field_type src_type;
+ u32 src_offset; /* for TYPE_CONST, this field is a constant */
+ u32 src_mask;
+ u32 src_shift;
+ enum field_type dst_type;
+ u32 dst_offset;
+ u32 dst_mask;
+ u32 dst_shift;
+};
+
+/*
+ * pack: a macro to copy from bits in src to bits in dst.
+ *
+ * For example,
+ * pack(TYPE_SDRAM, sdram_offset(emc_clock_source), 7:0,
+ * pmc_offset(pmc_scratch6), 15:8)
+ * is to:
+ * copy bits 7:0 of sdram_offset.emc_clock_source to
+ * bits 15:8 of pmc_scratch6 register.
+ *
+ * The first parameter of pack determines the type of src:
+ * TYPE_SDRAM: src is of SDRAM parameter,
+ * TYPE_PLLM: src is of PLLM,
+ * TYPE_CONST: src is a constant.
+ */
+#define pack(_src_type, src_off, src_bits, dst_off, dst_bits) \
+ { \
+ .src_type = _src_type, \
+ .src_offset = src_off, \
+ .src_mask = 0xfffffffful >> \
+ (31 - ((1 ? src_bits) - (0 ? src_bits))), \
+ .src_shift = 0 ? src_bits, \
+ .dst_offset = dst_off, \
+ .dst_mask = 0xfffffffful >> \
+ (31 - ((1 ? dst_bits) - (0 ? dst_bits))), \
+ .dst_shift = 0 ? dst_bits, \
+ }
+
/**
* Save warmboot memory settings for a later resume
@@ -131,4 +219,18 @@ int sign_data_block(u8 *source, u32 length, u8 *signature);
void wb_start(void); /* Start of WB assembly code */
void wb_end(void); /* End of WB assembly code */
+/* Common routines for T114 and T124 SOCs */
+
+/*
+ * t1x4_wb_save_sdram_params():
+ * save sdram parameters to scratch registers so sdram parameters can be
+ * restored when system resumes from LP0
+ */
+int t1x4_wb_save_sdram_params(struct sdram_params *sdram);
+
+/*
+ * t1x4_wb_prepare_code():
+ * prepare WB code, which will be executed by AVP when system resumes from LP0
+ */
+int t1x4_wb_prepare_code(u32 tegra_id, u32 seg_address, u32 seg_length);
#endif
diff --git a/arch/arm/include/asm/arch-tegra124/wb_param.h b/arch/arm/include/asm/arch-tegra124/wb_param.h
new file mode 100644
index 0000000000..526228598d
--- /dev/null
+++ b/arch/arm/include/asm/arch-tegra124/wb_param.h
@@ -0,0 +1,598 @@
+/*
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _TEGRA124_WB_PARAM_H_
+#define _TEGRA124_WB_PARAM_H_
+
+#define e(src, op1, op2, dst, dbit) \
+ encode(sdram_offset(src), op1, op2, sdram_offset(dst), dbit)
+
+struct encode_fields encode_list[] = {
+ e(emc_swizzle_rank0_byte0, 26:24, 30:28, swizzle_rank_byte_encode, 0),
+ e(emc_swizzle_rank0_byte1, 26:24, 30:28, swizzle_rank_byte_encode, 1),
+ e(emc_swizzle_rank0_byte2, 26:24, 30:28, swizzle_rank_byte_encode, 2),
+ e(emc_swizzle_rank0_byte3, 26:24, 30:28, swizzle_rank_byte_encode, 3),
+ e(emc_swizzle_rank1_byte0, 26:24, 30:28, swizzle_rank_byte_encode, 4),
+ e(emc_swizzle_rank1_byte1, 26:24, 30:28, swizzle_rank_byte_encode, 5),
+ e(emc_swizzle_rank1_byte2, 26:24, 30:28, swizzle_rank_byte_encode, 6),
+ e(emc_swizzle_rank1_byte3, 26:24, 30:28, swizzle_rank_byte_encode, 7),
+};
+
+#define s(offset, src, scratch, dst) \
+ pack(TYPE_SDRAM, sdram_offset(offset), src, pmc_offset(scratch), dst)
+
+#define m(offset, src, scratch, dst) \
+ pack(TYPE_PLLM, pllm_offset(offset), src, pmc_offset(scratch), dst)
+
+#define c(const, src, scratch, dst) \
+ pack(TYPE_CONST, const, src, pmc_offset(scratch), dst)
+
+struct pack_fields pack_list_1[] = {
+ s(emc_clock_source, 7:0, pmc_scratch6, 15:8),
+ s(emc_clock_source, 31:29, pmc_scratch6, 18:16),
+ s(emc_clock_source, 26:26, pmc_scratch6, 19:19),
+ s(emc_odt_write, 5:0, pmc_scratch6, 25:20),
+ s(emc_odt_write, 11:8, pmc_scratch6, 29:26),
+ s(emc_odt_write, 30:30, pmc_scratch6, 30:30),
+ s(emc_odt_write, 31:31, pmc_scratch6, 31:31),
+ s(emc_xm2dqpadctrl2, 18:16, pmc_scratch7, 22:20),
+ s(emc_xm2dqpadctrl2, 22:20, pmc_scratch7, 25:23),
+ s(emc_xm2dqpadctrl2, 26:24, pmc_scratch7, 28:26),
+ s(emc_xm2dqpadctrl2, 30:28, pmc_scratch7, 31:29),
+ s(emc_xm2dqpadctrl3, 18:16, pmc_scratch8, 22:20),
+ s(emc_xm2dqpadctrl3, 22:20, pmc_scratch8, 25:23),
+ s(emc_xm2dqpadctrl3, 26:24, pmc_scratch8, 28:26),
+ s(emc_xm2dqpadctrl3, 30:28, pmc_scratch8, 31:29),
+ s(emc_txsrdll, 11:0, pmc_scratch9, 31:20),
+ c(0, 31:0, pmc_scratch10, 31:0),
+ s(emc_dsr_vttgen_drv, 5:0, pmc_scratch10, 25:20),
+ s(emc_dsr_vttgen_drv, 18:16, pmc_scratch10, 28:26),
+ s(emc_dsr_vttgen_drv, 26:24, pmc_scratch10, 31:29),
+ s(emc_fbio_spare, 31:24, pmc_scratch11, 7:0),
+ s(emc_fbio_spare, 23:16, pmc_scratch11, 15:8),
+ s(emc_fbio_spare, 15:8, pmc_scratch11, 23:16),
+ s(emc_fbio_spare, 7:0, pmc_scratch11, 31:24),
+ s(emc_cfg_rsv, 31:0, pmc_scratch12, 31:0),
+ s(emc_cdb_cntl2, 31:0, pmc_scratch13, 31:0),
+ s(mc_emem_arb_da_turns, 31:0, pmc_scratch14, 31:0),
+ s(emc_cfg_dig_dll, 0:0, pmc_scratch17, 0:0),
+ s(emc_cfg_dig_dll, 25:2, pmc_scratch17, 24:1),
+ s(emc_cfg_dig_dll, 31:27, pmc_scratch17, 29:25),
+ s(emc_cdb_cntl1, 29:0, pmc_scratch18, 29:0),
+ s(mc_emem_arb_misc0, 14:0, pmc_scratch19, 14:0),
+ s(mc_emem_arb_misc0, 30:16, pmc_scratch19, 29:15),
+ s(emc_xm2dqspadctrl, 4:0, pmc_scratch22, 4:0),
+ s(emc_xm2dqspadctrl, 12:8, pmc_scratch22, 9:5),
+ s(emc_xm2dqspadctrl, 31:14, pmc_scratch22, 27:10),
+ s(emc_rdr, 3:0, pmc_scratch22, 31:28),
+ s(emc_xm2dqpadctrl, 31:4, pmc_scratch23, 27:0),
+ s(emc_rext, 3:0, pmc_scratch23, 31:28),
+ s(emc_xm2comppadctrl, 16:0, pmc_scratch24, 16:0),
+ s(emc_xm2comppadctrl, 24:20, pmc_scratch24, 21:17),
+ s(emc_xm2comppadctrl, 27:27, pmc_scratch24, 22:22),
+ s(emc_xm2comppadctrl, 31:28, pmc_scratch24, 26:23),
+ s(emc_r2w, 4:0, pmc_scratch24, 31:27),
+ s(emc_cfg, 9:1, pmc_scratch25, 8:0),
+ s(emc_cfg, 26:16, pmc_scratch25, 19:9),
+ s(emc_cfg, 31:28, pmc_scratch25, 23:20),
+ s(emc_xm2vttgenpadctrl, 0:0, pmc_scratch25, 24:24),
+ s(emc_xm2vttgenpadctrl, 2:2, pmc_scratch25, 25:25),
+ s(emc_xm2vttgenpadctrl, 18:16, pmc_scratch25, 28:26),
+ s(emc_xm2vttgenpadctrl, 26:24, pmc_scratch25, 31:29),
+ s(emc_zcal_interval, 23:10, pmc_scratch26, 13:0),
+ s(emc_zcal_interval, 9:0, pmc_scratch26, 23:14),
+ s(emc_sel_dpd_ctrl, 5:2, pmc_scratch26, 27:24),
+ s(emc_sel_dpd_ctrl, 8:8, pmc_scratch26, 28:28),
+ s(emc_sel_dpd_ctrl, 18:16, pmc_scratch26, 31:29),
+ s(emc_xm2vttgenpadctrl3, 22:0, pmc_scratch27, 22:0),
+ s(emc_xm2vttgenpadctrl3, 24:24, pmc_scratch27, 23:23),
+ s(emc_swizzle_rank0_byte_cfg, 1:0, pmc_scratch27, 25:24),
+ s(emc_swizzle_rank0_byte_cfg, 5:4, pmc_scratch27, 27:26),
+ s(emc_swizzle_rank0_byte_cfg, 9:8, pmc_scratch27, 29:28),
+ s(emc_swizzle_rank0_byte_cfg, 13:12, pmc_scratch27, 31:30),
+ s(emc_xm2clkpadctrl2, 5:0, pmc_scratch28, 5:0),
+ s(emc_xm2clkpadctrl2, 13:8, pmc_scratch28, 11:6),
+ s(emc_xm2clkpadctrl2, 20:16, pmc_scratch28, 16:12),
+ s(emc_xm2clkpadctrl2, 23:23, pmc_scratch28, 17:17),
+ s(emc_xm2clkpadctrl2, 28:24, pmc_scratch28, 22:18),
+ s(emc_xm2clkpadctrl2, 31:31, pmc_scratch28, 23:23),
+ s(emc_swizzle_rank1_byte_cfg, 1:0, pmc_scratch28, 25:24),
+ s(emc_swizzle_rank1_byte_cfg, 5:4, pmc_scratch28, 27:26),
+ s(emc_swizzle_rank1_byte_cfg, 9:8, pmc_scratch28, 29:28),
+ s(emc_swizzle_rank1_byte_cfg, 13:12, pmc_scratch28, 31:30),
+ s(mc_emem_arb_da_covers, 23:0, pmc_scratch29, 23:0),
+ s(mc_emem_arb_rsv, 7:0, pmc_scratch29, 31:24),
+ s(emc_auto_cal_config, 4:0, pmc_scratch30, 4:0),
+ s(emc_auto_cal_config, 12:8, pmc_scratch30, 9:5),
+ s(emc_auto_cal_config, 18:16, pmc_scratch30, 12:10),
+ s(emc_auto_cal_config, 25:20, pmc_scratch30, 18:13),
+ s(emc_auto_cal_config, 31:28, pmc_scratch30, 22:19),
+ s(emc_rfc, 8:0, pmc_scratch30, 31:23),
+ s(emc_xm2dqspadctrl2, 21:0, pmc_scratch31, 21:0),
+ s(emc_xm2dqspadctrl2, 24:24, pmc_scratch31, 22:22),
+ s(emc_ar2pden, 8:0, pmc_scratch31, 31:23),
+ s(emc_xm2clkpadctrl, 0:0, pmc_scratch32, 0:0),
+ s(emc_xm2clkpadctrl, 4:2, pmc_scratch32, 3:1),
+ s(emc_xm2clkpadctrl, 7:7, pmc_scratch32, 4:4),
+ s(emc_xm2clkpadctrl, 31:14, pmc_scratch32, 22:5),
+ s(emc_rfc_slr, 8:0, pmc_scratch32, 31:23),
+ s(emc_xm2dqspadctrl3, 0:0, pmc_scratch33, 0:0),
+ s(emc_xm2dqspadctrl3, 5:5, pmc_scratch33, 1:1),
+ s(emc_xm2dqspadctrl3, 12:8, pmc_scratch33, 6:2),
+ s(emc_xm2dqspadctrl3, 18:14, pmc_scratch33, 11:7),
+ s(emc_xm2dqspadctrl3, 24:20, pmc_scratch33, 16:12),
+ s(emc_xm2dqspadctrl3, 30:26, pmc_scratch33, 21:17),
+ s(emc_txsr, 9:0, pmc_scratch33, 31:22),
+ s(mc_emem_arb_cfg, 8:0, pmc_scratch40, 8:0),
+ s(mc_emem_arb_cfg, 20:16, pmc_scratch40, 13:9),
+ s(mc_emem_arb_cfg, 27:24, pmc_scratch40, 17:14),
+ s(mc_emem_arb_cfg, 31:28, pmc_scratch40, 21:18),
+ s(emc_mc2emcq, 2:0, pmc_scratch40, 24:22),
+ s(emc_mc2emcq, 10:8, pmc_scratch40, 27:25),
+ s(emc_mc2emcq, 27:24, pmc_scratch40, 31:28),
+ s(emc_auto_cal_interval, 20:0, pmc_scratch42, 20:0),
+ s(mc_emem_arb_outstanding_req, 8:0, pmc_scratch42, 29:21),
+ s(mc_emem_arb_outstanding_req, 31:30, pmc_scratch42, 31:30),
+ s(emc_mrs_wait_cnt2, 9:0, pmc_scratch44, 9:0),
+ s(emc_mrs_wait_cnt2, 25:16, pmc_scratch44, 19:10),
+ s(emc_txdsrvttgen, 11:0, pmc_scratch44, 31:20),
+ s(emc_mrs_wait_cnt, 9:0, pmc_scratch45, 9:0),
+ s(emc_mrs_wait_cnt, 25:16, pmc_scratch45, 19:10),
+ s(emc_cfg_pipe, 1:0, pmc_scratch45, 21:20),
+ s(emc_cfg_pipe, 9:4, pmc_scratch45, 27:22),
+ s(emc_cfg_pipe, 15:12, pmc_scratch45, 31:28),
+ s(emc_xm2dqspadctrl4, 22:18, pmc_scratch46, 4:0),
+ s(emc_xm2dqspadctrl4, 16:12, pmc_scratch46, 9:5),
+ s(emc_xm2dqspadctrl4, 10:6, pmc_scratch46, 14:10),
+ s(emc_xm2dqspadctrl4, 4:0, pmc_scratch46, 19:15),
+ s(emc_zcal_wait_cnt, 9:0, pmc_scratch46, 29:20),
+ s(emc_xm2dqspadctrl5, 22:18, pmc_scratch47, 4:0),
+ s(emc_xm2dqspadctrl5, 16:12, pmc_scratch47, 9:5),
+ s(emc_xm2dqspadctrl5, 10:6, pmc_scratch47, 14:10),
+ s(emc_xm2dqspadctrl5, 4:0, pmc_scratch47, 19:15),
+ s(emc_xm2vttgenpadctrl2, 5:0, pmc_scratch47, 25:20),
+ s(emc_xm2vttgenpadctrl2, 31:28, pmc_scratch47, 29:26),
+ s(emc_xm2dqspadctrl6, 12:8, pmc_scratch48, 4:0),
+ s(emc_xm2dqspadctrl6, 18:14, pmc_scratch48, 9:5),
+ s(emc_xm2dqspadctrl6, 24:20, pmc_scratch48, 14:10),
+ s(emc_xm2dqspadctrl6, 30:26, pmc_scratch48, 19:15),
+ s(emc_auto_cal_config3, 4:0, pmc_scratch48, 24:20),
+ s(emc_auto_cal_config3, 12:8, pmc_scratch48, 29:25),
+ s(emc_fbio_cfg5, 1:0, pmc_scratch48, 31:30),
+ s(emc_dll_xform_quse8, 4:0, pmc_scratch50, 4:0),
+ s(emc_dll_xform_quse8, 22:8, pmc_scratch50, 19:5),
+ s(mc_emem_arb_ring1_throttle, 4:0, pmc_scratch50, 24:20),
+ s(mc_emem_arb_ring1_throttle, 20:16, pmc_scratch50, 29:25),
+ s(emc_fbio_cfg5, 3:2, pmc_scratch50, 31:30),
+ s(emc_dll_xform_quse9, 4:0, pmc_scratch51, 4:0),
+ s(emc_dll_xform_quse9, 22:8, pmc_scratch51, 19:5),
+ s(emc_ctt_term_ctrl, 2:0, pmc_scratch51, 22:20),
+ s(emc_ctt_term_ctrl, 12:8, pmc_scratch51, 27:23),
+ s(emc_ctt_term_ctrl, 31:31, pmc_scratch51, 28:28),
+ s(emc_fbio_cfg6, 2:0, pmc_scratch51, 31:29),
+ s(emc_dll_xform_quse10, 4:0, pmc_scratch56, 4:0),
+ s(emc_dll_xform_quse10, 22:8, pmc_scratch56, 19:5),
+ s(emc_xm2cmdpadctrl, 10:3, pmc_scratch56, 27:20),
+ s(emc_xm2cmdpadctrl, 28:28, pmc_scratch56, 28:28),
+ s(emc_puterm_adj, 1:0, pmc_scratch56, 30:29),
+ s(emc_puterm_adj, 7:7, pmc_scratch56, 31:31),
+ s(emc_dll_xform_quse11, 4:0, pmc_scratch57, 4:0),
+ s(emc_dll_xform_quse11, 22:8, pmc_scratch57, 19:5),
+ s(emc_wdv, 3:0, pmc_scratch57, 31:28),
+ s(emc_dll_xform_quse12, 4:0, pmc_scratch58, 4:0),
+ s(emc_dll_xform_quse12, 22:8, pmc_scratch58, 19:5),
+ s(emc_burst_refresh_num, 3:0, pmc_scratch58, 31:28),
+ s(emc_dll_xform_quse13, 4:0, pmc_scratch59, 4:0),
+ s(emc_dll_xform_quse13, 22:8, pmc_scratch59, 19:5),
+ s(emc_wext, 3:0, pmc_scratch59, 31:28),
+ s(emc_dll_xform_quse14, 4:0, pmc_scratch60, 4:0),
+ s(emc_dll_xform_quse14, 22:8, pmc_scratch60, 19:5),
+ s(emc_clken_override, 3:1, pmc_scratch60, 30:28),
+ s(emc_clken_override, 6:6, pmc_scratch60, 31:31),
+ s(emc_dll_xform_quse15, 4:0, pmc_scratch61, 4:0),
+ s(emc_dll_xform_quse15, 22:8, pmc_scratch61, 19:5),
+ s(emc_r2r, 3:0, pmc_scratch61, 31:28),
+ s(emc_dll_xform_dq4, 4:0, pmc_scratch62, 4:0),
+ s(emc_dll_xform_dq4, 22:8, pmc_scratch62, 19:5),
+ s(emc_rc, 6:0, pmc_scratch62, 26:20),
+ s(emc_w2r, 4:0, pmc_scratch62, 31:27),
+ s(emc_dll_xform_dq5, 4:0, pmc_scratch63, 4:0),
+ s(emc_dll_xform_dq5, 22:8, pmc_scratch63, 19:5),
+ s(emc_tfaw, 6:0, pmc_scratch63, 26:20),
+ s(emc_r2p, 4:0, pmc_scratch63, 31:27),
+ s(emc_dll_xform_dq6, 4:0, pmc_scratch64, 4:0),
+ s(emc_dll_xform_dq6, 22:8, pmc_scratch64, 19:5),
+ s(emc_dli_trim_txdqs0, 6:0, pmc_scratch64, 26:20),
+ s(emc_qsafe, 4:0, pmc_scratch64, 31:27),
+ s(emc_dll_xform_dq7, 4:0, pmc_scratch65, 4:0),
+ s(emc_dll_xform_dq7, 22:8, pmc_scratch65, 19:5),
+ s(emc_dli_trim_txdqs1, 6:0, pmc_scratch65, 26:20),
+ s(emc_tclkstable, 4:0, pmc_scratch65, 31:27),
+ s(emc_auto_cal_config2, 4:0, pmc_scratch66, 4:0),
+ s(emc_auto_cal_config2, 12:8, pmc_scratch66, 9:5),
+ s(emc_auto_cal_config2, 20:16, pmc_scratch66, 14:10),
+ s(emc_auto_cal_config2, 28:24, pmc_scratch66, 19:15),
+ s(emc_dli_trim_txdqs2, 6:0, pmc_scratch66, 26:20),
+ s(emc_tclkstop, 4:0, pmc_scratch66, 31:27),
+ s(mc_emem_arb_misc1, 1:0, pmc_scratch67, 1:0),
+ s(mc_emem_arb_misc1, 12:4, pmc_scratch67, 10:2),
+ s(mc_emem_arb_misc1, 25:21, pmc_scratch67, 15:11),
+ s(mc_emem_arb_misc1, 31:28, pmc_scratch67, 19:16),
+ s(emc_dli_trim_txdqs3, 6:0, pmc_scratch67, 26:20),
+ s(emc_einput_duration, 4:0, pmc_scratch67, 31:27),
+ s(emc_zcal_mrw_cmd, 7:0, pmc_scratch68, 7:0),
+ s(emc_zcal_mrw_cmd, 23:16, pmc_scratch68, 15:8),
+ s(emc_zcal_mrw_cmd, 31:30, pmc_scratch68, 17:16),
+ s(emc_trefbw, 13:0, pmc_scratch68, 31:18),
+ s(emc_xm2cmdpadctrl2, 31:14, pmc_scratch69, 17:0),
+ s(emc_dli_trim_txdqs4, 6:0, pmc_scratch69, 24:18),
+ s(emc_dli_trim_txdqs5, 6:0, pmc_scratch69, 31:25),
+ s(emc_xm2cmdpadctrl3, 31:14, pmc_scratch70, 17:0),
+ s(emc_dli_trim_txdqs6, 6:0, pmc_scratch70, 24:18),
+ s(emc_dli_trim_txdqs7, 6:0, pmc_scratch70, 31:25),
+ s(emc_xm2cmdpadctrl5, 2:0, pmc_scratch71, 2:0),
+ s(emc_xm2cmdpadctrl5, 6:4, pmc_scratch71, 5:3),
+ s(emc_xm2cmdpadctrl5, 10:8, pmc_scratch71, 8:6),
+ s(emc_xm2cmdpadctrl5, 14:12, pmc_scratch71, 11:9),
+ s(emc_xm2cmdpadctrl5, 18:16, pmc_scratch71, 14:12),
+ s(emc_xm2cmdpadctrl5, 22:20, pmc_scratch71, 17:15),
+ s(emc_dli_trim_txdqs8, 6:0, pmc_scratch71, 24:18),
+ s(emc_dli_trim_txdqs9, 6:0, pmc_scratch71, 31:25),
+ s(emc_cdb_cntl3, 17:0, pmc_scratch72, 17:0),
+ s(emc_dli_trim_txdqs10, 6:0, pmc_scratch72, 24:18),
+ s(emc_dli_trim_txdqs11, 6:0, pmc_scratch72, 31:25),
+ s(emc_swizzle_rank0_byte0, 2:0, pmc_scratch73, 2:0),
+ s(emc_swizzle_rank0_byte0, 6:4, pmc_scratch73, 5:3),
+ s(emc_swizzle_rank0_byte0, 10:8, pmc_scratch73, 8:6),
+ s(emc_swizzle_rank0_byte0, 14:12, pmc_scratch73, 11:9),
+ s(emc_swizzle_rank0_byte0, 18:16, pmc_scratch73, 14:12),
+ s(emc_swizzle_rank0_byte0, 22:20, pmc_scratch73, 17:15),
+ s(emc_dli_trim_txdqs12, 6:0, pmc_scratch73, 24:18),
+ s(emc_dli_trim_txdqs13, 6:0, pmc_scratch73, 31:25),
+ s(emc_swizzle_rank0_byte1, 2:0, pmc_scratch74, 2:0),
+ s(emc_swizzle_rank0_byte1, 6:4, pmc_scratch74, 5:3),
+ s(emc_swizzle_rank0_byte1, 10:8, pmc_scratch74, 8:6),
+ s(emc_swizzle_rank0_byte1, 14:12, pmc_scratch74, 11:9),
+ s(emc_swizzle_rank0_byte1, 18:16, pmc_scratch74, 14:12),
+ s(emc_swizzle_rank0_byte1, 22:20, pmc_scratch74, 17:15),
+ s(emc_dli_trim_txdqs14, 6:0, pmc_scratch74, 24:18),
+ s(emc_dli_trim_txdqs15, 6:0, pmc_scratch74, 31:25),
+ s(emc_swizzle_rank0_byte2, 2:0, pmc_scratch75, 2:0),
+ s(emc_swizzle_rank0_byte2, 6:4, pmc_scratch75, 5:3),
+ s(emc_swizzle_rank0_byte2, 10:8, pmc_scratch75, 8:6),
+ s(emc_swizzle_rank0_byte2, 14:12, pmc_scratch75, 11:9),
+ s(emc_swizzle_rank0_byte2, 18:16, pmc_scratch75, 14:12),
+ s(emc_swizzle_rank0_byte2, 22:20, pmc_scratch75, 17:15),
+ s(mc_emem_arb_timing_rp, 6:0, pmc_scratch75, 24:18),
+ s(mc_emem_arb_timing_rc, 6:0, pmc_scratch75, 31:25),
+ s(emc_swizzle_rank0_byte3, 2:0, pmc_scratch76, 2:0),
+ s(emc_swizzle_rank0_byte3, 6:4, pmc_scratch76, 5:3),
+ s(emc_swizzle_rank0_byte3, 10:8, pmc_scratch76, 8:6),
+ s(emc_swizzle_rank0_byte3, 14:12, pmc_scratch76, 11:9),
+ s(emc_swizzle_rank0_byte3, 18:16, pmc_scratch76, 14:12),
+ s(emc_swizzle_rank0_byte3, 22:20, pmc_scratch76, 17:15),
+ s(mc_emem_arb_timing_faw, 6:0, pmc_scratch76, 24:18),
+ s(mc_emem_arb_timing_wap2pre, 6:0, pmc_scratch76, 31:25),
+ s(emc_swizzle_rank1_byte0, 2:0, pmc_scratch77, 2:0),
+ s(emc_swizzle_rank1_byte0, 6:4, pmc_scratch77, 5:3),
+ s(emc_swizzle_rank1_byte0, 10:8, pmc_scratch77, 8:6),
+ s(emc_swizzle_rank1_byte0, 14:12, pmc_scratch77, 11:9),
+ s(emc_swizzle_rank1_byte0, 18:16, pmc_scratch77, 14:12),
+ s(emc_swizzle_rank1_byte0, 22:20, pmc_scratch77, 17:15),
+ s(emc_ras, 5:0, pmc_scratch77, 23:18),
+ s(emc_rp, 5:0, pmc_scratch77, 29:24),
+ s(emc_cfg2, 9:8, pmc_scratch77, 31:30),
+ s(emc_swizzle_rank1_byte1, 2:0, pmc_scratch78, 2:0),
+ s(emc_swizzle_rank1_byte1, 6:4, pmc_scratch78, 5:3),
+ s(emc_swizzle_rank1_byte1, 10:8, pmc_scratch78, 8:6),
+ s(emc_swizzle_rank1_byte1, 14:12, pmc_scratch78, 11:9),
+ s(emc_swizzle_rank1_byte1, 18:16, pmc_scratch78, 14:12),
+ s(emc_swizzle_rank1_byte1, 22:20, pmc_scratch78, 17:15),
+ s(emc_w2p, 5:0, pmc_scratch78, 23:18),
+ s(emc_rd_rcd, 5:0, pmc_scratch78, 29:24),
+ s(emc_cfg2, 27:26, pmc_scratch78, 31:30),
+ s(emc_swizzle_rank1_byte2, 2:0, pmc_scratch79, 2:0),
+ s(emc_swizzle_rank1_byte2, 6:4, pmc_scratch79, 5:3),
+ s(emc_swizzle_rank1_byte2, 10:8, pmc_scratch79, 8:6),
+ s(emc_swizzle_rank1_byte2, 14:12, pmc_scratch79, 11:9),
+ s(emc_swizzle_rank1_byte2, 18:16, pmc_scratch79, 14:12),
+ s(emc_swizzle_rank1_byte2, 22:20, pmc_scratch79, 17:15),
+ s(emc_wr_rcd, 5:0, pmc_scratch79, 23:18),
+ s(emc_quse, 5:0, pmc_scratch79, 29:24),
+ s(emc_fbio_cfg5, 4:4, pmc_scratch79, 31:31),
+ s(emc_swizzle_rank1_byte3, 2:0, pmc_scratch80, 2:0),
+ s(emc_swizzle_rank1_byte3, 6:4, pmc_scratch80, 5:3),
+ s(emc_swizzle_rank1_byte3, 10:8, pmc_scratch80, 8:6),
+ s(emc_swizzle_rank1_byte3, 14:12, pmc_scratch80, 11:9),
+ s(emc_swizzle_rank1_byte3, 18:16, pmc_scratch80, 14:12),
+ s(emc_swizzle_rank1_byte3, 22:20, pmc_scratch80, 17:15),
+ s(emc_qrst, 5:0, pmc_scratch80, 23:18),
+ s(emc_rdv, 5:0, pmc_scratch80, 29:24),
+ s(emc_fbio_cfg5, 6:5, pmc_scratch80, 31:30),
+ s(emc_dyn_self_ref_control, 15:0, pmc_scratch81, 15:0),
+ s(emc_dyn_self_ref_control, 31:31, pmc_scratch81, 16:16),
+ s(emc_pdex2wr, 5:0, pmc_scratch81, 22:17),
+ s(emc_pdex2rd, 5:0, pmc_scratch81, 28:23),
+ s(emc_refresh, 5:0, pmc_scratch82, 5:0),
+ s(emc_refresh, 15:6, pmc_scratch82, 15:6),
+ s(emc_cmdq, 4:0, pmc_scratch82, 20:16),
+ s(emc_cmdq, 10:8, pmc_scratch82, 23:21),
+ s(emc_cmdq, 14:12, pmc_scratch82, 26:24),
+ s(emc_cmdq, 28:24, pmc_scratch82, 31:27),
+ s(emc_acpd_control, 15:0, pmc_scratch83, 15:0),
+ s(emc_cfg_dig_dll_period, 15:0, pmc_scratch83, 31:16),
+ s(emc_dll_xform_dqs0, 4:0, pmc_scratch84, 4:0),
+ s(emc_dll_xform_dqs0, 22:12, pmc_scratch84, 15:5),
+ s(emc_dll_xform_dqs1, 4:0, pmc_scratch84, 20:16),
+ s(emc_dll_xform_dqs1, 22:12, pmc_scratch84, 31:21),
+ s(emc_dll_xform_dqs2, 4:0, pmc_scratch85, 4:0),
+ s(emc_dll_xform_dqs2, 22:12, pmc_scratch85, 15:5),
+ s(emc_dll_xform_dqs3, 4:0, pmc_scratch85, 20:16),
+ s(emc_dll_xform_dqs3, 22:12, pmc_scratch85, 31:21),
+ s(emc_dll_xform_dqs4, 4:0, pmc_scratch86, 4:0),
+ s(emc_dll_xform_dqs4, 22:12, pmc_scratch86, 15:5),
+ s(emc_dll_xform_dqs5, 4:0, pmc_scratch86, 20:16),
+ s(emc_dll_xform_dqs5, 22:12, pmc_scratch86, 31:21),
+ s(emc_dll_xform_dqs6, 4:0, pmc_scratch87, 4:0),
+ s(emc_dll_xform_dqs6, 22:12, pmc_scratch87, 15:5),
+ s(emc_dll_xform_dqs7, 4:0, pmc_scratch87, 20:16),
+ s(emc_dll_xform_dqs7, 22:12, pmc_scratch87, 31:21),
+ s(emc_dll_xform_dqs8, 4:0, pmc_scratch88, 4:0),
+ s(emc_dll_xform_dqs8, 22:12, pmc_scratch88, 15:5),
+ s(emc_dll_xform_dqs9, 4:0, pmc_scratch88, 20:16),
+ s(emc_dll_xform_dqs9, 22:12, pmc_scratch88, 31:21),
+ s(emc_dll_xform_dqs10, 4:0, pmc_scratch89, 4:0),
+ s(emc_dll_xform_dqs10, 22:12, pmc_scratch89, 15:5),
+ s(emc_dll_xform_dqs11, 4:0, pmc_scratch89, 20:16),
+ s(emc_dll_xform_dqs11, 22:12, pmc_scratch89, 31:21),
+ s(emc_dll_xform_dqs12, 4:0, pmc_scratch90, 4:0),
+ s(emc_dll_xform_dqs12, 22:12, pmc_scratch90, 15:5),
+ s(emc_dll_xform_dqs13, 4:0, pmc_scratch90, 20:16),
+ s(emc_dll_xform_dqs13, 22:12, pmc_scratch90, 31:21),
+ s(emc_dll_xform_dqs14, 4:0, pmc_scratch91, 4:0),
+ s(emc_dll_xform_dqs14, 22:12, pmc_scratch91, 15:5),
+ s(emc_dll_xform_dqs15, 4:0, pmc_scratch91, 20:16),
+ s(emc_dll_xform_dqs15, 22:12, pmc_scratch91, 31:21),
+ s(emc_dll_xform_quse0, 4:0, pmc_scratch92, 4:0),
+ s(emc_dll_xform_quse0, 22:12, pmc_scratch92, 15:5),
+ s(emc_dll_xform_quse1, 4:0, pmc_scratch92, 20:16),
+ s(emc_dll_xform_quse1, 22:12, pmc_scratch92, 31:21),
+ s(emc_dll_xform_quse2, 4:0, pmc_scratch93, 4:0),
+ s(emc_dll_xform_quse2, 22:12, pmc_scratch93, 15:5),
+ s(emc_dll_xform_quse3, 4:0, pmc_scratch93, 20:16),
+ s(emc_dll_xform_quse3, 22:12, pmc_scratch93, 31:21),
+ s(emc_dll_xform_quse4, 4:0, pmc_scratch94, 4:0),
+ s(emc_dll_xform_quse4, 22:12, pmc_scratch94, 15:5),
+ s(emc_dll_xform_quse5, 4:0, pmc_scratch94, 20:16),
+ s(emc_dll_xform_quse5, 22:12, pmc_scratch94, 31:21),
+ s(emc_dll_xform_quse6, 4:0, pmc_scratch95, 4:0),
+ s(emc_dll_xform_quse6, 22:12, pmc_scratch95, 15:5),
+ s(emc_dll_xform_quse7, 4:0, pmc_scratch95, 20:16),
+ s(emc_dll_xform_quse7, 22:12, pmc_scratch95, 31:21),
+ s(emc_dll_xform_dq0, 4:0, pmc_scratch96, 4:0),
+ s(emc_dll_xform_dq0, 22:12, pmc_scratch96, 15:5),
+ s(emc_dll_xform_dq1, 4:0, pmc_scratch96, 20:16),
+ s(emc_dll_xform_dq1, 22:12, pmc_scratch96, 31:21),
+ s(emc_dll_xform_dq2, 4:0, pmc_scratch97, 4:0),
+ s(emc_dll_xform_dq2, 22:12, pmc_scratch97, 15:5),
+ s(emc_dll_xform_dq3, 4:0, pmc_scratch97, 20:16),
+ s(emc_dll_xform_dq3, 22:12, pmc_scratch97, 31:21),
+ s(emc_pre_refresh_req_cnt, 15:0, pmc_scratch98, 15:0),
+ s(emc_dll_xform_addr0, 4:0, pmc_scratch98, 20:16),
+ s(emc_dll_xform_addr0, 22:12, pmc_scratch98, 31:21),
+ s(emc_dll_xform_addr1, 4:0, pmc_scratch99, 4:0),
+ s(emc_dll_xform_addr1, 22:12, pmc_scratch99, 15:5),
+ s(emc_dll_xform_addr2, 4:0, pmc_scratch99, 20:16),
+ s(emc_dll_xform_addr2, 22:12, pmc_scratch99, 31:21),
+ s(emc_dll_xform_addr3, 4:0, pmc_scratch100, 4:0),
+ s(emc_dll_xform_addr3, 22:12, pmc_scratch100, 15:5),
+ s(emc_dll_xform_addr4, 4:0, pmc_scratch100, 20:16),
+ s(emc_dll_xform_addr4, 22:12, pmc_scratch100, 31:21),
+ s(emc_dll_xform_addr5, 4:0, pmc_scratch101, 4:0),
+ s(emc_dll_xform_addr5, 22:12, pmc_scratch101, 15:5),
+ s(emc_pchg2pden, 5:0, pmc_scratch102, 5:0),
+ s(emc_act2pden, 5:0, pmc_scratch102, 11:6),
+ s(emc_rw2pden, 5:0, pmc_scratch102, 17:12),
+ s(emc_tcke, 5:0, pmc_scratch102, 23:18),
+ s(emc_trpab, 5:0, pmc_scratch102, 29:24),
+ s(emc_fbio_cfg5, 8:7, pmc_scratch102, 31:30),
+ s(emc_ctt, 5:0, pmc_scratch103, 5:0),
+ s(emc_einput, 5:0, pmc_scratch103, 11:6),
+ s(emc_puterm_extra, 21:16, pmc_scratch103, 17:12),
+ s(emc_tckesr, 5:0, pmc_scratch103, 23:18),
+ s(emc_tpd, 5:0, pmc_scratch103, 29:24),
+ s(emc_fbio_cfg5, 10:9, pmc_scratch103, 31:30),
+ s(emc_rdv_mask, 5:0, pmc_scratch104, 5:0),
+ s(emc_xm2cmdpadctrl4, 0:0, pmc_scratch104, 6:6),
+ s(emc_xm2cmdpadctrl4, 2:2, pmc_scratch104, 7:7),
+ s(emc_xm2cmdpadctrl4, 4:4, pmc_scratch104, 8:8),
+ s(emc_xm2cmdpadctrl4, 6:6, pmc_scratch104, 9:9),
+ s(emc_xm2cmdpadctrl4, 8:8, pmc_scratch104, 10:10),
+ s(emc_xm2cmdpadctrl4, 10:10, pmc_scratch104, 11:11),
+ s(emc_qpop, 5:0, pmc_scratch104, 17:12),
+ s(mc_emem_arb_timing_rcd, 5:0, pmc_scratch104, 23:18),
+ s(mc_emem_arb_timing_ras, 5:0, pmc_scratch104, 29:24),
+ s(emc_fbio_cfg5, 12:11, pmc_scratch104, 31:30),
+ s(mc_emem_arb_timing_rap2pre, 5:0, pmc_scratch105, 5:0),
+ s(mc_emem_arb_timing_r2w, 5:0, pmc_scratch105, 11:6),
+ s(mc_emem_arb_timing_w2r, 5:0, pmc_scratch105, 17:12),
+ s(emc_ibdly, 4:0, pmc_scratch105, 22:18),
+ s(mc_emem_arb_timing_r2r, 4:0, pmc_scratch105, 27:23),
+ s(emc_w2w, 3:0, pmc_scratch105, 31:28),
+ s(mc_emem_arb_timing_w2w, 4:0, pmc_scratch106, 4:0),
+ s(mc_emem_arb_override, 27:27, pmc_scratch106, 5:5),
+ s(mc_emem_arb_override, 26:26, pmc_scratch106, 6:6),
+ s(mc_emem_arb_override, 16:16, pmc_scratch106, 7:7),
+ s(mc_emem_arb_override, 10:10, pmc_scratch106, 8:8),
+ s(mc_emem_arb_override, 4:4, pmc_scratch106, 9:9),
+ s(emc_wdv_mask, 3:0, pmc_scratch106, 13:10),
+ s(emc_ctt_duration, 3:0, pmc_scratch106, 17:14),
+ s(emc_quse_width, 3:0, pmc_scratch106, 21:18),
+ s(emc_puterm_width, 3:0, pmc_scratch106, 25:22),
+ s(emc_bgbias_ctl0, 3:0, pmc_scratch106, 29:26),
+ s(emc_fbio_cfg5, 25:24, pmc_scratch106, 31:30),
+ s(mc_emem_arb_timing_rrd, 3:0, pmc_scratch107, 3:0),
+ s(emc_fbio_cfg5, 23:20, pmc_scratch107, 10:7),
+ s(emc_fbio_cfg5, 15:13, pmc_scratch107, 13:11),
+ s(emc_cfg2, 5:3, pmc_scratch107, 16:14),
+ s(emc_fbio_cfg5, 26:26, pmc_scratch107, 17:17),
+ s(emc_fbio_cfg5, 28:28, pmc_scratch107, 18:18),
+ s(emc_cfg2, 2:0, pmc_scratch107, 21:19),
+ s(emc_cfg2, 7:6, pmc_scratch107, 23:22),
+ s(emc_cfg2, 15:10, pmc_scratch107, 29:24),
+ s(emc_cfg2, 23:22, pmc_scratch107, 31:30),
+ s(emc_cfg2, 25:24, pmc_scratch108, 1:0),
+ s(emc_cfg2, 31:28, pmc_scratch108, 5:2),
+ s(bootrom_patch_data, 31:0, pmc_scratch15, 31:0),
+ s(bootrom_patch_control, 31:0, pmc_scratch16, 31:0),
+ s(emc_dev_select, 1:0, pmc_scratch17, 31:30),
+ s(emc_zcal_warmcoldboot_enables, 1:0, pmc_scratch18, 31:30),
+ s(emc_cfg_dig_dll_period_warmboot, 1:0, pmc_scratch19, 31:30),
+ s(emc_warmboot_extra_modereg_write_en, 0:0, pmc_scratch46, 30:30),
+ s(mc_clken_override_all_warmboot, 0:0, pmc_scratch46, 31:31),
+ s(emc_clken_override_all_warmboot, 0:0, pmc_scratch47, 30:30),
+ s(emc_mrs_warmboot_enable, 0:0, pmc_scratch47, 31:31),
+ s(emc_timing_control_wait, 7:0, pmc_scratch57, 27:20),
+ s(emc_zcal_warmboot_wait, 7:0, pmc_scratch58, 27:20),
+ s(emc_auto_cal_wait, 7:0, pmc_scratch59, 27:20),
+ s(warmboot_wait, 7:0, pmc_scratch60, 27:20),
+ s(emc_pin_program_wait, 7:0, pmc_scratch61, 27:20),
+ s(ahb_arb_xbar_ctrl_mem_init_done, 0:0, pmc_scratch79, 30:30),
+ s(emc_extra_refresh_num, 2:0, pmc_scratch81, 31:29),
+ s(swizzle_rank_byte_encode, 15:0, pmc_scratch101, 31:16),
+ s(memory_type, 2:0, pmc_scratch107, 6:4),
+};
+
+struct pack_fields pack_list_ddr3[] = {
+ s(emc_mrs, 13:0, pmc_scratch5, 13:0),
+ s(emc_emrs, 13:0, pmc_scratch5, 27:14),
+ s(emc_mrs, 21:20, pmc_scratch5, 29:28),
+ s(emc_mrs, 31:30, pmc_scratch5, 31:30),
+ s(emc_emrs2, 13:0, pmc_scratch7, 13:0),
+ s(emc_emrs, 21:20, pmc_scratch7, 15:14),
+ s(emc_emrs, 31:30, pmc_scratch7, 17:16),
+ s(emc_emrs2, 21:20, pmc_scratch7, 19:18),
+ s(emc_emrs3, 13:0, pmc_scratch8, 13:0),
+ s(emc_emrs2, 31:30, pmc_scratch8, 15:14),
+ s(emc_emrs3, 21:20, pmc_scratch8, 17:16),
+ s(emc_emrs3, 31:30, pmc_scratch8, 19:18),
+ s(emc_warmboot_mrs_extra, 13:0, pmc_scratch9, 13:0),
+ s(emc_warmboot_mrs_extra, 31:30, pmc_scratch9, 15:14),
+ s(emc_warmboot_mrs_extra, 21:20, pmc_scratch9, 17:16),
+ s(emc_zq_cal_ddr3_warmboot, 31:30, pmc_scratch9, 19:18),
+ s(emc_mrs, 27:26, pmc_scratch10, 1:0),
+ s(emc_emrs, 27:26, pmc_scratch10, 3:2),
+ s(emc_emrs2, 27:26, pmc_scratch10, 5:4),
+ s(emc_emrs3, 27:26, pmc_scratch10, 7:6),
+ s(emc_warmboot_mrs_extra, 27:27, pmc_scratch10, 8:8),
+ s(emc_warmboot_mrs_extra, 26:26, pmc_scratch10, 9:9),
+ s(emc_zq_cal_ddr3_warmboot, 0:0, pmc_scratch10, 10:10),
+ s(emc_zq_cal_ddr3_warmboot, 4:4, pmc_scratch10, 11:11),
+ c(0, 31:0, pmc_scratch116, 31:0),
+ c(0, 31:0, pmc_scratch117, 31:0),
+};
+
+struct pack_fields pack_list_lpddr2[] = {
+ s(emc_mrw_lpddr2_zcal_warmboot, 23:16, pmc_scratch5, 7:0),
+ s(emc_mrw_lpddr2_zcal_warmboot, 7:0, pmc_scratch5, 15:8),
+ s(emc_warmboot_mrw_extra, 23:16, pmc_scratch5, 23:16),
+ s(emc_warmboot_mrw_extra, 7:0, pmc_scratch5, 31:24),
+ s(emc_mrw_lpddr2_zcal_warmboot, 31:30, pmc_scratch6, 1:0),
+ s(emc_warmboot_mrw_extra, 31:30, pmc_scratch6, 3:2),
+ s(emc_mrw_lpddr2_zcal_warmboot, 27:26, pmc_scratch6, 5:4),
+ s(emc_warmboot_mrw_extra, 27:26, pmc_scratch6, 7:6),
+ s(emc_mrw1, 7:0, pmc_scratch7, 7:0),
+ s(emc_mrw1, 23:16, pmc_scratch7, 15:8),
+ s(emc_mrw1, 27:26, pmc_scratch7, 17:16),
+ s(emc_mrw1, 31:30, pmc_scratch7, 19:18),
+ s(emc_mrw2, 7:0, pmc_scratch8, 7:0),
+ s(emc_mrw2, 23:16, pmc_scratch8, 15:8),
+ s(emc_mrw2, 27:26, pmc_scratch8, 17:16),
+ s(emc_mrw2, 31:30, pmc_scratch8, 19:18),
+ s(emc_mrw3, 7:0, pmc_scratch9, 7:0),
+ s(emc_mrw3, 23:16, pmc_scratch9, 15:8),
+ s(emc_mrw3, 27:26, pmc_scratch9, 17:16),
+ s(emc_mrw3, 31:30, pmc_scratch9, 19:18),
+ s(emc_mrw4, 7:0, pmc_scratch10, 7:0),
+ s(emc_mrw4, 23:16, pmc_scratch10, 15:8),
+ s(emc_mrw4, 27:26, pmc_scratch10, 17:16),
+ s(emc_mrw4, 31:30, pmc_scratch10, 19:18),
+};
+
+struct pack_fields pack_list_2[] = {
+ s(mc_video_protect_gpu_override0, 31:0, pmc_secure_scratch8, 31:0),
+ s(mc_video_protect_vpr_override, 3:0, pmc_secure_scratch9, 3:0),
+ s(mc_video_protect_vpr_override, 11:6, pmc_secure_scratch9, 9:4),
+ s(mc_video_protect_vpr_override, 23:14, pmc_secure_scratch9, 19:10),
+ s(mc_video_protect_vpr_override, 26:26, pmc_secure_scratch9, 20:20),
+ s(mc_video_protect_vpr_override, 31:29, pmc_secure_scratch9, 23:21),
+ s(emc_fbio_cfg5, 19:16, pmc_secure_scratch9, 27:24),
+ s(mc_display_snap_ring, 1:0, pmc_secure_scratch9, 29:28),
+ s(mc_display_snap_ring, 31:31, pmc_secure_scratch9, 30:30),
+ s(emc_adr_cfg, 0:0, pmc_secure_scratch9, 31:31),
+ s(mc_video_protect_gpu_override1, 15:0, pmc_secure_scratch10, 15:0),
+ s(mc_emem_adr_cfg_bank_mask0, 15:0, pmc_secure_scratch10, 31:16),
+ s(mc_emem_adr_cfg_bank_mask1, 15:0, pmc_secure_scratch11, 15:0),
+ s(mc_emem_adr_cfg_bank_mask2, 15:0, pmc_secure_scratch11, 31:16),
+ s(mc_emem_cfg, 13:0, pmc_secure_scratch12, 13:0),
+ s(mc_emem_cfg, 31:31, pmc_secure_scratch12, 14:14),
+ s(mc_video_protect_bom, 31:20, pmc_secure_scratch12, 26:15),
+ s(mc_video_protect_vpr_override1, 1:0, pmc_secure_scratch12, 28:27),
+ s(mc_video_protect_vpr_override1, 4:4, pmc_secure_scratch12, 29:29),
+ s(mc_video_protect_bom_adr_hi, 1:0, pmc_secure_scratch12, 31:30),
+ s(mc_video_protect_size_mb, 11:0, pmc_secure_scratch13, 11:0),
+ s(mc_sec_carveout_bom, 31:20, pmc_secure_scratch13, 23:12),
+ s(mc_emem_adr_cfg_bank_swizzle3, 2:0, pmc_secure_scratch13, 26:24),
+ s(mc_video_protect_write_access, 1:0, pmc_secure_scratch13, 28:27),
+ s(mc_sec_carveout_adr_hi, 1:0, pmc_secure_scratch13, 30:29),
+ s(mc_emem_adr_cfg, 0:0, pmc_secure_scratch13, 31:31),
+ s(mc_sec_carveout_size_mb, 11:0, pmc_secure_scratch14, 11:0),
+ s(mc_mts_carveout_bom, 31:20, pmc_secure_scratch14, 23:12),
+ s(mc_mts_carveout_adr_hi, 1:0, pmc_secure_scratch14, 25:24),
+ s(mc_sec_carveout_protect_write_access, 0:0, pmc_secure_scratch14, 26:26),
+ s(mc_mts_carveout_reg_ctrl, 0:0, pmc_secure_scratch14, 27:27),
+ s(mc_mts_carveout_size_mb, 11:0, pmc_secure_scratch15, 11:0),
+ s(mc_emem_adr_cfg_dev0, 2:0, pmc_secure_scratch15, 14:12),
+ s(mc_emem_adr_cfg_dev0, 9:8, pmc_secure_scratch15, 16:15),
+ s(mc_emem_adr_cfg_dev0, 19:16, pmc_secure_scratch15, 20:17),
+ s(mc_emem_adr_cfg_dev1, 2:0, pmc_secure_scratch15, 23:21),
+ s(mc_emem_adr_cfg_dev1, 9:8, pmc_secure_scratch15, 25:24),
+ s(mc_emem_adr_cfg_dev1, 19:16, pmc_secure_scratch15, 29:26),
+ c(0x1555555, 25:0, pmc_sec_disable2, 25:0),
+ c(0xff, 7:0, pmc_sec_disable, 19:12),
+ c(0, 31:0, pmc_scratch2, 31:0),
+ m(pllm_base, 15:0, pmc_scratch2, 15:0),
+ m(pllm_base, 20:20, pmc_scratch2, 16:16),
+ m(pllm_misc2, 2:0, pmc_scratch2, 19:17),
+ c(0, 31:0, pmc_scratch35, 31:0),
+ m(pllm_misc1, 23:0, pmc_scratch35, 23:0),
+ m(pllm_misc1, 30:28, pmc_scratch35, 30:28),
+ c(0, 31:0, pmc_scratch3, 31:0),
+ s(pllm_input_divider, 7:0, pmc_scratch3, 7:0),
+ c(0x3e, 7:0, pmc_scratch3, 15:8),
+ c(0, 3:0, pmc_scratch3, 19:16),
+ s(pllm_kvco, 0:0, pmc_scratch3, 20:20),
+ s(pllm_kcp, 1:0, pmc_scratch3, 22:21),
+ c(0, 31:0, pmc_scratch36, 31:0),
+ s(pllm_setup_control, 23:0, pmc_scratch36, 23:0),
+ c(0, 31:0, pmc_scratch4, 31:0),
+ s(pllm_stable_time, 9:0, pmc_scratch4, 9:0),
+ s(pllm_stable_time, 9:0, pmc_scratch4, 19:10),
+ s(pllm_select_div2, 0:0, pmc_pllm_wb0_override2, 27:27),
+ c(1, 0:0, pmc_pllp_wb0_override, 11:11),
+};
+
+#endif /* _TEGRA124_WB_PARAM_H_ */
diff --git a/board/nvidia/common/board.c b/board/nvidia/common/board.c
index d01abcee13..5306a56aab 100644
--- a/board/nvidia/common/board.c
+++ b/board/nvidia/common/board.c
@@ -40,6 +40,7 @@
#include <i2c.h>
#include <spi.h>
#include "emc.h"
+#include <libfdt.h>
DECLARE_GLOBAL_DATA_PTR;
@@ -164,9 +165,6 @@ int board_init(void)
#ifdef CONFIG_TEGRA_LP0
/* save Sdram params to PMC 2, 4, and 24 for WB0 */
warmboot_save_sdram_params();
-
- /* prepare the WB code to LP0 location */
- warmboot_prepare_code(TEGRA_LP0_ADDR, TEGRA_LP0_SIZE);
#endif
return 0;
@@ -201,6 +199,34 @@ int board_late_init(void)
/* Make sure we finish initing the LCD */
tegra_lcd_check_next_stage(gd->fdt_blob, 1);
#endif
+
+#ifdef CONFIG_TEGRA_LP0
+ /* prepare the WB code to LP0 location */
+ warmboot_prepare_code(TEGRA_LP0_ADDR, TEGRA_LP0_SIZE);
+#endif
+
+#ifdef CONFIG_TEGRA124
+ if (getenv_yesno("recovery") != 1) {
+ struct pmc_ctlr *pmc = (struct pmc_ctlr *)NV_PA_PMC_BASE;
+ unsigned int scratch = readl(&pmc->pmc_scratch0);
+
+ writel(scratch & ~(1 << 30) & ~(1 << 31), &pmc->pmc_scratch0);
+ if (scratch & (1 << 30)) {
+ printf("Found reboot-mode = bootloader!\n");
+ do_fastboot(NULL, 0, 0, NULL);
+ setenv("recovery", "0");
+ }
+ else if (scratch & (1 << 31)) {
+ printf("Found reboot-mode = recovery!\n");
+ setenv("recovery", "1");
+ }
+ else {
+ printf("No reboot-mode found\n");
+ setenv("recovery", "0");
+ }
+ }
+#endif
+
return 0;
}
@@ -253,3 +279,129 @@ void pad_init_mmc(struct mmc_host *host)
#endif /* T30 */
}
#endif /* MMC */
+
+#ifdef CONFIG_SERIAL_TAG
+void get_board_serial(struct tag_serialnr *serialnr)
+{
+ /*
+ * Check if we can read the EEPROM serial number
+ * and if so, use it instead.
+ */
+#if defined(CONFIG_SERIAL_EEPROM)
+ uchar data_buffer[NUM_SERIAL_ID_BYTES];
+
+ i2c_set_bus_num(EEPROM_I2C_BUS);
+
+ if (i2c_read(EEPROM_I2C_ADDRESS, EEPROM_SERIAL_OFFSET,
+ 1, data_buffer, NUM_SERIAL_ID_BYTES)) {
+ printf("%s: I2C read of bus %d chip %d addr %d failed!\n",
+ __func__, EEPROM_I2C_BUS, EEPROM_I2C_ADDRESS,
+ EEPROM_SERIAL_OFFSET);
+ } else {
+#ifdef DEBUG
+ int i;
+ printf("get_board_serial: Got ");
+ for (i = 0; i < NUM_SERIAL_ID_BYTES; i++)
+ printf("%02X:", data_buffer[i]);
+ printf("\n");
+#endif
+ serialnr->high = data_buffer[2];
+ serialnr->high |= (u32)data_buffer[3] << 8;
+ serialnr->high |= (u32)data_buffer[0] << 16;
+ serialnr->high |= (u32)data_buffer[1] << 24;
+
+ serialnr->low = data_buffer[7];
+ serialnr->low |= (u32)data_buffer[6] << 8;
+ serialnr->low |= (u32)data_buffer[5] << 16;
+ serialnr->low |= (u32)data_buffer[4] << 24;
+
+ printf("SEEPROM serialnr->high = %08X, ->low = %08X\n",
+ serialnr->high, serialnr->low);
+ }
+#else
+ debug("No serial EEPROM onboard, using default values\n");
+
+ /* pass board id to kernel */
+ serialnr->high = CONFIG_TEGRA_SERIAL_HIGH;
+ serialnr->low = CONFIG_TEGRA_SERIAL_LOW;
+ /* TODO: use FDT */
+
+ debug("Config file serialnr->high = %08X, ->low = %08X\n",
+ serialnr->high, serialnr->low);
+
+#endif /* SERIAL_EEPROM */
+}
+
+#ifdef CONFIG_OF_BOARD_SETUP
+void fdt_serial_tag_setup(void *blob, bd_t *bd)
+{
+ struct tag_serialnr serialnr;
+ int offset, ret;
+ u32 val;
+
+ offset = fdt_path_offset(blob, "/chosen/board_info");
+ if (offset < 0) {
+ int chosen = fdt_path_offset(blob, "/chosen");
+ offset = fdt_add_subnode(blob, chosen, "board_info");
+ if (offset < 0) {
+ printf("ERROR: add node /chosen/board_info: %s.\n",
+ fdt_strerror(offset));
+ return;
+ }
+ }
+
+ get_board_serial(&serialnr);
+
+ val = (serialnr.high & 0xFF0000) >> 16;
+ val |= (serialnr.high & 0xFF000000) >> 16;
+ val = cpu_to_fdt32(val);
+ ret = fdt_setprop(blob, offset, "id", &val, sizeof(val));
+ if (ret < 0) {
+ printf("ERROR: could not update id property %s.\n",
+ fdt_strerror(ret));
+ }
+
+ val = serialnr.high & 0xFFFF;
+ val = cpu_to_fdt32(val);
+ ret = fdt_setprop(blob, offset, "sku", &val, sizeof(val));
+ if (ret < 0) {
+ printf("ERROR: could not update sku property %s.\n",
+ fdt_strerror(ret));
+ }
+
+ val = serialnr.low >> 24;
+ val = cpu_to_fdt32(val);
+ ret = fdt_setprop(blob, offset, "fab", &val, sizeof(val));
+ if (ret < 0) {
+ printf("ERROR: could not update fab property %s.\n",
+ fdt_strerror(ret));
+ }
+
+ val = (serialnr.low >> 16) & 0xFF;
+ val = cpu_to_fdt32(val);
+ ret = fdt_setprop(blob, offset, "major_revision", &val, sizeof(val));
+ if (ret < 0) {
+ printf("ERROR: could not update major_revision property %s.\n",
+ fdt_strerror(ret));
+ }
+
+ val = (serialnr.low >> 8) & 0xFF;
+ val = cpu_to_fdt32(val);
+ ret = fdt_setprop(blob, offset, "minor_revision", &val, sizeof(val));
+ if (ret < 0) {
+ printf("ERROR: could not update minor_revision property %s.\n",
+ fdt_strerror(ret));
+ }
+}
+#endif /* OF_BOARD_SETUP */
+#endif /* SERIAL_TAG */
+
+#ifdef CONFIG_OF_BOARD_SETUP
+void ft_board_setup(void *blob, bd_t *bd)
+{
+ /* Overwrite DT file with right board info properties */
+#ifdef CONFIG_SERIAL_TAG
+ fdt_serial_tag_setup(blob, bd);
+#endif /* SERIAL_TAG */
+}
+#endif /* OF_BOARD_SETUP */
diff --git a/board/nvidia/jetson-tk1/jetson-tk1.c b/board/nvidia/jetson-tk1/jetson-tk1.c
index 5d37718f3b..9e6c4d4e3d 100644
--- a/board/nvidia/jetson-tk1/jetson-tk1.c
+++ b/board/nvidia/jetson-tk1/jetson-tk1.c
@@ -8,8 +8,11 @@
#include <common.h>
#include <asm/arch/gpio.h>
#include <asm/arch/pinmux.h>
+#include <asm/gpio.h>
#include "pinmux-config-jetson-tk1.h"
+#define KEY_RECOVERY_GPIO GPIO_PI1
+
/*
* Routine: pinmux_init
* Description: Do individual peripheral pinmux configs
@@ -27,3 +30,39 @@ void pinmux_init(void)
pinmux_config_drvgrp_table(jetson_tk1_drvgrps,
ARRAY_SIZE(jetson_tk1_drvgrps));
}
+
+#ifdef CONFIG_MISC_INIT_R
+int misc_init_r(void)
+{
+ int bootdelay = 2;
+ int abort = 0;
+ unsigned long ts;
+
+ /* Get GPIOs */
+ gpio_request(KEY_RECOVERY_GPIO, "recovery_btn");
+
+ printf("Checking for recovery ...\n");
+ /* delay 1000 ms */
+ while ((bootdelay > 0) && (!abort)) {
+ --bootdelay;
+ /* delay 1000 ms */
+ ts = get_timer(0);
+ do {
+ /* check for FORCE_RECOVERY button */
+ if (!gpio_get_value(KEY_RECOVERY_GPIO)) {
+ printf("\n*** RECOVERY BUTTON ***");
+ setenv("recovery", "1");
+ abort = 1;
+ }
+ udelay(10000);
+ } while (!abort && get_timer(ts) < 1000);
+ printf(".");
+ }
+ printf("\n");
+
+ /* Free GPIOs */
+ gpio_free(KEY_RECOVERY_GPIO);
+
+ return 0;
+}
+#endif
diff --git a/board/nvidia/jetson-tk1/pinmux-config-jetson-tk1.h b/board/nvidia/jetson-tk1/pinmux-config-jetson-tk1.h
index d338818a64..eebf5456c1 100644
--- a/board/nvidia/jetson-tk1/pinmux-config-jetson-tk1.h
+++ b/board/nvidia/jetson-tk1/pinmux-config-jetson-tk1.h
@@ -27,6 +27,7 @@ static const struct tegra_gpio_config jetson_tk1_gpio_inits[] = {
GPIO_INIT(H6, IN),
GPIO_INIT(H7, OUT0),
GPIO_INIT(I0, OUT0),
+ GPIO_INIT(I1, IN),
GPIO_INIT(I2, OUT0),
GPIO_INIT(I4, OUT0),
GPIO_INIT(I5, IN),
@@ -151,7 +152,7 @@ static const struct pmux_pingrp_config jetson_tk1_pingrps[] = {
PINCFG(PH6, DEFAULT, UP, NORMAL, INPUT, DEFAULT, DEFAULT),
PINCFG(PH7, DEFAULT, NORMAL, NORMAL, OUTPUT, DEFAULT, DEFAULT),
PINCFG(PI0, DEFAULT, NORMAL, NORMAL, OUTPUT, DEFAULT, DEFAULT),
- PINCFG(PI1, RSVD1, DOWN, TRISTATE, OUTPUT, DEFAULT, DEFAULT),
+ PINCFG(PI1, DEFAULT, UP, TRISTATE, INPUT, DEFAULT, DEFAULT),
PINCFG(PI2, DEFAULT, NORMAL, NORMAL, OUTPUT, DEFAULT, DEFAULT),
PINCFG(PI3, SPI4, NORMAL, NORMAL, OUTPUT, DEFAULT, DEFAULT),
PINCFG(PI4, DEFAULT, NORMAL, NORMAL, OUTPUT, DEFAULT, DEFAULT),
diff --git a/common/cmd_bootm.c b/common/cmd_bootm.c
index 3265d44f69..34644ffb1a 100644
--- a/common/cmd_bootm.c
+++ b/common/cmd_bootm.c
@@ -21,6 +21,10 @@
#include <linux/ctype.h>
#include <linux/err.h>
#include <u-boot/zlib.h>
+#ifdef CONFIG_CMD_BOOTAI
+#include <android_image.h>
+#include <part.h>
+#endif
DECLARE_GLOBAL_DATA_PTR;
@@ -642,6 +646,278 @@ U_BOOT_CMD(
);
#endif /* CONFIG_CMD_BOOTZ */
+#ifdef CONFIG_CMD_BOOTAI
+
+#ifndef CONFIG_CMD_BOOTAI_BOOT_PART
+#define CONFIG_CMD_BOOTAI_BOOT_PART "boot"
+#endif
+
+#ifndef CONFIG_CMD_BOOTAI_RECOVERY_PART
+#define CONFIG_CMD_BOOTAI_RECOVERY_PART "recovery"
+#endif
+
+void bootimg_print_image_hdr(struct andr_img_hdr *hdr)
+{
+ int i;
+ printf (" Image magic: %s\n", hdr->magic);
+
+ printf (" kernel_size: 0x%x\n", hdr->kernel_size);
+ printf (" kernel_addr: 0x%x\n", hdr->kernel_addr);
+
+ printf (" rdisk_size: 0x%x\n", hdr->ramdisk_size);
+ printf (" rdisk_addr: 0x%x\n", hdr->ramdisk_addr);
+
+ printf (" second_size: 0x%x\n", hdr->second_size);
+ printf (" second_addr: 0x%x\n", hdr->second_addr);
+
+ printf (" tags_addr: 0x%x\n", hdr->tags_addr);
+ printf (" page_size: 0x%x\n", hdr->page_size);
+
+ printf (" dt_size: 0x%x\n", hdr->dt_size);
+
+ printf (" name: %s\n", hdr->name);
+ printf (" cmdline: %s\n", hdr->cmdline);
+
+ for (i=0;i<8;i++)
+ printf (" id[%d]: 0x%x\n", i, hdr->id[i]);
+}
+
+#define _ALIGN(n,pagesz) ((n + (pagesz - 1)) & (~(pagesz - 1)))
+
+int do_fdt(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]);
+
+int do_bootai(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ u32 addr;
+ u32 fdt_addr = 0;
+ u32 kernel_addr = 0x81000000;
+ u32 ramdisk_addr = 0x82100000;
+ char ptn[16];
+ int boot_from_mmc = 0;
+ struct andr_img_hdr *hdr;
+ u64 num_sectors;
+ int status;
+ u32 mmc_instance = 0;
+
+ if (argc < 2) {
+ printf("%s: ERROR not enough arguments!!\n", __func__);
+ return -1;
+ }
+
+ if (!(strcmp(argv[1], "ram"))) {
+ boot_from_mmc = 0;
+ if (argc < 3) {
+ printf("%s: ERROR not enough arguments for 'ram' call!!\n", __func__);
+ return -1;
+ }
+ addr = simple_strtoul(argv[2], NULL, 16);
+ }
+ else {
+ boot_from_mmc = 1;
+ if (argc > 1)
+ mmc_instance = simple_strtoul(argv[1], NULL, 10);
+ addr = CONFIG_USB_FASTBOOT_BUF_ADDR;
+ }
+ if (getenv_yesno("recovery") == 1)
+ strcpy(ptn, CONFIG_CMD_BOOTAI_RECOVERY_PART);
+ else
+ strcpy(ptn, CONFIG_CMD_BOOTAI_BOOT_PART);
+
+ printf("%s: checking fdt_addr = %s\n", __func__, getenv("fdt_addr_r"));
+ fdt_addr = getenv_ulong("fdt_addr_r", 16, fdt_addr);
+ if (!fdt_addr) {
+ printf("%s: invalid fdtaddr in env\n", __func__);
+ goto fail;
+ }
+
+ hdr = (struct andr_img_hdr *) addr;
+
+ if (boot_from_mmc) {
+ int ret;
+ block_dev_desc_t *dev_desc;
+ disk_partition_t info;
+ unsigned sector;
+
+ memset(hdr, 0, sizeof(struct andr_img_hdr));
+
+ dev_desc = get_dev("mmc", mmc_instance);
+ if (!dev_desc || dev_desc->type == DEV_TYPE_UNKNOWN) {
+ printf("%s: invalid mmc device\n", __func__);
+ goto fail;
+ }
+
+ ret = get_partition_info_efi_by_name(dev_desc, ptn, &info);
+ if (ret) {
+ printf("%s: cannot find '%s' partition\n", __func__, ptn);
+ goto fail;
+ }
+ num_sectors = ((sizeof(struct andr_img_hdr) / info.blksz) + 1);
+ printf("%s: MMC read %llu sectors * blksz(%lu) @ %lu (size= %lu)\n", __func__, num_sectors, info.blksz, info.start, info.size);
+ dev_desc->block_read(dev_desc->dev, info.start, num_sectors, (void*)hdr);
+ if (memcmp(hdr->magic, ANDR_BOOT_MAGIC, 8)) {
+ printf("%s: bad boot image magic\n", __func__);
+ goto fail;
+ }
+
+ /* HACK: check if ramdisk_addr is an offset rather than full addr */
+ /* HACK: shouldn't need every device to define MEMORY_BASE */
+ if (hdr->ramdisk_addr < MEMORY_BASE)
+ hdr->ramdisk_addr += MEMORY_BASE;
+
+ /* print kernel info */
+ bootimg_print_image_hdr(hdr);
+ printf("\n\nramdisk sector count:%d\n", (int)(hdr->ramdisk_size / info.blksz) + 1);
+
+ /* read kernel */
+ sector = info.start + (hdr->page_size / info.blksz);
+ num_sectors = ((hdr->kernel_size / info.blksz) + 1);
+#ifndef CONFIG_CMD_BOOTAI_IGNORE_HDR_ADDR
+ kernel_addr = hdr->kernel_addr;
+#endif
+ status = dev_desc->block_read(dev_desc->dev, sector, num_sectors, (void*)kernel_addr);
+ if (status < 0) {
+ printf("%s: Could not read kernel image\n", __func__);
+ goto fail;
+ }
+
+ /* read ramdisk */
+ sector += _ALIGN(hdr->kernel_size, hdr->page_size) / info.blksz;
+ num_sectors = ((hdr->ramdisk_size / info.blksz) + 1);
+#ifndef CONFIG_CMD_BOOTAI_IGNORE_HDR_ADDR
+ ramdisk_addr = hdr->ramdisk_addr;
+#endif
+ status = dev_desc->block_read(dev_desc->dev, sector, num_sectors, (void*)ramdisk_addr);
+ if(status < 0) {
+ printf("%s: Could not read ramdisk\n", __func__);
+ goto fail;
+ }
+
+ if ((hdr->second_size) && (!hdr->dt_size)) {
+ /* read devtree */
+ sector += _ALIGN(hdr->ramdisk_size, hdr->page_size) / info.blksz;
+ debug("*** %s::devtree sector (second_size) == %u\n", __func__, sector);
+ num_sectors = ((hdr->second_size / info.blksz) + 1);
+ status = dev_desc->block_read(dev_desc->dev, sector, num_sectors, (void*)fdt_addr);
+ if(status < 0) {
+ printf("booti: Could not read devtree (second_size)\n");
+ goto fail;
+ }
+ }
+ else if (hdr->dt_size) {
+ /* read devtree (preferring dt_size value */
+ sector += _ALIGN(hdr->ramdisk_size, hdr->page_size) / info.blksz;
+ debug("*** %s::devtree sector (dt_size) == %u\n", __func__, sector);
+ num_sectors = ((hdr->dt_size / info.blksz) + 1);
+ status = dev_desc->block_read(dev_desc->dev, sector, num_sectors, (void*)fdt_addr);
+ if(status < 0) {
+ printf("%s: Could not read devtree (dt_size)\n", __func__);
+ goto fail;
+ }
+ }
+ else {
+ /* load 1mb of DTB partition */
+ }
+ }else {
+ u32 kaddr, raddr;
+
+ printf("Boot image downloaded using fastboot\n");
+
+ status = memcmp(hdr->magic, ANDR_BOOT_MAGIC, 8);
+ if (status != 0) {
+ printf("%s: bad boot image magic\n", __func__);
+ goto fail;
+ }
+
+ /* print kernel info */
+ bootimg_print_image_hdr(hdr);
+
+ kaddr = addr + hdr->page_size;
+ raddr = kaddr + _ALIGN(hdr->kernel_size, hdr->page_size);
+#ifndef CONFIG_CMD_BOOTAI_IGNORE_HDR_ADDR
+ kernel_addr = hdr->kernel_addr;
+#endif
+ memmove((void *) kernel_addr, (void *)kaddr, hdr->kernel_size);
+
+ /* check if ramdisk_addr is an offset rather than full addr */
+ if (hdr->ramdisk_addr < MEMORY_BASE)
+ hdr->ramdisk_addr += MEMORY_BASE;
+
+#ifndef CONFIG_CMD_BOOTAI_IGNORE_HDR_ADDR
+ ramdisk_addr = hdr->ramdisk_addr;
+#endif
+ memmove((void *) ramdisk_addr, (void *)raddr, hdr->ramdisk_size);
+
+ raddr += _ALIGN(hdr->ramdisk_size, hdr->page_size);
+
+ if ((hdr->second_size) && (!hdr->dt_size)) {
+ memmove((void *) fdt_addr, (void *)raddr, hdr->second_size);
+ }
+ else if (hdr->dt_size) {
+ raddr += _ALIGN(hdr->second_size, hdr->page_size);
+ memmove((void *) fdt_addr, (void *)raddr, hdr->dt_size);
+ }
+ else {
+ /* load 1mb of DTB partition */
+ }
+ }
+
+ // add boot.img cmdline to dtbootargs
+ if (hdr->cmdline) {
+ char temp[1024]; /* twice the size as normal */
+ char *append = getenv("bootargs_append");
+ if (append) {
+ sprintf(temp, "%s %s", append, hdr->cmdline);
+ setenv("bootargs", temp);
+ }
+ }
+
+ printf("kernel @ %08x (%d)\n", kernel_addr, hdr->kernel_size);
+ printf("ramdisk @ %08x (%d)\n", ramdisk_addr, hdr->ramdisk_size);
+ printf("dtb @ %08x (%d)\n", fdt_addr, hdr->second_size);
+ printf("dt-size (%d)\n", hdr->dt_size);
+
+ status = do_bootm_states(cmdtp, flag, argc, argv, BOOTM_STATE_START,
+ &images, 1);
+
+ images.ep = kernel_addr;
+ images.rd_start = ramdisk_addr;
+ images.rd_end = ramdisk_addr + hdr->ramdisk_size;
+ if ((hdr->second_size) && (!hdr->dt_size)) {
+ images.ft_len = hdr->second_size;
+ images.ft_addr = (void *)fdt_addr;
+ }
+ else if (hdr->dt_size) {
+ images.ft_len = hdr->dt_size;
+ images.ft_addr = (void *)fdt_addr;
+ }
+ /*
+ * We are doing the BOOTM_STATE_LOADOS state ourselves, so must
+ * disable interrupts ourselves
+ */
+ bootm_disable_interrupts();
+
+ images.os.os = IH_OS_LINUX;
+ status = do_bootm_states(cmdtp, flag, argc, argv,
+ BOOTM_STATE_OS_PREP | BOOTM_STATE_OS_FAKE_GO |
+ BOOTM_STATE_OS_GO,
+ &images, 1);
+
+ printf("%s: Control returned to monitor - resetting...\n", __func__);
+ return status;
+
+fail:
+ return 1;
+}
+
+
+U_BOOT_CMD(
+ bootai, 3, 1, do_bootai,
+ "bootai - boot android bootimg from memory\n",
+ "<addr>\n - boot application image stored in memory\n"
+ "\t'addr' should be the address of boot image which is zImage+ramdisk.img\n"
+);
+#endif /* CONFIG_CMD_BOOTAI */
+
#ifdef CONFIG_CMD_BOOTI
/* See Documentation/arm64/booting.txt in the Linux kernel */
struct Image_header {
diff --git a/common/cmd_fastboot.c b/common/cmd_fastboot.c
index 909616dcb7..e17b3fa232 100644
--- a/common/cmd_fastboot.c
+++ b/common/cmd_fastboot.c
@@ -11,7 +11,7 @@
#include <command.h>
#include <g_dnl.h>
-static int do_fastboot(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
+int do_fastboot(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
{
int ret;
diff --git a/drivers/mmc/tegra_mmc.c b/drivers/mmc/tegra_mmc.c
index ca9c4aa15f..5ecc2c97d2 100644
--- a/drivers/mmc/tegra_mmc.c
+++ b/drivers/mmc/tegra_mmc.c
@@ -332,7 +332,13 @@ static int tegra_mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd,
}
len = data->blocks * data->blocksize;
- bounce_buffer_start(&bbstate, buf, len, bbflags);
+ ret = bounce_buffer_start(&bbstate, buf, len, bbflags);
+ if (ret) {
+ printf("%s: bounce_buffer_start failed with error %d "
+ "(buf = %p, len = %u, flags = %u)\n",
+ __func__, ret, buf, len, bbflags);
+ return ret;
+ }
}
ret = mmc_send_cmd_bounced(mmc, cmd, data, &bbstate);
diff --git a/drivers/usb/gadget/f_fastboot.c b/drivers/usb/gadget/f_fastboot.c
index 71b62e5005..990fcb43de 100644
--- a/drivers/usb/gadget/f_fastboot.c
+++ b/drivers/usb/gadget/f_fastboot.c
@@ -23,6 +23,11 @@
#ifdef CONFIG_FASTBOOT_FLASH_MMC_DEV
#include <fb_mmc.h>
#endif
+#if defined(CONFIG_TEGRA124)
+#include <asm/io.h>
+#include <asm/arch-tegra/pmc.h>
+#include <android_image.h>
+#endif
#define FASTBOOT_VERSION "0.4"
@@ -319,6 +324,18 @@ static void compl_do_reset(struct usb_ep *ep, struct usb_request *req)
static void cb_reboot(struct usb_ep *ep, struct usb_request *req)
{
+#if defined(CONFIG_TEGRA124)
+ char *cmd = req->buf;
+ struct pmc_ctlr *pmc = (struct pmc_ctlr *)NV_PA_PMC_BASE;
+ if (strncmp("-bootloader", cmd + 6, 11) == 0) {
+ printf("Setting reboot-bootloader!\n");
+ writel(readl(&pmc->pmc_scratch0) | (1 << 30), &pmc->pmc_scratch0);
+ }
+ else if (strncmp("-recovery", cmd + 6, 9) == 0) {
+ printf("Setting reboot-recovery!\n");
+ writel(readl(&pmc->pmc_scratch0) | (1 << 31), &pmc->pmc_scratch0);
+ }
+#endif
fastboot_func->in_req->complete = compl_do_reset;
fastboot_tx_write_str("OKAY");
}
@@ -463,12 +480,21 @@ static void cb_download(struct usb_ep *ep, struct usb_request *req)
static void do_bootm_on_complete(struct usb_ep *ep, struct usb_request *req)
{
char boot_addr_start[12];
+#ifdef CONFIG_CMD_BOOTAI
+ char *bootm_args[] = { "bootai", "ram", boot_addr_start, NULL };
+#else
char *bootm_args[] = { "bootm", boot_addr_start, NULL };
+#endif
puts("Booting kernel..\n");
+#ifdef CONFIG_CMD_BOOTAI
+ sprintf(boot_addr_start, "0x%x", CONFIG_USB_FASTBOOT_BUF_ADDR);
+ do_bootai(NULL, 0, 3, bootm_args);
+#else
sprintf(boot_addr_start, "0x%lx", load_addr);
do_bootm(NULL, 0, 2, bootm_args);
+#endif
/* This only happens if image is somehow faulty so we start over */
do_reset(NULL, 0, 0, NULL);
@@ -502,6 +528,26 @@ static void cb_flash(struct usb_ep *ep, struct usb_request *req)
}
#endif
+static void cb_oem(struct usb_ep *ep, struct usb_request *req)
+{
+ char *cmd = req->buf;
+#if defined(CONFIG_TEGRA124)
+ struct pmc_ctlr *pmc = (struct pmc_ctlr *)NV_PA_PMC_BASE;
+ if (strncmp("recovery", cmd + 4, 8) == 0) {
+ printf("Setting reboot-recovery!\n");
+ writel(readl(&pmc->pmc_scratch0) | (1 << 31), &pmc->pmc_scratch0);
+ fastboot_func->in_req->complete = compl_do_reset;
+ fastboot_tx_write_str("OKAY");
+ } else
+#endif
+ if (strncmp("unlock", cmd + 4, 8) == 0) {
+ fastboot_tx_write_str("FAILnot implemented");
+ }
+ else {
+ fastboot_tx_write_str("FAILunknown oem command");
+ }
+}
+
struct cmd_dispatch_info {
char *cmd;
void (*cb)(struct usb_ep *ep, struct usb_request *req);
@@ -527,6 +573,10 @@ static const struct cmd_dispatch_info cmd_dispatch_info[] = {
.cb = cb_flash,
},
#endif
+ {
+ .cmd = "oem",
+ .cb = cb_oem,
+ },
};
static void rx_handler_command(struct usb_ep *ep, struct usb_request *req)
diff --git a/include/android_image.h b/include/android_image.h
index 094d60afe8..e982111484 100644
--- a/include/android_image.h
+++ b/include/android_image.h
@@ -31,7 +31,8 @@ struct andr_img_hdr {
u32 tags_addr; /* physical addr for kernel tags */
u32 page_size; /* flash page size we assume */
- u32 unused[2]; /* future expansion: should be 0 */
+ u32 dt_size; /* device tree in bytes */
+ u32 unused; /* future expansion: should be 0 */
char name[ANDR_BOOT_NAME_SIZE]; /* asciiz product name */
diff --git a/include/command.h b/include/command.h
index 6f06db1cc3..dc1d4ba73b 100644
--- a/include/command.h
+++ b/include/command.h
@@ -89,12 +89,19 @@ int cmd_process_error(cmd_tbl_t *cmdtp, int err);
extern int cmd_get_data_size(char* arg, int default_size);
#endif
+#ifdef CONFIG_CMD_FASTBOOT
+extern int do_fastboot(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]);
+#endif
+
#ifdef CONFIG_CMD_BOOTD
extern int do_bootd(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]);
#endif
#ifdef CONFIG_CMD_BOOTM
extern int do_bootm(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]);
extern int bootm_maybe_autostart(cmd_tbl_t *cmdtp, const char *cmd);
+#ifdef CONFIG_CMD_BOOTAI
+extern int do_bootai(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]);
+#endif
#else
static inline int bootm_maybe_autostart(cmd_tbl_t *cmdtp, const char *cmd)
{
diff --git a/include/config_distro_bootcmd.h b/include/config_distro_bootcmd.h
index be616e8bfd..56cc33745c 100644
--- a/include/config_distro_bootcmd.h
+++ b/include/config_distro_bootcmd.h
@@ -28,6 +28,25 @@
#define BOOTENV_DEV_NAME_BLKDEV(devtypeu, devtypel, instance) \
#devtypel #instance " "
+#ifdef CONFIG_CMD_BOOTAI
+#define BOOTENV_DEV_BLKDEV_ANDROID(devtypeu, devtypel, instance) \
+ "bootcmd_" #devtypel #instance "=" \
+ "if mmc dev " #instance "; " \
+ "then setenv devtype mmc; " \
+ "setenv devnum " #instance "; " \
+ "bootai " #instance "; fi\0"
+
+#define BOOTENV_SHARED_ANDROID
+#define BOOTENV_DEV_ANDROID BOOTENV_DEV_BLKDEV_ANDROID
+#define BOOTENV_DEV_NAME_ANDROID BOOTENV_DEV_NAME_BLKDEV
+#else
+#define BOOTENV_SHARED_ANDROID
+#define BOOTENV_DEV_ANDROID \
+ BOOT_TARGET_DEVICES_references_ANDROID_without_CONFIG_CMD_BOOTAI
+#define BOOTENV_DEV_NAME_ANDROID \
+ BOOT_TARGET_DEVICES_references_ANDROID_without_CONFIG_CMD_BOOTAI
+#endif
+
#ifdef CONFIG_CMD_MMC
#define BOOTENV_SHARED_MMC BOOTENV_SHARED_BLKDEV(mmc)
#define BOOTENV_DEV_MMC BOOTENV_DEV_BLKDEV
diff --git a/include/configs/jetson-tk1.h b/include/configs/jetson-tk1.h
index d67c025b9c..bf522b6990 100644
--- a/include/configs/jetson-tk1.h
+++ b/include/configs/jetson-tk1.h
@@ -10,8 +10,36 @@
#include <linux/sizes.h>
+/* LP0 suspend / resume */
+#define CONFIG_TEGRA_LP0
+#define CONFIG_AES
+
#include "tegra124-common.h"
+#ifdef CONFIG_SYS_MALLOC_LEN
+#undef CONFIG_SYS_MALLOC_LEN
+#endif
+#define CONFIG_SYS_MALLOC_LEN (128 << 20) /* 128MB for fastboot bounce_buffer */
+
+#ifdef CONFIG_TEGRA_LP0
+#define CONFIG_TEGRA124_LP0
+#endif
+
+#define CONFIG_OF_LIBFDT
+#define CONFIG_OF_BOARD_SETUP
+#define CONFIG_MISC_INIT_R /* call misc_init_r during start up */
+
+#define CONFIG_SETUP_MEMORY_TAGS 1
+#define CONFIG_INITRD_TAG 1
+#define CONFIG_SERIAL_TAG 1
+
+/* The following are used to retrieve the board id from an eeprom */
+#define CONFIG_SERIAL_EEPROM
+#define EEPROM_I2C_BUS 1
+#define EEPROM_I2C_ADDRESS 0x56
+#define EEPROM_SERIAL_OFFSET 0x04
+#define NUM_SERIAL_ID_BYTES 8
+
/* High-level configuration options */
#define V_PROMPT "Tegra124 (Jetson TK1) # "
#define CONFIG_TEGRA_BOARD_STRING "NVIDIA Jetson TK1"
@@ -22,6 +50,7 @@
#define CONFIG_SYS_NS16550_COM1 NV_PA_APB_UARTD_BASE
#define CONFIG_BOARD_EARLY_INIT_F
+#define CONFIG_BOARD_LATE_INIT
/* I2C */
#define CONFIG_SYS_I2C_TEGRA
@@ -70,6 +99,36 @@
#define CONFIG_CMD_NET
#define CONFIG_CMD_DHCP
+/* Fastboot support */
+#define CONFIG_CMD_FASTBOOT
+
+#ifdef CONFIG_CMD_FASTBOOT
+#define CONFIG_ANDROID_BOOT_IMAGE
+#define CONFIG_CMD_BOOTAI
+#define CONFIG_CMD_BOOTAI_IGNORE_HDR_ADDR
+#define MEMORY_BASE 0x80000000
+#define CONFIG_ADDR_DOWNLOAD (MEMORY_BASE + 0x12000000)
+#define CONFIG_USB_FASTBOOT_BUF_ADDR CONFIG_ADDR_DOWNLOAD
+#define CONFIG_USB_FASTBOOT_BUF_SIZE 0x40000000
+#define CONFIG_FASTBOOT_FLASH
+#define CONFIG_FASTBOOT_FLASH_MMC_DEV 0
+#define BOARD_EXTRA_ENV_SETTINGS \
+ "bootargs_append=" \
+ "init=init console=ttyS0,115200n8 " \
+ "lp0_vec=2064@0xf46ff000 mem=1862M@2048M vpr=151M@3945M tsec=32M@3913M " \
+ "core_edp_mv=1150 core_edp_ma=4000 " \
+ "tegraid=40.1.1.0.0 tegra_fbmem=32899072@0xad012000 fbcon=map:1 " \
+ "video=tegrafb memtype=255 ddr_die=2048M@2048M section=256M " \
+ "debug_uartport=lsport,3 " \
+ "power_supply=Adapter audio_codec=rt5640 " \
+ "modem_id=0 commchip_id=0 " \
+ "usbcore.old_scheme_first=1 usb_port_owner_info=0 " \
+ "lane_owner_info=6 emc_max_dvfs=0 touch_id=0@0 " \
+ "pmuboard=0x0177:0x0000:0x02:0x43:0x00 " \
+ "otf_key=c75e5bb91eb3bd947560357b64422f85 " \
+ "board_info=0x0177:0x0000:0x02:0x43:0x00\0"
+#endif
+
#include "tegra-common-usb-gadget.h"
#include "tegra-common-post.h"
diff --git a/include/configs/tegra-common-post.h b/include/configs/tegra-common-post.h
index 23e3c8af31..dfe0229934 100644
--- a/include/configs/tegra-common-post.h
+++ b/include/configs/tegra-common-post.h
@@ -9,12 +9,24 @@
#define __TEGRA_COMMON_POST_H
#ifndef CONFIG_SPL_BUILD
+#ifdef CONFIG_CMD_BOOTAI
+#define CONFIG_CMD_BOOTAI_BOOT_PART "LNX"
+#define CONFIG_CMD_BOOTAI_RECOVERY_PART "SOS"
#define BOOT_TARGET_DEVICES(func) \
func(MMC, mmc, 1) \
+ func(ANDROID, android, 0) \
func(MMC, mmc, 0) \
func(USB, usb, 0) \
func(PXE, pxe, na) \
func(DHCP, dhcp, na)
+#else
+#define BOOT_TARGET_DEVICES(func) \
+ func(MMC, mmc, 1) \
+ func(MMC, mmc, 0) \
+ func(USB, usb, 0) \
+ func(PXE, pxe, na) \
+ func(DHCP, dhcp, na)
+#endif
#include <config_distro_bootcmd.h>
#else
#define BOOTENV
diff --git a/include/configs/tegra-common-usb-gadget.h b/include/configs/tegra-common-usb-gadget.h
index 287460c132..ea3794feb3 100644
--- a/include/configs/tegra-common-usb-gadget.h
+++ b/include/configs/tegra-common-usb-gadget.h
@@ -15,8 +15,14 @@
#define CONFIG_CI_UDC
#define CONFIG_CI_UDC_HAS_HOSTPC
#define CONFIG_USB_GADGET_DUALSPEED
+#ifdef CONFIG_CMD_FASTBOOT
+/* Use Google fastboot vid/pid */
+#define CONFIG_G_DNL_VENDOR_NUM 0x18d1
+#define CONFIG_G_DNL_PRODUCT_NUM 0x0100
+#else
#define CONFIG_G_DNL_VENDOR_NUM 0x0955
#define CONFIG_G_DNL_PRODUCT_NUM 0x701A
+#endif
#define CONFIG_G_DNL_MANUFACTURER "NVIDIA"
#define CONFIG_USBDOWNLOAD_GADGET
/* USB mass storage protocol */
diff --git a/include/configs/tegra-common.h b/include/configs/tegra-common.h
index 834b3d5686..ed80b45bfe 100644
--- a/include/configs/tegra-common.h
+++ b/include/configs/tegra-common.h
@@ -105,7 +105,7 @@
* Increasing the size of the IO buffer as default nfsargs size is more
* than 256 and so it is not possible to edit it
*/
-#define CONFIG_SYS_CBSIZE (256 * 2) /* Console I/O Buffer Size */
+#define CONFIG_SYS_CBSIZE (512 * 2) /* Console I/O Buffer Size */
/* Print Buffer Size */
#define CONFIG_SYS_PBSIZE (CONFIG_SYS_CBSIZE + \
sizeof(CONFIG_SYS_PROMPT) + 16)
diff --git a/include/configs/tegra124-common.h b/include/configs/tegra124-common.h
index 61e5026574..9fe04f81de 100644
--- a/include/configs/tegra124-common.h
+++ b/include/configs/tegra124-common.h
@@ -76,4 +76,10 @@
#define CONFIG_USB_EHCI_TXFIFO_THRESH 0x10
#define CONFIG_SYS_USB_EHCI_MAX_ROOT_PORTS 1
+#ifdef CONFIG_TEGRA_LP0
+#define TEGRA_LP0_ADDR 0xF46FF000
+#define TEGRA_LP0_SIZE 0x2000
+#define TEGRA_LP0_ALIGN 0x10
+#endif
+
#endif /* _TEGRA124_COMMON_H_ */