Merge branch 'master' of https://source.denx.de/u-boot/custodians/u-boot-tegra
diff --git a/arch/arm/dts/tegra114.dtsi b/arch/arm/dts/tegra114.dtsi
index 8932ea3..68ee7f3 100644
--- a/arch/arm/dts/tegra114.dtsi
+++ b/arch/arm/dts/tegra114.dtsi
@@ -312,7 +312,7 @@
 	};
 
 	pwm: pwm@7000a000 {
-		compatible = "nvidia,tegra114-pwm", "nvidia,tegra20-pwm";
+		compatible = "nvidia,tegra114-pwm";
 		reg = <0x7000a000 0x100>;
 		#pwm-cells = <2>;
 		clocks = <&tegra_car TEGRA114_CLK_PWM>;
diff --git a/arch/arm/dts/tegra124.dtsi b/arch/arm/dts/tegra124.dtsi
index f473ba2..ffec9ca 100644
--- a/arch/arm/dts/tegra124.dtsi
+++ b/arch/arm/dts/tegra124.dtsi
@@ -377,7 +377,7 @@
 	};
 
 	pwm: pwm@7000a000 {
-		compatible = "nvidia,tegra124-pwm", "nvidia,tegra20-pwm";
+		compatible = "nvidia,tegra124-pwm", "nvidia,tegra114-pwm";
 		reg = <0x7000a000 0x100>;
 		#pwm-cells = <2>;
 		clocks = <&tegra_car TEGRA124_CLK_PWM>;
diff --git a/arch/arm/include/asm/arch-tegra/clock.h b/arch/arm/include/asm/arch-tegra/clock.h
index 1dd5d07..61ef81e 100644
--- a/arch/arm/include/asm/arch-tegra/clock.h
+++ b/arch/arm/include/asm/arch-tegra/clock.h
@@ -271,6 +271,19 @@
 int clock_decode_periph_id(struct udevice *dev);
 
 /**
+ * Get periph clock id and its parent from device tree.
+ *
+ * This works by looking up the peripheral's 'clocks' node and reading out
+ * the second and fourth cells, which are the peripheral and PLL clock numbers.
+ *
+ * @param dev          udevice associated with FDT node
+ * @param clk_id       pointer to int array of 2 values
+ *                     first is periph clock, second is
+ *                     its PLL parent according to FDT.
+ */
+int clock_decode_pair(struct udevice *dev, int *clk_id);
+
+/**
  * Checks if the oscillator bypass is enabled (XOBP bit)
  *
  * Return: 1 if bypass is enabled, 0 if not
@@ -354,6 +367,14 @@
  */
 enum periph_id clk_id_to_periph_id(int clk_id);
 
+/*
+ * Convert a device tree clock ID to our PLL ID.
+ *
+ * @param clk_id	Clock ID according to tegra device tree binding
+ * Return: clock ID, or CLOCK_ID_NONE if the clock ID is invalid
+ */
+enum clock_id clk_id_to_pll_id(int clk_id);
+
 /**
  * Set the output frequency you want for each PLL clock.
  * PLL output frequencies are programmed by setting their N, M and P values.
diff --git a/arch/arm/include/asm/arch-tegra/crypto.h b/arch/arm/include/asm/arch-tegra/crypto.h
new file mode 100644
index 0000000..7646163
--- /dev/null
+++ b/arch/arm/include/asm/arch-tegra/crypto.h
@@ -0,0 +1,47 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright (c) 2011 The Chromium OS Authors.
+ * (C) Copyright 2010 - 2011 NVIDIA Corporation <www.nvidia.com>
+ */
+
+#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 int length, u8 *signature);
+
+/**
+ * Sign an encrypted block of data
+ *
+ * \param source	Source data
+ * \param length	Size of source data
+ * \param signature	Destination address for signature, AES_KEY_LENGTH bytes
+ * \param key		AES128 encryption key
+ */
+int sign_enc_data_block(u8 *source, unsigned int length, u8 *signature, u8 *key);
+
+/**
+ * Encrypt a block of data
+ *
+ * \param source	Source data
+ * \param length	Size of source data
+ * \param key		AES128 encryption key
+ */
+int encrypt_data_block(u8 *source, unsigned int length, u8 *key);
+
+/**
+ * Decrypt a block of data
+ *
+ * \param source	Source data
+ * \param length	Size of source data
+ * \param key		AES128 encryption key
+ */
+int decrypt_data_block(u8 *source, unsigned int length, u8 *key);
+
+#endif /* #ifndef _CRYPTO_H_ */
diff --git a/arch/arm/include/asm/arch-tegra/sys_proto.h b/arch/arm/include/asm/arch-tegra/sys_proto.h
index c3a2673..566666a 100644
--- a/arch/arm/include/asm/arch-tegra/sys_proto.h
+++ b/arch/arm/include/asm/arch-tegra/sys_proto.h
@@ -31,4 +31,10 @@
  */
 int nvidia_board_init(void);
 
+/**
+ * nvidia_board_late_init() - perform any board-specific
+ *			      init on late stages
+ */
+void nvidia_board_late_init(void);
+
 #endif
diff --git a/arch/arm/include/asm/arch-tegra/tegra_i2c.h b/arch/arm/include/asm/arch-tegra/tegra_i2c.h
index c49f432..afec6bb 100644
--- a/arch/arm/include/asm/arch-tegra/tegra_i2c.h
+++ b/arch/arm/include/asm/arch-tegra/tegra_i2c.h
@@ -8,6 +8,7 @@
 #ifndef _TEGRA_I2C_H_
 #define _TEGRA_I2C_H_
 
+#include <asm/io.h>
 #include <asm/types.h>
 
 struct udevice;
@@ -154,4 +155,20 @@
  */
 int tegra_i2c_get_dvc_bus(struct udevice **busp);
 
+/* Pre-dm section used for initial setup of PMIC */
+#define I2C_SEND_2_BYTES		0x0A02
+
+static inline void tegra_i2c_ll_write(uint addr, uint data)
+{
+	struct i2c_ctlr *reg = (struct i2c_ctlr *)TEGRA_DVC_BASE;
+
+	writel(addr, &reg->cmd_addr0);
+	writel(0x2, &reg->cnfg);
+
+	writel(data, &reg->cmd_data1);
+	writel(I2C_SEND_2_BYTES, &reg->cnfg);
+}
+
+void pmic_enable_cpu_vdd(void);
+
 #endif	/* _TEGRA_I2C_H_ */
diff --git a/arch/arm/include/asm/arch-tegra30/clock-tables.h b/arch/arm/include/asm/arch-tegra30/clock-tables.h
index 8588009..6c899ff 100644
--- a/arch/arm/include/asm/arch-tegra30/clock-tables.h
+++ b/arch/arm/include/asm/arch-tegra30/clock-tables.h
@@ -190,9 +190,9 @@
 	PERIPH_ID_ACTMON,
 
 	/* 24 */
-	PERIPH_ID_EX_RESERVED24,
-	PERIPH_ID_EX_RESERVED25,
-	PERIPH_ID_EX_RESERVED26,
+	PERIPH_ID_EXTPERIPH1,
+	PERIPH_ID_EXTPERIPH2,
+	PERIPH_ID_EXTPERIPH3,
 	PERIPH_ID_EX_RESERVED27,
 	PERIPH_ID_SATA,
 	PERIPH_ID_HDA,
diff --git a/arch/arm/mach-tegra/Kconfig b/arch/arm/mach-tegra/Kconfig
index 4fc79eb..464bd07 100644
--- a/arch/arm/mach-tegra/Kconfig
+++ b/arch/arm/mach-tegra/Kconfig
@@ -15,6 +15,11 @@
 config TEGRA_CLKRST
 	bool
 
+config TEGRA_CRYPTO
+	bool "Tegra AES128 crypto module"
+	select AES
+	default n
+
 config TEGRA_GP_PADCTRL
 	bool
 
@@ -224,4 +229,13 @@
 	  for mechanical button actuators, or hooking up relays/... to the
 	  button.
 
+config CMD_EBTUPDATE
+	bool "Enable 'ebtupdate' command"
+	depends on TEGRA20 || TEGRA30
+	select TEGRA_CRYPTO
+	help
+	  Updating u-boot from within u-boot in rather complex or even
+	  impossible on production devices. To make it easier procedure of
+	  re-cryption was created. If your device was re-crypted choose Y.
+
 endif
diff --git a/arch/arm/mach-tegra/Makefile b/arch/arm/mach-tegra/Makefile
index 7165d70..9147050 100644
--- a/arch/arm/mach-tegra/Makefile
+++ b/arch/arm/mach-tegra/Makefile
@@ -16,6 +16,7 @@
 obj-y += board.o board2.o
 obj-y += cache.o
 obj-$(CONFIG_TEGRA_CLKRST) += clock.o
+obj-$(CONFIG_$(SPL_)TEGRA_CRYPTO) += crypto.o
 obj-$(CONFIG_TEGRA_PINCTRL) += pinmux-common.o
 obj-$(CONFIG_TEGRA_PMC) += powergate.o
 obj-y += xusb-padctl-dummy.o
diff --git a/arch/arm/mach-tegra/board2.c b/arch/arm/mach-tegra/board2.c
index c7a45f4..0df1836 100644
--- a/arch/arm/mach-tegra/board2.c
+++ b/arch/arm/mach-tegra/board2.c
@@ -56,6 +56,7 @@
 __weak void pin_mux_display(void) {}
 __weak void start_cpu_fan(void) {}
 __weak void cboot_late_init(void) {}
+__weak void nvidia_board_late_init(void) {}
 
 #if defined(CONFIG_TEGRA_NAND)
 __weak void pin_mux_nand(void)
@@ -267,6 +268,7 @@
 #endif
 	start_cpu_fan();
 	cboot_late_init();
+	nvidia_board_late_init();
 
 	return 0;
 }
diff --git a/arch/arm/mach-tegra/clock.c b/arch/arm/mach-tegra/clock.c
index 11bffc1..966009f 100644
--- a/arch/arm/mach-tegra/clock.c
+++ b/arch/arm/mach-tegra/clock.c
@@ -678,6 +678,29 @@
 	assert(clock_periph_id_isvalid(id));
 	return id;
 }
+
+/*
+ * Get periph clock id and its parent from device tree.
+ *
+ * @param dev		udevice associated with FDT node
+ * @param clk_id	pointer to u32 array of 2 values
+ *			first is periph clock, second is
+ *			its PLL parent according to FDT.
+ */
+int clock_decode_pair(struct udevice *dev, int *clk_id)
+{
+	u32 cell[4];
+	int err;
+
+	err = dev_read_u32_array(dev, "clocks", cell, ARRAY_SIZE(cell));
+	if (err)
+		return -EINVAL;
+
+	clk_id[0] = clk_id_to_periph_id(cell[1]);
+	clk_id[1] = clk_id_to_pll_id(cell[3]);
+
+	return 0;
+}
 #endif /* CONFIG_IS_ENABLED(OF_CONTROL) */
 
 int clock_verify(void)
diff --git a/arch/arm/mach-tegra/cpu.h b/arch/arm/mach-tegra/cpu.h
index d541825..006aae3 100644
--- a/arch/arm/mach-tegra/cpu.h
+++ b/arch/arm/mach-tegra/cpu.h
@@ -74,4 +74,3 @@
 int tegra_get_sku_info(void);
 int tegra_get_chip_sku(void);
 void adjust_pllp_out_freqs(void);
-void pmic_enable_cpu_vdd(void);
diff --git a/arch/arm/mach-tegra/tegra20/crypto.c b/arch/arm/mach-tegra/crypto.c
similarity index 68%
rename from arch/arm/mach-tegra/tegra20/crypto.c
rename to arch/arm/mach-tegra/crypto.c
index 1efaa5c..893da35 100644
--- a/arch/arm/mach-tegra/tegra20/crypto.c
+++ b/arch/arm/mach-tegra/crypto.c
@@ -7,7 +7,7 @@
 #include <common.h>
 #include <log.h>
 #include <linux/errno.h>
-#include "crypto.h"
+#include <asm/arch-tegra/crypto.h>
 #include "uboot_aes.h"
 
 static u8 zero_key[16];
@@ -17,6 +17,7 @@
 enum security_op {
 	SECURITY_SIGN		= 1 << 0,	/* Sign the data */
 	SECURITY_ENCRYPT	= 1 << 1,	/* Encrypt the data */
+	SECURITY_DECRYPT	= 1 << 2,	/* Dectypt the data */
 };
 
 /**
@@ -54,7 +55,7 @@
 	u8 left[AES128_KEY_LENGTH];
 	u8 k1[AES128_KEY_LENGTH];
 	u8 *cbc_chain_data;
-	unsigned i;
+	unsigned int i;
 
 	cbc_chain_data = zero_key;	/* Convenient array of 0's for IV */
 
@@ -92,7 +93,7 @@
 }
 
 /**
- * Encrypt and sign a block of data (depending on security mode).
+ * Decrypt, encrypt or sign a block of data (depending on security mode).
  *
  * \param key		Input AES key, length AES128_KEY_LENGTH
  * \param oper		Security operations mask to perform (enum security_op)
@@ -100,44 +101,68 @@
  * \param length	Size of source data
  * \param sig_dst	Destination address for signature, AES128_KEY_LENGTH bytes
  */
