ARM: tegra: collect SoC sources into mach-tegra

This commit moves files as follows:

 arch/arm/cpu/arm720t/tegra20/*      -> arch/arm/mach-tegra/tegra20/*
 arch/arm/cpu/arm720t/tegra30/*      -> arch/arm/mach-tegra/tegra30/*
 arch/arm/cpu/arm720t/tegra114/*     -> arch/arm/mach-tegra/tegra114/*
 arch/arm/cpu/arm720t/tegra124*      -> arch/arm/mach-tegra/tegra124/*
 arch/arm/cpu/arm720t/tegra-common/* -> arch/arm/mach-tegra/*
 arch/arm/cpu/armv7/tegra20/*        -> arch/arm/mach-tegra/tegra20/*
 arch/arm/cpu/armv7/tegra30/*        -> arch/arm/mach-tegra/tegra30/*
 arch/arm/cpu/armv7/tegra114/*       -> arch/arm/mach-tegra/tegra114/*
 arch/arm/cpu/armv7/tegra124/*       -> arch/arm/mach-tegra/tegra124/*
 arch/arm/cpu/armv7/tegra-common/*   -> arch/arm/mach-tegra/*
 arch/arm/cpu/tegra20-common/*       -> arch/arm/mach-tegra/tegra20/*
 arch/arm/cpu/tegra30-common/*       -> arch/arm/mach-tegra/tegra30/*
 arch/arm/cpu/tegra114-common/*      -> arch/arm/mach-tegra/tegra114/*
 arch/arm/cpu/tegra124-common/*      -> arch/arm/mach-tegra/tegra124/*
 arch/arm/cpu/tegra-common/*         -> arch/arm/mach-tegra/*

Signed-off-by: Masahiro Yamada <yamada.m@jp.panasonic.com>
Tested-by: Simon Glass <sjg@chromium.org> [ on nyan-big ]
Cc: Stephen Warren <swarren@nvidia.com>
Cc: Tom Warren <twarren@nvidia.com>
diff --git a/arch/arm/mach-tegra/Kconfig b/arch/arm/mach-tegra/Kconfig
new file mode 100644
index 0000000..3a8e2b1
--- /dev/null
+++ b/arch/arm/mach-tegra/Kconfig
@@ -0,0 +1,52 @@
+if TEGRA
+
+choice
+	prompt "Tegra SoC select"
+
+config TEGRA20
+	bool "Tegra20 family"
+
+config TEGRA30
+	bool "Tegra30 family"
+
+config TEGRA114
+	bool "Tegra114 family"
+
+config TEGRA124
+	bool "Tegra124 family"
+
+endchoice
+
+config SYS_MALLOC_F
+	default y
+
+config SYS_MALLOC_F_LEN
+	default 0x1800
+
+config USE_PRIVATE_LIBGCC
+	default y if SPL_BUILD
+
+config DM
+	default y if !SPL_BUILD
+
+config DM_SERIAL
+	default y if !SPL_BUILD
+
+config DM_SPI
+	default y if !SPL_BUILD
+
+config DM_SPI_FLASH
+	default y if !SPL_BUILD
+
+config DM_I2C
+	default y if !SPL_BUILD
+
+config DM_GPIO
+	default y if !SPL_BUILD
+
+source "arch/arm/mach-tegra/tegra20/Kconfig"
+source "arch/arm/mach-tegra/tegra30/Kconfig"
+source "arch/arm/mach-tegra/tegra114/Kconfig"
+source "arch/arm/mach-tegra/tegra124/Kconfig"
+
+endif
diff --git a/arch/arm/mach-tegra/Makefile b/arch/arm/mach-tegra/Makefile
new file mode 100644
index 0000000..04cef0a
--- /dev/null
+++ b/arch/arm/mach-tegra/Makefile
@@ -0,0 +1,31 @@
+#
+# (C) Copyright 2010,2011 Nvidia Corporation.
+#
+# (C) Copyright 2000-2008
+# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+#
+# SPDX-License-Identifier:	GPL-2.0+
+#
+
+ifdef CONFIG_SPL_BUILD
+obj-y += spl.o
+obj-y += cpu.o
+else
+obj-$(CONFIG_CMD_ENTERRCM) += cmd_enterrcm.o
+endif
+
+obj-y += ap.o
+obj-y += board.o
+obj-y += cache.o
+obj-y += clock.o
+obj-y += lowlevel_init.o
+obj-y += pinmux-common.o
+obj-y += powergate.o
+obj-y += xusb-padctl.o
+obj-$(CONFIG_DISPLAY_CPUINFO) += sys_info.o
+obj-$(CONFIG_TEGRA124) += vpr.o
+
+obj-$(CONFIG_TEGRA20) += tegra20/
+obj-$(CONFIG_TEGRA30) += tegra30/
+obj-$(CONFIG_TEGRA114) += tegra114/
+obj-$(CONFIG_TEGRA124) += tegra124/
diff --git a/arch/arm/mach-tegra/ap.c b/arch/arm/mach-tegra/ap.c
new file mode 100644
index 0000000..a17dfd1
--- /dev/null
+++ b/arch/arm/mach-tegra/ap.c
@@ -0,0 +1,169 @@
+/*
+* (C) Copyright 2010-2014
+* NVIDIA Corporation <www.nvidia.com>
+*
+ * SPDX-License-Identifier:	GPL-2.0+
+*/
+
+/* Tegra AP (Application Processor) code */
+
+#include <common.h>
+#include <asm/io.h>
+#include <asm/arch/gp_padctrl.h>
+#include <asm/arch-tegra/ap.h>
+#include <asm/arch-tegra/clock.h>
+#include <asm/arch-tegra/fuse.h>
+#include <asm/arch-tegra/pmc.h>
+#include <asm/arch-tegra/scu.h>
+#include <asm/arch-tegra/tegra.h>
+#include <asm/arch-tegra/warmboot.h>
+
+int tegra_get_chip(void)
+{
+	int rev;
+	struct apb_misc_gp_ctlr *gp =
+		(struct apb_misc_gp_ctlr *)NV_PA_APB_MISC_GP_BASE;
+
+	/*
+	 * This is undocumented, Chip ID is bits 15:8 of the register
+	 * APB_MISC + 0x804, and has value 0x20 for Tegra20, 0x30 for
+	 * Tegra30, 0x35 for T114, and 0x40 for Tegra124.
+	 */
+	rev = (readl(&gp->hidrev) & HIDREV_CHIPID_MASK) >> HIDREV_CHIPID_SHIFT;
+	debug("%s: CHIPID is 0x%02X\n", __func__, rev);
+
+	return rev;
+}
+
+int tegra_get_sku_info(void)
+{
+	int sku_id;
+	struct fuse_regs *fuse = (struct fuse_regs *)NV_PA_FUSE_BASE;
+
+	sku_id = readl(&fuse->sku_info) & 0xff;
+	debug("%s: SKU info byte is 0x%02X\n", __func__, sku_id);
+
+	return sku_id;
+}
+
+int tegra_get_chip_sku(void)
+{
+	uint sku_id, chip_id;
+
+	chip_id = tegra_get_chip();
+	sku_id = tegra_get_sku_info();
+
+	switch (chip_id) {
+	case CHIPID_TEGRA20:
+		switch (sku_id) {
+		case SKU_ID_T20_7:
+		case SKU_ID_T20:
+			return TEGRA_SOC_T20;
+		case SKU_ID_T25SE:
+		case SKU_ID_AP25:
+		case SKU_ID_T25:
+		case SKU_ID_AP25E:
+		case SKU_ID_T25E:
+			return TEGRA_SOC_T25;
+		}
+		break;
+	case CHIPID_TEGRA30:
+		switch (sku_id) {
+		case SKU_ID_T33:
+		case SKU_ID_T30:
+		case SKU_ID_TM30MQS_P_A3:
+		default:
+			return TEGRA_SOC_T30;
+		}
+		break;
+	case CHIPID_TEGRA114:
+		switch (sku_id) {
+		case SKU_ID_T114_ENG:
+		case SKU_ID_T114_1:
+		default:
+			return TEGRA_SOC_T114;
+		}
+		break;
+	case CHIPID_TEGRA124:
+		switch (sku_id) {
+		case SKU_ID_T124_ENG:
+		default:
+			return TEGRA_SOC_T124;
+		}
+		break;
+	}
+
+	/* unknown chip/sku id */
+	printf("%s: ERROR: UNKNOWN CHIP/SKU ID COMBO (0x%02X/0x%02X)\n",
+		__func__, chip_id, sku_id);
+	return TEGRA_SOC_UNKNOWN;
+}
+
+static void enable_scu(void)
+{
+	struct scu_ctlr *scu = (struct scu_ctlr *)NV_PA_ARM_PERIPHBASE;
+	u32 reg;
+
+	/* Only enable the SCU on T20/T25 */
+	if (tegra_get_chip() != CHIPID_TEGRA20)
+		return;
+
+	/* If SCU already setup/enabled, return */
+	if (readl(&scu->scu_ctrl) & SCU_CTRL_ENABLE)
+		return;
+
+	/* Invalidate all ways for all processors */
+	writel(0xFFFF, &scu->scu_inv_all);
+
+	/* Enable SCU - bit 0 */
+	reg = readl(&scu->scu_ctrl);
+	reg |= SCU_CTRL_ENABLE;
+	writel(reg, &scu->scu_ctrl);
+}
+
+static u32 get_odmdata(void)
+{
+	/*
+	 * ODMDATA is stored in the BCT in IRAM by the BootROM.
+	 * The BCT start and size are stored in the BIT in IRAM.
+	 * Read the data @ bct_start + (bct_size - 12). This works
+	 * on BCTs for currently supported SoCs, which are locked down.
+	 * If this changes in new chips, we can revisit this algorithm.
+	 */
+
+	u32 bct_start, odmdata;
+
+	bct_start = readl(NV_PA_BASE_SRAM + NVBOOTINFOTABLE_BCTPTR);
+	odmdata = readl(bct_start + BCT_ODMDATA_OFFSET);
+
+	return odmdata;
+}
+
+static void init_pmc_scratch(void)
+{
+	struct pmc_ctlr *const pmc = (struct pmc_ctlr *)NV_PA_PMC_BASE;
+	u32 odmdata;
+	int i;
+
+	/* SCRATCH0 is initialized by the boot ROM and shouldn't be cleared */
+	for (i = 0; i < 23; i++)
+		writel(0, &pmc->pmc_scratch1+i);
+
+	/* ODMDATA is for kernel use to determine RAM size, LP config, etc. */
+	odmdata = get_odmdata();
+	writel(odmdata, &pmc->pmc_scratch20);
+}
+
+void s_init(void)
+{
+	/* Init PMC scratch memory */
+	init_pmc_scratch();
+
+	enable_scu();
+
+	/* init the cache */
+	config_cache();
+
+	/* init vpr */
+	config_vpr();
+}
diff --git a/arch/arm/mach-tegra/board.c b/arch/arm/mach-tegra/board.c
new file mode 100644
index 0000000..b6a84a5
--- /dev/null
+++ b/arch/arm/mach-tegra/board.c
@@ -0,0 +1,159 @@
+/*
+ *  (C) Copyright 2010-2014
+ *  NVIDIA Corporation <www.nvidia.com>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <asm/arch/clock.h>
+#include <asm/arch/funcmux.h>
+#include <asm/arch/mc.h>
+#include <asm/arch/tegra.h>
+#include <asm/arch-tegra/board.h>
+#include <asm/arch-tegra/pmc.h>
+#include <asm/arch-tegra/sys_proto.h>
+#include <asm/arch-tegra/warmboot.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+enum {
+	/* UARTs which we can enable */
+	UARTA	= 1 << 0,
+	UARTB	= 1 << 1,
+	UARTC	= 1 << 2,
+	UARTD	= 1 << 3,
+	UARTE	= 1 << 4,
+	UART_COUNT = 5,
+};
+
+/* Read the RAM size directly from the memory controller */
+unsigned int query_sdram_size(void)
+{
+	struct mc_ctlr *const mc = (struct mc_ctlr *)NV_PA_MC_BASE;
+	u32 size_mb;
+
+	size_mb = readl(&mc->mc_emem_cfg);
+#if defined(CONFIG_TEGRA20)
+	debug("mc->mc_emem_cfg (MEM_SIZE_KB) = 0x%08x\n", size_mb);
+	size_mb = get_ram_size((void *)PHYS_SDRAM_1, size_mb * 1024);
+#else
+	debug("mc->mc_emem_cfg (MEM_SIZE_MB) = 0x%08x\n", size_mb);
+	size_mb = get_ram_size((void *)PHYS_SDRAM_1, size_mb * 1024 * 1024);
+#endif
+
+#if defined(CONFIG_TEGRA30) || defined(CONFIG_TEGRA114)
+	/* External memory limited to 2047 MB due to IROM/HI-VEC */
+	if (size_mb == SZ_2G) size_mb -= SZ_1M;
+#endif
+
+	return size_mb;
+}
+
+int dram_init(void)
+{
+	/* We do not initialise DRAM here. We just query the size */
+	gd->ram_size = query_sdram_size();
+	return 0;
+}
+
+#ifdef CONFIG_DISPLAY_BOARDINFO
+int checkboard(void)
+{
+	printf("Board: %s\n", sysinfo.board_string);
+	return 0;
+}
+#endif	/* CONFIG_DISPLAY_BOARDINFO */
+
+static int uart_configs[] = {
+#if defined(CONFIG_TEGRA20)
+ #if defined(CONFIG_TEGRA_UARTA_UAA_UAB)
+	FUNCMUX_UART1_UAA_UAB,
+ #elif defined(CONFIG_TEGRA_UARTA_GPU)
+	FUNCMUX_UART1_GPU,
+ #elif defined(CONFIG_TEGRA_UARTA_SDIO1)
+	FUNCMUX_UART1_SDIO1,
+ #else
+	FUNCMUX_UART1_IRRX_IRTX,
+#endif
+	FUNCMUX_UART2_UAD,
+	-1,
+	FUNCMUX_UART4_GMC,
+	-1,
+#elif defined(CONFIG_TEGRA30)
+	FUNCMUX_UART1_ULPI,	/* UARTA */
+	-1,
+	-1,
+	-1,
+	-1,
+#elif defined(CONFIG_TEGRA114)
+	-1,
+	-1,
+	-1,
+	FUNCMUX_UART4_GMI,	/* UARTD */
+	-1,
+#else	/* Tegra124 */
+	FUNCMUX_UART1_KBC,	/* UARTA */
+	-1,
+	-1,
+	FUNCMUX_UART4_GPIO,	/* UARTD */
+	-1,
+#endif
+};
+
+/**
+ * Set up the specified uarts
+ *
+ * @param uarts_ids	Mask containing UARTs to init (UARTx)
+ */
+static void setup_uarts(int uart_ids)
+{
+	static enum periph_id id_for_uart[] = {
+		PERIPH_ID_UART1,
+		PERIPH_ID_UART2,
+		PERIPH_ID_UART3,
+		PERIPH_ID_UART4,
+		PERIPH_ID_UART5,
+	};
+	size_t i;
+
+	for (i = 0; i < UART_COUNT; i++) {
+		if (uart_ids & (1 << i)) {
+			enum periph_id id = id_for_uart[i];
+
+			funcmux_select(id, uart_configs[i]);
+			clock_ll_start_uart(id);
+		}
+	}
+}
+
+void board_init_uart_f(void)
+{
+	int uart_ids = 0;	/* bit mask of which UART ids to enable */
+
+#ifdef CONFIG_TEGRA_ENABLE_UARTA
+	uart_ids |= UARTA;
+#endif
+#ifdef CONFIG_TEGRA_ENABLE_UARTB
+	uart_ids |= UARTB;
+#endif
+#ifdef CONFIG_TEGRA_ENABLE_UARTC
+	uart_ids |= UARTC;
+#endif
+#ifdef CONFIG_TEGRA_ENABLE_UARTD
+	uart_ids |= UARTD;
+#endif
+#ifdef CONFIG_TEGRA_ENABLE_UARTE
+	uart_ids |= UARTE;
+#endif
+	setup_uarts(uart_ids);
+}
+
+#ifndef CONFIG_SYS_DCACHE_OFF
+void enable_caches(void)
+{
+	/* Enable D-cache. I-cache is already enabled in start.S */
+	dcache_enable();
+}
+#endif
diff --git a/arch/arm/mach-tegra/cache.c b/arch/arm/mach-tegra/cache.c
new file mode 100644
index 0000000..94f5bce
--- /dev/null
+++ b/arch/arm/mach-tegra/cache.c
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2013-2014, NVIDIA CORPORATION.  All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* Tegra cache routines */
+
+#include <common.h>
+#include <asm/io.h>
+#include <asm/arch-tegra/ap.h>
+#include <asm/arch/gp_padctrl.h>
+
+void config_cache(void)
+{
+	u32 reg = 0;
+
+	/* enable SMP mode and FW for CPU0, by writing to Auxiliary Ctl reg */
+	asm volatile(
+		"mrc p15, 0, r0, c1, c0, 1\n"
+		"orr r0, r0, #0x41\n"
+		"mcr p15, 0, r0, c1, c0, 1\n");
+
+	/* Currently, only Tegra114+ needs this L2 cache change to boot Linux */
+	if (tegra_get_chip() < CHIPID_TEGRA114)
+		return;
+
+	/*
+	 * Systems with an architectural L2 cache must not use the PL310.
+	 * Config L2CTLR here for a data RAM latency of 3 cycles.
+	 */
+	asm("mrc p15, 1, %0, c9, c0, 2" : : "r" (reg));
+	reg &= ~7;
+	reg |= 2;
+	asm("mcr p15, 1, %0, c9, c0, 2" : : "r" (reg));
+}
diff --git a/arch/arm/mach-tegra/clock.c b/arch/arm/mach-tegra/clock.c
new file mode 100644
index 0000000..11c7435
--- /dev/null
+++ b/arch/arm/mach-tegra/clock.c
@@ -0,0 +1,669 @@
+/*
+ * Copyright (c) 2010-2014, NVIDIA CORPORATION.  All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* Tegra SoC common clock control functions */
+
+#include <common.h>
+#include <asm/io.h>
+#include <asm/arch/clock.h>
+#include <asm/arch/tegra.h>
+#include <asm/arch-tegra/clk_rst.h>
+#include <asm/arch-tegra/timer.h>
+#include <div64.h>
+#include <fdtdec.h>
+
+/*
+ * This is our record of the current clock rate of each clock. We don't
+ * fill all of these in since we are only really interested in clocks which
+ * we use as parents.
+ */
+static unsigned pll_rate[CLOCK_ID_COUNT];
+
+/*
+ * The oscillator frequency is fixed to one of four set values. Based on this
+ * the other clocks are set up appropriately.
+ */
+static unsigned osc_freq[CLOCK_OSC_FREQ_COUNT] = {
+	13000000,
+	19200000,
+	12000000,
+	26000000,
+};
+
+/* return 1 if a peripheral ID is in range */
+#define clock_type_id_isvalid(id) ((id) >= 0 && \
+		(id) < CLOCK_TYPE_COUNT)
+
+char pllp_valid = 1;	/* PLLP is set up correctly */
+
+/* return 1 if a periphc_internal_id is in range */
+#define periphc_internal_id_isvalid(id) ((id) >= 0 && \
+		(id) < PERIPHC_COUNT)
+
+/* number of clock outputs of a PLL */
+static const u8 pll_num_clkouts[] = {
+	1,	/* PLLC */
+	1,	/* PLLM */
+	4,	/* PLLP */
+	1,	/* PLLA */
+	0,	/* PLLU */
+	0,	/* PLLD */
+};
+
+int clock_get_osc_bypass(void)
+{
+	struct clk_rst_ctlr *clkrst =
+			(struct clk_rst_ctlr *)NV_PA_CLK_RST_BASE;
+	u32 reg;
+
+	reg = readl(&clkrst->crc_osc_ctrl);
+	return (reg & OSC_XOBP_MASK) >> OSC_XOBP_SHIFT;
+}
+
+/* Returns a pointer to the registers of the given pll */
+static struct clk_pll *get_pll(enum clock_id clkid)
+{
+	struct clk_rst_ctlr *clkrst =
+			(struct clk_rst_ctlr *)NV_PA_CLK_RST_BASE;
+
+	assert(clock_id_is_pll(clkid));
+	return &clkrst->crc_pll[clkid];
+}
+
+int clock_ll_read_pll(enum clock_id clkid, u32 *divm, u32 *divn,
+		u32 *divp, u32 *cpcon, u32 *lfcon)
+{
+	struct clk_pll *pll = get_pll(clkid);
+	u32 data;
+
+	assert(clkid != CLOCK_ID_USB);
+
+	/* Safety check, adds to code size but is small */
+	if (!clock_id_is_pll(clkid) || clkid == CLOCK_ID_USB)
+		return -1;
+	data = readl(&pll->pll_base);
+	*divm = (data & PLL_DIVM_MASK) >> PLL_DIVM_SHIFT;
+	*divn = (data & PLL_DIVN_MASK) >> PLL_DIVN_SHIFT;
+	*divp = (data & PLL_DIVP_MASK) >> PLL_DIVP_SHIFT;
+	data = readl(&pll->pll_misc);
+	*cpcon = (data & PLL_CPCON_MASK) >> PLL_CPCON_SHIFT;
+	*lfcon = (data & PLL_LFCON_MASK) >> PLL_LFCON_SHIFT;
+
+	return 0;
+}
+
+unsigned long clock_start_pll(enum clock_id clkid, u32 divm, u32 divn,
+		u32 divp, u32 cpcon, u32 lfcon)
+{
+	struct clk_pll *pll = get_pll(clkid);
+	u32 data;
+
+	/*
+	 * We cheat by treating all PLL (except PLLU) in the same fashion.
+	 * This works only because:
+	 * - same fields are always mapped at same offsets, except DCCON
+	 * - DCCON is always 0, doesn't conflict
+	 * - M,N, P of PLLP values are ignored for PLLP
+	 */
+	data = (cpcon << PLL_CPCON_SHIFT) | (lfcon << PLL_LFCON_SHIFT);
+	writel(data, &pll->pll_misc);
+
+	data = (divm << PLL_DIVM_SHIFT) | (divn << PLL_DIVN_SHIFT) |
+			(0 << PLL_BYPASS_SHIFT) | (1 << PLL_ENABLE_SHIFT);
+
+	if (clkid == CLOCK_ID_USB)
+		data |= divp << PLLU_VCO_FREQ_SHIFT;
+	else
+		data |= divp << PLL_DIVP_SHIFT;
+	writel(data, &pll->pll_base);
+
+	/* calculate the stable time */
+	return timer_get_us() + CLOCK_PLL_STABLE_DELAY_US;
+}
+
+void clock_ll_set_source_divisor(enum periph_id periph_id, unsigned source,
+			unsigned divisor)
+{
+	u32 *reg = get_periph_source_reg(periph_id);
+	u32 value;
+
+	value = readl(reg);
+
+	value &= ~OUT_CLK_SOURCE_31_30_MASK;
+	value |= source << OUT_CLK_SOURCE_31_30_SHIFT;
+
+	value &= ~OUT_CLK_DIVISOR_MASK;
+	value |= divisor << OUT_CLK_DIVISOR_SHIFT;
+
+	writel(value, reg);
+}
+
+void clock_ll_set_source(enum periph_id periph_id, unsigned source)
+{
+	u32 *reg = get_periph_source_reg(periph_id);
+
+	clrsetbits_le32(reg, OUT_CLK_SOURCE_31_30_MASK,
+			source << OUT_CLK_SOURCE_31_30_SHIFT);
+}
+
+/**
+ * Given the parent's rate and the required rate for the children, this works
+ * out the peripheral clock divider to use, in 7.1 binary format.
+ *
+ * @param divider_bits	number of divider bits (8 or 16)
+ * @param parent_rate	clock rate of parent clock in Hz
+ * @param rate		required clock rate for this clock
+ * @return divider which should be used
+ */
+static int clk_get_divider(unsigned divider_bits, unsigned long parent_rate,
+			   unsigned long rate)
+{
+	u64 divider = parent_rate * 2;
+	unsigned max_divider = 1 << divider_bits;
+
+	divider += rate - 1;
+	do_div(divider, rate);
+
+	if ((s64)divider - 2 < 0)
+		return 0;
+
+	if ((s64)divider - 2 >= max_divider)
+		return -1;
+
+	return divider - 2;
+}
+
+int clock_set_pllout(enum clock_id clkid, enum pll_out_id pllout, unsigned rate)
+{
+	struct clk_pll *pll = get_pll(clkid);
+	int data = 0, div = 0, offset = 0;
+
+	if (!clock_id_is_pll(clkid))
+		return -1;
+
+	if (pllout + 1 > pll_num_clkouts[clkid])
+		return -1;
+
+	div = clk_get_divider(8, pll_rate[clkid], rate);
+
+	if (div < 0)
+		return -1;
+
+	/* out2 and out4 are in the high part of the register */
+	if (pllout == PLL_OUT2 || pllout == PLL_OUT4)
+		offset = 16;
+
+	data = (div << PLL_OUT_RATIO_SHIFT) |
+			PLL_OUT_OVRRIDE | PLL_OUT_CLKEN | PLL_OUT_RSTN;
+	clrsetbits_le32(&pll->pll_out[pllout >> 1],
+			PLL_OUT_RATIO_MASK << offset, data << offset);
+
+	return 0;
+}
+
+/**
+ * Given the parent's rate and the divider in 7.1 format, this works out the
+ * resulting peripheral clock rate.
+ *
+ * @param parent_rate	clock rate of parent clock in Hz
+ * @param divider which should be used in 7.1 format
+ * @return effective clock rate of peripheral
+ */
+static unsigned long get_rate_from_divider(unsigned long parent_rate,
+					   int divider)
+{
+	u64 rate;
+
+	rate = (u64)parent_rate * 2;
+	do_div(rate, divider + 2);
+	return rate;
+}
+
+unsigned long clock_get_periph_rate(enum periph_id periph_id,
+		enum clock_id parent)
+{
+	u32 *reg = get_periph_source_reg(periph_id);
+
+	return get_rate_from_divider(pll_rate[parent],
+		(readl(reg) & OUT_CLK_DIVISOR_MASK) >> OUT_CLK_DIVISOR_SHIFT);
+}
+
+/**
+ * Find the best available 7.1 format divisor given a parent clock rate and
+ * required child clock rate. This function assumes that a second-stage
+ * divisor is available which can divide by powers of 2 from 1 to 256.
+ *
+ * @param divider_bits	number of divider bits (8 or 16)
+ * @param parent_rate	clock rate of parent clock in Hz
+ * @param rate		required clock rate for this clock
+ * @param extra_div	value for the second-stage divisor (not set if this
+ *			function returns -1.
+ * @return divider which should be used, or -1 if nothing is valid
+ *
+ */
+static int find_best_divider(unsigned divider_bits, unsigned long parent_rate,
+				unsigned long rate, int *extra_div)
+{
+	int shift;
+	int best_divider = -1;
+	int best_error = rate;
+
+	/* try dividers from 1 to 256 and find closest match */
+	for (shift = 0; shift <= 8 && best_error > 0; shift++) {
+		unsigned divided_parent = parent_rate >> shift;
+		int divider = clk_get_divider(divider_bits, divided_parent,
+						rate);
+		unsigned effective_rate = get_rate_from_divider(divided_parent,
+						divider);
+		int error = rate - effective_rate;
+
+		/* Given a valid divider, look for the lowest error */
+		if (divider != -1 && error < best_error) {
+			best_error = error;
+			*extra_div = 1 << shift;
+			best_divider = divider;
+		}
+	}
+
+	/* return what we found - *extra_div will already be set */
+	return best_divider;
+}
+
+/**
+ * Adjust peripheral PLL to use the given divider and source.
+ *
+ * @param periph_id	peripheral to adjust
+ * @param source	Source number (0-3 or 0-7)
+ * @param mux_bits	Number of mux bits (2 or 4)
+ * @param divider	Required divider in 7.1 or 15.1 format
+ * @return 0 if ok, -1 on error (requesting a parent clock which is not valid
+ *		for this peripheral)
+ */
+static int adjust_periph_pll(enum periph_id periph_id, int source,
+				int mux_bits, unsigned divider)
+{
+	u32 *reg = get_periph_source_reg(periph_id);
+
+	clrsetbits_le32(reg, OUT_CLK_DIVISOR_MASK,
+			divider << OUT_CLK_DIVISOR_SHIFT);
+	udelay(1);
+
+	/* work out the source clock and set it */
+	if (source < 0)
+		return -1;
+
+	switch (mux_bits) {
+	case MASK_BITS_31_30:
+		clrsetbits_le32(reg, OUT_CLK_SOURCE_31_30_MASK,
+				source << OUT_CLK_SOURCE_31_30_SHIFT);
+		break;
+
+	case MASK_BITS_31_29:
+		clrsetbits_le32(reg, OUT_CLK_SOURCE_31_29_MASK,
+				source << OUT_CLK_SOURCE_31_29_SHIFT);
+		break;
+
+	case MASK_BITS_31_28:
+		clrsetbits_le32(reg, OUT_CLK_SOURCE_31_28_MASK,
+				source << OUT_CLK_SOURCE_31_28_SHIFT);
+		break;
+
+	default:
+		return -1;
+	}
+
+	udelay(2);
+	return 0;
+}
+
+unsigned clock_adjust_periph_pll_div(enum periph_id periph_id,
+		enum clock_id parent, unsigned rate, int *extra_div)
+{
+	unsigned effective_rate;
+	int mux_bits, divider_bits, source;
+	int divider;
+	int xdiv = 0;
+
+	/* work out the source clock and set it */
+	source = get_periph_clock_source(periph_id, parent, &mux_bits,
+					 &divider_bits);
+
+	divider = find_best_divider(divider_bits, pll_rate[parent],
+				    rate, &xdiv);
+	if (extra_div)
+		*extra_div = xdiv;
+
+	assert(divider >= 0);
+	if (adjust_periph_pll(periph_id, source, mux_bits, divider))
+		return -1U;
+	debug("periph %d, rate=%d, reg=%p = %x\n", periph_id, rate,
+		get_periph_source_reg(periph_id),
+		readl(get_periph_source_reg(periph_id)));
+
+	/* Check what we ended up with. This shouldn't matter though */
+	effective_rate = clock_get_periph_rate(periph_id, parent);
+	if (extra_div)
+		effective_rate /= *extra_div;
+	if (rate != effective_rate)
+		debug("Requested clock rate %u not honored (got %u)\n",
+			rate, effective_rate);
+	return effective_rate;
+}
+
+unsigned clock_start_periph_pll(enum periph_id periph_id,
+		enum clock_id parent, unsigned rate)
+{
+	unsigned effective_rate;
+
+	reset_set_enable(periph_id, 1);
+	clock_enable(periph_id);
+
+	effective_rate = clock_adjust_periph_pll_div(periph_id, parent, rate,
+						 NULL);
+
+	reset_set_enable(periph_id, 0);
+	return effective_rate;
+}
+
+void clock_enable(enum periph_id clkid)
+{
+	clock_set_enable(clkid, 1);
+}
+
+void clock_disable(enum periph_id clkid)
+{
+	clock_set_enable(clkid, 0);
+}
+
+void reset_periph(enum periph_id periph_id, int us_delay)
+{
+	/* Put peripheral into reset */
+	reset_set_enable(periph_id, 1);
+	udelay(us_delay);
+
+	/* Remove reset */
+	reset_set_enable(periph_id, 0);
+
+	udelay(us_delay);
+}
+
+void reset_cmplx_set_enable(int cpu, int which, int reset)
+{
+	struct clk_rst_ctlr *clkrst =
+			(struct clk_rst_ctlr *)NV_PA_CLK_RST_BASE;
+	u32 mask;
+
+	/* Form the mask, which depends on the cpu chosen (2 or 4) */
+	assert(cpu >= 0 && cpu < MAX_NUM_CPU);
+	mask = which << cpu;
+
+	/* either enable or disable those reset for that CPU */
+	if (reset)
+		writel(mask, &clkrst->crc_cpu_cmplx_set);
+	else
+		writel(mask, &clkrst->crc_cpu_cmplx_clr);
+}
+
+unsigned clock_get_rate(enum clock_id clkid)
+{
+	struct clk_pll *pll;
+	u32 base;
+	u32 divm;
+	u64 parent_rate;
+	u64 rate;
+
+	parent_rate = osc_freq[clock_get_osc_freq()];
+	if (clkid == CLOCK_ID_OSC)
+		return parent_rate;
+
+	pll = get_pll(clkid);
+	base = readl(&pll->pll_base);
+
+	/* Oh for bf_unpack()... */
+	rate = parent_rate * ((base & PLL_DIVN_MASK) >> PLL_DIVN_SHIFT);
+	divm = (base & PLL_DIVM_MASK) >> PLL_DIVM_SHIFT;
+	if (clkid == CLOCK_ID_USB)
+		divm <<= (base & PLLU_VCO_FREQ_MASK) >> PLLU_VCO_FREQ_SHIFT;
+	else
+		divm <<= (base & PLL_DIVP_MASK) >> PLL_DIVP_SHIFT;
+	do_div(rate, divm);
+	return rate;
+}
+
+/**
+ * Set the output frequency you want for each PLL clock.
+ * PLL output frequencies are programmed by setting their N, M and P values.
+ * The governing equations are:
+ *     VCO = (Fi / m) * n, Fo = VCO / (2^p)
+ *     where Fo is the output frequency from the PLL.
+ * Example: Set the output frequency to 216Mhz(Fo) with 12Mhz OSC(Fi)
+ *     216Mhz = ((12Mhz / m) * n) / (2^p) so n=432,m=12,p=1
+ * Please see Tegra TRM section 5.3 to get the detail for PLL Programming
+ *
+ * @param n PLL feedback divider(DIVN)
+ * @param m PLL input divider(DIVN)
+ * @param p post divider(DIVP)
+ * @param cpcon base PLL charge pump(CPCON)
+ * @return 0 if ok, -1 on error (the requested PLL is incorrect and cannot
+ *		be overriden), 1 if PLL is already correct
+ */
+int clock_set_rate(enum clock_id clkid, u32 n, u32 m, u32 p, u32 cpcon)
+{
+	u32 base_reg;
+	u32 misc_reg;
+	struct clk_pll *pll;
+
+	pll = get_pll(clkid);
+
+	base_reg = readl(&pll->pll_base);
+
+	/* Set BYPASS, m, n and p to PLL_BASE */
+	base_reg &= ~PLL_DIVM_MASK;
+	base_reg |= m << PLL_DIVM_SHIFT;
+
+	base_reg &= ~PLL_DIVN_MASK;
+	base_reg |= n << PLL_DIVN_SHIFT;
+
+	base_reg &= ~PLL_DIVP_MASK;
+	base_reg |= p << PLL_DIVP_SHIFT;
+
+	if (clkid == CLOCK_ID_PERIPH) {
+		/*
+		 * If the PLL is already set up, check that it is correct
+		 * and record this info for clock_verify() to check.
+		 */
+		if (base_reg & PLL_BASE_OVRRIDE_MASK) {
+			base_reg |= PLL_ENABLE_MASK;
+			if (base_reg != readl(&pll->pll_base))
+				pllp_valid = 0;
+			return pllp_valid ? 1 : -1;
+		}
+		base_reg |= PLL_BASE_OVRRIDE_MASK;
+	}
+
+	base_reg |= PLL_BYPASS_MASK;
+	writel(base_reg, &pll->pll_base);
+
+	/* Set cpcon to PLL_MISC */
+	misc_reg = readl(&pll->pll_misc);
+	misc_reg &= ~PLL_CPCON_MASK;
+	misc_reg |= cpcon << PLL_CPCON_SHIFT;
+	writel(misc_reg, &pll->pll_misc);
+
+	/* Enable PLL */
+	base_reg |= PLL_ENABLE_MASK;
+	writel(base_reg, &pll->pll_base);
+
+	/* Disable BYPASS */
+	base_reg &= ~PLL_BYPASS_MASK;
+	writel(base_reg, &pll->pll_base);
+
+	return 0;
+}
+
+void clock_ll_start_uart(enum periph_id periph_id)
+{
+	/* Assert UART reset and enable clock */
+	reset_set_enable(periph_id, 1);
+	clock_enable(periph_id);
+	clock_ll_set_source(periph_id, 0); /* UARTx_CLK_SRC = 00, PLLP_OUT0 */
+
+	/* wait for 2us */
+	udelay(2);
+
+	/* De-assert reset to UART */
+	reset_set_enable(periph_id, 0);
+}
+
+#ifdef CONFIG_OF_CONTROL
+int clock_decode_periph_id(const void *blob, int node)
+{
+	enum periph_id id;
+	u32 cell[2];
+	int err;
+
+	err = fdtdec_get_int_array(blob, node, "clocks", cell,
+				   ARRAY_SIZE(cell));
+	if (err)
+		return -1;
+	id = clk_id_to_periph_id(cell[1]);
+	assert(clock_periph_id_isvalid(id));
+	return id;
+}
+#endif /* CONFIG_OF_CONTROL */
+
+int clock_verify(void)
+{
+	struct clk_pll *pll = get_pll(CLOCK_ID_PERIPH);
+	u32 reg = readl(&pll->pll_base);
+
+	if (!pllp_valid) {
+		printf("Warning: PLLP %x is not correct\n", reg);
+		return -1;
+	}
+	debug("PLLP %x is correct\n", reg);
+	return 0;
+}
+
+void clock_init(void)
+{
+	pll_rate[CLOCK_ID_MEMORY] = clock_get_rate(CLOCK_ID_MEMORY);
+	pll_rate[CLOCK_ID_PERIPH] = clock_get_rate(CLOCK_ID_PERIPH);
+	pll_rate[CLOCK_ID_CGENERAL] = clock_get_rate(CLOCK_ID_CGENERAL);
+	pll_rate[CLOCK_ID_OSC] = clock_get_rate(CLOCK_ID_OSC);
+	pll_rate[CLOCK_ID_SFROM32KHZ] = 32768;
+	pll_rate[CLOCK_ID_XCPU] = clock_get_rate(CLOCK_ID_XCPU);
+	debug("Osc = %d\n", pll_rate[CLOCK_ID_OSC]);
+	debug("PLLM = %d\n", pll_rate[CLOCK_ID_MEMORY]);
+	debug("PLLP = %d\n", pll_rate[CLOCK_ID_PERIPH]);
+	debug("PLLC = %d\n", pll_rate[CLOCK_ID_CGENERAL]);
+	debug("PLLX = %d\n", pll_rate[CLOCK_ID_XCPU]);
+
+	/* Do any special system timer/TSC setup */
+	arch_timer_init();
+}
+
+static void set_avp_clock_source(u32 src)
+{
+	struct clk_rst_ctlr *clkrst =
+			(struct clk_rst_ctlr *)NV_PA_CLK_RST_BASE;
+	u32 val;
+
+	val = (src << SCLK_SWAKEUP_FIQ_SOURCE_SHIFT) |
+		(src << SCLK_SWAKEUP_IRQ_SOURCE_SHIFT) |
+		(src << SCLK_SWAKEUP_RUN_SOURCE_SHIFT) |
+		(src << SCLK_SWAKEUP_IDLE_SOURCE_SHIFT) |
+		(SCLK_SYS_STATE_RUN << SCLK_SYS_STATE_SHIFT);
+	writel(val, &clkrst->crc_sclk_brst_pol);
+	udelay(3);
+}
+
+/*
+ * This function is useful on Tegra30, and any later SoCs that have compatible
+ * PLLP configuration registers.
+ */
+void tegra30_set_up_pllp(void)
+{
+	struct clk_rst_ctlr *clkrst = (struct clk_rst_ctlr *)NV_PA_CLK_RST_BASE;
+	u32 reg;
+
+	/*
+	 * Based on the Tegra TRM, the system clock (which is the AVP clock) can
+	 * run up to 275MHz. On power on, the default sytem clock source is set
+	 * to PLLP_OUT0. This function sets PLLP's (hence PLLP_OUT0's) rate to
+	 * 408MHz which is beyond system clock's upper limit.
+	 *
+	 * The fix is to set the system clock to CLK_M before initializing PLLP,
+	 * and then switch back to PLLP_OUT4, which has an appropriate divider
+	 * configured, after PLLP has been configured
+	 */
+	set_avp_clock_source(SCLK_SOURCE_CLKM);
+
+	/*
+	 * PLLP output frequency set to 408Mhz
+	 * PLLC output frequency set to 228Mhz
+	 */
+	switch (clock_get_osc_freq()) {
+	case CLOCK_OSC_FREQ_12_0: /* OSC is 12Mhz */
+		clock_set_rate(CLOCK_ID_PERIPH, 408, 12, 0, 8);
+		clock_set_rate(CLOCK_ID_CGENERAL, 456, 12, 1, 8);
+		break;
+
+	case CLOCK_OSC_FREQ_26_0: /* OSC is 26Mhz */
+		clock_set_rate(CLOCK_ID_PERIPH, 408, 26, 0, 8);
+		clock_set_rate(CLOCK_ID_CGENERAL, 600, 26, 0, 8);
+		break;
+
+	case CLOCK_OSC_FREQ_13_0: /* OSC is 13Mhz */
+		clock_set_rate(CLOCK_ID_PERIPH, 408, 13, 0, 8);
+		clock_set_rate(CLOCK_ID_CGENERAL, 600, 13, 0, 8);
+		break;
+	case CLOCK_OSC_FREQ_19_2:
+	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;
+	}
+
+	/* Set PLLP_OUT1, 2, 3 & 4 freqs to 9.6, 48, 102 & 204MHz */
+
+	/* OUT1, 2 */
+	/* Assert RSTN before enable */
+	reg = PLLP_OUT2_RSTN_EN | PLLP_OUT1_RSTN_EN;
+	writel(reg, &clkrst->crc_pll[CLOCK_ID_PERIPH].pll_out[0]);
+	/* Set divisor and reenable */
+	reg = (IN_408_OUT_48_DIVISOR << PLLP_OUT2_RATIO)
+		| PLLP_OUT2_OVR | PLLP_OUT2_CLKEN | PLLP_OUT2_RSTN_DIS
+		| (IN_408_OUT_9_6_DIVISOR << PLLP_OUT1_RATIO)
+		| PLLP_OUT1_OVR | PLLP_OUT1_CLKEN | PLLP_OUT1_RSTN_DIS;
+	writel(reg, &clkrst->crc_pll[CLOCK_ID_PERIPH].pll_out[0]);
+
+	/* OUT3, 4 */
+	/* Assert RSTN before enable */
+	reg = PLLP_OUT4_RSTN_EN | PLLP_OUT3_RSTN_EN;
+	writel(reg, &clkrst->crc_pll[CLOCK_ID_PERIPH].pll_out[1]);
+	/* Set divisor and reenable */
+	reg = (IN_408_OUT_204_DIVISOR << PLLP_OUT4_RATIO)
+		| PLLP_OUT4_OVR | PLLP_OUT4_CLKEN | PLLP_OUT4_RSTN_DIS
+		| (IN_408_OUT_102_DIVISOR << PLLP_OUT3_RATIO)
+		| PLLP_OUT3_OVR | PLLP_OUT3_CLKEN | PLLP_OUT3_RSTN_DIS;
+	writel(reg, &clkrst->crc_pll[CLOCK_ID_PERIPH].pll_out[1]);
+
+	set_avp_clock_source(SCLK_SOURCE_PLLP_OUT4);
+}
diff --git a/arch/arm/mach-tegra/cmd_enterrcm.c b/arch/arm/mach-tegra/cmd_enterrcm.c
new file mode 100644
index 0000000..a94ec93
--- /dev/null
+++ b/arch/arm/mach-tegra/cmd_enterrcm.c
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2012, NVIDIA CORPORATION.  All rights reserved.
+ *
+ * Derived from code (arch/arm/lib/reset.c) that is:
+ *
+ * (C) Copyright 2002
+ * Sysgo Real-Time Solutions, GmbH <www.elinos.com>
+ * Marius Groeger <mgroeger@sysgo.de>
+ *
+ * (C) Copyright 2002
+ * Sysgo Real-Time Solutions, GmbH <www.elinos.com>
+ * Alex Zuepke <azu@sysgo.de>
+ *
+ * (C) Copyright 2002
+ * Gary Jennejohn, DENX Software Engineering, <garyj@denx.de>
+ *
+ * (C) Copyright 2004
+ * DAVE Srl
+ * http://www.dave-tech.it
+ * http://www.wawnet.biz
+ * mailto:info@wawnet.biz
+ *
+ * (C) Copyright 2004 Texas Insturments
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <asm/arch/tegra.h>
+#include <asm/arch-tegra/pmc.h>
+
+static int do_enterrcm(cmd_tbl_t *cmdtp, int flag, int argc,
+		       char * const argv[])
+{
+	struct pmc_ctlr *pmc = (struct pmc_ctlr *)NV_PA_PMC_BASE;
+
+	puts("Entering RCM...\n");
+	udelay(50000);
+
+	pmc->pmc_scratch0 = 2;
+	disable_interrupts();
+	reset_cpu(0);
+
+	return 0;
+}
+
+U_BOOT_CMD(
+	enterrcm, 1, 0, do_enterrcm,
+	"reset Tegra and enter USB Recovery Mode",
+	""
+);
diff --git a/arch/arm/mach-tegra/cpu.c b/arch/arm/mach-tegra/cpu.c
new file mode 100644
index 0000000..c6f3b02
--- /dev/null
+++ b/arch/arm/mach-tegra/cpu.c
@@ -0,0 +1,384 @@
+/*
+ * Copyright (c) 2010-2014, NVIDIA CORPORATION.  All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <asm/arch/clock.h>
+#include <asm/arch/gp_padctrl.h>
+#include <asm/arch/pinmux.h>
+#include <asm/arch/tegra.h>
+#include <asm/arch-tegra/clk_rst.h>
+#include <asm/arch-tegra/pmc.h>
+#include <asm/arch-tegra/scu.h>
+#include "cpu.h"
+
+int get_num_cpus(void)
+{
+	struct apb_misc_gp_ctlr *gp;
+	uint rev;
+
+	gp = (struct apb_misc_gp_ctlr *)NV_PA_APB_MISC_GP_BASE;
+	rev = (readl(&gp->hidrev) & HIDREV_CHIPID_MASK) >> HIDREV_CHIPID_SHIFT;
+
+	switch (rev) {
+	case CHIPID_TEGRA20:
+		return 2;
+		break;
+	case CHIPID_TEGRA30:
+	case CHIPID_TEGRA114:
+	default:
+		return 4;
+		break;
+	}
+}
+
+/*
+ * Timing tables for each SOC for all four oscillator options.
+ */
+struct clk_pll_table tegra_pll_x_table[TEGRA_SOC_CNT][CLOCK_OSC_FREQ_COUNT] = {
+	/*
+	 * T20: 1 GHz
+	 *
+	 * Register   Field  Bits   Width
+	 * ------------------------------
+	 * PLLX_BASE  p      22:20    3
+	 * PLLX_BASE  n      17: 8   10
+	 * PLLX_BASE  m       4: 0    5
+	 * PLLX_MISC  cpcon  11: 8    4
+	 */
+	{
+		{ .n = 1000, .m = 13, .p = 0, .cpcon = 12 }, /* OSC: 13.0 MHz */
+		{ .n =  625, .m = 12, .p = 0, .cpcon =  8 }, /* OSC: 19.2 MHz */
+		{ .n = 1000, .m = 12, .p = 0, .cpcon = 12 }, /* OSC: 12.0 MHz */
+		{ .n = 1000, .m = 26, .p = 0, .cpcon = 12 }, /* OSC: 26.0 MHz */
+	},
+	/*
+	 * T25: 1.2 GHz
+	 *
+	 * Register   Field  Bits   Width
+	 * ------------------------------
+	 * PLLX_BASE  p      22:20    3
+	 * PLLX_BASE  n      17: 8   10
+	 * PLLX_BASE  m       4: 0    5
+	 * PLLX_MISC  cpcon  11: 8    4
+	 */
+	{
+		{ .n = 923, .m = 10, .p = 0, .cpcon = 12 }, /* OSC: 13.0 MHz */
+		{ .n = 750, .m = 12, .p = 0, .cpcon =  8 }, /* OSC: 19.2 MHz */
+		{ .n = 600, .m =  6, .p = 0, .cpcon = 12 }, /* OSC: 12.0 MHz */
+		{ .n = 600, .m = 13, .p = 0, .cpcon = 12 }, /* OSC: 26.0 MHz */
+	},
+	/*
+	 * T30: 600 MHz
+	 *
+	 * Register   Field  Bits   Width
+	 * ------------------------------
+	 * PLLX_BASE  p      22:20    3
+	 * PLLX_BASE  n      17: 8   10
+	 * PLLX_BASE  m       4: 0    5
+	 * PLLX_MISC  cpcon  11: 8    4
+	 */
+	{
+		{ .n = 600, .m = 13, .p = 0, .cpcon = 8 }, /* OSC: 13.0 MHz */
+		{ .n = 500, .m = 16, .p = 0, .cpcon = 8 }, /* OSC: 19.2 MHz */
+		{ .n = 600, .m = 12, .p = 0, .cpcon = 8 }, /* OSC: 12.0 MHz */
+		{ .n = 600, .m = 26, .p = 0, .cpcon = 8 }, /* OSC: 26.0 MHz */
+	},
+	/*
+	 * T114: 700 MHz
+	 *
+	 * Register   Field  Bits   Width
+	 * ------------------------------
+	 * PLLX_BASE  p      23:20    4
+	 * PLLX_BASE  n      15: 8    8
+	 * PLLX_BASE  m       7: 0    8
+	 */
+	{
+		{ .n = 108, .m = 1, .p = 1 }, /* OSC: 13.0 MHz */
+		{ .n =  73, .m = 1, .p = 1 }, /* OSC: 19.2 MHz */
+		{ .n = 116, .m = 1, .p = 1 }, /* OSC: 12.0 MHz */
+		{ .n = 108, .m = 2, .p = 1 }, /* OSC: 26.0 MHz */
+	},
+
+	/*
+	 * T124: 700 MHz
+	 *
+	 * Register   Field  Bits   Width
+	 * ------------------------------
+	 * PLLX_BASE  p      23:20    4
+	 * PLLX_BASE  n      15: 8    8
+	 * PLLX_BASE  m       7: 0    8
+	 */
+	{
+		{ .n = 108, .m = 1, .p = 1 }, /* OSC: 13.0 MHz */
+		{ .n =  73, .m = 1, .p = 1 }, /* OSC: 19.2 MHz */
+		{ .n = 116, .m = 1, .p = 1 }, /* OSC: 12.0 MHz */
+		{ .n = 108, .m = 2, .p = 1 }, /* OSC: 26.0 MHz */
+	},
+};
+
+static inline void pllx_set_iddq(void)
+{
+#if defined(CONFIG_TEGRA124)
+	struct clk_rst_ctlr *clkrst = (struct clk_rst_ctlr *)NV_PA_CLK_RST_BASE;
+	u32 reg;
+
+	/* Disable IDDQ */
+	reg = readl(&clkrst->crc_pllx_misc3);
+	reg &= ~PLLX_IDDQ_MASK;
+	writel(reg, &clkrst->crc_pllx_misc3);
+	udelay(2);
+	debug("%s: IDDQ: PLLX IDDQ = 0x%08X\n", __func__,
+	      readl(&clkrst->crc_pllx_misc3));
+#endif
+}
+
+int pllx_set_rate(struct clk_pll_simple *pll , u32 divn, u32 divm,
+		u32 divp, u32 cpcon)
+{
+	int chip = tegra_get_chip();
+	u32 reg;
+
+	/* If PLLX is already enabled, just return */
+	if (readl(&pll->pll_base) & PLL_ENABLE_MASK) {
+		debug("pllx_set_rate: PLLX already enabled, returning\n");
+		return 0;
+	}
+
+	debug(" pllx_set_rate entry\n");
+
+	pllx_set_iddq();
+
+	/* Set BYPASS, m, n and p to PLLX_BASE */
+	reg = PLL_BYPASS_MASK | (divm << PLL_DIVM_SHIFT);
+	reg |= ((divn << PLL_DIVN_SHIFT) | (divp << PLL_DIVP_SHIFT));
+	writel(reg, &pll->pll_base);
+
+	/* Set cpcon to PLLX_MISC */
+	if (chip == CHIPID_TEGRA20 || chip == CHIPID_TEGRA30)
+		reg = (cpcon << PLL_CPCON_SHIFT);
+	else
+		reg = 0;
+
+	/* Set dccon to PLLX_MISC if freq > 600MHz */
+	if (divn > 600)
+		reg |= (1 << PLL_DCCON_SHIFT);
+	writel(reg, &pll->pll_misc);
+
+	/* Disable BYPASS */
+	reg = readl(&pll->pll_base);
+	reg &= ~PLL_BYPASS_MASK;
+	writel(reg, &pll->pll_base);
+	debug("pllx_set_rate: base = 0x%08X\n", reg);
+
+	/* Set lock_enable to PLLX_MISC */
+	reg = readl(&pll->pll_misc);
+	reg |= PLL_LOCK_ENABLE_MASK;
+	writel(reg, &pll->pll_misc);
+	debug("pllx_set_rate: misc = 0x%08X\n", reg);
+
+	/* Enable PLLX last, once it's all configured */
+	reg = readl(&pll->pll_base);
+	reg |= PLL_ENABLE_MASK;
+	writel(reg, &pll->pll_base);
+	debug("pllx_set_rate: base final = 0x%08X\n", reg);
+
+	return 0;
+}
+
+void init_pllx(void)
+{
+	struct clk_rst_ctlr *clkrst = (struct clk_rst_ctlr *)NV_PA_CLK_RST_BASE;
+	struct clk_pll_simple *pll = &clkrst->crc_pll_simple[SIMPLE_PLLX];
+	int soc_type, sku_info, chip_sku;
+	enum clock_osc_freq osc;
+	struct clk_pll_table *sel;
+
+	debug("init_pllx entry\n");
+
+	/* get SOC (chip) type */
+	soc_type = tegra_get_chip();
+	debug(" init_pllx: SoC = 0x%02X\n", soc_type);
+
+	/* get SKU info */
+	sku_info = tegra_get_sku_info();
+	debug(" init_pllx: SKU info byte = 0x%02X\n", sku_info);
+
+	/* get chip SKU, combo of the above info */
+	chip_sku = tegra_get_chip_sku();
+	debug(" init_pllx: Chip SKU = %d\n", chip_sku);
+
+	/* get osc freq */
+	osc = clock_get_osc_freq();
+	debug(" init_pllx: osc = %d\n", osc);
+
+	/* set pllx */
+	sel = &tegra_pll_x_table[chip_sku][osc];
+	pllx_set_rate(pll, sel->n, sel->m, sel->p, sel->cpcon);
+}
+
+void enable_cpu_clock(int enable)
+{
+	struct clk_rst_ctlr *clkrst = (struct clk_rst_ctlr *)NV_PA_CLK_RST_BASE;
+	u32 clk;
+
+	/*
+	 * NOTE:
+	 * Regardless of whether the request is to enable or disable the CPU
+	 * clock, every processor in the CPU complex except the master (CPU 0)
+	 * will have it's clock stopped because the AVP only talks to the
+	 * master.
+	 */
+
+	if (enable) {
+		/* Initialize PLLX */
+		init_pllx();
+
+		/* Wait until all clocks are stable */
+		udelay(PLL_STABILIZATION_DELAY);
+
+		writel(CCLK_BURST_POLICY, &clkrst->crc_cclk_brst_pol);
+		writel(SUPER_CCLK_DIVIDER, &clkrst->crc_super_cclk_div);
+	}
+
+	/*
+	 * Read the register containing the individual CPU clock enables and
+	 * always stop the clocks to CPUs > 0.
+	 */
+	clk = readl(&clkrst->crc_clk_cpu_cmplx);
+	clk |= 1 << CPU1_CLK_STP_SHIFT;
+	if (get_num_cpus() == 4)
+		clk |= (1 << CPU2_CLK_STP_SHIFT) + (1 << CPU3_CLK_STP_SHIFT);
+
+	/* Stop/Unstop the CPU clock */
+	clk &= ~CPU0_CLK_STP_MASK;
+	clk |= !enable << CPU0_CLK_STP_SHIFT;
+	writel(clk, &clkrst->crc_clk_cpu_cmplx);
+
+	clock_enable(PERIPH_ID_CPU);
+}
+
+static int is_cpu_powered(void)
+{
+	struct pmc_ctlr *pmc = (struct pmc_ctlr *)NV_PA_PMC_BASE;
+
+	return (readl(&pmc->pmc_pwrgate_status) & CPU_PWRED) ? 1 : 0;
+}
+
+static void remove_cpu_io_clamps(void)
+{
+	struct pmc_ctlr *pmc = (struct pmc_ctlr *)NV_PA_PMC_BASE;
+	u32 reg;
+
+	/* Remove the clamps on the CPU I/O signals */
+	reg = readl(&pmc->pmc_remove_clamping);
+	reg |= CPU_CLMP;
+	writel(reg, &pmc->pmc_remove_clamping);
+
+	/* Give I/O signals time to stabilize */
+	udelay(IO_STABILIZATION_DELAY);
+}
+
+void powerup_cpu(void)
+{
+	struct pmc_ctlr *pmc = (struct pmc_ctlr *)NV_PA_PMC_BASE;
+	u32 reg;
+	int timeout = IO_STABILIZATION_DELAY;
+
+	if (!is_cpu_powered()) {
+		/* Toggle the CPU power state (OFF -> ON) */
+		reg = readl(&pmc->pmc_pwrgate_toggle);
+		reg &= PARTID_CP;
+		reg |= START_CP;
+		writel(reg, &pmc->pmc_pwrgate_toggle);
+
+		/* Wait for the power to come up */
+		while (!is_cpu_powered()) {
+			if (timeout-- == 0)
+				printf("CPU failed to power up!\n");
+			else
+				udelay(10);
+		}
+
+		/*
+		 * Remove the I/O clamps from CPU power partition.
+		 * Recommended only on a Warm boot, if the CPU partition gets
+		 * power gated. Shouldn't cause any harm when called after a
+		 * cold boot according to HW, probably just redundant.
+		 */
+		remove_cpu_io_clamps();
+	}
+}
+
+void reset_A9_cpu(int reset)
+{
+	/*
+	* NOTE:  Regardless of whether the request is to hold the CPU in reset
+	*        or take it out of reset, every processor in the CPU complex
+	*        except the master (CPU 0) will be held in reset because the
+	*        AVP only talks to the master. The AVP does not know that there
+	*        are multiple processors in the CPU complex.
+	*/
+	int mask = crc_rst_cpu | crc_rst_de | crc_rst_debug;
+	int num_cpus = get_num_cpus();
+	int cpu;
+
+	debug("reset_a9_cpu entry\n");
+	/* Hold CPUs 1 onwards in reset, and CPU 0 if asked */
+	for (cpu = 1; cpu < num_cpus; cpu++)
+		reset_cmplx_set_enable(cpu, mask, 1);
+	reset_cmplx_set_enable(0, mask, reset);
+
+	/* Enable/Disable master CPU reset */
+	reset_set_enable(PERIPH_ID_CPU, reset);
+}
+
+void clock_enable_coresight(int enable)
+{
+	u32 rst, src = 2;
+
+	debug("clock_enable_coresight entry\n");
+	clock_set_enable(PERIPH_ID_CORESIGHT, enable);
+	reset_set_enable(PERIPH_ID_CORESIGHT, !enable);
+
+	if (enable) {
+		/*
+		 * Put CoreSight on PLLP_OUT0 and divide it down as per
+		 * PLLP base frequency based on SoC type (T20/T30+).
+		 * Clock divider request would setup CSITE clock as 144MHz
+		 * for PLLP base 216MHz and 204MHz for PLLP base 408MHz
+		 */
+		src = CLK_DIVIDER(NVBL_PLLP_KHZ, CSITE_KHZ);
+		clock_ll_set_source_divisor(PERIPH_ID_CSI, 0, src);
+
+		/* Unlock the CPU CoreSight interfaces */
+		rst = CORESIGHT_UNLOCK;
+		writel(rst, CSITE_CPU_DBG0_LAR);
+		writel(rst, CSITE_CPU_DBG1_LAR);
+		if (get_num_cpus() == 4) {
+			writel(rst, CSITE_CPU_DBG2_LAR);
+			writel(rst, CSITE_CPU_DBG3_LAR);
+		}
+	}
+}
+
+void halt_avp(void)
+{
+	for (;;) {
+		writel(HALT_COP_EVENT_JTAG | (FLOW_MODE_STOP << 29),
+		       FLOW_CTLR_HALT_COP_EVENTS);
+	}
+}
diff --git a/arch/arm/mach-tegra/cpu.h b/arch/arm/mach-tegra/cpu.h
new file mode 100644
index 0000000..b4ca44f
--- /dev/null
+++ b/arch/arm/mach-tegra/cpu.h
@@ -0,0 +1,74 @@
+/*
+ * (C) Copyright 2010-2014
+ * NVIDIA Corporation <www.nvidia.com>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+#include <asm/types.h>
+
+/* Stabilization delays, in usec */
+#define PLL_STABILIZATION_DELAY (300)
+#define IO_STABILIZATION_DELAY	(1000)
+
+#if defined(CONFIG_TEGRA20)
+#define NVBL_PLLP_KHZ	216000
+#define CSITE_KHZ	144000
+#elif defined(CONFIG_TEGRA30) || defined(CONFIG_TEGRA114) || \
+	defined(CONFIG_TEGRA124)
+#define NVBL_PLLP_KHZ	408000
+#define CSITE_KHZ	204000
+#else
+#error "Unknown Tegra chip!"
+#endif
+
+#define PLLX_ENABLED		(1 << 30)
+#define CCLK_BURST_POLICY	0x20008888
+#define SUPER_CCLK_DIVIDER	0x80000000
+
+/* Calculate clock fractional divider value from ref and target frequencies */
+#define CLK_DIVIDER(REF, FREQ)  ((((REF) * 2) / FREQ) - 2)
+
+/* Calculate clock frequency value from reference and clock divider value */
+#define CLK_FREQUENCY(REF, REG)  (((REF) * 2) / (REG + 2))
+
+/* AVP/CPU ID */
+#define PG_UP_TAG_0_PID_CPU	0x55555555	/* CPU aka "a9" aka "mpcore" */
+#define PG_UP_TAG_0             0x0
+
+#define CORESIGHT_UNLOCK	0xC5ACCE55;
+
+#define EXCEP_VECTOR_CPU_RESET_VECTOR	(NV_PA_EVP_BASE + 0x100)
+#define CSITE_CPU_DBG0_LAR		(NV_PA_CSITE_BASE + 0x10FB0)
+#define CSITE_CPU_DBG1_LAR		(NV_PA_CSITE_BASE + 0x12FB0)
+#define CSITE_CPU_DBG2_LAR		(NV_PA_CSITE_BASE + 0x14FB0)
+#define CSITE_CPU_DBG3_LAR		(NV_PA_CSITE_BASE + 0x16FB0)
+
+#define FLOW_CTLR_HALT_COP_EVENTS	(NV_PA_FLOW_BASE + 4)
+#define FLOW_MODE_STOP			2
+#define HALT_COP_EVENT_JTAG		(1 << 28)
+#define HALT_COP_EVENT_IRQ_1		(1 << 11)
+#define HALT_COP_EVENT_FIQ_1		(1 << 9)
+
+#define FLOW_MODE_NONE		0
+
+#define SIMPLE_PLLX     (CLOCK_ID_XCPU - CLOCK_ID_FIRST_SIMPLE)
+
+struct clk_pll_table {
+	u16	n;
+	u16	m;
+	u8	p;
+	u8	cpcon;
+};
+
+void clock_enable_coresight(int enable);
+void enable_cpu_clock(int enable);
+void halt_avp(void)  __attribute__ ((noreturn));
+void init_pllx(void);
+void powerup_cpu(void);
+void reset_A9_cpu(int reset);
+void start_cpu(u32 reset_vector);
+int tegra_get_chip(void);
+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/lowlevel_init.S b/arch/arm/mach-tegra/lowlevel_init.S
new file mode 100644
index 0000000..a211bb3
--- /dev/null
+++ b/arch/arm/mach-tegra/lowlevel_init.S
@@ -0,0 +1,26 @@
+/*
+ * SoC-specific setup info
+ *
+ * (C) Copyright 2010,2011
+ * NVIDIA Corporation <www.nvidia.com>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <config.h>
+#include <version.h>
+#include <linux/linkage.h>
+
+	.align	5
+ENTRY(reset_cpu)
+	ldr	r1, rstctl			@ get addr for global reset
+						@ reg
+	ldr	r3, [r1]
+	orr	r3, r3, #0x10
+	str	r3, [r1]			@ force reset
+	mov	r0, r0
+_loop_forever:
+	b	_loop_forever
+rstctl:
+	.word	PRM_RSTCTRL
+ENDPROC(reset_cpu)
diff --git a/arch/arm/mach-tegra/pinmux-common.c b/arch/arm/mach-tegra/pinmux-common.c
new file mode 100644
index 0000000..6e3ab0c
--- /dev/null
+++ b/arch/arm/mach-tegra/pinmux-common.c
@@ -0,0 +1,527 @@
+/*
+ * Copyright (c) 2010-2013, NVIDIA CORPORATION. All rights reserved.
+ * Copyright (c) 2011 The Chromium OS Authors.
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <asm/arch/pinmux.h>
+
+/* return 1 if a pingrp is in range */
+#define pmux_pingrp_isvalid(pin) (((pin) >= 0) && ((pin) < PMUX_PINGRP_COUNT))
+
+/* return 1 if a pmux_func is in range */
+#define pmux_func_isvalid(func) \
+	(((func) >= 0) && ((func) < PMUX_FUNC_COUNT))
+
+/* return 1 if a pin_pupd_is in range */
+#define pmux_pin_pupd_isvalid(pupd) \
+	(((pupd) >= PMUX_PULL_NORMAL) && ((pupd) <= PMUX_PULL_UP))
+
+/* return 1 if a pin_tristate_is in range */
+#define pmux_pin_tristate_isvalid(tristate) \
+	(((tristate) >= PMUX_TRI_NORMAL) && ((tristate) <= PMUX_TRI_TRISTATE))
+
+#ifdef TEGRA_PMX_HAS_PIN_IO_BIT_ETC
+/* return 1 if a pin_io_is in range */
+#define pmux_pin_io_isvalid(io) \
+	(((io) >= PMUX_PIN_OUTPUT) && ((io) <= PMUX_PIN_INPUT))
+
+/* return 1 if a pin_lock is in range */
+#define pmux_pin_lock_isvalid(lock) \
+	(((lock) >= PMUX_PIN_LOCK_DISABLE) && ((lock) <= PMUX_PIN_LOCK_ENABLE))
+
+/* return 1 if a pin_od is in range */
+#define pmux_pin_od_isvalid(od) \
+	(((od) >= PMUX_PIN_OD_DISABLE) && ((od) <= PMUX_PIN_OD_ENABLE))
+
+/* return 1 if a pin_ioreset_is in range */
+#define pmux_pin_ioreset_isvalid(ioreset) \
+	(((ioreset) >= PMUX_PIN_IO_RESET_DISABLE) && \
+	 ((ioreset) <= PMUX_PIN_IO_RESET_ENABLE))
+
+#ifdef TEGRA_PMX_HAS_RCV_SEL
+/* return 1 if a pin_rcv_sel_is in range */
+#define pmux_pin_rcv_sel_isvalid(rcv_sel) \
+	(((rcv_sel) >= PMUX_PIN_RCV_SEL_NORMAL) && \
+	 ((rcv_sel) <= PMUX_PIN_RCV_SEL_HIGH))
+#endif /* TEGRA_PMX_HAS_RCV_SEL */
+#endif /* TEGRA_PMX_HAS_PIN_IO_BIT_ETC */
+
+#define _R(offset)	(u32 *)(NV_PA_APB_MISC_BASE + (offset))
+
+#if defined(CONFIG_TEGRA20)
+
+#define MUX_REG(grp)	_R(0x80 + ((tegra_soc_pingroups[grp].ctl_id / 16) * 4))
+#define MUX_SHIFT(grp)	((tegra_soc_pingroups[grp].ctl_id % 16) * 2)
+
+#define PULL_REG(grp)	_R(0xa0 + ((tegra_soc_pingroups[grp].pull_id / 16) * 4))
+#define PULL_SHIFT(grp)	((tegra_soc_pingroups[grp].pull_id % 16) * 2)
+
+#define TRI_REG(grp)	_R(0x14 + (((grp) / 32) * 4))
+#define TRI_SHIFT(grp)	((grp) % 32)
+
+#else
+
+#define REG(pin)	_R(0x3000 + ((pin) * 4))
+
+#define MUX_REG(pin)	REG(pin)
+#define MUX_SHIFT(pin)	0
+
+#define PULL_REG(pin)	REG(pin)
+#define PULL_SHIFT(pin)	2
+
+#define TRI_REG(pin)	REG(pin)
+#define TRI_SHIFT(pin)	4
+
+#endif /* CONFIG_TEGRA20 */
+
+#define DRV_REG(group)	_R(0x868 + ((group) * 4))
+
+#define IO_SHIFT	5
+#define OD_SHIFT	6
+#define LOCK_SHIFT	7
+#define IO_RESET_SHIFT	8
+#define RCV_SEL_SHIFT	9
+
+#if !defined(CONFIG_TEGRA20) && !defined(CONFIG_TEGRA30)
+/* This register/field only exists on Tegra114 and later */
+#define APB_MISC_PP_PINMUX_GLOBAL_0 0x40
+#define CLAMP_INPUTS_WHEN_TRISTATED 1
+
+void pinmux_set_tristate_input_clamping(void)
+{
+	u32 *reg = _R(APB_MISC_PP_PINMUX_GLOBAL_0);
+	u32 val;
+
+	val = readl(reg);
+	val |= CLAMP_INPUTS_WHEN_TRISTATED;
+	writel(val, reg);
+}
+#endif
+
+void pinmux_set_func(enum pmux_pingrp pin, enum pmux_func func)
+{
+	u32 *reg = MUX_REG(pin);
+	int i, mux = -1;
+	u32 val;
+
+	if (func == PMUX_FUNC_DEFAULT)
+		return;
+
+	/* Error check on pin and func */
+	assert(pmux_pingrp_isvalid(pin));
+	assert(pmux_func_isvalid(func));
+
+	if (func >= PMUX_FUNC_RSVD1) {
+		mux = (func - PMUX_FUNC_RSVD1) & 3;
+	} else {
+		/* Search for the appropriate function */
+		for (i = 0; i < 4; i++) {
+			if (tegra_soc_pingroups[pin].funcs[i] == func) {
+				mux = i;
+				break;
+			}
+		}
+	}
+	assert(mux != -1);
+
+	val = readl(reg);
+	val &= ~(3 << MUX_SHIFT(pin));
+	val |= (mux << MUX_SHIFT(pin));
+	writel(val, reg);
+}
+
+void pinmux_set_pullupdown(enum pmux_pingrp pin, enum pmux_pull pupd)
+{
+	u32 *reg = PULL_REG(pin);
+	u32 val;
+
+	/* Error check on pin and pupd */
+	assert(pmux_pingrp_isvalid(pin));
+	assert(pmux_pin_pupd_isvalid(pupd));
+
+	val = readl(reg);
+	val &= ~(3 << PULL_SHIFT(pin));
+	val |= (pupd << PULL_SHIFT(pin));
+	writel(val, reg);
+}
+
+static void pinmux_set_tristate(enum pmux_pingrp pin, int tri)
+{
+	u32 *reg = TRI_REG(pin);
+	u32 val;
+
+	/* Error check on pin */
+	assert(pmux_pingrp_isvalid(pin));
+	assert(pmux_pin_tristate_isvalid(tri));
+
+	val = readl(reg);
+	if (tri == PMUX_TRI_TRISTATE)
+		val |= (1 << TRI_SHIFT(pin));
+	else
+		val &= ~(1 << TRI_SHIFT(pin));
+	writel(val, reg);
+}
+
+void pinmux_tristate_enable(enum pmux_pingrp pin)
+{
+	pinmux_set_tristate(pin, PMUX_TRI_TRISTATE);
+}
+
+void pinmux_tristate_disable(enum pmux_pingrp pin)
+{
+	pinmux_set_tristate(pin, PMUX_TRI_NORMAL);
+}
+
+#ifdef TEGRA_PMX_HAS_PIN_IO_BIT_ETC
+void pinmux_set_io(enum pmux_pingrp pin, enum pmux_pin_io io)
+{
+	u32 *reg = REG(pin);
+	u32 val;
+
+	if (io == PMUX_PIN_NONE)
+		return;
+
+	/* Error check on pin and io */
+	assert(pmux_pingrp_isvalid(pin));
+	assert(pmux_pin_io_isvalid(io));
+
+	val = readl(reg);
+	if (io == PMUX_PIN_INPUT)
+		val |= (io & 1) << IO_SHIFT;
+	else
+		val &= ~(1 << IO_SHIFT);
+	writel(val, reg);
+}
+
+static void pinmux_set_lock(enum pmux_pingrp pin, enum pmux_pin_lock lock)
+{
+	u32 *reg = REG(pin);
+	u32 val;
+
+	if (lock == PMUX_PIN_LOCK_DEFAULT)
+		return;
+
+	/* Error check on pin and lock */
+	assert(pmux_pingrp_isvalid(pin));
+	assert(pmux_pin_lock_isvalid(lock));
+
+	val = readl(reg);
+	if (lock == PMUX_PIN_LOCK_ENABLE) {
+		val |= (1 << LOCK_SHIFT);
+	} else {
+		if (val & (1 << LOCK_SHIFT))
+			printf("%s: Cannot clear LOCK bit!\n", __func__);
+		val &= ~(1 << LOCK_SHIFT);
+	}
+	writel(val, reg);
+
+	return;
+}
+
+static void pinmux_set_od(enum pmux_pingrp pin, enum pmux_pin_od od)
+{
+	u32 *reg = REG(pin);
+	u32 val;
+
+	if (od == PMUX_PIN_OD_DEFAULT)
+		return;
+
+	/* Error check on pin and od */
+	assert(pmux_pingrp_isvalid(pin));
+	assert(pmux_pin_od_isvalid(od));
+
+	val = readl(reg);
+	if (od == PMUX_PIN_OD_ENABLE)
+		val |= (1 << OD_SHIFT);
+	else
+		val &= ~(1 << OD_SHIFT);
+	writel(val, reg);
+
+	return;
+}
+
+static void pinmux_set_ioreset(enum pmux_pingrp pin,
+				enum pmux_pin_ioreset ioreset)
+{
+	u32 *reg = REG(pin);
+	u32 val;
+
+	if (ioreset == PMUX_PIN_IO_RESET_DEFAULT)
+		return;
+
+	/* Error check on pin and ioreset */
+	assert(pmux_pingrp_isvalid(pin));
+	assert(pmux_pin_ioreset_isvalid(ioreset));
+
+	val = readl(reg);
+	if (ioreset == PMUX_PIN_IO_RESET_ENABLE)
+		val |= (1 << IO_RESET_SHIFT);
+	else
+		val &= ~(1 << IO_RESET_SHIFT);
+	writel(val, reg);
+
+	return;
+}
+
+#ifdef TEGRA_PMX_HAS_RCV_SEL
+static void pinmux_set_rcv_sel(enum pmux_pingrp pin,
+				enum pmux_pin_rcv_sel rcv_sel)
+{
+	u32 *reg = REG(pin);
+	u32 val;
+
+	if (rcv_sel == PMUX_PIN_RCV_SEL_DEFAULT)
+		return;
+
+	/* Error check on pin and rcv_sel */
+	assert(pmux_pingrp_isvalid(pin));
+	assert(pmux_pin_rcv_sel_isvalid(rcv_sel));
+
+	val = readl(reg);
+	if (rcv_sel == PMUX_PIN_RCV_SEL_HIGH)
+		val |= (1 << RCV_SEL_SHIFT);
+	else
+		val &= ~(1 << RCV_SEL_SHIFT);
+	writel(val, reg);
+
+	return;
+}
+#endif /* TEGRA_PMX_HAS_RCV_SEL */
+#endif /* TEGRA_PMX_HAS_PIN_IO_BIT_ETC */
+
+static void pinmux_config_pingrp(const struct pmux_pingrp_config *config)
+{
+	enum pmux_pingrp pin = config->pingrp;
+
+	pinmux_set_func(pin, config->func);
+	pinmux_set_pullupdown(pin, config->pull);
+	pinmux_set_tristate(pin, config->tristate);
+#ifdef TEGRA_PMX_HAS_PIN_IO_BIT_ETC
+	pinmux_set_io(pin, config->io);
+	pinmux_set_lock(pin, config->lock);
+	pinmux_set_od(pin, config->od);
+	pinmux_set_ioreset(pin, config->ioreset);
+#ifdef TEGRA_PMX_HAS_RCV_SEL
+	pinmux_set_rcv_sel(pin, config->rcv_sel);
+#endif
+#endif
+}
+
+void pinmux_config_pingrp_table(const struct pmux_pingrp_config *config,
+				int len)
+{
+	int i;
+
+	for (i = 0; i < len; i++)
+		pinmux_config_pingrp(&config[i]);
+}
+
+#ifdef TEGRA_PMX_HAS_DRVGRPS
+
+#define pmux_drvgrp_isvalid(pd) (((pd) >= 0) && ((pd) < PMUX_DRVGRP_COUNT))
+
+#define pmux_slw_isvalid(slw) \
+	(((slw) >= PMUX_SLWF_MIN) && ((slw) <= PMUX_SLWF_MAX))
+
+#define pmux_drv_isvalid(drv) \
+	(((drv) >= PMUX_DRVUP_MIN) && ((drv) <= PMUX_DRVUP_MAX))
+
+#define pmux_lpmd_isvalid(lpm) \
+	(((lpm) >= PMUX_LPMD_X8) && ((lpm) <= PMUX_LPMD_X))
+
+#define pmux_schmt_isvalid(schmt) \
+	(((schmt) >= PMUX_SCHMT_DISABLE) && ((schmt) <= PMUX_SCHMT_ENABLE))
+
+#define pmux_hsm_isvalid(hsm) \
+	(((hsm) >= PMUX_HSM_DISABLE) && ((hsm) <= PMUX_HSM_ENABLE))
+
+#define HSM_SHIFT	2
+#define SCHMT_SHIFT	3
+#define LPMD_SHIFT	4
+#define LPMD_MASK	(3 << LPMD_SHIFT)
+#define DRVDN_SHIFT	12
+#define DRVDN_MASK	(0x7F << DRVDN_SHIFT)
+#define DRVUP_SHIFT	20
+#define DRVUP_MASK	(0x7F << DRVUP_SHIFT)
+#define SLWR_SHIFT	28
+#define SLWR_MASK	(3 << SLWR_SHIFT)
+#define SLWF_SHIFT	30
+#define SLWF_MASK	(3 << SLWF_SHIFT)
+
+static void pinmux_set_drvup_slwf(enum pmux_drvgrp grp, int slwf)
+{
+	u32 *reg = DRV_REG(grp);
+	u32 val;
+
+	/* NONE means unspecified/do not change/use POR value */
+	if (slwf == PMUX_SLWF_NONE)
+		return;
+
+	/* Error check on pad and slwf */
+	assert(pmux_drvgrp_isvalid(grp));
+	assert(pmux_slw_isvalid(slwf));
+
+	val = readl(reg);
+	val &= ~SLWF_MASK;
+	val |= (slwf << SLWF_SHIFT);
+	writel(val, reg);
+
+	return;
+}
+
+static void pinmux_set_drvdn_slwr(enum pmux_drvgrp grp, int slwr)
+{
+	u32 *reg = DRV_REG(grp);
+	u32 val;
+
+	/* NONE means unspecified/do not change/use POR value */
+	if (slwr == PMUX_SLWR_NONE)
+		return;
+
+	/* Error check on pad and slwr */
+	assert(pmux_drvgrp_isvalid(grp));
+	assert(pmux_slw_isvalid(slwr));
+
+	val = readl(reg);
+	val &= ~SLWR_MASK;
+	val |= (slwr << SLWR_SHIFT);
+	writel(val, reg);
+
+	return;
+}
+
+static void pinmux_set_drvup(enum pmux_drvgrp grp, int drvup)
+{
+	u32 *reg = DRV_REG(grp);
+	u32 val;
+
+	/* NONE means unspecified/do not change/use POR value */
+	if (drvup == PMUX_DRVUP_NONE)
+		return;
+
+	/* Error check on pad and drvup */
+	assert(pmux_drvgrp_isvalid(grp));
+	assert(pmux_drv_isvalid(drvup));
+
+	val = readl(reg);
+	val &= ~DRVUP_MASK;
+	val |= (drvup << DRVUP_SHIFT);
+	writel(val, reg);
+
+	return;
+}
+
+static void pinmux_set_drvdn(enum pmux_drvgrp grp, int drvdn)
+{
+	u32 *reg = DRV_REG(grp);
+	u32 val;
+
+	/* NONE means unspecified/do not change/use POR value */
+	if (drvdn == PMUX_DRVDN_NONE)
+		return;
+
+	/* Error check on pad and drvdn */
+	assert(pmux_drvgrp_isvalid(grp));
+	assert(pmux_drv_isvalid(drvdn));
+
+	val = readl(reg);
+	val &= ~DRVDN_MASK;
+	val |= (drvdn << DRVDN_SHIFT);
+	writel(val, reg);
+
+	return;
+}
+
+static void pinmux_set_lpmd(enum pmux_drvgrp grp, enum pmux_lpmd lpmd)
+{
+	u32 *reg = DRV_REG(grp);
+	u32 val;
+
+	/* NONE means unspecified/do not change/use POR value */
+	if (lpmd == PMUX_LPMD_NONE)
+		return;
+
+	/* Error check pad and lpmd value */
+	assert(pmux_drvgrp_isvalid(grp));
+	assert(pmux_lpmd_isvalid(lpmd));
+
+	val = readl(reg);
+	val &= ~LPMD_MASK;
+	val |= (lpmd << LPMD_SHIFT);
+	writel(val, reg);
+
+	return;
+}
+
+static void pinmux_set_schmt(enum pmux_drvgrp grp, enum pmux_schmt schmt)
+{
+	u32 *reg = DRV_REG(grp);
+	u32 val;
+
+	/* NONE means unspecified/do not change/use POR value */
+	if (schmt == PMUX_SCHMT_NONE)
+		return;
+
+	/* Error check pad */
+	assert(pmux_drvgrp_isvalid(grp));
+	assert(pmux_schmt_isvalid(schmt));
+
+	val = readl(reg);
+	if (schmt == PMUX_SCHMT_ENABLE)
+		val |= (1 << SCHMT_SHIFT);
+	else
+		val &= ~(1 << SCHMT_SHIFT);
+	writel(val, reg);
+
+	return;
+}
+
+static void pinmux_set_hsm(enum pmux_drvgrp grp, enum pmux_hsm hsm)
+{
+	u32 *reg = DRV_REG(grp);
+	u32 val;
+
+	/* NONE means unspecified/do not change/use POR value */
+	if (hsm == PMUX_HSM_NONE)
+		return;
+
+	/* Error check pad */
+	assert(pmux_drvgrp_isvalid(grp));
+	assert(pmux_hsm_isvalid(hsm));
+
+	val = readl(reg);
+	if (hsm == PMUX_HSM_ENABLE)
+		val |= (1 << HSM_SHIFT);
+	else
+		val &= ~(1 << HSM_SHIFT);
+	writel(val, reg);
+
+	return;
+}
+
+static void pinmux_config_drvgrp(const struct pmux_drvgrp_config *config)
+{
+	enum pmux_drvgrp grp = config->drvgrp;
+
+	pinmux_set_drvup_slwf(grp, config->slwf);
+	pinmux_set_drvdn_slwr(grp, config->slwr);
+	pinmux_set_drvup(grp, config->drvup);
+	pinmux_set_drvdn(grp, config->drvdn);
+	pinmux_set_lpmd(grp, config->lpmd);
+	pinmux_set_schmt(grp, config->schmt);
+	pinmux_set_hsm(grp, config->hsm);
+}
+
+void pinmux_config_drvgrp_table(const struct pmux_drvgrp_config *config,
+				int len)
+{
+	int i;
+
+	for (i = 0; i < len; i++)
+		pinmux_config_drvgrp(&config[i]);
+}
+#endif /* TEGRA_PMX_HAS_DRVGRPS */
diff --git a/arch/arm/mach-tegra/powergate.c b/arch/arm/mach-tegra/powergate.c
new file mode 100644
index 0000000..439cff3
--- /dev/null
+++ b/arch/arm/mach-tegra/powergate.c
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2014, NVIDIA CORPORATION.  All rights reserved.
+ *
+ * SPDX-License-Identifier: GPL-2.0
+ */
+
+#include <common.h>
+#include <errno.h>
+
+#include <asm/io.h>
+#include <asm/types.h>
+
+#include <asm/arch/powergate.h>
+#include <asm/arch/tegra.h>
+
+#define PWRGATE_TOGGLE 0x30
+#define  PWRGATE_TOGGLE_START (1 << 8)
+
+#define REMOVE_CLAMPING 0x34
+
+#define PWRGATE_STATUS 0x38
+
+static int tegra_powergate_set(enum tegra_powergate id, bool state)
+{
+	u32 value, mask = state ? (1 << id) : 0, old_mask;
+	unsigned long start, timeout = 25;
+
+	value = readl(NV_PA_PMC_BASE + PWRGATE_STATUS);
+	old_mask = value & (1 << id);
+
+	if (mask == old_mask)
+		return 0;
+
+	writel(PWRGATE_TOGGLE_START | id, NV_PA_PMC_BASE + PWRGATE_TOGGLE);
+
+	start = get_timer(0);
+
+	while (get_timer(start) < timeout) {
+		value = readl(NV_PA_PMC_BASE + PWRGATE_STATUS);
+		if ((value & (1 << id)) == mask)
+			return 0;
+	}
+
+	return -ETIMEDOUT;
+}
+
+static int tegra_powergate_power_on(enum tegra_powergate id)
+{
+	return tegra_powergate_set(id, true);
+}
+
+int tegra_powergate_power_off(enum tegra_powergate id)
+{
+	return tegra_powergate_set(id, false);
+}
+
+static int tegra_powergate_remove_clamping(enum tegra_powergate id)
+{
+	unsigned long value;
+
+	/*
+	 * The REMOVE_CLAMPING register has the bits for the PCIE and VDEC
+	 * partitions reversed. This was originally introduced on Tegra20 but
+	 * has since been carried forward for backwards-compatibility.
+	 */
+	if (id == TEGRA_POWERGATE_VDEC)
+		value = 1 << TEGRA_POWERGATE_PCIE;
+	else if (id == TEGRA_POWERGATE_PCIE)
+		value = 1 << TEGRA_POWERGATE_VDEC;
+	else
+		value = 1 << id;
+
+	writel(value, NV_PA_PMC_BASE + REMOVE_CLAMPING);
+
+	return 0;
+}
+
+int tegra_powergate_sequence_power_up(enum tegra_powergate id,
+				      enum periph_id periph)
+{
+	int err;
+
+	reset_set_enable(periph, 1);
+
+	err = tegra_powergate_power_on(id);
+	if (err < 0)
+		return err;
+
+	clock_enable(periph);
+
+	udelay(10);
+
+	err = tegra_powergate_remove_clamping(id);
+	if (err < 0)
+		return err;
+
+	udelay(10);
+
+	reset_set_enable(periph, 0);
+
+	return 0;
+}
diff --git a/arch/arm/mach-tegra/spl.c b/arch/arm/mach-tegra/spl.c
new file mode 100644
index 0000000..e0f9d5b
--- /dev/null
+++ b/arch/arm/mach-tegra/spl.c
@@ -0,0 +1,49 @@
+/*
+ * (C) Copyright 2012
+ * NVIDIA Inc, <www.nvidia.com>
+ *
+ * Allen Martin <amartin@nvidia.com>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+#include <common.h>
+#include <spl.h>
+
+#include <asm/io.h>
+#include <asm/arch/clock.h>
+#include <asm/arch/pinmux.h>
+#include <asm/arch/tegra.h>
+#include <asm/arch-tegra/apb_misc.h>
+#include <asm/arch-tegra/board.h>
+#include <asm/spl.h>
+#include "cpu.h"
+
+void spl_board_init(void)
+{
+	struct apb_misc_pp_ctlr *apb_misc =
+				(struct apb_misc_pp_ctlr *)NV_PA_APB_MISC_BASE;
+
+	/* enable JTAG */
+	writel(0xC0, &apb_misc->cfg_ctl);
+
+	board_init_uart_f();
+
+	/* Initialize periph GPIOs */
+	gpio_early_init_uart();
+
+	clock_early_init();
+	preloader_console_init();
+}
+
+u32 spl_boot_device(void)
+{
+	return BOOT_DEVICE_RAM;
+}
+
+void __noreturn jump_to_image_no_args(struct spl_image_info *spl_image)
+{
+	debug("image entry point: 0x%X\n", spl_image->entry_point);
+
+	start_cpu((u32)spl_image->entry_point);
+	halt_avp();
+}
diff --git a/arch/arm/mach-tegra/sys_info.c b/arch/arm/mach-tegra/sys_info.c
new file mode 100644
index 0000000..5933c35
--- /dev/null
+++ b/arch/arm/mach-tegra/sys_info.c
@@ -0,0 +1,31 @@
+/*
+ * (C) Copyright 2010,2011
+ * NVIDIA Corporation <www.nvidia.com>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <linux/ctype.h>
+
+static void upstring(char *s)
+{
+	while (*s) {
+		*s = toupper(*s);
+		s++;
+	}
+}
+
+/* Print CPU information */
+int print_cpuinfo(void)
+{
+	char soc_name[10];
+
+	strncpy(soc_name, CONFIG_SYS_SOC, 10);
+	upstring(soc_name);
+	puts(soc_name);
+	puts("\n");
+
+	/* TBD: Add printf of major/minor rev info, stepping, etc. */
+	return 0;
+}
diff --git a/arch/arm/mach-tegra/tegra114/Kconfig b/arch/arm/mach-tegra/tegra114/Kconfig
new file mode 100644
index 0000000..31012bc
--- /dev/null
+++ b/arch/arm/mach-tegra/tegra114/Kconfig
@@ -0,0 +1,16 @@
+if TEGRA114
+
+choice
+	prompt "Tegra114 board select"
+
+config TARGET_DALMORE
+	bool "NVIDIA Tegra114 Dalmore evaluation board"
+
+endchoice
+
+config SYS_SOC
+	default "tegra114"
+
+source "board/nvidia/dalmore/Kconfig"
+
+endif
diff --git a/arch/arm/mach-tegra/tegra114/Makefile b/arch/arm/mach-tegra/tegra114/Makefile
new file mode 100644
index 0000000..7489f5f
--- /dev/null
+++ b/arch/arm/mach-tegra/tegra114/Makefile
@@ -0,0 +1,19 @@
+#
+# Copyright (c) 2010-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/>.
+#
+
+obj-$(CONFIG_SPL_BUILD) += cpu.o
+
+obj-y	+= clock.o funcmux.o pinmux.o
diff --git a/arch/arm/mach-tegra/tegra114/clock.c b/arch/arm/mach-tegra/tegra114/clock.c
new file mode 100644
index 0000000..d5194e1
--- /dev/null
+++ b/arch/arm/mach-tegra/tegra114/clock.c
@@ -0,0 +1,669 @@
+/*
+ * Copyright (c) 2010-2014, NVIDIA CORPORATION.  All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* Tegra114 Clock control functions */
+
+#include <common.h>
+#include <asm/io.h>
+#include <asm/arch/clock.h>
+#include <asm/arch/sysctr.h>
+#include <asm/arch/tegra.h>
+#include <asm/arch-tegra/clk_rst.h>
+#include <asm/arch-tegra/timer.h>
+#include <div64.h>
+#include <fdtdec.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
+ * source. This gives us a clock 'type' and exploits what commonality exists
+ * in the device.
+ *
+ * Letters are obvious, except for T which means CLK_M, and S which means the
+ * clock derived from 32KHz. Beware that CLK_M (also called OSC in the
+ * datasheet) and PLL_M are different things. The former is the basic
+ * clock supplied to the SOC from an external oscillator. The latter is the
+ * memory clock PLL.
+ *
+ * See definitions in clock_id in the header file.
+ */
+enum clock_type_id {
+	CLOCK_TYPE_AXPT,	/* PLL_A, PLL_X, PLL_P, CLK_M */
+	CLOCK_TYPE_MCPA,	/* and so on */
+	CLOCK_TYPE_MCPT,
+	CLOCK_TYPE_PCM,
+	CLOCK_TYPE_PCMT,
+	CLOCK_TYPE_PCMT16,
+	CLOCK_TYPE_PDCT,
+	CLOCK_TYPE_ACPT,
+	CLOCK_TYPE_ASPTE,
+	CLOCK_TYPE_PMDACD2T,
+	CLOCK_TYPE_PCST,
+
+	CLOCK_TYPE_COUNT,
+	CLOCK_TYPE_NONE = -1,   /* invalid clock type */
+};
+
+enum {
+	CLOCK_MAX_MUX   = 8     /* number of source options for each clock */
+};
+
+/*
+ * Clock source mux for each clock type. This just converts our enum into
+ * a list of mux sources for use by the code.
+ *
+ * Note:
+ *  The extra column in each clock source array is used to store the mask
+ *  bits in its register for the source.
+ */
+#define CLK(x) CLOCK_ID_ ## x
+static enum clock_id clock_source[CLOCK_TYPE_COUNT][CLOCK_MAX_MUX+1] = {
+	{ CLK(AUDIO),	CLK(XCPU),	CLK(PERIPH),	CLK(OSC),
+		CLK(NONE),	CLK(NONE),	CLK(NONE),	CLK(NONE),
+		MASK_BITS_31_30},
+	{ CLK(MEMORY),	CLK(CGENERAL),	CLK(PERIPH),	CLK(AUDIO),
+		CLK(NONE),	CLK(NONE),	CLK(NONE),	CLK(NONE),
+		MASK_BITS_31_30},
+	{ CLK(MEMORY),	CLK(CGENERAL),	CLK(PERIPH),	CLK(OSC),
+		CLK(NONE),	CLK(NONE),	CLK(NONE),	CLK(NONE),
+		MASK_BITS_31_30},
+	{ CLK(PERIPH),	CLK(CGENERAL),	CLK(MEMORY),	CLK(NONE),
+		CLK(NONE),	CLK(NONE),	CLK(NONE),	CLK(NONE),
+		MASK_BITS_31_30},
+	{ CLK(PERIPH),	CLK(CGENERAL),	CLK(MEMORY),	CLK(OSC),
+		CLK(NONE),	CLK(NONE),	CLK(NONE),	CLK(NONE),
+		MASK_BITS_31_30},
+	{ CLK(PERIPH),	CLK(CGENERAL),	CLK(MEMORY),	CLK(OSC),
+		CLK(NONE),	CLK(NONE),	CLK(NONE),	CLK(NONE),
+		MASK_BITS_31_30},
+	{ CLK(PERIPH),	CLK(DISPLAY),	CLK(CGENERAL),	CLK(OSC),
+		CLK(NONE),	CLK(NONE),	CLK(NONE),	CLK(NONE),
+		MASK_BITS_31_30},
+	{ CLK(AUDIO),	CLK(CGENERAL),	CLK(PERIPH),	CLK(OSC),
+		CLK(NONE),	CLK(NONE),	CLK(NONE),	CLK(NONE),
+		MASK_BITS_31_30},
+	{ CLK(AUDIO),	CLK(SFROM32KHZ),	CLK(PERIPH),	CLK(OSC),
+		CLK(EPCI),	CLK(NONE),	CLK(NONE),	CLK(NONE),
+		MASK_BITS_31_29},
+	{ CLK(PERIPH),	CLK(MEMORY),	CLK(DISPLAY),	CLK(AUDIO),
+		CLK(CGENERAL),	CLK(DISPLAY2),	CLK(OSC),	CLK(NONE),
+		MASK_BITS_31_29},
+	{ CLK(PERIPH),	CLK(CGENERAL),	CLK(SFROM32KHZ),	CLK(OSC),
+		CLK(NONE),	CLK(NONE),	CLK(NONE),	CLK(NONE),
+		MASK_BITS_31_28}
+};
+
+/*
+ * Clock type for each peripheral clock source. We put the name in each
+ * record just so it is easy to match things up
+ */
+#define TYPE(name, type) type
+static enum clock_type_id clock_periph_type[PERIPHC_COUNT] = {
+	/* 0x00 */
+	TYPE(PERIPHC_I2S1,	CLOCK_TYPE_AXPT),
+	TYPE(PERIPHC_I2S2,	CLOCK_TYPE_AXPT),
+	TYPE(PERIPHC_SPDIF_OUT,	CLOCK_TYPE_AXPT),
+	TYPE(PERIPHC_SPDIF_IN,	CLOCK_TYPE_PCM),
+	TYPE(PERIPHC_PWM,	CLOCK_TYPE_PCST),  /* only PWM uses b29:28 */
+	TYPE(PERIPHC_NONE,	CLOCK_TYPE_NONE),
+	TYPE(PERIPHC_SBC2,	CLOCK_TYPE_PCMT),
+	TYPE(PERIPHC_SBC3,	CLOCK_TYPE_PCMT),
+
+	/* 0x08 */
+	TYPE(PERIPHC_NONE,	CLOCK_TYPE_NONE),
+	TYPE(PERIPHC_I2C1,	CLOCK_TYPE_PCMT16),
+	TYPE(PERIPHC_I2C5,	CLOCK_TYPE_PCMT16),
+	TYPE(PERIPHC_NONE,	CLOCK_TYPE_NONE),
+	TYPE(PERIPHC_NONE,	CLOCK_TYPE_NONE),
+	TYPE(PERIPHC_SBC1,	CLOCK_TYPE_PCMT),
+	TYPE(PERIPHC_DISP1,	CLOCK_TYPE_PMDACD2T),
+	TYPE(PERIPHC_DISP2,	CLOCK_TYPE_PMDACD2T),
+
+	/* 0x10 */
+	TYPE(PERIPHC_CVE,	CLOCK_TYPE_PDCT),
+	TYPE(PERIPHC_NONE,	CLOCK_TYPE_NONE),
+	TYPE(PERIPHC_VI,	CLOCK_TYPE_MCPA),
+	TYPE(PERIPHC_NONE,	CLOCK_TYPE_NONE),
+	TYPE(PERIPHC_SDMMC1,	CLOCK_TYPE_PCMT),
+	TYPE(PERIPHC_SDMMC2,	CLOCK_TYPE_PCMT),
+	TYPE(PERIPHC_G3D,	CLOCK_TYPE_MCPA),
+	TYPE(PERIPHC_G2D,	CLOCK_TYPE_MCPA),
+
+	/* 0x18 */
+	TYPE(PERIPHC_NDFLASH,	CLOCK_TYPE_PCMT),
+	TYPE(PERIPHC_SDMMC4,	CLOCK_TYPE_PCMT),
+	TYPE(PERIPHC_VFIR,	CLOCK_TYPE_PCMT),
+	TYPE(PERIPHC_EPP,	CLOCK_TYPE_MCPA),
+	TYPE(PERIPHC_MPE,	CLOCK_TYPE_MCPA),
+	TYPE(PERIPHC_MIPI,	CLOCK_TYPE_PCMT),	/* MIPI base-band HSI */
+	TYPE(PERIPHC_UART1,	CLOCK_TYPE_PCMT),
+	TYPE(PERIPHC_UART2,	CLOCK_TYPE_PCMT),
+
+	/* 0x20 */
+	TYPE(PERIPHC_HOST1X,	CLOCK_TYPE_MCPA),
+	TYPE(PERIPHC_NONE,	CLOCK_TYPE_NONE),
+	TYPE(PERIPHC_TVO,	CLOCK_TYPE_PDCT),
+	TYPE(PERIPHC_HDMI,	CLOCK_TYPE_PMDACD2T),
+	TYPE(PERIPHC_NONE,	CLOCK_TYPE_NONE),
+	TYPE(PERIPHC_TVDAC,	CLOCK_TYPE_PDCT),
+	TYPE(PERIPHC_I2C2,	CLOCK_TYPE_PCMT16),
+	TYPE(PERIPHC_EMC,	CLOCK_TYPE_MCPT),
+
+	/* 0x28 */
+	TYPE(PERIPHC_UART3,	CLOCK_TYPE_PCMT),
+	TYPE(PERIPHC_NONE,	CLOCK_TYPE_NONE),
+	TYPE(PERIPHC_VI,	CLOCK_TYPE_MCPA),
+	TYPE(PERIPHC_NONE,	CLOCK_TYPE_NONE),
+	TYPE(PERIPHC_NONE,	CLOCK_TYPE_NONE),
+	TYPE(PERIPHC_SBC4,	CLOCK_TYPE_PCMT),
+	TYPE(PERIPHC_I2C3,	CLOCK_TYPE_PCMT16),
+	TYPE(PERIPHC_SDMMC3,	CLOCK_TYPE_PCMT),
+
+	/* 0x30 */
+	TYPE(PERIPHC_UART4,	CLOCK_TYPE_PCMT),
+	TYPE(PERIPHC_UART5,	CLOCK_TYPE_PCMT),
+	TYPE(PERIPHC_VDE,	CLOCK_TYPE_PCMT),
+	TYPE(PERIPHC_OWR,	CLOCK_TYPE_PCMT),
+	TYPE(PERIPHC_NOR,	CLOCK_TYPE_PCMT),
+	TYPE(PERIPHC_CSITE,	CLOCK_TYPE_PCMT),
+	TYPE(PERIPHC_I2S0,      CLOCK_TYPE_AXPT),
+	TYPE(PERIPHC_NONE,      CLOCK_TYPE_NONE),
+
+	/* 0x38h */  /* Jumps to reg offset 0x3B0h */
+	TYPE(PERIPHC_G3D2,      CLOCK_TYPE_MCPA),
+	TYPE(PERIPHC_MSELECT,   CLOCK_TYPE_PCMT),
+	TYPE(PERIPHC_TSENSOR,   CLOCK_TYPE_PCST),	/* s/b PCTS */
+	TYPE(PERIPHC_I2S3,	CLOCK_TYPE_AXPT),
+	TYPE(PERIPHC_I2S4,	CLOCK_TYPE_AXPT),
+	TYPE(PERIPHC_I2C4,	CLOCK_TYPE_PCMT16),
+	TYPE(PERIPHC_SBC5,	CLOCK_TYPE_PCMT),
+	TYPE(PERIPHC_SBC6,	CLOCK_TYPE_PCMT),
+
+	/* 0x40 */
+	TYPE(PERIPHC_AUDIO,	CLOCK_TYPE_ACPT),
+	TYPE(PERIPHC_NONE,	CLOCK_TYPE_NONE),
+	TYPE(PERIPHC_DAM0,	CLOCK_TYPE_ACPT),
+	TYPE(PERIPHC_DAM1,	CLOCK_TYPE_ACPT),
+	TYPE(PERIPHC_DAM2,	CLOCK_TYPE_ACPT),
+	TYPE(PERIPHC_HDA2CODEC2X, CLOCK_TYPE_PCMT),
+	TYPE(PERIPHC_ACTMON,	CLOCK_TYPE_PCST),	/* MASK 31:30 */
+	TYPE(PERIPHC_EXTPERIPH1, CLOCK_TYPE_ASPTE),
+
+	/* 0x48 */
+	TYPE(PERIPHC_EXTPERIPH2, CLOCK_TYPE_ASPTE),
+	TYPE(PERIPHC_EXTPERIPH3, CLOCK_TYPE_ASPTE),
+	TYPE(PERIPHC_NANDSPEED,	CLOCK_TYPE_PCMT),
+	TYPE(PERIPHC_I2CSLOW,	CLOCK_TYPE_PCST),	/* MASK 31:30 */
+	TYPE(PERIPHC_SYS,	CLOCK_TYPE_NONE),
+	TYPE(PERIPHC_SPEEDO,	CLOCK_TYPE_PCMT),
+	TYPE(PERIPHC_NONE,	CLOCK_TYPE_NONE),
+	TYPE(PERIPHC_NONE,	CLOCK_TYPE_NONE),
+
+	/* 0x50 */
+	TYPE(PERIPHC_NONE,	CLOCK_TYPE_NONE),
+	TYPE(PERIPHC_NONE,	CLOCK_TYPE_NONE),
+	TYPE(PERIPHC_NONE,	CLOCK_TYPE_NONE),
+	TYPE(PERIPHC_NONE,	CLOCK_TYPE_NONE),
+	TYPE(PERIPHC_SATAOOB,	CLOCK_TYPE_PCMT),	/* offset 0x420h */
+	TYPE(PERIPHC_SATA,	CLOCK_TYPE_PCMT),
+	TYPE(PERIPHC_HDA,	CLOCK_TYPE_PCMT),
+};
+
+/*
+ * This array translates a periph_id to a periphc_internal_id
+ *
+ * Not present/matched up:
+ *	uint vi_sensor;	 _VI_SENSOR_0,		0x1A8
+ *	SPDIF - which is both 0x08 and 0x0c
+ *
+ */
+#define NONE(name) (-1)
+#define OFFSET(name, value) PERIPHC_ ## name
+static s8 periph_id_to_internal_id[PERIPH_ID_COUNT] = {
+	/* Low word: 31:0 */
+	NONE(CPU),
+	NONE(COP),
+	NONE(TRIGSYS),
+	NONE(RESERVED3),
+	NONE(RTC),
+	NONE(TMR),
+	PERIPHC_UART1,
+	PERIPHC_UART2,	/* and vfir 0x68 */
+
+	/* 8 */
+	NONE(GPIO),
+	PERIPHC_SDMMC2,
+	NONE(SPDIF),		/* 0x08 and 0x0c, unclear which to use */
+	PERIPHC_I2S1,
+	PERIPHC_I2C1,
+	PERIPHC_NDFLASH,
+	PERIPHC_SDMMC1,
+	PERIPHC_SDMMC4,
+
+	/* 16 */
+	NONE(RESERVED16),
+	PERIPHC_PWM,
+	PERIPHC_I2S2,
+	PERIPHC_EPP,
+	PERIPHC_VI,
+	PERIPHC_G2D,
+	NONE(USBD),
+	NONE(ISP),
+
+	/* 24 */
+	PERIPHC_G3D,
+	NONE(RESERVED25),
+	PERIPHC_DISP2,
+	PERIPHC_DISP1,
+	PERIPHC_HOST1X,
+	NONE(VCP),
+	PERIPHC_I2S0,
+	NONE(CACHE2),
+
+	/* Middle word: 63:32 */
+	NONE(MEM),
+	NONE(AHBDMA),
+	NONE(APBDMA),
+	NONE(RESERVED35),
+	NONE(RESERVED36),
+	NONE(STAT_MON),
+	NONE(RESERVED38),
+	NONE(RESERVED39),
+
+	/* 40 */
+	NONE(KFUSE),
+	NONE(SBC1),	/* SBC1, 0x34, is this SPI1? */
+	PERIPHC_NOR,
+	NONE(RESERVED43),
+	PERIPHC_SBC2,
+	NONE(RESERVED45),
+	PERIPHC_SBC3,
+	PERIPHC_I2C5,
+
+	/* 48 */
+	NONE(DSI),
+	PERIPHC_TVO,	/* also CVE 0x40 */
+	PERIPHC_MIPI,
+	PERIPHC_HDMI,
+	NONE(CSI),
+	PERIPHC_TVDAC,
+	PERIPHC_I2C2,
+	PERIPHC_UART3,
+
+	/* 56 */
+	NONE(RESERVED56),
+	PERIPHC_EMC,
+	NONE(USB2),
+	NONE(USB3),
+	PERIPHC_MPE,
+	PERIPHC_VDE,
+	NONE(BSEA),
+	NONE(BSEV),
+
+	/* Upper word 95:64 */
+	PERIPHC_SPEEDO,
+	PERIPHC_UART4,
+	PERIPHC_UART5,
+	PERIPHC_I2C3,
+	PERIPHC_SBC4,
+	PERIPHC_SDMMC3,
+	NONE(PCIE),
+	PERIPHC_OWR,
+
+	/* 72 */
+	NONE(AFI),
+	PERIPHC_CSITE,
+	NONE(PCIEXCLK),
+	NONE(AVPUCQ),
+	NONE(RESERVED76),
+	NONE(RESERVED77),
+	NONE(RESERVED78),
+	NONE(DTV),
+
+	/* 80 */
+	PERIPHC_NANDSPEED,
+	PERIPHC_I2CSLOW,
+	NONE(DSIB),
+	NONE(RESERVED83),
+	NONE(IRAMA),
+	NONE(IRAMB),
+	NONE(IRAMC),
+	NONE(IRAMD),
+
+	/* 88 */
+	NONE(CRAM2),
+	NONE(RESERVED89),
+	NONE(MDOUBLER),
+	NONE(RESERVED91),
+	NONE(SUSOUT),
+	NONE(RESERVED93),
+	NONE(RESERVED94),
+	NONE(RESERVED95),
+
+	/* V word: 31:0 */
+	NONE(CPUG),
+	NONE(CPULP),
+	PERIPHC_G3D2,
+	PERIPHC_MSELECT,
+	PERIPHC_TSENSOR,
+	PERIPHC_I2S3,
+	PERIPHC_I2S4,
+	PERIPHC_I2C4,
+
+	/* 08 */
+	PERIPHC_SBC5,
+	PERIPHC_SBC6,
+	PERIPHC_AUDIO,
+	NONE(APBIF),
+	PERIPHC_DAM0,
+	PERIPHC_DAM1,
+	PERIPHC_DAM2,
+	PERIPHC_HDA2CODEC2X,
+
+	/* 16 */
+	NONE(ATOMICS),
+	NONE(RESERVED17),
+	NONE(RESERVED18),
+	NONE(RESERVED19),
+	NONE(RESERVED20),
+	NONE(RESERVED21),
+	NONE(RESERVED22),
+	PERIPHC_ACTMON,
+
+	/* 24 */
+	NONE(RESERVED24),
+	NONE(RESERVED25),
+	NONE(RESERVED26),
+	NONE(RESERVED27),
+	PERIPHC_SATA,
+	PERIPHC_HDA,
+	NONE(RESERVED30),
+	NONE(RESERVED31),
+
+	/* W word: 31:0 */
+	NONE(HDA2HDMICODEC),
+	NONE(RESERVED1_SATACOLD),
+	NONE(RESERVED2_PCIERX0),
+	NONE(RESERVED3_PCIERX1),
+	NONE(RESERVED4_PCIERX2),
+	NONE(RESERVED5_PCIERX3),
+	NONE(RESERVED6_PCIERX4),
+	NONE(RESERVED7_PCIERX5),
+
+	/* 40 */
+	NONE(CEC),
+	NONE(PCIE2_IOBIST),
+	NONE(EMC_IOBIST),
+	NONE(HDMI_IOBIST),
+	NONE(SATA_IOBIST),
+	NONE(MIPI_IOBIST),
+	NONE(EMC1_IOBIST),
+	NONE(XUSB),
+
+	/* 48 */
+	NONE(CILAB),
+	NONE(CILCD),
+	NONE(CILE),
+	NONE(DSIA_LP),
+	NONE(DSIB_LP),
+	NONE(RESERVED21_ENTROPY),
+	NONE(RESERVED22_W),
+	NONE(RESERVED23_W),
+
+	/* 56 */
+	NONE(RESERVED24_W),
+	NONE(AMX0),
+	NONE(ADX0),
+	NONE(DVFS),
+	NONE(XUSB_SS),
+	NONE(EMC_DLL),
+	NONE(MC1),
+	NONE(EMC1),
+};
+
+/*
+ * Get the oscillator frequency, from the corresponding hardware configuration
+ * field. Note that T30/T114 support 3 new higher freqs, but we map back
+ * to the old T20 freqs. Support for the higher oscillators is TBD.
+ */
+enum clock_osc_freq clock_get_osc_freq(void)
+{
+	struct clk_rst_ctlr *clkrst =
+			(struct clk_rst_ctlr *)NV_PA_CLK_RST_BASE;
+	u32 reg;
+
+	reg = readl(&clkrst->crc_osc_ctrl);
+	reg = (reg & OSC_FREQ_MASK) >> OSC_FREQ_SHIFT;
+
+	if (reg & 1)				/* one of the newer freqs */
+		printf("Warning: OSC_FREQ is unsupported! (%d)\n", reg);
+
+	return reg >> 2;	/* Map to most common (T20) freqs */
+}
+
+/* Returns a pointer to the clock source register for a peripheral */
+u32 *get_periph_source_reg(enum periph_id periph_id)
+{
+	struct clk_rst_ctlr *clkrst =
+		(struct clk_rst_ctlr *)NV_PA_CLK_RST_BASE;
+	enum periphc_internal_id internal_id;
+
+	/* Coresight is a special case */
+	if (periph_id == PERIPH_ID_CSI)
+		return &clkrst->crc_clk_src[PERIPH_ID_CSI+1];
+
+	assert(periph_id >= PERIPH_ID_FIRST && periph_id < PERIPH_ID_COUNT);
+	internal_id = periph_id_to_internal_id[periph_id];
+	assert(internal_id != -1);
+	if (internal_id >= PERIPHC_VW_FIRST) {
+		internal_id -= PERIPHC_VW_FIRST;
+		return &clkrst->crc_clk_src_vw[internal_id];
+	} else
+		return &clkrst->crc_clk_src[internal_id];
+}
+
+/**
+ * Given a peripheral ID and the required source clock, this returns which
+ * value should be programmed into the source mux for that peripheral.
+ *
+ * There is special code here to handle the one source type with 5 sources.
+ *
+ * @param periph_id	peripheral to start
+ * @param source	PLL id of required parent clock
+ * @param mux_bits	Set to number of bits in mux register: 2 or 4
+ * @param divider_bits Set to number of divider bits (8 or 16)
+ * @return mux value (0-4, or -1 if not found)
+ */
+int get_periph_clock_source(enum periph_id periph_id,
+	enum clock_id parent, int *mux_bits, int *divider_bits)
+{
+	enum clock_type_id type;
+	enum periphc_internal_id internal_id;
+	int mux;
+
+	assert(clock_periph_id_isvalid(periph_id));
+
+	internal_id = periph_id_to_internal_id[periph_id];
+	assert(periphc_internal_id_isvalid(internal_id));
+
+	type = clock_periph_type[internal_id];
+	assert(clock_type_id_isvalid(type));
+
+	*mux_bits = clock_source[type][CLOCK_MAX_MUX];
+
+	if (type == CLOCK_TYPE_PCMT16)
+		*divider_bits = 16;
+	else
+		*divider_bits = 8;
+
+	for (mux = 0; mux < CLOCK_MAX_MUX; mux++)
+		if (clock_source[type][mux] == parent)
+			return mux;
+
+	/* if we get here, either us or the caller has made a mistake */
+	printf("Caller requested bad clock: periph=%d, parent=%d\n", periph_id,
+		parent);
+	return -1;
+}
+
+void clock_set_enable(enum periph_id periph_id, int enable)
+{
+	struct clk_rst_ctlr *clkrst =
+		(struct clk_rst_ctlr *)NV_PA_CLK_RST_BASE;
+	u32 *clk;
+	u32 reg;
+
+	/* Enable/disable the clock to this peripheral */
+	assert(clock_periph_id_isvalid(periph_id));
+	if ((int)periph_id < (int)PERIPH_ID_VW_FIRST)
+		clk = &clkrst->crc_clk_out_enb[PERIPH_REG(periph_id)];
+	else
+		clk = &clkrst->crc_clk_out_enb_vw[PERIPH_REG(periph_id)];
+	reg = readl(clk);
+	if (enable)
+		reg |= PERIPH_MASK(periph_id);
+	else
+		reg &= ~PERIPH_MASK(periph_id);
+	writel(reg, clk);
+}
+
+void reset_set_enable(enum periph_id periph_id, int enable)
+{
+	struct clk_rst_ctlr *clkrst =
+		(struct clk_rst_ctlr *)NV_PA_CLK_RST_BASE;
+	u32 *reset;
+	u32 reg;
+
+	/* Enable/disable reset to the peripheral */
+	assert(clock_periph_id_isvalid(periph_id));
+	if (periph_id < PERIPH_ID_VW_FIRST)
+		reset = &clkrst->crc_rst_dev[PERIPH_REG(periph_id)];
+	else
+		reset = &clkrst->crc_rst_dev_vw[PERIPH_REG(periph_id)];
+	reg = readl(reset);
+	if (enable)
+		reg |= PERIPH_MASK(periph_id);
+	else
+		reg &= ~PERIPH_MASK(periph_id);
+	writel(reg, reset);
+}
+
+#ifdef CONFIG_OF_CONTROL
+/*
+ * Convert a device tree clock ID to our peripheral ID. They are mostly
+ * the same but we are very cautious so we check that a valid clock ID is
+ * provided.
+ *
+ * @param clk_id    Clock ID according to tegra114 device tree binding
+ * @return peripheral ID, or PERIPH_ID_NONE if the clock ID is invalid
+ */
+enum periph_id clk_id_to_periph_id(int clk_id)
+{
+	if (clk_id > PERIPH_ID_COUNT)
+		return PERIPH_ID_NONE;
+
+	switch (clk_id) {
+	case PERIPH_ID_RESERVED3:
+	case PERIPH_ID_RESERVED16:
+	case PERIPH_ID_RESERVED24:
+	case PERIPH_ID_RESERVED35:
+	case PERIPH_ID_RESERVED43:
+	case PERIPH_ID_RESERVED45:
+	case PERIPH_ID_RESERVED56:
+	case PERIPH_ID_RESERVED76:
+	case PERIPH_ID_RESERVED77:
+	case PERIPH_ID_RESERVED78:
+	case PERIPH_ID_RESERVED83:
+	case PERIPH_ID_RESERVED89:
+	case PERIPH_ID_RESERVED91:
+	case PERIPH_ID_RESERVED93:
+	case PERIPH_ID_RESERVED94:
+	case PERIPH_ID_RESERVED95:
+		return PERIPH_ID_NONE;
+	default:
+		return clk_id;
+	}
+}
+#endif /* CONFIG_OF_CONTROL */
+
+void clock_early_init(void)
+{
+	struct clk_rst_ctlr *clkrst =
+		(struct clk_rst_ctlr *)NV_PA_CLK_RST_BASE;
+
+	tegra30_set_up_pllp();
+
+	/*
+	 * PLLC output frequency set to 600Mhz
+	 * PLLD output frequency set to 925Mhz
+	 */
+	switch (clock_get_osc_freq()) {
+	case CLOCK_OSC_FREQ_12_0: /* OSC is 12Mhz */
+		clock_set_rate(CLOCK_ID_CGENERAL, 600, 12, 0, 8);
+		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_CGENERAL, 600, 26, 0, 8);
+		clock_set_rate(CLOCK_ID_DISPLAY, 925, 26, 0, 12);
+		break;
+
+	case CLOCK_OSC_FREQ_13_0: /* OSC is 13Mhz */
+		clock_set_rate(CLOCK_ID_CGENERAL, 600, 13, 0, 8);
+		clock_set_rate(CLOCK_ID_DISPLAY, 925, 13, 0, 12);
+		break;
+	case CLOCK_OSC_FREQ_19_2:
+	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;
+	}
+
+	/* PLLC_MISC2: Set dynramp_stepA/B. MISC2 maps to pll_out[1] */
+	writel(0x00561600, &clkrst->crc_pll[CLOCK_ID_CGENERAL].pll_out[1]);
+
+	/* PLLC_MISC: Set LOCK_ENABLE */
+	writel(0x01000000, &clkrst->crc_pll[CLOCK_ID_CGENERAL].pll_misc);
+	udelay(2);
+
+	/* PLLD_MISC: Set CLKENABLE, CPCON 12, LFCON 1 */
+	writel(0x40000C10, &clkrst->crc_pll[CLOCK_ID_DISPLAY].pll_misc);
+	udelay(2);
+}
+
+void arch_timer_init(void)
+{
+	struct sysctr_ctlr *sysctr = (struct sysctr_ctlr *)NV_PA_TSC_BASE;
+	u32 freq, val;
+
+	freq = clock_get_rate(CLOCK_ID_OSC);
+	debug("%s: osc freq is %dHz [0x%08X]\n", __func__, freq, freq);
+
+	/* ARM CNTFRQ */
+	asm("mcr p15, 0, %0, c14, c0, 0\n" : : "r" (freq));
+
+	/* Only T114 has the System Counter regs */
+	debug("%s: setting CNTFID0 to 0x%08X\n", __func__, freq);
+	writel(freq, &sysctr->cntfid0);
+
+	val = readl(&sysctr->cntcr);
+	val |= TSC_CNTCR_ENABLE | TSC_CNTCR_HDBG;
+	writel(val, &sysctr->cntcr);
+	debug("%s: TSC CNTCR = 0x%08X\n", __func__, val);
+}
diff --git a/arch/arm/mach-tegra/tegra114/cpu.c b/arch/arm/mach-tegra/tegra114/cpu.c
new file mode 100644
index 0000000..18dc1af
--- /dev/null
+++ b/arch/arm/mach-tegra/tegra114/cpu.c
@@ -0,0 +1,310 @@
+/*
+ * Copyright (c) 2010-2014, NVIDIA CORPORATION.  All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <asm/arch/clock.h>
+#include <asm/arch/flow.h>
+#include <asm/arch/pinmux.h>
+#include <asm/arch/tegra.h>
+#include <asm/arch-tegra/clk_rst.h>
+#include <asm/arch-tegra/pmc.h>
+#include "../cpu.h"
+
+/* Tegra114-specific CPU init code */
+static void enable_cpu_power_rail(void)
+{
+	struct pmc_ctlr *pmc = (struct pmc_ctlr *)NV_PA_PMC_BASE;
+	struct clk_rst_ctlr *clkrst = (struct clk_rst_ctlr *)NV_PA_CLK_RST_BASE;
+	u32 reg;
+
+	debug("enable_cpu_power_rail entry\n");
+
+	/* un-tristate PWR_I2C SCL/SDA, rest of the defaults are correct */
+	pinmux_tristate_disable(PMUX_PINGRP_PWR_I2C_SCL_PZ6);
+	pinmux_tristate_disable(PMUX_PINGRP_PWR_I2C_SDA_PZ7);
+
+	/*
+	 * Set CPUPWRGOOD_TIMER - APB clock is 1/2 of SCLK (102MHz),
+	 * set it for 25ms (102MHz * .025)
+	 */
+	reg = 0x26E8F0;
+	writel(reg, &pmc->pmc_cpupwrgood_timer);
+
+	/* Set polarity to 0 (normal) and enable CPUPWRREQ_OE */
+	clrbits_le32(&pmc->pmc_cntrl, CPUPWRREQ_POL);
+	setbits_le32(&pmc->pmc_cntrl, CPUPWRREQ_OE);
+
+	/*
+	 * Set CLK_RST_CONTROLLER_CPU_SOFTRST_CTRL2_0_CAR2PMC_CPU_ACK_WIDTH
+	 * to 408 to satisfy the requirement of having at least 16 CPU clock
+	 * cycles before clamp removal.
+	 */
+
+	clrbits_le32(&clkrst->crc_cpu_softrst_ctrl2, 0xFFF);
+	setbits_le32(&clkrst->crc_cpu_softrst_ctrl2, 408);
+}
+
+static void enable_cpu_clocks(void)
+{
+	struct clk_rst_ctlr *clkrst = (struct clk_rst_ctlr *)NV_PA_CLK_RST_BASE;
+	u32 reg;
+
+	debug("enable_cpu_clocks entry\n");
+
+	/* Wait for PLL-X to lock */
+	do {
+		reg = readl(&clkrst->crc_pll_simple[SIMPLE_PLLX].pll_base);
+	} while ((reg & PLL_LOCK_MASK) == 0);
+
+	/* Wait until all clocks are stable */
+	udelay(PLL_STABILIZATION_DELAY);
+
+	writel(CCLK_BURST_POLICY, &clkrst->crc_cclk_brst_pol);
+	writel(SUPER_CCLK_DIVIDER, &clkrst->crc_super_cclk_div);
+
+	/* Always enable the main CPU complex clocks */
+	clock_enable(PERIPH_ID_CPU);
+	clock_enable(PERIPH_ID_CPULP);
+	clock_enable(PERIPH_ID_CPUG);
+}
+
+static void remove_cpu_resets(void)
+{
+	struct clk_rst_ctlr *clkrst = (struct clk_rst_ctlr *)NV_PA_CLK_RST_BASE;
+	u32 reg;
+
+	debug("remove_cpu_resets entry\n");
+	/* Take the slow non-CPU partition out of reset */
+	reg = readl(&clkrst->crc_rst_cpulp_cmplx_clr);
+	writel((reg | CLR_NONCPURESET), &clkrst->crc_rst_cpulp_cmplx_clr);
+
+	/* Take the fast non-CPU partition out of reset */
+	reg = readl(&clkrst->crc_rst_cpug_cmplx_clr);
+	writel((reg | CLR_NONCPURESET), &clkrst->crc_rst_cpug_cmplx_clr);
+
+	/* Clear the SW-controlled reset of the slow cluster */
+	reg = readl(&clkrst->crc_rst_cpulp_cmplx_clr);
+	reg |= (CLR_CPURESET0+CLR_DBGRESET0+CLR_CORERESET0+CLR_CXRESET0);
+	writel(reg, &clkrst->crc_rst_cpulp_cmplx_clr);
+
+	/* Clear the SW-controlled reset of the fast cluster */
+	reg = readl(&clkrst->crc_rst_cpug_cmplx_clr);
+	reg |= (CLR_CPURESET0+CLR_DBGRESET0+CLR_CORERESET0+CLR_CXRESET0);
+	reg |= (CLR_CPURESET1+CLR_DBGRESET1+CLR_CORERESET1+CLR_CXRESET1);
+	reg |= (CLR_CPURESET2+CLR_DBGRESET2+CLR_CORERESET2+CLR_CXRESET2);
+	reg |= (CLR_CPURESET3+CLR_DBGRESET3+CLR_CORERESET3+CLR_CXRESET3);
+	writel(reg, &clkrst->crc_rst_cpug_cmplx_clr);
+}
+
+/**
+ * The T114 requires some special clock initialization, including setting up
+ * the DVC I2C, turning on MSELECT and selecting the G CPU cluster
+ */
+void t114_init_clocks(void)
+{
+	struct clk_rst_ctlr *clkrst =
+			(struct clk_rst_ctlr *)NV_PA_CLK_RST_BASE;
+	struct flow_ctlr *flow = (struct flow_ctlr *)NV_PA_FLOW_BASE;
+	u32 val;
+
+	debug("t114_init_clocks entry\n");
+
+	/* Set active CPU cluster to G */
+	clrbits_le32(&flow->cluster_control, 1);
+
+	writel(SUPER_SCLK_ENB_MASK, &clkrst->crc_super_sclk_div);
+
+	debug("Setting up PLLX\n");
+	init_pllx();
+
+	val = (1 << CLK_SYS_RATE_AHB_RATE_SHIFT);
+	writel(val, &clkrst->crc_clk_sys_rate);
+
+	/* Enable clocks to required peripherals. TBD - minimize this list */
+	debug("Enabling clocks\n");
+
+	clock_set_enable(PERIPH_ID_CACHE2, 1);
+	clock_set_enable(PERIPH_ID_GPIO, 1);
+	clock_set_enable(PERIPH_ID_TMR, 1);
+	clock_set_enable(PERIPH_ID_RTC, 1);
+	clock_set_enable(PERIPH_ID_CPU, 1);
+	clock_set_enable(PERIPH_ID_EMC, 1);
+	clock_set_enable(PERIPH_ID_I2C5, 1);
+	clock_set_enable(PERIPH_ID_FUSE, 1);
+	clock_set_enable(PERIPH_ID_PMC, 1);
+	clock_set_enable(PERIPH_ID_APBDMA, 1);
+	clock_set_enable(PERIPH_ID_MEM, 1);
+	clock_set_enable(PERIPH_ID_IRAMA, 1);
+	clock_set_enable(PERIPH_ID_IRAMB, 1);
+	clock_set_enable(PERIPH_ID_IRAMC, 1);
+	clock_set_enable(PERIPH_ID_IRAMD, 1);
+	clock_set_enable(PERIPH_ID_CORESIGHT, 1);
+	clock_set_enable(PERIPH_ID_MSELECT, 1);
+	clock_set_enable(PERIPH_ID_EMC1, 1);
+	clock_set_enable(PERIPH_ID_MC1, 1);
+	clock_set_enable(PERIPH_ID_DVFS, 1);
+
+	/*
+	 * Set MSELECT clock source as PLLP (00), and ask for a clock
+	 * divider that would set the MSELECT clock at 102MHz for a
+	 * PLLP base of 408MHz.
+	 */
+	clock_ll_set_source_divisor(PERIPH_ID_MSELECT, 0,
+		CLK_DIVIDER(NVBL_PLLP_KHZ, 102000));
+
+	/* I2C5 (DVC) gets CLK_M and a divisor of 17 */
+	clock_ll_set_source_divisor(PERIPH_ID_I2C5, 3, 16);
+
+	/* Give clocks time to stabilize */
+	udelay(1000);
+
+	/* Take required peripherals out of reset */
+	debug("Taking periphs out of reset\n");
+	reset_set_enable(PERIPH_ID_CACHE2, 0);
+	reset_set_enable(PERIPH_ID_GPIO, 0);
+	reset_set_enable(PERIPH_ID_TMR, 0);
+	reset_set_enable(PERIPH_ID_COP, 0);
+	reset_set_enable(PERIPH_ID_EMC, 0);
+	reset_set_enable(PERIPH_ID_I2C5, 0);
+	reset_set_enable(PERIPH_ID_FUSE, 0);
+	reset_set_enable(PERIPH_ID_APBDMA, 0);
+	reset_set_enable(PERIPH_ID_MEM, 0);
+	reset_set_enable(PERIPH_ID_CORESIGHT, 0);
+	reset_set_enable(PERIPH_ID_MSELECT, 0);
+	reset_set_enable(PERIPH_ID_EMC1, 0);
+	reset_set_enable(PERIPH_ID_MC1, 0);
+	reset_set_enable(PERIPH_ID_DVFS, 0);
+
+	debug("t114_init_clocks exit\n");
+}
+
+static bool is_partition_powered(u32 partid)
+{
+	struct pmc_ctlr *pmc = (struct pmc_ctlr *)NV_PA_PMC_BASE;
+	u32 reg;
+
+	/* Get power gate status */
+	reg = readl(&pmc->pmc_pwrgate_status);
+	return !!(reg & (1 << partid));
+}
+
+static bool is_clamp_enabled(u32 partid)
+{
+	struct pmc_ctlr *pmc = (struct pmc_ctlr *)NV_PA_PMC_BASE;
+	u32 reg;
+
+	/* Get clamp status. */
+	reg = readl(&pmc->pmc_clamp_status);
+	return !!(reg & (1 << partid));
+}
+
+static void power_partition(u32 partid)
+{
+	struct pmc_ctlr *pmc = (struct pmc_ctlr *)NV_PA_PMC_BASE;
+
+	debug("%s: part ID = %08X\n", __func__, partid);
+	/* Is the partition already on? */
+	if (!is_partition_powered(partid)) {
+		/* No, toggle the partition power state (OFF -> ON) */
+		debug("power_partition, toggling state\n");
+		writel(START_CP | partid, &pmc->pmc_pwrgate_toggle);
+
+		/* Wait for the power to come up */
+		while (!is_partition_powered(partid))
+			;
+
+		/* Wait for the clamp status to be cleared */
+		while (is_clamp_enabled(partid))
+			;
+
+		/* Give I/O signals time to stabilize */
+		udelay(IO_STABILIZATION_DELAY);
+	}
+}
+
+void powerup_cpus(void)
+{
+	debug("powerup_cpus entry\n");
+
+	/* We boot to the fast cluster */
+	debug("powerup_cpus entry: G cluster\n");
+	/* Power up the fast cluster rail partition */
+	power_partition(CRAIL);
+
+	/* Power up the fast cluster non-CPU partition */
+	power_partition(C0NC);
+
+	/* Power up the fast cluster CPU0 partition */
+	power_partition(CE0);
+}
+
+void start_cpu(u32 reset_vector)
+{
+	u32 imme, inst;
+
+	debug("start_cpu entry, reset_vector = %x\n", reset_vector);
+
+	t114_init_clocks();
+
+	/* Enable VDD_CPU */
+	enable_cpu_power_rail();
+
+	/* Get the CPU(s) running */
+	enable_cpu_clocks();
+
+	/* Enable CoreSight */
+	clock_enable_coresight(1);
+
+	/* Take CPU(s) out of reset */
+	remove_cpu_resets();
+
+	/* Set the entry point for CPU execution from reset */
+
+	/*
+	 * A01P with patched boot ROM; vector hard-coded to 0x4003fffc.
+	 * See nvbug 1193357 for details.
+	 */
+
+	/* mov r0, #lsb(reset_vector) */
+	imme = reset_vector & 0xffff;
+	inst = imme & 0xfff;
+	inst |= ((imme >> 12) << 16);
+	inst |= 0xe3000000;
+	writel(inst, 0x4003fff0);
+
+	/* movt r0, #msb(reset_vector) */
+	imme = (reset_vector >> 16) & 0xffff;
+	inst = imme & 0xfff;
+	inst |= ((imme >> 12) << 16);
+	inst |= 0xe3400000;
+	writel(inst, 0x4003fff4);
+
+	/* bx r0 */
+	writel(0xe12fff10, 0x4003fff8);
+
+	/* b -12 */
+	imme = (u32)-20;
+	inst = (imme >> 2) & 0xffffff;
+	inst |= 0xea000000;
+	writel(inst, 0x4003fffc);
+
+	/* Write to orignal location for compatibility */
+	writel(reset_vector, EXCEP_VECTOR_CPU_RESET_VECTOR);
+
+	/* If the CPU(s) don't already have power, power 'em up */
+	powerup_cpus();
+}
diff --git a/arch/arm/mach-tegra/tegra114/funcmux.c b/arch/arm/mach-tegra/tegra114/funcmux.c
new file mode 100644
index 0000000..52441c7
--- /dev/null
+++ b/arch/arm/mach-tegra/tegra114/funcmux.c
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2010-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/>.
+ */
+
+/* Tegra114 high-level function multiplexing */
+
+#include <common.h>
+#include <asm/arch/clock.h>
+#include <asm/arch/funcmux.h>
+#include <asm/arch/pinmux.h>
+
+int funcmux_select(enum periph_id id, int config)
+{
+	int bad_config = config != FUNCMUX_DEFAULT;
+
+	switch (id) {
+	case PERIPH_ID_UART4:
+		switch (config) {
+		case FUNCMUX_UART4_GMI:
+			pinmux_set_func(PMUX_PINGRP_GMI_A16_PJ7,
+					PMUX_FUNC_UARTD);
+			pinmux_set_func(PMUX_PINGRP_GMI_A17_PB0,
+					PMUX_FUNC_UARTD);
+			pinmux_set_func(PMUX_PINGRP_GMI_A18_PB1,
+					PMUX_FUNC_UARTD);
+			pinmux_set_func(PMUX_PINGRP_GMI_A19_PK7,
+					PMUX_FUNC_UARTD);
+
+			pinmux_set_io(PMUX_PINGRP_GMI_A16_PJ7, PMUX_PIN_OUTPUT);
+			pinmux_set_io(PMUX_PINGRP_GMI_A17_PB0, PMUX_PIN_INPUT);
+			pinmux_set_io(PMUX_PINGRP_GMI_A18_PB1, PMUX_PIN_INPUT);
+			pinmux_set_io(PMUX_PINGRP_GMI_A19_PK7, PMUX_PIN_OUTPUT);
+
+			pinmux_tristate_disable(PMUX_PINGRP_GMI_A16_PJ7);
+			pinmux_tristate_disable(PMUX_PINGRP_GMI_A17_PB0);
+			pinmux_tristate_disable(PMUX_PINGRP_GMI_A18_PB1);
+			pinmux_tristate_disable(PMUX_PINGRP_GMI_A19_PK7);
+			break;
+		}
+		break;
+
+	/* Add other periph IDs here as needed */
+
+	default:
+		debug("%s: invalid periph_id %d", __func__, id);
+		return -1;
+	}
+
+	if (bad_config) {
+		debug("%s: invalid config %d for periph_id %d", __func__,
+		      config, id);
+		return -1;
+	}
+	return 0;
+}
diff --git a/arch/arm/mach-tegra/tegra114/pinmux.c b/arch/arm/mach-tegra/tegra114/pinmux.c
new file mode 100644
index 0000000..3e5acb9
--- /dev/null
+++ b/arch/arm/mach-tegra/tegra114/pinmux.c
@@ -0,0 +1,293 @@
+/*
+ * Copyright (c) 2010-2014, NVIDIA CORPORATION. All rights reserved.
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <asm/arch/pinmux.h>
+
+#define PIN(pin, f0, f1, f2, f3)	\
+	{				\
+		.funcs = {		\
+			PMUX_FUNC_##f0,	\
+			PMUX_FUNC_##f1,	\
+			PMUX_FUNC_##f2,	\
+			PMUX_FUNC_##f3,	\
+		},			\
+	}
+
+#define PIN_RESERVED {}
+
+static const struct pmux_pingrp_desc tegra114_pingroups[] = {
+	/*  pin,                    f0,         f1,       f2,           f3 */
+	/* Offset 0x3000 */
+	PIN(ULPI_DATA0_PO1,         SPI3,       HSI,      UARTA,        ULPI),
+	PIN(ULPI_DATA1_PO2,         SPI3,       HSI,      UARTA,        ULPI),
+	PIN(ULPI_DATA2_PO3,         SPI3,       HSI,      UARTA,        ULPI),
+	PIN(ULPI_DATA3_PO4,         SPI3,       HSI,      UARTA,        ULPI),
+	PIN(ULPI_DATA4_PO5,         SPI2,       HSI,      UARTA,        ULPI),
+	PIN(ULPI_DATA5_PO6,         SPI2,       HSI,      UARTA,        ULPI),
+	PIN(ULPI_DATA6_PO7,         SPI2,       HSI,      UARTA,        ULPI),
+	PIN(ULPI_DATA7_PO0,         SPI2,       HSI,      UARTA,        ULPI),
+	PIN(ULPI_CLK_PY0,           SPI1,       SPI5,     UARTD,        ULPI),
+	PIN(ULPI_DIR_PY1,           SPI1,       SPI5,     UARTD,        ULPI),
+	PIN(ULPI_NXT_PY2,           SPI1,       SPI5,     UARTD,        ULPI),
+	PIN(ULPI_STP_PY3,           SPI1,       SPI5,     UARTD,        ULPI),
+	PIN(DAP3_FS_PP0,            I2S2,       SPI5,     DISPLAYA,     DISPLAYB),
+	PIN(DAP3_DIN_PP1,           I2S2,       SPI5,     DISPLAYA,     DISPLAYB),
+	PIN(DAP3_DOUT_PP2,          I2S2,       SPI5,     DISPLAYA,     DISPLAYB),
+	PIN(DAP3_SCLK_PP3,          I2S2,       SPI5,     DISPLAYA,     DISPLAYB),
+	PIN(PV0,                    USB,        RSVD2,    RSVD3,        RSVD4),
+	PIN(PV1,                    RSVD1,      RSVD2,    RSVD3,        RSVD4),
+	PIN(SDMMC1_CLK_PZ0,         SDMMC1,     CLK12,    RSVD3,        RSVD4),
+	PIN(SDMMC1_CMD_PZ1,         SDMMC1,     SPDIF,    SPI4,         UARTA),
+	PIN(SDMMC1_DAT3_PY4,        SDMMC1,     SPDIF,    SPI4,         UARTA),
+	PIN(SDMMC1_DAT2_PY5,        SDMMC1,     PWM0,     SPI4,         UARTA),
+	PIN(SDMMC1_DAT1_PY6,        SDMMC1,     PWM1,     SPI4,         UARTA),
+	PIN(SDMMC1_DAT0_PY7,        SDMMC1,     RSVD2,    SPI4,         UARTA),
+	PIN_RESERVED,
+	PIN_RESERVED,
+	/* Offset 0x3068 */
+	PIN(CLK2_OUT_PW5,           EXTPERIPH2, RSVD2,    RSVD3,        RSVD4),
+	PIN(CLK2_REQ_PCC5,          DAP,        RSVD2,    RSVD3,        RSVD4),
+	PIN_RESERVED,
+	PIN_RESERVED,
+	PIN_RESERVED,
+	PIN_RESERVED,
+	PIN_RESERVED,
+	PIN_RESERVED,
+	PIN_RESERVED,
+	PIN_RESERVED,
+	PIN_RESERVED,
+	PIN_RESERVED,
+	PIN_RESERVED,
+	PIN_RESERVED,
+	PIN_RESERVED,
+	PIN_RESERVED,
+	PIN_RESERVED,
+	PIN_RESERVED,
+	PIN_RESERVED,
+	PIN_RESERVED,
+	PIN_RESERVED,
+	PIN_RESERVED,
+	PIN_RESERVED,
+	PIN_RESERVED,
+	PIN_RESERVED,
+	PIN_RESERVED,
+	PIN_RESERVED,
+	PIN_RESERVED,
+	PIN_RESERVED,
+	PIN_RESERVED,
+	PIN_RESERVED,
+	PIN_RESERVED,
+	PIN_RESERVED,
+	PIN_RESERVED,
+	PIN_RESERVED,
+	PIN_RESERVED,
+	PIN_RESERVED,
+	PIN_RESERVED,
+	PIN_RESERVED,
+	PIN_RESERVED,
+	PIN_RESERVED,
+	PIN_RESERVED,
+	/* Offset 0x3110 */
+	PIN(HDMI_INT_PN7,           RSVD1,      RSVD2,    RSVD3,        RSVD4),
+	PIN(DDC_SCL_PV4,            I2C4,       RSVD2,    RSVD3,        RSVD4),
+	PIN(DDC_SDA_PV5,            I2C4,       RSVD2,    RSVD3,        RSVD4),
+	PIN_RESERVED,
+	PIN_RESERVED,
+	PIN_RESERVED,
+	PIN_RESERVED,
+	PIN_RESERVED,
+	PIN_RESERVED,
+	PIN_RESERVED,
+	PIN_RESERVED,
+	PIN_RESERVED,
+	PIN_RESERVED,
+	PIN_RESERVED,
+	PIN_RESERVED,
+	PIN_RESERVED,
+	PIN_RESERVED,
+	PIN_RESERVED,
+	PIN_RESERVED,
+	PIN_RESERVED,
+	PIN_RESERVED,
+	/* Offset 0x3164 */
+	PIN(UART2_RXD_PC3,          IRDA,       SPDIF,    UARTA,        SPI4),
+	PIN(UART2_TXD_PC2,          IRDA,       SPDIF,    UARTA,        SPI4),
+	PIN(UART2_RTS_N_PJ6,        UARTA,      UARTB,    RSVD3,        SPI4),
+	PIN(UART2_CTS_N_PJ5,        UARTA,      UARTB,    RSVD3,        SPI4),
+	PIN(UART3_TXD_PW6,          UARTC,      RSVD2,    RSVD3,        SPI4),
+	PIN(UART3_RXD_PW7,          UARTC,      RSVD2,    RSVD3,        SPI4),
+	PIN(UART3_CTS_N_PA1,        UARTC,      SDMMC1,   DTV,          SPI4),
+	PIN(UART3_RTS_N_PC0,        UARTC,      PWM0,     DTV,          DISPLAYA),
+	PIN(PU0,                    OWR,        UARTA,    RSVD3,        RSVD4),
+	PIN(PU1,                    RSVD1,      UARTA,    RSVD3,        RSVD4),
+	PIN(PU2,                    RSVD1,      UARTA,    RSVD3,        RSVD4),
+	PIN(PU3,                    PWM0,       UARTA,    DISPLAYA,     DISPLAYB),
+	PIN(PU4,                    PWM1,       UARTA,    DISPLAYA,     DISPLAYB),
+	PIN(PU5,                    PWM2,       UARTA,    DISPLAYA,     DISPLAYB),
+	PIN(PU6,                    PWM3,       UARTA,    USB,          DISPLAYB),
+	PIN(GEN1_I2C_SDA_PC5,       I2C1,       RSVD2,    RSVD3,        RSVD4),
+	PIN(GEN1_I2C_SCL_PC4,       I2C1,       RSVD2,    RSVD3,        RSVD4),
+	PIN(DAP4_FS_PP4,            I2S3,       RSVD2,    DTV,          RSVD4),
+	PIN(DAP4_DIN_PP5,           I2S3,       RSVD2,    RSVD3,        RSVD4),
+	PIN(DAP4_DOUT_PP6,          I2S3,       RSVD2,    DTV,          RSVD4),
+	PIN(DAP4_SCLK_PP7,          I2S3,       RSVD2,    RSVD3,        RSVD4),
+	PIN(CLK3_OUT_PEE0,          EXTPERIPH3, RSVD2,    RSVD3,        RSVD4),
+	PIN(CLK3_REQ_PEE1,          DEV3,       RSVD2,    RSVD3,        RSVD4),
+	PIN(GMI_WP_N_PC7,           RSVD1,      NAND,     GMI,          GMI_ALT),
+	PIN(GMI_IORDY_PI5,          SDMMC2,     RSVD2,    GMI,          TRACE),
+	PIN(GMI_WAIT_PI7,           SPI4,       NAND,     GMI,          DTV),
+	PIN(GMI_ADV_N_PK0,          RSVD1,      NAND,     GMI,          TRACE),
+	PIN(GMI_CLK_PK1,            SDMMC2,     NAND,     GMI,          TRACE),
+	PIN(GMI_CS0_N_PJ0,          RSVD1,      NAND,     GMI,          USB),
+	PIN(GMI_CS1_N_PJ2,          RSVD1,      NAND,     GMI,          SOC),
+	PIN(GMI_CS2_N_PK3,          SDMMC2,     NAND,     GMI,          TRACE),
+	PIN(GMI_CS3_N_PK4,          SDMMC2,     NAND,     GMI,          GMI_ALT),
+	PIN(GMI_CS4_N_PK2,          USB,        NAND,     GMI,          TRACE),
+	PIN(GMI_CS6_N_PI3,          NAND,       NAND_ALT, GMI,          SPI4),
+	PIN(GMI_CS7_N_PI6,          NAND,       NAND_ALT, GMI,          SDMMC2),
+	PIN(GMI_AD0_PG0,            RSVD1,      NAND,     GMI,          RSVD4),
+	PIN(GMI_AD1_PG1,            RSVD1,      NAND,     GMI,          RSVD4),
+	PIN(GMI_AD2_PG2,            RSVD1,      NAND,     GMI,          RSVD4),
+	PIN(GMI_AD3_PG3,            RSVD1,      NAND,     GMI,          RSVD4),
+	PIN(GMI_AD4_PG4,            RSVD1,      NAND,     GMI,          RSVD4),
+	PIN(GMI_AD5_PG5,            RSVD1,      NAND,     GMI,          SPI4),
+	PIN(GMI_AD6_PG6,            RSVD1,      NAND,     GMI,          SPI4),
+	PIN(GMI_AD7_PG7,            RSVD1,      NAND,     GMI,          SPI4),
+	PIN(GMI_AD8_PH0,            PWM0,       NAND,     GMI,          DTV),
+	PIN(GMI_AD9_PH1,            PWM1,       NAND,     GMI,          CLDVFS),
+	PIN(GMI_AD10_PH2,           PWM2,       NAND,     GMI,          CLDVFS),
+	PIN(GMI_AD11_PH3,           PWM3,       NAND,     GMI,          USB),
+	PIN(GMI_AD12_PH4,           SDMMC2,     NAND,     GMI,          RSVD4),
+	PIN(GMI_AD13_PH5,           SDMMC2,     NAND,     GMI,          RSVD4),
+	PIN(GMI_AD14_PH6,           SDMMC2,     NAND,     GMI,          DTV),
+	PIN(GMI_AD15_PH7,           SDMMC2,     NAND,     GMI,          DTV),
+	PIN(GMI_A16_PJ7,            UARTD,      TRACE,    GMI,          GMI_ALT),
+	PIN(GMI_A17_PB0,            UARTD,      RSVD2,    GMI,          TRACE),
+	PIN(GMI_A18_PB1,            UARTD,      RSVD2,    GMI,          TRACE),
+	PIN(GMI_A19_PK7,            UARTD,      SPI4,     GMI,          TRACE),
+	PIN(GMI_WR_N_PI0,           RSVD1,      NAND,     GMI,          SPI4),
+	PIN(GMI_OE_N_PI1,           RSVD1,      NAND,     GMI,          SOC),
+	PIN(GMI_DQS_P_PJ3,          SDMMC2,     NAND,     GMI,          TRACE),
+	PIN(GMI_RST_N_PI4,          NAND,       NAND_ALT, GMI,          RSVD4),
+	PIN(GEN2_I2C_SCL_PT5,       I2C2,       RSVD2,    GMI,          RSVD4),
+	PIN(GEN2_I2C_SDA_PT6,       I2C2,       RSVD2,    GMI,          RSVD4),
+	PIN(SDMMC4_CLK_PCC4,        SDMMC4,     RSVD2,    GMI,          RSVD4),
+	PIN(SDMMC4_CMD_PT7,         SDMMC4,     RSVD2,    GMI,          RSVD4),
+	PIN(SDMMC4_DAT0_PAA0,       SDMMC4,     SPI3,     GMI,          RSVD4),
+	PIN(SDMMC4_DAT1_PAA1,       SDMMC4,     SPI3,     GMI,          RSVD4),
+	PIN(SDMMC4_DAT2_PAA2,       SDMMC4,     SPI3,     GMI,          RSVD4),
+	PIN(SDMMC4_DAT3_PAA3,       SDMMC4,     SPI3,     GMI,          RSVD4),
+	PIN(SDMMC4_DAT4_PAA4,       SDMMC4,     SPI3,     GMI,          RSVD4),
+	PIN(SDMMC4_DAT5_PAA5,       SDMMC4,     SPI3,     GMI,          RSVD4),
+	PIN(SDMMC4_DAT6_PAA6,       SDMMC4,     SPI3,     GMI,          RSVD4),
+	PIN(SDMMC4_DAT7_PAA7,       SDMMC4,     RSVD2,    GMI,          RSVD4),
+	PIN_RESERVED,
+	/* Offset 0x3284 */
+	PIN(CAM_MCLK_PCC0,          VI,         VI_ALT1,  VI_ALT3,      RSVD4),
+	PIN(PCC1,                   I2S4,       RSVD2,    RSVD3,        RSVD4),
+	PIN(PBB0,                   I2S4,       VI,       VI_ALT1,      VI_ALT3),
+	PIN(CAM_I2C_SCL_PBB1,       VGP1,       I2C3,     RSVD3,        RSVD4),
+	PIN(CAM_I2C_SDA_PBB2,       VGP2,       I2C3,     RSVD3,        RSVD4),
+	PIN(PBB3,                   VGP3,       DISPLAYA, DISPLAYB,     RSVD4),
+	PIN(PBB4,                   VGP4,       DISPLAYA, DISPLAYB,     RSVD4),
+	PIN(PBB5,                   VGP5,       DISPLAYA, DISPLAYB,     RSVD4),
+	PIN(PBB6,                   VGP6,       DISPLAYA, DISPLAYB,     RSVD4),
+	PIN(PBB7,                   I2S4,       RSVD2,    RSVD3,        RSVD4),
+	PIN(PCC2,                   I2S4,       RSVD2,    RSVD3,        RSVD4),
+	PIN(JTAG_RTCK,              RTCK,       RSVD2,    RSVD3,        RSVD4),
+	PIN(PWR_I2C_SCL_PZ6,        I2CPWR,     RSVD2,    RSVD3,        RSVD4),
+	PIN(PWR_I2C_SDA_PZ7,        I2CPWR,     RSVD2,    RSVD3,        RSVD4),
+	PIN(KB_ROW0_PR0,            KBC,        RSVD2,    RSVD3,        RSVD4),
+	PIN(KB_ROW1_PR1,            KBC,        RSVD2,    RSVD3,        RSVD4),
+	PIN(KB_ROW2_PR2,            KBC,        RSVD2,    RSVD3,        RSVD4),
+	PIN(KB_ROW3_PR3,            KBC,        DISPLAYA, RSVD3,        DISPLAYB),
+	PIN(KB_ROW4_PR4,            KBC,        DISPLAYA, SPI2,         DISPLAYB),
+	PIN(KB_ROW5_PR5,            KBC,        DISPLAYA, SPI2,         DISPLAYB),
+	PIN(KB_ROW6_PR6,            KBC,        DISPLAYA, DISPLAYA_ALT, DISPLAYB),
+	PIN(KB_ROW7_PR7,            KBC,        RSVD2,    CLDVFS,       UARTA),
+	PIN(KB_ROW8_PS0,            KBC,        RSVD2,    CLDVFS,       UARTA),
+	PIN(KB_ROW9_PS1,            KBC,        RSVD2,    RSVD3,        UARTA),
+	PIN(KB_ROW10_PS2,           KBC,        RSVD2,    RSVD3,        UARTA),
+	PIN_RESERVED,
+	PIN_RESERVED,
+	PIN_RESERVED,
+	PIN_RESERVED,
+	PIN_RESERVED,
+	/* Offset 0x32fc */
+	PIN(KB_COL0_PQ0,            KBC,        USB,      SPI2,         EMC_DLL),
+	PIN(KB_COL1_PQ1,            KBC,        RSVD2,    SPI2,         EMC_DLL),
+	PIN(KB_COL2_PQ2,            KBC,        RSVD2,    SPI2,         RSVD4),
+	PIN(KB_COL3_PQ3,            KBC,        DISPLAYA, PWM2,         UARTA),
+	PIN(KB_COL4_PQ4,            KBC,        OWR,      SDMMC3,       UARTA),
+	PIN(KB_COL5_PQ5,            KBC,        RSVD2,    SDMMC1,       RSVD4),
+	PIN(KB_COL6_PQ6,            KBC,        RSVD2,    SPI2,         RSVD4),
+	PIN(KB_COL7_PQ7,            KBC,        RSVD2,    SPI2,         RSVD4),
+	PIN(CLK_32K_OUT_PA0,        BLINK,      SOC,      RSVD3,        RSVD4),
+	PIN(SYS_CLK_REQ_PZ5,        SYSCLK,     RSVD2,    RSVD3,        RSVD4),
+	PIN(CORE_PWR_REQ,           PWRON,      RSVD2,    RSVD3,        RSVD4),
+	PIN(CPU_PWR_REQ,            CPU,        RSVD2,    RSVD3,        RSVD4),
+	PIN(PWR_INT_N,              PMI,        RSVD2,    RSVD3,        RSVD4),
+	PIN(CLK_32K_IN,             CLK,        RSVD2,    RSVD3,        RSVD4),
+	PIN(OWR,                    OWR,        RSVD2,    RSVD3,        RSVD4),
+	PIN(DAP1_FS_PN0,            I2S0,       HDA,      GMI,          RSVD4),
+	PIN(DAP1_DIN_PN1,           I2S0,       HDA,      GMI,          RSVD4),
+	PIN(DAP1_DOUT_PN2,          I2S0,       HDA,      GMI,          RSVD4),
+	PIN(DAP1_SCLK_PN3,          I2S0,       HDA,      GMI,          RSVD4),
+	PIN(CLK1_REQ_PEE2,          DAP,        DAP1,     RSVD3,        RSVD4),
+	PIN(CLK1_OUT_PW4,           EXTPERIPH1, DAP2,     RSVD3,        RSVD4),
+	PIN(SPDIF_IN_PK6,           SPDIF,      USB,      RSVD3,        RSVD4),
+	PIN(SPDIF_OUT_PK5,          SPDIF,      RSVD2,    RSVD3,        RSVD4),
+	PIN(DAP2_FS_PA2,            I2S1,       HDA,      RSVD3,        RSVD4),
+	PIN(DAP2_DIN_PA4,           I2S1,       HDA,      RSVD3,        RSVD4),
+	PIN(DAP2_DOUT_PA5,          I2S1,       HDA,      RSVD3,        RSVD4),
+	PIN(DAP2_SCLK_PA3,          I2S1,       HDA,      RSVD3,        RSVD4),
+	PIN(DVFS_PWM_PX0,           SPI6,       CLDVFS,   RSVD3,        RSVD4),
+	PIN(GPIO_X1_AUD_PX1,        SPI6,       RSVD2,    RSVD3,        RSVD4),
+	PIN(GPIO_X3_AUD_PX3,        SPI6,       SPI1,     RSVD3,        RSVD4),
+	PIN(DVFS_CLK_PX2,           SPI6,       CLDVFS,   RSVD3,        RSVD4),
+	PIN(GPIO_X4_AUD_PX4,        RSVD1,      SPI1,     SPI2,         DAP2),
+	PIN(GPIO_X5_AUD_PX5,        RSVD1,      SPI1,     SPI2,         RSVD4),
+	PIN(GPIO_X6_AUD_PX6,        SPI6,       SPI1,     SPI2,         RSVD4),
+	PIN(GPIO_X7_AUD_PX7,        RSVD1,      SPI1,     SPI2,         RSVD4),
+	PIN_RESERVED,
+	PIN_RESERVED,
+	/* Offset 0x3390 */
+	PIN(SDMMC3_CLK_PA6,         SDMMC3,     RSVD2,    RSVD3,        SPI3),
+	PIN(SDMMC3_CMD_PA7,         SDMMC3,     PWM3,     UARTA,        SPI3),
+	PIN(SDMMC3_DAT0_PB7,        SDMMC3,     RSVD2,    RSVD3,        SPI3),
+	PIN(SDMMC3_DAT1_PB6,        SDMMC3,     PWM2,     UARTA,        SPI3),
+	PIN(SDMMC3_DAT2_PB5,        SDMMC3,     PWM1,     DISPLAYA,     SPI3),
+	PIN(SDMMC3_DAT3_PB4,        SDMMC3,     PWM0,     DISPLAYB,     SPI3),
+	PIN_RESERVED,
+	PIN_RESERVED,
+	PIN_RESERVED,
+	PIN_RESERVED,
+	PIN_RESERVED,
+	PIN_RESERVED,
+	PIN_RESERVED,
+	PIN_RESERVED,
+	PIN_RESERVED,
+	PIN_RESERVED,
+	PIN_RESERVED,
+	PIN_RESERVED,
+	PIN_RESERVED,
+	PIN_RESERVED,
+	/* Offset 0x33e0 */
+	PIN(HDMI_CEC_PEE3,          CEC,        SDMMC3,   RSVD3,        SOC),
+	PIN(SDMMC1_WP_N_PV3,        SDMMC1,     CLK12,    SPI4,         UARTA),
+	PIN(SDMMC3_CD_N_PV2,        SDMMC3,     OWR,      RSVD3,        RSVD4),
+	PIN(GPIO_W2_AUD_PW2,        SPI6,       RSVD2,    SPI2,         I2C1),
+	PIN(GPIO_W3_AUD_PW3,        SPI6,       SPI1,     SPI2,         I2C1),
+	PIN(USB_VBUS_EN0_PN4,       USB,        RSVD2,    RSVD3,        RSVD4),
+	PIN(USB_VBUS_EN1_PN5,       USB,        RSVD2,    RSVD3,        RSVD4),
+	PIN(SDMMC3_CLK_LB_IN_PEE5,  SDMMC3,     RSVD2,    RSVD3,        RSVD4),
+	PIN(SDMMC3_CLK_LB_OUT_PEE4, SDMMC3,     RSVD2,    RSVD3,        RSVD4),
+	PIN(GMI_CLK_LB,             SDMMC2,     NAND,     GMI,          RSVD4),
+	PIN(RESET_OUT_N,            RSVD1,      RSVD2,    RSVD3,        RESET_OUT_N),
+};
+const struct pmux_pingrp_desc *tegra_soc_pingroups = tegra114_pingroups;
diff --git a/arch/arm/mach-tegra/tegra124/Kconfig b/arch/arm/mach-tegra/tegra124/Kconfig
new file mode 100644
index 0000000..88f627c
--- /dev/null
+++ b/arch/arm/mach-tegra/tegra124/Kconfig
@@ -0,0 +1,30 @@
+if TEGRA124
+
+choice
+	prompt "Tegra124 board select"
+
+config TARGET_JETSON_TK1
+	bool "NVIDIA Tegra124 Jetson TK1 board"
+
+config TARGET_NYAN_BIG
+	bool "Google/NVIDIA Nyan-big Chrombook"
+	help
+	  Nyan Big is a Tegra124 clamshell board that is very similar
+	  to venice2, but it has a different panel, the sdcard CD and WP
+	  sense are flipped, and it has a different revision of the AS3722
+	  PMIC. The retail name is the Acer Chromebook 13 CB5-311-T7NN
+	  (13.3-inch HD, NVIDIA Tegra K1, 2GB).
+
+config TARGET_VENICE2
+	bool "NVIDIA Tegra124 Venice2"
+
+endchoice
+
+config SYS_SOC
+	default "tegra124"
+
+source "board/nvidia/jetson-tk1/Kconfig"
+source "board/nvidia/nyan-big/Kconfig"
+source "board/nvidia/venice2/Kconfig"
+
+endif
diff --git a/arch/arm/mach-tegra/tegra124/Makefile b/arch/arm/mach-tegra/tegra124/Makefile
new file mode 100644
index 0000000..ef2da29
--- /dev/null
+++ b/arch/arm/mach-tegra/tegra124/Makefile
@@ -0,0 +1,13 @@
+#
+# (C) Copyright 2013-2014
+# NVIDIA Corporation <www.nvidia.com>
+#
+# SPDX-License-Identifier:     GPL-2.0+
+#
+
+obj-$(CONFIG_SPL_BUILD) += cpu.o
+
+obj-y	+= clock.o
+obj-y	+= funcmux.o
+obj-y	+= pinmux.o
+obj-y	+= xusb-padctl.o
diff --git a/arch/arm/mach-tegra/tegra124/clock.c b/arch/arm/mach-tegra/tegra124/clock.c
new file mode 100644
index 0000000..fc8bd19
--- /dev/null
+++ b/arch/arm/mach-tegra/tegra124/clock.c
@@ -0,0 +1,935 @@
+/*
+ * (C) Copyright 2013
+ * NVIDIA Corporation <www.nvidia.com>
+ *
+ * SPDX-License-Identifier:     GPL-2.0+
+ */
+
+/* Tegra124 Clock control functions */
+
+#include <common.h>
+#include <asm/io.h>
+#include <asm/arch/clock.h>
+#include <asm/arch/sysctr.h>
+#include <asm/arch/tegra.h>
+#include <asm/arch-tegra/clk_rst.h>
+#include <asm/arch-tegra/timer.h>
+#include <div64.h>
+#include <fdtdec.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
+ * source. This gives us a clock 'type' and exploits what commonality exists
+ * in the device.
+ *
+ * Letters are obvious, except for T which means CLK_M, and S which means the
+ * clock derived from 32KHz. Beware that CLK_M (also called OSC in the
+ * datasheet) and PLL_M are different things. The former is the basic
+ * clock supplied to the SOC from an external oscillator. The latter is the
+ * memory clock PLL.
+ *
+ * See definitions in clock_id in the header file.
+ */
+enum clock_type_id {
+	CLOCK_TYPE_AXPT,	/* PLL_A, PLL_X, PLL_P, CLK_M */
+	CLOCK_TYPE_MCPA,	/* and so on */
+	CLOCK_TYPE_MCPT,
+	CLOCK_TYPE_PCM,
+	CLOCK_TYPE_PCMT,
+	CLOCK_TYPE_PDCT,
+	CLOCK_TYPE_ACPT,
+	CLOCK_TYPE_ASPTE,
+	CLOCK_TYPE_PMDACD2T,
+	CLOCK_TYPE_PCST,
+
+	CLOCK_TYPE_PC2CC3M,
+	CLOCK_TYPE_PC2CC3S_T,
+	CLOCK_TYPE_PC2CC3M_T,
+	CLOCK_TYPE_PC2CC3M_T16,	/* PC2CC3M_T, but w/16-bit divisor (I2C) */
+	CLOCK_TYPE_MC2CC3P_A,
+	CLOCK_TYPE_M,
+	CLOCK_TYPE_MCPTM2C2C3,
+	CLOCK_TYPE_PC2CC3T_S,
+	CLOCK_TYPE_AC2CC3P_TS2,
+
+	CLOCK_TYPE_COUNT,
+	CLOCK_TYPE_NONE = -1,   /* invalid clock type */
+};
+
+enum {
+	CLOCK_MAX_MUX   = 8     /* number of source options for each clock */
+};
+
+/*
+ * Clock source mux for each clock type. This just converts our enum into
+ * a list of mux sources for use by the code.
+ *
+ * Note:
+ *  The extra column in each clock source array is used to store the mask
+ *  bits in its register for the source.
+ */
+#define CLK(x) CLOCK_ID_ ## x
+static enum clock_id clock_source[CLOCK_TYPE_COUNT][CLOCK_MAX_MUX+1] = {
+	{ CLK(AUDIO),	CLK(XCPU),	CLK(PERIPH),	CLK(OSC),
+		CLK(NONE),	CLK(NONE),	CLK(NONE),	CLK(NONE),
+		MASK_BITS_31_30},
+	{ CLK(MEMORY),	CLK(CGENERAL),	CLK(PERIPH),	CLK(AUDIO),
+		CLK(NONE),	CLK(NONE),	CLK(NONE),	CLK(NONE),
+		MASK_BITS_31_30},
+	{ CLK(MEMORY),	CLK(CGENERAL),	CLK(PERIPH),	CLK(OSC),
+		CLK(NONE),	CLK(NONE),	CLK(NONE),	CLK(NONE),
+		MASK_BITS_31_30},
+	{ CLK(PERIPH),	CLK(CGENERAL),	CLK(MEMORY),	CLK(NONE),
+		CLK(NONE),	CLK(NONE),	CLK(NONE),	CLK(NONE),
+		MASK_BITS_31_30},
+	{ CLK(PERIPH),	CLK(CGENERAL),	CLK(MEMORY),	CLK(OSC),
+		CLK(NONE),	CLK(NONE),	CLK(NONE),	CLK(NONE),
+		MASK_BITS_31_30},
+	{ CLK(PERIPH),	CLK(DISPLAY),	CLK(CGENERAL),	CLK(OSC),
+		CLK(NONE),	CLK(NONE),	CLK(NONE),	CLK(NONE),
+		MASK_BITS_31_30},
+	{ CLK(AUDIO),	CLK(CGENERAL),	CLK(PERIPH),	CLK(OSC),
+		CLK(NONE),	CLK(NONE),	CLK(NONE),	CLK(NONE),
+		MASK_BITS_31_30},
+	{ CLK(AUDIO),	CLK(SFROM32KHZ),	CLK(PERIPH),	CLK(OSC),
+		CLK(EPCI),	CLK(NONE),	CLK(NONE),	CLK(NONE),
+		MASK_BITS_31_29},
+	{ CLK(PERIPH),	CLK(MEMORY),	CLK(DISPLAY),	CLK(AUDIO),
+		CLK(CGENERAL),	CLK(DISPLAY2),	CLK(OSC),	CLK(NONE),
+		MASK_BITS_31_29},
+	{ CLK(PERIPH),	CLK(CGENERAL),	CLK(SFROM32KHZ),	CLK(OSC),
+		CLK(NONE),	CLK(NONE),	CLK(NONE),	CLK(NONE),
+		MASK_BITS_31_28},
+
+	/* Additional clock types on Tegra114+ */
+	/* CLOCK_TYPE_PC2CC3M */
+	{ CLK(PERIPH),	CLK(CGENERAL2),	CLK(CGENERAL),	CLK(CGENERAL3),
+		CLK(MEMORY),	CLK(NONE),	CLK(NONE),	CLK(NONE),
+		MASK_BITS_31_29},
+	/* CLOCK_TYPE_PC2CC3S_T */
+	{ CLK(PERIPH),	CLK(CGENERAL2),	CLK(CGENERAL),	CLK(CGENERAL3),
+		CLK(SFROM32KHZ), CLK(NONE),	CLK(OSC),	CLK(NONE),
+		MASK_BITS_31_29},
+	/* CLOCK_TYPE_PC2CC3M_T */
+	{ CLK(PERIPH),	CLK(CGENERAL2),	CLK(CGENERAL),	CLK(CGENERAL3),
+		CLK(MEMORY),	CLK(NONE),	CLK(OSC),	CLK(NONE),
+		MASK_BITS_31_29},
+	/* CLOCK_TYPE_PC2CC3M_T, w/16-bit divisor (I2C) */
+	{ CLK(PERIPH),	CLK(CGENERAL2),	CLK(CGENERAL),	CLK(CGENERAL3),
+		CLK(MEMORY),	CLK(NONE),	CLK(OSC),	CLK(NONE),
+		MASK_BITS_31_29},
+	/* CLOCK_TYPE_MC2CC3P_A */
+	{ CLK(MEMORY),	CLK(CGENERAL2),	CLK(CGENERAL),	CLK(CGENERAL3),
+		CLK(PERIPH),	CLK(NONE),	CLK(AUDIO),	CLK(NONE),
+		MASK_BITS_31_29},
+	/* CLOCK_TYPE_M */
+	{ CLK(MEMORY),		CLK(NONE),	CLK(NONE),	CLK(NONE),
+		CLK(NONE),	CLK(NONE),	CLK(NONE),	CLK(NONE),
+		MASK_BITS_31_30},
+	/* CLOCK_TYPE_MCPTM2C2C3 */
+	{ CLK(MEMORY),	CLK(CGENERAL),	CLK(PERIPH),	CLK(OSC),
+		CLK(MEMORY2),	CLK(CGENERAL2),	CLK(CGENERAL3),	CLK(NONE),
+		MASK_BITS_31_29},
+	/* CLOCK_TYPE_PC2CC3T_S */
+	{ CLK(PERIPH),	CLK(CGENERAL2),	CLK(CGENERAL),	CLK(CGENERAL3),
+		CLK(OSC),	CLK(NONE),	CLK(SFROM32KHZ), CLK(NONE),
+		MASK_BITS_31_29},
+	/* CLOCK_TYPE_AC2CC3P_TS2 */
+	{ CLK(AUDIO),	CLK(CGENERAL2),	CLK(CGENERAL),	CLK(CGENERAL3),
+		CLK(PERIPH),	CLK(NONE),	CLK(OSC),	CLK(SRC2),
+		MASK_BITS_31_29},
+};
+
+/*
+ * Clock type for each peripheral clock source. We put the name in each
+ * record just so it is easy to match things up
+ */
+#define TYPE(name, type) type
+static enum clock_type_id clock_periph_type[PERIPHC_COUNT] = {
+	/* 0x00 */
+	TYPE(PERIPHC_I2S1,	CLOCK_TYPE_AXPT),
+	TYPE(PERIPHC_I2S2,	CLOCK_TYPE_AXPT),
+	TYPE(PERIPHC_SPDIF_OUT,	CLOCK_TYPE_AXPT),
+	TYPE(PERIPHC_SPDIF_IN,	CLOCK_TYPE_PC2CC3M),
+	TYPE(PERIPHC_PWM,	CLOCK_TYPE_PC2CC3S_T),
+	TYPE(PERIPHC_05h,	CLOCK_TYPE_NONE),
+	TYPE(PERIPHC_SBC2,	CLOCK_TYPE_PC2CC3M_T),
+	TYPE(PERIPHC_SBC3,	CLOCK_TYPE_PC2CC3M_T),
+
+	/* 0x08 */
+	TYPE(PERIPHC_08h,	CLOCK_TYPE_NONE),
+	TYPE(PERIPHC_I2C1,	CLOCK_TYPE_PC2CC3M_T16),
+	TYPE(PERIPHC_I2C5,	CLOCK_TYPE_PC2CC3M_T16),
+	TYPE(PERIPHC_0bh,	CLOCK_TYPE_NONE),
+	TYPE(PERIPHC_0ch,	CLOCK_TYPE_NONE),
+	TYPE(PERIPHC_SBC1,	CLOCK_TYPE_PC2CC3M_T),
+	TYPE(PERIPHC_DISP1,	CLOCK_TYPE_PMDACD2T),
+	TYPE(PERIPHC_DISP2,	CLOCK_TYPE_PMDACD2T),
+
+	/* 0x10 */
+	TYPE(PERIPHC_10h,	CLOCK_TYPE_NONE),
+	TYPE(PERIPHC_11h,	CLOCK_TYPE_NONE),
+	TYPE(PERIPHC_VI,	CLOCK_TYPE_MC2CC3P_A),
+	TYPE(PERIPHC_13h,	CLOCK_TYPE_NONE),
+	TYPE(PERIPHC_SDMMC1,	CLOCK_TYPE_PC2CC3M_T),
+	TYPE(PERIPHC_SDMMC2,	CLOCK_TYPE_PC2CC3M_T),
+	TYPE(PERIPHC_16h,	CLOCK_TYPE_NONE),
+	TYPE(PERIPHC_17h,	CLOCK_TYPE_NONE),
+
+	/* 0x18 */
+	TYPE(PERIPHC_18h,	CLOCK_TYPE_NONE),
+	TYPE(PERIPHC_SDMMC4,	CLOCK_TYPE_PC2CC3M_T),
+	TYPE(PERIPHC_VFIR,	CLOCK_TYPE_PC2CC3M_T),
+	TYPE(PERIPHC_1Bh,	CLOCK_TYPE_NONE),
+	TYPE(PERIPHC_1Ch,	CLOCK_TYPE_NONE),
+	TYPE(PERIPHC_HSI,	CLOCK_TYPE_PC2CC3M_T),
+	TYPE(PERIPHC_UART1,	CLOCK_TYPE_PC2CC3M_T),
+	TYPE(PERIPHC_UART2,	CLOCK_TYPE_PC2CC3M_T),
+
+	/* 0x20 */
+	TYPE(PERIPHC_HOST1X,	CLOCK_TYPE_MC2CC3P_A),
+	TYPE(PERIPHC_21h,	CLOCK_TYPE_NONE),
+	TYPE(PERIPHC_22h,	CLOCK_TYPE_NONE),
+	TYPE(PERIPHC_HDMI,	CLOCK_TYPE_PMDACD2T),
+	TYPE(PERIPHC_24h,	CLOCK_TYPE_NONE),
+	TYPE(PERIPHC_25h,	CLOCK_TYPE_NONE),
+	TYPE(PERIPHC_I2C2,	CLOCK_TYPE_PC2CC3M_T16),
+	TYPE(PERIPHC_EMC,	CLOCK_TYPE_MCPTM2C2C3),
+
+	/* 0x28 */
+	TYPE(PERIPHC_UART3,	CLOCK_TYPE_PC2CC3M_T),
+	TYPE(PERIPHC_29h,	CLOCK_TYPE_NONE),
+	TYPE(PERIPHC_VI_SENSOR,	CLOCK_TYPE_MC2CC3P_A),
+	TYPE(PERIPHC_2bh,	CLOCK_TYPE_NONE),
+	TYPE(PERIPHC_2ch,	CLOCK_TYPE_NONE),
+	TYPE(PERIPHC_SBC4,	CLOCK_TYPE_PC2CC3M_T),
+	TYPE(PERIPHC_I2C3,	CLOCK_TYPE_PC2CC3M_T16),
+	TYPE(PERIPHC_SDMMC3,	CLOCK_TYPE_PC2CC3M_T),
+
+	/* 0x30 */
+	TYPE(PERIPHC_UART4,	CLOCK_TYPE_PC2CC3M_T),
+	TYPE(PERIPHC_UART5,	CLOCK_TYPE_PC2CC3M_T),
+	TYPE(PERIPHC_VDE,	CLOCK_TYPE_PC2CC3M_T),
+	TYPE(PERIPHC_OWR,	CLOCK_TYPE_PC2CC3M_T),
+	TYPE(PERIPHC_NOR,	CLOCK_TYPE_PC2CC3M_T),
+	TYPE(PERIPHC_CSITE,	CLOCK_TYPE_PC2CC3M_T),
+	TYPE(PERIPHC_I2S0,	CLOCK_TYPE_AXPT),
+	TYPE(PERIPHC_DTV,	CLOCK_TYPE_NONE),
+
+	/* 0x38 */
+	TYPE(PERIPHC_38h,	CLOCK_TYPE_NONE),
+	TYPE(PERIPHC_39h,	CLOCK_TYPE_NONE),
+	TYPE(PERIPHC_3ah,	CLOCK_TYPE_NONE),
+	TYPE(PERIPHC_3bh,	CLOCK_TYPE_NONE),
+	TYPE(PERIPHC_MSENC,	CLOCK_TYPE_MC2CC3P_A),
+	TYPE(PERIPHC_TSEC,	CLOCK_TYPE_PC2CC3M_T),
+	TYPE(PERIPHC_3eh,	CLOCK_TYPE_NONE),
+	TYPE(PERIPHC_OSC,	CLOCK_TYPE_NONE),
+
+	/* 0x40 */
+	TYPE(PERIPHC_40h,	CLOCK_TYPE_NONE),	/* start with 0x3b0 */
+	TYPE(PERIPHC_MSELECT,	CLOCK_TYPE_PC2CC3M_T),
+	TYPE(PERIPHC_TSENSOR,	CLOCK_TYPE_PC2CC3T_S),
+	TYPE(PERIPHC_I2S3,	CLOCK_TYPE_AXPT),
+	TYPE(PERIPHC_I2S4,	CLOCK_TYPE_AXPT),
+	TYPE(PERIPHC_I2C4,	CLOCK_TYPE_PC2CC3M_T16),
+	TYPE(PERIPHC_SBC5,	CLOCK_TYPE_PC2CC3M_T),
+	TYPE(PERIPHC_SBC6,	CLOCK_TYPE_PC2CC3M_T),
+
+	/* 0x48 */
+	TYPE(PERIPHC_AUDIO,	CLOCK_TYPE_AC2CC3P_TS2),
+	TYPE(PERIPHC_49h,	CLOCK_TYPE_NONE),
+	TYPE(PERIPHC_DAM0,	CLOCK_TYPE_AC2CC3P_TS2),
+	TYPE(PERIPHC_DAM1,	CLOCK_TYPE_AC2CC3P_TS2),
+	TYPE(PERIPHC_DAM2,	CLOCK_TYPE_AC2CC3P_TS2),
+	TYPE(PERIPHC_HDA2CODEC2X, CLOCK_TYPE_PC2CC3M_T),
+	TYPE(PERIPHC_ACTMON,	CLOCK_TYPE_PC2CC3S_T),
+	TYPE(PERIPHC_EXTPERIPH1, CLOCK_TYPE_ASPTE),
+
+	/* 0x50 */
+	TYPE(PERIPHC_EXTPERIPH2, CLOCK_TYPE_ASPTE),
+	TYPE(PERIPHC_EXTPERIPH3, CLOCK_TYPE_ASPTE),
+	TYPE(PERIPHC_52h,	CLOCK_TYPE_NONE),
+	TYPE(PERIPHC_I2CSLOW,	CLOCK_TYPE_PC2CC3S_T),
+	TYPE(PERIPHC_SYS,	CLOCK_TYPE_NONE),
+	TYPE(PERIPHC_55h,	CLOCK_TYPE_NONE),
+	TYPE(PERIPHC_56h,	CLOCK_TYPE_NONE),
+	TYPE(PERIPHC_57h,	CLOCK_TYPE_NONE),
+
+	/* 0x58 */
+	TYPE(PERIPHC_58h,	CLOCK_TYPE_NONE),
+	TYPE(PERIPHC_59h,	CLOCK_TYPE_NONE),
+	TYPE(PERIPHC_5ah,	CLOCK_TYPE_NONE),
+	TYPE(PERIPHC_5bh,	CLOCK_TYPE_NONE),
+	TYPE(PERIPHC_SATAOOB,	CLOCK_TYPE_PCMT),
+	TYPE(PERIPHC_SATA,	CLOCK_TYPE_PCMT),
+	TYPE(PERIPHC_HDA,	CLOCK_TYPE_PC2CC3M_T),
+	TYPE(PERIPHC_5fh,	CLOCK_TYPE_NONE),
+
+	/* 0x60 */
+	TYPE(PERIPHC_XUSB_CORE_HOST, CLOCK_TYPE_NONE),
+	TYPE(PERIPHC_XUSB_FALCON, CLOCK_TYPE_NONE),
+	TYPE(PERIPHC_XUSB_FS,	CLOCK_TYPE_NONE),
+	TYPE(PERIPHC_XUSB_CORE_DEV, CLOCK_TYPE_NONE),
+	TYPE(PERIPHC_XUSB_SS,	CLOCK_TYPE_NONE),
+	TYPE(PERIPHC_CILAB,	CLOCK_TYPE_NONE),
+	TYPE(PERIPHC_CILCD,	CLOCK_TYPE_NONE),
+	TYPE(PERIPHC_CILE,	CLOCK_TYPE_NONE),
+
+	/* 0x68 */
+	TYPE(PERIPHC_DSIA_LP,	CLOCK_TYPE_NONE),
+	TYPE(PERIPHC_DSIB_LP,	CLOCK_TYPE_NONE),
+	TYPE(PERIPHC_ENTROPY,	CLOCK_TYPE_NONE),
+	TYPE(PERIPHC_DVFS_REF,	CLOCK_TYPE_NONE),
+	TYPE(PERIPHC_DVFS_SOC,	CLOCK_TYPE_NONE),
+	TYPE(PERIPHC_TRACECLKIN, CLOCK_TYPE_NONE),
+	TYPE(PERIPHC_ADX0,	CLOCK_TYPE_NONE),
+	TYPE(PERIPHC_AMX0,	CLOCK_TYPE_NONE),
+
+	/* 0x70 */
+	TYPE(PERIPHC_EMC_LATENCY, CLOCK_TYPE_NONE),
+	TYPE(PERIPHC_SOC_THERM,	CLOCK_TYPE_NONE),
+	TYPE(PERIPHC_72h,	CLOCK_TYPE_NONE),
+	TYPE(PERIPHC_73h,	CLOCK_TYPE_NONE),
+	TYPE(PERIPHC_74h,	CLOCK_TYPE_NONE),
+	TYPE(PERIPHC_75h,	CLOCK_TYPE_NONE),
+	TYPE(PERIPHC_VI_SENSOR2, CLOCK_TYPE_NONE),
+	TYPE(PERIPHC_I2C6,	CLOCK_TYPE_PC2CC3M_T16),
+
+	/* 0x78 */
+	TYPE(PERIPHC_78h,	CLOCK_TYPE_NONE),
+	TYPE(PERIPHC_EMC_DLL,	CLOCK_TYPE_MCPTM2C2C3),
+	TYPE(PERIPHC_HDMI_AUDIO, CLOCK_TYPE_NONE),
+	TYPE(PERIPHC_CLK72MHZ,	CLOCK_TYPE_NONE),
+	TYPE(PERIPHC_ADX1,	CLOCK_TYPE_AC2CC3P_TS2),
+	TYPE(PERIPHC_AMX1,	CLOCK_TYPE_AC2CC3P_TS2),
+	TYPE(PERIPHC_VIC,	CLOCK_TYPE_NONE),
+	TYPE(PERIPHC_7Fh,	CLOCK_TYPE_NONE),
+};
+
+/*
+ * This array translates a periph_id to a periphc_internal_id
+ *
+ * Not present/matched up:
+ *	uint vi_sensor;	 _VI_SENSOR_0,		0x1A8
+ *	SPDIF - which is both 0x08 and 0x0c
+ *
+ */
+#define NONE(name) (-1)
+#define OFFSET(name, value) PERIPHC_ ## name
+static s8 periph_id_to_internal_id[PERIPH_ID_COUNT] = {
+	/* Low word: 31:0 */
+	NONE(CPU),
+	NONE(COP),
+	NONE(TRIGSYS),
+	NONE(ISPB),
+	NONE(RESERVED4),
+	NONE(TMR),
+	PERIPHC_UART1,
+	PERIPHC_UART2,	/* and vfir 0x68 */
+
+	/* 8 */
+	NONE(GPIO),
+	PERIPHC_SDMMC2,
+	PERIPHC_SPDIF_IN,
+	PERIPHC_I2S1,
+	PERIPHC_I2C1,
+	NONE(RESERVED13),
+	PERIPHC_SDMMC1,
+	PERIPHC_SDMMC4,
+
+	/* 16 */
+	NONE(TCW),
+	PERIPHC_PWM,
+	PERIPHC_I2S2,
+	NONE(RESERVED19),
+	PERIPHC_VI,
+	NONE(RESERVED21),
+	NONE(USBD),
+	NONE(ISP),
+
+	/* 24 */
+	NONE(RESERVED24),
+	NONE(RESERVED25),
+	PERIPHC_DISP2,
+	PERIPHC_DISP1,
+	PERIPHC_HOST1X,
+	NONE(VCP),
+	PERIPHC_I2S0,
+	NONE(CACHE2),
+
+	/* Middle word: 63:32 */
+	NONE(MEM),
+	NONE(AHBDMA),
+	NONE(APBDMA),
+	NONE(RESERVED35),
+	NONE(RESERVED36),
+	NONE(STAT_MON),
+	NONE(RESERVED38),
+	NONE(FUSE),
+
+	/* 40 */
+	NONE(KFUSE),
+	PERIPHC_SBC1,		/* SBCx = SPIx */
+	PERIPHC_NOR,
+	NONE(RESERVED43),
+	PERIPHC_SBC2,
+	NONE(XIO),
+	PERIPHC_SBC3,
+	PERIPHC_I2C5,
+
+	/* 48 */
+	NONE(DSI),
+	NONE(RESERVED49),
+	PERIPHC_HSI,
+	PERIPHC_HDMI,
+	NONE(CSI),
+	NONE(RESERVED53),
+	PERIPHC_I2C2,
+	PERIPHC_UART3,
+
+	/* 56 */
+	NONE(MIPI_CAL),
+	PERIPHC_EMC,
+	NONE(USB2),
+	NONE(USB3),
+	NONE(RESERVED60),
+	PERIPHC_VDE,
+	NONE(BSEA),
+	NONE(BSEV),
+
+	/* Upper word 95:64 */
+	NONE(RESERVED64),
+	PERIPHC_UART4,
+	PERIPHC_UART5,
+	PERIPHC_I2C3,
+	PERIPHC_SBC4,
+	PERIPHC_SDMMC3,
+	NONE(PCIE),
+	PERIPHC_OWR,
+
+	/* 72 */
+	NONE(AFI),
+	PERIPHC_CSITE,
+	NONE(PCIEXCLK),
+	NONE(AVPUCQ),
+	NONE(LA),
+	NONE(TRACECLKIN),
+	NONE(SOC_THERM),
+	NONE(DTV),
+
+	/* 80 */
+	NONE(RESERVED80),
+	PERIPHC_I2CSLOW,
+	NONE(DSIB),
+	PERIPHC_TSEC,
+	NONE(RESERVED84),
+	NONE(RESERVED85),
+	NONE(RESERVED86),
+	NONE(EMUCIF),
+
+	/* 88 */
+	NONE(RESERVED88),
+	NONE(XUSB_HOST),
+	NONE(RESERVED90),
+	PERIPHC_MSENC,
+	NONE(RESERVED92),
+	NONE(RESERVED93),
+	NONE(RESERVED94),
+	NONE(XUSB_DEV),
+
+	/* V word: 31:0 */
+	NONE(CPUG),
+	NONE(CPULP),
+	NONE(V_RESERVED2),
+	PERIPHC_MSELECT,
+	NONE(V_RESERVED4),
+	PERIPHC_I2S3,
+	PERIPHC_I2S4,
+	PERIPHC_I2C4,
+
+	/* 104 */
+	PERIPHC_SBC5,
+	PERIPHC_SBC6,
+	PERIPHC_AUDIO,
+	NONE(APBIF),
+	PERIPHC_DAM0,
+	PERIPHC_DAM1,
+	PERIPHC_DAM2,
+	PERIPHC_HDA2CODEC2X,
+
+	/* 112 */
+	NONE(ATOMICS),
+	NONE(V_RESERVED17),
+	NONE(V_RESERVED18),
+	NONE(V_RESERVED19),
+	NONE(V_RESERVED20),
+	NONE(V_RESERVED21),
+	NONE(V_RESERVED22),
+	PERIPHC_ACTMON,
+
+	/* 120 */
+	NONE(EXTPERIPH1),
+	NONE(EXTPERIPH2),
+	NONE(EXTPERIPH3),
+	NONE(OOB),
+	PERIPHC_SATA,
+	PERIPHC_HDA,
+	NONE(TZRAM),
+	NONE(SE),
+
+	/* W word: 31:0 */
+	NONE(HDA2HDMICODEC),
+	NONE(SATACOLD),
+	NONE(W_RESERVED2),
+	NONE(W_RESERVED3),
+	NONE(W_RESERVED4),
+	NONE(W_RESERVED5),
+	NONE(W_RESERVED6),
+	NONE(W_RESERVED7),
+
+	/* 136 */
+	NONE(CEC),
+	NONE(W_RESERVED9),
+	NONE(W_RESERVED10),
+	NONE(W_RESERVED11),
+	NONE(W_RESERVED12),
+	NONE(W_RESERVED13),
+	NONE(XUSB_PADCTL),
+	NONE(W_RESERVED15),
+
+	/* 144 */
+	NONE(W_RESERVED16),
+	NONE(W_RESERVED17),
+	NONE(W_RESERVED18),
+	NONE(W_RESERVED19),
+	NONE(W_RESERVED20),
+	NONE(ENTROPY),
+	NONE(DDS),
+	NONE(W_RESERVED23),
+
+	/* 152 */
+	NONE(DP2),
+	NONE(AMX0),
+	NONE(ADX0),
+	NONE(DVFS),
+	NONE(XUSB_SS),
+	NONE(W_RESERVED29),
+	NONE(W_RESERVED30),
+	NONE(W_RESERVED31),
+
+	/* X word: 31:0 */
+	NONE(SPARE),
+	NONE(X_RESERVED1),
+	NONE(X_RESERVED2),
+	NONE(X_RESERVED3),
+	NONE(CAM_MCLK),
+	NONE(CAM_MCLK2),
+	PERIPHC_I2C6,
+	NONE(X_RESERVED7),
+
+	/* 168 */
+	NONE(X_RESERVED8),
+	NONE(X_RESERVED9),
+	NONE(X_RESERVED10),
+	NONE(VIM2_CLK),
+	NONE(X_RESERVED12),
+	NONE(X_RESERVED13),
+	NONE(EMC_DLL),
+	NONE(X_RESERVED15),
+
+	/* 176 */
+	NONE(HDMI_AUDIO),
+	NONE(CLK72MHZ),
+	NONE(VIC),
+	NONE(X_RESERVED19),
+	NONE(ADX1),
+	NONE(DPAUX),
+	NONE(SOR0),
+	NONE(X_RESERVED23),
+
+	/* 184 */
+	NONE(GPU),
+	NONE(AMX1),
+	NONE(X_RESERVED26),
+	NONE(X_RESERVED27),
+	NONE(X_RESERVED28),
+	NONE(X_RESERVED29),
+	NONE(X_RESERVED30),
+	NONE(X_RESERVED31),
+};
+
+/*
+ * Get the oscillator frequency, from the corresponding hardware configuration
+ * field. Note that Tegra30+ support 3 new higher freqs, but we map back
+ * to the old T20 freqs. Support for the higher oscillators is TBD.
+ */
+enum clock_osc_freq clock_get_osc_freq(void)
+{
+	struct clk_rst_ctlr *clkrst =
+			(struct clk_rst_ctlr *)NV_PA_CLK_RST_BASE;
+	u32 reg;
+
+	reg = readl(&clkrst->crc_osc_ctrl);
+	reg = (reg & OSC_FREQ_MASK) >> OSC_FREQ_SHIFT;
+
+	if (reg & 1)				/* one of the newer freqs */
+		printf("Warning: OSC_FREQ is unsupported! (%d)\n", reg);
+
+	return reg >> 2;	/* Map to most common (T20) freqs */
+}
+
+/* Returns a pointer to the clock source register for a peripheral */
+u32 *get_periph_source_reg(enum periph_id periph_id)
+{
+	struct clk_rst_ctlr *clkrst =
+		(struct clk_rst_ctlr *)NV_PA_CLK_RST_BASE;
+	enum periphc_internal_id internal_id;
+
+	/* Coresight is a special case */
+	if (periph_id == PERIPH_ID_CSI)
+		return &clkrst->crc_clk_src[PERIPH_ID_CSI+1];
+
+	assert(periph_id >= PERIPH_ID_FIRST && periph_id < PERIPH_ID_COUNT);
+	internal_id = periph_id_to_internal_id[periph_id];
+	assert(internal_id != -1);
+	if (internal_id >= PERIPHC_VW_FIRST) {
+		internal_id -= PERIPHC_VW_FIRST;
+		return &clkrst->crc_clk_src_vw[internal_id];
+	} else {
+		return &clkrst->crc_clk_src[internal_id];
+	}
+}
+
+/**
+ * Given a peripheral ID and the required source clock, this returns which
+ * value should be programmed into the source mux for that peripheral.
+ *
+ * There is special code here to handle the one source type with 5 sources.
+ *
+ * @param periph_id	peripheral to start
+ * @param source	PLL id of required parent clock
+ * @param mux_bits	Set to number of bits in mux register: 2 or 4
+ * @param divider_bits Set to number of divider bits (8 or 16)
+ * @return mux value (0-4, or -1 if not found)
+ */
+int get_periph_clock_source(enum periph_id periph_id,
+	enum clock_id parent, int *mux_bits, int *divider_bits)
+{
+	enum clock_type_id type;
+	enum periphc_internal_id internal_id;
+	int mux;
+
+	assert(clock_periph_id_isvalid(periph_id));
+
+	internal_id = periph_id_to_internal_id[periph_id];
+	assert(periphc_internal_id_isvalid(internal_id));
+
+	type = clock_periph_type[internal_id];
+	assert(clock_type_id_isvalid(type));
+
+	*mux_bits = clock_source[type][CLOCK_MAX_MUX];
+
+	if (type == CLOCK_TYPE_PC2CC3M_T16)
+		*divider_bits = 16;
+	else
+		*divider_bits = 8;
+
+	for (mux = 0; mux < CLOCK_MAX_MUX; mux++)
+		if (clock_source[type][mux] == parent)
+			return mux;
+
+	/* if we get here, either us or the caller has made a mistake */
+	printf("Caller requested bad clock: periph=%d, parent=%d\n", periph_id,
+	       parent);
+	return -1;
+}
+
+void clock_set_enable(enum periph_id periph_id, int enable)
+{
+	struct clk_rst_ctlr *clkrst =
+		(struct clk_rst_ctlr *)NV_PA_CLK_RST_BASE;
+	u32 *clk;
+	u32 reg;
+
+	/* Enable/disable the clock to this peripheral */
+	assert(clock_periph_id_isvalid(periph_id));
+	if ((int)periph_id < (int)PERIPH_ID_VW_FIRST)
+		clk = &clkrst->crc_clk_out_enb[PERIPH_REG(periph_id)];
+	else
+		clk = &clkrst->crc_clk_out_enb_vw[PERIPH_REG(periph_id)];
+	reg = readl(clk);
+	if (enable)
+		reg |= PERIPH_MASK(periph_id);
+	else
+		reg &= ~PERIPH_MASK(periph_id);
+	writel(reg, clk);
+}
+
+void reset_set_enable(enum periph_id periph_id, int enable)
+{
+	struct clk_rst_ctlr *clkrst =
+		(struct clk_rst_ctlr *)NV_PA_CLK_RST_BASE;
+	u32 *reset;
+	u32 reg;
+
+	/* Enable/disable reset to the peripheral */
+	assert(clock_periph_id_isvalid(periph_id));
+	if (periph_id < PERIPH_ID_VW_FIRST)
+		reset = &clkrst->crc_rst_dev[PERIPH_REG(periph_id)];
+	else
+		reset = &clkrst->crc_rst_dev_vw[PERIPH_REG(periph_id)];
+	reg = readl(reset);
+	if (enable)
+		reg |= PERIPH_MASK(periph_id);
+	else
+		reg &= ~PERIPH_MASK(periph_id);
+	writel(reg, reset);
+}
+
+#ifdef CONFIG_OF_CONTROL
+/*
+ * Convert a device tree clock ID to our peripheral ID. They are mostly
+ * the same but we are very cautious so we check that a valid clock ID is
+ * provided.
+ *
+ * @param clk_id    Clock ID according to tegra124 device tree binding
+ * @return peripheral ID, or PERIPH_ID_NONE if the clock ID is invalid
+ */
+enum periph_id clk_id_to_periph_id(int clk_id)
+{
+	if (clk_id > PERIPH_ID_COUNT)
+		return PERIPH_ID_NONE;
+
+	switch (clk_id) {
+	case PERIPH_ID_RESERVED4:
+	case PERIPH_ID_RESERVED25:
+	case PERIPH_ID_RESERVED35:
+	case PERIPH_ID_RESERVED36:
+	case PERIPH_ID_RESERVED38:
+	case PERIPH_ID_RESERVED43:
+	case PERIPH_ID_RESERVED49:
+	case PERIPH_ID_RESERVED53:
+	case PERIPH_ID_RESERVED64:
+	case PERIPH_ID_RESERVED84:
+	case PERIPH_ID_RESERVED85:
+	case PERIPH_ID_RESERVED86:
+	case PERIPH_ID_RESERVED88:
+	case PERIPH_ID_RESERVED90:
+	case PERIPH_ID_RESERVED92:
+	case PERIPH_ID_RESERVED93:
+	case PERIPH_ID_RESERVED94:
+	case PERIPH_ID_V_RESERVED2:
+	case PERIPH_ID_V_RESERVED4:
+	case PERIPH_ID_V_RESERVED17:
+	case PERIPH_ID_V_RESERVED18:
+	case PERIPH_ID_V_RESERVED19:
+	case PERIPH_ID_V_RESERVED20:
+	case PERIPH_ID_V_RESERVED21:
+	case PERIPH_ID_V_RESERVED22:
+	case PERIPH_ID_W_RESERVED2:
+	case PERIPH_ID_W_RESERVED3:
+	case PERIPH_ID_W_RESERVED4:
+	case PERIPH_ID_W_RESERVED5:
+	case PERIPH_ID_W_RESERVED6:
+	case PERIPH_ID_W_RESERVED7:
+	case PERIPH_ID_W_RESERVED9:
+	case PERIPH_ID_W_RESERVED10:
+	case PERIPH_ID_W_RESERVED11:
+	case PERIPH_ID_W_RESERVED12:
+	case PERIPH_ID_W_RESERVED13:
+	case PERIPH_ID_W_RESERVED15:
+	case PERIPH_ID_W_RESERVED16:
+	case PERIPH_ID_W_RESERVED17:
+	case PERIPH_ID_W_RESERVED18:
+	case PERIPH_ID_W_RESERVED19:
+	case PERIPH_ID_W_RESERVED20:
+	case PERIPH_ID_W_RESERVED23:
+	case PERIPH_ID_W_RESERVED29:
+	case PERIPH_ID_W_RESERVED30:
+	case PERIPH_ID_W_RESERVED31:
+		return PERIPH_ID_NONE;
+	default:
+		return clk_id;
+	}
+}
+#endif /* CONFIG_OF_CONTROL */
+
+void clock_early_init(void)
+{
+	struct clk_rst_ctlr *clkrst =
+		(struct clk_rst_ctlr *)NV_PA_CLK_RST_BASE;
+
+	tegra30_set_up_pllp();
+
+	/*
+	 * PLLC output frequency set to 600Mhz
+	 * PLLD output frequency set to 925Mhz
+	 */
+	switch (clock_get_osc_freq()) {
+	case CLOCK_OSC_FREQ_12_0: /* OSC is 12Mhz */
+		clock_set_rate(CLOCK_ID_CGENERAL, 600, 12, 0, 8);
+		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_CGENERAL, 600, 26, 0, 8);
+		clock_set_rate(CLOCK_ID_DISPLAY, 925, 26, 0, 12);
+		break;
+
+	case CLOCK_OSC_FREQ_13_0: /* OSC is 13Mhz */
+		clock_set_rate(CLOCK_ID_CGENERAL, 600, 13, 0, 8);
+		clock_set_rate(CLOCK_ID_DISPLAY, 925, 13, 0, 12);
+		break;
+	case CLOCK_OSC_FREQ_19_2:
+	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;
+	}
+
+	/* PLLC_MISC2: Set dynramp_stepA/B. MISC2 maps to pll_out[1] */
+	writel(0x00561600, &clkrst->crc_pll[CLOCK_ID_CGENERAL].pll_out[1]);
+
+	/* PLLC_MISC: Set LOCK_ENABLE */
+	writel(0x01000000, &clkrst->crc_pll[CLOCK_ID_CGENERAL].pll_misc);
+	udelay(2);
+
+	/* PLLD_MISC: Set CLKENABLE, CPCON 12, LFCON 1 */
+	writel(0x40000C10, &clkrst->crc_pll[CLOCK_ID_DISPLAY].pll_misc);
+	udelay(2);
+}
+
+void arch_timer_init(void)
+{
+	struct sysctr_ctlr *sysctr = (struct sysctr_ctlr *)NV_PA_TSC_BASE;
+	u32 freq, val;
+
+	freq = clock_get_rate(CLOCK_ID_OSC);
+	debug("%s: osc freq is %dHz [0x%08X]\n", __func__, freq, freq);
+
+	/* ARM CNTFRQ */
+	asm("mcr p15, 0, %0, c14, c0, 0\n" : : "r" (freq));
+
+	/* Only Tegra114+ has the System Counter regs */
+	debug("%s: setting CNTFID0 to 0x%08X\n", __func__, freq);
+	writel(freq, &sysctr->cntfid0);
+
+	val = readl(&sysctr->cntcr);
+	val |= TSC_CNTCR_ENABLE | TSC_CNTCR_HDBG;
+	writel(val, &sysctr->cntcr);
+	debug("%s: TSC CNTCR = 0x%08X\n", __func__, val);
+}
+
+#define PLLE_SS_CNTL 0x68
+#define  PLLE_SS_CNTL_SSCINCINTR(x) (((x) & 0x3f) << 24)
+#define  PLLE_SS_CNTL_SSCINC(x) (((x) & 0xff) << 16)
+#define  PLLE_SS_CNTL_SSCINVERT (1 << 15)
+#define  PLLE_SS_CNTL_SSCCENTER (1 << 14)
+#define  PLLE_SS_CNTL_SSCBYP (1 << 12)
+#define  PLLE_SS_CNTL_INTERP_RESET (1 << 11)
+#define  PLLE_SS_CNTL_BYPASS_SS (1 << 10)
+#define  PLLE_SS_CNTL_SSCMAX(x) (((x) & 0x1ff) << 0)
+
+#define PLLE_BASE 0x0e8
+#define  PLLE_BASE_ENABLE (1 << 30)
+#define  PLLE_BASE_LOCK_OVERRIDE (1 << 29)
+#define  PLLE_BASE_PLDIV_CML(x) (((x) & 0xf) << 24)
+#define  PLLE_BASE_NDIV(x) (((x) & 0xff) << 8)
+#define  PLLE_BASE_MDIV(x) (((x) & 0xff) << 0)
+
+#define PLLE_MISC 0x0ec
+#define  PLLE_MISC_IDDQ_SWCTL (1 << 14)
+#define  PLLE_MISC_IDDQ_OVERRIDE (1 << 13)
+#define  PLLE_MISC_LOCK_ENABLE (1 << 9)
+#define  PLLE_MISC_PTS (1 << 8)
+#define  PLLE_MISC_VREG_BG_CTRL(x) (((x) & 0x3) << 4)
+#define  PLLE_MISC_VREG_CTRL(x) (((x) & 0x3) << 2)
+
+#define PLLE_AUX 0x48c
+#define  PLLE_AUX_SEQ_ENABLE (1 << 24)
+#define  PLLE_AUX_ENABLE_SWCTL (1 << 4)
+
+int tegra_plle_enable(void)
+{
+	unsigned int m = 1, n = 200, cpcon = 13;
+	u32 value;
+
+	value = readl(NV_PA_CLK_RST_BASE + PLLE_BASE);
+	value &= ~PLLE_BASE_LOCK_OVERRIDE;
+	writel(value, NV_PA_CLK_RST_BASE + PLLE_BASE);
+
+	value = readl(NV_PA_CLK_RST_BASE + PLLE_AUX);
+	value |= PLLE_AUX_ENABLE_SWCTL;
+	value &= ~PLLE_AUX_SEQ_ENABLE;
+	writel(value, NV_PA_CLK_RST_BASE + PLLE_AUX);
+
+	udelay(1);
+
+	value = readl(NV_PA_CLK_RST_BASE + PLLE_MISC);
+	value |= PLLE_MISC_IDDQ_SWCTL;
+	value &= ~PLLE_MISC_IDDQ_OVERRIDE;
+	value |= PLLE_MISC_LOCK_ENABLE;
+	value |= PLLE_MISC_PTS;
+	value |= PLLE_MISC_VREG_BG_CTRL(3);
+	value |= PLLE_MISC_VREG_CTRL(2);
+	writel(value, NV_PA_CLK_RST_BASE + PLLE_MISC);
+
+	udelay(5);
+
+	value = readl(NV_PA_CLK_RST_BASE + PLLE_SS_CNTL);
+	value |= PLLE_SS_CNTL_SSCBYP | PLLE_SS_CNTL_INTERP_RESET |
+		 PLLE_SS_CNTL_BYPASS_SS;
+	writel(value, NV_PA_CLK_RST_BASE + PLLE_SS_CNTL);
+
+	value = readl(NV_PA_CLK_RST_BASE + PLLE_BASE);
+	value &= ~PLLE_BASE_PLDIV_CML(0xf);
+	value &= ~PLLE_BASE_NDIV(0xff);
+	value &= ~PLLE_BASE_MDIV(0xff);
+	value |= PLLE_BASE_PLDIV_CML(cpcon);
+	value |= PLLE_BASE_NDIV(n);
+	value |= PLLE_BASE_MDIV(m);
+	writel(value, NV_PA_CLK_RST_BASE + PLLE_BASE);
+
+	udelay(1);
+
+	value = readl(NV_PA_CLK_RST_BASE + PLLE_BASE);
+	value |= PLLE_BASE_ENABLE;
+	writel(value, NV_PA_CLK_RST_BASE + PLLE_BASE);
+
+	/* wait for lock */
+	udelay(300);
+
+	value = readl(NV_PA_CLK_RST_BASE + PLLE_SS_CNTL);
+	value &= ~PLLE_SS_CNTL_SSCINVERT;
+	value &= ~PLLE_SS_CNTL_SSCCENTER;
+
+	value &= ~PLLE_SS_CNTL_SSCINCINTR(0x3f);
+	value &= ~PLLE_SS_CNTL_SSCINC(0xff);
+	value &= ~PLLE_SS_CNTL_SSCMAX(0x1ff);
+
+	value |= PLLE_SS_CNTL_SSCINCINTR(0x20);
+	value |= PLLE_SS_CNTL_SSCINC(0x01);
+	value |= PLLE_SS_CNTL_SSCMAX(0x25);
+
+	writel(value, NV_PA_CLK_RST_BASE + PLLE_SS_CNTL);
+
+	value = readl(NV_PA_CLK_RST_BASE + PLLE_SS_CNTL);
+	value &= ~PLLE_SS_CNTL_SSCBYP;
+	value &= ~PLLE_SS_CNTL_BYPASS_SS;
+	writel(value, NV_PA_CLK_RST_BASE + PLLE_SS_CNTL);
+
+	udelay(1);
+
+	value = readl(NV_PA_CLK_RST_BASE + PLLE_SS_CNTL);
+	value &= ~PLLE_SS_CNTL_INTERP_RESET;
+	writel(value, NV_PA_CLK_RST_BASE + PLLE_SS_CNTL);
+
+	udelay(1);
+
+	return 0;
+}
diff --git a/arch/arm/mach-tegra/tegra124/cpu.c b/arch/arm/mach-tegra/tegra124/cpu.c
new file mode 100644
index 0000000..974f203
--- /dev/null
+++ b/arch/arm/mach-tegra/tegra124/cpu.c
@@ -0,0 +1,265 @@
+/*
+ * (C) Copyright 2013
+ * NVIDIA Corporation <www.nvidia.com>
+ *
+ * SPDX-License-Identifier:     GPL-2.0+
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <asm/arch/ahb.h>
+#include <asm/arch/clock.h>
+#include <asm/arch/flow.h>
+#include <asm/arch/pinmux.h>
+#include <asm/arch/tegra.h>
+#include <asm/arch-tegra/clk_rst.h>
+#include <asm/arch-tegra/pmc.h>
+#include <asm/arch-tegra/ap.h>
+#include "../cpu.h"
+
+/* Tegra124-specific CPU init code */
+
+static void enable_cpu_power_rail(void)
+{
+	struct pmc_ctlr *pmc = (struct pmc_ctlr *)NV_PA_PMC_BASE;
+
+	debug("enable_cpu_power_rail entry\n");
+
+	/* un-tristate PWR_I2C SCL/SDA, rest of the defaults are correct */
+	pinmux_tristate_disable(PMUX_PINGRP_PWR_I2C_SCL_PZ6);
+	pinmux_tristate_disable(PMUX_PINGRP_PWR_I2C_SDA_PZ7);
+
+	pmic_enable_cpu_vdd();
+
+	/*
+	 * Set CPUPWRGOOD_TIMER - APB clock is 1/2 of SCLK (102MHz),
+	 * set it for 5ms as per SysEng (102MHz*5ms = 510000 (7C830h).
+	 */
+	writel(0x7C830, &pmc->pmc_cpupwrgood_timer);
+
+	/* Set polarity to 0 (normal) and enable CPUPWRREQ_OE */
+	clrbits_le32(&pmc->pmc_cntrl, CPUPWRREQ_POL);
+	setbits_le32(&pmc->pmc_cntrl, CPUPWRREQ_OE);
+}
+
+static void enable_cpu_clocks(void)
+{
+	struct clk_rst_ctlr *clkrst = (struct clk_rst_ctlr *)NV_PA_CLK_RST_BASE;
+	u32 reg;
+
+	debug("enable_cpu_clocks entry\n");
+
+	/* Wait for PLL-X to lock */
+	do {
+		reg = readl(&clkrst->crc_pll_simple[SIMPLE_PLLX].pll_base);
+		debug("%s: PLLX base = 0x%08X\n", __func__, reg);
+	} while ((reg & PLL_LOCK_MASK) == 0);
+
+	debug("%s: PLLX locked, delay for stable clocks\n", __func__);
+	/* Wait until all clocks are stable */
+	udelay(PLL_STABILIZATION_DELAY);
+
+	debug("%s: Setting CCLK_BURST and DIVIDER\n", __func__);
+	writel(CCLK_BURST_POLICY, &clkrst->crc_cclk_brst_pol);
+	writel(SUPER_CCLK_DIVIDER, &clkrst->crc_super_cclk_div);
+
+	debug("%s: Enabling clock to all CPUs\n", __func__);
+	/* Enable the clock to all CPUs */
+	reg = CLR_CPU3_CLK_STP | CLR_CPU2_CLK_STP | CLR_CPU1_CLK_STP |
+		CLR_CPU0_CLK_STP;
+	writel(reg, &clkrst->crc_clk_cpu_cmplx_clr);
+
+	debug("%s: Enabling main CPU complex clocks\n", __func__);
+	/* Always enable the main CPU complex clocks */
+	clock_enable(PERIPH_ID_CPU);
+	clock_enable(PERIPH_ID_CPULP);
+	clock_enable(PERIPH_ID_CPUG);
+
+	debug("%s: Done\n", __func__);
+}
+
+static void remove_cpu_resets(void)
+{
+	struct clk_rst_ctlr *clkrst = (struct clk_rst_ctlr *)NV_PA_CLK_RST_BASE;
+	u32 reg;
+
+	debug("remove_cpu_resets entry\n");
+
+	/* Take the slow and fast partitions out of reset */
+	reg = CLR_NONCPURESET;
+	writel(reg, &clkrst->crc_rst_cpulp_cmplx_clr);
+	writel(reg, &clkrst->crc_rst_cpug_cmplx_clr);
+
+	/* Clear the SW-controlled reset of the slow cluster */
+	reg = CLR_CPURESET0 | CLR_DBGRESET0 | CLR_CORERESET0 | CLR_CXRESET0 |
+		CLR_L2RESET | CLR_PRESETDBG;
+	writel(reg, &clkrst->crc_rst_cpulp_cmplx_clr);
+
+	/* Clear the SW-controlled reset of the 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 |
+		CLR_L2RESET | CLR_PRESETDBG;
+	writel(reg, &clkrst->crc_rst_cpug_cmplx_clr);
+}
+
+/**
+ * The Tegra124 requires some special clock initialization, including setting up
+ * the DVC I2C, turning on MSELECT and selecting the G CPU cluster
+ */
+void tegra124_init_clocks(void)
+{
+	struct flow_ctlr *flow = (struct flow_ctlr *)NV_PA_FLOW_BASE;
+	struct pmc_ctlr *pmc = (struct pmc_ctlr *)NV_PA_PMC_BASE;
+	struct clk_rst_ctlr *clkrst =
+			(struct clk_rst_ctlr *)NV_PA_CLK_RST_BASE;
+	u32 val;
+
+	debug("tegra124_init_clocks entry\n");
+
+	/* Set active CPU cluster to G */
+	clrbits_le32(&flow->cluster_control, 1);
+
+	/* Change the oscillator drive strength */
+	val = readl(&clkrst->crc_osc_ctrl);
+	val &= ~OSC_XOFS_MASK;
+	val |= (OSC_DRIVE_STRENGTH << OSC_XOFS_SHIFT);
+	writel(val, &clkrst->crc_osc_ctrl);
+
+	/* Update same value in PMC_OSC_EDPD_OVER XOFS field for warmboot */
+	val = readl(&pmc->pmc_osc_edpd_over);
+	val &= ~PMC_XOFS_MASK;
+	val |= (OSC_DRIVE_STRENGTH << PMC_XOFS_SHIFT);
+	writel(val, &pmc->pmc_osc_edpd_over);
+
+	/* Set HOLD_CKE_LOW_EN to 1 */
+	setbits_le32(&pmc->pmc_cntrl2, HOLD_CKE_LOW_EN);
+
+	debug("Setting up PLLX\n");
+	init_pllx();
+
+	val = (1 << CLK_SYS_RATE_AHB_RATE_SHIFT);
+	writel(val, &clkrst->crc_clk_sys_rate);
+
+	/* Enable clocks to required peripherals. TBD - minimize this list */
+	debug("Enabling clocks\n");
+
+	clock_set_enable(PERIPH_ID_CACHE2, 1);
+	clock_set_enable(PERIPH_ID_GPIO, 1);
+	clock_set_enable(PERIPH_ID_TMR, 1);
+	clock_set_enable(PERIPH_ID_CPU, 1);
+	clock_set_enable(PERIPH_ID_EMC, 1);
+	clock_set_enable(PERIPH_ID_I2C5, 1);
+	clock_set_enable(PERIPH_ID_APBDMA, 1);
+	clock_set_enable(PERIPH_ID_MEM, 1);
+	clock_set_enable(PERIPH_ID_CORESIGHT, 1);
+	clock_set_enable(PERIPH_ID_MSELECT, 1);
+	clock_set_enable(PERIPH_ID_DVFS, 1);
+
+	/*
+	 * Set MSELECT clock source as PLLP (00), and ask for a clock
+	 * divider that would set the MSELECT clock at 102MHz for a
+	 * PLLP base of 408MHz.
+	 */
+	clock_ll_set_source_divisor(PERIPH_ID_MSELECT, 0,
+				    CLK_DIVIDER(NVBL_PLLP_KHZ, 102000));
+
+	/* Give clock time to stabilize */
+	udelay(IO_STABILIZATION_DELAY);
+
+	/* I2C5 (DVC) gets CLK_M and a divisor of 17 */
+	clock_ll_set_source_divisor(PERIPH_ID_I2C5, 3, 16);
+
+	/* Give clock time to stabilize */
+	udelay(IO_STABILIZATION_DELAY);
+
+	/* Take required peripherals out of reset */
+	debug("Taking periphs out of reset\n");
+	reset_set_enable(PERIPH_ID_CACHE2, 0);
+	reset_set_enable(PERIPH_ID_GPIO, 0);
+	reset_set_enable(PERIPH_ID_TMR, 0);
+	reset_set_enable(PERIPH_ID_COP, 0);
+	reset_set_enable(PERIPH_ID_EMC, 0);
+	reset_set_enable(PERIPH_ID_I2C5, 0);
+	reset_set_enable(PERIPH_ID_APBDMA, 0);
+	reset_set_enable(PERIPH_ID_MEM, 0);
+	reset_set_enable(PERIPH_ID_CORESIGHT, 0);
+	reset_set_enable(PERIPH_ID_MSELECT, 0);
+	reset_set_enable(PERIPH_ID_DVFS, 0);
+
+	debug("tegra124_init_clocks exit\n");
+}
+
+static bool is_partition_powered(u32 partid)
+{
+	struct pmc_ctlr *pmc = (struct pmc_ctlr *)NV_PA_PMC_BASE;
+	u32 reg;
+
+	/* Get power gate status */
+	reg = readl(&pmc->pmc_pwrgate_status);
+	return !!(reg & (1 << partid));
+}
+
+static void power_partition(u32 partid)
+{
+	struct pmc_ctlr *pmc = (struct pmc_ctlr *)NV_PA_PMC_BASE;
+
+	debug("%s: part ID = %08X\n", __func__, partid);
+	/* Is the partition already on? */
+	if (!is_partition_powered(partid)) {
+		/* No, toggle the partition power state (OFF -> ON) */
+		debug("power_partition, toggling state\n");
+		writel(START_CP | partid, &pmc->pmc_pwrgate_toggle);
+
+		/* Wait for the power to come up */
+		while (!is_partition_powered(partid))
+			;
+
+		/* Give I/O signals time to stabilize */
+		udelay(IO_STABILIZATION_DELAY);
+	}
+}
+
+void powerup_cpus(void)
+{
+	debug("powerup_cpus entry\n");
+
+	/* We boot to the fast cluster */
+	debug("powerup_cpus entry: G cluster\n");
+
+	/* Power up the fast cluster rail partition */
+	debug("powerup_cpus: CRAIL\n");
+	power_partition(CRAIL);
+
+	/* Power up the fast cluster non-CPU partition */
+	debug("powerup_cpus: C0NC\n");
+	power_partition(C0NC);
+
+	/* Power up the fast cluster CPU0 partition */
+	debug("powerup_cpus: CE0\n");
+	power_partition(CE0);
+
+	debug("powerup_cpus: done\n");
+}
+
+void start_cpu(u32 reset_vector)
+{
+	struct pmc_ctlr *pmc = (struct pmc_ctlr *)NV_PA_PMC_BASE;
+
+	debug("start_cpu entry, reset_vector = %x\n", reset_vector);
+
+	tegra124_init_clocks();
+
+	/* Set power-gating timer multiplier */
+	writel((MULT_8 << TIMER_MULT_SHIFT) | (MULT_8 << TIMER_MULT_CPU_SHIFT),
+	       &pmc->pmc_pwrgate_timer_mult);
+
+	enable_cpu_power_rail();
+	enable_cpu_clocks();
+	clock_enable_coresight(1);
+	remove_cpu_resets();
+	writel(reset_vector, EXCEP_VECTOR_CPU_RESET_VECTOR);
+	powerup_cpus();
+	debug("start_cpu exit, should continue @ reset_vector\n");
+}
diff --git a/arch/arm/mach-tegra/tegra124/funcmux.c b/arch/arm/mach-tegra/tegra124/funcmux.c
new file mode 100644
index 0000000..cced787
--- /dev/null
+++ b/arch/arm/mach-tegra/tegra124/funcmux.c
@@ -0,0 +1,71 @@
+/*
+ * (C) Copyright 2013
+ * NVIDIA Corporation <www.nvidia.com>
+ *
+ * SPDX-License-Identifier:     GPL-2.0+
+ */
+
+/* Tegra124 high-level function multiplexing */
+
+#include <common.h>
+#include <asm/arch/clock.h>
+#include <asm/arch/funcmux.h>
+#include <asm/arch/pinmux.h>
+
+int funcmux_select(enum periph_id id, int config)
+{
+	int bad_config = config != FUNCMUX_DEFAULT;
+
+	switch (id) {
+	case PERIPH_ID_UART4:
+		switch (config) {
+		case FUNCMUX_UART4_GPIO: /* TXD,RXD,CTS,RTS */
+			pinmux_set_func(PMUX_PINGRP_PJ7, PMUX_FUNC_UARTD);
+			pinmux_set_func(PMUX_PINGRP_PB0, PMUX_FUNC_UARTD);
+			pinmux_set_func(PMUX_PINGRP_PB1, PMUX_FUNC_UARTD);
+			pinmux_set_func(PMUX_PINGRP_PK7, PMUX_FUNC_UARTD);
+
+			pinmux_set_io(PMUX_PINGRP_PJ7, PMUX_PIN_OUTPUT);
+			pinmux_set_io(PMUX_PINGRP_PB0, PMUX_PIN_INPUT);
+			pinmux_set_io(PMUX_PINGRP_PB1, PMUX_PIN_INPUT);
+			pinmux_set_io(PMUX_PINGRP_PK7, PMUX_PIN_OUTPUT);
+
+			pinmux_tristate_disable(PMUX_PINGRP_PJ7);
+			pinmux_tristate_disable(PMUX_PINGRP_PB0);
+			pinmux_tristate_disable(PMUX_PINGRP_PB1);
+			pinmux_tristate_disable(PMUX_PINGRP_PK7);
+			break;
+		}
+		break;
+
+	case PERIPH_ID_UART1:
+		switch (config) {
+		case FUNCMUX_UART1_KBC:
+			pinmux_set_func(PMUX_PINGRP_KB_ROW9_PS1,
+					PMUX_FUNC_UARTA);
+			pinmux_set_func(PMUX_PINGRP_KB_ROW10_PS2,
+					PMUX_FUNC_UARTA);
+
+			pinmux_set_io(PMUX_PINGRP_KB_ROW9_PS1, PMUX_PIN_OUTPUT);
+			pinmux_set_io(PMUX_PINGRP_KB_ROW10_PS2, PMUX_PIN_INPUT);
+
+			pinmux_tristate_disable(PMUX_PINGRP_KB_ROW9_PS1);
+			pinmux_tristate_disable(PMUX_PINGRP_KB_ROW10_PS2);
+			break;
+		}
+		break;
+
+	/* Add other periph IDs here as needed */
+
+	default:
+		debug("%s: invalid periph_id %d", __func__, id);
+		return -1;
+	}
+
+	if (bad_config) {
+		debug("%s: invalid config %d for periph_id %d", __func__,
+		      config, id);
+		return -1;
+	}
+	return 0;
+}
diff --git a/arch/arm/mach-tegra/tegra124/pinmux.c b/arch/arm/mach-tegra/tegra124/pinmux.c
new file mode 100644
index 0000000..c6685ea
--- /dev/null
+++ b/arch/arm/mach-tegra/tegra124/pinmux.c
@@ -0,0 +1,306 @@
+/*
+ * Copyright (c) 2013-2014, NVIDIA CORPORATION. All rights reserved.
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <asm/arch/pinmux.h>
+
+#define PIN(pin, f0, f1, f2, f3)	\
+	{				\
+		.funcs = {		\
+			PMUX_FUNC_##f0,	\
+			PMUX_FUNC_##f1,	\
+			PMUX_FUNC_##f2,	\
+			PMUX_FUNC_##f3,	\
+		},			\
+	}
+
+#define PIN_RESERVED {}
+
+static const struct pmux_pingrp_desc tegra124_pingroups[] = {
+	/*  pin,                    f0,         f1,       f2,           f3 */
+	/* Offset 0x3000 */
+	PIN(ULPI_DATA0_PO1,         SPI3,       HSI,      UARTA,        ULPI),
+	PIN(ULPI_DATA1_PO2,         SPI3,       HSI,      UARTA,        ULPI),
+	PIN(ULPI_DATA2_PO3,         SPI3,       HSI,      UARTA,        ULPI),
+	PIN(ULPI_DATA3_PO4,         SPI3,       HSI,      UARTA,        ULPI),
+	PIN(ULPI_DATA4_PO5,         SPI2,       HSI,      UARTA,        ULPI),
+	PIN(ULPI_DATA5_PO6,         SPI2,       HSI,      UARTA,        ULPI),
+	PIN(ULPI_DATA6_PO7,         SPI2,       HSI,      UARTA,        ULPI),
+	PIN(ULPI_DATA7_PO0,         SPI2,       HSI,      UARTA,        ULPI),
+	PIN(ULPI_CLK_PY0,           SPI1,       SPI5,     UARTD,        ULPI),
+	PIN(ULPI_DIR_PY1,           SPI1,       SPI5,     UARTD,        ULPI),
+	PIN(ULPI_NXT_PY2,           SPI1,       SPI5,     UARTD,        ULPI),
+	PIN(ULPI_STP_PY3,           SPI1,       SPI5,     UARTD,        ULPI),
+	PIN(DAP3_FS_PP0,            I2S2,       SPI5,     DISPLAYA,     DISPLAYB),
+	PIN(DAP3_DIN_PP1,           I2S2,       SPI5,     DISPLAYA,     DISPLAYB),
+	PIN(DAP3_DOUT_PP2,          I2S2,       SPI5,     DISPLAYA,     RSVD4),
+	PIN(DAP3_SCLK_PP3,          I2S2,       SPI5,     RSVD3,        DISPLAYB),
+	PIN(PV0,                    RSVD1,      RSVD2,    RSVD3,        RSVD4),
+	PIN(PV1,                    RSVD1,      RSVD2,    RSVD3,        RSVD4),
+	PIN(SDMMC1_CLK_PZ0,         SDMMC1,     CLK12,    RSVD3,        RSVD4),
+	PIN(SDMMC1_CMD_PZ1,         SDMMC1,     SPDIF,    SPI4,         UARTA),
+	PIN(SDMMC1_DAT3_PY4,        SDMMC1,     SPDIF,    SPI4,         UARTA),
+	PIN(SDMMC1_DAT2_PY5,        SDMMC1,     PWM0,     SPI4,         UARTA),
+	PIN(SDMMC1_DAT1_PY6,        SDMMC1,     PWM1,     SPI4,         UARTA),
+	PIN(SDMMC1_DAT0_PY7,        SDMMC1,     RSVD2,    SPI4,         UARTA),
+	PIN_RESERVED,
+	PIN_RESERVED,
+	/* Offset 0x3068 */
+	PIN(CLK2_OUT_PW5,           EXTPERIPH2, RSVD2,    RSVD3,        RSVD4),
+	PIN(CLK2_REQ_PCC5,          DAP,        RSVD2,    RSVD3,        RSVD4),
+	PIN_RESERVED,
+	PIN_RESERVED,
+	PIN_RESERVED,
+	PIN_RESERVED,
+	PIN_RESERVED,
+	PIN_RESERVED,
+	PIN_RESERVED,
+	PIN_RESERVED,
+	PIN_RESERVED,
+	PIN_RESERVED,
+	PIN_RESERVED,
+	PIN_RESERVED,
+	PIN_RESERVED,
+	PIN_RESERVED,
+	PIN_RESERVED,
+	PIN_RESERVED,
+	PIN_RESERVED,
+	PIN_RESERVED,
+	PIN_RESERVED,
+	PIN_RESERVED,
+	PIN_RESERVED,
+	PIN_RESERVED,
+	PIN_RESERVED,
+	PIN_RESERVED,
+	PIN_RESERVED,
+	PIN_RESERVED,
+	PIN_RESERVED,
+	PIN_RESERVED,
+	PIN_RESERVED,
+	PIN_RESERVED,
+	PIN_RESERVED,
+	PIN_RESERVED,
+	PIN_RESERVED,
+	PIN_RESERVED,
+	PIN_RESERVED,
+	PIN_RESERVED,
+	PIN_RESERVED,
+	PIN_RESERVED,
+	PIN_RESERVED,
+	PIN_RESERVED,
+	/* Offset 0x3110 */
+	PIN(HDMI_INT_PN7,           RSVD1,      RSVD2,    RSVD3,        RSVD4),
+	PIN(DDC_SCL_PV4,            I2C4,       RSVD2,    RSVD3,        RSVD4),
+	PIN(DDC_SDA_PV5,            I2C4,       RSVD2,    RSVD3,        RSVD4),
+	PIN_RESERVED,
+	PIN_RESERVED,
+	PIN_RESERVED,
+	PIN_RESERVED,
+	PIN_RESERVED,
+	PIN_RESERVED,
+	PIN_RESERVED,
+	PIN_RESERVED,
+	PIN_RESERVED,
+	PIN_RESERVED,
+	PIN_RESERVED,
+	PIN_RESERVED,
+	PIN_RESERVED,
+	PIN_RESERVED,
+	PIN_RESERVED,
+	PIN_RESERVED,
+	PIN_RESERVED,
+	PIN_RESERVED,
+	/* Offset 0x3164 */
+	PIN(UART2_RXD_PC3,          IRDA,       SPDIF,    UARTA,        SPI4),
+	PIN(UART2_TXD_PC2,          IRDA,       SPDIF,    UARTA,        SPI4),
+	PIN(UART2_RTS_N_PJ6,        UARTA,      UARTB,    GMI,          SPI4),
+	PIN(UART2_CTS_N_PJ5,        UARTA,      UARTB,    GMI,          SPI4),
+	PIN(UART3_TXD_PW6,          UARTC,      RSVD2,    GMI,          SPI4),
+	PIN(UART3_RXD_PW7,          UARTC,      RSVD2,    GMI,          SPI4),
+	PIN(UART3_CTS_N_PA1,        UARTC,      SDMMC1,   DTV,          GMI),
+	PIN(UART3_RTS_N_PC0,        UARTC,      PWM0,     DTV,          GMI),
+	PIN(PU0,                    OWR,        UARTA,    GMI,          RSVD4),
+	PIN(PU1,                    RSVD1,      UARTA,    GMI,          RSVD4),
+	PIN(PU2,                    RSVD1,      UARTA,    GMI,          RSVD4),
+	PIN(PU3,                    PWM0,       UARTA,    GMI,          DISPLAYB),
+	PIN(PU4,                    PWM1,       UARTA,    GMI,          DISPLAYB),
+	PIN(PU5,                    PWM2,       UARTA,    GMI,          DISPLAYB),
+	PIN(PU6,                    PWM3,       UARTA,    RSVD3,        GMI),
+	PIN(GEN1_I2C_SDA_PC5,       I2C1,       RSVD2,    RSVD3,        RSVD4),
+	PIN(GEN1_I2C_SCL_PC4,       I2C1,       RSVD2,    RSVD3,        RSVD4),
+	PIN(DAP4_FS_PP4,            I2S3,       GMI,      DTV,          RSVD4),
+	PIN(DAP4_DIN_PP5,           I2S3,       GMI,      RSVD3,        RSVD4),
+	PIN(DAP4_DOUT_PP6,          I2S3,       GMI,      DTV,          RSVD4),
+	PIN(DAP4_SCLK_PP7,          I2S3,       GMI,      RSVD3,        RSVD4),
+	PIN(CLK3_OUT_PEE0,          EXTPERIPH3, RSVD2,    RSVD3,        RSVD4),
+	PIN(CLK3_REQ_PEE1,          DEV3,       RSVD2,    RSVD3,        RSVD4),
+	PIN(PC7,                    RSVD1,      RSVD2,    GMI,          GMI_ALT),
+	PIN(PI5,                    SDMMC2,     RSVD2,    GMI,          RSVD4),
+	PIN(PI7,                    RSVD1,      TRACE,    GMI,          DTV),
+	PIN(PK0,                    RSVD1,      SDMMC3,   GMI,          SOC),
+	PIN(PK1,                    SDMMC2,     TRACE,    GMI,          RSVD4),
+	PIN(PJ0,                    RSVD1,      RSVD2,    GMI,          USB),
+	PIN(PJ2,                    RSVD1,      RSVD2,    GMI,          SOC),
+	PIN(PK3,                    SDMMC2,     TRACE,    GMI,          CCLA),
+	PIN(PK4,                    SDMMC2,     RSVD2,    GMI,          GMI_ALT),
+	PIN(PK2,                    RSVD1,      RSVD2,    GMI,          RSVD4),
+	PIN(PI3,                    RSVD1,      RSVD2,    GMI,          SPI4),
+	PIN(PI6,                    RSVD1,      RSVD2,    GMI,          SDMMC2),
+	PIN(PG0,                    RSVD1,      RSVD2,    GMI,          RSVD4),
+	PIN(PG1,                    RSVD1,      RSVD2,    GMI,          RSVD4),
+	PIN(PG2,                    RSVD1,      TRACE,    GMI,          RSVD4),
+	PIN(PG3,                    RSVD1,      TRACE,    GMI,          RSVD4),
+	PIN(PG4,                    RSVD1,      TMDS,     GMI,          SPI4),
+	PIN(PG5,                    RSVD1,      RSVD2,    GMI,          SPI4),
+	PIN(PG6,                    RSVD1,      RSVD2,    GMI,          SPI4),
+	PIN(PG7,                    RSVD1,      RSVD2,    GMI,          SPI4),
+	PIN(PH0,                    PWM0,       TRACE,    GMI,          DTV),
+	PIN(PH1,                    PWM1,       TMDS,     GMI,          DISPLAYA),
+	PIN(PH2,                    PWM2,       TMDS,     GMI,          CLDVFS),
+	PIN(PH3,                    PWM3,       SPI4,     GMI,          CLDVFS),
+	PIN(PH4,                    SDMMC2,     RSVD2,    GMI,          RSVD4),
+	PIN(PH5,                    SDMMC2,     RSVD2,    GMI,          RSVD4),
+	PIN(PH6,                    SDMMC2,     TRACE,    GMI,          DTV),
+	PIN(PH7,                    SDMMC2,     TRACE,    GMI,          DTV),
+	PIN(PJ7,                    UARTD,      RSVD2,    GMI,          GMI_ALT),
+	PIN(PB0,                    UARTD,      RSVD2,    GMI,          RSVD4),
+	PIN(PB1,                    UARTD,      RSVD2,    GMI,          RSVD4),
+	PIN(PK7,                    UARTD,      RSVD2,    GMI,          RSVD4),
+	PIN(PI0,                    RSVD1,      RSVD2,    GMI,          RSVD4),
+	PIN(PI1,                    RSVD1,      RSVD2,    GMI,          RSVD4),
+	PIN(PI2,                    SDMMC2,     TRACE,    GMI,          RSVD4),
+	PIN(PI4,                    SPI4,       TRACE,    GMI,          DISPLAYA),
+	PIN(GEN2_I2C_SCL_PT5,       I2C2,       RSVD2,    GMI,          RSVD4),
+	PIN(GEN2_I2C_SDA_PT6,       I2C2,       RSVD2,    GMI,          RSVD4),
+	PIN(SDMMC4_CLK_PCC4,        SDMMC4,     RSVD2,    GMI,          RSVD4),
+	PIN(SDMMC4_CMD_PT7,         SDMMC4,     RSVD2,    GMI,          RSVD4),
+	PIN(SDMMC4_DAT0_PAA0,       SDMMC4,     SPI3,     GMI,          RSVD4),
+	PIN(SDMMC4_DAT1_PAA1,       SDMMC4,     SPI3,     GMI,          RSVD4),
+	PIN(SDMMC4_DAT2_PAA2,       SDMMC4,     SPI3,     GMI,          RSVD4),
+	PIN(SDMMC4_DAT3_PAA3,       SDMMC4,     SPI3,     GMI,          RSVD4),
+	PIN(SDMMC4_DAT4_PAA4,       SDMMC4,     SPI3,     GMI,          RSVD4),
+	PIN(SDMMC4_DAT5_PAA5,       SDMMC4,     SPI3,     RSVD3,        RSVD4),
+	PIN(SDMMC4_DAT6_PAA6,       SDMMC4,     SPI3,     GMI,          RSVD4),
+	PIN(SDMMC4_DAT7_PAA7,       SDMMC4,     RSVD2,    GMI,          RSVD4),
+	PIN_RESERVED,
+	/* Offset 0x3284 */
+	PIN(CAM_MCLK_PCC0,          VI,         VI_ALT1,  VI_ALT3,      SDMMC2),
+	PIN(PCC1,                   I2S4,       RSVD2,    RSVD3,        SDMMC2),
+	PIN(PBB0,                   VGP6,       VIMCLK2,  SDMMC2,       VIMCLK2_ALT),
+	PIN(CAM_I2C_SCL_PBB1,       VGP1,       I2C3,     RSVD3,        SDMMC2),
+	PIN(CAM_I2C_SDA_PBB2,       VGP2,       I2C3,     RSVD3,        SDMMC2),
+	PIN(PBB3,                   VGP3,       DISPLAYA, DISPLAYB,     SDMMC2),
+	PIN(PBB4,                   VGP4,       DISPLAYA, DISPLAYB,     SDMMC2),
+	PIN(PBB5,                   VGP5,       DISPLAYA, RSVD3,        SDMMC2),
+	PIN(PBB6,                   I2S4,       RSVD2,    DISPLAYB,     SDMMC2),
+	PIN(PBB7,                   I2S4,       RSVD2,    RSVD3,        SDMMC2),
+	PIN(PCC2,                   I2S4,       RSVD2,    SDMMC3,       SDMMC2),
+	PIN(JTAG_RTCK,              RTCK,       RSVD2,    RSVD3,        RSVD4),
+	PIN(PWR_I2C_SCL_PZ6,        I2CPWR,     RSVD2,    RSVD3,        RSVD4),
+	PIN(PWR_I2C_SDA_PZ7,        I2CPWR,     RSVD2,    RSVD3,        RSVD4),
+	PIN(KB_ROW0_PR0,            KBC,        RSVD2,    RSVD3,        RSVD4),
+	PIN(KB_ROW1_PR1,            KBC,        RSVD2,    RSVD3,        RSVD4),
+	PIN(KB_ROW2_PR2,            KBC,        RSVD2,    RSVD3,        RSVD4),
+	PIN(KB_ROW3_PR3,            KBC,        DISPLAYA, SYS,          DISPLAYB),
+	PIN(KB_ROW4_PR4,            KBC,        DISPLAYA, RSVD3,        DISPLAYB),
+	PIN(KB_ROW5_PR5,            KBC,        DISPLAYA, RSVD3,        DISPLAYB),
+	PIN(KB_ROW6_PR6,            KBC,        DISPLAYA, DISPLAYA_ALT, DISPLAYB),
+	PIN(KB_ROW7_PR7,            KBC,        RSVD2,    CLDVFS,       UARTA),
+	PIN(KB_ROW8_PS0,            KBC,        RSVD2,    CLDVFS,       UARTA),
+	PIN(KB_ROW9_PS1,            KBC,        RSVD2,    RSVD3,        UARTA),
+	PIN(KB_ROW10_PS2,           KBC,        RSVD2,    RSVD3,        UARTA),
+	PIN(KB_ROW11_PS3,           KBC,        RSVD2,    RSVD3,        IRDA),
+	PIN(KB_ROW12_PS4,           KBC,        RSVD2,    RSVD3,        IRDA),
+	PIN(KB_ROW13_PS5,           KBC,        RSVD2,    SPI2,         RSVD4),
+	PIN(KB_ROW14_PS6,           KBC,        RSVD2,    SPI2,         RSVD4),
+	PIN(KB_ROW15_PS7,           KBC,        SOC,      RSVD3,        RSVD4),
+	PIN(KB_COL0_PQ0,            KBC,        RSVD2,    SPI2,         RSVD4),
+	PIN(KB_COL1_PQ1,            KBC,        RSVD2,    SPI2,         RSVD4),
+	PIN(KB_COL2_PQ2,            KBC,        RSVD2,    SPI2,         RSVD4),
+	PIN(KB_COL3_PQ3,            KBC,        DISPLAYA, PWM2,         UARTA),
+	PIN(KB_COL4_PQ4,            KBC,        OWR,      SDMMC3,       UARTA),
+	PIN(KB_COL5_PQ5,            KBC,        RSVD2,    SDMMC3,       RSVD4),
+	PIN(KB_COL6_PQ6,            KBC,        RSVD2,    SPI2,         UARTD),
+	PIN(KB_COL7_PQ7,            KBC,        RSVD2,    SPI2,         UARTD),
+	PIN(CLK_32K_OUT_PA0,        BLINK,      SOC,      RSVD3,        RSVD4),
+	PIN_RESERVED,
+	/* Offset 0x3324 */
+	PIN(CORE_PWR_REQ,           PWRON,      RSVD2,    RSVD3,        RSVD4),
+	PIN(CPU_PWR_REQ,            CPU,        RSVD2,    RSVD3,        RSVD4),
+	PIN(PWR_INT_N,              PMI,        RSVD2,    RSVD3,        RSVD4),
+	PIN(CLK_32K_IN,             CLK,        RSVD2,    RSVD3,        RSVD4),
+	PIN(OWR,                    OWR,        RSVD2,    RSVD3,        RSVD4),
+	PIN(DAP1_FS_PN0,            I2S0,       HDA,      GMI,          RSVD4),
+	PIN(DAP1_DIN_PN1,           I2S0,       HDA,      GMI,          RSVD4),
+	PIN(DAP1_DOUT_PN2,          I2S0,       HDA,      GMI,          SATA),
+	PIN(DAP1_SCLK_PN3,          I2S0,       HDA,      GMI,          RSVD4),
+	PIN(DAP_MCLK1_REQ_PEE2,     DAP,        DAP1,     SATA,         RSVD4),
+	PIN(DAP_MCLK1_PW4,          EXTPERIPH1, DAP2,     RSVD3,        RSVD4),
+	PIN(SPDIF_IN_PK6,           SPDIF,      RSVD2,    RSVD3,        I2C3),
+	PIN(SPDIF_OUT_PK5,          SPDIF,      RSVD2,    RSVD3,        I2C3),
+	PIN(DAP2_FS_PA2,            I2S1,       HDA,      GMI,          RSVD4),
+	PIN(DAP2_DIN_PA4,           I2S1,       HDA,      GMI,          RSVD4),
+	PIN(DAP2_DOUT_PA5,          I2S1,       HDA,      GMI,          RSVD4),
+	PIN(DAP2_SCLK_PA3,          I2S1,       HDA,      GMI,          RSVD4),
+	PIN(DVFS_PWM_PX0,           SPI6,       CLDVFS,   GMI,          RSVD4),
+	PIN(GPIO_X1_AUD_PX1,        SPI6,       RSVD2,    GMI,          RSVD4),
+	PIN(GPIO_X3_AUD_PX3,        SPI6,       SPI1,     GMI,          RSVD4),
+	PIN(DVFS_CLK_PX2,           SPI6,       CLDVFS,   GMI,          RSVD4),
+	PIN(GPIO_X4_AUD_PX4,        GMI,        SPI1,     SPI2,         DAP2),
+	PIN(GPIO_X5_AUD_PX5,        GMI,        SPI1,     SPI2,         RSVD4),
+	PIN(GPIO_X6_AUD_PX6,        SPI6,       SPI1,     SPI2,         GMI),
+	PIN(GPIO_X7_AUD_PX7,        RSVD1,      SPI1,     SPI2,         RSVD4),
+	PIN_RESERVED,
+	PIN_RESERVED,
+	/* Offset 0x3390 */
+	PIN(SDMMC3_CLK_PA6,         SDMMC3,     RSVD2,    RSVD3,        SPI3),
+	PIN(SDMMC3_CMD_PA7,         SDMMC3,     PWM3,     UARTA,        SPI3),
+	PIN(SDMMC3_DAT0_PB7,        SDMMC3,     RSVD2,    RSVD3,        SPI3),
+	PIN(SDMMC3_DAT1_PB6,        SDMMC3,     PWM2,     UARTA,        SPI3),
+	PIN(SDMMC3_DAT2_PB5,        SDMMC3,     PWM1,     DISPLAYA,     SPI3),
+	PIN(SDMMC3_DAT3_PB4,        SDMMC3,     PWM0,     DISPLAYB,     SPI3),
+	PIN_RESERVED,
+	PIN_RESERVED,
+	PIN_RESERVED,
+	PIN_RESERVED,
+	PIN_RESERVED,
+	/* Offset 0x33bc */
+	PIN(PEX_L0_RST_N_PDD1,      PE0,        RSVD2,    RSVD3,        RSVD4),
+	PIN(PEX_L0_CLKREQ_N_PDD2,   PE0,        RSVD2,    RSVD3,        RSVD4),
+	PIN(PEX_WAKE_N_PDD3,        PE,         RSVD2,    RSVD3,        RSVD4),
+	PIN_RESERVED,
+	/* Offset 0x33cc */
+	PIN(PEX_L1_RST_N_PDD5,      PE1,        RSVD2,    RSVD3,        RSVD4),
+	PIN(PEX_L1_CLKREQ_N_PDD6,   PE1,        RSVD2,    RSVD3,        RSVD4),
+	PIN_RESERVED,
+	PIN_RESERVED,
+	PIN_RESERVED,
+	/* Offset 0x33e0 */
+	PIN(HDMI_CEC_PEE3,          CEC,        RSVD2,    RSVD3,        RSVD4),
+	PIN(SDMMC1_WP_N_PV3,        SDMMC1,     CLK12,    SPI4,         UARTA),
+	PIN(SDMMC3_CD_N_PV2,        SDMMC3,     OWR,      RSVD3,        RSVD4),
+	PIN(GPIO_W2_AUD_PW2,        SPI6,       RSVD2,    SPI2,         I2C1),
+	PIN(GPIO_W3_AUD_PW3,        SPI6,       SPI1,     SPI2,         I2C1),
+	PIN(USB_VBUS_EN0_PN4,       USB,        RSVD2,    RSVD3,        RSVD4),
+	PIN(USB_VBUS_EN1_PN5,       USB,        RSVD2,    RSVD3,        RSVD4),
+	PIN(SDMMC3_CLK_LB_IN_PEE5,  SDMMC3,     RSVD2,    RSVD3,        RSVD4),
+	PIN(SDMMC3_CLK_LB_OUT_PEE4, SDMMC3,     RSVD2,    RSVD3,        RSVD4),
+	PIN(GMI_CLK_LB,             SDMMC2,     RSVD2,    GMI,          RSVD4),
+	PIN(RESET_OUT_N,            RSVD1,      RSVD2,    RSVD3,        RESET_OUT_N),
+	PIN(KB_ROW16_PT0,           KBC,        RSVD2,    RSVD3,        UARTC),
+	PIN(KB_ROW17_PT1,           KBC,        RSVD2,    RSVD3,        UARTC),
+	PIN(USB_VBUS_EN2_PFF1,      USB,        RSVD2,    RSVD3,        RSVD4),
+	PIN(PFF2,                   SATA,       RSVD2,    RSVD3,        RSVD4),
+	PIN_RESERVED,
+	PIN_RESERVED,
+	PIN_RESERVED,
+	PIN_RESERVED,
+	PIN_RESERVED,
+	/* Offset 0x3430 */
+	PIN(DP_HPD_PFF0,            DP,         RSVD2,    RSVD3,        RSVD4),
+};
+const struct pmux_pingrp_desc *tegra_soc_pingroups = tegra124_pingroups;
diff --git a/arch/arm/mach-tegra/tegra124/xusb-padctl.c b/arch/arm/mach-tegra/tegra124/xusb-padctl.c
new file mode 100644
index 0000000..43af883
--- /dev/null
+++ b/arch/arm/mach-tegra/tegra124/xusb-padctl.c
@@ -0,0 +1,716 @@
+/*
+ * Copyright (c) 2014, NVIDIA CORPORATION.  All rights reserved.
+ *
+ * SPDX-License-Identifier: GPL-2.0
+ */
+
+#define pr_fmt(fmt) "tegra-xusb-padctl: " fmt
+
+#include <common.h>
+#include <errno.h>
+#include <fdtdec.h>
+#include <malloc.h>
+
+#include <asm/io.h>
+
+#include <asm/arch/clock.h>
+#include <asm/arch-tegra/xusb-padctl.h>
+
+#include <dt-bindings/pinctrl/pinctrl-tegra-xusb.h>
+
+#define XUSB_PADCTL_ELPG_PROGRAM 0x01c
+#define XUSB_PADCTL_ELPG_PROGRAM_AUX_MUX_LP0_VCORE_DOWN (1 << 26)
+#define XUSB_PADCTL_ELPG_PROGRAM_AUX_MUX_LP0_CLAMP_EN_EARLY (1 << 25)
+#define XUSB_PADCTL_ELPG_PROGRAM_AUX_MUX_LP0_CLAMP_EN (1 << 24)
+
+#define XUSB_PADCTL_IOPHY_PLL_P0_CTL1 0x040
+#define XUSB_PADCTL_IOPHY_PLL_P0_CTL1_PLL0_LOCKDET (1 << 19)
+#define XUSB_PADCTL_IOPHY_PLL_P0_CTL1_REFCLK_SEL_MASK (0xf << 12)
+#define XUSB_PADCTL_IOPHY_PLL_P0_CTL1_PLL_RST (1 << 1)
+
+#define XUSB_PADCTL_IOPHY_PLL_P0_CTL2 0x044
+#define XUSB_PADCTL_IOPHY_PLL_P0_CTL2_REFCLKBUF_EN (1 << 6)
+#define XUSB_PADCTL_IOPHY_PLL_P0_CTL2_TXCLKREF_EN (1 << 5)
+#define XUSB_PADCTL_IOPHY_PLL_P0_CTL2_TXCLKREF_SEL (1 << 4)
+
+#define XUSB_PADCTL_IOPHY_PLL_S0_CTL1 0x138
+#define XUSB_PADCTL_IOPHY_PLL_S0_CTL1_PLL1_LOCKDET (1 << 27)
+#define XUSB_PADCTL_IOPHY_PLL_S0_CTL1_PLL1_MODE (1 << 24)
+#define XUSB_PADCTL_IOPHY_PLL_S0_CTL1_PLL_PWR_OVRD (1 << 3)
+#define XUSB_PADCTL_IOPHY_PLL_S0_CTL1_PLL_RST (1 << 1)
+#define XUSB_PADCTL_IOPHY_PLL_S0_CTL1_PLL_IDDQ (1 << 0)
+
+#define XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL1 0x148
+#define XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL1_IDDQ_OVRD (1 << 1)
+#define XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL1_IDDQ (1 << 0)
+
+enum tegra124_function {
+	TEGRA124_FUNC_SNPS,
+	TEGRA124_FUNC_XUSB,
+	TEGRA124_FUNC_UART,
+	TEGRA124_FUNC_PCIE,
+	TEGRA124_FUNC_USB3,
+	TEGRA124_FUNC_SATA,
+	TEGRA124_FUNC_RSVD,
+};
+
+static const char *const tegra124_functions[] = {
+	"snps",
+	"xusb",
+	"uart",
+	"pcie",
+	"usb3",
+	"sata",
+	"rsvd",
+};
+
+static const unsigned int tegra124_otg_functions[] = {
+	TEGRA124_FUNC_SNPS,
+	TEGRA124_FUNC_XUSB,
+	TEGRA124_FUNC_UART,
+	TEGRA124_FUNC_RSVD,
+};
+
+static const unsigned int tegra124_usb_functions[] = {
+	TEGRA124_FUNC_SNPS,
+	TEGRA124_FUNC_XUSB,
+};
+
+static const unsigned int tegra124_pci_functions[] = {
+	TEGRA124_FUNC_PCIE,
+	TEGRA124_FUNC_USB3,
+	TEGRA124_FUNC_SATA,
+	TEGRA124_FUNC_RSVD,
+};
+
+struct tegra_xusb_padctl_lane {
+	const char *name;
+
+	unsigned int offset;
+	unsigned int shift;
+	unsigned int mask;
+	unsigned int iddq;
+
+	const unsigned int *funcs;
+	unsigned int num_funcs;
+};
+
+#define TEGRA124_LANE(_name, _offset, _shift, _mask, _iddq, _funcs)	\
+	{								\
+		.name = _name,						\
+		.offset = _offset,					\
+		.shift = _shift,					\
+		.mask = _mask,						\
+		.iddq = _iddq,						\
+		.num_funcs = ARRAY_SIZE(tegra124_##_funcs##_functions),	\
+		.funcs = tegra124_##_funcs##_functions,			\
+	}
+
+static const struct tegra_xusb_padctl_lane tegra124_lanes[] = {
+	TEGRA124_LANE("otg-0",  0x004,  0, 0x3, 0, otg),
+	TEGRA124_LANE("otg-1",  0x004,  2, 0x3, 0, otg),
+	TEGRA124_LANE("otg-2",  0x004,  4, 0x3, 0, otg),
+	TEGRA124_LANE("ulpi-0", 0x004, 12, 0x1, 0, usb),
+	TEGRA124_LANE("hsic-0", 0x004, 14, 0x1, 0, usb),
+	TEGRA124_LANE("hsic-1", 0x004, 15, 0x1, 0, usb),
+	TEGRA124_LANE("pcie-0", 0x134, 16, 0x3, 1, pci),
+	TEGRA124_LANE("pcie-1", 0x134, 18, 0x3, 2, pci),
+	TEGRA124_LANE("pcie-2", 0x134, 20, 0x3, 3, pci),
+	TEGRA124_LANE("pcie-3", 0x134, 22, 0x3, 4, pci),
+	TEGRA124_LANE("pcie-4", 0x134, 24, 0x3, 5, pci),
+	TEGRA124_LANE("sata-0", 0x134, 26, 0x3, 6, pci),
+};
+
+struct tegra_xusb_phy_ops {
+	int (*prepare)(struct tegra_xusb_phy *phy);
+	int (*enable)(struct tegra_xusb_phy *phy);
+	int (*disable)(struct tegra_xusb_phy *phy);
+	int (*unprepare)(struct tegra_xusb_phy *phy);
+};
+
+struct tegra_xusb_phy {
+	const struct tegra_xusb_phy_ops *ops;
+
+	struct tegra_xusb_padctl *padctl;
+};
+
+struct tegra_xusb_padctl_pin {
+	const struct tegra_xusb_padctl_lane *lane;
+
+	unsigned int func;
+	int iddq;
+};
+
+#define MAX_GROUPS 3
+#define MAX_PINS 6
+
+struct tegra_xusb_padctl_group {
+	const char *name;
+
+	const char *pins[MAX_PINS];
+	unsigned int num_pins;
+
+	const char *func;
+	int iddq;
+};
+
+struct tegra_xusb_padctl_config {
+	const char *name;
+
+	struct tegra_xusb_padctl_group groups[MAX_GROUPS];
+	unsigned int num_groups;
+};
+
+struct tegra_xusb_padctl {
+	struct fdt_resource regs;
+
+	unsigned int enable;
+
+	struct tegra_xusb_phy phys[2];
+
+	const struct tegra_xusb_padctl_lane *lanes;
+	unsigned int num_lanes;
+
+	const char *const *functions;
+	unsigned int num_functions;
+
+	struct tegra_xusb_padctl_config config;
+};
+
+static inline u32 padctl_readl(struct tegra_xusb_padctl *padctl,
+			       unsigned long offset)
+{
+	return readl(padctl->regs.start + offset);
+}
+
+static inline void padctl_writel(struct tegra_xusb_padctl *padctl,
+				 u32 value, unsigned long offset)
+{
+	writel(value, padctl->regs.start + offset);
+}
+
+static int tegra_xusb_padctl_enable(struct tegra_xusb_padctl *padctl)
+{
+	u32 value;
+
+	if (padctl->enable++ > 0)
+		return 0;
+
+	value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM);
+	value &= ~XUSB_PADCTL_ELPG_PROGRAM_AUX_MUX_LP0_CLAMP_EN;
+	padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM);
+
+	udelay(100);
+
+	value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM);
+	value &= ~XUSB_PADCTL_ELPG_PROGRAM_AUX_MUX_LP0_CLAMP_EN_EARLY;
+	padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM);
+
+	udelay(100);
+
+	value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM);
+	value &= ~XUSB_PADCTL_ELPG_PROGRAM_AUX_MUX_LP0_VCORE_DOWN;
+	padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM);
+
+	return 0;
+}
+
+static int tegra_xusb_padctl_disable(struct tegra_xusb_padctl *padctl)
+{
+	u32 value;
+
+	if (padctl->enable == 0) {
+		error("tegra-xusb-padctl: unbalanced enable/disable");
+		return 0;
+	}
+
+	if (--padctl->enable > 0)
+		return 0;
+
+	value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM);
+	value |= XUSB_PADCTL_ELPG_PROGRAM_AUX_MUX_LP0_VCORE_DOWN;
+	padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM);
+
+	udelay(100);
+
+	value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM);
+	value |= XUSB_PADCTL_ELPG_PROGRAM_AUX_MUX_LP0_CLAMP_EN_EARLY;
+	padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM);
+
+	udelay(100);
+
+	value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM);
+	value |= XUSB_PADCTL_ELPG_PROGRAM_AUX_MUX_LP0_CLAMP_EN;
+	padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM);
+
+	return 0;
+}
+
+static int phy_prepare(struct tegra_xusb_phy *phy)
+{
+	return tegra_xusb_padctl_enable(phy->padctl);
+}
+
+static int phy_unprepare(struct tegra_xusb_phy *phy)
+{
+	return tegra_xusb_padctl_disable(phy->padctl);
+}
+
+static int pcie_phy_enable(struct tegra_xusb_phy *phy)
+{
+	struct tegra_xusb_padctl *padctl = phy->padctl;
+	int err = -ETIMEDOUT;
+	unsigned long start;
+	u32 value;
+
+	value = padctl_readl(padctl, XUSB_PADCTL_IOPHY_PLL_P0_CTL1);
+	value &= ~XUSB_PADCTL_IOPHY_PLL_P0_CTL1_REFCLK_SEL_MASK;
+	padctl_writel(padctl, value, XUSB_PADCTL_IOPHY_PLL_P0_CTL1);
+
+	value = padctl_readl(padctl, XUSB_PADCTL_IOPHY_PLL_P0_CTL2);
+	value |= XUSB_PADCTL_IOPHY_PLL_P0_CTL2_REFCLKBUF_EN |
+		 XUSB_PADCTL_IOPHY_PLL_P0_CTL2_TXCLKREF_EN |
+		 XUSB_PADCTL_IOPHY_PLL_P0_CTL2_TXCLKREF_SEL;
+	padctl_writel(padctl, value, XUSB_PADCTL_IOPHY_PLL_P0_CTL2);
+
+	value = padctl_readl(padctl, XUSB_PADCTL_IOPHY_PLL_P0_CTL1);
+	value |= XUSB_PADCTL_IOPHY_PLL_P0_CTL1_PLL_RST;
+	padctl_writel(padctl, value, XUSB_PADCTL_IOPHY_PLL_P0_CTL1);
+
+	start = get_timer(0);
+
+	while (get_timer(start) < 50) {
+		value = padctl_readl(padctl, XUSB_PADCTL_IOPHY_PLL_P0_CTL1);
+		if (value & XUSB_PADCTL_IOPHY_PLL_P0_CTL1_PLL0_LOCKDET) {
+			err = 0;
+			break;
+		}
+	}
+
+	return err;
+}
+
+static int pcie_phy_disable(struct tegra_xusb_phy *phy)
+{
+	struct tegra_xusb_padctl *padctl = phy->padctl;
+	u32 value;
+
+	value = padctl_readl(padctl, XUSB_PADCTL_IOPHY_PLL_P0_CTL1);
+	value &= ~XUSB_PADCTL_IOPHY_PLL_P0_CTL1_PLL_RST;
+	padctl_writel(padctl, value, XUSB_PADCTL_IOPHY_PLL_P0_CTL1);
+
+	return 0;
+}
+
+static int sata_phy_enable(struct tegra_xusb_phy *phy)
+{
+	struct tegra_xusb_padctl *padctl = phy->padctl;
+	int err = -ETIMEDOUT;
+	unsigned long start;
+	u32 value;
+
+	value = padctl_readl(padctl, XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL1);
+	value &= ~XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL1_IDDQ_OVRD;
+	value &= ~XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL1_IDDQ;
+	padctl_writel(padctl, value, XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL1);
+
+	value = padctl_readl(padctl, XUSB_PADCTL_IOPHY_PLL_S0_CTL1);
+	value &= ~XUSB_PADCTL_IOPHY_PLL_S0_CTL1_PLL_PWR_OVRD;
+	value &= ~XUSB_PADCTL_IOPHY_PLL_S0_CTL1_PLL_IDDQ;
+	padctl_writel(padctl, value, XUSB_PADCTL_IOPHY_PLL_S0_CTL1);
+
+	value = padctl_readl(padctl, XUSB_PADCTL_IOPHY_PLL_S0_CTL1);
+	value |= XUSB_PADCTL_IOPHY_PLL_S0_CTL1_PLL1_MODE;
+	padctl_writel(padctl, value, XUSB_PADCTL_IOPHY_PLL_S0_CTL1);
+
+	value = padctl_readl(padctl, XUSB_PADCTL_IOPHY_PLL_S0_CTL1);
+	value |= XUSB_PADCTL_IOPHY_PLL_S0_CTL1_PLL_RST;
+	padctl_writel(padctl, value, XUSB_PADCTL_IOPHY_PLL_S0_CTL1);
+
+	start = get_timer(0);
+
+	while (get_timer(start) < 50) {
+		value = padctl_readl(padctl, XUSB_PADCTL_IOPHY_PLL_S0_CTL1);
+		if (value & XUSB_PADCTL_IOPHY_PLL_S0_CTL1_PLL1_LOCKDET) {
+			err = 0;
+			break;
+		}
+	}
+
+	return err;
+}
+
+static int sata_phy_disable(struct tegra_xusb_phy *phy)
+{
+	struct tegra_xusb_padctl *padctl = phy->padctl;
+	u32 value;
+
+	value = padctl_readl(padctl, XUSB_PADCTL_IOPHY_PLL_S0_CTL1);
+	value &= ~XUSB_PADCTL_IOPHY_PLL_S0_CTL1_PLL_RST;
+	padctl_writel(padctl, value, XUSB_PADCTL_IOPHY_PLL_S0_CTL1);
+
+	value = padctl_readl(padctl, XUSB_PADCTL_IOPHY_PLL_S0_CTL1);
+	value &= ~XUSB_PADCTL_IOPHY_PLL_S0_CTL1_PLL1_MODE;
+	padctl_writel(padctl, value, XUSB_PADCTL_IOPHY_PLL_S0_CTL1);
+
+	value = padctl_readl(padctl, XUSB_PADCTL_IOPHY_PLL_S0_CTL1);
+	value |= XUSB_PADCTL_IOPHY_PLL_S0_CTL1_PLL_PWR_OVRD;
+	value |= XUSB_PADCTL_IOPHY_PLL_S0_CTL1_PLL_IDDQ;
+	padctl_writel(padctl, value, XUSB_PADCTL_IOPHY_PLL_S0_CTL1);
+
+	value = padctl_readl(padctl, XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL1);
+	value |= ~XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL1_IDDQ_OVRD;
+	value |= ~XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL1_IDDQ;
+	padctl_writel(padctl, value, XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL1);
+
+	return 0;
+}
+
+static const struct tegra_xusb_phy_ops pcie_phy_ops = {
+	.prepare = phy_prepare,
+	.enable = pcie_phy_enable,
+	.disable = pcie_phy_disable,
+	.unprepare = phy_unprepare,
+};
+
+static const struct tegra_xusb_phy_ops sata_phy_ops = {
+	.prepare = phy_prepare,
+	.enable = sata_phy_enable,
+	.disable = sata_phy_disable,
+	.unprepare = phy_unprepare,
+};
+
+static struct tegra_xusb_padctl *padctl = &(struct tegra_xusb_padctl) {
+	.phys = {
+		[0] = {
+			.ops = &pcie_phy_ops,
+		},
+		[1] = {
+			.ops = &sata_phy_ops,
+		},
+	},
+};
+
+static const struct tegra_xusb_padctl_lane *
+tegra_xusb_padctl_find_lane(struct tegra_xusb_padctl *padctl, const char *name)
+{
+	unsigned int i;
+
+	for (i = 0; i < padctl->num_lanes; i++)
+		if (strcmp(name, padctl->lanes[i].name) == 0)
+			return &padctl->lanes[i];
+
+	return NULL;
+}
+
+static int
+tegra_xusb_padctl_group_parse_dt(struct tegra_xusb_padctl *padctl,
+				 struct tegra_xusb_padctl_group *group,
+				 const void *fdt, int node)
+{
+	unsigned int i;
+	int len, err;
+
+	group->name = fdt_get_name(fdt, node, &len);
+
+	len = fdt_count_strings(fdt, node, "nvidia,lanes");
+	if (len < 0) {
+		error("tegra-xusb-padctl: failed to parse \"nvidia,lanes\" property");
+		return -EINVAL;
+	}
+
+	group->num_pins = len;
+
+	for (i = 0; i < group->num_pins; i++) {
+		err = fdt_get_string_index(fdt, node, "nvidia,lanes", i,
+					   &group->pins[i]);
+		if (err < 0) {
+			error("tegra-xusb-padctl: failed to read string from \"nvidia,lanes\" property");
+			return -EINVAL;
+		}
+	}
+
+	group->num_pins = len;
+
+	err = fdt_get_string(fdt, node, "nvidia,function", &group->func);
+	if (err < 0) {
+		error("tegra-xusb-padctl: failed to parse \"nvidia,func\" property");
+		return -EINVAL;
+	}
+
+	group->iddq = fdtdec_get_int(fdt, node, "nvidia,iddq", -1);
+
+	return 0;
+}
+
+static int tegra_xusb_padctl_find_function(struct tegra_xusb_padctl *padctl,
+					   const char *name)
+{
+	unsigned int i;
+
+	for (i = 0; i < padctl->num_functions; i++)
+		if (strcmp(name, padctl->functions[i]) == 0)
+			return i;
+
+	return -ENOENT;
+}
+
+static int
+tegra_xusb_padctl_lane_find_function(struct tegra_xusb_padctl *padctl,
+				     const struct tegra_xusb_padctl_lane *lane,
+				     const char *name)
+{
+	unsigned int i;
+	int func;
+
+	func = tegra_xusb_padctl_find_function(padctl, name);
+	if (func < 0)
+		return func;
+
+	for (i = 0; i < lane->num_funcs; i++)
+		if (lane->funcs[i] == func)
+			return i;
+
+	return -ENOENT;
+}
+
+static int
+tegra_xusb_padctl_group_apply(struct tegra_xusb_padctl *padctl,
+			      const struct tegra_xusb_padctl_group *group)
+{
+	unsigned int i;
+
+	for (i = 0; i < group->num_pins; i++) {
+		const struct tegra_xusb_padctl_lane *lane;
+		unsigned int func;
+		u32 value;
+
+		lane = tegra_xusb_padctl_find_lane(padctl, group->pins[i]);
+		if (!lane) {
+			error("tegra-xusb-padctl: no lane for pin %s",
+			      group->pins[i]);
+			continue;
+		}
+
+		func = tegra_xusb_padctl_lane_find_function(padctl, lane,
+							    group->func);
+		if (func < 0) {
+			error("tegra-xusb-padctl: function %s invalid for lane %s: %d",
+			      group->func, lane->name, func);
+			continue;
+		}
+
+		value = padctl_readl(padctl, lane->offset);
+
+		/* set pin function */
+		value &= ~(lane->mask << lane->shift);
+		value |= func << lane->shift;
+
+		/*
+		 * Set IDDQ if supported on the lane and specified in the
+		 * configuration.
+		 */
+		if (lane->iddq > 0 && group->iddq >= 0) {
+			if (group->iddq != 0)
+				value &= ~(1 << lane->iddq);
+			else
+				value |= 1 << lane->iddq;
+		}
+
+		padctl_writel(padctl, value, lane->offset);
+	}
+
+	return 0;
+}
+
+static int
+tegra_xusb_padctl_config_apply(struct tegra_xusb_padctl *padctl,
+			       struct tegra_xusb_padctl_config *config)
+{
+	unsigned int i;
+
+	for (i = 0; i < config->num_groups; i++) {
+		const struct tegra_xusb_padctl_group *group;
+		int err;
+
+		group = &config->groups[i];
+
+		err = tegra_xusb_padctl_group_apply(padctl, group);
+		if (err < 0) {
+			error("tegra-xusb-padctl: failed to apply group %s: %d",
+			      group->name, err);
+			continue;
+		}
+	}
+
+	return 0;
+}
+
+static int
+tegra_xusb_padctl_config_parse_dt(struct tegra_xusb_padctl *padctl,
+				  struct tegra_xusb_padctl_config *config,
+				  const void *fdt, int node)
+{
+	int subnode;
+
+	config->name = fdt_get_name(fdt, node, NULL);
+
+	fdt_for_each_subnode(fdt, subnode, node) {
+		struct tegra_xusb_padctl_group *group;
+		int err;
+
+		group = &config->groups[config->num_groups];
+
+		err = tegra_xusb_padctl_group_parse_dt(padctl, group, fdt,
+						       subnode);
+		if (err < 0) {
+			error("tegra-xusb-padctl: failed to parse group %s",
+			      group->name);
+			return err;
+		}
+
+		config->num_groups++;
+	}
+
+	return 0;
+}
+
+static int tegra_xusb_padctl_parse_dt(struct tegra_xusb_padctl *padctl,
+				      const void *fdt, int node)
+{
+	int subnode, err;
+
+	err = fdt_get_resource(fdt, node, "reg", 0, &padctl->regs);
+	if (err < 0) {
+		error("tegra-xusb-padctl: registers not found");
+		return err;
+	}
+
+	fdt_for_each_subnode(fdt, subnode, node) {
+		struct tegra_xusb_padctl_config *config = &padctl->config;
+
+		err = tegra_xusb_padctl_config_parse_dt(padctl, config, fdt,
+							subnode);
+		if (err < 0) {
+			error("tegra-xusb-padctl: failed to parse entry %s: %d",
+			      config->name, err);
+			continue;
+		}
+	}
+
+	return 0;
+}
+
+static int process_nodes(const void *fdt, int nodes[], unsigned int count)
+{
+	unsigned int i;
+
+	for (i = 0; i < count; i++) {
+		enum fdt_compat_id id;
+		int err;
+
+		if (!fdtdec_get_is_enabled(fdt, nodes[i]))
+			continue;
+
+		id = fdtdec_lookup(fdt, nodes[i]);
+		switch (id) {
+		case COMPAT_NVIDIA_TEGRA124_XUSB_PADCTL:
+			break;
+
+		default:
+			error("tegra-xusb-padctl: unsupported compatible: %s",
+			      fdtdec_get_compatible(id));
+			continue;
+		}
+
+		padctl->num_lanes = ARRAY_SIZE(tegra124_lanes);
+		padctl->lanes = tegra124_lanes;
+
+		padctl->num_functions = ARRAY_SIZE(tegra124_functions);
+		padctl->functions = tegra124_functions;
+
+		err = tegra_xusb_padctl_parse_dt(padctl, fdt, nodes[i]);
+		if (err < 0) {
+			error("tegra-xusb-padctl: failed to parse DT: %d",
+			      err);
+			continue;
+		}
+
+		/* deassert XUSB padctl reset */
+		reset_set_enable(PERIPH_ID_XUSB_PADCTL, 0);
+
+		err = tegra_xusb_padctl_config_apply(padctl, &padctl->config);
+		if (err < 0) {
+			error("tegra-xusb-padctl: failed to apply pinmux: %d",
+			      err);
+			continue;
+		}
+
+		/* only a single instance is supported */
+		break;
+	}
+
+	return 0;
+}
+
+struct tegra_xusb_phy *tegra_xusb_phy_get(unsigned int type)
+{
+	struct tegra_xusb_phy *phy = NULL;
+
+	switch (type) {
+	case TEGRA_XUSB_PADCTL_PCIE:
+		phy = &padctl->phys[0];
+		phy->padctl = padctl;
+		break;
+
+	case TEGRA_XUSB_PADCTL_SATA:
+		phy = &padctl->phys[1];
+		phy->padctl = padctl;
+		break;
+	}
+
+	return phy;
+}
+
+int tegra_xusb_phy_prepare(struct tegra_xusb_phy *phy)
+{
+	if (phy && phy->ops && phy->ops->prepare)
+		return phy->ops->prepare(phy);
+
+	return phy ? -ENOSYS : -EINVAL;
+}
+
+int tegra_xusb_phy_enable(struct tegra_xusb_phy *phy)
+{
+	if (phy && phy->ops && phy->ops->enable)
+		return phy->ops->enable(phy);
+
+	return phy ? -ENOSYS : -EINVAL;
+}
+
+int tegra_xusb_phy_disable(struct tegra_xusb_phy *phy)
+{
+	if (phy && phy->ops && phy->ops->disable)
+		return phy->ops->disable(phy);
+
+	return phy ? -ENOSYS : -EINVAL;
+}
+
+int tegra_xusb_phy_unprepare(struct tegra_xusb_phy *phy)
+{
+	if (phy && phy->ops && phy->ops->unprepare)
+		return phy->ops->unprepare(phy);
+
+	return phy ? -ENOSYS : -EINVAL;
+}
+
+void tegra_xusb_padctl_init(const void *fdt)
+{
+	int count, nodes[1];
+
+	count = fdtdec_find_aliases_for_id(fdt, "padctl",
+					   COMPAT_NVIDIA_TEGRA124_XUSB_PADCTL,
+					   nodes, ARRAY_SIZE(nodes));
+	if (process_nodes(fdt, nodes, count))
+		return;
+}
diff --git a/arch/arm/mach-tegra/tegra20/Kconfig b/arch/arm/mach-tegra/tegra20/Kconfig
new file mode 100644
index 0000000..a354e2a
--- /dev/null
+++ b/arch/arm/mach-tegra/tegra20/Kconfig
@@ -0,0 +1,52 @@
+if TEGRA20
+
+choice
+	prompt "Tegra20 board select"
+
+config TARGET_HARMONY
+	bool "NVIDIA Tegra20 Harmony evaluation board"
+
+config TARGET_MEDCOM_WIDE
+	bool "Avionic Design Medcom-Wide board"
+
+config TARGET_PAZ00
+	bool "Paz00 board"
+
+config TARGET_PLUTUX
+	bool "Avionic Design Plutux board"
+
+config TARGET_SEABOARD
+	bool "NVIDIA Seaboard"
+
+config TARGET_TEC
+	bool "Avionic Design Tamonten Evaluation Carrier"
+
+config TARGET_TRIMSLICE
+	bool "Compulab TrimSlice board"
+
+config TARGET_VENTANA
+	bool "NVIDIA Tegra20 Ventana evaluation board"
+
+config TARGET_WHISTLER
+	bool "NVIDIA Tegra20 Whistler evaluation board"
+
+config TARGET_COLIBRI_T20_IRIS
+	bool "Toradex Colibri T20 board"
+
+endchoice
+
+config SYS_SOC
+	default "tegra20"
+
+source "board/nvidia/harmony/Kconfig"
+source "board/avionic-design/medcom-wide/Kconfig"
+source "board/compal/paz00/Kconfig"
+source "board/avionic-design/plutux/Kconfig"
+source "board/nvidia/seaboard/Kconfig"
+source "board/avionic-design/tec/Kconfig"
+source "board/compulab/trimslice/Kconfig"
+source "board/nvidia/ventana/Kconfig"
+source "board/nvidia/whistler/Kconfig"
+source "board/toradex/colibri_t20_iris/Kconfig"
+
+endif
diff --git a/arch/arm/mach-tegra/tegra20/Makefile b/arch/arm/mach-tegra/tegra20/Makefile
new file mode 100644
index 0000000..d48f9bb
--- /dev/null
+++ b/arch/arm/mach-tegra/tegra20/Makefile
@@ -0,0 +1,21 @@
+#
+# (C) Copyright 2010,2011 Nvidia Corporation.
+#
+# SPDX-License-Identifier:	GPL-2.0+
+#
+
+ifdef CONFIG_SPL_BUILD
+obj-y	+= cpu.o
+else
+obj-$(CONFIG_PWM_TEGRA) += pwm.o
+obj-$(CONFIG_VIDEO_TEGRA) += display.o
+endif
+
+# 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 funcmux.o pinmux.o
+obj-$(CONFIG_TEGRA_LP0) += warmboot.o crypto.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/clock.c b/arch/arm/mach-tegra/tegra20/clock.c
new file mode 100644
index 0000000..7b9e10c
--- /dev/null
+++ b/arch/arm/mach-tegra/tegra20/clock.c
@@ -0,0 +1,687 @@
+/*
+ * Copyright (c) 2011 The Chromium OS Authors.
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+/* Tegra20 Clock control functions */
+
+#include <common.h>
+#include <errno.h>
+#include <asm/io.h>
+#include <asm/arch/clock.h>
+#include <asm/arch/tegra.h>
+#include <asm/arch-tegra/clk_rst.h>
+#include <asm/arch-tegra/timer.h>
+#include <div64.h>
+#include <fdtdec.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
+ * source. This gives us a clock 'type' and exploits what commonality exists
+ * in the device.
+ *
+ * Letters are obvious, except for T which means CLK_M, and S which means the
+ * clock derived from 32KHz. Beware that CLK_M (also called OSC in the
+ * datasheet) and PLL_M are different things. The former is the basic
+ * clock supplied to the SOC from an external oscillator. The latter is the
+ * memory clock PLL.
+ *
+ * See definitions in clock_id in the header file.
+ */
+enum clock_type_id {
+	CLOCK_TYPE_AXPT,	/* PLL_A, PLL_X, PLL_P, CLK_M */
+	CLOCK_TYPE_MCPA,	/* and so on */
+	CLOCK_TYPE_MCPT,
+	CLOCK_TYPE_PCM,
+	CLOCK_TYPE_PCMT,
+	CLOCK_TYPE_PCMT16,	/* CLOCK_TYPE_PCMT with 16-bit divider */
+	CLOCK_TYPE_PCXTS,
+	CLOCK_TYPE_PDCT,
+
+	CLOCK_TYPE_COUNT,
+	CLOCK_TYPE_NONE = -1,	/* invalid clock type */
+};
+
+enum {
+	CLOCK_MAX_MUX	= 4	/* number of source options for each clock */
+};
+
+/*
+ * Clock source mux for each clock type. This just converts our enum into
+ * a list of mux sources for use by the code. Note that CLOCK_TYPE_PCXTS
+ * is special as it has 5 sources. Since it also has a different number of
+ * bits in its register for the source, we just handle it with a special
+ * case in the code.
+ */
+#define CLK(x) CLOCK_ID_ ## x
+static enum clock_id clock_source[CLOCK_TYPE_COUNT][CLOCK_MAX_MUX] = {
+	{ CLK(AUDIO),	CLK(XCPU),	CLK(PERIPH),	CLK(OSC)	},
+	{ CLK(MEMORY),	CLK(CGENERAL),	CLK(PERIPH),	CLK(AUDIO)	},
+	{ CLK(MEMORY),	CLK(CGENERAL),	CLK(PERIPH),	CLK(OSC)	},
+	{ CLK(PERIPH),	CLK(CGENERAL),	CLK(MEMORY),	CLK(NONE)	},
+	{ CLK(PERIPH),	CLK(CGENERAL),	CLK(MEMORY),	CLK(OSC)	},
+	{ CLK(PERIPH),	CLK(CGENERAL),	CLK(MEMORY),	CLK(OSC)	},
+	{ CLK(PERIPH),	CLK(CGENERAL),	CLK(XCPU),	CLK(OSC)	},
+	{ CLK(PERIPH),	CLK(DISPLAY),	CLK(CGENERAL),	CLK(OSC)	},
+};
+
+/*
+ * Clock peripheral IDs which sadly don't match up with PERIPH_ID. This is
+ * not in the header file since it is for purely internal use - we want
+ * callers to use the PERIPH_ID for all access to peripheral clocks to avoid
+ * confusion bewteen PERIPH_ID_... and PERIPHC_...
+ *
+ * We don't call this CLOCK_PERIPH_ID or PERIPH_CLOCK_ID as it would just be
+ * confusing.
+ *
+ * Note to SOC vendors: perhaps define a unified numbering for peripherals and
+ * use it for reset, clock enable, clock source/divider and even pinmuxing
+ * if you can.
+ */
+enum periphc_internal_id {
+	/* 0x00 */
+	PERIPHC_I2S1,
+	PERIPHC_I2S2,
+	PERIPHC_SPDIF_OUT,
+	PERIPHC_SPDIF_IN,
+	PERIPHC_PWM,
+	PERIPHC_SPI1,
+	PERIPHC_SPI2,
+	PERIPHC_SPI3,
+
+	/* 0x08 */
+	PERIPHC_XIO,
+	PERIPHC_I2C1,
+	PERIPHC_DVC_I2C,
+	PERIPHC_TWC,
+	PERIPHC_0c,
+	PERIPHC_10,	/* PERIPHC_SPI1, what is this really? */
+	PERIPHC_DISP1,
+	PERIPHC_DISP2,
+
+	/* 0x10 */
+	PERIPHC_CVE,
+	PERIPHC_IDE0,
+	PERIPHC_VI,
+	PERIPHC_1c,
+	PERIPHC_SDMMC1,
+	PERIPHC_SDMMC2,
+	PERIPHC_G3D,
+	PERIPHC_G2D,
+
+	/* 0x18 */
+	PERIPHC_NDFLASH,
+	PERIPHC_SDMMC4,
+	PERIPHC_VFIR,
+	PERIPHC_EPP,
+	PERIPHC_MPE,
+	PERIPHC_MIPI,
+	PERIPHC_UART1,
+	PERIPHC_UART2,
+
+	/* 0x20 */
+	PERIPHC_HOST1X,
+	PERIPHC_21,
+	PERIPHC_TVO,
+	PERIPHC_HDMI,
+	PERIPHC_24,
+	PERIPHC_TVDAC,
+	PERIPHC_I2C2,
+	PERIPHC_EMC,
+
+	/* 0x28 */
+	PERIPHC_UART3,
+	PERIPHC_29,
+	PERIPHC_VI_SENSOR,
+	PERIPHC_2b,
+	PERIPHC_2c,
+	PERIPHC_SPI4,
+	PERIPHC_I2C3,
+	PERIPHC_SDMMC3,
+
+	/* 0x30 */
+	PERIPHC_UART4,
+	PERIPHC_UART5,
+	PERIPHC_VDE,
+	PERIPHC_OWR,
+	PERIPHC_NOR,
+	PERIPHC_CSITE,
+
+	PERIPHC_COUNT,
+
+	PERIPHC_NONE = -1,
+};
+
+/*
+ * Clock type for each peripheral clock source. We put the name in each
+ * record just so it is easy to match things up
+ */
+#define TYPE(name, type) type
+static enum clock_type_id clock_periph_type[PERIPHC_COUNT] = {
+	/* 0x00 */
+	TYPE(PERIPHC_I2S1,	CLOCK_TYPE_AXPT),
+	TYPE(PERIPHC_I2S2,	CLOCK_TYPE_AXPT),
+	TYPE(PERIPHC_SPDIF_OUT,	CLOCK_TYPE_AXPT),
+	TYPE(PERIPHC_SPDIF_IN,	CLOCK_TYPE_PCM),
+	TYPE(PERIPHC_PWM,	CLOCK_TYPE_PCXTS),
+	TYPE(PERIPHC_SPI1,	CLOCK_TYPE_PCMT),
+	TYPE(PERIPHC_SPI22,	CLOCK_TYPE_PCMT),
+	TYPE(PERIPHC_SPI3,	CLOCK_TYPE_PCMT),
+
+	/* 0x08 */
+	TYPE(PERIPHC_XIO,	CLOCK_TYPE_PCMT),
+	TYPE(PERIPHC_I2C1,	CLOCK_TYPE_PCMT16),
+	TYPE(PERIPHC_DVC_I2C,	CLOCK_TYPE_PCMT16),
+	TYPE(PERIPHC_TWC,	CLOCK_TYPE_PCMT),
+	TYPE(PERIPHC_NONE,	CLOCK_TYPE_NONE),
+	TYPE(PERIPHC_SPI1,	CLOCK_TYPE_PCMT),
+	TYPE(PERIPHC_DISP1,	CLOCK_TYPE_PDCT),
+	TYPE(PERIPHC_DISP2,	CLOCK_TYPE_PDCT),
+
+	/* 0x10 */
+	TYPE(PERIPHC_CVE,	CLOCK_TYPE_PDCT),
+	TYPE(PERIPHC_IDE0,	CLOCK_TYPE_PCMT),
+	TYPE(PERIPHC_VI,	CLOCK_TYPE_MCPA),
+	TYPE(PERIPHC_NONE,	CLOCK_TYPE_NONE),
+	TYPE(PERIPHC_SDMMC1,	CLOCK_TYPE_PCMT),
+	TYPE(PERIPHC_SDMMC2,	CLOCK_TYPE_PCMT),
+	TYPE(PERIPHC_G3D,	CLOCK_TYPE_MCPA),
+	TYPE(PERIPHC_G2D,	CLOCK_TYPE_MCPA),
+
+	/* 0x18 */
+	TYPE(PERIPHC_NDFLASH,	CLOCK_TYPE_PCMT),
+	TYPE(PERIPHC_SDMMC4,	CLOCK_TYPE_PCMT),
+	TYPE(PERIPHC_VFIR,	CLOCK_TYPE_PCMT),
+	TYPE(PERIPHC_EPP,	CLOCK_TYPE_MCPA),
+	TYPE(PERIPHC_MPE,	CLOCK_TYPE_MCPA),
+	TYPE(PERIPHC_MIPI,	CLOCK_TYPE_PCMT),
+	TYPE(PERIPHC_UART1,	CLOCK_TYPE_PCMT),
+	TYPE(PERIPHC_UART2,	CLOCK_TYPE_PCMT),
+
+	/* 0x20 */
+	TYPE(PERIPHC_HOST1X,	CLOCK_TYPE_MCPA),
+	TYPE(PERIPHC_NONE,	CLOCK_TYPE_NONE),
+	TYPE(PERIPHC_TVO,	CLOCK_TYPE_PDCT),
+	TYPE(PERIPHC_HDMI,	CLOCK_TYPE_PDCT),
+	TYPE(PERIPHC_NONE,	CLOCK_TYPE_NONE),
+	TYPE(PERIPHC_TVDAC,	CLOCK_TYPE_PDCT),
+	TYPE(PERIPHC_I2C2,	CLOCK_TYPE_PCMT16),
+	TYPE(PERIPHC_EMC,	CLOCK_TYPE_MCPT),
+
+	/* 0x28 */
+	TYPE(PERIPHC_UART3,	CLOCK_TYPE_PCMT),
+	TYPE(PERIPHC_NONE,	CLOCK_TYPE_NONE),
+	TYPE(PERIPHC_VI,	CLOCK_TYPE_MCPA),
+	TYPE(PERIPHC_NONE,	CLOCK_TYPE_NONE),
+	TYPE(PERIPHC_NONE,	CLOCK_TYPE_NONE),
+	TYPE(PERIPHC_SPI4,	CLOCK_TYPE_PCMT),
+	TYPE(PERIPHC_I2C3,	CLOCK_TYPE_PCMT16),
+	TYPE(PERIPHC_SDMMC3,	CLOCK_TYPE_PCMT),
+
+	/* 0x30 */
+	TYPE(PERIPHC_UART4,	CLOCK_TYPE_PCMT),
+	TYPE(PERIPHC_UART5,	CLOCK_TYPE_PCMT),
+	TYPE(PERIPHC_VDE,	CLOCK_TYPE_PCMT),
+	TYPE(PERIPHC_OWR,	CLOCK_TYPE_PCMT),
+	TYPE(PERIPHC_NOR,	CLOCK_TYPE_PCMT),
+	TYPE(PERIPHC_CSITE,	CLOCK_TYPE_PCMT),
+};
+
+/*
+ * This array translates a periph_id to a periphc_internal_id
+ *
+ * Not present/matched up:
+ *	uint vi_sensor;	 _VI_SENSOR_0,		0x1A8
+ *	SPDIF - which is both 0x08 and 0x0c
+ *
+ */
+#define NONE(name) (-1)
+#define OFFSET(name, value) PERIPHC_ ## name
+static s8 periph_id_to_internal_id[PERIPH_ID_COUNT] = {
+	/* Low word: 31:0 */
+	NONE(CPU),
+	NONE(RESERVED1),
+	NONE(RESERVED2),
+	NONE(AC97),
+	NONE(RTC),
+	NONE(TMR),
+	PERIPHC_UART1,
+	PERIPHC_UART2,	/* and vfir 0x68 */
+
+	/* 0x08 */
+	NONE(GPIO),
+	PERIPHC_SDMMC2,
+	NONE(SPDIF),		/* 0x08 and 0x0c, unclear which to use */
+	PERIPHC_I2S1,
+	PERIPHC_I2C1,
+	PERIPHC_NDFLASH,
+	PERIPHC_SDMMC1,
+	PERIPHC_SDMMC4,
+
+	/* 0x10 */
+	PERIPHC_TWC,
+	PERIPHC_PWM,
+	PERIPHC_I2S2,
+	PERIPHC_EPP,
+	PERIPHC_VI,
+	PERIPHC_G2D,
+	NONE(USBD),
+	NONE(ISP),
+
+	/* 0x18 */
+	PERIPHC_G3D,
+	PERIPHC_IDE0,
+	PERIPHC_DISP2,
+	PERIPHC_DISP1,
+	PERIPHC_HOST1X,
+	NONE(VCP),
+	NONE(RESERVED30),
+	NONE(CACHE2),
+
+	/* Middle word: 63:32 */
+	NONE(MEM),
+	NONE(AHBDMA),
+	NONE(APBDMA),
+	NONE(RESERVED35),
+	NONE(KBC),
+	NONE(STAT_MON),
+	NONE(PMC),
+	NONE(FUSE),
+
+	/* 0x28 */
+	NONE(KFUSE),
+	NONE(SBC1),	/* SBC1, 0x34, is this SPI1? */
+	PERIPHC_NOR,
+	PERIPHC_SPI1,
+	PERIPHC_SPI2,
+	PERIPHC_XIO,
+	PERIPHC_SPI3,
+	PERIPHC_DVC_I2C,
+
+	/* 0x30 */
+	NONE(DSI),
+	PERIPHC_TVO,	/* also CVE 0x40 */
+	PERIPHC_MIPI,
+	PERIPHC_HDMI,
+	PERIPHC_CSITE,
+	PERIPHC_TVDAC,
+	PERIPHC_I2C2,
+	PERIPHC_UART3,
+
+	/* 0x38 */
+	NONE(RESERVED56),
+	PERIPHC_EMC,
+	NONE(USB2),
+	NONE(USB3),
+	PERIPHC_MPE,
+	PERIPHC_VDE,
+	NONE(BSEA),
+	NONE(BSEV),
+
+	/* Upper word 95:64 */
+	NONE(SPEEDO),
+	PERIPHC_UART4,
+	PERIPHC_UART5,
+	PERIPHC_I2C3,
+	PERIPHC_SPI4,
+	PERIPHC_SDMMC3,
+	NONE(PCIE),
+	PERIPHC_OWR,
+
+	/* 0x48 */
+	NONE(AFI),
+	NONE(CORESIGHT),
+	NONE(PCIEXCLK),
+	NONE(AVPUCQ),
+	NONE(RESERVED76),
+	NONE(RESERVED77),
+	NONE(RESERVED78),
+	NONE(RESERVED79),
+
+	/* 0x50 */
+	NONE(RESERVED80),
+	NONE(RESERVED81),
+	NONE(RESERVED82),
+	NONE(RESERVED83),
+	NONE(IRAMA),
+	NONE(IRAMB),
+	NONE(IRAMC),
+	NONE(IRAMD),
+
+	/* 0x58 */
+	NONE(CRAM2),
+};
+
+/*
+ * Get the oscillator frequency, from the corresponding hardware configuration
+ * field. T20 has 4 frequencies that it supports.
+ */
+enum clock_osc_freq clock_get_osc_freq(void)
+{
+	struct clk_rst_ctlr *clkrst =
+			(struct clk_rst_ctlr *)NV_PA_CLK_RST_BASE;
+	u32 reg;
+
+	reg = readl(&clkrst->crc_osc_ctrl);
+	return (reg & OSC_FREQ_MASK) >> OSC_FREQ_SHIFT;
+}
+
+/* Returns a pointer to the clock source register for a peripheral */
+u32 *get_periph_source_reg(enum periph_id periph_id)
+{
+	struct clk_rst_ctlr *clkrst =
+			(struct clk_rst_ctlr *)NV_PA_CLK_RST_BASE;
+	enum periphc_internal_id internal_id;
+
+	assert(clock_periph_id_isvalid(periph_id));
+	internal_id = periph_id_to_internal_id[periph_id];
+	assert(internal_id != -1);
+	return &clkrst->crc_clk_src[internal_id];
+}
+
+/**
+ * Given a peripheral ID and the required source clock, this returns which
+ * value should be programmed into the source mux for that peripheral.
+ *
+ * There is special code here to handle the one source type with 5 sources.
+ *
+ * @param periph_id	peripheral to start
+ * @param source	PLL id of required parent clock
+ * @param mux_bits	Set to number of bits in mux register: 2 or 4
+ * @param divider_bits	Set to number of divider bits (8 or 16)
+ * @return mux value (0-4, or -1 if not found)
+ */
+int get_periph_clock_source(enum periph_id periph_id,
+		enum clock_id parent, int *mux_bits, int *divider_bits)
+{
+	enum clock_type_id type;
+	enum periphc_internal_id internal_id;
+	int mux;
+
+	assert(clock_periph_id_isvalid(periph_id));
+
+	internal_id = periph_id_to_internal_id[periph_id];
+	assert(periphc_internal_id_isvalid(internal_id));
+
+	type = clock_periph_type[internal_id];
+	assert(clock_type_id_isvalid(type));
+
+	/*
+	 * Special cases here for the clock with a 4-bit source mux and I2C
+	 * with its 16-bit divisor
+	 */
+	if (type == CLOCK_TYPE_PCXTS)
+		*mux_bits = MASK_BITS_31_28;
+	else
+		*mux_bits = MASK_BITS_31_30;
+	if (type == CLOCK_TYPE_PCMT16)
+		*divider_bits = 16;
+	else
+		*divider_bits = 8;
+
+	for (mux = 0; mux < CLOCK_MAX_MUX; mux++)
+		if (clock_source[type][mux] == parent)
+			return mux;
+
+	/*
+	 * Not found: it might be looking for the 'S' in CLOCK_TYPE_PCXTS
+	 * which is not in our table. If not, then they are asking for a
+	 * source which this peripheral can't access through its mux.
+	 */
+	assert(type == CLOCK_TYPE_PCXTS);
+	assert(parent == CLOCK_ID_SFROM32KHZ);
+	if (type == CLOCK_TYPE_PCXTS && parent == CLOCK_ID_SFROM32KHZ)
+		return 4;	/* mux value for this clock */
+
+	/* if we get here, either us or the caller has made a mistake */
+	printf("Caller requested bad clock: periph=%d, parent=%d\n", periph_id,
+		parent);
+	return -1;
+}
+
+void clock_set_enable(enum periph_id periph_id, int enable)
+{
+	struct clk_rst_ctlr *clkrst =
+			(struct clk_rst_ctlr *)NV_PA_CLK_RST_BASE;
+	u32 *clk = &clkrst->crc_clk_out_enb[PERIPH_REG(periph_id)];
+	u32 reg;
+
+	/* Enable/disable the clock to this peripheral */
+	assert(clock_periph_id_isvalid(periph_id));
+	reg = readl(clk);
+	if (enable)
+		reg |= PERIPH_MASK(periph_id);
+	else
+		reg &= ~PERIPH_MASK(periph_id);
+	writel(reg, clk);
+}
+
+void reset_set_enable(enum periph_id periph_id, int enable)
+{
+	struct clk_rst_ctlr *clkrst =
+			(struct clk_rst_ctlr *)NV_PA_CLK_RST_BASE;
+	u32 *reset = &clkrst->crc_rst_dev[PERIPH_REG(periph_id)];
+	u32 reg;
+
+	/* Enable/disable reset to the peripheral */
+	assert(clock_periph_id_isvalid(periph_id));
+	reg = readl(reset);
+	if (enable)
+		reg |= PERIPH_MASK(periph_id);
+	else
+		reg &= ~PERIPH_MASK(periph_id);
+	writel(reg, reset);
+}
+
+#ifdef CONFIG_OF_CONTROL
+/*
+ * Convert a device tree clock ID to our peripheral ID. They are mostly
+ * the same but we are very cautious so we check that a valid clock ID is
+ * provided.
+ *
+ * @param clk_id	Clock ID according to tegra20 device tree binding
+ * @return peripheral ID, or PERIPH_ID_NONE if the clock ID is invalid
+ */
+enum periph_id clk_id_to_periph_id(int clk_id)
+{
+	if (clk_id > PERIPH_ID_COUNT)
+		return PERIPH_ID_NONE;
+
+	switch (clk_id) {
+	case PERIPH_ID_RESERVED1:
+	case PERIPH_ID_RESERVED2:
+	case PERIPH_ID_RESERVED30:
+	case PERIPH_ID_RESERVED35:
+	case PERIPH_ID_RESERVED56:
+	case PERIPH_ID_PCIEXCLK:
+	case PERIPH_ID_RESERVED76:
+	case PERIPH_ID_RESERVED77:
+	case PERIPH_ID_RESERVED78:
+	case PERIPH_ID_RESERVED79:
+	case PERIPH_ID_RESERVED80:
+	case PERIPH_ID_RESERVED81:
+	case PERIPH_ID_RESERVED82:
+	case PERIPH_ID_RESERVED83:
+	case PERIPH_ID_RESERVED91:
+		return PERIPH_ID_NONE;
+	default:
+		return clk_id;
+	}
+}
+#endif /* CONFIG_OF_CONTROL */
+
+void clock_early_init(void)
+{
+	/*
+	 * PLLP output frequency set to 216MHz
+	 * PLLC output frequency set to 600Mhz
+	 *
+	 * TODO: Can we calculate these values instead of hard-coding?
+	 */
+	switch (clock_get_osc_freq()) {
+	case CLOCK_OSC_FREQ_12_0: /* OSC is 12Mhz */
+		clock_set_rate(CLOCK_ID_PERIPH, 432, 12, 1, 8);
+		clock_set_rate(CLOCK_ID_CGENERAL, 600, 12, 0, 8);
+		break;
+
+	case CLOCK_OSC_FREQ_26_0: /* OSC is 26Mhz */
+		clock_set_rate(CLOCK_ID_PERIPH, 432, 26, 1, 8);
+		clock_set_rate(CLOCK_ID_CGENERAL, 600, 26, 0, 8);
+		break;
+
+	case CLOCK_OSC_FREQ_13_0: /* OSC is 13Mhz */
+		clock_set_rate(CLOCK_ID_PERIPH, 432, 13, 1, 8);
+		clock_set_rate(CLOCK_ID_CGENERAL, 600, 13, 0, 8);
+		break;
+	case CLOCK_OSC_FREQ_19_2:
+	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;
+	}
+}
+
+void arch_timer_init(void)
+{
+}
+
+#define PMC_SATA_PWRGT 0x1ac
+#define  PMC_SATA_PWRGT_PLLE_IDDQ_OVERRIDE (1 << 5)
+#define  PMC_SATA_PWRGT_PLLE_IDDQ_SWCTL (1 << 4)
+
+#define PLLE_SS_CNTL 0x68
+#define  PLLE_SS_CNTL_SSCINCINTRV(x) (((x) & 0x3f) << 24)
+#define  PLLE_SS_CNTL_SSCINC(x) (((x) & 0xff) << 16)
+#define  PLLE_SS_CNTL_SSCBYP (1 << 12)
+#define  PLLE_SS_CNTL_INTERP_RESET (1 << 11)
+#define  PLLE_SS_CNTL_BYPASS_SS (1 << 10)
+#define  PLLE_SS_CNTL_SSCMAX(x) (((x) & 0x1ff) << 0)
+
+#define PLLE_BASE 0x0e8
+#define  PLLE_BASE_ENABLE_CML (1 << 31)
+#define  PLLE_BASE_ENABLE (1 << 30)
+#define  PLLE_BASE_PLDIV_CML(x) (((x) & 0xf) << 24)
+#define  PLLE_BASE_PLDIV(x) (((x) & 0x3f) << 16)
+#define  PLLE_BASE_NDIV(x) (((x) & 0xff) << 8)
+#define  PLLE_BASE_MDIV(x) (((x) & 0xff) << 0)
+
+#define PLLE_MISC 0x0ec
+#define  PLLE_MISC_SETUP_BASE(x) (((x) & 0xffff) << 16)
+#define  PLLE_MISC_PLL_READY (1 << 15)
+#define  PLLE_MISC_LOCK (1 << 11)
+#define  PLLE_MISC_LOCK_ENABLE (1 << 9)
+#define  PLLE_MISC_SETUP_EXT(x) (((x) & 0x3) << 2)
+
+static int tegra_plle_train(void)
+{
+	unsigned int timeout = 2000;
+	unsigned long value;
+
+	value = readl(NV_PA_PMC_BASE + PMC_SATA_PWRGT);
+	value |= PMC_SATA_PWRGT_PLLE_IDDQ_OVERRIDE;
+	writel(value, NV_PA_PMC_BASE + PMC_SATA_PWRGT);
+
+	value = readl(NV_PA_PMC_BASE + PMC_SATA_PWRGT);
+	value |= PMC_SATA_PWRGT_PLLE_IDDQ_SWCTL;
+	writel(value, NV_PA_PMC_BASE + PMC_SATA_PWRGT);
+
+	value = readl(NV_PA_PMC_BASE + PMC_SATA_PWRGT);
+	value &= ~PMC_SATA_PWRGT_PLLE_IDDQ_OVERRIDE;
+	writel(value, NV_PA_PMC_BASE + PMC_SATA_PWRGT);
+
+	do {
+		value = readl(NV_PA_CLK_RST_BASE + PLLE_MISC);
+		if (value & PLLE_MISC_PLL_READY)
+			break;
+
+		udelay(100);
+	} while (--timeout);
+
+	if (timeout == 0) {
+		error("timeout waiting for PLLE to become ready");
+		return -ETIMEDOUT;
+	}
+
+	return 0;
+}
+
+int tegra_plle_enable(void)
+{
+	unsigned int timeout = 1000;
+	u32 value;
+	int err;
+
+	/* disable PLLE clock */
+	value = readl(NV_PA_CLK_RST_BASE + PLLE_BASE);
+	value &= ~PLLE_BASE_ENABLE_CML;
+	value &= ~PLLE_BASE_ENABLE;
+	writel(value, NV_PA_CLK_RST_BASE + PLLE_BASE);
+
+	/* clear lock enable and setup field */
+	value = readl(NV_PA_CLK_RST_BASE + PLLE_MISC);
+	value &= ~PLLE_MISC_LOCK_ENABLE;
+	value &= ~PLLE_MISC_SETUP_BASE(0xffff);
+	value &= ~PLLE_MISC_SETUP_EXT(0x3);
+	writel(value, NV_PA_CLK_RST_BASE + PLLE_MISC);
+
+	value = readl(NV_PA_CLK_RST_BASE + PLLE_MISC);
+	if ((value & PLLE_MISC_PLL_READY) == 0) {
+		err = tegra_plle_train();
+		if (err < 0) {
+			error("failed to train PLLE: %d", err);
+			return err;
+		}
+	}
+
+	value = readl(NV_PA_CLK_RST_BASE + PLLE_MISC);
+	value |= PLLE_MISC_SETUP_BASE(0x7);
+	value |= PLLE_MISC_LOCK_ENABLE;
+	value |= PLLE_MISC_SETUP_EXT(0);
+	writel(value, NV_PA_CLK_RST_BASE + PLLE_MISC);
+
+	value = readl(NV_PA_CLK_RST_BASE + PLLE_SS_CNTL);
+	value |= PLLE_SS_CNTL_SSCBYP | PLLE_SS_CNTL_INTERP_RESET |
+		 PLLE_SS_CNTL_BYPASS_SS;
+	writel(value, NV_PA_CLK_RST_BASE + PLLE_SS_CNTL);
+
+	value = readl(NV_PA_CLK_RST_BASE + PLLE_BASE);
+	value |= PLLE_BASE_ENABLE_CML | PLLE_BASE_ENABLE;
+	writel(value, NV_PA_CLK_RST_BASE + PLLE_BASE);
+
+	do {
+		value = readl(NV_PA_CLK_RST_BASE + PLLE_MISC);
+		if (value & PLLE_MISC_LOCK)
+			break;
+
+		udelay(2);
+	} while (--timeout);
+
+	if (timeout == 0) {
+		error("timeout waiting for PLLE to lock");
+		return -ETIMEDOUT;
+	}
+
+	udelay(50);
+
+	value = readl(NV_PA_CLK_RST_BASE + PLLE_SS_CNTL);
+	value &= ~PLLE_SS_CNTL_SSCINCINTRV(0x3f);
+	value |= PLLE_SS_CNTL_SSCINCINTRV(0x18);
+
+	value &= ~PLLE_SS_CNTL_SSCINC(0xff);
+	value |= PLLE_SS_CNTL_SSCINC(0x01);
+
+	value &= ~PLLE_SS_CNTL_SSCBYP;
+	value &= ~PLLE_SS_CNTL_INTERP_RESET;
+	value &= ~PLLE_SS_CNTL_BYPASS_SS;
+
+	value &= ~PLLE_SS_CNTL_SSCMAX(0x1ff);
+	value |= PLLE_SS_CNTL_SSCMAX(0x24);
+	writel(value, NV_PA_CLK_RST_BASE + PLLE_SS_CNTL);
+
+	return 0;
+}
diff --git a/arch/arm/mach-tegra/tegra20/cpu.c b/arch/arm/mach-tegra/tegra20/cpu.c
new file mode 100644
index 0000000..67f49d7
--- /dev/null
+++ b/arch/arm/mach-tegra/tegra20/cpu.c
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2010-2012, NVIDIA CORPORATION.  All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <asm/arch/tegra.h>
+#include <asm/arch-tegra/pmc.h>
+#include "../cpu.h"
+
+static void enable_cpu_power_rail(void)
+{
+	struct pmc_ctlr *pmc = (struct pmc_ctlr *)NV_PA_PMC_BASE;
+	u32 reg;
+
+	reg = readl(&pmc->pmc_cntrl);
+	reg |= CPUPWRREQ_OE;
+	writel(reg, &pmc->pmc_cntrl);
+
+	/*
+	 * The TI PMU65861C needs a 3.75ms delay between enabling
+	 * the power rail and enabling the CPU clock.  This delay
+	 * between SM1EN and SM1 is for switching time + the ramp
+	 * up of the voltage to the CPU (VDD_CPU from PMU).
+	 */
+	udelay(3750);
+}
+
+void start_cpu(u32 reset_vector)
+{
+	/* Enable VDD_CPU */
+	enable_cpu_power_rail();
+
+	/* Hold the CPUs in reset */
+	reset_A9_cpu(1);
+
+	/* Disable the CPU clock */
+	enable_cpu_clock(0);
+
+	/* Enable CoreSight */
+	clock_enable_coresight(1);
+
+	/*
+	 * Set the entry point for CPU execution from reset,
+	 *  if it's a non-zero value.
+	 */
+	if (reset_vector)
+		writel(reset_vector, EXCEP_VECTOR_CPU_RESET_VECTOR);
+
+	/* Enable the CPU clock */
+	enable_cpu_clock(1);
+
+	/* If the CPU doesn't already have power, power it up */
+	powerup_cpu();
+
+	/* Take the CPU out of reset */
+	reset_A9_cpu(0);
+}
diff --git a/arch/arm/mach-tegra/tegra20/crypto.c b/arch/arm/mach-tegra/tegra20/crypto.c
new file mode 100644
index 0000000..ec95d7c
--- /dev/null
+++ b/arch/arm/mach-tegra/tegra20/crypto.c
@@ -0,0 +1,137 @@
+/*
+ * Copyright (c) 2011 The Chromium OS Authors.
+ * (C) Copyright 2010 - 2011 NVIDIA Corporation <www.nvidia.com>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#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 */
+};
+
+/**
+ * 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;
+
+	aes_cbc_encrypt_blocks(key_schedule, tmp_data, left, 1);
+
+	left_shift_vector(left, k1, sizeof(left));
+
+	if ((left[0] >> 7) != 0) /* get MSB of L */
+		k1[AES_KEY_LENGTH-1] ^= AES_CMAC_CONST_RB;
+
+	/* compute the AES-CMAC value */
+	for (i = 0; i < num_aes_blocks; i++) {
+		/* Apply the chain data */
+		aes_apply_cbc_chain_data(cbc_chain_data, src, tmp_data);
+
+		/* for the final block, XOR K1 into the IV */
+		if (i == num_aes_blocks - 1)
+			aes_apply_cbc_chain_data(tmp_data, k1, tmp_data);
+
+		/* encrypt the AES block */
+		aes_encrypt(tmp_data, key_schedule, dst);
+
+		debug("sign_obj: block %d of %d\n", i, num_aes_blocks);
+
+		/* Update pointers for next loop. */
+		cbc_chain_data = dst;
+		src += AES_KEY_LENGTH;
+	}
+}
+
+/**
+ * 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);
+
+	/*
+	 * 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");
+		aes_cbc_encrypt_blocks(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/mach-tegra/tegra20/crypto.h b/arch/arm/mach-tegra/tegra20/crypto.h
new file mode 100644
index 0000000..f59b927
--- /dev/null
+++ b/arch/arm/mach-tegra/tegra20/crypto.h
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2011 The Chromium OS Authors.
+ * (C) Copyright 2010 - 2011 NVIDIA Corporation <www.nvidia.com>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#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/tegra20/display.c b/arch/arm/mach-tegra/tegra20/display.c
new file mode 100644
index 0000000..61efed6
--- /dev/null
+++ b/arch/arm/mach-tegra/tegra20/display.c
@@ -0,0 +1,394 @@
+/*
+ *  (C) Copyright 2010
+ *  NVIDIA Corporation <www.nvidia.com>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <asm/arch/clock.h>
+#include <asm/arch/tegra.h>
+#include <asm/arch/display.h>
+#include <asm/arch/dc.h>
+#include <asm/arch-tegra/clk_rst.h>
+#include <asm/arch-tegra/timer.h>
+
+static struct fdt_disp_config config;
+
+static void update_window(struct dc_ctlr *dc, struct disp_ctl_win *win)
+{
+	unsigned h_dda, v_dda;
+	unsigned long val;
+
+	val = readl(&dc->cmd.disp_win_header);
+	val |= WINDOW_A_SELECT;
+	writel(val, &dc->cmd.disp_win_header);
+
+	writel(win->fmt, &dc->win.color_depth);
+
+	clrsetbits_le32(&dc->win.byte_swap, BYTE_SWAP_MASK,
+			BYTE_SWAP_NOSWAP << BYTE_SWAP_SHIFT);
+
+	val = win->out_x << H_POSITION_SHIFT;
+	val |= win->out_y << V_POSITION_SHIFT;
+	writel(val, &dc->win.pos);
+
+	val = win->out_w << H_SIZE_SHIFT;
+	val |= win->out_h << V_SIZE_SHIFT;
+	writel(val, &dc->win.size);
+
+	val = (win->w * win->bpp / 8) << H_PRESCALED_SIZE_SHIFT;
+	val |= win->h << V_PRESCALED_SIZE_SHIFT;
+	writel(val, &dc->win.prescaled_size);
+
+	writel(0, &dc->win.h_initial_dda);
+	writel(0, &dc->win.v_initial_dda);
+
+	h_dda = (win->w * 0x1000) / max(win->out_w - 1, 1U);
+	v_dda = (win->h * 0x1000) / max(win->out_h - 1, 1U);
+
+	val = h_dda << H_DDA_INC_SHIFT;
+	val |= v_dda << V_DDA_INC_SHIFT;
+	writel(val, &dc->win.dda_increment);
+
+	writel(win->stride, &dc->win.line_stride);
+	writel(0, &dc->win.buf_stride);
+
+	val = WIN_ENABLE;
+	if (win->bpp < 24)
+		val |= COLOR_EXPAND;
+	writel(val, &dc->win.win_opt);
+
+	writel((unsigned long)win->phys_addr, &dc->winbuf.start_addr);
+	writel(win->x, &dc->winbuf.addr_h_offset);
+	writel(win->y, &dc->winbuf.addr_v_offset);
+
+	writel(0xff00, &dc->win.blend_nokey);
+	writel(0xff00, &dc->win.blend_1win);
+
+	val = GENERAL_ACT_REQ | WIN_A_ACT_REQ;
+	val |= GENERAL_UPDATE | WIN_A_UPDATE;
+	writel(val, &dc->cmd.state_ctrl);
+}
+
+static void write_pair(struct fdt_disp_config *config, int item, u32 *reg)
+{
+	writel(config->horiz_timing[item] |
+			(config->vert_timing[item] << 16), reg);
+}
+
+static int update_display_mode(struct dc_disp_reg *disp,
+		struct fdt_disp_config *config)
+{
+	unsigned long val;
+	unsigned long rate;
+	unsigned long div;
+
+	writel(0x0, &disp->disp_timing_opt);
+	write_pair(config, FDT_LCD_TIMING_REF_TO_SYNC, &disp->ref_to_sync);
+	write_pair(config, FDT_LCD_TIMING_SYNC_WIDTH, &disp->sync_width);
+	write_pair(config, FDT_LCD_TIMING_BACK_PORCH, &disp->back_porch);
+	write_pair(config, FDT_LCD_TIMING_FRONT_PORCH, &disp->front_porch);
+
+	writel(config->width | (config->height << 16), &disp->disp_active);
+
+	val = DE_SELECT_ACTIVE << DE_SELECT_SHIFT;
+	val |= DE_CONTROL_NORMAL << DE_CONTROL_SHIFT;
+	writel(val, &disp->data_enable_opt);
+
+	val = DATA_FORMAT_DF1P1C << DATA_FORMAT_SHIFT;
+	val |= DATA_ALIGNMENT_MSB << DATA_ALIGNMENT_SHIFT;
+	val |= DATA_ORDER_RED_BLUE << DATA_ORDER_SHIFT;
+	writel(val, &disp->disp_interface_ctrl);
+
+	/*
+	 * The pixel clock divider is in 7.1 format (where the bottom bit
+	 * represents 0.5). Here we calculate the divider needed to get from
+	 * the display clock (typically 600MHz) to the pixel clock. We round
+	 * up or down as requried.
+	 */
+	rate = clock_get_periph_rate(PERIPH_ID_DISP1, CLOCK_ID_CGENERAL);
+	div = ((rate * 2 + config->pixel_clock / 2) / config->pixel_clock) - 2;
+	debug("Display clock %lu, divider %lu\n", rate, div);
+
+	writel(0x00010001, &disp->shift_clk_opt);
+
+	val = PIXEL_CLK_DIVIDER_PCD1 << PIXEL_CLK_DIVIDER_SHIFT;
+	val |= div << SHIFT_CLK_DIVIDER_SHIFT;
+	writel(val, &disp->disp_clk_ctrl);
+
+	return 0;
+}
+
+/* Start up the display and turn on power to PWMs */
+static void basic_init(struct dc_cmd_reg *cmd)
+{
+	u32 val;
+
+	writel(0x00000100, &cmd->gen_incr_syncpt_ctrl);
+	writel(0x0000011a, &cmd->cont_syncpt_vsync);
+	writel(0x00000000, &cmd->int_type);
+	writel(0x00000000, &cmd->int_polarity);
+	writel(0x00000000, &cmd->int_mask);
+	writel(0x00000000, &cmd->int_enb);
+
+	val = PW0_ENABLE | PW1_ENABLE | PW2_ENABLE;
+	val |= PW3_ENABLE | PW4_ENABLE | PM0_ENABLE;
+	val |= PM1_ENABLE;
+	writel(val, &cmd->disp_pow_ctrl);
+
+	val = readl(&cmd->disp_cmd);
+	val |= CTRL_MODE_C_DISPLAY << CTRL_MODE_SHIFT;
+	writel(val, &cmd->disp_cmd);
+}
+
+static void basic_init_timer(struct dc_disp_reg *disp)
+{
+	writel(0x00000020, &disp->mem_high_pri);
+	writel(0x00000001, &disp->mem_high_pri_timer);
+}
+
+static const u32 rgb_enb_tab[PIN_REG_COUNT] = {
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+};
+
+static const u32 rgb_polarity_tab[PIN_REG_COUNT] = {
+	0x00000000,
+	0x01000000,
+	0x00000000,
+	0x00000000,
+};
+
+static const u32 rgb_data_tab[PIN_REG_COUNT] = {
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+};
+
+static const u32 rgb_sel_tab[PIN_OUTPUT_SEL_COUNT] = {
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00210222,
+	0x00002200,
+	0x00020000,
+};
+
+static void rgb_enable(struct dc_com_reg *com)
+{
+	int i;
+
+	for (i = 0; i < PIN_REG_COUNT; i++) {
+		writel(rgb_enb_tab[i], &com->pin_output_enb[i]);
+		writel(rgb_polarity_tab[i], &com->pin_output_polarity[i]);
+		writel(rgb_data_tab[i], &com->pin_output_data[i]);
+	}
+
+	for (i = 0; i < PIN_OUTPUT_SEL_COUNT; i++)
+		writel(rgb_sel_tab[i], &com->pin_output_sel[i]);
+}
+
+static int setup_window(struct disp_ctl_win *win,
+			struct fdt_disp_config *config)
+{
+	win->x = 0;
+	win->y = 0;
+	win->w = config->width;
+	win->h = config->height;
+	win->out_x = 0;
+	win->out_y = 0;
+	win->out_w = config->width;
+	win->out_h = config->height;
+	win->phys_addr = config->frame_buffer;
+	win->stride = config->width * (1 << config->log2_bpp) / 8;
+	debug("%s: depth = %d\n", __func__, config->log2_bpp);
+	switch (config->log2_bpp) {
+	case 5:
+	case 24:
+		win->fmt = COLOR_DEPTH_R8G8B8A8;
+		win->bpp = 32;
+		break;
+	case 4:
+		win->fmt = COLOR_DEPTH_B5G6R5;
+		win->bpp = 16;
+		break;
+
+	default:
+		debug("Unsupported LCD bit depth");
+		return -1;
+	}
+
+	return 0;
+}
+
+struct fdt_disp_config *tegra_display_get_config(void)
+{
+	return config.valid ? &config : NULL;
+}
+
+static void debug_timing(const char *name, unsigned int timing[])
+{
+#ifdef DEBUG
+	int i;
+
+	debug("%s timing: ", name);
+	for (i = 0; i < FDT_LCD_TIMING_COUNT; i++)
+		debug("%d ", timing[i]);
+	debug("\n");
+#endif
+}
+
+/**
+ * Decode panel information from the fdt, according to a standard binding
+ *
+ * @param blob		fdt blob
+ * @param node		offset of fdt node to read from
+ * @param config	structure to store fdt config into
+ * @return 0 if ok, -ve on error
+ */
+static int tegra_decode_panel(const void *blob, int node,
+			      struct fdt_disp_config *config)
+{
+	int front, back, ref;
+
+	config->width = fdtdec_get_int(blob, node, "xres", -1);
+	config->height = fdtdec_get_int(blob, node, "yres", -1);
+	config->pixel_clock = fdtdec_get_int(blob, node, "clock", 0);
+	if (!config->pixel_clock || config->width == -1 ||
+			config->height == -1) {
+		debug("%s: Pixel parameters missing\n", __func__);
+		return -FDT_ERR_NOTFOUND;
+	}
+
+	back = fdtdec_get_int(blob, node, "left-margin", -1);
+	front = fdtdec_get_int(blob, node, "right-margin", -1);
+	ref = fdtdec_get_int(blob, node, "hsync-len", -1);
+	if ((back | front | ref) == -1) {
+		debug("%s: Horizontal parameters missing\n", __func__);
+		return -FDT_ERR_NOTFOUND;
+	}
+
+	/* Use a ref-to-sync of 1 always, and take this from the front porch */
+	config->horiz_timing[FDT_LCD_TIMING_REF_TO_SYNC] = 1;
+	config->horiz_timing[FDT_LCD_TIMING_SYNC_WIDTH] = ref;
+	config->horiz_timing[FDT_LCD_TIMING_BACK_PORCH] = back;
+	config->horiz_timing[FDT_LCD_TIMING_FRONT_PORCH] = front -
+		config->horiz_timing[FDT_LCD_TIMING_REF_TO_SYNC];
+	debug_timing("horiz", config->horiz_timing);
+
+	back = fdtdec_get_int(blob, node, "upper-margin", -1);
+	front = fdtdec_get_int(blob, node, "lower-margin", -1);
+	ref = fdtdec_get_int(blob, node, "vsync-len", -1);
+	if ((back | front | ref) == -1) {
+		debug("%s: Vertical parameters missing\n", __func__);
+		return -FDT_ERR_NOTFOUND;
+	}
+
+	config->vert_timing[FDT_LCD_TIMING_REF_TO_SYNC] = 1;
+	config->vert_timing[FDT_LCD_TIMING_SYNC_WIDTH] = ref;
+	config->vert_timing[FDT_LCD_TIMING_BACK_PORCH] = back;
+	config->vert_timing[FDT_LCD_TIMING_FRONT_PORCH] = front -
+		config->vert_timing[FDT_LCD_TIMING_REF_TO_SYNC];
+	debug_timing("vert", config->vert_timing);
+
+	return 0;
+}
+
+/**
+ * Decode the display controller information from the fdt.
+ *
+ * @param blob		fdt blob
+ * @param config	structure to store fdt config into
+ * @return 0 if ok, -ve on error
+ */
+static int tegra_display_decode_config(const void *blob,
+				       struct fdt_disp_config *config)
+{
+	int node, rgb;
+	int bpp, bit;
+
+	/* TODO: Support multiple controllers */
+	node = fdtdec_next_compatible(blob, 0, COMPAT_NVIDIA_TEGRA20_DC);
+	if (node < 0) {
+		debug("%s: Cannot find display controller node in fdt\n",
+		      __func__);
+		return node;
+	}
+	config->disp = (struct disp_ctlr *)fdtdec_get_addr(blob, node, "reg");
+	if (!config->disp) {
+		debug("%s: No display controller address\n", __func__);
+		return -1;
+	}
+
+	rgb = fdt_subnode_offset(blob, node, "rgb");
+
+	config->panel_node = fdtdec_lookup_phandle(blob, rgb, "nvidia,panel");
+	if (config->panel_node < 0) {
+		debug("%s: Cannot find panel information\n", __func__);
+		return -1;
+	}
+
+	if (tegra_decode_panel(blob, config->panel_node, config)) {
+		debug("%s: Failed to decode panel information\n", __func__);
+		return -1;
+	}
+
+	bpp = fdtdec_get_int(blob, config->panel_node, "nvidia,bits-per-pixel",
+			     -1);
+	bit = ffs(bpp) - 1;
+	if (bpp == (1 << bit))
+		config->log2_bpp = bit;
+	else
+		config->log2_bpp = bpp;
+	if (bpp == -1) {
+		debug("%s: Pixel bpp parameters missing\n", __func__);
+		return -FDT_ERR_NOTFOUND;
+	}
+	config->bpp = bpp;
+
+	config->valid = 1;	/* we have a valid configuration */
+
+	return 0;
+}
+
+int tegra_display_probe(const void *blob, void *default_lcd_base)
+{
+	struct disp_ctl_win window;
+	struct dc_ctlr *dc;
+
+	if (tegra_display_decode_config(blob, &config))
+		return -1;
+
+	config.frame_buffer = (u32)default_lcd_base;
+
+	dc = (struct dc_ctlr *)config.disp;
+
+	/*
+	 * A header file for clock constants was NAKed upstream.
+	 * TODO: Put this into the FDT and fdt_lcd struct when we have clock
+	 * support there
+	 */
+	clock_start_periph_pll(PERIPH_ID_HOST1X, CLOCK_ID_PERIPH,
+			       144 * 1000000);
+	clock_start_periph_pll(PERIPH_ID_DISP1, CLOCK_ID_CGENERAL,
+			       600 * 1000000);
+	basic_init(&dc->cmd);
+	basic_init_timer(&dc->disp);
+	rgb_enable(&dc->com);
+
+	if (config.pixel_clock)
+		update_display_mode(&dc->disp, &config);
+
+	if (setup_window(&window, &config))
+		return -1;
+
+	update_window(dc, &window);
+
+	return 0;
+}
diff --git a/arch/arm/mach-tegra/tegra20/emc.c b/arch/arm/mach-tegra/tegra20/emc.c
new file mode 100644
index 0000000..ed2462a
--- /dev/null
+++ b/arch/arm/mach-tegra/tegra20/emc.c
@@ -0,0 +1,270 @@
+/*
+ * Copyright (c) 2011 The Chromium OS Authors.
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <fdtdec.h>
+#include <asm/io.h>
+#include <asm/arch-tegra/ap.h>
+#include <asm/arch-tegra/apb_misc.h>
+#include <asm/arch/clock.h>
+#include <asm/arch/emc.h>
+#include <asm/arch/tegra.h>
+
+/*
+ * The EMC registers have shadow registers.  When the EMC clock is updated
+ * in the clock controller, the shadow registers are copied to the active
+ * registers, allowing glitchless memory bus frequency changes.
+ * This function updates the shadow registers for a new clock frequency,
+ * and relies on the clock lock on the emc clock to avoid races between
+ * multiple frequency changes
+ */
+
+/*
+ * This table defines the ordering of the registers provided to
+ * tegra_set_mmc()
+ * TODO: Convert to fdt version once available
+ */
+static const unsigned long emc_reg_addr[TEGRA_EMC_NUM_REGS] = {
+	0x2c,	/* RC */
+	0x30,	/* RFC */
+	0x34,	/* RAS */
+	0x38,	/* RP */
+	0x3c,	/* R2W */
+	0x40,	/* W2R */
+	0x44,	/* R2P */
+	0x48,	/* W2P */
+	0x4c,	/* RD_RCD */
+	0x50,	/* WR_RCD */
+	0x54,	/* RRD */
+	0x58,	/* REXT */
+	0x5c,	/* WDV */
+	0x60,	/* QUSE */
+	0x64,	/* QRST */
+	0x68,	/* QSAFE */
+	0x6c,	/* RDV */
+	0x70,	/* REFRESH */
+	0x74,	/* BURST_REFRESH_NUM */
+	0x78,	/* PDEX2WR */
+	0x7c,	/* PDEX2RD */
+	0x80,	/* PCHG2PDEN */
+	0x84,	/* ACT2PDEN */
+	0x88,	/* AR2PDEN */
+	0x8c,	/* RW2PDEN */
+	0x90,	/* TXSR */
+	0x94,	/* TCKE */
+	0x98,	/* TFAW */
+	0x9c,	/* TRPAB */
+	0xa0,	/* TCLKSTABLE */
+	0xa4,	/* TCLKSTOP */
+	0xa8,	/* TREFBW */
+	0xac,	/* QUSE_EXTRA */
+	0x114,	/* FBIO_CFG6 */
+	0xb0,	/* ODT_WRITE */
+	0xb4,	/* ODT_READ */
+	0x104,	/* FBIO_CFG5 */
+	0x2bc,	/* CFG_DIG_DLL */
+	0x2c0,	/* DLL_XFORM_DQS */
+	0x2c4,	/* DLL_XFORM_QUSE */
+	0x2e0,	/* ZCAL_REF_CNT */
+	0x2e4,	/* ZCAL_WAIT_CNT */
+	0x2a8,	/* AUTO_CAL_INTERVAL */
+	0x2d0,	/* CFG_CLKTRIM_0 */
+	0x2d4,	/* CFG_CLKTRIM_1 */
+	0x2d8,	/* CFG_CLKTRIM_2 */
+};
+
+struct emc_ctlr *emc_get_controller(const void *blob)
+{
+	fdt_addr_t addr;
+	int node;
+
+	node = fdtdec_next_compatible(blob, 0, COMPAT_NVIDIA_TEGRA20_EMC);
+	if (node > 0) {
+		addr = fdtdec_get_addr(blob, node, "reg");
+		if (addr != FDT_ADDR_T_NONE)
+			return (struct emc_ctlr *)addr;
+	}
+	return NULL;
+}
+
+/* Error codes we use */
+enum {
+	ERR_NO_EMC_NODE = -10,
+	ERR_NO_EMC_REG,
+	ERR_NO_FREQ,
+	ERR_FREQ_NOT_FOUND,
+	ERR_BAD_REGS,
+	ERR_NO_RAM_CODE,
+	ERR_RAM_CODE_NOT_FOUND,
+};
+
+/**
+ * Find EMC tables for the given ram code.
+ *
+ * The tegra EMC binding has two options, one using the ram code and one not.
+ * We detect which is in use by looking for the nvidia,use-ram-code property.
+ * If this is not present, then the EMC tables are directly below 'node',
+ * otherwise we select the correct emc-tables subnode based on the 'ram_code'
+ * value.
+ *
+ * @param blob		Device tree blob
+ * @param node		EMC node (nvidia,tegra20-emc compatible string)
+ * @param ram_code	RAM code to select (0-3, or -1 if unknown)
+ * @return 0 if ok, otherwise a -ve ERR_ code (see enum above)
+ */
+static int find_emc_tables(const void *blob, int node, int ram_code)
+{
+	int need_ram_code;
+	int depth;
+	int offset;
+
+	/* If we are using RAM codes, scan through the tables for our code */
+	need_ram_code = fdtdec_get_bool(blob, node, "nvidia,use-ram-code");
+	if (!need_ram_code)
+		return node;
+	if (ram_code == -1) {
+		debug("%s: RAM code required but not supplied\n", __func__);
+		return ERR_NO_RAM_CODE;
+	}
+
+	offset = node;
+	depth = 0;
+	do {
+		/*
+		 * Sadly there is no compatible string so we cannot use
+		 * fdtdec_next_compatible_subnode().
+		 */
+		offset = fdt_next_node(blob, offset, &depth);
+		if (depth <= 0)
+			break;
+
+		/* Make sure this is a direct subnode */
+		if (depth != 1)
+			continue;
+		if (strcmp("emc-tables", fdt_get_name(blob, offset, NULL)))
+			continue;
+
+		if (fdtdec_get_int(blob, offset, "nvidia,ram-code", -1)
+				== ram_code)
+			return offset;
+	} while (1);
+
+	debug("%s: Could not find tables for RAM code %d\n", __func__,
+	      ram_code);
+	return ERR_RAM_CODE_NOT_FOUND;
+}
+
+/**
+ * Decode the EMC node of the device tree, returning a pointer to the emc
+ * controller and the table to be used for the given rate.
+ *
+ * @param blob	Device tree blob
+ * @param rate	Clock speed of memory controller in Hz (=2x memory bus rate)
+ * @param emcp	Returns address of EMC controller registers
+ * @param tablep Returns pointer to table to program into EMC. There are
+ *		TEGRA_EMC_NUM_REGS entries, destined for offsets as per the
+ *		emc_reg_addr array.
+ * @return 0 if ok, otherwise a -ve error code which will allow someone to
+ * figure out roughly what went wrong by looking at this code.
+ */
+static int decode_emc(const void *blob, unsigned rate, struct emc_ctlr **emcp,
+		      const u32 **tablep)
+{
+	struct apb_misc_pp_ctlr *pp =
+		(struct apb_misc_pp_ctlr *)NV_PA_APB_MISC_BASE;
+	int ram_code;
+	int depth;
+	int node;
+
+	ram_code = (readl(&pp->strapping_opt_a) & RAM_CODE_MASK)
+			>> RAM_CODE_SHIFT;
+	/*
+	 * The EMC clock rate is twice the bus rate, and the bus rate is
+	 * measured in kHz
+	 */
+	rate = rate / 2 / 1000;
+
+	node = fdtdec_next_compatible(blob, 0, COMPAT_NVIDIA_TEGRA20_EMC);
+	if (node < 0) {
+		debug("%s: No EMC node found in FDT\n", __func__);
+		return ERR_NO_EMC_NODE;
+	}
+	*emcp = (struct emc_ctlr *)fdtdec_get_addr(blob, node, "reg");
+	if (*emcp == (struct emc_ctlr *)FDT_ADDR_T_NONE) {
+		debug("%s: No EMC node reg property\n", __func__);
+		return ERR_NO_EMC_REG;
+	}
+
+	/* Work out the parent node which contains our EMC tables */
+	node = find_emc_tables(blob, node, ram_code & 3);
+	if (node < 0)
+		return node;
+
+	depth = 0;
+	for (;;) {
+		int node_rate;
+
+		node = fdtdec_next_compatible_subnode(blob, node,
+				COMPAT_NVIDIA_TEGRA20_EMC_TABLE, &depth);
+		if (node < 0)
+			break;
+		node_rate = fdtdec_get_int(blob, node, "clock-frequency", -1);
+		if (node_rate == -1) {
+			debug("%s: Missing clock-frequency\n", __func__);
+			return ERR_NO_FREQ; /* we expect this property */
+		}
+
+		if (node_rate == rate)
+			break;
+	}
+	if (node < 0) {
+		debug("%s: No node found for clock frequency %d\n", __func__,
+		      rate);
+		return ERR_FREQ_NOT_FOUND;
+	}
+
+	*tablep = fdtdec_locate_array(blob, node, "nvidia,emc-registers",
+				      TEGRA_EMC_NUM_REGS);
+	if (!*tablep) {
+		debug("%s: node '%s' array missing / wrong size\n", __func__,
+		      fdt_get_name(blob, node, NULL));
+		return ERR_BAD_REGS;
+	}
+
+	/* All seems well */
+	return 0;
+}
+
+int tegra_set_emc(const void *blob, unsigned rate)
+{
+	struct emc_ctlr *emc;
+	const u32 *table = NULL;
+	int err, i;
+
+	err = decode_emc(blob, rate, &emc, &table);
+	if (err) {
+		debug("Warning: no valid EMC (%d), memory timings unset\n",
+		       err);
+		return err;
+	}
+
+	debug("%s: Table found, setting EMC values as follows:\n", __func__);
+	for (i = 0; i < TEGRA_EMC_NUM_REGS; i++) {
+		u32 value = fdt32_to_cpu(table[i]);
+		u32 addr = (uintptr_t)emc + emc_reg_addr[i];
+
+		debug("   %#x: %#x\n", addr, value);
+		writel(value, addr);
+	}
+
+	/* trigger emc with new settings */
+	clock_adjust_periph_pll_div(PERIPH_ID_EMC, CLOCK_ID_MEMORY,
+				clock_get_rate(CLOCK_ID_MEMORY), NULL);
+	debug("EMC clock set to %lu\n",
+	      clock_get_periph_rate(PERIPH_ID_EMC, CLOCK_ID_MEMORY));
+
+	return 0;
+}
diff --git a/arch/arm/mach-tegra/tegra20/funcmux.c b/arch/arm/mach-tegra/tegra20/funcmux.c
new file mode 100644
index 0000000..0df4a07
--- /dev/null
+++ b/arch/arm/mach-tegra/tegra20/funcmux.c
@@ -0,0 +1,296 @@
+/*
+ * Copyright (c) 2011 The Chromium OS Authors.
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+/* Tegra20 high-level function multiplexing */
+#include <common.h>
+#include <asm/arch/clock.h>
+#include <asm/arch/funcmux.h>
+#include <asm/arch/pinmux.h>
+
+/*
+ * The PINMUX macro is used to set up pinmux tables.
+ */
+#define PINMUX(grp, mux, pupd, tri)                   \
+	{PMUX_PINGRP_##grp, PMUX_FUNC_##mux, PMUX_PULL_##pupd, PMUX_TRI_##tri}
+
+static const struct pmux_pingrp_config disp1_default[] = {
+	PINMUX(LDI,   DISPA,      NORMAL,    NORMAL),
+	PINMUX(LHP0,  DISPA,      NORMAL,    NORMAL),
+	PINMUX(LHP1,  DISPA,      NORMAL,    NORMAL),
+	PINMUX(LHP2,  DISPA,      NORMAL,    NORMAL),
+	PINMUX(LHS,   DISPA,      NORMAL,    NORMAL),
+	PINMUX(LM0,   RSVD4,      NORMAL,    NORMAL),
+	PINMUX(LPP,   DISPA,      NORMAL,    NORMAL),
+	PINMUX(LPW0,  DISPA,      NORMAL,    NORMAL),
+	PINMUX(LPW2,  DISPA,      NORMAL,    NORMAL),
+	PINMUX(LSC0,  DISPA,      NORMAL,    NORMAL),
+	PINMUX(LSPI,  DISPA,      NORMAL,    NORMAL),
+	PINMUX(LVP1,  DISPA,      NORMAL,    NORMAL),
+	PINMUX(LVS,   DISPA,      NORMAL,    NORMAL),
+	PINMUX(SLXD,  SPDIF,      NORMAL,    NORMAL),
+};
+
+
+int funcmux_select(enum periph_id id, int config)
+{
+	int bad_config = config != FUNCMUX_DEFAULT;
+
+	switch (id) {
+	case PERIPH_ID_UART1:
+		switch (config) {
+		case FUNCMUX_UART1_IRRX_IRTX:
+			pinmux_set_func(PMUX_PINGRP_IRRX, PMUX_FUNC_UARTA);
+			pinmux_set_func(PMUX_PINGRP_IRTX, PMUX_FUNC_UARTA);
+			pinmux_tristate_disable(PMUX_PINGRP_IRRX);
+			pinmux_tristate_disable(PMUX_PINGRP_IRTX);
+			break;
+		case FUNCMUX_UART1_UAA_UAB:
+			pinmux_set_func(PMUX_PINGRP_UAA, PMUX_FUNC_UARTA);
+			pinmux_set_func(PMUX_PINGRP_UAB, PMUX_FUNC_UARTA);
+			pinmux_tristate_disable(PMUX_PINGRP_UAA);
+			pinmux_tristate_disable(PMUX_PINGRP_UAB);
+			bad_config = 0;
+			break;
+		case FUNCMUX_UART1_GPU:
+			pinmux_set_func(PMUX_PINGRP_GPU, PMUX_FUNC_UARTA);
+			pinmux_tristate_disable(PMUX_PINGRP_GPU);
+			bad_config = 0;
+			break;
+		case FUNCMUX_UART1_SDIO1:
+			pinmux_set_func(PMUX_PINGRP_SDIO1, PMUX_FUNC_UARTA);
+			pinmux_tristate_disable(PMUX_PINGRP_SDIO1);
+			bad_config = 0;
+			break;
+		}
+		if (!bad_config) {
+			/*
+			 * Tegra appears to boot with function UARTA pre-
+			 * selected on mux group SDB. If two mux groups are
+			 * both set to the same function, it's unclear which
+			 * group's pins drive the RX signals into the HW.
+			 * For UARTA, SDB certainly overrides group IRTX in
+			 * practice. To solve this, configure some alternative
+			 * function on SDB to avoid the conflict. Also, tri-
+			 * state the group to avoid driving any signal onto it
+			 * until we know what's connected.
+			 */
+			pinmux_tristate_enable(PMUX_PINGRP_SDB);
+			pinmux_set_func(PMUX_PINGRP_SDB,  PMUX_FUNC_SDIO3);
+		}
+		break;
+
+	case PERIPH_ID_UART2:
+		if (config == FUNCMUX_UART2_UAD) {
+			pinmux_set_func(PMUX_PINGRP_UAD, PMUX_FUNC_UARTB);
+			pinmux_tristate_disable(PMUX_PINGRP_UAD);
+		}
+		break;
+
+	case PERIPH_ID_UART4:
+		if (config == FUNCMUX_UART4_GMC) {
+			pinmux_set_func(PMUX_PINGRP_GMC, PMUX_FUNC_UARTD);
+			pinmux_tristate_disable(PMUX_PINGRP_GMC);
+		}
+		break;
+
+	case PERIPH_ID_DVC_I2C:
+		/* there is only one selection, pinmux_config is ignored */
+		if (config == FUNCMUX_DVC_I2CP) {
+			pinmux_set_func(PMUX_PINGRP_I2CP, PMUX_FUNC_I2C);
+			pinmux_tristate_disable(PMUX_PINGRP_I2CP);
+		}
+		break;
+
+	case PERIPH_ID_I2C1:
+		/* support pinmux_config of 0 for now, */
+		if (config == FUNCMUX_I2C1_RM) {
+			pinmux_set_func(PMUX_PINGRP_RM, PMUX_FUNC_I2C);
+			pinmux_tristate_disable(PMUX_PINGRP_RM);
+		}
+		break;
+	case PERIPH_ID_I2C2: /* I2C2 */
+		switch (config) {
+		case FUNCMUX_I2C2_DDC:	/* DDC pin group, select I2C2 */
+			pinmux_set_func(PMUX_PINGRP_DDC, PMUX_FUNC_I2C2);
+			/* PTA to HDMI */
+			pinmux_set_func(PMUX_PINGRP_PTA, PMUX_FUNC_HDMI);
+			pinmux_tristate_disable(PMUX_PINGRP_DDC);
+			break;
+		case FUNCMUX_I2C2_PTA:	/* PTA pin group, select I2C2 */
+			pinmux_set_func(PMUX_PINGRP_PTA, PMUX_FUNC_I2C2);
+			/* set DDC_SEL to RSVDx (RSVD2 works for now) */
+			pinmux_set_func(PMUX_PINGRP_DDC, PMUX_FUNC_RSVD2);
+			pinmux_tristate_disable(PMUX_PINGRP_PTA);
+			bad_config = 0;
+			break;
+		}
+		break;
+	case PERIPH_ID_I2C3: /* I2C3 */
+		/* support pinmux_config of 0 for now */
+		if (config == FUNCMUX_I2C3_DTF) {
+			pinmux_set_func(PMUX_PINGRP_DTF, PMUX_FUNC_I2C3);
+			pinmux_tristate_disable(PMUX_PINGRP_DTF);
+		}
+		break;
+
+	case PERIPH_ID_SDMMC1:
+		if (config == FUNCMUX_SDMMC1_SDIO1_4BIT) {
+			pinmux_set_func(PMUX_PINGRP_SDIO1, PMUX_FUNC_SDIO1);
+			pinmux_tristate_disable(PMUX_PINGRP_SDIO1);
+		}
+		break;
+
+	case PERIPH_ID_SDMMC2:
+		if (config == FUNCMUX_SDMMC2_DTA_DTD_8BIT) {
+			pinmux_set_func(PMUX_PINGRP_DTA, PMUX_FUNC_SDIO2);
+			pinmux_set_func(PMUX_PINGRP_DTD, PMUX_FUNC_SDIO2);
+
+			pinmux_tristate_disable(PMUX_PINGRP_DTA);
+			pinmux_tristate_disable(PMUX_PINGRP_DTD);
+		}
+		break;
+
+	case PERIPH_ID_SDMMC3:
+		switch (config) {
+		case FUNCMUX_SDMMC3_SDB_SLXA_8BIT:
+			pinmux_set_func(PMUX_PINGRP_SLXA, PMUX_FUNC_SDIO3);
+			pinmux_set_func(PMUX_PINGRP_SLXC, PMUX_FUNC_SDIO3);
+			pinmux_set_func(PMUX_PINGRP_SLXD, PMUX_FUNC_SDIO3);
+			pinmux_set_func(PMUX_PINGRP_SLXK, PMUX_FUNC_SDIO3);
+
+			pinmux_tristate_disable(PMUX_PINGRP_SLXA);
+			pinmux_tristate_disable(PMUX_PINGRP_SLXC);
+			pinmux_tristate_disable(PMUX_PINGRP_SLXD);
+			pinmux_tristate_disable(PMUX_PINGRP_SLXK);
+			/* fall through */
+
+		case FUNCMUX_SDMMC3_SDB_4BIT:
+			pinmux_set_func(PMUX_PINGRP_SDB, PMUX_FUNC_SDIO3);
+			pinmux_set_func(PMUX_PINGRP_SDC, PMUX_FUNC_SDIO3);
+			pinmux_set_func(PMUX_PINGRP_SDD, PMUX_FUNC_SDIO3);
+
+			pinmux_tristate_disable(PMUX_PINGRP_SDB);
+			pinmux_tristate_disable(PMUX_PINGRP_SDC);
+			pinmux_tristate_disable(PMUX_PINGRP_SDD);
+			bad_config = 0;
+			break;
+		}
+		break;
+
+	case PERIPH_ID_SDMMC4:
+		switch (config) {
+		case FUNCMUX_SDMMC4_ATC_ATD_8BIT:
+			pinmux_set_func(PMUX_PINGRP_ATC, PMUX_FUNC_SDIO4);
+			pinmux_set_func(PMUX_PINGRP_ATD, PMUX_FUNC_SDIO4);
+
+			pinmux_tristate_disable(PMUX_PINGRP_ATC);
+			pinmux_tristate_disable(PMUX_PINGRP_ATD);
+			break;
+
+		case FUNCMUX_SDMMC4_ATB_GMA_GME_8_BIT:
+			pinmux_set_func(PMUX_PINGRP_GME, PMUX_FUNC_SDIO4);
+			pinmux_tristate_disable(PMUX_PINGRP_GME);
+			/* fall through */
+
+		case FUNCMUX_SDMMC4_ATB_GMA_4_BIT:
+			pinmux_set_func(PMUX_PINGRP_ATB, PMUX_FUNC_SDIO4);
+			pinmux_set_func(PMUX_PINGRP_GMA, PMUX_FUNC_SDIO4);
+
+			pinmux_tristate_disable(PMUX_PINGRP_ATB);
+			pinmux_tristate_disable(PMUX_PINGRP_GMA);
+			bad_config = 0;
+			break;
+		}
+		break;
+
+	case PERIPH_ID_KBC:
+		if (config == FUNCMUX_DEFAULT) {
+			enum pmux_pingrp grp[] = {PMUX_PINGRP_KBCA,
+				PMUX_PINGRP_KBCB, PMUX_PINGRP_KBCC,
+				PMUX_PINGRP_KBCD, PMUX_PINGRP_KBCE,
+				PMUX_PINGRP_KBCF};
+			int i;
+
+			for (i = 0; i < ARRAY_SIZE(grp); i++) {
+				pinmux_tristate_disable(grp[i]);
+				pinmux_set_func(grp[i], PMUX_FUNC_KBC);
+				pinmux_set_pullupdown(grp[i], PMUX_PULL_UP);
+			}
+		}
+		break;
+
+	case PERIPH_ID_USB2:
+		if (config == FUNCMUX_USB2_ULPI) {
+			pinmux_set_func(PMUX_PINGRP_UAA, PMUX_FUNC_ULPI);
+			pinmux_set_func(PMUX_PINGRP_UAB, PMUX_FUNC_ULPI);
+			pinmux_set_func(PMUX_PINGRP_UDA, PMUX_FUNC_ULPI);
+
+			pinmux_tristate_disable(PMUX_PINGRP_UAA);
+			pinmux_tristate_disable(PMUX_PINGRP_UAB);
+			pinmux_tristate_disable(PMUX_PINGRP_UDA);
+		}
+		break;
+
+	case PERIPH_ID_SPI1:
+		if (config == FUNCMUX_SPI1_GMC_GMD) {
+			pinmux_set_func(PMUX_PINGRP_GMC, PMUX_FUNC_SFLASH);
+			pinmux_set_func(PMUX_PINGRP_GMD, PMUX_FUNC_SFLASH);
+
+			pinmux_tristate_disable(PMUX_PINGRP_GMC);
+			pinmux_tristate_disable(PMUX_PINGRP_GMD);
+		}
+		break;
+
+	case PERIPH_ID_NDFLASH:
+		switch (config) {
+		case FUNCMUX_NDFLASH_ATC:
+			pinmux_set_func(PMUX_PINGRP_ATC, PMUX_FUNC_NAND);
+			pinmux_tristate_disable(PMUX_PINGRP_ATC);
+			break;
+		case FUNCMUX_NDFLASH_KBC_8_BIT:
+			pinmux_set_func(PMUX_PINGRP_KBCA, PMUX_FUNC_NAND);
+			pinmux_set_func(PMUX_PINGRP_KBCC, PMUX_FUNC_NAND);
+			pinmux_set_func(PMUX_PINGRP_KBCD, PMUX_FUNC_NAND);
+			pinmux_set_func(PMUX_PINGRP_KBCE, PMUX_FUNC_NAND);
+			pinmux_set_func(PMUX_PINGRP_KBCF, PMUX_FUNC_NAND);
+
+			pinmux_tristate_disable(PMUX_PINGRP_KBCA);
+			pinmux_tristate_disable(PMUX_PINGRP_KBCC);
+			pinmux_tristate_disable(PMUX_PINGRP_KBCD);
+			pinmux_tristate_disable(PMUX_PINGRP_KBCE);
+			pinmux_tristate_disable(PMUX_PINGRP_KBCF);
+
+			bad_config = 0;
+			break;
+		}
+		break;
+	case PERIPH_ID_DISP1:
+		if (config == FUNCMUX_DEFAULT) {
+			int i;
+
+			for (i = PMUX_PINGRP_LD0; i <= PMUX_PINGRP_LD17; i++) {
+				pinmux_set_func(i, PMUX_FUNC_DISPA);
+				pinmux_tristate_disable(i);
+				pinmux_set_pullupdown(i, PMUX_PULL_NORMAL);
+			}
+			pinmux_config_pingrp_table(disp1_default,
+						   ARRAY_SIZE(disp1_default));
+		}
+		break;
+
+	default:
+		debug("%s: invalid periph_id %d", __func__, id);
+		return -1;
+	}
+
+	if (bad_config) {
+		debug("%s: invalid config %d for periph_id %d", __func__,
+		      config, id);
+		return -1;
+	}
+
+	return 0;
+}
diff --git a/arch/arm/mach-tegra/tegra20/pinmux.c b/arch/arm/mach-tegra/tegra20/pinmux.c
new file mode 100644
index 0000000..e484f99
--- /dev/null
+++ b/arch/arm/mach-tegra/tegra20/pinmux.c
@@ -0,0 +1,425 @@
+/*
+ * Copyright (c) 2011 The Chromium OS Authors.
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+/* Tegra20 pin multiplexing functions */
+
+#include <common.h>
+#include <asm/io.h>
+#include <asm/arch/pinmux.h>
+
+/*
+ * This defines the order of the pin mux control bits in the registers. For
+ * some reason there is no correspendence between the tristate, pin mux and
+ * pullup/pulldown registers.
+ */
+enum pmux_ctlid {
+	/* 0: APB_MISC_PP_PIN_MUX_CTL_A_0 */
+	MUXCTL_UAA,
+	MUXCTL_UAB,
+	MUXCTL_UAC,
+	MUXCTL_UAD,
+	MUXCTL_UDA,
+	MUXCTL_RESERVED5,
+	MUXCTL_ATE,
+	MUXCTL_RM,
+
+	MUXCTL_ATB,
+	MUXCTL_RESERVED9,
+	MUXCTL_ATD,
+	MUXCTL_ATC,
+	MUXCTL_ATA,
+	MUXCTL_KBCF,
+	MUXCTL_KBCE,
+	MUXCTL_SDMMC1,
+
+	/* 16: APB_MISC_PP_PIN_MUX_CTL_B_0 */
+	MUXCTL_GMA,
+	MUXCTL_GMC,
+	MUXCTL_HDINT,
+	MUXCTL_SLXA,
+	MUXCTL_OWC,
+	MUXCTL_SLXC,
+	MUXCTL_SLXD,
+	MUXCTL_SLXK,
+
+	MUXCTL_UCA,
+	MUXCTL_UCB,
+	MUXCTL_DTA,
+	MUXCTL_DTB,
+	MUXCTL_RESERVED28,
+	MUXCTL_DTC,
+	MUXCTL_DTD,
+	MUXCTL_DTE,
+
+	/* 32: APB_MISC_PP_PIN_MUX_CTL_C_0 */
+	MUXCTL_DDC,
+	MUXCTL_CDEV1,
+	MUXCTL_CDEV2,
+	MUXCTL_CSUS,
+	MUXCTL_I2CP,
+	MUXCTL_KBCA,
+	MUXCTL_KBCB,
+	MUXCTL_KBCC,
+
+	MUXCTL_IRTX,
+	MUXCTL_IRRX,
+	MUXCTL_DAP1,
+	MUXCTL_DAP2,
+	MUXCTL_DAP3,
+	MUXCTL_DAP4,
+	MUXCTL_GMB,
+	MUXCTL_GMD,
+
+	/* 48: APB_MISC_PP_PIN_MUX_CTL_D_0 */
+	MUXCTL_GME,
+	MUXCTL_GPV,
+	MUXCTL_GPU,
+	MUXCTL_SPDO,
+	MUXCTL_SPDI,
+	MUXCTL_SDB,
+	MUXCTL_SDC,
+	MUXCTL_SDD,
+
+	MUXCTL_SPIH,
+	MUXCTL_SPIG,
+	MUXCTL_SPIF,
+	MUXCTL_SPIE,
+	MUXCTL_SPID,
+	MUXCTL_SPIC,
+	MUXCTL_SPIB,
+	MUXCTL_SPIA,
+
+	/* 64: APB_MISC_PP_PIN_MUX_CTL_E_0 */
+	MUXCTL_LPW0,
+	MUXCTL_LPW1,
+	MUXCTL_LPW2,
+	MUXCTL_LSDI,
+	MUXCTL_LSDA,
+	MUXCTL_LSPI,
+	MUXCTL_LCSN,
+	MUXCTL_LDC,
+
+	MUXCTL_LSCK,
+	MUXCTL_LSC0,
+	MUXCTL_LSC1,
+	MUXCTL_LHS,
+	MUXCTL_LVS,
+	MUXCTL_LM0,
+	MUXCTL_LM1,
+	MUXCTL_LVP0,
+
+	/* 80: APB_MISC_PP_PIN_MUX_CTL_F_0 */
+	MUXCTL_LD0,
+	MUXCTL_LD1,
+	MUXCTL_LD2,
+	MUXCTL_LD3,
+	MUXCTL_LD4,
+	MUXCTL_LD5,
+	MUXCTL_LD6,
+	MUXCTL_LD7,
+
+	MUXCTL_LD8,
+	MUXCTL_LD9,
+	MUXCTL_LD10,
+	MUXCTL_LD11,
+	MUXCTL_LD12,
+	MUXCTL_LD13,
+	MUXCTL_LD14,
+	MUXCTL_LD15,
+
+	/* 96: APB_MISC_PP_PIN_MUX_CTL_G_0 */
+	MUXCTL_LD16,
+	MUXCTL_LD17,
+	MUXCTL_LHP1,
+	MUXCTL_LHP2,
+	MUXCTL_LVP1,
+	MUXCTL_LHP0,
+	MUXCTL_RESERVED102,
+	MUXCTL_LPP,
+
+	MUXCTL_LDI,
+	MUXCTL_PMC,
+	MUXCTL_CRTP,
+	MUXCTL_PTA,
+	MUXCTL_RESERVED108,
+	MUXCTL_KBCD,
+	MUXCTL_GPU7,
+	MUXCTL_DTF,
+
+	MUXCTL_NONE = -1,
+};
+
+/*
+ * And this defines the order of the pullup/pulldown controls which are again
+ * in a different order
+ */
+enum pmux_pullid {
+	/* 0: APB_MISC_PP_PULLUPDOWN_REG_A_0 */
+	PUCTL_ATA,
+	PUCTL_ATB,
+	PUCTL_ATC,
+	PUCTL_ATD,
+	PUCTL_ATE,
+	PUCTL_DAP1,
+	PUCTL_DAP2,
+	PUCTL_DAP3,
+
+	PUCTL_DAP4,
+	PUCTL_DTA,
+	PUCTL_DTB,
+	PUCTL_DTC,
+	PUCTL_DTD,
+	PUCTL_DTE,
+	PUCTL_DTF,
+	PUCTL_GPV,
+
+	/* 16: APB_MISC_PP_PULLUPDOWN_REG_B_0 */
+	PUCTL_RM,
+	PUCTL_I2CP,
+	PUCTL_PTA,
+	PUCTL_GPU7,
+	PUCTL_KBCA,
+	PUCTL_KBCB,
+	PUCTL_KBCC,
+	PUCTL_KBCD,
+
+	PUCTL_SPDI,
+	PUCTL_SPDO,
+	PUCTL_GPSLXAU,
+	PUCTL_CRTP,
+	PUCTL_SLXC,
+	PUCTL_SLXD,
+	PUCTL_SLXK,
+
+	/* 32: APB_MISC_PP_PULLUPDOWN_REG_C_0 */
+	PUCTL_CDEV1,
+	PUCTL_CDEV2,
+	PUCTL_SPIA,
+	PUCTL_SPIB,
+	PUCTL_SPIC,
+	PUCTL_SPID,
+	PUCTL_SPIE,
+	PUCTL_SPIF,
+
+	PUCTL_SPIG,
+	PUCTL_SPIH,
+	PUCTL_IRTX,
+	PUCTL_IRRX,
+	PUCTL_GME,
+	PUCTL_RESERVED45,
+	PUCTL_XM2D,
+	PUCTL_XM2C,
+
+	/* 48: APB_MISC_PP_PULLUPDOWN_REG_D_0 */
+	PUCTL_UAA,
+	PUCTL_UAB,
+	PUCTL_UAC,
+	PUCTL_UAD,
+	PUCTL_UCA,
+	PUCTL_UCB,
+	PUCTL_LD17,
+	PUCTL_LD19_18,
+
+	PUCTL_LD21_20,
+	PUCTL_LD23_22,
+	PUCTL_LS,
+	PUCTL_LC,
+	PUCTL_CSUS,
+	PUCTL_DDRC,
+	PUCTL_SDC,
+	PUCTL_SDD,
+
+	/* 64: APB_MISC_PP_PULLUPDOWN_REG_E_0 */
+	PUCTL_KBCF,
+	PUCTL_KBCE,
+	PUCTL_PMCA,
+	PUCTL_PMCB,
+	PUCTL_PMCC,
+	PUCTL_PMCD,
+	PUCTL_PMCE,
+	PUCTL_CK32,
+
+	PUCTL_UDA,
+	PUCTL_SDMMC1,
+	PUCTL_GMA,
+	PUCTL_GMB,
+	PUCTL_GMC,
+	PUCTL_GMD,
+	PUCTL_DDC,
+	PUCTL_OWC,
+
+	PUCTL_NONE = -1
+};
+
+/* Convenient macro for defining pin group properties */
+#define PINALL(pingrp, f0, f1, f2, f3, mux, pupd)	\
+	{						\
+		.funcs = {				\
+			PMUX_FUNC_ ## f0,		\
+			PMUX_FUNC_ ## f1,		\
+			PMUX_FUNC_ ## f2,		\
+			PMUX_FUNC_ ## f3,		\
+		},					\
+		.ctl_id = mux,				\
+		.pull_id = pupd				\
+	}
+
+/* A normal pin group where the mux name and pull-up name match */
+#define PIN(pingrp, f0, f1, f2, f3) \
+	PINALL(pingrp, f0, f1, f2, f3, MUXCTL_##pingrp, PUCTL_##pingrp)
+
+/* A pin group where the pull-up name doesn't have a 1-1 mapping */
+#define PINP(pingrp, f0, f1, f2, f3, pupd) \
+	PINALL(pingrp, f0, f1, f2, f3, MUXCTL_##pingrp, PUCTL_##pupd)
+
+/* A pin group number which is not used */
+#define PIN_RESERVED \
+	PIN(NONE, RSVD1, RSVD2, RSVD3, RSVD4)
+
+#define DRVGRP(drvgrp) \
+	PINALL(drvgrp, RSVD1, RSVD2, RSVD3, RSVD4, MUXCTL_NONE, PUCTL_NONE)
+
+static const struct pmux_pingrp_desc tegra20_pingroups[] = {
+	PIN(ATA,    IDE,       NAND,      GMI,       RSVD4),
+	PIN(ATB,    IDE,       NAND,      GMI,       SDIO4),
+	PIN(ATC,    IDE,       NAND,      GMI,       SDIO4),
+	PIN(ATD,    IDE,       NAND,      GMI,       SDIO4),
+	PIN(CDEV1,  OSC,       PLLA_OUT,  PLLM_OUT1, AUDIO_SYNC),
+	PIN(CDEV2,  OSC,       AHB_CLK,   APB_CLK,   PLLP_OUT4),
+	PIN(CSUS,   PLLC_OUT1, PLLP_OUT2, PLLP_OUT3, VI_SENSOR_CLK),
+	PIN(DAP1,   DAP1,      RSVD2,     GMI,       SDIO2),
+
+	PIN(DAP2,   DAP2,      TWC,       RSVD3,     GMI),
+	PIN(DAP3,   DAP3,      RSVD2,     RSVD3,     RSVD4),
+	PIN(DAP4,   DAP4,      RSVD2,     GMI,       RSVD4),
+	PIN(DTA,    RSVD1,     SDIO2,     VI,        RSVD4),
+	PIN(DTB,    RSVD1,     RSVD2,     VI,        SPI1),
+	PIN(DTC,    RSVD1,     RSVD2,     VI,        RSVD4),
+	PIN(DTD,    RSVD1,     SDIO2,     VI,        RSVD4),
+	PIN(DTE,    RSVD1,     RSVD2,     VI,        SPI1),
+
+	PINP(GPU,   PWM,       UARTA,     GMI,       RSVD4,         GPSLXAU),
+	PIN(GPV,    PCIE,      RSVD2,     RSVD3,     RSVD4),
+	PIN(I2CP,   I2C,       RSVD2,     RSVD3,     RSVD4),
+	PIN(IRTX,   UARTA,     UARTB,     GMI,       SPI4),
+	PIN(IRRX,   UARTA,     UARTB,     GMI,       SPI4),
+	PIN(KBCB,   KBC,       NAND,      SDIO2,     MIO),
+	PIN(KBCA,   KBC,       NAND,      SDIO2,     EMC_TEST0_DLL),
+	PINP(PMC,   PWR_ON,    PWR_INTR,  RSVD3,     RSVD4,         NONE),
+
+	PIN(PTA,    I2C2,      HDMI,      GMI,       RSVD4),
+	PIN(RM,     I2C,       RSVD2,     RSVD3,     RSVD4),
+	PIN(KBCE,   KBC,       NAND,      OWR,       RSVD4),
+	PIN(KBCF,   KBC,       NAND,      TRACE,     MIO),
+	PIN(GMA,    UARTE,     SPI3,      GMI,       SDIO4),
+	PIN(GMC,    UARTD,     SPI4,      GMI,       SFLASH),
+	PIN(SDMMC1, SDIO1,     RSVD2,     UARTE,     UARTA),
+	PIN(OWC,    OWR,       RSVD2,     RSVD3,     RSVD4),
+
+	PIN(GME,    RSVD1,     DAP5,      GMI,       SDIO4),
+	PIN(SDC,    PWM,       TWC,       SDIO3,     SPI3),
+	PIN(SDD,    UARTA,     PWM,       SDIO3,     SPI3),
+	PIN_RESERVED,
+	PINP(SLXA,  PCIE,      SPI4,      SDIO3,     SPI2,          CRTP),
+	PIN(SLXC,   SPDIF,     SPI4,      SDIO3,     SPI2),
+	PIN(SLXD,   SPDIF,     SPI4,      SDIO3,     SPI2),
+	PIN(SLXK,   PCIE,      SPI4,      SDIO3,     SPI2),
+
+	PIN(SPDI,   SPDIF,     RSVD2,     I2C,       SDIO2),
+	PIN(SPDO,   SPDIF,     RSVD2,     I2C,       SDIO2),
+	PIN(SPIA,   SPI1,      SPI2,      SPI3,      GMI),
+	PIN(SPIB,   SPI1,      SPI2,      SPI3,      GMI),
+	PIN(SPIC,   SPI1,      SPI2,      SPI3,      GMI),
+	PIN(SPID,   SPI2,      SPI1,      SPI2_ALT,  GMI),
+	PIN(SPIE,   SPI2,      SPI1,      SPI2_ALT,  GMI),
+	PIN(SPIF,   SPI3,      SPI1,      SPI2,      RSVD4),
+
+	PIN(SPIG,   SPI3,      SPI2,      SPI2_ALT,  I2C),
+	PIN(SPIH,   SPI3,      SPI2,      SPI2_ALT,  I2C),
+	PIN(UAA,    SPI3,      MIPI_HS,   UARTA,     ULPI),
+	PIN(UAB,    SPI2,      MIPI_HS,   UARTA,     ULPI),
+	PIN(UAC,    OWR,       RSVD2,     RSVD3,     RSVD4),
+	PIN(UAD,    UARTB,     SPDIF,     UARTA,     SPI4),
+	PIN(UCA,    UARTC,     RSVD2,     GMI,       RSVD4),
+	PIN(UCB,    UARTC,     PWM,       GMI,       RSVD4),
+
+	PIN_RESERVED,
+	PIN(ATE,    IDE,       NAND,      GMI,       RSVD4),
+	PIN(KBCC,   KBC,       NAND,      TRACE,     EMC_TEST1_DLL),
+	PIN_RESERVED,
+	PIN_RESERVED,
+	PIN(GMB,    IDE,       NAND,      GMI,       GMI_INT),
+	PIN(GMD,    RSVD1,     NAND,      GMI,       SFLASH),
+	PIN(DDC,    I2C2,      RSVD2,     RSVD3,     RSVD4),
+
+	/* 64 */
+	PINP(LD0,   DISPA,     DISPB,     XIO,       RSVD4,         LD17),
+	PINP(LD1,   DISPA,     DISPB,     XIO,       RSVD4,         LD17),
+	PINP(LD2,   DISPA,     DISPB,     XIO,       RSVD4,         LD17),
+	PINP(LD3,   DISPA,     DISPB,     XIO,       RSVD4,         LD17),
+	PINP(LD4,   DISPA,     DISPB,     XIO,       RSVD4,         LD17),
+	PINP(LD5,   DISPA,     DISPB,     XIO,       RSVD4,         LD17),
+	PINP(LD6,   DISPA,     DISPB,     XIO,       RSVD4,         LD17),
+	PINP(LD7,   DISPA,     DISPB,     XIO,       RSVD4,         LD17),
+
+	PINP(LD8,   DISPA,     DISPB,     XIO,       RSVD4,         LD17),
+	PINP(LD9,   DISPA,     DISPB,     XIO,       RSVD4,         LD17),
+	PINP(LD10,  DISPA,     DISPB,     XIO,       RSVD4,         LD17),
+	PINP(LD11,  DISPA,     DISPB,     XIO,       RSVD4,         LD17),
+	PINP(LD12,  DISPA,     DISPB,     XIO,       RSVD4,         LD17),
+	PINP(LD13,  DISPA,     DISPB,     XIO,       RSVD4,         LD17),
+	PINP(LD14,  DISPA,     DISPB,     XIO,       RSVD4,         LD17),
+	PINP(LD15,  DISPA,     DISPB,     XIO,       RSVD4,         LD17),
+
+	PINP(LD16,  DISPA,     DISPB,     XIO,       RSVD4,         LD17),
+	PINP(LD17,  DISPA,     DISPB,     RSVD3,     RSVD4,         LD17),
+	PINP(LHP0,  DISPA,     DISPB,     RSVD3,     RSVD4,         LD21_20),
+	PINP(LHP1,  DISPA,     DISPB,     RSVD3,     RSVD4,         LD19_18),
+	PINP(LHP2,  DISPA,     DISPB,     RSVD3,     RSVD4,         LD19_18),
+	PINP(LVP0,  DISPA,     DISPB,     RSVD3,     RSVD4,         LC),
+	PINP(LVP1,  DISPA,     DISPB,     RSVD3,     RSVD4,         LD21_20),
+	PINP(HDINT, HDMI,      RSVD2,     RSVD3,     RSVD4,         LC),
+
+	PINP(LM0,   DISPA,     DISPB,     SPI3,      RSVD4,         LC),
+	PINP(LM1,   DISPA,     DISPB,     RSVD3,     CRT,           LC),
+	PINP(LVS,   DISPA,     DISPB,     XIO,       RSVD4,         LC),
+	PINP(LSC0,  DISPA,     DISPB,     XIO,       RSVD4,         LC),
+	PINP(LSC1,  DISPA,     DISPB,     SPI3,      HDMI,          LS),
+	PINP(LSCK,  DISPA,     DISPB,     SPI3,      HDMI,          LS),
+	PINP(LDC,   DISPA,     DISPB,     RSVD3,     RSVD4,         LS),
+	PINP(LCSN,  DISPA,     DISPB,     SPI3,      RSVD4,         LS),
+
+	/* 96 */
+	PINP(LSPI,  DISPA,     DISPB,     XIO,       HDMI,          LC),
+	PINP(LSDA,  DISPA,     DISPB,     SPI3,      HDMI,          LS),
+	PINP(LSDI,  DISPA,     DISPB,     SPI3,      RSVD4,         LS),
+	PINP(LPW0,  DISPA,     DISPB,     SPI3,      HDMI,          LS),
+	PINP(LPW1,  DISPA,     DISPB,     RSVD3,     RSVD4,         LS),
+	PINP(LPW2,  DISPA,     DISPB,     SPI3,      HDMI,          LS),
+	PINP(LDI,   DISPA,     DISPB,     RSVD3,     RSVD4,         LD23_22),
+	PINP(LHS,   DISPA,     DISPB,     XIO,       RSVD4,         LC),
+
+	PINP(LPP,   DISPA,     DISPB,     RSVD3,     RSVD4,         LD23_22),
+	PIN_RESERVED,
+	PIN(KBCD,   KBC,       NAND,      SDIO2,     MIO),
+	PIN(GPU7,   RTCK,      RSVD2,     RSVD3,     RSVD4),
+	PIN(DTF,    I2C3,      RSVD2,     VI,        RSVD4),
+	PIN(UDA,    SPI1,      RSVD2,     UARTD,     ULPI),
+	PIN(CRTP,   CRT,       RSVD2,     RSVD3,     RSVD4),
+	PINP(SDB,   UARTA,     PWM,       SDIO3,     SPI2,          NONE),
+
+	/* these pin groups only have pullup and pull down control */
+	DRVGRP(CK32),
+	DRVGRP(DDRC),
+	DRVGRP(PMCA),
+	DRVGRP(PMCB),
+	DRVGRP(PMCC),
+	DRVGRP(PMCD),
+	DRVGRP(PMCE),
+	DRVGRP(XM2C),
+	DRVGRP(XM2D),
+};
+const struct pmux_pingrp_desc *tegra_soc_pingroups = tegra20_pingroups;
diff --git a/arch/arm/mach-tegra/tegra20/pmu.c b/arch/arm/mach-tegra/tegra20/pmu.c
new file mode 100644
index 0000000..a774246
--- /dev/null
+++ b/arch/arm/mach-tegra/tegra20/pmu.c
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2011 The Chromium OS Authors.
+ * (C) Copyright 2010,2011 NVIDIA Corporation <www.nvidia.com>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <i2c.h>
+#include <tps6586x.h>
+#include <asm/io.h>
+#include <asm/arch/tegra.h>
+#include <asm/arch-tegra/ap.h>
+#include <asm/arch-tegra/tegra_i2c.h>
+#include <asm/arch-tegra/sys_proto.h>
+
+#define VDD_CORE_NOMINAL_T25	0x17	/* 1.3v */
+#define VDD_CPU_NOMINAL_T25	0x10	/* 1.125v */
+
+#define VDD_CORE_NOMINAL_T20	0x16	/* 1.275v */
+#define VDD_CPU_NOMINAL_T20	0x0f	/* 1.1v */
+
+#define VDD_RELATION		0x02	/*  50mv */
+#define VDD_TRANSITION_STEP	0x06	/* 150mv */
+#define VDD_TRANSITION_RATE	0x06	/* 3.52mv/us */
+
+#define PMI_I2C_ADDRESS	0x34	/* chip requires this address */
+
+int pmu_set_nominal(void)
+{
+	struct udevice *bus, *dev;
+	int core, cpu;
+	int ret;
+
+	/* by default, the table has been filled with T25 settings */
+	switch (tegra_get_chip_sku()) {
+	case TEGRA_SOC_T20:
+		core = VDD_CORE_NOMINAL_T20;
+		cpu = VDD_CPU_NOMINAL_T20;
+		break;
+	case TEGRA_SOC_T25:
+		core = VDD_CORE_NOMINAL_T25;
+		cpu = VDD_CPU_NOMINAL_T25;
+		break;
+	default:
+		debug("%s: Unknown SKU id\n", __func__);
+		return -1;
+	}
+
+	ret = tegra_i2c_get_dvc_bus(&bus);
+	if (ret) {
+		debug("%s: Cannot find DVC I2C bus\n", __func__);
+		return ret;
+	}
+	ret = i2c_get_chip(bus, PMI_I2C_ADDRESS, 1, &dev);
+	if (ret) {
+		debug("%s: Cannot find DVC I2C chip\n", __func__);
+		return ret;
+	}
+
+	tps6586x_init(dev);
+	tps6586x_set_pwm_mode(TPS6586X_PWM_SM1);
+	return tps6586x_adjust_sm0_sm1(core, cpu, VDD_TRANSITION_STEP,
+				VDD_TRANSITION_RATE, VDD_RELATION);
+}
diff --git a/arch/arm/mach-tegra/tegra20/pwm.c b/arch/arm/mach-tegra/tegra20/pwm.c
new file mode 100644
index 0000000..5b88636
--- /dev/null
+++ b/arch/arm/mach-tegra/tegra20/pwm.c
@@ -0,0 +1,86 @@
+/*
+ * Tegra2 pulse width frequency modulator definitions
+ *
+ * Copyright (c) 2011 The Chromium OS Authors.
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <fdtdec.h>
+#include <asm/io.h>
+#include <asm/arch/clock.h>
+#include <asm/arch/pwm.h>
+
+struct pwm_info {
+	struct pwm_ctlr *pwm;		/* Registers for our pwm controller */
+	int pwm_node;			/* PWM device tree node */
+} local;
+
+void pwm_enable(unsigned channel, int rate, int pulse_width, int freq_divider)
+{
+	u32 reg;
+
+	assert(channel < PWM_NUM_CHANNELS);
+
+	/* TODO: Can we use clock_adjust_periph_pll_div() here? */
+	clock_start_periph_pll(PERIPH_ID_PWM, CLOCK_ID_SFROM32KHZ, rate);
+
+	reg = PWM_ENABLE_MASK;
+	reg |= pulse_width << PWM_WIDTH_SHIFT;
+	reg |= freq_divider << PWM_DIVIDER_SHIFT;
+	writel(reg, &local.pwm[channel].control);
+	debug("%s: channel=%d, rate=%d\n", __func__, channel, rate);
+}
+
+int pwm_request(const void *blob, int node, const char *prop_name)
+{
+	int pwm_node;
+	u32 data[3];
+
+	if (fdtdec_get_int_array(blob, node, prop_name, data,
+			ARRAY_SIZE(data))) {
+		debug("%s: Cannot decode PWM property '%s'\n", __func__,
+		      prop_name);
+		return -1;
+	}
+
+	pwm_node = fdt_node_offset_by_phandle(blob, data[0]);
+	if (pwm_node != local.pwm_node) {
+		debug("%s: PWM property '%s' phandle %d not recognised"
+		      "- expecting %d\n", __func__, prop_name, data[0],
+		      local.pwm_node);
+		return -1;
+	}
+	if (data[1] >= PWM_NUM_CHANNELS) {
+		debug("%s: PWM property '%s': invalid channel %u\n", __func__,
+		      prop_name, data[1]);
+		return -1;
+	}
+
+	/*
+	 * TODO: We could maintain a list of requests, but it might not be
+	 * worth it for U-Boot.
+	 */
+	return data[1];
+}
+
+int pwm_init(const void *blob)
+{
+	local.pwm_node = fdtdec_next_compatible(blob, 0,
+						COMPAT_NVIDIA_TEGRA20_PWM);
+	if (local.pwm_node < 0) {
+		debug("%s: Cannot find device tree node\n", __func__);
+		return -1;
+	}
+
+	local.pwm = (struct pwm_ctlr *)fdtdec_get_addr(blob, local.pwm_node,
+						       "reg");
+	if (local.pwm == (struct pwm_ctlr *)FDT_ADDR_T_NONE) {
+		debug("%s: Cannot find pwm reg address\n", __func__);
+		return -1;
+	}
+	debug("Tegra PWM at %p, node %d\n", local.pwm, local.pwm_node);
+
+	return 0;
+}
diff --git a/arch/arm/mach-tegra/tegra20/warmboot.c b/arch/arm/mach-tegra/tegra20/warmboot.c
new file mode 100644
index 0000000..5fdc4bb
--- /dev/null
+++ b/arch/arm/mach-tegra/tegra20/warmboot.c
@@ -0,0 +1,372 @@
+/*
+ * (C) Copyright 2010 - 2011
+ * NVIDIA Corporation <www.nvidia.com>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <asm/errno.h>
+#include <asm/arch/clock.h>
+#include <asm/arch/emc.h>
+#include <asm/arch/gp_padctrl.h>
+#include <asm/arch/pinmux.h>
+#include <asm/arch/sdram_param.h>
+#include <asm/arch/tegra.h>
+#include <asm/arch-tegra/ap.h>
+#include <asm/arch-tegra/apb_misc.h>
+#include <asm/arch-tegra/clk_rst.h>
+#include <asm/arch-tegra/pmc.h>
+#include <asm/arch-tegra/fuse.h>
+#include <asm/arch-tegra/warmboot.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#ifndef CONFIG_TEGRA_CLOCK_SCALING
+#error "You must enable CONFIG_TEGRA_CLOCK_SCALING to use CONFIG_TEGRA_LP0"
+#endif
+
+/*
+ * This is the place in SRAM where the SDRAM parameters are stored. There
+ * are 4 blocks, one for each RAM code
+ */
+#define SDRAM_PARAMS_BASE	(NV_PA_BASE_SRAM + 0x188)
+
+/* TODO: If we later add support for the Misc GP controller, refactor this */
+union xm2cfga_reg {
+	struct {
+		u32 reserved0:2;
+		u32 hsm_en:1;
+		u32 reserved1:2;
+		u32 preemp_en:1;
+		u32 vref_en:1;
+		u32 reserved2:5;
+		u32 cal_drvdn:5;
+		u32 reserved3:3;
+		u32 cal_drvup:5;
+		u32 reserved4:3;
+		u32 cal_drvdn_slwr:2;
+		u32 cal_drvup_slwf:2;
+	};
+	u32 word;
+};
+
+union xm2cfgd_reg {
+	struct {
+		u32 reserved0:2;
+		u32 hsm_en:1;
+		u32 schmt_en:1;
+		u32 lpmd:2;
+		u32 vref_en:1;
+		u32 reserved1:5;
+		u32 cal_drvdn:5;
+		u32 reserved2:3;
+		u32 cal_drvup:5;
+		u32 reserved3:3;
+		u32 cal_drvdn_slwr:2;
+		u32 cal_drvup_slwf:2;
+	};
+	u32 word;
+};
+
+/*
+ * TODO: This register is not documented in the TRM yet. We could move this
+ * into the EMC and give it a proper interface, but not while it is
+ * undocumented.
+ */
+union fbio_spare_reg {
+	struct {
+		u32 reserved:24;
+		u32 cfg_wb0:8;
+	};
+	u32 word;
+};
+
+/* We pack the resume information into these unions for later */
+union scratch2_reg {
+	struct {
+		u32 pllm_base_divm:5;
+		u32 pllm_base_divn:10;
+		u32 pllm_base_divp:3;
+		u32 pllm_misc_lfcon:4;
+		u32 pllm_misc_cpcon:4;
+		u32 gp_xm2cfga_padctrl_preemp:1;
+		u32 gp_xm2cfgd_padctrl_schmt:1;
+		u32 osc_ctrl_xobp:1;
+		u32 memory_type:3;
+	};
+	u32 word;
+};
+
+union scratch4_reg {
+	struct {
+		u32 emc_clock_divider:8;
+		u32 pllm_stable_time:8;
+		u32 pllx_stable_time:8;
+		u32 emc_fbio_spare_cfg_wb0:8;
+	};
+	u32 word;
+};
+
+union scratch24_reg {
+	struct {
+		u32 emc_auto_cal_wait:8;
+		u32 emc_pin_program_wait:8;
+		u32 warmboot_wait:8;
+		u32 reserved:8;
+	};
+	u32 word;
+};
+
+int warmboot_save_sdram_params(void)
+{
+	u32 ram_code;
+	struct sdram_params sdram;
+	struct apb_misc_pp_ctlr *apb_misc =
+				(struct apb_misc_pp_ctlr *)NV_PA_APB_MISC_BASE;
+	struct pmc_ctlr *pmc = (struct pmc_ctlr *)NV_PA_PMC_BASE;
+	struct apb_misc_gp_ctlr *gp =
+			(struct apb_misc_gp_ctlr *)NV_PA_APB_MISC_GP_BASE;
+	struct emc_ctlr *emc = emc_get_controller(gd->fdt_blob);
+	union scratch2_reg scratch2;
+	union scratch4_reg scratch4;
+	union scratch24_reg scratch24;
+	union xm2cfga_reg xm2cfga;
+	union xm2cfgd_reg xm2cfgd;
+	union fbio_spare_reg fbio_spare;
+
+	/* get ram code that is used as index to array sdram_params in BCT */
+	ram_code = (readl(&apb_misc->strapping_opt_a) >>
+			  STRAP_OPT_A_RAM_CODE_SHIFT) & 3;
+	memcpy(&sdram,
+	       (char *)((struct sdram_params *)SDRAM_PARAMS_BASE + ram_code),
+	       sizeof(sdram));
+
+	xm2cfga.word = readl(&gp->xm2cfga);
+	xm2cfgd.word = readl(&gp->xm2cfgd);
+
+	scratch2.word = 0;
+	scratch2.osc_ctrl_xobp = clock_get_osc_bypass();
+
+	/* Get the memory PLL settings */
+	{
+		u32 divm, divn, divp, cpcon, lfcon;
+
+		if (clock_ll_read_pll(CLOCK_ID_MEMORY, &divm, &divn, &divp,
+					&cpcon, &lfcon))
+			return -1;
+		scratch2.pllm_base_divm = divm;
+		scratch2.pllm_base_divn = divn;
+		scratch2.pllm_base_divp = divp;
+		scratch2.pllm_misc_cpcon = cpcon;
+		scratch2.pllm_misc_lfcon = lfcon;
+	}
+
+	scratch2.gp_xm2cfga_padctrl_preemp = xm2cfga.preemp_en;
+	scratch2.gp_xm2cfgd_padctrl_schmt = xm2cfgd.schmt_en;
+	scratch2.memory_type = sdram.memory_type;
+	writel(scratch2.word, &pmc->pmc_scratch2);
+
+	/* collect data from various sources for pmc_scratch4 */
+	fbio_spare.word = readl(&emc->fbio_spare);
+	scratch4.word = 0;
+	scratch4.emc_fbio_spare_cfg_wb0 = fbio_spare.cfg_wb0;
+	scratch4.emc_clock_divider = sdram.emc_clock_divider;
+	scratch4.pllm_stable_time = -1;
+	scratch4.pllx_stable_time = -1;
+	writel(scratch4.word, &pmc->pmc_scratch4);
+
+	/* collect various data from sdram for pmc_scratch24 */
+	scratch24.word = 0;
+	scratch24.emc_pin_program_wait = sdram.emc_pin_program_wait;
+	scratch24.emc_auto_cal_wait = sdram.emc_auto_cal_wait;
+	scratch24.warmboot_wait = sdram.warm_boot_wait;
+	writel(scratch24.word, &pmc->pmc_scratch24);
+
+	return 0;
+}
+
+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 ap20_is_odm_production_mode(void)
+{
+	struct fuse_regs *fuse = (struct fuse_regs *)NV_PA_FUSE_BASE;
+
+	if (!is_failure_analysis_mode(fuse) &&
+	    is_odm_production_mode_fuse_set(fuse))
+		return 1;
+	else
+		return 0;
+}
+
+static int ap20_is_production_mode(void)
+{
+	struct fuse_regs *fuse = (struct fuse_regs *)NV_PA_FUSE_BASE;
+
+	if (get_major_version() == 0)
+		return 1;
+
+	if (!is_failure_analysis_mode(fuse) &&
+	    is_production_mode_fuse_set(fuse) &&
+	    !is_odm_production_mode_fuse_set(fuse))
+		return 1;
+	else
+		return 0;
+}
+
+static enum fuse_operating_mode fuse_get_operation_mode(void)
+{
+	u32 chip_id;
+	struct apb_misc_gp_ctlr *gp =
+		(struct apb_misc_gp_ctlr *)NV_PA_APB_MISC_GP_BASE;
+
+	chip_id = (readl(&gp->hidrev) & HIDREV_CHIPID_MASK) >>
+			HIDREV_CHIPID_SHIFT;
+	if (chip_id == CHIPID_TEGRA20) {
+		if (ap20_is_odm_production_mode()) {
+			printf("!! odm_production_mode is not supported !!\n");
+			return MODE_UNDEFINED;
+		} else
+			if (ap20_is_production_mode())
+				return MODE_PRODUCTION;
+			else
+				return MODE_UNDEFINED;
+	}
+	return MODE_UNDEFINED;
+}
+
+static void determine_crypto_options(int *is_encrypted, int *is_signed,
+				     int *use_zero_key)
+{
+	switch (fuse_get_operation_mode()) {
+	case MODE_PRODUCTION:
+		*is_encrypted = 0;
+		*is_signed = 1;
+		*use_zero_key = 1;
+		break;
+	case MODE_UNDEFINED:
+	default:
+		*is_encrypted = 0;
+		*is_signed = 0;
+		*use_zero_key  = 0;
+		break;
+	}
+}
+
+static int sign_wb_code(u32 start, u32 length, int use_zero_key)
+{
+	int err;
+	u8 *source;		/* Pointer to source */
+	u8 *hash;
+
+	/* Calculate AES block parameters. */
+	source = (u8 *)(start + offsetof(struct wb_header, random_aes_block));
+	length -= offsetof(struct wb_header, random_aes_block);
+	hash = (u8 *)(start + offsetof(struct wb_header, hash));
+	err = sign_data_block(source, length, hash);
+
+	return err;
+}
+
+int warmboot_prepare_code(u32 seg_address, u32 seg_length)
+{
+	int err = 0;
+	u32 length;			/* length of the signed/encrypt code */
+	struct wb_header *dst_header;	/* Pointer to dest WB header */
+	int is_encrypted;		/* Segment is encrypted */
+	int is_signed;			/* Segment is signed */
+	int use_zero_key;		/* Use key of all zeros */
+
+	/* Determine crypto options. */
+	determine_crypto_options(&is_encrypted, &is_signed, &use_zero_key);
+
+	/* Get the actual code limits. */
+	length = roundup(((u32)wb_end - (u32)wb_start), 16);
+
+	/*
+	 * The region specified by seg_address must be in SDRAM and must be
+	 * nonzero in length.
+	 */
+	if (seg_length == 0 || seg_address < NV_PA_SDRAM_BASE ||
+		seg_address + seg_length >= NV_PA_SDRAM_BASE + gd->ram_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 {
+			*aes_block++ = 0;
+		} 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("Warning: warmboot code copy failed (error=%d)\n", err);
+
+	return err;
+}
diff --git a/arch/arm/mach-tegra/tegra20/warmboot_avp.c b/arch/arm/mach-tegra/tegra20/warmboot_avp.c
new file mode 100644
index 0000000..27ce5f4
--- /dev/null
+++ b/arch/arm/mach-tegra/tegra20/warmboot_avp.c
@@ -0,0 +1,236 @@
+/*
+ * (C) Copyright 2010 - 2011
+ * NVIDIA Corporation <www.nvidia.com>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <asm/arch/clock.h>
+#include <asm/arch/flow.h>
+#include <asm/arch/pinmux.h>
+#include <asm/arch/tegra.h>
+#include <asm/arch-tegra/ap.h>
+#include <asm/arch-tegra/apb_misc.h>
+#include <asm/arch-tegra/clk_rst.h>
+#include <asm/arch-tegra/pmc.h>
+#include <asm/arch-tegra/warmboot.h>
+#include "warmboot_avp.h"
+
+#define DEBUG_RESET_CORESIGHT
+
+void wb_start(void)
+{
+	struct apb_misc_pp_ctlr *apb_misc =
+				(struct apb_misc_pp_ctlr *)NV_PA_APB_MISC_BASE;
+	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;
+	union osc_ctrl_reg osc_ctrl;
+	union pllx_base_reg pllx_base;
+	union pllx_misc_reg pllx_misc;
+	union scratch3_reg scratch3;
+	u32 reg;
+
+	/* enable JTAG & TBE */
+	writel(CONFIG_CTL_TBE | CONFIG_CTL_JTAG, &apb_misc->cfg_ctl);
+
+	/* 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;
+
+#ifdef DEBUG_RESET_CORESIGHT
+	/* Assert CoreSight reset */
+	reg = readl(&clkrst->crc_rst_dev[TEGRA_DEV_U]);
+	reg |= SWR_CSITE_RST;
+	writel(reg, &clkrst->crc_rst_dev[TEGRA_DEV_U]);
+#endif
+
+	/* TODO: Set the drive strength - maybe make this a board parameter? */
+	osc_ctrl.word = readl(&clkrst->crc_osc_ctrl);
+	osc_ctrl.xofs = 4;
+	osc_ctrl.xoe = 1;
+	writel(osc_ctrl.word, &clkrst->crc_osc_ctrl);
+
+	/* Power up the CPU complex if necessary */
+	if (!(readl(&pmc->pmc_pwrgate_status) & PWRGATE_STATUS_CPU)) {
+		reg = PWRGATE_TOGGLE_PARTID_CPU | PWRGATE_TOGGLE_START;
+		writel(reg, &pmc->pmc_pwrgate_toggle);
+		while (!(readl(&pmc->pmc_pwrgate_status) & PWRGATE_STATUS_CPU))
+			;
+	}
+
+	/* Remove the I/O clamps from the CPU power partition. */
+	reg = readl(&pmc->pmc_remove_clamping);
+	reg |= CPU_CLMP;
+	writel(reg, &pmc->pmc_remove_clamping);
+
+	reg = EVENT_ZERO_VAL_20 | EVENT_MSEC | EVENT_MODE_STOP;
+	writel(reg, &flow->halt_cop_events);
+
+	/* Assert CPU complex reset */
+	reg = readl(&clkrst->crc_rst_dev[TEGRA_DEV_L]);
+	reg |= CPU_RST;
+	writel(reg, &clkrst->crc_rst_dev[TEGRA_DEV_L]);
+
+	/* Hold both CPUs in reset */
+	reg = CPU_CMPLX_CPURESET0 | CPU_CMPLX_CPURESET1 | CPU_CMPLX_DERESET0 |
+	      CPU_CMPLX_DERESET1 | CPU_CMPLX_DBGRESET0 | CPU_CMPLX_DBGRESET1;
+	writel(reg, &clkrst->crc_cpu_cmplx_set);
+
+	/* Halt CPU1 at the flow controller for uni-processor configurations */
+	writel(EVENT_MODE_STOP, &flow->halt_cpu1_events);
+
+	/*
+	 * Set the CPU reset vector. 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);
+
+	/* Start the CPU0 clock and stop the CPU1 clock */
+	reg = CPU_CMPLX_CPU_BRIDGE_CLKDIV_4 | CPU_CMPLX_CPU0_CLK_STP_RUN |
+	      CPU_CMPLX_CPU1_CLK_STP_STOP;
+	writel(reg, &clkrst->crc_clk_cpu_cmplx);
+
+	/* Enable the CPU complex clock */
+	reg = readl(&clkrst->crc_clk_out_enb[TEGRA_DEV_L]);
+	reg |= CLK_ENB_CPU;
+	writel(reg, &clkrst->crc_clk_out_enb[TEGRA_DEV_L]);
+
+	/* Make sure the resets were held for at least 2 microseconds */
+	reg = readl(TIMER_USEC_CNTR);
+	while (readl(TIMER_USEC_CNTR) <= (reg + 2))
+		;
+
+#ifdef DEBUG_RESET_CORESIGHT
+	/*
+	 * 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 = readl(&clkrst->crc_rst_dev[TEGRA_DEV_U]);
+	reg &= ~SWR_CSITE_RST;
+	writel(reg, &clkrst->crc_rst_dev[TEGRA_DEV_U]);
+#endif
+
+	/* Unlock the CPU CoreSight interfaces */
+	reg = 0xC5ACCE55;
+	writel(reg, CSITE_CPU_DBG0_LAR);
+	writel(reg, CSITE_CPU_DBG1_LAR);
+
+	/*
+	 * Sample the microsecond timestamp again. This is the time we must
+	 * use when returning from LP0 for PLL stabilization delays.
+	 */
+	reg = readl(TIMER_USEC_CNTR);
+	writel(reg, &pmc->pmc_scratch1);
+
+	pllx_base.word = 0;
+	pllx_misc.word = 0;
+	scratch3.word = readl(&pmc->pmc_scratch3);
+
+	/* Get the OSC. For 19.2 MHz, use 19 to make the calculations easier */
+	reg = (readl(TIMER_USEC_CFG) & USEC_CFG_DIVISOR_MASK) + 1;
+
+	/*
+	 * According to the TRM, for 19.2MHz OSC, the USEC_DIVISOR is 0x5f, and
+	 * USEC_DIVIDEND is 0x04. So, if USEC_DIVISOR > 26, OSC is 19.2 MHz.
+	 *
+	 * reg is used to calculate the pllx freq, which is used to determine if
+	 * to set dccon or not.
+	 */
+	if (reg > 26)
+		reg = 19;
+
+	/* PLLX_BASE.PLLX_DIVM */
+	if (scratch3.pllx_base_divm == reg)
+		reg = 0;
+	else
+		reg = 1;
+
+	/* PLLX_BASE.PLLX_DIVN */
+	pllx_base.divn = scratch3.pllx_base_divn;
+	reg = scratch3.pllx_base_divn << reg;
+
+	/* PLLX_BASE.PLLX_DIVP */
+	pllx_base.divp = scratch3.pllx_base_divp;
+	reg = reg >> scratch3.pllx_base_divp;
+
+	pllx_base.bypass = 1;
+
+	/* PLLX_MISC_DCCON must be set for pllx frequency > 600 MHz. */
+	if (reg > 600)
+		pllx_misc.dccon = 1;
+
+	/* PLLX_MISC_LFCON */
+	pllx_misc.lfcon = scratch3.pllx_misc_lfcon;
+
+	/* PLLX_MISC_CPCON */
+	pllx_misc.cpcon = scratch3.pllx_misc_cpcon;
+
+	writel(pllx_misc.word, &clkrst->crc_pll_simple[SIMPLE_PLLX].pll_misc);
+	writel(pllx_base.word, &clkrst->crc_pll_simple[SIMPLE_PLLX].pll_base);
+
+	pllx_base.enable = 1;
+	writel(pllx_base.word, &clkrst->crc_pll_simple[SIMPLE_PLLX].pll_base);
+	pllx_base.bypass = 0;
+	writel(pllx_base.word, &clkrst->crc_pll_simple[SIMPLE_PLLX].pll_base);
+
+	writel(0, flow->halt_cpu_events);
+
+	reg = CPU_CMPLX_CPURESET0 | CPU_CMPLX_DBGRESET0 | CPU_CMPLX_DERESET0;
+	writel(reg, &clkrst->crc_cpu_cmplx_clr);
+
+	reg = PLLM_OUT1_RSTN_RESET_DISABLE | PLLM_OUT1_CLKEN_ENABLE |
+	      PLLM_OUT1_RATIO_VAL_8;
+	writel(reg, &clkrst->crc_pll[CLOCK_ID_MEMORY].pll_out[0]);
+
+	reg = SCLK_SWAKE_FIQ_SRC_PLLM_OUT1 | SCLK_SWAKE_IRQ_SRC_PLLM_OUT1 |
+	      SCLK_SWAKE_RUN_SRC_PLLM_OUT1 | SCLK_SWAKE_IDLE_SRC_PLLM_OUT1 |
+	      SCLK_SYS_STATE_IDLE;
+	writel(reg, &clkrst->crc_sclk_brst_pol);
+
+	/* avp_resume: no return after the write */
+	reg = readl(&clkrst->crc_rst_dev[TEGRA_DEV_L]);
+	reg &= ~CPU_RST;
+	writel(reg, &clkrst->crc_rst_dev[TEGRA_DEV_L]);
+
+	/* avp_halt: */
+avp_halt:
+	reg = EVENT_MODE_STOP | EVENT_JTAG;
+	writel(reg, flow->halt_cop_events);
+	goto avp_halt;
+
+do_reset:
+	/*
+	 * Execution comes here if something goes wrong. The chip is reset and
+	 * a cold boot is performed.
+	 */
+	writel(SWR_TRIG_SYS_RST, &clkrst->crc_rst_dev[TEGRA_DEV_L]);
+	goto do_reset;
+}
+
+/*
+ * 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/mach-tegra/tegra20/warmboot_avp.h b/arch/arm/mach-tegra/tegra20/warmboot_avp.h
new file mode 100644
index 0000000..7b86acb
--- /dev/null
+++ b/arch/arm/mach-tegra/tegra20/warmboot_avp.h
@@ -0,0 +1,65 @@
+/*
+ * (C) Copyright 2010, 2011
+ * NVIDIA Corporation <www.nvidia.com>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#ifndef _WARMBOOT_AVP_H_
+#define _WARMBOOT_AVP_H_
+
+#define TEGRA_DEV_L			0
+#define TEGRA_DEV_H			1
+#define TEGRA_DEV_U			2
+
+#define SIMPLE_PLLX			(CLOCK_ID_XCPU - CLOCK_ID_FIRST_SIMPLE)
+#define SIMPLE_PLLE			(CLOCK_ID_EPCI - CLOCK_ID_FIRST_SIMPLE)
+
+#define TIMER_USEC_CNTR			(NV_PA_TMRUS_BASE + 0)
+#define TIMER_USEC_CFG			(NV_PA_TMRUS_BASE + 4)
+
+#define USEC_CFG_DIVISOR_MASK		0xffff
+
+#define CONFIG_CTL_TBE			(1 << 7)
+#define CONFIG_CTL_JTAG			(1 << 6)
+
+#define CPU_RST				(1 << 0)
+#define CLK_ENB_CPU			(1 << 0)
+#define SWR_TRIG_SYS_RST		(1 << 2)
+#define SWR_CSITE_RST			(1 << 9)
+
+#define PWRGATE_STATUS_CPU		(1 << 0)
+#define PWRGATE_TOGGLE_PARTID_CPU	(0 << 0)
+#define PWRGATE_TOGGLE_START		(1 << 8)
+
+#define CPU_CMPLX_CPU_BRIDGE_CLKDIV_4	(3 << 0)
+#define CPU_CMPLX_CPU0_CLK_STP_STOP	(1 << 8)
+#define CPU_CMPLX_CPU0_CLK_STP_RUN	(0 << 8)
+#define CPU_CMPLX_CPU1_CLK_STP_STOP	(1 << 9)
+#define CPU_CMPLX_CPU1_CLK_STP_RUN	(0 << 9)
+
+#define CPU_CMPLX_CPURESET0		(1 << 0)
+#define CPU_CMPLX_CPURESET1		(1 << 1)
+#define CPU_CMPLX_DERESET0		(1 << 4)
+#define CPU_CMPLX_DERESET1		(1 << 5)
+#define CPU_CMPLX_DBGRESET0		(1 << 12)
+#define CPU_CMPLX_DBGRESET1		(1 << 13)
+
+#define PLLM_OUT1_RSTN_RESET_DISABLE	(1 << 0)
+#define PLLM_OUT1_CLKEN_ENABLE		(1 << 1)
+#define PLLM_OUT1_RATIO_VAL_8		(8 << 8)
+
+#define SCLK_SYS_STATE_IDLE		(1 << 28)
+#define SCLK_SWAKE_FIQ_SRC_PLLM_OUT1	(7 << 12)
+#define SCLK_SWAKE_IRQ_SRC_PLLM_OUT1	(7 << 8)
+#define SCLK_SWAKE_RUN_SRC_PLLM_OUT1	(7 << 4)
+#define SCLK_SWAKE_IDLE_SRC_PLLM_OUT1	(7 << 0)
+
+#define EVENT_ZERO_VAL_20		(20 << 0)
+#define EVENT_MSEC			(1 << 24)
+#define EVENT_JTAG			(1 << 28)
+#define EVENT_MODE_STOP			(2 << 29)
+
+#define CCLK_PLLP_BURST_POLICY		0x20004444
+
+#endif
diff --git a/arch/arm/mach-tegra/tegra30/Kconfig b/arch/arm/mach-tegra/tegra30/Kconfig
new file mode 100644
index 0000000..3abdc7b
--- /dev/null
+++ b/arch/arm/mach-tegra/tegra30/Kconfig
@@ -0,0 +1,32 @@
+if TEGRA30
+
+choice
+	prompt "Tegra30 board select"
+
+config TARGET_APALIS_T30
+	bool "Toradex Apalis T30 board"
+
+config TARGET_BEAVER
+	bool "NVIDIA Tegra30 Beaver evaluation board"
+
+config TARGET_CARDHU
+	bool "NVIDIA Tegra30 Cardhu evaluation board"
+
+config TARGET_COLIBRI_T30
+	bool "Toradex Colibri T30 board"
+
+config TARGET_TEC_NG
+	bool "Avionic Design TEC-NG board"
+
+endchoice
+
+config SYS_SOC
+	default "tegra30"
+
+source "board/toradex/apalis_t30/Kconfig"
+source "board/nvidia/beaver/Kconfig"
+source "board/nvidia/cardhu/Kconfig"
+source "board/toradex/colibri_t30/Kconfig"
+source "board/avionic-design/tec-ng/Kconfig"
+
+endif
diff --git a/arch/arm/mach-tegra/tegra30/Makefile b/arch/arm/mach-tegra/tegra30/Makefile
new file mode 100644
index 0000000..bc250de
--- /dev/null
+++ b/arch/arm/mach-tegra/tegra30/Makefile
@@ -0,0 +1,19 @@
+#
+# Copyright (c) 2010-2012, NVIDIA CORPORATION.  All rights reserved.
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms and conditions of the GNU General Public License,
+# version 2, as published by the Free Software Foundation.
+#
+# This program is distributed in the hope it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+# more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+
+obj-$(CONFIG_SPL_BUILD) += cpu.o
+
+obj-y	+= clock.o funcmux.o pinmux.o
diff --git a/arch/arm/mach-tegra/tegra30/clock.c b/arch/arm/mach-tegra/tegra30/clock.c
new file mode 100644
index 0000000..0eb0f0a
--- /dev/null
+++ b/arch/arm/mach-tegra/tegra30/clock.c
@@ -0,0 +1,744 @@
+/*
+ * Copyright (c) 2010-2014, NVIDIA CORPORATION.  All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* Tegra30 Clock control functions */
+
+#include <common.h>
+#include <errno.h>
+#include <asm/io.h>
+#include <asm/arch/clock.h>
+#include <asm/arch/tegra.h>
+#include <asm/arch-tegra/clk_rst.h>
+#include <asm/arch-tegra/timer.h>
+#include <div64.h>
+#include <fdtdec.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
+ * source. This gives us a clock 'type' and exploits what commonality exists
+ * in the device.
+ *
+ * Letters are obvious, except for T which means CLK_M, and S which means the
+ * clock derived from 32KHz. Beware that CLK_M (also called OSC in the
+ * datasheet) and PLL_M are different things. The former is the basic
+ * clock supplied to the SOC from an external oscillator. The latter is the
+ * memory clock PLL.
+ *
+ * See definitions in clock_id in the header file.
+ */
+enum clock_type_id {
+	CLOCK_TYPE_AXPT,	/* PLL_A, PLL_X, PLL_P, CLK_M */
+	CLOCK_TYPE_MCPA,	/* and so on */
+	CLOCK_TYPE_MCPT,
+	CLOCK_TYPE_PCM,
+	CLOCK_TYPE_PCMT,
+	CLOCK_TYPE_PCMT16,
+	CLOCK_TYPE_PDCT,
+	CLOCK_TYPE_ACPT,
+	CLOCK_TYPE_ASPTE,
+	CLOCK_TYPE_PMDACD2T,
+	CLOCK_TYPE_PCST,
+
+	CLOCK_TYPE_COUNT,
+	CLOCK_TYPE_NONE = -1,   /* invalid clock type */
+};
+
+enum {
+	CLOCK_MAX_MUX   = 8     /* number of source options for each clock */
+};
+
+/*
+ * Clock source mux for each clock type. This just converts our enum into
+ * a list of mux sources for use by the code.
+ *
+ * Note:
+ *  The extra column in each clock source array is used to store the mask
+ *  bits in its register for the source.
+ */
+#define CLK(x) CLOCK_ID_ ## x
+static enum clock_id clock_source[CLOCK_TYPE_COUNT][CLOCK_MAX_MUX+1] = {
+	{ CLK(AUDIO),   CLK(XCPU),      CLK(PERIPH),    CLK(OSC),
+		CLK(NONE),      CLK(NONE),      CLK(NONE),      CLK(NONE),
+		MASK_BITS_31_30},
+	{ CLK(MEMORY),  CLK(CGENERAL),  CLK(PERIPH),    CLK(AUDIO),
+		CLK(NONE),      CLK(NONE),      CLK(NONE),      CLK(NONE),
+		MASK_BITS_31_30},
+	{ CLK(MEMORY),  CLK(CGENERAL),  CLK(PERIPH),    CLK(OSC),
+		CLK(NONE),      CLK(NONE),      CLK(NONE),      CLK(NONE),
+		MASK_BITS_31_30},
+	{ CLK(PERIPH),  CLK(CGENERAL),  CLK(MEMORY),    CLK(NONE),
+		CLK(NONE),      CLK(NONE),      CLK(NONE),      CLK(NONE),
+		MASK_BITS_31_30},
+	{ CLK(PERIPH),  CLK(CGENERAL),  CLK(MEMORY),    CLK(OSC),
+		CLK(NONE),      CLK(NONE),      CLK(NONE),      CLK(NONE),
+		MASK_BITS_31_30},
+	{ CLK(PERIPH),  CLK(CGENERAL),  CLK(MEMORY),    CLK(OSC),
+		CLK(NONE),      CLK(NONE),      CLK(NONE),      CLK(NONE),
+		MASK_BITS_31_30},
+	{ CLK(PERIPH),  CLK(DISPLAY),   CLK(CGENERAL),  CLK(OSC),
+		CLK(NONE),      CLK(NONE),      CLK(NONE),      CLK(NONE),
+		MASK_BITS_31_30},
+	{ CLK(AUDIO),   CLK(CGENERAL),  CLK(PERIPH),    CLK(OSC),
+		CLK(NONE),      CLK(NONE),      CLK(NONE),      CLK(NONE),
+		MASK_BITS_31_30},
+	{ CLK(AUDIO),   CLK(SFROM32KHZ),	CLK(PERIPH),   CLK(OSC),
+		CLK(EPCI),      CLK(NONE),      CLK(NONE),      CLK(NONE),
+		MASK_BITS_31_29},
+	{ CLK(PERIPH),  CLK(MEMORY),    CLK(DISPLAY),   CLK(AUDIO),
+		CLK(CGENERAL),  CLK(DISPLAY2),  CLK(OSC),       CLK(NONE),
+		MASK_BITS_31_29},
+	{ CLK(PERIPH),  CLK(CGENERAL),  CLK(SFROM32KHZ), CLK(OSC),
+		CLK(NONE),      CLK(NONE),      CLK(NONE),      CLK(NONE),
+		MASK_BITS_31_28}
+};
+
+/*
+ * Clock type for each peripheral clock source. We put the name in each
+ * record just so it is easy to match things up
+ */
+#define TYPE(name, type) type
+static enum clock_type_id clock_periph_type[PERIPHC_COUNT] = {
+	/* 0x00 */
+	TYPE(PERIPHC_I2S1,	CLOCK_TYPE_AXPT),
+	TYPE(PERIPHC_I2S2,      CLOCK_TYPE_AXPT),
+	TYPE(PERIPHC_SPDIF_OUT, CLOCK_TYPE_AXPT),
+	TYPE(PERIPHC_SPDIF_IN,  CLOCK_TYPE_PCM),
+	TYPE(PERIPHC_PWM,       CLOCK_TYPE_PCST),  /* only PWM uses b29:28 */
+	TYPE(PERIPHC_NONE,      CLOCK_TYPE_NONE),
+	TYPE(PERIPHC_SBC2,      CLOCK_TYPE_PCMT),
+	TYPE(PERIPHC_SBC3,      CLOCK_TYPE_PCMT),
+
+	/* 0x08 */
+	TYPE(PERIPHC_NONE,      CLOCK_TYPE_NONE),
+	TYPE(PERIPHC_I2C1,      CLOCK_TYPE_PCMT16),
+	TYPE(PERIPHC_DVC_I2C,   CLOCK_TYPE_PCMT16),
+	TYPE(PERIPHC_NONE,      CLOCK_TYPE_NONE),
+	TYPE(PERIPHC_NONE,      CLOCK_TYPE_NONE),
+	TYPE(PERIPHC_SBC1,      CLOCK_TYPE_PCMT),
+	TYPE(PERIPHC_DISP1,     CLOCK_TYPE_PMDACD2T),
+	TYPE(PERIPHC_DISP2,     CLOCK_TYPE_PMDACD2T),
+
+	/* 0x10 */
+	TYPE(PERIPHC_CVE,       CLOCK_TYPE_PDCT),
+	TYPE(PERIPHC_NONE,      CLOCK_TYPE_NONE),
+	TYPE(PERIPHC_VI,	CLOCK_TYPE_MCPA),
+	TYPE(PERIPHC_NONE,      CLOCK_TYPE_NONE),
+	TYPE(PERIPHC_SDMMC1,    CLOCK_TYPE_PCMT),
+	TYPE(PERIPHC_SDMMC2,	CLOCK_TYPE_PCMT),
+	TYPE(PERIPHC_G3D,	CLOCK_TYPE_MCPA),
+	TYPE(PERIPHC_G2D,	CLOCK_TYPE_MCPA),
+
+	/* 0x18 */
+	TYPE(PERIPHC_NDFLASH,	CLOCK_TYPE_PCMT),
+	TYPE(PERIPHC_SDMMC4,	CLOCK_TYPE_PCMT),
+	TYPE(PERIPHC_VFIR,      CLOCK_TYPE_PCMT),
+	TYPE(PERIPHC_EPP,       CLOCK_TYPE_MCPA),
+	TYPE(PERIPHC_MPE,       CLOCK_TYPE_MCPA),
+	TYPE(PERIPHC_MIPI,      CLOCK_TYPE_PCMT),       /* MIPI base-band HSI */
+	TYPE(PERIPHC_UART1,     CLOCK_TYPE_PCMT),
+	TYPE(PERIPHC_UART2,     CLOCK_TYPE_PCMT),
+
+	/* 0x20 */
+	TYPE(PERIPHC_HOST1X,    CLOCK_TYPE_MCPA),
+	TYPE(PERIPHC_NONE,      CLOCK_TYPE_NONE),
+	TYPE(PERIPHC_TVO,       CLOCK_TYPE_PDCT),
+	TYPE(PERIPHC_HDMI,      CLOCK_TYPE_PMDACD2T),
+	TYPE(PERIPHC_NONE,      CLOCK_TYPE_NONE),
+	TYPE(PERIPHC_TVDAC,     CLOCK_TYPE_PDCT),
+	TYPE(PERIPHC_I2C2,      CLOCK_TYPE_PCMT16),
+	TYPE(PERIPHC_EMC,	CLOCK_TYPE_MCPT),
+
+	/* 0x28 */
+	TYPE(PERIPHC_UART3,	CLOCK_TYPE_PCMT),
+	TYPE(PERIPHC_NONE,	CLOCK_TYPE_NONE),
+	TYPE(PERIPHC_VI,	CLOCK_TYPE_MCPA),
+	TYPE(PERIPHC_NONE,      CLOCK_TYPE_NONE),
+	TYPE(PERIPHC_NONE,      CLOCK_TYPE_NONE),
+	TYPE(PERIPHC_SBC4,      CLOCK_TYPE_PCMT),
+	TYPE(PERIPHC_I2C3,      CLOCK_TYPE_PCMT16),
+	TYPE(PERIPHC_SDMMC3,    CLOCK_TYPE_PCMT),
+
+	/* 0x30 */
+	TYPE(PERIPHC_UART4,	CLOCK_TYPE_PCMT),
+	TYPE(PERIPHC_UART5,	CLOCK_TYPE_PCMT),
+	TYPE(PERIPHC_VDE,	CLOCK_TYPE_PCMT),
+	TYPE(PERIPHC_OWR,       CLOCK_TYPE_PCMT),
+	TYPE(PERIPHC_NOR,       CLOCK_TYPE_PCMT),
+	TYPE(PERIPHC_CSITE,     CLOCK_TYPE_PCMT),
+	TYPE(PERIPHC_I2S0,      CLOCK_TYPE_AXPT),
+	TYPE(PERIPHC_NONE,      CLOCK_TYPE_NONE),
+
+	/* 0x38h */	     /* Jumps to reg offset 0x3B0h - new for T30 */
+	TYPE(PERIPHC_G3D2,      CLOCK_TYPE_MCPA),
+	TYPE(PERIPHC_MSELECT,   CLOCK_TYPE_PCMT),
+	TYPE(PERIPHC_TSENSOR,   CLOCK_TYPE_PCST),       /* s/b PCTS */
+	TYPE(PERIPHC_I2S3,      CLOCK_TYPE_AXPT),
+	TYPE(PERIPHC_I2S4,      CLOCK_TYPE_AXPT),
+	TYPE(PERIPHC_I2C4,      CLOCK_TYPE_PCMT16),
+	TYPE(PERIPHC_SBC5,      CLOCK_TYPE_PCMT),
+	TYPE(PERIPHC_SBC6,      CLOCK_TYPE_PCMT),
+
+	/* 0x40 */
+	TYPE(PERIPHC_AUDIO,     CLOCK_TYPE_ACPT),
+	TYPE(PERIPHC_NONE,      CLOCK_TYPE_NONE),
+	TYPE(PERIPHC_DAM0,      CLOCK_TYPE_ACPT),
+	TYPE(PERIPHC_DAM1,      CLOCK_TYPE_ACPT),
+	TYPE(PERIPHC_DAM2,      CLOCK_TYPE_ACPT),
+	TYPE(PERIPHC_HDA2CODEC2X, CLOCK_TYPE_PCMT),
+	TYPE(PERIPHC_ACTMON,    CLOCK_TYPE_PCST),       /* MASK 31:30 */
+	TYPE(PERIPHC_EXTPERIPH1, CLOCK_TYPE_ASPTE),
+
+	/* 0x48 */
+	TYPE(PERIPHC_EXTPERIPH2, CLOCK_TYPE_ASPTE),
+	TYPE(PERIPHC_EXTPERIPH3, CLOCK_TYPE_ASPTE),
+	TYPE(PERIPHC_NANDSPEED, CLOCK_TYPE_PCMT),
+	TYPE(PERIPHC_I2CSLOW,   CLOCK_TYPE_PCST),       /* MASK 31:30 */
+	TYPE(PERIPHC_SYS,       CLOCK_TYPE_NONE),
+	TYPE(PERIPHC_SPEEDO,    CLOCK_TYPE_PCMT),
+	TYPE(PERIPHC_NONE,      CLOCK_TYPE_NONE),
+	TYPE(PERIPHC_NONE,      CLOCK_TYPE_NONE),
+
+	/* 0x50 */
+	TYPE(PERIPHC_NONE,      CLOCK_TYPE_NONE),
+	TYPE(PERIPHC_NONE,      CLOCK_TYPE_NONE),
+	TYPE(PERIPHC_NONE,      CLOCK_TYPE_NONE),
+	TYPE(PERIPHC_NONE,      CLOCK_TYPE_NONE),
+	TYPE(PERIPHC_SATAOOB,   CLOCK_TYPE_PCMT),       /* offset 0x420h */
+	TYPE(PERIPHC_SATA,      CLOCK_TYPE_PCMT),
+	TYPE(PERIPHC_HDA,       CLOCK_TYPE_PCMT),
+};
+
+/*
+ * This array translates a periph_id to a periphc_internal_id
+ *
+ * Not present/matched up:
+ *	uint vi_sensor;	 _VI_SENSOR_0,		0x1A8
+ *	SPDIF - which is both 0x08 and 0x0c
+ *
+ */
+#define NONE(name) (-1)
+#define OFFSET(name, value) PERIPHC_ ## name
+static s8 periph_id_to_internal_id[PERIPH_ID_COUNT] = {
+	/* Low word: 31:0 */
+	NONE(CPU),
+	NONE(COP),
+	NONE(TRIGSYS),
+	NONE(RESERVED3),
+	NONE(RESERVED4),
+	NONE(TMR),
+	PERIPHC_UART1,
+	PERIPHC_UART2,  /* and vfir 0x68 */
+
+	/* 8 */
+	NONE(GPIO),
+	PERIPHC_SDMMC2,
+	NONE(SPDIF),	    /* 0x08 and 0x0c, unclear which to use */
+	PERIPHC_I2S1,
+	PERIPHC_I2C1,
+	PERIPHC_NDFLASH,
+	PERIPHC_SDMMC1,
+	PERIPHC_SDMMC4,
+
+	/* 16 */
+	NONE(RESERVED16),
+	PERIPHC_PWM,
+	PERIPHC_I2S2,
+	PERIPHC_EPP,
+	PERIPHC_VI,
+	PERIPHC_G2D,
+	NONE(USBD),
+	NONE(ISP),
+
+	/* 24 */
+	PERIPHC_G3D,
+	NONE(RESERVED25),
+	PERIPHC_DISP2,
+	PERIPHC_DISP1,
+	PERIPHC_HOST1X,
+	NONE(VCP),
+	PERIPHC_I2S0,
+	NONE(CACHE2),
+
+	/* Middle word: 63:32 */
+	NONE(MEM),
+	NONE(AHBDMA),
+	NONE(APBDMA),
+	NONE(RESERVED35),
+	NONE(RESERVED36),
+	NONE(STAT_MON),
+	NONE(RESERVED38),
+	NONE(RESERVED39),
+
+	/* 40 */
+	NONE(KFUSE),
+	PERIPHC_SBC1,
+	PERIPHC_NOR,
+	NONE(RESERVED43),
+	PERIPHC_SBC2,
+	NONE(RESERVED45),
+	PERIPHC_SBC3,
+	PERIPHC_DVC_I2C,
+
+	/* 48 */
+	NONE(DSI),
+	PERIPHC_TVO,    /* also CVE 0x40 */
+	PERIPHC_MIPI,
+	PERIPHC_HDMI,
+	NONE(CSI),
+	PERIPHC_TVDAC,
+	PERIPHC_I2C2,
+	PERIPHC_UART3,
+
+	/* 56 */
+	NONE(RESERVED56),
+	PERIPHC_EMC,
+	NONE(USB2),
+	NONE(USB3),
+	PERIPHC_MPE,
+	PERIPHC_VDE,
+	NONE(BSEA),
+	NONE(BSEV),
+
+	/* Upper word 95:64 */
+	PERIPHC_SPEEDO,
+	PERIPHC_UART4,
+	PERIPHC_UART5,
+	PERIPHC_I2C3,
+	PERIPHC_SBC4,
+	PERIPHC_SDMMC3,
+	NONE(PCIE),
+	PERIPHC_OWR,
+
+	/* 72 */
+	NONE(AFI),
+	PERIPHC_CSITE,
+	NONE(PCIEXCLK),
+	NONE(AVPUCQ),
+	NONE(RESERVED76),
+	NONE(RESERVED77),
+	NONE(RESERVED78),
+	NONE(DTV),
+
+	/* 80 */
+	PERIPHC_NANDSPEED,
+	PERIPHC_I2CSLOW,
+	NONE(DSIB),
+	NONE(RESERVED83),
+	NONE(IRAMA),
+	NONE(IRAMB),
+	NONE(IRAMC),
+	NONE(IRAMD),
+
+	/* 88 */
+	NONE(CRAM2),
+	NONE(RESERVED89),
+	NONE(MDOUBLER),
+	NONE(RESERVED91),
+	NONE(SUSOUT),
+	NONE(RESERVED93),
+	NONE(RESERVED94),
+	NONE(RESERVED95),
+
+	/* V word: 31:0 */
+	NONE(CPUG),
+	NONE(CPULP),
+	PERIPHC_G3D2,
+	PERIPHC_MSELECT,
+	PERIPHC_TSENSOR,
+	PERIPHC_I2S3,
+	PERIPHC_I2S4,
+	PERIPHC_I2C4,
+
+	/* 08 */
+	PERIPHC_SBC5,
+	PERIPHC_SBC6,
+	PERIPHC_AUDIO,
+	NONE(APBIF),
+	PERIPHC_DAM0,
+	PERIPHC_DAM1,
+	PERIPHC_DAM2,
+	PERIPHC_HDA2CODEC2X,
+
+	/* 16 */
+	NONE(ATOMICS),
+	NONE(RESERVED17),
+	NONE(RESERVED18),
+	NONE(RESERVED19),
+	NONE(RESERVED20),
+	NONE(RESERVED21),
+	NONE(RESERVED22),
+	PERIPHC_ACTMON,
+
+	/* 24 */
+	NONE(RESERVED24),
+	NONE(RESERVED25),
+	NONE(RESERVED26),
+	NONE(RESERVED27),
+	PERIPHC_SATA,
+	PERIPHC_HDA,
+	NONE(RESERVED30),
+	NONE(RESERVED31),
+
+	/* W word: 31:0 */
+	NONE(HDA2HDMICODEC),
+	NONE(SATACOLD),
+	NONE(RESERVED0_PCIERX0),
+	NONE(RESERVED1_PCIERX1),
+	NONE(RESERVED2_PCIERX2),
+	NONE(RESERVED3_PCIERX3),
+	NONE(RESERVED4_PCIERX4),
+	NONE(RESERVED5_PCIERX5),
+
+	/* 40 */
+	NONE(CEC),
+	NONE(RESERVED6_PCIE2),
+	NONE(RESERVED7_EMC),
+	NONE(RESERVED8_HDMI),
+	NONE(RESERVED9_SATA),
+	NONE(RESERVED10_MIPI),
+	NONE(EX_RESERVED46),
+	NONE(EX_RESERVED47),
+};
+
+/*
+ * Get the oscillator frequency, from the corresponding hardware configuration
+ * field. Note that T30 supports 3 new higher freqs, but we map back
+ * to the old T20 freqs. Support for the higher oscillators is TBD.
+ */
+enum clock_osc_freq clock_get_osc_freq(void)
+{
+	struct clk_rst_ctlr *clkrst =
+			(struct clk_rst_ctlr *)NV_PA_CLK_RST_BASE;
+	u32 reg;
+
+	reg = readl(&clkrst->crc_osc_ctrl);
+	reg = (reg & OSC_FREQ_MASK) >> OSC_FREQ_SHIFT;
+
+	if (reg & 1)			/* one of the newer freqs */
+		printf("Warning: OSC_FREQ is unsupported! (%d)\n", reg);
+
+	return reg >> 2;	/* Map to most common (T20) freqs */
+}
+
+/* Returns a pointer to the clock source register for a peripheral */
+u32 *get_periph_source_reg(enum periph_id periph_id)
+{
+	struct clk_rst_ctlr *clkrst =
+		(struct clk_rst_ctlr *)NV_PA_CLK_RST_BASE;
+	enum periphc_internal_id internal_id;
+
+	/* Coresight is a special case */
+	if (periph_id == PERIPH_ID_CSI)
+		return &clkrst->crc_clk_src[PERIPH_ID_CSI+1];
+
+	assert(periph_id >= PERIPH_ID_FIRST && periph_id < PERIPH_ID_COUNT);
+	internal_id = periph_id_to_internal_id[periph_id];
+	assert(internal_id != -1);
+	if (internal_id >= PERIPHC_VW_FIRST) {
+		internal_id -= PERIPHC_VW_FIRST;
+		return &clkrst->crc_clk_src_vw[internal_id];
+	} else
+		return &clkrst->crc_clk_src[internal_id];
+}
+
+/**
+ * Given a peripheral ID and the required source clock, this returns which
+ * value should be programmed into the source mux for that peripheral.
+ *
+ * There is special code here to handle the one source type with 5 sources.
+ *
+ * @param periph_id	peripheral to start
+ * @param source	PLL id of required parent clock
+ * @param mux_bits	Set to number of bits in mux register: 2 or 4
+ * @param divider_bits  Set to number of divider bits (8 or 16)
+ * @return mux value (0-4, or -1 if not found)
+ */
+int get_periph_clock_source(enum periph_id periph_id,
+	enum clock_id parent, int *mux_bits, int *divider_bits)
+{
+	enum clock_type_id type;
+	enum periphc_internal_id internal_id;
+	int mux;
+
+	assert(clock_periph_id_isvalid(periph_id));
+
+	internal_id = periph_id_to_internal_id[periph_id];
+	assert(periphc_internal_id_isvalid(internal_id));
+
+	type = clock_periph_type[internal_id];
+	assert(clock_type_id_isvalid(type));
+
+	*mux_bits = clock_source[type][CLOCK_MAX_MUX];
+
+	if (type == CLOCK_TYPE_PCMT16)
+		*divider_bits = 16;
+	else
+		*divider_bits = 8;
+
+	for (mux = 0; mux < CLOCK_MAX_MUX; mux++)
+		if (clock_source[type][mux] == parent)
+			return mux;
+
+	/* if we get here, either us or the caller has made a mistake */
+	printf("Caller requested bad clock: periph=%d, parent=%d\n", periph_id,
+		parent);
+	return -1;
+}
+
+void clock_set_enable(enum periph_id periph_id, int enable)
+{
+	struct clk_rst_ctlr *clkrst =
+			(struct clk_rst_ctlr *)NV_PA_CLK_RST_BASE;
+	u32 *clk;
+	u32 reg;
+
+	/* Enable/disable the clock to this peripheral */
+	assert(clock_periph_id_isvalid(periph_id));
+	if ((int)periph_id < (int)PERIPH_ID_VW_FIRST)
+		clk = &clkrst->crc_clk_out_enb[PERIPH_REG(periph_id)];
+	else
+		clk = &clkrst->crc_clk_out_enb_vw[PERIPH_REG(periph_id)];
+	reg = readl(clk);
+	if (enable)
+		reg |= PERIPH_MASK(periph_id);
+	else
+		reg &= ~PERIPH_MASK(periph_id);
+	writel(reg, clk);
+}
+
+void reset_set_enable(enum periph_id periph_id, int enable)
+{
+	struct clk_rst_ctlr *clkrst =
+			(struct clk_rst_ctlr *)NV_PA_CLK_RST_BASE;
+	u32 *reset;
+	u32 reg;
+
+	/* Enable/disable reset to the peripheral */
+	assert(clock_periph_id_isvalid(periph_id));
+	if (periph_id < PERIPH_ID_VW_FIRST)
+		reset = &clkrst->crc_rst_dev[PERIPH_REG(periph_id)];
+	else
+		reset = &clkrst->crc_rst_dev_vw[PERIPH_REG(periph_id)];
+	reg = readl(reset);
+	if (enable)
+		reg |= PERIPH_MASK(periph_id);
+	else
+		reg &= ~PERIPH_MASK(periph_id);
+	writel(reg, reset);
+}
+
+#ifdef CONFIG_OF_CONTROL
+/*
+ * Convert a device tree clock ID to our peripheral ID. They are mostly
+ * the same but we are very cautious so we check that a valid clock ID is
+ * provided.
+ *
+ * @param clk_id	Clock ID according to tegra30 device tree binding
+ * @return peripheral ID, or PERIPH_ID_NONE if the clock ID is invalid
+ */
+enum periph_id clk_id_to_periph_id(int clk_id)
+{
+	if (clk_id > PERIPH_ID_COUNT)
+		return PERIPH_ID_NONE;
+
+	switch (clk_id) {
+	case PERIPH_ID_RESERVED3:
+	case PERIPH_ID_RESERVED4:
+	case PERIPH_ID_RESERVED16:
+	case PERIPH_ID_RESERVED24:
+	case PERIPH_ID_RESERVED35:
+	case PERIPH_ID_RESERVED43:
+	case PERIPH_ID_RESERVED45:
+	case PERIPH_ID_RESERVED56:
+	case PERIPH_ID_PCIEXCLK:
+	case PERIPH_ID_RESERVED76:
+	case PERIPH_ID_RESERVED77:
+	case PERIPH_ID_RESERVED78:
+	case PERIPH_ID_RESERVED83:
+	case PERIPH_ID_RESERVED89:
+	case PERIPH_ID_RESERVED91:
+	case PERIPH_ID_RESERVED93:
+	case PERIPH_ID_RESERVED94:
+	case PERIPH_ID_RESERVED95:
+		return PERIPH_ID_NONE;
+	default:
+		return clk_id;
+	}
+}
+#endif /* CONFIG_OF_CONTROL */
+
+void clock_early_init(void)
+{
+	tegra30_set_up_pllp();
+}
+
+void arch_timer_init(void)
+{
+}
+
+#define PMC_SATA_PWRGT 0x1ac
+#define  PMC_SATA_PWRGT_PLLE_IDDQ_OVERRIDE (1 << 5)
+#define  PMC_SATA_PWRGT_PLLE_IDDQ_SWCTL (1 << 4)
+
+#define PLLE_SS_CNTL 0x68
+#define  PLLE_SS_CNTL_SSCINCINTRV(x) (((x) & 0x3f) << 24)
+#define  PLLE_SS_CNTL_SSCINC(x) (((x) & 0xff) << 16)
+#define  PLLE_SS_CNTL_SSCBYP (1 << 12)
+#define  PLLE_SS_CNTL_INTERP_RESET (1 << 11)
+#define  PLLE_SS_CNTL_BYPASS_SS (1 << 10)
+#define  PLLE_SS_CNTL_SSCMAX(x) (((x) & 0x1ff) << 0)
+
+#define PLLE_BASE 0x0e8
+#define  PLLE_BASE_ENABLE_CML (1 << 31)
+#define  PLLE_BASE_ENABLE (1 << 30)
+#define  PLLE_BASE_PLDIV_CML(x) (((x) & 0xf) << 24)
+#define  PLLE_BASE_PLDIV(x) (((x) & 0x3f) << 16)
+#define  PLLE_BASE_NDIV(x) (((x) & 0xff) << 8)
+#define  PLLE_BASE_MDIV(x) (((x) & 0xff) << 0)
+
+#define PLLE_MISC 0x0ec
+#define  PLLE_MISC_SETUP_BASE(x) (((x) & 0xffff) << 16)
+#define  PLLE_MISC_PLL_READY (1 << 15)
+#define  PLLE_MISC_LOCK (1 << 11)
+#define  PLLE_MISC_LOCK_ENABLE (1 << 9)
+#define  PLLE_MISC_SETUP_EXT(x) (((x) & 0x3) << 2)
+
+static int tegra_plle_train(void)
+{
+	unsigned int timeout = 2000;
+	unsigned long value;
+
+	value = readl(NV_PA_PMC_BASE + PMC_SATA_PWRGT);
+	value |= PMC_SATA_PWRGT_PLLE_IDDQ_OVERRIDE;
+	writel(value, NV_PA_PMC_BASE + PMC_SATA_PWRGT);
+
+	value = readl(NV_PA_PMC_BASE + PMC_SATA_PWRGT);
+	value |= PMC_SATA_PWRGT_PLLE_IDDQ_SWCTL;
+	writel(value, NV_PA_PMC_BASE + PMC_SATA_PWRGT);
+
+	value = readl(NV_PA_PMC_BASE + PMC_SATA_PWRGT);
+	value &= ~PMC_SATA_PWRGT_PLLE_IDDQ_OVERRIDE;
+	writel(value, NV_PA_PMC_BASE + PMC_SATA_PWRGT);
+
+	do {
+		value = readl(NV_PA_CLK_RST_BASE + PLLE_MISC);
+		if (value & PLLE_MISC_PLL_READY)
+			break;
+
+		udelay(100);
+	} while (--timeout);
+
+	if (timeout == 0) {
+		error("timeout waiting for PLLE to become ready");
+		return -ETIMEDOUT;
+	}
+
+	return 0;
+}
+
+int tegra_plle_enable(void)
+{
+	unsigned int cpcon = 11, p = 18, n = 150, m = 1, timeout = 1000;
+	u32 value;
+	int err;
+
+	/* disable PLLE clock */
+	value = readl(NV_PA_CLK_RST_BASE + PLLE_BASE);
+	value &= ~PLLE_BASE_ENABLE_CML;
+	value &= ~PLLE_BASE_ENABLE;
+	writel(value, NV_PA_CLK_RST_BASE + PLLE_BASE);
+
+	/* clear lock enable and setup field */
+	value = readl(NV_PA_CLK_RST_BASE + PLLE_MISC);
+	value &= ~PLLE_MISC_LOCK_ENABLE;
+	value &= ~PLLE_MISC_SETUP_BASE(0xffff);
+	value &= ~PLLE_MISC_SETUP_EXT(0x3);
+	writel(value, NV_PA_CLK_RST_BASE + PLLE_MISC);
+
+	value = readl(NV_PA_CLK_RST_BASE + PLLE_MISC);
+	if ((value & PLLE_MISC_PLL_READY) == 0) {
+		err = tegra_plle_train();
+		if (err < 0) {
+			error("failed to train PLLE: %d", err);
+			return err;
+		}
+	}
+
+	/* configure PLLE */
+	value = readl(NV_PA_CLK_RST_BASE + PLLE_BASE);
+
+	value &= ~PLLE_BASE_PLDIV_CML(0x0f);
+	value |= PLLE_BASE_PLDIV_CML(cpcon);
+
+	value &= ~PLLE_BASE_PLDIV(0x3f);
+	value |= PLLE_BASE_PLDIV(p);
+
+	value &= ~PLLE_BASE_NDIV(0xff);
+	value |= PLLE_BASE_NDIV(n);
+
+	value &= ~PLLE_BASE_MDIV(0xff);
+	value |= PLLE_BASE_MDIV(m);
+
+	writel(value, NV_PA_CLK_RST_BASE + PLLE_BASE);
+
+	value = readl(NV_PA_CLK_RST_BASE + PLLE_MISC);
+	value |= PLLE_MISC_SETUP_BASE(0x7);
+	value |= PLLE_MISC_LOCK_ENABLE;
+	value |= PLLE_MISC_SETUP_EXT(0);
+	writel(value, NV_PA_CLK_RST_BASE + PLLE_MISC);
+
+	value = readl(NV_PA_CLK_RST_BASE + PLLE_SS_CNTL);
+	value |= PLLE_SS_CNTL_SSCBYP | PLLE_SS_CNTL_INTERP_RESET |
+		 PLLE_SS_CNTL_BYPASS_SS;
+	writel(value, NV_PA_CLK_RST_BASE + PLLE_SS_CNTL);
+
+	value = readl(NV_PA_CLK_RST_BASE + PLLE_BASE);
+	value |= PLLE_BASE_ENABLE_CML | PLLE_BASE_ENABLE;
+	writel(value, NV_PA_CLK_RST_BASE + PLLE_BASE);
+
+	do {
+		value = readl(NV_PA_CLK_RST_BASE + PLLE_MISC);
+		if (value & PLLE_MISC_LOCK)
+			break;
+
+		udelay(2);
+	} while (--timeout);
+
+	if (timeout == 0) {
+		error("timeout waiting for PLLE to lock");
+		return -ETIMEDOUT;
+	}
+
+	udelay(50);
+
+	value = readl(NV_PA_CLK_RST_BASE + PLLE_SS_CNTL);
+	value &= ~PLLE_SS_CNTL_SSCINCINTRV(0x3f);
+	value |= PLLE_SS_CNTL_SSCINCINTRV(0x18);
+
+	value &= ~PLLE_SS_CNTL_SSCINC(0xff);
+	value |= PLLE_SS_CNTL_SSCINC(0x01);
+
+	value &= ~PLLE_SS_CNTL_SSCBYP;
+	value &= ~PLLE_SS_CNTL_INTERP_RESET;
+	value &= ~PLLE_SS_CNTL_BYPASS_SS;
+
+	value &= ~PLLE_SS_CNTL_SSCMAX(0x1ff);
+	value |= PLLE_SS_CNTL_SSCMAX(0x24);
+	writel(value, NV_PA_CLK_RST_BASE + PLLE_SS_CNTL);
+
+	return 0;
+}
diff --git a/arch/arm/mach-tegra/tegra30/cpu.c b/arch/arm/mach-tegra/tegra30/cpu.c
new file mode 100644
index 0000000..c76e74c
--- /dev/null
+++ b/arch/arm/mach-tegra/tegra30/cpu.c
@@ -0,0 +1,183 @@
+/*
+ * Copyright (c) 2010-2014, NVIDIA CORPORATION.  All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <asm/arch/clock.h>
+#include <asm/arch/flow.h>
+#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 "../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
+
+static void enable_cpu_power_rail(void)
+{
+	struct pmc_ctlr *pmc = (struct pmc_ctlr *)NV_PA_PMC_BASE;
+	u32 reg;
+
+	debug("enable_cpu_power_rail entry\n");
+	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);
+}
+
+/**
+ * The T30 requires some special clock initialization, including setting up
+ * the dvc i2c, turning on mselect and selecting the G CPU cluster
+ */
+void t30_init_clocks(void)
+{
+	struct clk_rst_ctlr *clkrst =
+			(struct clk_rst_ctlr *)NV_PA_CLK_RST_BASE;
+	struct flow_ctlr *flow = (struct flow_ctlr *)NV_PA_FLOW_BASE;
+	u32 val;
+
+	debug("t30_init_clocks entry\n");
+	/* Set active CPU cluster to G */
+	clrbits_le32(flow->cluster_control, 1 << 0);
+
+	writel(SUPER_SCLK_ENB_MASK, &clkrst->crc_super_sclk_div);
+
+	val = (0 << CLK_SYS_RATE_HCLK_DISABLE_SHIFT) |
+		(1 << CLK_SYS_RATE_AHB_RATE_SHIFT) |
+		(0 << CLK_SYS_RATE_PCLK_DISABLE_SHIFT) |
+		(0 << CLK_SYS_RATE_APB_RATE_SHIFT);
+	writel(val, &clkrst->crc_clk_sys_rate);
+
+	/* Put i2c, mselect in reset and enable clocks */
+	reset_set_enable(PERIPH_ID_DVC_I2C, 1);
+	clock_set_enable(PERIPH_ID_DVC_I2C, 1);
+	reset_set_enable(PERIPH_ID_MSELECT, 1);
+	clock_set_enable(PERIPH_ID_MSELECT, 1);
+
+	/* Switch MSELECT clock to PLLP (00) and use a divisor of 2 */
+	clock_ll_set_source_divisor(PERIPH_ID_MSELECT, 0, 2);
+
+	/*
+	 * Our high-level clock routines are not available prior to
+	 * relocation. We use the low-level functions which require a
+	 * hard-coded divisor. Use CLK_M with divide by (n + 1 = 17)
+	 */
+	clock_ll_set_source_divisor(PERIPH_ID_DVC_I2C, 3, 16);
+
+	/*
+	 * Give clocks time to stabilize, then take i2c and mselect out of
+	 * reset
+	 */
+	udelay(1000);
+	reset_set_enable(PERIPH_ID_DVC_I2C, 0);
+	reset_set_enable(PERIPH_ID_MSELECT, 0);
+}
+
+static void set_cpu_running(int run)
+{
+	struct flow_ctlr *flow = (struct flow_ctlr *)NV_PA_FLOW_BASE;
+
+	debug("set_cpu_running entry, run = %d\n", run);
+	writel(run ? FLOW_MODE_NONE : FLOW_MODE_STOP, &flow->halt_cpu_events);
+}
+
+void start_cpu(u32 reset_vector)
+{
+	debug("start_cpu entry, reset_vector = %x\n", reset_vector);
+	t30_init_clocks();
+
+	/* Enable VDD_CPU */
+	enable_cpu_power_rail();
+
+	set_cpu_running(0);
+
+	/* Hold the CPUs in reset */
+	reset_A9_cpu(1);
+
+	/* Disable the CPU clock */
+	enable_cpu_clock(0);
+
+	/* Enable CoreSight */
+	clock_enable_coresight(1);
+
+	/*
+	 * Set the entry point for CPU execution from reset,
+	 *  if it's a non-zero value.
+	 */
+	if (reset_vector)
+		writel(reset_vector, EXCEP_VECTOR_CPU_RESET_VECTOR);
+
+	/* Enable the CPU clock */
+	enable_cpu_clock(1);
+
+	/* If the CPU doesn't already have power, power it up */
+	powerup_cpu();
+
+	/* Take the CPU out of reset */
+	reset_A9_cpu(0);
+
+	set_cpu_running(1);
+}
diff --git a/arch/arm/mach-tegra/tegra30/funcmux.c b/arch/arm/mach-tegra/tegra30/funcmux.c
new file mode 100644
index 0000000..409335c
--- /dev/null
+++ b/arch/arm/mach-tegra/tegra30/funcmux.c
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2010-2012, NVIDIA CORPORATION.  All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* Tegra30 high-level function multiplexing */
+
+#include <common.h>
+#include <asm/arch/clock.h>
+#include <asm/arch/funcmux.h>
+#include <asm/arch/pinmux.h>
+
+int funcmux_select(enum periph_id id, int config)
+{
+	int bad_config = config != FUNCMUX_DEFAULT;
+
+	switch (id) {
+	case PERIPH_ID_UART1:
+		switch (config) {
+		case FUNCMUX_UART1_ULPI:
+			pinmux_set_func(PMUX_PINGRP_ULPI_DATA0_PO1,
+					PMUX_FUNC_UARTA);
+			pinmux_set_func(PMUX_PINGRP_ULPI_DATA1_PO2,
+					PMUX_FUNC_UARTA);
+			pinmux_set_func(PMUX_PINGRP_ULPI_DATA2_PO3,
+					PMUX_FUNC_UARTA);
+			pinmux_set_func(PMUX_PINGRP_ULPI_DATA3_PO4,
+					PMUX_FUNC_UARTA);
+			pinmux_tristate_disable(PMUX_PINGRP_ULPI_DATA0_PO1);
+			pinmux_tristate_disable(PMUX_PINGRP_ULPI_DATA1_PO2);
+			pinmux_tristate_disable(PMUX_PINGRP_ULPI_DATA2_PO3);
+			pinmux_tristate_disable(PMUX_PINGRP_ULPI_DATA3_PO4);
+			break;
+		}
+		break;
+
+	/* Add other periph IDs here as needed */
+
+	default:
+		debug("%s: invalid periph_id %d", __func__, id);
+		return -1;
+	}
+
+	if (bad_config) {
+		debug("%s: invalid config %d for periph_id %d", __func__,
+		      config, id);
+		return -1;
+	}
+	return 0;
+}
diff --git a/arch/arm/mach-tegra/tegra30/pinmux.c b/arch/arm/mach-tegra/tegra30/pinmux.c
new file mode 100644
index 0000000..7eb0574
--- /dev/null
+++ b/arch/arm/mach-tegra/tegra30/pinmux.c
@@ -0,0 +1,276 @@
+/*
+ * Copyright (c) 2010-2014, NVIDIA CORPORATION. All rights reserved.
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <asm/arch/pinmux.h>
+
+#define PIN(pin, f0, f1, f2, f3)	\
+	{				\
+		.funcs = {		\
+			PMUX_FUNC_##f0,	\
+			PMUX_FUNC_##f1,	\
+			PMUX_FUNC_##f2,	\
+			PMUX_FUNC_##f3,	\
+		},			\
+	}
+
+#define PIN_RESERVED {}
+
+static const struct pmux_pingrp_desc tegra30_pingroups[] = {
+	/*  pin,                  f0,           f1,       f2,       f3 */
+	/* Offset 0x3000 */
+	PIN(ULPI_DATA0_PO1,       SPI3,         HSI,      UARTA,    ULPI),
+	PIN(ULPI_DATA1_PO2,       SPI3,         HSI,      UARTA,    ULPI),
+	PIN(ULPI_DATA2_PO3,       SPI3,         HSI,      UARTA,    ULPI),
+	PIN(ULPI_DATA3_PO4,       SPI3,         HSI,      UARTA,    ULPI),
+	PIN(ULPI_DATA4_PO5,       SPI2,         HSI,      UARTA,    ULPI),
+	PIN(ULPI_DATA5_PO6,       SPI2,         HSI,      UARTA,    ULPI),
+	PIN(ULPI_DATA6_PO7,       SPI2,         HSI,      UARTA,    ULPI),
+	PIN(ULPI_DATA7_PO0,       SPI2,         HSI,      UARTA,    ULPI),
+	PIN(ULPI_CLK_PY0,         SPI1,         RSVD2,    UARTD,    ULPI),
+	PIN(ULPI_DIR_PY1,         SPI1,         RSVD2,    UARTD,    ULPI),
+	PIN(ULPI_NXT_PY2,         SPI1,         RSVD2,    UARTD,    ULPI),
+	PIN(ULPI_STP_PY3,         SPI1,         RSVD2,    UARTD,    ULPI),
+	PIN(DAP3_FS_PP0,          I2S2,         RSVD2,    DISPLAYA, DISPLAYB),
+	PIN(DAP3_DIN_PP1,         I2S2,         RSVD2,    DISPLAYA, DISPLAYB),
+	PIN(DAP3_DOUT_PP2,        I2S2,         RSVD2,    DISPLAYA, DISPLAYB),
+	PIN(DAP3_SCLK_PP3,        I2S2,         RSVD2,    DISPLAYA, DISPLAYB),
+	PIN(PV0,                  RSVD1,        RSVD2,    RSVD3,    RSVD4),
+	PIN(PV1,                  RSVD1,        RSVD2,    RSVD3,    RSVD4),
+	PIN(SDMMC1_CLK_PZ0,       SDMMC1,       RSVD2,    RSVD3,    UARTA),
+	PIN(SDMMC1_CMD_PZ1,       SDMMC1,       RSVD2,    RSVD3,    UARTA),
+	PIN(SDMMC1_DAT3_PY4,      SDMMC1,       RSVD2,    UARTE,    UARTA),
+	PIN(SDMMC1_DAT2_PY5,      SDMMC1,       RSVD2,    UARTE,    UARTA),
+	PIN(SDMMC1_DAT1_PY6,      SDMMC1,       RSVD2,    UARTE,    UARTA),
+	PIN(SDMMC1_DAT0_PY7,      SDMMC1,       RSVD2,    UARTE,    UARTA),
+	PIN(PV2,                  OWR,          RSVD2,    RSVD3,    RSVD4),
+	PIN(PV3,                  CLK_12M_OUT,  RSVD2,    RSVD3,    RSVD4),
+	PIN(CLK2_OUT_PW5,         EXTPERIPH2,   RSVD2,    RSVD3,    RSVD4),
+	PIN(CLK2_REQ_PCC5,        DAP,          RSVD2,    RSVD3,    RSVD4),
+	PIN(LCD_PWR1_PC1,         DISPLAYA,     DISPLAYB, RSVD3,    RSVD4),
+	PIN(LCD_PWR2_PC6,         DISPLAYA,     DISPLAYB, SPI5,     HDCP),
+	PIN(LCD_SDIN_PZ2,         DISPLAYA,     DISPLAYB, SPI5,     RSVD4),
+	PIN(LCD_SDOUT_PN5,        DISPLAYA,     DISPLAYB, SPI5,     HDCP),
+	PIN(LCD_WR_N_PZ3,         DISPLAYA,     DISPLAYB, SPI5,     HDCP),
+	PIN(LCD_CS0_N_PN4,        DISPLAYA,     DISPLAYB, SPI5,     RSVD4),
+	PIN(LCD_DC0_PN6,          DISPLAYA,     DISPLAYB, RSVD3,    RSVD4),
+	PIN(LCD_SCK_PZ4,          DISPLAYA,     DISPLAYB, SPI5,     HDCP),
+	PIN(LCD_PWR0_PB2,         DISPLAYA,     DISPLAYB, SPI5,     HDCP),
+	PIN(LCD_PCLK_PB3,         DISPLAYA,     DISPLAYB, RSVD3,    RSVD4),
+	PIN(LCD_DE_PJ1,           DISPLAYA,     DISPLAYB, RSVD3,    RSVD4),
+	PIN(LCD_HSYNC_PJ3,        DISPLAYA,     DISPLAYB, RSVD3,    RSVD4),
+	PIN(LCD_VSYNC_PJ4,        DISPLAYA,     DISPLAYB, RSVD3,    RSVD4),
+	PIN(LCD_D0_PE0,           DISPLAYA,     DISPLAYB, RSVD3,    RSVD4),
+	PIN(LCD_D1_PE1,           DISPLAYA,     DISPLAYB, RSVD3,    RSVD4),
+	PIN(LCD_D2_PE2,           DISPLAYA,     DISPLAYB, RSVD3,    RSVD4),
+	PIN(LCD_D3_PE3,           DISPLAYA,     DISPLAYB, RSVD3,    RSVD4),
+	PIN(LCD_D4_PE4,           DISPLAYA,     DISPLAYB, RSVD3,    RSVD4),
+	PIN(LCD_D5_PE5,           DISPLAYA,     DISPLAYB, RSVD3,    RSVD4),
+	PIN(LCD_D6_PE6,           DISPLAYA,     DISPLAYB, RSVD3,    RSVD4),
+	PIN(LCD_D7_PE7,           DISPLAYA,     DISPLAYB, RSVD3,    RSVD4),
+	PIN(LCD_D8_PF0,           DISPLAYA,     DISPLAYB, RSVD3,    RSVD4),
+	PIN(LCD_D9_PF1,           DISPLAYA,     DISPLAYB, RSVD3,    RSVD4),
+	PIN(LCD_D10_PF2,          DISPLAYA,     DISPLAYB, RSVD3,    RSVD4),
+	PIN(LCD_D11_PF3,          DISPLAYA,     DISPLAYB, RSVD3,    RSVD4),
+	PIN(LCD_D12_PF4,          DISPLAYA,     DISPLAYB, RSVD3,    RSVD4),
+	PIN(LCD_D13_PF5,          DISPLAYA,     DISPLAYB, RSVD3,    RSVD4),
+	PIN(LCD_D14_PF6,          DISPLAYA,     DISPLAYB, RSVD3,    RSVD4),
+	PIN(LCD_D15_PF7,          DISPLAYA,     DISPLAYB, RSVD3,    RSVD4),
+	PIN(LCD_D16_PM0,          DISPLAYA,     DISPLAYB, RSVD3,    RSVD4),
+	PIN(LCD_D17_PM1,          DISPLAYA,     DISPLAYB, RSVD3,    RSVD4),
+	PIN(LCD_D18_PM2,          DISPLAYA,     DISPLAYB, RSVD3,    RSVD4),
+	PIN(LCD_D19_PM3,          DISPLAYA,     DISPLAYB, RSVD3,    RSVD4),
+	PIN(LCD_D20_PM4,          DISPLAYA,     DISPLAYB, RSVD3,    RSVD4),
+	PIN(LCD_D21_PM5,          DISPLAYA,     DISPLAYB, RSVD3,    RSVD4),
+	PIN(LCD_D22_PM6,          DISPLAYA,     DISPLAYB, RSVD3,    RSVD4),
+	PIN(LCD_D23_PM7,          DISPLAYA,     DISPLAYB, RSVD3,    RSVD4),
+	PIN(LCD_CS1_N_PW0,        DISPLAYA,     DISPLAYB, SPI5,     RSVD4),
+	PIN(LCD_M1_PW1,           DISPLAYA,     DISPLAYB, RSVD3,    RSVD4),
+	PIN(LCD_DC1_PD2,          DISPLAYA,     DISPLAYB, RSVD3,    RSVD4),
+	PIN(HDMI_INT_PN7,         HDMI,         RSVD2,    RSVD3,    RSVD4),
+	PIN(DDC_SCL_PV4,          I2C4,         RSVD2,    RSVD3,    RSVD4),
+	PIN(DDC_SDA_PV5,          I2C4,         RSVD2,    RSVD3,    RSVD4),
+	PIN(CRT_HSYNC_PV6,        CRT,          RSVD2,    RSVD3,    RSVD4),
+	PIN(CRT_VSYNC_PV7,        CRT,          RSVD2,    RSVD3,    RSVD4),
+	PIN(VI_D0_PT4,            DDR,          RSVD2,    VI,       RSVD4),
+	PIN(VI_D1_PD5,            DDR,          SDMMC2,   VI,       RSVD4),
+	PIN(VI_D2_PL0,            DDR,          SDMMC2,   VI,       RSVD4),
+	PIN(VI_D3_PL1,            DDR,          SDMMC2,   VI,       RSVD4),
+	PIN(VI_D4_PL2,            DDR,          SDMMC2,   VI,       RSVD4),
+	PIN(VI_D5_PL3,            DDR,          SDMMC2,   VI,       RSVD4),
+	PIN(VI_D6_PL4,            DDR,          SDMMC2,   VI,       RSVD4),
+	PIN(VI_D7_PL5,            DDR,          SDMMC2,   VI,       RSVD4),
+	PIN(VI_D8_PL6,            DDR,          SDMMC2,   VI,       RSVD4),
+	PIN(VI_D9_PL7,            DDR,          SDMMC2,   VI,       RSVD4),
+	PIN(VI_D10_PT2,           DDR,          RSVD2,    VI,       RSVD4),
+	PIN(VI_D11_PT3,           DDR,          RSVD2,    VI,       RSVD4),
+	PIN(VI_PCLK_PT0,          RSVD1,        SDMMC2,   VI,       RSVD4),
+	PIN(VI_MCLK_PT1,          VI,           VI_ALT1,  VI_ALT2,  VI_ALT3),
+	PIN(VI_VSYNC_PD6,         DDR,          RSVD2,    VI,       RSVD4),
+	PIN(VI_HSYNC_PD7,         DDR,          RSVD2,    VI,       RSVD4),
+	PIN(UART2_RXD_PC3,        UARTB,        SPDIF,    UARTA,    SPI4),
+	PIN(UART2_TXD_PC2,        UARTB,        SPDIF,    UARTA,    SPI4),
+	PIN(UART2_RTS_N_PJ6,      UARTA,        UARTB,    GMI,      SPI4),
+	PIN(UART2_CTS_N_PJ5,      UARTA,        UARTB,    GMI,      SPI4),
+	PIN(UART3_TXD_PW6,        UARTC,        RSVD2,    GMI,      RSVD4),
+	PIN(UART3_RXD_PW7,        UARTC,        RSVD2,    GMI,      RSVD4),
+	PIN(UART3_CTS_N_PA1,      UARTC,        RSVD2,    GMI,      RSVD4),
+	PIN(UART3_RTS_N_PC0,      UARTC,        PWM0,     GMI,      RSVD4),
+	PIN(PU0,                  OWR,          UARTA,    GMI,      RSVD4),
+	PIN(PU1,                  RSVD1,        UARTA,    GMI,      RSVD4),
+	PIN(PU2,                  RSVD1,        UARTA,    GMI,      RSVD4),
+	PIN(PU3,                  PWM0,         UARTA,    GMI,      RSVD4),
+	PIN(PU4,                  PWM1,         UARTA,    GMI,      RSVD4),
+	PIN(PU5,                  PWM2,         UARTA,    GMI,      RSVD4),
+	PIN(PU6,                  PWM3,         UARTA,    GMI,      RSVD4),
+	PIN(GEN1_I2C_SDA_PC5,     I2C1,         RSVD2,    RSVD3,    RSVD4),
+	PIN(GEN1_I2C_SCL_PC4,     I2C1,         RSVD2,    RSVD3,    RSVD4),
+	PIN(DAP4_FS_PP4,          I2S3,         RSVD2,    GMI,      RSVD4),
+	PIN(DAP4_DIN_PP5,         I2S3,         RSVD2,    GMI,      RSVD4),
+	PIN(DAP4_DOUT_PP6,        I2S3,         RSVD2,    GMI,      RSVD4),
+	PIN(DAP4_SCLK_PP7,        I2S3,         RSVD2,    GMI,      RSVD4),
+	PIN(CLK3_OUT_PEE0,        EXTPERIPH3,   RSVD2,    RSVD3,    RSVD4),
+	PIN(CLK3_REQ_PEE1,        DEV3,         RSVD2,    RSVD3,    RSVD4),
+	PIN(GMI_WP_N_PC7,         RSVD1,        NAND,     GMI,      GMI_ALT),
+	PIN(GMI_IORDY_PI5,        RSVD1,        NAND,     GMI,      RSVD4),
+	PIN(GMI_WAIT_PI7,         RSVD1,        NAND,     GMI,      RSVD4),
+	PIN(GMI_ADV_N_PK0,        RSVD1,        NAND,     GMI,      RSVD4),
+	PIN(GMI_CLK_PK1,          RSVD1,        NAND,     GMI,      RSVD4),
+	PIN(GMI_CS0_N_PJ0,        RSVD1,        NAND,     GMI,      DTV),
+	PIN(GMI_CS1_N_PJ2,        RSVD1,        NAND,     GMI,      DTV),
+	PIN(GMI_CS2_N_PK3,        RSVD1,        NAND,     GMI,      RSVD4),
+	PIN(GMI_CS3_N_PK4,        RSVD1,        NAND,     GMI,      GMI_ALT),
+	PIN(GMI_CS4_N_PK2,        RSVD1,        NAND,     GMI,      RSVD4),
+	PIN(GMI_CS6_N_PI3,        NAND,         NAND_ALT, GMI,      SATA),
+	PIN(GMI_CS7_N_PI6,        NAND,         NAND_ALT, GMI,      GMI_ALT),
+	PIN(GMI_AD0_PG0,          RSVD1,        NAND,     GMI,      RSVD4),
+	PIN(GMI_AD1_PG1,          RSVD1,        NAND,     GMI,      RSVD4),
+	PIN(GMI_AD2_PG2,          RSVD1,        NAND,     GMI,      RSVD4),
+	PIN(GMI_AD3_PG3,          RSVD1,        NAND,     GMI,      RSVD4),
+	PIN(GMI_AD4_PG4,          RSVD1,        NAND,     GMI,      RSVD4),
+	PIN(GMI_AD5_PG5,          RSVD1,        NAND,     GMI,      RSVD4),
+	PIN(GMI_AD6_PG6,          RSVD1,        NAND,     GMI,      RSVD4),
+	PIN(GMI_AD7_PG7,          RSVD1,        NAND,     GMI,      RSVD4),
+	PIN(GMI_AD8_PH0,          PWM0,         NAND,     GMI,      RSVD4),
+	PIN(GMI_AD9_PH1,          PWM1,         NAND,     GMI,      RSVD4),
+	PIN(GMI_AD10_PH2,         PWM2,         NAND,     GMI,      RSVD4),
+	PIN(GMI_AD11_PH3,         PWM3,         NAND,     GMI,      RSVD4),
+	PIN(GMI_AD12_PH4,         RSVD1,        NAND,     GMI,      RSVD4),
+	PIN(GMI_AD13_PH5,         RSVD1,        NAND,     GMI,      RSVD4),
+	PIN(GMI_AD14_PH6,         RSVD1,        NAND,     GMI,      RSVD4),
+	PIN(GMI_AD15_PH7,         RSVD1,        NAND,     GMI,      RSVD4),
+	PIN(GMI_A16_PJ7,          UARTD,        SPI4,     GMI,      GMI_ALT),
+	PIN(GMI_A17_PB0,          UARTD,        SPI4,     GMI,      DTV),
+	PIN(GMI_A18_PB1,          UARTD,        SPI4,     GMI,      DTV),
+	PIN(GMI_A19_PK7,          UARTD,        SPI4,     GMI,      RSVD4),
+	PIN(GMI_WR_N_PI0,         RSVD1,        NAND,     GMI,      RSVD4),
+	PIN(GMI_OE_N_PI1,         RSVD1,        NAND,     GMI,      RSVD4),
+	PIN(GMI_DQS_PI2,          RSVD1,        NAND,     GMI,      RSVD4),
+	PIN(GMI_RST_N_PI4,        NAND,         NAND_ALT, GMI,      RSVD4),
+	PIN(GEN2_I2C_SCL_PT5,     I2C2,         HDCP,     GMI,      RSVD4),
+	PIN(GEN2_I2C_SDA_PT6,     I2C2,         HDCP,     GMI,      RSVD4),
+	PIN(SDMMC4_CLK_PCC4,      INVALID,      NAND,     GMI,      SDMMC4),
+	PIN(SDMMC4_CMD_PT7,       I2C3,         NAND,     GMI,      SDMMC4),
+	PIN(SDMMC4_DAT0_PAA0,     UARTE,        SPI3,     GMI,      SDMMC4),
+	PIN(SDMMC4_DAT1_PAA1,     UARTE,        SPI3,     GMI,      SDMMC4),
+	PIN(SDMMC4_DAT2_PAA2,     UARTE,        SPI3,     GMI,      SDMMC4),
+	PIN(SDMMC4_DAT3_PAA3,     UARTE,        SPI3,     GMI,      SDMMC4),
+	PIN(SDMMC4_DAT4_PAA4,     I2C3,         I2S4,     GMI,      SDMMC4),
+	PIN(SDMMC4_DAT5_PAA5,     VGP3,         I2S4,     GMI,      SDMMC4),
+	PIN(SDMMC4_DAT6_PAA6,     VGP4,         I2S4,     GMI,      SDMMC4),
+	PIN(SDMMC4_DAT7_PAA7,     VGP5,         I2S4,     GMI,      SDMMC4),
+	PIN(SDMMC4_RST_N_PCC3,    VGP6,         RSVD2,    RSVD3,    SDMMC4),
+	PIN(CAM_MCLK_PCC0,        VI,           VI_ALT1,  VI_ALT3,  SDMMC4),
+	PIN(PCC1,                 I2S4,         RSVD2,    RSVD3,    SDMMC4),
+	PIN(PBB0,                 I2S4,         RSVD2,    RSVD3,    SDMMC4),
+	PIN(CAM_I2C_SCL_PBB1,     VGP1,         I2C3,     RSVD3,    SDMMC4),
+	PIN(CAM_I2C_SDA_PBB2,     VGP2,         I2C3,     RSVD3,    SDMMC4),
+	PIN(PBB3,                 VGP3,         DISPLAYA, DISPLAYB, SDMMC4),
+	PIN(PBB4,                 VGP4,         DISPLAYA, DISPLAYB, SDMMC4),
+	PIN(PBB5,                 VGP5,         DISPLAYA, DISPLAYB, SDMMC4),
+	PIN(PBB6,                 VGP6,         DISPLAYA, DISPLAYB, SDMMC4),
+	PIN(PBB7,                 I2S4,         RSVD2,    RSVD3,    SDMMC4),
+	PIN(PCC2,                 I2S4,         RSVD2,    RSVD3,    RSVD4),
+	PIN(JTAG_RTCK_PU7,        RTCK,         RSVD2,    RSVD3,    RSVD4),
+	PIN(PWR_I2C_SCL_PZ6,      I2CPWR,       RSVD2,    RSVD3,    RSVD4),
+	PIN(PWR_I2C_SDA_PZ7,      I2CPWR,       RSVD2,    RSVD3,    RSVD4),
+	PIN(KB_ROW0_PR0,          KBC,          NAND,     RSVD3,    RSVD4),
+	PIN(KB_ROW1_PR1,          KBC,          NAND,     RSVD3,    RSVD4),
+	PIN(KB_ROW2_PR2,          KBC,          NAND,     RSVD3,    RSVD4),
+	PIN(KB_ROW3_PR3,          KBC,          NAND,     RSVD3,    INVALID),
+	PIN(KB_ROW4_PR4,          KBC,          NAND,     TRACE,    RSVD4),
+	PIN(KB_ROW5_PR5,          KBC,          NAND,     TRACE,    OWR),
+	PIN(KB_ROW6_PR6,          KBC,          NAND,     SDMMC2,   MIO),
+	PIN(KB_ROW7_PR7,          KBC,          NAND,     SDMMC2,   MIO),
+	PIN(KB_ROW8_PS0,          KBC,          NAND,     SDMMC2,   MIO),
+	PIN(KB_ROW9_PS1,          KBC,          NAND,     SDMMC2,   MIO),
+	PIN(KB_ROW10_PS2,         KBC,          NAND,     SDMMC2,   MIO),
+	PIN(KB_ROW11_PS3,         KBC,          NAND,     SDMMC2,   MIO),
+	PIN(KB_ROW12_PS4,         KBC,          NAND,     SDMMC2,   MIO),
+	PIN(KB_ROW13_PS5,         KBC,          NAND,     SDMMC2,   MIO),
+	PIN(KB_ROW14_PS6,         KBC,          NAND,     SDMMC2,   MIO),
+	PIN(KB_ROW15_PS7,         KBC,          NAND,     SDMMC2,   MIO),
+	PIN(KB_COL0_PQ0,          KBC,          NAND,     TRACE,    TEST),
+	PIN(KB_COL1_PQ1,          KBC,          NAND,     TRACE,    TEST),
+	PIN(KB_COL2_PQ2,          KBC,          NAND,     TRACE,    RSVD4),
+	PIN(KB_COL3_PQ3,          KBC,          NAND,     TRACE,    RSVD4),
+	PIN(KB_COL4_PQ4,          KBC,          NAND,     TRACE,    RSVD4),
+	PIN(KB_COL5_PQ5,          KBC,          NAND,     TRACE,    RSVD4),
+	PIN(KB_COL6_PQ6,          KBC,          NAND,     TRACE,    MIO),
+	PIN(KB_COL7_PQ7,          KBC,          NAND,     TRACE,    MIO),
+	PIN(CLK_32K_OUT_PA0,      BLINK,        RSVD2,    RSVD3,    RSVD4),
+	PIN(SYS_CLK_REQ_PZ5,      SYSCLK,       RSVD2,    RSVD3,    RSVD4),
+	PIN(CORE_PWR_REQ,         CORE_PWR_REQ, RSVD2,    RSVD3,    RSVD4),
+	PIN(CPU_PWR_REQ,          CPU_PWR_REQ,  RSVD2,    RSVD3,    RSVD4),
+	PIN(PWR_INT_N,            PWR_INT_N,    RSVD2,    RSVD3,    RSVD4),
+	PIN(CLK_32K_IN,           CLK_32K_IN,   RSVD2,    RSVD3,    RSVD4),
+	PIN(OWR,                  OWR,          CEC,      RSVD3,    RSVD4),
+	PIN(DAP1_FS_PN0,          I2S0,         HDA,      GMI,      SDMMC2),
+	PIN(DAP1_DIN_PN1,         I2S0,         HDA,      GMI,      SDMMC2),
+	PIN(DAP1_DOUT_PN2,        I2S0,         HDA,      GMI,      SDMMC2),
+	PIN(DAP1_SCLK_PN3,        I2S0,         HDA,      GMI,      SDMMC2),
+	PIN(CLK1_REQ_PEE2,        DAP,          HDA,      RSVD3,    RSVD4),
+	PIN(CLK1_OUT_PW4,         EXTPERIPH1,   RSVD2,    RSVD3,    RSVD4),
+	PIN(SPDIF_IN_PK6,         SPDIF,        HDA,      I2C1,     SDMMC2),
+	PIN(SPDIF_OUT_PK5,        SPDIF,        RSVD2,    I2C1,     SDMMC2),
+	PIN(DAP2_FS_PA2,          I2S1,         HDA,      RSVD3,    GMI),
+	PIN(DAP2_DIN_PA4,         I2S1,         HDA,      RSVD3,    GMI),
+	PIN(DAP2_DOUT_PA5,        I2S1,         HDA,      RSVD3,    GMI),
+	PIN(DAP2_SCLK_PA3,        I2S1,         HDA,      RSVD3,    GMI),
+	PIN(SPI2_MOSI_PX0,        SPI6,         SPI2,     SPI3,     GMI),
+	PIN(SPI2_MISO_PX1,        SPI6,         SPI2,     SPI3,     GMI),
+	PIN(SPI2_CS0_N_PX3,       SPI6,         SPI2,     SPI3,     GMI),
+	PIN(SPI2_SCK_PX2,         SPI6,         SPI2,     SPI3,     GMI),
+	PIN(SPI1_MOSI_PX4,        SPI2,         SPI1,     SPI2_ALT, GMI),
+	PIN(SPI1_SCK_PX5,         SPI2,         SPI1,     SPI2_ALT, GMI),
+	PIN(SPI1_CS0_N_PX6,       SPI2,         SPI1,     SPI2_ALT, GMI),
+	PIN(SPI1_MISO_PX7,        SPI3,         SPI1,     SPI2_ALT, RSVD4),
+	PIN(SPI2_CS1_N_PW2,       SPI3,         SPI2,     SPI2_ALT, I2C1),
+	PIN(SPI2_CS2_N_PW3,       SPI3,         SPI2,     SPI2_ALT, I2C1),
+	PIN(SDMMC3_CLK_PA6,       UARTA,        PWM2,     SDMMC3,   SPI3),
+	PIN(SDMMC3_CMD_PA7,       UARTA,        PWM3,     SDMMC3,   SPI2),
+	PIN(SDMMC3_DAT0_PB7,      RSVD1,        RSVD2,    SDMMC3,   SPI3),
+	PIN(SDMMC3_DAT1_PB6,      RSVD1,        RSVD2,    SDMMC3,   SPI3),
+	PIN(SDMMC3_DAT2_PB5,      RSVD1,        PWM1,     SDMMC3,   SPI3),
+	PIN(SDMMC3_DAT3_PB4,      RSVD1,        PWM0,     SDMMC3,   SPI3),
+	PIN(SDMMC3_DAT4_PD1,      PWM1,         SPI4,     SDMMC3,   SPI2),
+	PIN(SDMMC3_DAT5_PD0,      PWM0,         SPI4,     SDMMC3,   SPI2),
+	PIN(SDMMC3_DAT6_PD3,      SPDIF,        SPI4,     SDMMC3,   SPI2),
+	PIN(SDMMC3_DAT7_PD4,      SPDIF,        SPI4,     SDMMC3,   SPI2),
+	PIN(PEX_L0_PRSNT_N_PDD0,  PCIE,         HDA,      RSVD3,    RSVD4),
+	PIN(PEX_L0_RST_N_PDD1,    PCIE,         HDA,      RSVD3,    RSVD4),
+	PIN(PEX_L0_CLKREQ_N_PDD2, PCIE,         HDA,      RSVD3,    RSVD4),
+	PIN(PEX_WAKE_N_PDD3,      PCIE,         HDA,      RSVD3,    RSVD4),
+	PIN(PEX_L1_PRSNT_N_PDD4,  PCIE,         HDA,      RSVD3,    RSVD4),
+	PIN(PEX_L1_RST_N_PDD5,    PCIE,         HDA,      RSVD3,    RSVD4),
+	PIN(PEX_L1_CLKREQ_N_PDD6, PCIE,         HDA,      RSVD3,    RSVD4),
+	PIN(PEX_L2_PRSNT_N_PDD7,  PCIE,         HDA,      RSVD3,    RSVD4),
+	PIN(PEX_L2_RST_N_PCC6,    PCIE,         HDA,      RSVD3,    RSVD4),
+	PIN(PEX_L2_CLKREQ_N_PCC7, PCIE,         HDA,      RSVD3,    RSVD4),
+	PIN(HDMI_CEC_PEE3,        CEC,          RSVD2,    RSVD3,    RSVD4),
+};
+const struct pmux_pingrp_desc *tegra_soc_pingroups = tegra30_pingroups;
diff --git a/arch/arm/mach-tegra/vpr.c b/arch/arm/mach-tegra/vpr.c
new file mode 100644
index 0000000..f695811
--- /dev/null
+++ b/arch/arm/mach-tegra/vpr.c
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2014, NVIDIA CORPORATION.  All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* Tegra vpr routines */
+
+#include <common.h>
+#include <asm/io.h>
+#include <asm/arch/tegra.h>
+#include <asm/arch/mc.h>
+
+/* Configures VPR.  Right now, all we do is turn it off. */
+void config_vpr(void)
+{
+	struct mc_ctlr *mc = (struct mc_ctlr *)NV_PA_MC_BASE;
+
+	/* Turn VPR off */
+	writel(0, &mc->mc_video_protect_size_mb);
+	writel(TEGRA_MC_VIDEO_PROTECT_REG_WRITE_ACCESS_DISABLED,
+	       &mc->mc_video_protect_reg_ctrl);
+	/* read back to ensure the write went through */
+	readl(&mc->mc_video_protect_reg_ctrl);
+}
diff --git a/arch/arm/mach-tegra/xusb-padctl.c b/arch/arm/mach-tegra/xusb-padctl.c
new file mode 100644
index 0000000..65f8d2e
--- /dev/null
+++ b/arch/arm/mach-tegra/xusb-padctl.c
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2014, NVIDIA CORPORATION.  All rights reserved.
+ *
+ * SPDX-License-Identifier: GPL-2.0
+ */
+
+#include <common.h>
+#include <errno.h>
+
+#include <asm/arch-tegra/xusb-padctl.h>
+
+struct tegra_xusb_phy * __weak tegra_xusb_phy_get(unsigned int type)
+{
+	return NULL;
+}
+
+int __weak tegra_xusb_phy_prepare(struct tegra_xusb_phy *phy)
+{
+	return -ENOSYS;
+}
+
+int __weak tegra_xusb_phy_enable(struct tegra_xusb_phy *phy)
+{
+	return -ENOSYS;
+}
+
+int __weak tegra_xusb_phy_disable(struct tegra_xusb_phy *phy)
+{
+	return -ENOSYS;
+}
+
+int __weak tegra_xusb_phy_unprepare(struct tegra_xusb_phy *phy)
+{
+	return -ENOSYS;
+}
+
+void __weak tegra_xusb_padctl_init(const void *fdt)
+{
+}