-static int encrypt_and_sign(u8 *key, enum security_op oper, u8 *src,
-			    u32 length, u8 *sig_dst)
+static int tegra_crypto_core(u8 *key, enum security_op oper, u8 *src,
+			     u32 length, u8 *sig_dst)
 {
 	u32 num_aes_blocks;
 	u8 key_schedule[AES128_EXPAND_KEY_LENGTH];
 	u8 iv[AES128_KEY_LENGTH] = {0};
 
-	debug("encrypt_and_sign: length = %d\n", length);
+	debug("%s: length = %d\n", __func__, length);
 
-	/*
-	 * 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,
-		       AES128_KEY_LENGTH, key_schedule);
+	aes_expand_key(key, AES128_KEY_LENGTH, key_schedule);
 
 	num_aes_blocks = (length + AES128_KEY_LENGTH - 1) / AES128_KEY_LENGTH;
 
+	if (oper & SECURITY_DECRYPT) {
+		/* Perform this in place, resulting in src being decrypted. */
+		debug("%s: begin decryption\n", __func__);
+		aes_cbc_decrypt_blocks(AES128_KEY_LENGTH, key_schedule, iv, src,
+				       src, num_aes_blocks);
+		debug("%s: end decryption\n", __func__);
+	}
+
 	if (oper & SECURITY_ENCRYPT) {
 		/* Perform this in place, resulting in src being encrypted. */
-		debug("encrypt_and_sign: begin encryption\n");
+		debug("%s: begin encryption\n", __func__);
 		aes_cbc_encrypt_blocks(AES128_KEY_LENGTH, key_schedule, iv, src,
 				       src, num_aes_blocks);
-		debug("encrypt_and_sign: end encryption\n");
+		debug("%s: end encryption\n", __func__);
 	}
 
 	if (oper & SECURITY_SIGN) {
 		/* encrypt the data, overwriting the result in signature. */
-		debug("encrypt_and_sign: begin signing\n");
+		debug("%s: begin signing\n", __func__);
 		sign_object(key, key_schedule, src, sig_dst, num_aes_blocks);
-		debug("encrypt_and_sign: end signing\n");
+		debug("%s: end signing\n", __func__);
 	}
 
 	return 0;
 }
 
+/**
+ * Tegra crypto group
+ */
+int sign_data_block(u8 *source, unsigned int length, u8 *signature)
+{
+	return tegra_crypto_core(zero_key, SECURITY_SIGN, source,
+				 length, signature);
+}
+
+int sign_enc_data_block(u8 *source, unsigned int length, u8 *signature, u8 *key)
+{
+	return tegra_crypto_core(key, SECURITY_SIGN, source,
+				 length, signature);
+}
+
+int encrypt_data_block(u8 *source, unsigned int length, u8 *key)
+{
+	return tegra_crypto_core(key, SECURITY_ENCRYPT, source,
+				 length, NULL);
+}
+
-int sign_data_block(u8 *source, unsigned length, u8 *signature)
+int decrypt_data_block(u8 *source, unsigned int length, u8 *key)
 {
-	return encrypt_and_sign(zero_key, SECURITY_SIGN, source,
-				length, signature);
+	return tegra_crypto_core(key, SECURITY_DECRYPT, source,
+				 length, NULL);
 }
diff --git a/arch/arm/mach-tegra/tegra114/clock.c b/arch/arm/mach-tegra/tegra114/clock.c
index 143f868..8ad71f5 100644
--- a/arch/arm/mach-tegra/tegra114/clock.c
+++ b/arch/arm/mach-tegra/tegra114/clock.c
@@ -19,6 +19,8 @@
 #include <fdtdec.h>
 #include <linux/delay.h>
 
+#include <dt-bindings/clock/tegra114-car.h>
+
 /*
  * Clock types that we can use as a source. The Tegra114 has muxes for the
  * peripheral clocks, and in most cases there are four options for the clock
@@ -646,6 +648,41 @@
 		return clk_id;
 	}
 }
+
+/*
+ * Convert a device tree clock ID to our PLL ID.
+ *
+ * @param clk_id	Clock ID according to tegra114 device tree binding
+ * Return: clock ID, or CLOCK_ID_NONE if the clock ID is invalid
+ */
+enum clock_id clk_id_to_pll_id(int clk_id)
+{
+	switch (clk_id) {
+	case TEGRA114_CLK_PLL_C:
+		return CLOCK_ID_CGENERAL;
+	case TEGRA114_CLK_PLL_M:
+		return CLOCK_ID_MEMORY;
+	case TEGRA114_CLK_PLL_P:
+		return CLOCK_ID_PERIPH;
+	case TEGRA114_CLK_PLL_A:
+		return CLOCK_ID_AUDIO;
+	case TEGRA114_CLK_PLL_U:
+		return CLOCK_ID_USB;
+	case TEGRA114_CLK_PLL_D:
+	case TEGRA114_CLK_PLL_D_OUT0:
+		return CLOCK_ID_DISPLAY;
+	case TEGRA114_CLK_PLL_X:
+		return CLOCK_ID_XCPU;
+	case TEGRA114_CLK_PLL_E_OUT0:
+		return CLOCK_ID_EPCI;
+	case TEGRA114_CLK_CLK_32K:
+		return CLOCK_ID_32KHZ;
+	case TEGRA114_CLK_CLK_M:
+		return CLOCK_ID_CLK_M;
+	default:
+		return CLOCK_ID_NONE;
+	}
+}
 #endif /* CONFIG_IS_ENABLED(OF_CONTROL) */
 
 void clock_early_init(void)
@@ -745,7 +782,7 @@
 	{ PERIPH_ID_SDMMC2, CLOCK_ID_PERIPH },
 	{ PERIPH_ID_SDMMC3, CLOCK_ID_PERIPH },
 	{ PERIPH_ID_SDMMC4, CLOCK_ID_PERIPH },
-	{ PERIPH_ID_PWM, CLOCK_ID_SFROM32KHZ },
+	{ PERIPH_ID_PWM, CLOCK_ID_PERIPH },
 	{ PERIPH_ID_I2C1, CLOCK_ID_PERIPH },
 	{ PERIPH_ID_I2C2, CLOCK_ID_PERIPH },
 	{ PERIPH_ID_I2C3, CLOCK_ID_PERIPH },
diff --git a/arch/arm/mach-tegra/tegra124/clock.c b/arch/arm/mach-tegra/tegra124/clock.c
index da38b26..ca9549a 100644
--- a/arch/arm/mach-tegra/tegra124/clock.c
+++ b/arch/arm/mach-tegra/tegra124/clock.c
@@ -19,6 +19,9 @@
 #include <fdtdec.h>
 #include <linux/delay.h>
 
+#include <dt-bindings/clock/tegra124-car.h>
+#include <dt-bindings/clock/tegra124-car-common.h>
+
 /*
  * Clock types that we can use as a source. The Tegra124 has muxes for the
  * peripheral clocks, and in most cases there are four options for the clock
@@ -826,6 +829,41 @@
 		return clk_id;
 	}
 }
+
+/*
+ * Convert a device tree clock ID to our PLL ID.
+ *
+ * @param clk_id	Clock ID according to tegra124 device tree binding
+ * Return: clock ID, or CLOCK_ID_NONE if the clock ID is invalid
+ */
+enum clock_id clk_id_to_pll_id(int clk_id)
+{
+	switch (clk_id) {
+	case TEGRA124_CLK_PLL_C:
+		return CLOCK_ID_CGENERAL;
+	case TEGRA124_CLK_PLL_M:
+		return CLOCK_ID_MEMORY;
+	case TEGRA124_CLK_PLL_P:
+		return CLOCK_ID_PERIPH;
+	case TEGRA124_CLK_PLL_A:
+		return CLOCK_ID_AUDIO;
+	case TEGRA124_CLK_PLL_U:
+		return CLOCK_ID_USB;
+	case TEGRA124_CLK_PLL_D:
+	case TEGRA124_CLK_PLL_D_OUT0:
+		return CLOCK_ID_DISPLAY;
+	case TEGRA124_CLK_PLL_X:
+		return CLOCK_ID_XCPU;
+	case TEGRA124_CLK_PLL_E:
+		return CLOCK_ID_EPCI;
+	case TEGRA124_CLK_CLK_32K:
+		return CLOCK_ID_32KHZ;
+	case TEGRA124_CLK_CLK_M:
+		return CLOCK_ID_CLK_M;
+	default:
+		return CLOCK_ID_NONE;
+	}
+}
 #endif /* CONFIG_IS_ENABLED(OF_CONTROL) */
 
 void clock_early_init(void)
@@ -1170,7 +1208,7 @@
 	{ PERIPH_ID_SDMMC2, CLOCK_ID_PERIPH },
 	{ PERIPH_ID_SDMMC3, CLOCK_ID_PERIPH },
 	{ PERIPH_ID_SDMMC4, CLOCK_ID_PERIPH },
-	{ PERIPH_ID_PWM, CLOCK_ID_SFROM32KHZ },
+	{ PERIPH_ID_PWM, CLOCK_ID_PERIPH },
 	{ PERIPH_ID_I2C1, CLOCK_ID_PERIPH },
 	{ PERIPH_ID_I2C2, CLOCK_ID_PERIPH },
 	{ PERIPH_ID_I2C3, CLOCK_ID_PERIPH },
diff --git a/arch/arm/mach-tegra/tegra124/cpu.c b/arch/arm/mach-tegra/tegra124/cpu.c
index d5f2683..b1bfe8f 100644
--- a/arch/arm/mach-tegra/tegra124/cpu.c
+++ b/arch/arm/mach-tegra/tegra124/cpu.c
@@ -14,10 +14,14 @@
 #include <asm/arch/tegra.h>
 #include <asm/arch-tegra/clk_rst.h>
 #include <asm/arch-tegra/pmc.h>
+#include <asm/arch-tegra/tegra_i2c.h>
 #include <asm/arch-tegra/ap.h>
 #include <linux/delay.h>
 #include "../cpu.h"
 
+/* In case this function is not defined */
+__weak void pmic_enable_cpu_vdd(void) {}
+
 /* Tegra124-specific CPU init code */
 
 static void enable_cpu_power_rail(void)
diff --git a/arch/arm/mach-tegra/tegra20/Kconfig b/arch/arm/mach-tegra/tegra20/Kconfig
index 955786c..57d1102 100644
--- a/arch/arm/mach-tegra/tegra20/Kconfig
+++ b/arch/arm/mach-tegra/tegra20/Kconfig
@@ -3,6 +3,7 @@
 config TEGRA_LP0
 	bool
 	select TEGRA_CLOCK_SCALING
+	select TEGRA_CRYPTO
 
 config TEGRA_PMU
 	bool
diff --git a/arch/arm/mach-tegra/tegra20/Makefile b/arch/arm/mach-tegra/tegra20/Makefile
index bb17c90..991cabe 100644
--- a/arch/arm/mach-tegra/tegra20/Makefile
+++ b/arch/arm/mach-tegra/tegra20/Makefile
@@ -2,9 +2,8 @@
 #
 # (C) Copyright 2010,2011 Nvidia Corporation.
 
-ifdef CONFIG_SPL_BUILD
-obj-y	+= cpu.o
-endif
+obj-$(CONFIG_SPL_BUILD) += cpu.o
+obj-$(CONFIG_$(SPL_)CMD_EBTUPDATE) += bct.o
 
 # The AVP is ARMv4T architecture so we must use special compiler
 # flags for any startup files it might use.
@@ -13,6 +12,6 @@
 CFLAGS_REMOVE_warmboot_avp.o := $(LTO_CFLAGS)
 
 obj-y	+= clock.o funcmux.o pinmux.o
-obj-$(CONFIG_TEGRA_LP0) += warmboot.o crypto.o warmboot_avp.o
+obj-$(CONFIG_TEGRA_LP0) += warmboot.o warmboot_avp.o
 obj-$(CONFIG_TEGRA_CLOCK_SCALING) += emc.o
 obj-$(CONFIG_TEGRA_PMU) += pmu.o
diff --git a/arch/arm/mach-tegra/tegra20/bct.c b/arch/arm/mach-tegra/tegra20/bct.c
new file mode 100644
index 0000000..5eb4899
--- /dev/null
+++ b/arch/arm/mach-tegra/tegra20/bct.c
@@ -0,0 +1,79 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2022, Ramin <raminterex@yahoo.com>
+ * Copyright (c) 2022, Svyatoslav Ryhel <clamor95@gmail.com>
+ */
+
+#include <common.h>
+#include <command.h>
+#include <log.h>
+#include <asm/arch-tegra/crypto.h>
+#include "bct.h"
+#include "uboot_aes.h"
+
+/*
+ * @param  bct		boot config table start in RAM
+ * @param  ect		bootloader start in RAM
+ * @param  ebt_size	bootloader file size in bytes
+ * Return: 0, or 1 if failed
+ */
+static int bct_patch(u8 *bct, u8 *ebt, u32 ebt_size)
+{
+	struct nvboot_config_table *bct_tbl = NULL;
+	u8 ebt_hash[AES128_KEY_LENGTH] = { 0 };
+	u8 sbk[AES128_KEY_LENGTH] = { 0 };
+	u8 *bct_hash = bct;
+	int ret;
+
+	bct += BCT_HASH;
+
+	memcpy(sbk, (u8 *)(bct + BCT_LENGTH),
+	       NVBOOT_CMAC_AES_HASH_LENGTH * 4);
+
+	ret = decrypt_data_block(bct, BCT_LENGTH, sbk);
+	if (ret)
+		return 1;
+
+	ebt_size = roundup(ebt_size, EBT_ALIGNMENT);
+
+	ret = encrypt_data_block(ebt, ebt_size, sbk);
+	if (ret)
+		return 1;
+
+	ret = sign_enc_data_block(ebt, ebt_size, ebt_hash, sbk);
+	if (ret)
+		return 1;
+
+	bct_tbl = (struct nvboot_config_table *)bct;
+
+	memcpy((u8 *)&bct_tbl->bootloader[0].crypto_hash,
+	       ebt_hash, NVBOOT_CMAC_AES_HASH_LENGTH * 4);
+	bct_tbl->bootloader[0].entry_point = CONFIG_SPL_TEXT_BASE;
+	bct_tbl->bootloader[0].load_addr = CONFIG_SPL_TEXT_BASE;
+	bct_tbl->bootloader[0].length = ebt_size;
+
+	ret = encrypt_data_block(bct, BCT_LENGTH, sbk);
+	if (ret)
+		return 1;
+
+	ret = sign_enc_data_block(bct, BCT_LENGTH, bct_hash, sbk);
+	if (ret)
+		return 1;
+
+	return 0;
+}
+
+static int do_ebtupdate(struct cmd_tbl *cmdtp, int flag, int argc,
+			char *const argv[])
+{
+	u32 bct_addr = hextoul(argv[1], NULL);
+	u32 ebt_addr = hextoul(argv[2], NULL);
+	u32 ebt_size = hextoul(argv[3], NULL);
+
+	return bct_patch((u8 *)bct_addr, (u8 *)ebt_addr, ebt_size);
+}
+
+U_BOOT_CMD(ebtupdate,	4,	0,	do_ebtupdate,
+	   "update bootloader on re-crypted Tegra20 devices",
+	   ""
+);
diff --git a/arch/arm/mach-tegra/tegra20/bct.h b/arch/arm/mach-tegra/tegra20/bct.h
new file mode 100644
index 0000000..4b78aef
--- /dev/null
+++ b/arch/arm/mach-tegra/tegra20/bct.h
@@ -0,0 +1,42 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+
+#ifndef _BCT_H_
+#define _BCT_H_
+
+/*
+ * Defines the BCT parametres for T20
+ */
+#define BCT_LENGTH		0xFE0
+#define BCT_HASH		0x10
+#define EBT_ALIGNMENT		0x10
+
+/*
+ * Defines the CMAC-AES-128 hash length in 32 bit words. (128 bits = 4 words)
+ */
+#define NVBOOT_CMAC_AES_HASH_LENGTH		4
+
+/*
+ * Defines the maximum number of bootloader descriptions in the BCT.
+ */
+#define NVBOOT_MAX_BOOTLOADERS			4
+
+struct nv_bootloader_info {
+	u32 version;
+	u32 start_blk;
+	u32 start_page;
+	u32 length;
+	u32 load_addr;
+	u32 entry_point;
+	u32 attribute;
+	u32 crypto_hash[NVBOOT_CMAC_AES_HASH_LENGTH];
+};
+
+struct nvboot_config_table {
+	u32 unused0[4];
+	u32 boot_data_version;
+	u32 unused1[668];
+	struct nv_bootloader_info bootloader[NVBOOT_MAX_BOOTLOADERS];
+	u32 unused2[508];
+};
+
+#endif /* _BCT_H_ */
diff --git a/arch/arm/mach-tegra/tegra20/clock.c b/arch/arm/mach-tegra/tegra20/clock.c
index 8c12743..067a9f1 100644
--- a/arch/arm/mach-tegra/tegra20/clock.c
+++ b/arch/arm/mach-tegra/tegra20/clock.c
@@ -20,6 +20,8 @@
 #include <fdtdec.h>
 #include <linux/delay.h>
 
+#include <dt-bindings/clock/tegra20-car.h>
+
 /*
  * Clock types that we can use as a source. The Tegra20 has muxes for the
  * peripheral clocks, and in most cases there are four options for the clock
@@ -578,6 +580,41 @@
 		return clk_id;
 	}
 }
+
+/*
+ * Convert a device tree clock ID to our PLL ID.
+ *
+ * @param clk_id	Clock ID according to tegra20 device tree binding
+ * Return: clock ID, or CLOCK_ID_NONE if the clock ID is invalid
+ */
+enum clock_id clk_id_to_pll_id(int clk_id)
+{
+	switch (clk_id) {
+	case TEGRA20_CLK_PLL_C:
+		return CLOCK_ID_CGENERAL;
+	case TEGRA20_CLK_PLL_M:
+		return CLOCK_ID_MEMORY;
+	case TEGRA20_CLK_PLL_P:
+		return CLOCK_ID_PERIPH;
+	case TEGRA20_CLK_PLL_A:
+		return CLOCK_ID_AUDIO;
+	case TEGRA20_CLK_PLL_U:
+		return CLOCK_ID_USB;
+	case TEGRA20_CLK_PLL_D:
+	case TEGRA20_CLK_PLL_D_OUT0:
+		return CLOCK_ID_DISPLAY;
+	case TEGRA20_CLK_PLL_X:
+		return CLOCK_ID_XCPU;
+	case TEGRA20_CLK_PLL_E:
+		return CLOCK_ID_EPCI;
+	case TEGRA20_CLK_CLK_32K:
+		return CLOCK_ID_32KHZ;
+	case TEGRA20_CLK_CLK_M:
+		return CLOCK_ID_CLK_M;
+	default:
+		return CLOCK_ID_NONE;
+	}
+}
 #endif /* CONFIG_IS_ENABLED(OF_CONTROL) */
 
 void clock_early_init(void)
@@ -760,14 +797,14 @@
 	{ PERIPH_ID_SBC2, CLOCK_ID_PERIPH },
 	{ PERIPH_ID_SBC3, CLOCK_ID_PERIPH },
 	{ PERIPH_ID_SBC4, CLOCK_ID_PERIPH },
-	{ PERIPH_ID_HOST1X, CLOCK_ID_PERIPH },
-	{ PERIPH_ID_DISP1, CLOCK_ID_CGENERAL },
+	{ PERIPH_ID_HOST1X, CLOCK_ID_CGENERAL },
+	{ PERIPH_ID_DISP1, CLOCK_ID_PERIPH },
 	{ PERIPH_ID_NDFLASH, CLOCK_ID_PERIPH },
 	{ PERIPH_ID_SDMMC1, CLOCK_ID_PERIPH },
 	{ PERIPH_ID_SDMMC2, CLOCK_ID_PERIPH },
 	{ PERIPH_ID_SDMMC3, CLOCK_ID_PERIPH },
 	{ PERIPH_ID_SDMMC4, CLOCK_ID_PERIPH },
-	{ PERIPH_ID_PWM, CLOCK_ID_SFROM32KHZ },
+	{ PERIPH_ID_PWM, CLOCK_ID_PERIPH },
 	{ PERIPH_ID_DVC_I2C, CLOCK_ID_PERIPH },
 	{ PERIPH_ID_I2C1, CLOCK_ID_PERIPH },
 	{ PERIPH_ID_I2C2, CLOCK_ID_PERIPH },
diff --git a/arch/arm/mach-tegra/tegra20/crypto.h b/arch/arm/mach-tegra/tegra20/crypto.h
deleted file mode 100644
index a773d03..0000000
--- a/arch/arm/mach-tegra/tegra20/crypto.h
+++ /dev/null
@@ -1,19 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0+ */
-/*
- * Copyright (c) 2011 The Chromium OS Authors.
- * (C) Copyright 2010 - 2011 NVIDIA Corporation <www.nvidia.com>
- */
-
-#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/mach-tegra/tegra210/clock.c b/arch/arm/mach-tegra/tegra210/clock.c
index 330753f..900537a 100644
--- a/arch/arm/mach-tegra/tegra210/clock.c
+++ b/arch/arm/mach-tegra/tegra210/clock.c
@@ -22,6 +22,8 @@
 #include <linux/bitops.h>
 #include <linux/delay.h>
 
+#include <dt-bindings/clock/tegra210-car.h>
+
 /*
  * Clock types that we can use as a source. The Tegra210 has muxes for the
  * peripheral clocks, and in most cases there are four options for the clock
@@ -914,6 +916,41 @@
 		return clk_id;
 	}
 }
+
+/*
+ * Convert a device tree clock ID to our PLL ID.
+ *
+ * @param clk_id	Clock ID according to tegra210 device tree binding
+ * Return: clock ID, or CLOCK_ID_NONE if the clock ID is invalid
+ */
+enum clock_id clk_id_to_pll_id(int clk_id)
+{
+	switch (clk_id) {
+	case TEGRA210_CLK_PLL_C:
+		return CLOCK_ID_CGENERAL;
+	case TEGRA210_CLK_PLL_M:
+		return CLOCK_ID_MEMORY;
+	case TEGRA210_CLK_PLL_P:
+		return CLOCK_ID_PERIPH;
+	case TEGRA210_CLK_PLL_A:
+		return CLOCK_ID_AUDIO;
+	case TEGRA210_CLK_PLL_U:
+		return CLOCK_ID_USB;
+	case TEGRA210_CLK_PLL_D:
+	case TEGRA210_CLK_PLL_D_OUT0:
+		return CLOCK_ID_DISPLAY;
+	case TEGRA210_CLK_PLL_X:
+		return CLOCK_ID_XCPU;
+	case TEGRA210_CLK_PLL_E:
+		return CLOCK_ID_EPCI;
+	case TEGRA210_CLK_CLK_32K:
+		return CLOCK_ID_32KHZ;
+	case TEGRA210_CLK_CLK_M:
+		return CLOCK_ID_CLK_M;
+	default:
+		return CLOCK_ID_NONE;
+	}
+}
 #endif /* CONFIG_OF_CONTROL */
 
 /*
@@ -1241,7 +1278,7 @@
 	{ PERIPH_ID_SDMMC2, CLOCK_ID_PERIPH },
 	{ PERIPH_ID_SDMMC3, CLOCK_ID_PERIPH },
 	{ PERIPH_ID_SDMMC4, CLOCK_ID_PERIPH },
-	{ PERIPH_ID_PWM, CLOCK_ID_SFROM32KHZ },
+	{ PERIPH_ID_PWM, CLOCK_ID_PERIPH },
 	{ PERIPH_ID_I2C1, CLOCK_ID_PERIPH },
 	{ PERIPH_ID_I2C2, CLOCK_ID_PERIPH },
 	{ PERIPH_ID_I2C3, CLOCK_ID_PERIPH },
diff --git a/arch/arm/mach-tegra/tegra30/Kconfig b/arch/arm/mach-tegra/tegra30/Kconfig
index 5619d1c..85b8ce2 100644
--- a/arch/arm/mach-tegra/tegra30/Kconfig
+++ b/arch/arm/mach-tegra/tegra30/Kconfig
@@ -1,11 +1,5 @@
 if TEGRA30
 
-config TEGRA_VDD_CORE_TPS62361B_SET3
-	bool
-
-config TEGRA_VDD_CORE_TPS62366A_SET1
-	bool
-
 choice
 	prompt "Tegra30 board select"
 	optional
@@ -17,12 +11,10 @@
 config TARGET_BEAVER
 	bool "NVIDIA Tegra30 Beaver evaluation board"
 	select BOARD_LATE_INIT
-	select TEGRA_VDD_CORE_TPS62366A_SET1
 
 config TARGET_CARDHU
 	bool "NVIDIA Tegra30 Cardhu evaluation board"
 	select BOARD_LATE_INIT
-	select TEGRA_VDD_CORE_TPS62361B_SET3
 
 config TARGET_COLIBRI_T30
 	bool "Toradex Colibri T30 board"
diff --git a/arch/arm/mach-tegra/tegra30/Makefile b/arch/arm/mach-tegra/tegra30/Makefile
index 9f17057..28dd486 100644
--- a/arch/arm/mach-tegra/tegra30/Makefile
+++ b/arch/arm/mach-tegra/tegra30/Makefile
@@ -3,5 +3,6 @@
 # Copyright (c) 2010-2012, NVIDIA CORPORATION.  All rights reserved.
 
 obj-$(CONFIG_SPL_BUILD) += cpu.o
+obj-$(CONFIG_$(SPL_)CMD_EBTUPDATE) += bct.o
 
 obj-y	+= clock.o funcmux.o pinmux.o
diff --git a/arch/arm/mach-tegra/tegra30/bct.c b/arch/arm/mach-tegra/tegra30/bct.c
new file mode 100644
index 0000000..c56958d
--- /dev/null
+++ b/arch/arm/mach-tegra/tegra30/bct.c
@@ -0,0 +1,79 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2022, Ramin <raminterex@yahoo.com>
+ * Copyright (c) 2022, Svyatoslav Ryhel <clamor95@gmail.com>
+ */
+
+#include <common.h>
+#include <command.h>
+#include <log.h>
+#include <asm/arch-tegra/crypto.h>
+#include "bct.h"
+#include "uboot_aes.h"
+
+/*
+ * @param  bct		boot config table start in RAM
+ * @param  ect		bootloader start in RAM
+ * @param  ebt_size	bootloader file size in bytes
+ * Return: 0, or 1 if failed
+ */
+static int bct_patch(u8 *bct, u8 *ebt, u32 ebt_size)
+{
+	struct nvboot_config_table *bct_tbl = NULL;
+	u8 ebt_hash[AES128_KEY_LENGTH] = { 0 };
+	u8 sbk[AES128_KEY_LENGTH] = { 0 };
+	u8 *bct_hash = bct;
+	int ret;
+
+	bct += BCT_HASH;
+
+	memcpy(sbk, (u8 *)(bct + BCT_LENGTH),
+	       NVBOOT_CMAC_AES_HASH_LENGTH * 4);
+
+	ret = decrypt_data_block(bct, BCT_LENGTH, sbk);
+	if (ret)
+		return 1;
+
+	ebt_size = roundup(ebt_size, EBT_ALIGNMENT);
+
+	ret = encrypt_data_block(ebt, ebt_size, sbk);
+	if (ret)
+		return 1;
+
+	ret = sign_enc_data_block(ebt, ebt_size, ebt_hash, sbk);
+	if (ret)
+		return 1;
+
+	bct_tbl = (struct nvboot_config_table *)bct;
+
+	memcpy((u8 *)&bct_tbl->bootloader[0].crypto_hash,
+	       ebt_hash, NVBOOT_CMAC_AES_HASH_LENGTH * 4);
+	bct_tbl->bootloader[0].entry_point = CONFIG_SPL_TEXT_BASE;
+	bct_tbl->bootloader[0].load_addr = CONFIG_SPL_TEXT_BASE;
+	bct_tbl->bootloader[0].length = ebt_size;
+
+	ret = encrypt_data_block(bct, BCT_LENGTH, sbk);
+	if (ret)
+		return 1;
+
+	ret = sign_enc_data_block(bct, BCT_LENGTH, bct_hash, sbk);
+	if (ret)
+		return 1;
+
+	return 0;
+}
+
+static int do_ebtupdate(struct cmd_tbl *cmdtp, int flag, int argc,
+			char *const argv[])
+{
+	u32 bct_addr = hextoul(argv[1], NULL);
+	u32 ebt_addr = hextoul(argv[2], NULL);
+	u32 ebt_size = hextoul(argv[3], NULL);
+
+	return bct_patch((u8 *)bct_addr, (u8 *)ebt_addr, ebt_size);
+}
+
+U_BOOT_CMD(ebtupdate,	4,	0,	do_ebtupdate,
+	   "update bootloader on re-crypted Tegra30 devices",
+	   ""
+);
diff --git a/arch/arm/mach-tegra/tegra30/bct.h b/arch/arm/mach-tegra/tegra30/bct.h
new file mode 100644
index 0000000..9797384
--- /dev/null
+++ b/arch/arm/mach-tegra/tegra30/bct.h
@@ -0,0 +1,42 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+
+#ifndef _BCT_H_
+#define _BCT_H_
+
+/*
+ * Defines the BCT parametres for T30
+ */
+#define BCT_LENGTH		0x17E0
+#define BCT_HASH		0x10
+#define EBT_ALIGNMENT		0x10
+
+/*
+ * Defines the CMAC-AES-128 hash length in 32 bit words. (128 bits = 4 words)
+ */
+#define NVBOOT_CMAC_AES_HASH_LENGTH		4
+
+/*
+ * Defines the maximum number of bootloader descriptions in the BCT.
+ */
+#define NVBOOT_MAX_BOOTLOADERS			4
+
+struct nv_bootloader_info {
+	u32 version;
+	u32 start_blk;
+	u32 start_page;
+	u32 length;
+	u32 load_addr;
+	u32 entry_point;
+	u32 attribute;
+	u32 crypto_hash[NVBOOT_CMAC_AES_HASH_LENGTH];
+};
+
+struct nvboot_config_table {
+	u32 unused0[4];
+	u32 boot_data_version;
+	u32 unused1[972];
+	struct nv_bootloader_info bootloader[NVBOOT_MAX_BOOTLOADERS];
+	u32 unused2[508];
+};
+
+#endif /* _BCT_H_ */
diff --git a/arch/arm/mach-tegra/tegra30/clock.c b/arch/arm/mach-tegra/tegra30/clock.c
index 449b66e..1dc9d09 100644
--- a/arch/arm/mach-tegra/tegra30/clock.c
+++ b/arch/arm/mach-tegra/tegra30/clock.c
@@ -19,6 +19,8 @@
 #include <fdtdec.h>
 #include <linux/delay.h>
 
+#include <dt-bindings/clock/tegra30-car.h>
+
 /*
  * Clock types that we can use as a source. The Tegra30 has muxes for the
  * peripheral clocks, and in most cases there are four options for the clock
@@ -377,9 +379,9 @@
 	PERIPHC_ACTMON,
 
 	/* 24 */
-	NONE(RESERVED24),
-	NONE(RESERVED25),
-	NONE(RESERVED26),
+	PERIPHC_EXTPERIPH1,
+	PERIPHC_EXTPERIPH2,
+	PERIPHC_EXTPERIPH3,
 	NONE(RESERVED27),
 	PERIPHC_SATA,
 	PERIPHC_HDA,
@@ -628,11 +630,87 @@
 		return clk_id;
 	}
 }
+
+/*
+ * Convert a device tree clock ID to our PLL ID.
+ *
+ * @param clk_id	Clock ID according to tegra30 device tree binding
+ * Return: clock ID, or CLOCK_ID_NONE if the clock ID is invalid
+ */
+enum clock_id clk_id_to_pll_id(int clk_id)
+{
+	switch (clk_id) {
+	case TEGRA30_CLK_PLL_C:
+		return CLOCK_ID_CGENERAL;
+	case TEGRA30_CLK_PLL_M:
+		return CLOCK_ID_MEMORY;
+	case TEGRA30_CLK_PLL_P:
+		return CLOCK_ID_PERIPH;
+	case TEGRA30_CLK_PLL_A:
+		return CLOCK_ID_AUDIO;
+	case TEGRA30_CLK_PLL_U:
+		return CLOCK_ID_USB;
+	case TEGRA30_CLK_PLL_D:
+	case TEGRA30_CLK_PLL_D_OUT0:
+		return CLOCK_ID_DISPLAY;
+	case TEGRA30_CLK_PLL_X:
+		return CLOCK_ID_XCPU;
+	case TEGRA30_CLK_PLL_E:
+		return CLOCK_ID_EPCI;
+	case TEGRA30_CLK_CLK_32K:
+		return CLOCK_ID_32KHZ;
+	case TEGRA30_CLK_CLK_M:
+		return CLOCK_ID_CLK_M;
+	default:
+		return CLOCK_ID_NONE;
+	}
+}
 #endif /* CONFIG_IS_ENABLED(OF_CONTROL) */
 
 void clock_early_init(void)
 {
+	struct clk_rst_ctlr *clkrst =
+		(struct clk_rst_ctlr *)NV_PA_CLK_RST_BASE;
+	struct clk_pll_info *pllinfo;
+	u32 data;
+
 	tegra30_set_up_pllp();
+
+	/*
+	 * PLLD output frequency set to 925Mhz
+	 */
+	switch (clock_get_osc_freq()) {
+	case CLOCK_OSC_FREQ_12_0: /* OSC is 12Mhz */
+	case CLOCK_OSC_FREQ_48_0: /* OSC is 48Mhz */
+		clock_set_rate(CLOCK_ID_DISPLAY, 925, 12, 0, 12);
+		break;
+
+	case CLOCK_OSC_FREQ_26_0: /* OSC is 26Mhz */
+		clock_set_rate(CLOCK_ID_DISPLAY, 925, 26, 0, 12);
+		break;
+
+	case CLOCK_OSC_FREQ_13_0: /* OSC is 13Mhz */
+	case CLOCK_OSC_FREQ_16_8: /* OSC is 16.8Mhz */
+		clock_set_rate(CLOCK_ID_DISPLAY, 925, 13, 0, 12);
+		break;
+
+	case CLOCK_OSC_FREQ_19_2:
+	case CLOCK_OSC_FREQ_38_4:
+	default:
+		/*
+		 * These are not supported. It is too early to print a
+		 * message and the UART likely won't work anyway due to the
+		 * oscillator being wrong.
+		 */
+		break;
+	}
+
+	/* PLLD_MISC: Set CLKENABLE, CPCON 12, LFCON 1, and enable lock */
+	pllinfo = &tegra_pll_info_table[CLOCK_ID_DISPLAY];
+	data = (12 << pllinfo->kcp_shift) | (1 << pllinfo->kvco_shift);
+	data |= (1 << PLLD_CLKENABLE) | (1 << pllinfo->lock_ena);
+	writel(data, &clkrst->crc_pll[CLOCK_ID_DISPLAY].pll_misc);
+	udelay(2);
 }
 
 void arch_timer_init(void)
@@ -799,14 +877,14 @@
 	{ PERIPH_ID_SBC4, CLOCK_ID_PERIPH },
 	{ PERIPH_ID_SBC5, CLOCK_ID_PERIPH },
 	{ PERIPH_ID_SBC6, CLOCK_ID_PERIPH },
-	{ PERIPH_ID_HOST1X, CLOCK_ID_PERIPH },
-	{ PERIPH_ID_DISP1, CLOCK_ID_CGENERAL },
+	{ PERIPH_ID_HOST1X, CLOCK_ID_CGENERAL },
+	{ PERIPH_ID_DISP1, CLOCK_ID_PERIPH },
 	{ PERIPH_ID_NDFLASH, CLOCK_ID_PERIPH },
 	{ PERIPH_ID_SDMMC1, CLOCK_ID_PERIPH },
 	{ PERIPH_ID_SDMMC2, CLOCK_ID_PERIPH },
 	{ PERIPH_ID_SDMMC3, CLOCK_ID_PERIPH },
 	{ PERIPH_ID_SDMMC4, CLOCK_ID_PERIPH },
-	{ PERIPH_ID_PWM, CLOCK_ID_SFROM32KHZ },
+	{ PERIPH_ID_PWM, CLOCK_ID_PERIPH },
 	{ PERIPH_ID_DVC_I2C, CLOCK_ID_PERIPH },
 	{ PERIPH_ID_I2C1, CLOCK_ID_PERIPH },
 	{ PERIPH_ID_I2C2, CLOCK_ID_PERIPH },
diff --git a/arch/arm/mach-tegra/tegra30/cpu.c b/arch/arm/mach-tegra/tegra30/cpu.c
index 651edd2..60bbf13 100644
--- a/arch/arm/mach-tegra/tegra30/cpu.c
+++ b/arch/arm/mach-tegra/tegra30/cpu.c
@@ -15,37 +15,8 @@
 #include <linux/delay.h>
 #include "../cpu.h"
 
-/* Tegra30-specific CPU init code */
-void tegra_i2c_ll_write_addr(uint addr, uint config)
-{
-	struct i2c_ctlr *reg = (struct i2c_ctlr *)TEGRA_DVC_BASE;
-
-	writel(addr, &reg->cmd_addr0);
-	writel(config, &reg->cnfg);
-}
-
-void tegra_i2c_ll_write_data(uint data, uint config)
-{
-	struct i2c_ctlr *reg = (struct i2c_ctlr *)TEGRA_DVC_BASE;
-
-	writel(data, &reg->cmd_data1);
-	writel(config, &reg->cnfg);
-}
-
-#define TPS62366A_I2C_ADDR		0xC0
-#define TPS62366A_SET1_REG		0x01
-#define TPS62366A_SET1_DATA		(0x4600 | TPS62366A_SET1_REG)
-
-#define TPS62361B_I2C_ADDR		0xC0
-#define TPS62361B_SET3_REG		0x03
-#define TPS62361B_SET3_DATA		(0x4600 | TPS62361B_SET3_REG)
-
-#define TPS65911_I2C_ADDR		0x5A
-#define TPS65911_VDDCTRL_OP_REG		0x28
-#define TPS65911_VDDCTRL_SR_REG		0x27
-#define TPS65911_VDDCTRL_OP_DATA	(0x2400 | TPS65911_VDDCTRL_OP_REG)
-#define TPS65911_VDDCTRL_SR_DATA	(0x0100 | TPS65911_VDDCTRL_SR_REG)
-#define I2C_SEND_2_BYTES		0x0A02
+/* In case this function is not defined */
+__weak void pmic_enable_cpu_vdd(void) {}
 
 static void enable_cpu_power_rail(void)
 {
@@ -56,27 +27,6 @@
 	reg = readl(&pmc->pmc_cntrl);
 	reg |= CPUPWRREQ_OE;
 	writel(reg, &pmc->pmc_cntrl);
-
-	/* Set VDD_CORE to 1.200V. */
-#ifdef CONFIG_TEGRA_VDD_CORE_TPS62366A_SET1
-	tegra_i2c_ll_write_addr(TPS62366A_I2C_ADDR, 2);
-	tegra_i2c_ll_write_data(TPS62366A_SET1_DATA, I2C_SEND_2_BYTES);
-#endif
-#ifdef CONFIG_TEGRA_VDD_CORE_TPS62361B_SET3
-	tegra_i2c_ll_write_addr(TPS62361B_I2C_ADDR, 2);
-	tegra_i2c_ll_write_data(TPS62361B_SET3_DATA, I2C_SEND_2_BYTES);
-#endif
-	udelay(1000);
-
-	/*
-	 * Bring up CPU VDD via the TPS65911x PMIC on the DVC I2C bus.
-	 * First set VDD to 1.0125V, then enable the VDD regulator.
-	 */
-	tegra_i2c_ll_write_addr(TPS65911_I2C_ADDR, 2);
-	tegra_i2c_ll_write_data(TPS65911_VDDCTRL_OP_DATA, I2C_SEND_2_BYTES);
-	udelay(1000);
-	tegra_i2c_ll_write_data(TPS65911_VDDCTRL_SR_DATA, I2C_SEND_2_BYTES);
-	udelay(10 * 1000);
 }
 
 /**
@@ -142,6 +92,7 @@
 
 	/* Enable VDD_CPU */
 	enable_cpu_power_rail();
+	pmic_enable_cpu_vdd();
 
 	set_cpu_running(0);
 
diff --git a/board/avionic-design/tec-ng/Makefile b/board/avionic-design/tec-ng/Makefile
index 46df14d..d6890e5 100644
--- a/board/avionic-design/tec-ng/Makefile
+++ b/board/avionic-design/tec-ng/Makefile
@@ -3,4 +3,6 @@
 # (C) Copyright 2013
 # Avionic Design GmbH <www.avionic-design.de>
 
-obj-y	:= ../common/tamonten-ng.o
+obj-$(CONFIG_SPL_BUILD) += tec-ng-spl.o
+
+obj-y	+= ../common/tamonten-ng.o
diff --git a/board/avionic-design/tec-ng/tec-ng-spl.c b/board/avionic-design/tec-ng/tec-ng-spl.c
new file mode 100644
index 0000000..6e54464
--- /dev/null
+++ b/board/avionic-design/tec-ng/tec-ng-spl.c
@@ -0,0 +1,34 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ *  (C) Copyright 2010-2013
+ *  NVIDIA Corporation <www.nvidia.com>
+ *
+ *  (C) Copyright 2021
+ *  Svyatoslav Ryhel <clamor95@gmail.com>
+ */
+
+#include <common.h>
+#include <asm/arch-tegra/tegra_i2c.h>
+#include <linux/delay.h>
+
+/* I2C addr is in 8 bit */
+#define TPS65911_I2C_ADDR		0x5A
+#define TPS65911_VDDCTRL_OP_REG		0x28
+#define TPS65911_VDDCTRL_SR_REG		0x27
+#define TPS65911_VDDCTRL_OP_DATA	(0x2400 | TPS65911_VDDCTRL_OP_REG)
+#define TPS65911_VDDCTRL_SR_DATA	(0x0100 | TPS65911_VDDCTRL_SR_REG)
+
+void pmic_enable_cpu_vdd(void)
+{
+	/*
+	 * Bring up CPU VDD via the TPS65911x PMIC on the DVC I2C bus.
+	 * First set VDD to 1.0125V, then enable the VDD regulator.
+	 */
+	udelay(1000);
+	tegra_i2c_ll_write(TPS65911_I2C_ADDR,
+			   TPS65911_VDDCTRL_OP_DATA);
+	udelay(1000);
+	tegra_i2c_ll_write(TPS65911_I2C_ADDR,
+			   TPS65911_VDDCTRL_SR_DATA);
+	udelay(10 * 1000);
+}
diff --git a/board/nvidia/beaver/Makefile b/board/nvidia/beaver/Makefile
index 80cff3e..5e9e708 100644
--- a/board/nvidia/beaver/Makefile
+++ b/board/nvidia/beaver/Makefile
@@ -2,4 +2,6 @@
 #
 # Copyright (c) 2010-2013, NVIDIA CORPORATION.  All rights reserved.
 
+obj-$(CONFIG_SPL_BUILD) += beaver-spl.o
+
 obj-y	= ../cardhu/cardhu.o
diff --git a/board/nvidia/beaver/beaver-spl.c b/board/nvidia/beaver/beaver-spl.c
new file mode 100644
index 0000000..b5d0c14
--- /dev/null
+++ b/board/nvidia/beaver/beaver-spl.c
@@ -0,0 +1,43 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ *  (C) Copyright 2010-2013
+ *  NVIDIA Corporation <www.nvidia.com>
+ *
+ *  (C) Copyright 2021
+ *  Svyatoslav Ryhel <clamor95@gmail.com>
+ */
+
+#include <common.h>
+#include <asm/arch-tegra/tegra_i2c.h>
+#include <linux/delay.h>
+
+/* I2C addr is in 8 bit */
+#define TPS65911_I2C_ADDR		0x5A
+#define TPS65911_VDDCTRL_OP_REG		0x28
+#define TPS65911_VDDCTRL_SR_REG		0x27
+#define TPS65911_VDDCTRL_OP_DATA	(0x2400 | TPS65911_VDDCTRL_OP_REG)
+#define TPS65911_VDDCTRL_SR_DATA	(0x0100 | TPS65911_VDDCTRL_SR_REG)
+
+#define TPS62366A_I2C_ADDR		0xC0
+#define TPS62366A_SET1_REG		0x01
+#define TPS62366A_SET1_DATA		(0x4600 | TPS62366A_SET1_REG)
+
+void pmic_enable_cpu_vdd(void)
+{
+	/* Set VDD_CORE to 1.200V. */
+	tegra_i2c_ll_write(TPS62366A_I2C_ADDR,
+			   TPS62366A_SET1_DATA);
+
+	udelay(1000);
+
+	/*
+	 * Bring up CPU VDD via the TPS65911x PMIC on the DVC I2C bus.
+	 * First set VDD to 1.0125V, then enable the VDD regulator.
+	 */
+	tegra_i2c_ll_write(TPS65911_I2C_ADDR,
+			   TPS65911_VDDCTRL_OP_DATA);
+	udelay(1000);
+	tegra_i2c_ll_write(TPS65911_I2C_ADDR,
+			   TPS65911_VDDCTRL_SR_DATA);
+	udelay(10 * 1000);
+}
diff --git a/board/nvidia/cardhu/Makefile b/board/nvidia/cardhu/Makefile
index 9597105..6f480cd 100644
--- a/board/nvidia/cardhu/Makefile
+++ b/board/nvidia/cardhu/Makefile
@@ -3,4 +3,6 @@
 #  (C) Copyright 2010-2012
 #  NVIDIA Corporation <www.nvidia.com>
 
-obj-y	:= cardhu.o
+obj-$(CONFIG_SPL_BUILD) += cardhu-spl.o
+
+obj-y	+= cardhu.o
diff --git a/board/nvidia/cardhu/cardhu-spl.c b/board/nvidia/cardhu/cardhu-spl.c
new file mode 100644
index 0000000..de2fa30
--- /dev/null
+++ b/board/nvidia/cardhu/cardhu-spl.c
@@ -0,0 +1,43 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ *  (C) Copyright 2010-2013
+ *  NVIDIA Corporation <www.nvidia.com>
+ *
+ *  (C) Copyright 2021
+ *  Svyatoslav Ryhel <clamor95@gmail.com>
+ */
+
+#include <common.h>
+#include <asm/arch-tegra/tegra_i2c.h>
+#include <linux/delay.h>
+
+/* I2C addr is in 8 bit */
+#define TPS65911_I2C_ADDR		0x5A
+#define TPS65911_VDDCTRL_OP_REG		0x28
+#define TPS65911_VDDCTRL_SR_REG		0x27
+#define TPS65911_VDDCTRL_OP_DATA	(0x2400 | TPS65911_VDDCTRL_OP_REG)
+#define TPS65911_VDDCTRL_SR_DATA	(0x0100 | TPS65911_VDDCTRL_SR_REG)
+
+#define TPS62361B_I2C_ADDR		0xC0
+#define TPS62361B_SET3_REG		0x03
+#define TPS62361B_SET3_DATA		(0x4600 | TPS62361B_SET3_REG)
+
+void pmic_enable_cpu_vdd(void)
+{
+	/* Set VDD_CORE to 1.200V. */
+	tegra_i2c_ll_write(TPS62361B_I2C_ADDR,
+			   TPS62361B_SET3_DATA);
+
+	udelay(1000);
+
+	/*
+	 * Bring up CPU VDD via the TPS65911x PMIC on the DVC I2C bus.
+	 * First set VDD to 1.0125V, then enable the VDD regulator.
+	 */
+	tegra_i2c_ll_write(TPS65911_I2C_ADDR,
+			   TPS65911_VDDCTRL_OP_DATA);
+	udelay(1000);
+	tegra_i2c_ll_write(TPS65911_I2C_ADDR,
+			   TPS65911_VDDCTRL_SR_DATA);
+	udelay(10 * 1000);
+}
diff --git a/board/nvidia/venice2/as3722_init.c b/board/nvidia/venice2/as3722_init.c
index ba67654..395bdd9 100644
--- a/board/nvidia/venice2/as3722_init.c
+++ b/board/nvidia/venice2/as3722_init.c
@@ -9,25 +9,42 @@
 #include <asm/io.h>
 #include <asm/arch-tegra/tegra_i2c.h>
 #include <linux/delay.h>
-#include "as3722_init.h"
 
-/* AS3722-PMIC-specific early init code - get CPU rails up, etc */
+/* AS3722-PMIC-specific early init regs */
 
-void tegra_i2c_ll_write_addr(uint addr, uint config)
-{
-	struct i2c_ctlr *reg = (struct i2c_ctlr *)TEGRA_DVC_BASE;
+#define AS3722_I2C_ADDR		0x80
 
-	writel(addr, &reg->cmd_addr0);
-	writel(config, &reg->cnfg);
-}
+#define AS3722_SD0VOLTAGE_REG	0x00	/* CPU */
+#define AS3722_SD1VOLTAGE_REG	0x01	/* CORE, already set by OTP */
+#define AS3722_SD6VOLTAGE_REG	0x06	/* GPU */
+#define AS3722_SDCONTROL_REG	0x4D
 
-void tegra_i2c_ll_write_data(uint data, uint config)
-{
-	struct i2c_ctlr *reg = (struct i2c_ctlr *)TEGRA_DVC_BASE;
+#define AS3722_LDO2VOLTAGE_REG	0x12	/* VPP_FUSE */
+#define AS3722_LDO6VOLTAGE_REG	0x16	/* VDD_SDMMC */
+#define AS3722_LDCONTROL_REG	0x4E
 
-	writel(data, &reg->cmd_data1);
-	writel(config, &reg->cnfg);
-}
+#if defined(CONFIG_TARGET_VENICE2)
+#define AS3722_SD0VOLTAGE_DATA	(0x2800 | AS3722_SD0VOLTAGE_REG)
+#else /* TK1 or Nyan-Big */
+#define AS3722_SD0VOLTAGE_DATA	(0x3C00 | AS3722_SD0VOLTAGE_REG)
+#endif
+#define AS3722_SD0CONTROL_DATA	(0x0100 | AS3722_SDCONTROL_REG)
+
+#if defined(CONFIG_TARGET_JETSON_TK1) || defined(CONFIG_TARGET_CEI_TK1_SOM)
+#define AS3722_SD1VOLTAGE_DATA	(0x2800 | AS3722_SD1VOLTAGE_REG)
+#define AS3722_SD1CONTROL_DATA	(0x0200 | AS3722_SDCONTROL_REG)
+#endif
+
+#define AS3722_SD6CONTROL_DATA	(0x4000 | AS3722_SDCONTROL_REG)
+#define AS3722_SD6VOLTAGE_DATA	(0x2800 | AS3722_SD6VOLTAGE_REG)
+
+#define AS3722_LDO2CONTROL_DATA	(0x0400 | AS3722_LDCONTROL_REG)
+#define AS3722_LDO2VOLTAGE_DATA	(0x1000 | AS3722_LDO2VOLTAGE_REG)
+
+#define AS3722_LDO6CONTROL_DATA	(0x4000 | AS3722_LDCONTROL_REG)
+#define AS3722_LDO6VOLTAGE_DATA	(0x3F00 | AS3722_LDO6VOLTAGE_REG)
+
+/* AS3722-PMIC-specific early init code - get CPU rails up, etc */
 
 void pmic_enable_cpu_vdd(void)
 {
@@ -37,8 +54,8 @@
 	/* Set up VDD_CORE, for boards where OTP is incorrect*/
 	debug("%s: Setting VDD_CORE via AS3722 reg 1\n", __func__);
 	/* Configure VDD_CORE via the AS3722 PMIC on the PWR I2C bus */
-	tegra_i2c_ll_write_addr(AS3722_I2C_ADDR, 2);
-	tegra_i2c_ll_write_data(AS3722_SD1VOLTAGE_DATA, I2C_SEND_2_BYTES);
+	tegra_i2c_ll_write(AS3722_I2C_ADDR,
+			   AS3722_SD1VOLTAGE_DATA);
 	/*
 	 * Don't write SDCONTROL - it's already 0x7F, i.e. all SDs enabled.
 	 * tegra_i2c_ll_write_data(AS3722_SD1CONTROL_DATA, I2C_SEND_2_BYTES);
@@ -51,8 +68,8 @@
 	 * Bring up VDD_CPU via the AS3722 PMIC on the PWR I2C bus.
 	 * First set VDD to 1.0V, then enable the VDD regulator.
 	 */
-	tegra_i2c_ll_write_addr(AS3722_I2C_ADDR, 2);
-	tegra_i2c_ll_write_data(AS3722_SD0VOLTAGE_DATA, I2C_SEND_2_BYTES);
+	tegra_i2c_ll_write(AS3722_I2C_ADDR,
+			   AS3722_SD0VOLTAGE_DATA);
 	/*
 	 * Don't write SDCONTROL - it's already 0x7F, i.e. all SDs enabled.
 	 * tegra_i2c_ll_write_data(AS3722_SD0CONTROL_DATA, I2C_SEND_2_BYTES);
@@ -64,8 +81,8 @@
 	 * Bring up VDD_GPU via the AS3722 PMIC on the PWR I2C bus.
 	 * First set VDD to 1.0V, then enable the VDD regulator.
 	 */
-	tegra_i2c_ll_write_addr(AS3722_I2C_ADDR, 2);
-	tegra_i2c_ll_write_data(AS3722_SD6VOLTAGE_DATA, I2C_SEND_2_BYTES);
+	tegra_i2c_ll_write(AS3722_I2C_ADDR,
+			   AS3722_SD6VOLTAGE_DATA);
 	/*
 	 * Don't write SDCONTROL - it's already 0x7F, i.e. all SDs enabled.
 	 * tegra_i2c_ll_write_data(AS3722_SD6CONTROL_DATA, I2C_SEND_2_BYTES);
@@ -77,8 +94,8 @@
 	 * Bring up VPP_FUSE via the AS3722 PMIC on the PWR I2C bus.
 	 * First set VDD to 1.2V, then enable the VDD regulator.
 	 */
-	tegra_i2c_ll_write_addr(AS3722_I2C_ADDR, 2);
-	tegra_i2c_ll_write_data(AS3722_LDO2VOLTAGE_DATA, I2C_SEND_2_BYTES);
+	tegra_i2c_ll_write(AS3722_I2C_ADDR,
+			   AS3722_LDO2VOLTAGE_DATA);
 	/*
 	 * Don't write LDCONTROL - it's already 0xFF, i.e. all LDOs enabled.
 	 * tegra_i2c_ll_write_data(AS3722_LDO2CONTROL_DATA, I2C_SEND_2_BYTES);
@@ -93,8 +110,8 @@
 	 * NOTE: We do this early because doing it later seems to hose the CPU
 	 * power rail/partition startup. Need to debug.
 	 */
-	tegra_i2c_ll_write_addr(AS3722_I2C_ADDR, 2);
-	tegra_i2c_ll_write_data(AS3722_LDO6VOLTAGE_DATA, I2C_SEND_2_BYTES);
+	tegra_i2c_ll_write(AS3722_I2C_ADDR,
+			   AS3722_LDO6VOLTAGE_DATA);
 	/*
 	 * Don't write LDCONTROL - it's already 0xFF, i.e. all LDOs enabled.
 	 * tegra_i2c_ll_write_data(AS3722_LDO6CONTROL_DATA, I2C_SEND_2_BYTES);
diff --git a/board/nvidia/venice2/as3722_init.h b/board/nvidia/venice2/as3722_init.h
deleted file mode 100644
index 17e7d76..0000000
--- a/board/nvidia/venice2/as3722_init.h
+++ /dev/null
@@ -1,43 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0+ */
-/*
- * (C) Copyright 2013
- * NVIDIA Corporation <www.nvidia.com>
- */
-
-/* AS3722-PMIC-specific early init regs */
-
-#define AS3722_I2C_ADDR		0x80
-
-#define AS3722_SD0VOLTAGE_REG	0x00	/* CPU */
-#define AS3722_SD1VOLTAGE_REG	0x01	/* CORE, already set by OTP */
-#define AS3722_SD6VOLTAGE_REG	0x06	/* GPU */
-#define AS3722_SDCONTROL_REG	0x4D
-
-#define AS3722_LDO2VOLTAGE_REG	0x12	/* VPP_FUSE */
-#define AS3722_LDO6VOLTAGE_REG	0x16	/* VDD_SDMMC */
-#define AS3722_LDCONTROL_REG	0x4E
-
-#if defined(CONFIG_TARGET_VENICE2)
-#define AS3722_SD0VOLTAGE_DATA	(0x2800 | AS3722_SD0VOLTAGE_REG)
-#else /* TK1 or Nyan-Big */
-#define AS3722_SD0VOLTAGE_DATA	(0x3C00 | AS3722_SD0VOLTAGE_REG)
-#endif
-#define AS3722_SD0CONTROL_DATA	(0x0100 | AS3722_SDCONTROL_REG)
-
-#if defined(CONFIG_TARGET_JETSON_TK1) || defined(CONFIG_TARGET_CEI_TK1_SOM)
-#define AS3722_SD1VOLTAGE_DATA	(0x2800 | AS3722_SD1VOLTAGE_REG)
-#define AS3722_SD1CONTROL_DATA	(0x0200 | AS3722_SDCONTROL_REG)
-#endif
-
-#define AS3722_SD6CONTROL_DATA	(0x4000 | AS3722_SDCONTROL_REG)
-#define AS3722_SD6VOLTAGE_DATA	(0x2800 | AS3722_SD6VOLTAGE_REG)
-
-#define AS3722_LDO2CONTROL_DATA	(0x0400 | AS3722_LDCONTROL_REG)
-#define AS3722_LDO2VOLTAGE_DATA	(0x1000 | AS3722_LDO2VOLTAGE_REG)
-
-#define AS3722_LDO6CONTROL_DATA	(0x4000 | AS3722_LDCONTROL_REG)
-#define AS3722_LDO6VOLTAGE_DATA	(0x3F00 | AS3722_LDO6VOLTAGE_REG)
-
-#define I2C_SEND_2_BYTES	0x0A02
-
-void pmic_enable_cpu_vdd(void);
diff --git a/board/toradex/apalis-tk1/as3722_init.c b/board/toradex/apalis-tk1/as3722_init.c
index 68169f5..e9bd102 100644
--- a/board/toradex/apalis-tk1/as3722_init.c
+++ b/board/toradex/apalis-tk1/as3722_init.c
@@ -8,25 +8,40 @@
 #include <asm/io.h>
 #include <asm/arch-tegra/tegra_i2c.h>
 #include <linux/delay.h>
-#include "as3722_init.h"
 
-/* AS3722-PMIC-specific early init code - get CPU rails up, etc */
+/* AS3722-PMIC-specific early init regs */
 
-void tegra_i2c_ll_write_addr(uint addr, uint config)
-{
-	struct i2c_ctlr *reg = (struct i2c_ctlr *)TEGRA_DVC_BASE;
+#define AS3722_I2C_ADDR		0x80
 
-	writel(addr, &reg->cmd_addr0);
-	writel(config, &reg->cnfg);
-}
+#define AS3722_SD0VOLTAGE_REG	0x00	/* CPU */
+#define AS3722_SD1VOLTAGE_REG	0x01	/* CORE, already set by OTP */
+#define AS3722_SD6VOLTAGE_REG	0x06	/* GPU */
+#define AS3722_SDCONTROL_REG	0x4D
 
-void tegra_i2c_ll_write_data(uint data, uint config)
-{
-	struct i2c_ctlr *reg = (struct i2c_ctlr *)TEGRA_DVC_BASE;
+#define AS3722_LDO1VOLTAGE_REG	0x11	/* VDD_SDMMC1 */
+#define AS3722_LDO2VOLTAGE_REG	0x12	/* VPP_FUSE */
+#define AS3722_LDO6VOLTAGE_REG	0x16	/* VDD_SDMMC3 */
+#define AS3722_LDCONTROL_REG	0x4E
+
+#define AS3722_SD0VOLTAGE_DATA	(0x3C00 | AS3722_SD0VOLTAGE_REG)
+#define AS3722_SD0CONTROL_DATA	(0x0100 | AS3722_SDCONTROL_REG)
+
+#define AS3722_SD1VOLTAGE_DATA	(0x3200 | AS3722_SD1VOLTAGE_REG)
+#define AS3722_SD1CONTROL_DATA	(0x0200 | AS3722_SDCONTROL_REG)
 
-	writel(data, &reg->cmd_data1);
-	writel(config, &reg->cnfg);
-}
+#define AS3722_SD6CONTROL_DATA	(0x4000 | AS3722_SDCONTROL_REG)
+#define AS3722_SD6VOLTAGE_DATA	(0x2800 | AS3722_SD6VOLTAGE_REG)
+
+#define AS3722_LDO1CONTROL_DATA	(0x0200 | AS3722_LDCONTROL_REG)
+#define AS3722_LDO1VOLTAGE_DATA	(0x7F00 | AS3722_LDO1VOLTAGE_REG)
+
+#define AS3722_LDO2CONTROL_DATA	(0x0400 | AS3722_LDCONTROL_REG)
+#define AS3722_LDO2VOLTAGE_DATA	(0x1000 | AS3722_LDO2VOLTAGE_REG)
+
+#define AS3722_LDO6CONTROL_DATA	(0x4000 | AS3722_LDCONTROL_REG)
+#define AS3722_LDO6VOLTAGE_DATA	(0x3F00 | AS3722_LDO6VOLTAGE_REG)
+
+/* AS3722-PMIC-specific early init code - get CPU rails up, etc */
 
 void pmic_enable_cpu_vdd(void)
 {
@@ -36,8 +51,8 @@
 	/* Set up VDD_CORE, for boards where OTP is incorrect*/
 	debug("%s: Setting VDD_CORE via AS3722 reg 1\n", __func__);
 	/* Configure VDD_CORE via the AS3722 PMIC on the PWR I2C bus */
-	tegra_i2c_ll_write_addr(AS3722_I2C_ADDR, 2);
-	tegra_i2c_ll_write_data(AS3722_SD1VOLTAGE_DATA, I2C_SEND_2_BYTES);
+	tegra_i2c_ll_write(AS3722_I2C_ADDR,
+			   AS3722_SD1VOLTAGE_DATA);
 	/*
 	 * Don't write SDCONTROL - it's already 0x7F, i.e. all SDs enabled.
 	 * tegra_i2c_ll_write_data(AS3722_SD1CONTROL_DATA, I2C_SEND_2_BYTES);
@@ -49,23 +64,17 @@
 	 * Make sure all non-fused regulators are down.
 	 * That way we're in known state after software reboot from linux
 	 */
-	tegra_i2c_ll_write_addr(AS3722_I2C_ADDR, 2);
-	tegra_i2c_ll_write_data(0x0003, I2C_SEND_2_BYTES);
+	tegra_i2c_ll_write(AS3722_I2C_ADDR, 0x0003);
 	udelay(10 * 1000);
-	tegra_i2c_ll_write_addr(AS3722_I2C_ADDR, 2);
-	tegra_i2c_ll_write_data(0x0004, I2C_SEND_2_BYTES);
+	tegra_i2c_ll_write(AS3722_I2C_ADDR, 0x0004);
 	udelay(10 * 1000);
-	tegra_i2c_ll_write_addr(AS3722_I2C_ADDR, 2);
-	tegra_i2c_ll_write_data(0x001b, I2C_SEND_2_BYTES);
+	tegra_i2c_ll_write(AS3722_I2C_ADDR, 0x001b);
 	udelay(10 * 1000);
-	tegra_i2c_ll_write_addr(AS3722_I2C_ADDR, 2);
-	tegra_i2c_ll_write_data(0x0014, I2C_SEND_2_BYTES);
+	tegra_i2c_ll_write(AS3722_I2C_ADDR, 0x0014);
 	udelay(10 * 1000);
-	tegra_i2c_ll_write_addr(AS3722_I2C_ADDR, 2);
-	tegra_i2c_ll_write_data(0x001a, I2C_SEND_2_BYTES);
+	tegra_i2c_ll_write(AS3722_I2C_ADDR, 0x001a);
 	udelay(10 * 1000);
-	tegra_i2c_ll_write_addr(AS3722_I2C_ADDR, 2);
-	tegra_i2c_ll_write_data(0x0019, I2C_SEND_2_BYTES);
+	tegra_i2c_ll_write(AS3722_I2C_ADDR, 0x0019);
 	udelay(10 * 1000);
 
 	debug("%s: Setting VDD_CPU to 1.0V via AS3722 reg 0/4D\n", __func__);
@@ -73,8 +82,8 @@
 	 * Bring up VDD_CPU via the AS3722 PMIC on the PWR I2C bus.
 	 * First set VDD to 1.0V, then enable the VDD regulator.
 	 */
-	tegra_i2c_ll_write_addr(AS3722_I2C_ADDR, 2);
-	tegra_i2c_ll_write_data(AS3722_SD0VOLTAGE_DATA, I2C_SEND_2_BYTES);
+	tegra_i2c_ll_write(AS3722_I2C_ADDR,
+			   AS3722_SD0VOLTAGE_DATA);
 	/*
 	 * Don't write SDCONTROL - it's already 0x7F, i.e. all SDs enabled.
 	 * tegra_i2c_ll_write_data(AS3722_SD0CONTROL_DATA, I2C_SEND_2_BYTES);
@@ -86,8 +95,8 @@
 	 * Bring up VDD_GPU via the AS3722 PMIC on the PWR I2C bus.
 	 * First set VDD to 1.0V, then enable the VDD regulator.
 	 */
-	tegra_i2c_ll_write_addr(AS3722_I2C_ADDR, 2);
-	tegra_i2c_ll_write_data(AS3722_SD6VOLTAGE_DATA, I2C_SEND_2_BYTES);
+	tegra_i2c_ll_write(AS3722_I2C_ADDR,
+			   AS3722_SD6VOLTAGE_DATA);
 	/*
 	 * Don't write SDCONTROL - it's already 0x7F, i.e. all SDs enabled.
 	 * tegra_i2c_ll_write_data(AS3722_SD6CONTROL_DATA, I2C_SEND_2_BYTES);
@@ -99,8 +108,8 @@
 	 * Bring up VPP_FUSE via the AS3722 PMIC on the PWR I2C bus.
 	 * First set VDD to 1.2V, then enable the VDD regulator.
 	 */
-	tegra_i2c_ll_write_addr(AS3722_I2C_ADDR, 2);
-	tegra_i2c_ll_write_data(AS3722_LDO2VOLTAGE_DATA, I2C_SEND_2_BYTES);
+	tegra_i2c_ll_write(AS3722_I2C_ADDR,
+			   AS3722_LDO2VOLTAGE_DATA);
 	/*
 	 * Don't write LDCONTROL - it's already 0xFF, i.e. all LDOs enabled.
 	 * tegra_i2c_ll_write_data(AS3722_LDO2CONTROL_DATA, I2C_SEND_2_BYTES);
@@ -115,8 +124,8 @@
 	 * NOTE: We do this early because doing it later seems to hose the CPU
 	 * power rail/partition startup. Need to debug.
 	 */
-	tegra_i2c_ll_write_addr(AS3722_I2C_ADDR, 2);
-	tegra_i2c_ll_write_data(AS3722_LDO1VOLTAGE_DATA, I2C_SEND_2_BYTES);
+	tegra_i2c_ll_write(AS3722_I2C_ADDR,
+			   AS3722_LDO1VOLTAGE_DATA);
 	/*
 	 * Don't write LDCONTROL - it's already 0xFF, i.e. all LDOs enabled.
 	 * tegra_i2c_ll_write_data(AS3722_LDO1CONTROL_DATA, I2C_SEND_2_BYTES);
@@ -131,8 +140,8 @@
 	 * NOTE: We do this early because doing it later seems to hose the CPU
 	 * power rail/partition startup. Need to debug.
 	 */
-	tegra_i2c_ll_write_addr(AS3722_I2C_ADDR, 2);
-	tegra_i2c_ll_write_data(AS3722_LDO6VOLTAGE_DATA, I2C_SEND_2_BYTES);
+	tegra_i2c_ll_write(AS3722_I2C_ADDR,
+			   AS3722_LDO6VOLTAGE_DATA);
 	/*
 	 * Don't write LDCONTROL - it's already 0xFF, i.e. all LDOs enabled.
 	 * tegra_i2c_ll_write_data(AS3722_LDO6CONTROL_DATA, I2C_SEND_2_BYTES);
diff --git a/board/toradex/apalis-tk1/as3722_init.h b/board/toradex/apalis-tk1/as3722_init.h
deleted file mode 100644
index 99836de..0000000
--- a/board/toradex/apalis-tk1/as3722_init.h
+++ /dev/null
@@ -1,40 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0+ */
-/*
- * Copyright (c) 2012-2016 Toradex, Inc.
- */
-
-/* AS3722-PMIC-specific early init regs */
-
-#define AS3722_I2C_ADDR		0x80
-
-#define AS3722_SD0VOLTAGE_REG	0x00	/* CPU */
-#define AS3722_SD1VOLTAGE_REG	0x01	/* CORE, already set by OTP */
-#define AS3722_SD6VOLTAGE_REG	0x06	/* GPU */
-#define AS3722_SDCONTROL_REG	0x4D
-
-#define AS3722_LDO1VOLTAGE_REG	0x11	/* VDD_SDMMC1 */
-#define AS3722_LDO2VOLTAGE_REG	0x12	/* VPP_FUSE */
-#define AS3722_LDO6VOLTAGE_REG	0x16	/* VDD_SDMMC3 */
-#define AS3722_LDCONTROL_REG	0x4E
-
-#define AS3722_SD0VOLTAGE_DATA	(0x3C00 | AS3722_SD0VOLTAGE_REG)
-#define AS3722_SD0CONTROL_DATA	(0x0100 | AS3722_SDCONTROL_REG)
-
-#define AS3722_SD1VOLTAGE_DATA	(0x3200 | AS3722_SD1VOLTAGE_REG)
-#define AS3722_SD1CONTROL_DATA	(0x0200 | AS3722_SDCONTROL_REG)
-
-#define AS3722_SD6CONTROL_DATA	(0x4000 | AS3722_SDCONTROL_REG)
-#define AS3722_SD6VOLTAGE_DATA	(0x2800 | AS3722_SD6VOLTAGE_REG)
-
-#define AS3722_LDO1CONTROL_DATA	(0x0200 | AS3722_LDCONTROL_REG)
-#define AS3722_LDO1VOLTAGE_DATA	(0x7F00 | AS3722_LDO1VOLTAGE_REG)
-
-#define AS3722_LDO2CONTROL_DATA	(0x0400 | AS3722_LDCONTROL_REG)
-#define AS3722_LDO2VOLTAGE_DATA	(0x1000 | AS3722_LDO2VOLTAGE_REG)
-
-#define AS3722_LDO6CONTROL_DATA	(0x4000 | AS3722_LDCONTROL_REG)
-#define AS3722_LDO6VOLTAGE_DATA	(0x3F00 | AS3722_LDO6VOLTAGE_REG)
-
-#define I2C_SEND_2_BYTES	0x0A02
-
-void pmic_enable_cpu_vdd(void);
diff --git a/board/toradex/apalis_t30/Makefile b/board/toradex/apalis_t30/Makefile
index 0ea3d8f..eed6070 100644
--- a/board/toradex/apalis_t30/Makefile
+++ b/board/toradex/apalis_t30/Makefile
@@ -1,4 +1,6 @@
 # Copyright (c) 2014 Marcel Ziswiler
 # SPDX-License-Identifier:      GPL-2.0+
 
+obj-$(CONFIG_SPL_BUILD) += apalis_t30-spl.o
+
 obj-y	+= apalis_t30.o
diff --git a/board/toradex/apalis_t30/apalis_t30-spl.c b/board/toradex/apalis_t30/apalis_t30-spl.c
new file mode 100644
index 0000000..6e54464
--- /dev/null
+++ b/board/toradex/apalis_t30/apalis_t30-spl.c
@@ -0,0 +1,34 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ *  (C) Copyright 2010-2013
+ *  NVIDIA Corporation <www.nvidia.com>
+ *
+ *  (C) Copyright 2021
+ *  Svyatoslav Ryhel <clamor95@gmail.com>
+ */
+
+#include <common.h>
+#include <asm/arch-tegra/tegra_i2c.h>
+#include <linux/delay.h>
+
+/* I2C addr is in 8 bit */
+#define TPS65911_I2C_ADDR		0x5A
+#define TPS65911_VDDCTRL_OP_REG		0x28
+#define TPS65911_VDDCTRL_SR_REG		0x27
+#define TPS65911_VDDCTRL_OP_DATA	(0x2400 | TPS65911_VDDCTRL_OP_REG)
+#define TPS65911_VDDCTRL_SR_DATA	(0x0100 | TPS65911_VDDCTRL_SR_REG)
+
+void pmic_enable_cpu_vdd(void)
+{
+	/*
+	 * Bring up CPU VDD via the TPS65911x PMIC on the DVC I2C bus.
+	 * First set VDD to 1.0125V, then enable the VDD regulator.
+	 */
+	udelay(1000);
+	tegra_i2c_ll_write(TPS65911_I2C_ADDR,
+			   TPS65911_VDDCTRL_OP_DATA);
+	udelay(1000);
+	tegra_i2c_ll_write(TPS65911_I2C_ADDR,
+			   TPS65911_VDDCTRL_SR_DATA);
+	udelay(10 * 1000);
+}
diff --git a/board/toradex/colibri_t30/Makefile b/board/toradex/colibri_t30/Makefile
index 4242902..8f33323 100644
--- a/board/toradex/colibri_t30/Makefile
+++ b/board/toradex/colibri_t30/Makefile
@@ -1,4 +1,6 @@
 # Copyright (c) 2013-2014 Stefan Agner
 # SPDX-License-Identifier:      GPL-2.0+
 
+obj-$(CONFIG_SPL_BUILD) += colibri_t30-spl.o
+
 obj-y	+= colibri_t30.o
diff --git a/board/toradex/colibri_t30/colibri_t30-spl.c b/board/toradex/colibri_t30/colibri_t30-spl.c
new file mode 100644
index 0000000..6e54464
--- /dev/null
+++ b/board/toradex/colibri_t30/colibri_t30-spl.c
@@ -0,0 +1,34 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ *  (C) Copyright 2010-2013
+ *  NVIDIA Corporation <www.nvidia.com>
+ *
+ *  (C) Copyright 2021
+ *  Svyatoslav Ryhel <clamor95@gmail.com>
+ */
+
+#include <common.h>
+#include <asm/arch-tegra/tegra_i2c.h>
+#include <linux/delay.h>
+
+/* I2C addr is in 8 bit */
+#define TPS65911_I2C_ADDR		0x5A
+#define TPS65911_VDDCTRL_OP_REG		0x28
+#define TPS65911_VDDCTRL_SR_REG		0x27
+#define TPS65911_VDDCTRL_OP_DATA	(0x2400 | TPS65911_VDDCTRL_OP_REG)
+#define TPS65911_VDDCTRL_SR_DATA	(0x0100 | TPS65911_VDDCTRL_SR_REG)
+
+void pmic_enable_cpu_vdd(void)
+{
+	/*
+	 * Bring up CPU VDD via the TPS65911x PMIC on the DVC I2C bus.
+	 * First set VDD to 1.0125V, then enable the VDD regulator.
+	 */
+	udelay(1000);
+	tegra_i2c_ll_write(TPS65911_I2C_ADDR,
+			   TPS65911_VDDCTRL_OP_DATA);
+	udelay(1000);
+	tegra_i2c_ll_write(TPS65911_I2C_ADDR,
+			   TPS65911_VDDCTRL_SR_DATA);
+	udelay(10 * 1000);
+}
diff --git a/configs/beaver_defconfig b/configs/beaver_defconfig
index 94baba4..0a782ad 100644
--- a/configs/beaver_defconfig
+++ b/configs/beaver_defconfig
@@ -64,8 +64,5 @@
 CONFIG_USB_HOST_ETHER=y
 CONFIG_USB_ETHER_ASIX=y
 CONFIG_USB_GADGET=y
-CONFIG_USB_GADGET_MANUFACTURER="NVIDIA"
-CONFIG_USB_GADGET_VENDOR_NUM=0x0955
-CONFIG_USB_GADGET_PRODUCT_NUM=0x701a
 CONFIG_CI_UDC=y
 CONFIG_USB_GADGET_DOWNLOAD=y
diff --git a/configs/cei-tk1-som_defconfig b/configs/cei-tk1-som_defconfig
index 702f6bc..8d9351e 100644
--- a/configs/cei-tk1-som_defconfig
+++ b/configs/cei-tk1-som_defconfig
@@ -70,8 +70,5 @@
 CONFIG_USB_HOST_ETHER=y
 CONFIG_USB_ETHER_ASIX=y
 CONFIG_USB_GADGET=y
-CONFIG_USB_GADGET_MANUFACTURER="NVIDIA"
-CONFIG_USB_GADGET_VENDOR_NUM=0x0955
-CONFIG_USB_GADGET_PRODUCT_NUM=0x701a
 CONFIG_CI_UDC=y
 CONFIG_USB_GADGET_DOWNLOAD=y
diff --git a/configs/dalmore_defconfig b/configs/dalmore_defconfig
index e5fd0d5..baa2632 100644
--- a/configs/dalmore_defconfig
+++ b/configs/dalmore_defconfig
@@ -60,8 +60,5 @@
 CONFIG_USB_HOST_ETHER=y
 CONFIG_USB_ETHER_ASIX=y
 CONFIG_USB_GADGET=y
-CONFIG_USB_GADGET_MANUFACTURER="NVIDIA"
-CONFIG_USB_GADGET_VENDOR_NUM=0x0955
-CONFIG_USB_GADGET_PRODUCT_NUM=0x701a
 CONFIG_CI_UDC=y
 CONFIG_USB_GADGET_DOWNLOAD=y
diff --git a/configs/jetson-tk1_defconfig b/configs/jetson-tk1_defconfig
index fc5360a..fb1f337 100644
--- a/configs/jetson-tk1_defconfig
+++ b/configs/jetson-tk1_defconfig
@@ -70,8 +70,5 @@
 CONFIG_USB_HOST_ETHER=y
 CONFIG_USB_ETHER_ASIX=y
 CONFIG_USB_GADGET=y
-CONFIG_USB_GADGET_MANUFACTURER="NVIDIA"
-CONFIG_USB_GADGET_VENDOR_NUM=0x0955
-CONFIG_USB_GADGET_PRODUCT_NUM=0x701a
 CONFIG_CI_UDC=y
 CONFIG_USB_GADGET_DOWNLOAD=y
diff --git a/configs/nyan-big_defconfig b/configs/nyan-big_defconfig
index 6d6d890..2017d5c 100644
--- a/configs/nyan-big_defconfig
+++ b/configs/nyan-big_defconfig
@@ -93,9 +93,6 @@
 CONFIG_USB_HOST_ETHER=y
 CONFIG_USB_ETHER_ASIX=y
 CONFIG_USB_GADGET=y
-CONFIG_USB_GADGET_MANUFACTURER="NVIDIA"
-CONFIG_USB_GADGET_VENDOR_NUM=0x0955
-CONFIG_USB_GADGET_PRODUCT_NUM=0x701a
 CONFIG_CI_UDC=y
 CONFIG_USB_GADGET_DOWNLOAD=y
 CONFIG_VIDEO=y
diff --git a/configs/p2371-0000_defconfig b/configs/p2371-0000_defconfig
index e807491..2962a7d 100644
--- a/configs/p2371-0000_defconfig
+++ b/configs/p2371-0000_defconfig
@@ -48,8 +48,5 @@
 CONFIG_USB_HOST_ETHER=y
 CONFIG_USB_ETHER_ASIX=y
 CONFIG_USB_GADGET=y
-CONFIG_USB_GADGET_MANUFACTURER="NVIDIA"
-CONFIG_USB_GADGET_VENDOR_NUM=0x0955
-CONFIG_USB_GADGET_PRODUCT_NUM=0x701a
 CONFIG_CI_UDC=y
 CONFIG_USB_GADGET_DOWNLOAD=y
diff --git a/configs/p2371-2180_defconfig b/configs/p2371-2180_defconfig
index ea62e18..6b44361 100644
--- a/configs/p2371-2180_defconfig
+++ b/configs/p2371-2180_defconfig
@@ -57,8 +57,5 @@
 CONFIG_USB_HOST_ETHER=y
 CONFIG_USB_ETHER_ASIX=y
 CONFIG_USB_GADGET=y
-CONFIG_USB_GADGET_MANUFACTURER="NVIDIA"
-CONFIG_USB_GADGET_VENDOR_NUM=0x0955
-CONFIG_USB_GADGET_PRODUCT_NUM=0x701a
 CONFIG_CI_UDC=y
 CONFIG_USB_GADGET_DOWNLOAD=y
diff --git a/configs/p2571_defconfig b/configs/p2571_defconfig
index bc3fb3e..00b0dc6 100644
--- a/configs/p2571_defconfig
+++ b/configs/p2571_defconfig
@@ -49,8 +49,5 @@
 CONFIG_USB_HOST_ETHER=y
 CONFIG_USB_ETHER_ASIX=y
 CONFIG_USB_GADGET=y
-CONFIG_USB_GADGET_MANUFACTURER="NVIDIA"
-CONFIG_USB_GADGET_VENDOR_NUM=0x0955
-CONFIG_USB_GADGET_PRODUCT_NUM=0x701a
 CONFIG_CI_UDC=y
 CONFIG_USB_GADGET_DOWNLOAD=y
diff --git a/configs/p3450-0000_defconfig b/configs/p3450-0000_defconfig
index 8e16afd..d35bea4 100644
--- a/configs/p3450-0000_defconfig
+++ b/configs/p3450-0000_defconfig
@@ -61,8 +61,5 @@
 CONFIG_USB_HOST_ETHER=y
 CONFIG_USB_ETHER_ASIX=y
 CONFIG_USB_GADGET=y
-CONFIG_USB_GADGET_MANUFACTURER="NVIDIA"
-CONFIG_USB_GADGET_VENDOR_NUM=0x0955
-CONFIG_USB_GADGET_PRODUCT_NUM=0x701a
 CONFIG_CI_UDC=y
 CONFIG_USB_GADGET_DOWNLOAD=y
diff --git a/configs/venice2_defconfig b/configs/venice2_defconfig
index 09fa531..c30bd25 100644
--- a/configs/venice2_defconfig
+++ b/configs/venice2_defconfig
@@ -59,8 +59,5 @@
 CONFIG_USB_HOST_ETHER=y
 CONFIG_USB_ETHER_ASIX=y
 CONFIG_USB_GADGET=y
-CONFIG_USB_GADGET_MANUFACTURER="NVIDIA"
-CONFIG_USB_GADGET_VENDOR_NUM=0x0955
-CONFIG_USB_GADGET_PRODUCT_NUM=0x701a
 CONFIG_CI_UDC=y
 CONFIG_USB_GADGET_DOWNLOAD=y
diff --git a/doc/usage/cmd/ebtupdate.rst b/doc/usage/cmd/ebtupdate.rst
new file mode 100644
index 0000000..d90474c
--- /dev/null
+++ b/doc/usage/cmd/ebtupdate.rst
@@ -0,0 +1,69 @@
+.. SPDX-License-Identifier: GPL-2.0+:
+
+ebtupdate command
+=================
+
+Synopsis
+--------
+
+::
+
+    ebtupdate [<bct> [<ebt>] [<size>]]
+
+Description
+-----------
+
+The "ebtupdate" command is used to self-update bootloader on Tegra 2 and Tegra 3
+production devices which were processed using re-cryption.
+
+The "ebtupdate" performs encryption of new bootloader and decryption, patching
+and re-encryption of BCT "in situ". After BCT and bootloader can be written in
+their respective places.
+
+bct
+    address of BCT block pre-loaded into RAM.
+
+ebt
+    address of the bootloader pre-loaded into RAM.
+
+size
+    size of the pre-loaded bootloader.
+
+Example
+-------
+
+This is the boot log of a LG Optimus Vu:
+
+::
+
+    => mmc dev 0 1
+    switch to partitions #1, OK
+    mmc0(part 1) is current device
+    => mmc read $kernel_addr_r 0 $boot_block_size
+    MMC read: dev # 0, block # 0, count 4096 ... 4096 blocks read: OK
+    => load mmc 0:1 $ramdisk_addr_r $bootloader_file
+    684783 bytes read in 44 ms (14.8 MiB/s)
+    => size mmc 0:1 $bootloader_file
+    => ebtupdate $kernel_addr_r $ramdisk_addr_r $filesize
+    => mmc dev 0 1
+    switch to partitions #1, OK
+    mmc0(part 1) is current device
+    => mmc write $kernel_addr_r 0 $boot_block_size
+    MMC write: dev # 0, block # 0, count 4096 ... 4096 blocks written: OK
+    => mmc dev 0 2
+    switch to partitions #2, OK
+    mmc0(part 2) is current device
+    => mmc write $ramdisk_addr_r 0 $boot_block_size
+    MMC write: dev # 0, block # 0, count 4096 ... 4096 blocks written: OK
+
+Configuration
+-------------
+
+The ebtupdate command is only available if CONFIG_CMD_EBTUPDATE=y and
+only on Tegra 2 and Tegra 3 configurations.
+
+Return value
+------------
+
+The return value $? is set to 0 (true) if everything went successfully. If an
+error occurs, the return value $? is set to 1 (false).
diff --git a/doc/usage/index.rst b/doc/usage/index.rst
index cde7dcb..840c20c 100644
--- a/doc/usage/index.rst
+++ b/doc/usage/index.rst
@@ -41,6 +41,7 @@
    cmd/conitrace
    cmd/cyclic
    cmd/dm
+   cmd/ebtupdate
    cmd/echo
    cmd/eficonfig
    cmd/env
diff --git a/drivers/pwm/tegra_pwm.c b/drivers/pwm/tegra_pwm.c
index 36c35c6..95fc264 100644
--- a/drivers/pwm/tegra_pwm.c
+++ b/drivers/pwm/tegra_pwm.c
@@ -20,19 +20,21 @@
 {
 	struct tegra_pwm_priv *priv = dev_get_priv(dev);
 	struct pwm_ctlr *regs = priv->regs;
+	const u32 pwm_max_freq = dev_get_driver_data(dev);
 	uint pulse_width;
 	u32 reg;
 
 	if (channel >= 4)
 		return -EINVAL;
 	debug("%s: Configure '%s' channel %u\n", __func__, dev->name, channel);
-	/* We ignore the period here and just use 32KHz */
-	clock_start_periph_pll(PERIPH_ID_PWM, CLOCK_ID_SFROM32KHZ, 32768);
+
+	clock_start_periph_pll(PERIPH_ID_PWM, CLOCK_ID_PERIPH, pwm_max_freq);
 
 	pulse_width = duty_ns * 255 / period_ns;
 
 	reg = pulse_width << PWM_WIDTH_SHIFT;
 	reg |= 1 << PWM_DIVIDER_SHIFT;
+	reg |= PWM_ENABLE_MASK;
 	writel(reg, &regs[channel].control);
 	debug("%s: pulse_width=%u\n", __func__, pulse_width);
 
@@ -68,8 +70,8 @@
 };
 
 static const struct udevice_id tegra_pwm_ids[] = {
-	{ .compatible = "nvidia,tegra124-pwm" },
-	{ .compatible = "nvidia,tegra20-pwm" },
+	{ .compatible = "nvidia,tegra20-pwm", .data = 48 * 1000000 },
+	{ .compatible = "nvidia,tegra114-pwm", .data = 408 * 1000000 },
 	{ }
 };
 
diff --git a/drivers/spi/tegra20_slink.c b/drivers/spi/tegra20_slink.c
index 209ba8b..d0e7885 100644
--- a/drivers/spi/tegra20_slink.c
+++ b/drivers/spi/tegra20_slink.c
@@ -208,16 +208,14 @@
 	u32 reg, tmpdout, tmpdin = 0;
 	const u8 *dout = data_out;
 	u8 *din = data_in;
-	int num_bytes;
-	int ret;
+	int num_bytes, overflow;
+	int ret = 0;
 
 	debug("%s: slave %u:%u dout %p din %p bitlen %u\n",
 	      __func__, dev_seq(bus), spi_chip_select(dev), dout, din, bitlen);
-	if (bitlen % 8)
-		return -1;
-	num_bytes = bitlen / 8;
 
-	ret = 0;
+	num_bytes = DIV_ROUND_UP(bitlen, 8);
+	overflow = bitlen % 8;
 
 	reg = readl(&regs->status);
 	writel(reg, &regs->status);	/* Clear all SPI events via R/W */
@@ -254,8 +252,13 @@
 
 		num_bytes -= bytes;
 
-		clrsetbits_le32(&regs->command, SLINK_CMD_BIT_LENGTH_MASK,
-				bytes * 8 - 1);
+		if (overflow && !num_bytes)
+			clrsetbits_le32(&regs->command, SLINK_CMD_BIT_LENGTH_MASK,
+					(bytes - 1) * 8 + overflow - 1);
+		else
+			clrsetbits_le32(&regs->command, SLINK_CMD_BIT_LENGTH_MASK,
+					bytes * 8 - 1);
+
 		writel(tmpdout, &regs->tx_fifo);
 		setbits_le32(&regs->command, SLINK_CMD_GO);
 
diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig
index e120efe..941f97c 100644
--- a/drivers/usb/gadget/Kconfig
+++ b/drivers/usb/gadget/Kconfig
@@ -40,6 +40,7 @@
 
 config USB_GADGET_MANUFACTURER
 	string "Vendor name of the USB device"
+	default "NVIDIA" if ARCH_TEGRA
 	default "Allwinner Technology" if ARCH_SUNXI
 	default "Rockchip" if ARCH_ROCKCHIP
 	default "U-Boot"
@@ -49,6 +50,7 @@
 
 config USB_GADGET_VENDOR_NUM
 	hex "Vendor ID of the USB device"
+	default 0x0955 if ARCH_TEGRA
 	default 0x1f3a if ARCH_SUNXI
 	default 0x2207 if ARCH_ROCKCHIP
 	default 0x0
@@ -59,6 +61,7 @@
 
 config USB_GADGET_PRODUCT_NUM
 	hex "Product ID of the USB device"
+	default 0x701a if ARCH_TEGRA
 	default 0x1010 if ARCH_SUNXI
 	default 0x310a if ROCKCHIP_RK3036
 	default 0x300a if ROCKCHIP_RK3066