[coreboot-gerrit] Patch set updated for coreboot: nvidia/tegra210: add new SoC

Patrick Georgi (pgeorgi@google.com) gerrit at coreboot.org
Fri Jun 26 23:38:31 CEST 2015


Patrick Georgi (pgeorgi at google.com) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/10633

-gerrit

commit 7447af484d07b477301af4029a777a64366a9845
Author: Patrick Georgi <pgeorgi at chromium.org>
Date:   Mon Jun 22 19:41:29 2015 +0200

    nvidia/tegra210: add new SoC
    
    This includes Chrome OS downstream up to Change-Id: I714fdc87e.
    
    Change-Id: I81853434600390d643160fe57554495b2bfe60ab
    Signed-off-by: Patrick Georgi <pgeorgi at chromium.org>
---
 src/arch/arm64/Makefile.inc                        |    5 +-
 src/soc/nvidia/tegra210/Kconfig                    |  144 ++
 src/soc/nvidia/tegra210/Makefile.inc               |  159 ++
 src/soc/nvidia/tegra210/addressmap.c               |  232 +++
 src/soc/nvidia/tegra210/ape.c                      |   55 +
 src/soc/nvidia/tegra210/bootblock.c                |   97 ++
 src/soc/nvidia/tegra210/bootblock_asm.S            |   45 +
 src/soc/nvidia/tegra210/cbmem.c                    |   40 +
 src/soc/nvidia/tegra210/ccplex.c                   |  122 ++
 src/soc/nvidia/tegra210/chip.h                     |   99 ++
 src/soc/nvidia/tegra210/clock.c                    |  786 +++++++++
 src/soc/nvidia/tegra210/cpu.c                      |   79 +
 src/soc/nvidia/tegra210/cpu_lib.S                  |   27 +
 src/soc/nvidia/tegra210/dc.c                       |  249 +++
 src/soc/nvidia/tegra210/dma.c                      |  147 ++
 src/soc/nvidia/tegra210/dp.c                       | 1663 ++++++++++++++++++++
 src/soc/nvidia/tegra210/dsi.c                      | 1045 ++++++++++++
 src/soc/nvidia/tegra210/flow_ctrl.c                |  113 ++
 src/soc/nvidia/tegra210/funitcfg.c                 |  186 +++
 src/soc/nvidia/tegra210/gic.c                      |   31 +
 src/soc/nvidia/tegra210/i2c.c                      |   57 +
 src/soc/nvidia/tegra210/i2c6.c                     |   95 ++
 src/soc/nvidia/tegra210/include/soc/addressmap.h   |  142 ++
 src/soc/nvidia/tegra210/include/soc/ccplex.h       |   33 +
 src/soc/nvidia/tegra210/include/soc/clk_rst.h      |  599 +++++++
 src/soc/nvidia/tegra210/include/soc/clock.h        |  442 ++++++
 src/soc/nvidia/tegra210/include/soc/clst_clk.h     |   61 +
 src/soc/nvidia/tegra210/include/soc/cpu.h          |   33 +
 src/soc/nvidia/tegra210/include/soc/display.h      |   60 +
 src/soc/nvidia/tegra210/include/soc/dma.h          |  189 +++
 src/soc/nvidia/tegra210/include/soc/emc.h          |  475 ++++++
 src/soc/nvidia/tegra210/include/soc/flow.h         |   86 +
 src/soc/nvidia/tegra210/include/soc/flow_ctrl.h    |   30 +
 src/soc/nvidia/tegra210/include/soc/funitcfg.h     |   94 ++
 src/soc/nvidia/tegra210/include/soc/gpio.h         |   25 +
 src/soc/nvidia/tegra210/include/soc/id.h           |   35 +
 src/soc/nvidia/tegra210/include/soc/maincpu.h      |   29 +
 src/soc/nvidia/tegra210/include/soc/mc.h           |  231 +++
 src/soc/nvidia/tegra210/include/soc/memlayout.ld   |   44 +
 .../tegra210/include/soc/memlayout_vboot2.ld       |   47 +
 src/soc/nvidia/tegra210/include/soc/mipi-phy.h     |   46 +
 src/soc/nvidia/tegra210/include/soc/mipi_display.h |  148 ++
 src/soc/nvidia/tegra210/include/soc/mipi_dsi.h     |  316 ++++
 .../nvidia/tegra210/include/soc/mmu_operations.h   |   28 +
 src/soc/nvidia/tegra210/include/soc/mtc.h          |   37 +
 src/soc/nvidia/tegra210/include/soc/padconfig.h    |   94 ++
 src/soc/nvidia/tegra210/include/soc/pinmux.h       |  285 ++++
 src/soc/nvidia/tegra210/include/soc/pmc.h          |  680 ++++++++
 src/soc/nvidia/tegra210/include/soc/power.h        |   32 +
 src/soc/nvidia/tegra210/include/soc/romstage.h     |   29 +
 src/soc/nvidia/tegra210/include/soc/sdram.h        |   31 +
 .../nvidia/tegra210/include/soc/sdram_configs.h    |   28 +
 src/soc/nvidia/tegra210/include/soc/sdram_param.h  |  979 ++++++++++++
 src/soc/nvidia/tegra210/include/soc/secure_boot.h  |   37 +
 src/soc/nvidia/tegra210/include/soc/sor.h          |  930 +++++++++++
 src/soc/nvidia/tegra210/include/soc/spi.h          |   67 +
 src/soc/nvidia/tegra210/include/soc/sysctr.h       |   55 +
 src/soc/nvidia/tegra210/include/soc/tegra_dsi.h    |  223 +++
 src/soc/nvidia/tegra210/include/soc/verstage.h     |   25 +
 .../jdi_25x18_display/panel-jdi-lpm102a188a.c      |  215 +++
 .../jdi_25x18_display/panel-jdi-lpm102a188a.h      |  131 ++
 src/soc/nvidia/tegra210/lp0/Makefile               |   58 +
 src/soc/nvidia/tegra210/lp0/tegra_lp0_resume.c     |  691 ++++++++
 src/soc/nvidia/tegra210/lp0/tegra_lp0_resume.ld    |   73 +
 src/soc/nvidia/tegra210/maincpu.S                  |   55 +
 src/soc/nvidia/tegra210/mipi-phy.c                 |   92 ++
 src/soc/nvidia/tegra210/mipi.c                     |  204 +++
 src/soc/nvidia/tegra210/mipi_dsi.c                 |  431 +++++
 src/soc/nvidia/tegra210/mmu_operations.c           |   81 +
 src/soc/nvidia/tegra210/monotonic_timer.c          |   27 +
 src/soc/nvidia/tegra210/mtc.c                      |   89 ++
 src/soc/nvidia/tegra210/padconfig.c                |  137 ++
 src/soc/nvidia/tegra210/power.c                    |  129 ++
 src/soc/nvidia/tegra210/psci.c                     |  194 +++
 src/soc/nvidia/tegra210/ram_code.c                 |   29 +
 src/soc/nvidia/tegra210/ramstage.c                 |   39 +
 src/soc/nvidia/tegra210/reset.c                    |   29 +
 src/soc/nvidia/tegra210/reset_handler.S            |   75 +
 src/soc/nvidia/tegra210/romstage.c                 |   90 ++
 src/soc/nvidia/tegra210/romstage_asm.S             |   27 +
 src/soc/nvidia/tegra210/sdram.c                    | 1082 +++++++++++++
 src/soc/nvidia/tegra210/sdram_lp0.c                |  628 ++++++++
 src/soc/nvidia/tegra210/secmon.c                   |   50 +
 src/soc/nvidia/tegra210/soc.c                      |  191 +++
 src/soc/nvidia/tegra210/sor.c                      | 1100 +++++++++++++
 src/soc/nvidia/tegra210/spi.c                      |  944 +++++++++++
 src/soc/nvidia/tegra210/stack.S                    |   45 +
 src/soc/nvidia/tegra210/uart.c                     |  135 ++
 src/soc/nvidia/tegra210/verstage.c                 |   52 +
 89 files changed, 19322 insertions(+), 2 deletions(-)

diff --git a/src/arch/arm64/Makefile.inc b/src/arch/arm64/Makefile.inc
index 1aeef76..a651d25 100644
--- a/src/arch/arm64/Makefile.inc
+++ b/src/arch/arm64/Makefile.inc
@@ -195,12 +195,12 @@ BL31_MAKEARGS += DEBUG=1
 endif # CONFIG_CONSOLE_SERIAL
 
 # Avoid build/release|build/debug distinction by overriding BUILD_PLAT directly
-BL31_MAKEARGS += BUILD_PLAT="$(top)/$(obj)/3rdparty/arm-trusted-firmware"
+BL31_MAKEARGS += BUILD_PLAT="$(abspath $(obj)/3rdparty/arm-trusted-firmware)"
 
 BL31_CFLAGS := -fno-pic -fno-stack-protector
 BL31_LDFLAGS := --emit-relocs
 
-BL31 := $(obj)/3rdparty/arm-trusted-firmware/bl31/bl31.elf
+BL31 := $(obj)/bl31.elf
 
 $(BL31):
 	@printf "    MAKE       $(subst $(obj)/,,$(@))\n"
@@ -208,6 +208,7 @@ $(BL31):
 	CFLAGS="$(BL31_CFLAGS)" \
 	LDFLAGS="$(BL31_LDFLAGS)" \
 	$(MAKE) -C $(BL31_SOURCE) $(BL31_MAKEARGS) bl31
+	mv $(obj)/3rdparty/arm-trusted-firmware/bl31/bl31.elf $@
 
 .PHONY: $(BL31)
 
diff --git a/src/soc/nvidia/tegra210/Kconfig b/src/soc/nvidia/tegra210/Kconfig
new file mode 100644
index 0000000..d6b6878
--- /dev/null
+++ b/src/soc/nvidia/tegra210/Kconfig
@@ -0,0 +1,144 @@
+config SOC_NVIDIA_TEGRA210
+	bool
+	default n
+	select ARCH_BOOTBLOCK_ARMV4
+	select ARCH_VERSTAGE_ARMV4
+	select ARCH_ROMSTAGE_ARMV4
+	select ARCH_RAMSTAGE_ARMV8_64
+	select ARCH_ARM64_CPU_CORTEX_A57
+	select ARCH_ARM64_CORTEX_A57_POWER_DOWN_SUPPORT
+	select BOOTBLOCK_CONSOLE
+	select GIC
+	select HAVE_MONOTONIC_TIMER
+	select GENERIC_UDELAY
+	select HAVE_HARD_RESET
+	select HAVE_UART_SPECIAL
+	select HAVE_UART_MEMORY_MAPPED
+	select EARLY_CONSOLE
+	select ARM_BOOTBLOCK_CUSTOM
+	select DYNAMIC_CBMEM
+	select SMP
+	select ARM64_USE_ARM_TRUSTED_FIRMWARE
+	select HAS_PRECBMEM_TIMESTAMP_REGION
+	select CHROMEOS_RAMOOPS_NON_ACPI
+	select GENERIC_GPIO_LIB
+
+if SOC_NVIDIA_TEGRA210
+
+config MAINBOARD_DO_DSI_INIT
+	bool "Use dsi graphics interface"
+	depends on MAINBOARD_DO_NATIVE_VGA_INIT
+	default n
+	help
+	  Initialize dsi display
+
+config MAINBOARD_DO_SOR_INIT
+	bool "Use dp graphics interface"
+	depends on MAINBOARD_DO_NATIVE_VGA_INIT
+	default n
+	help
+	  Initialize dp display
+
+config BOOTBLOCK_CPU_INIT
+	string
+	default "soc/nvidia/tegra210/bootblock.c"
+	help
+	  CPU/SoC-specific bootblock code. This is useful if the
+	  bootblock must load microcode or copy data from ROM before
+	  searching for the bootblock.
+
+config MAX_CPUS
+	int
+	default 4
+
+choice CONSOLE_SERIAL_TEGRA210_UART_CHOICES
+	prompt "Serial Console UART"
+	default CONSOLE_SERIAL_TEGRA210_UARTA
+	depends on CONSOLE_SERIAL_UART
+
+config CONSOLE_SERIAL_TEGRA210_UARTA
+	bool "UARTA"
+	help
+	  Serial console on UART A.
+
+config CONSOLE_SERIAL_TEGRA210_UARTB
+	bool "UARTB"
+	help
+	  Serial console on UART B.
+
+config CONSOLE_SERIAL_TEGRA210_UARTC
+	bool "UARTC"
+	help
+	  Serial console on UART C.
+
+config CONSOLE_SERIAL_TEGRA210_UARTD
+	bool "UARTD"
+	help
+	  Serial console on UART D.
+
+config CONSOLE_SERIAL_TEGRA210_UARTE
+	bool "UARTE"
+	help
+	  Serial console on UART E.
+
+endchoice
+
+config CONSOLE_SERIAL_TEGRA210_UART_ADDRESS
+	hex
+	depends on CONSOLE_SERIAL_UART
+	default 0x70006000 if CONSOLE_SERIAL_TEGRA210_UARTA
+	default 0x70006040 if CONSOLE_SERIAL_TEGRA210_UARTB
+	default 0x70006200 if CONSOLE_SERIAL_TEGRA210_UARTC
+	default 0x70006300 if CONSOLE_SERIAL_TEGRA210_UARTD
+	default 0x70006400 if CONSOLE_SERIAL_TEGRA210_UARTE
+	help
+	  Map the UART names to the respective MMIO addres.
+
+config BOOTROM_SDRAM_INIT
+	bool "SoC BootROM does SDRAM init with full BCT"
+	default n
+	help
+	  Use during Foster LPDDR4 bringup.
+
+config TRUSTZONE_CARVEOUT_SIZE_MB
+	hex "Size of Trust Zone region"
+	default 0x4
+	help
+	  Size of Trust Zone area in MiB to reserve in memory map.
+
+# Default to 700MHz. This value is based on nv bootloader setting.
+config PLLX_KHZ
+        int
+        default 700000
+endif
+
+config HAVE_MTC
+	bool "Add external Memory controller Training Code binary"
+	default n
+	depends on USE_BLOBS
+	help
+	  Select this option to add emc training firmware
+
+if HAVE_MTC
+
+config MTC_FILE
+	string "tegra mtc firmware filename"
+	default "tegra_mtc.bin"
+	help
+	  The filename of the mtc firmware
+
+config MTC_DIRECTORY
+	string "Directory where MTC firmware file is located"
+	default "."
+	help
+	  Path to directory where MTC firmware file is located.
+
+config MTC_ADDRESS
+	hex
+	default 0x81000000
+	help
+	  The DRAM location where MTC firmware to be loaded in. This location
+	  needs to be consistent with the location defined in tegra_mtc.ld
+
+endif # HAVE_MTC
+
diff --git a/src/soc/nvidia/tegra210/Makefile.inc b/src/soc/nvidia/tegra210/Makefile.inc
new file mode 100644
index 0000000..98e752c
--- /dev/null
+++ b/src/soc/nvidia/tegra210/Makefile.inc
@@ -0,0 +1,159 @@
+ifeq ($(CONFIG_SOC_NVIDIA_TEGRA210),y)
+
+CBOOTIMAGE_OPTS = --soc tegra210
+
+bootblock-y += bootblock.c
+bootblock-y += bootblock_asm.S
+bootblock-y += clock.c
+bootblock-y += spi.c
+bootblock-y += i2c.c
+bootblock-y += dma.c
+bootblock-y += monotonic_timer.c
+bootblock-y += padconfig.c
+bootblock-y += power.c
+bootblock-y += funitcfg.c
+bootblock-y += reset.c
+bootblock-y += ../tegra/gpio.c
+bootblock-y += ../tegra/i2c.c
+bootblock-y += ../tegra/pingroup.c
+bootblock-y += ../tegra/pinmux.c
+bootblock-y += ../tegra/apbmisc.c
+bootblock-y += ../tegra/usb.c
+ifeq ($(CONFIG_BOOTBLOCK_CONSOLE),y)
+bootblock-$(CONFIG_DRIVERS_UART) += uart.c
+endif
+
+verstage-y += verstage.c
+verstage-y += dma.c
+verstage-y += monotonic_timer.c
+verstage-y += spi.c
+verstage-y += padconfig.c
+verstage-y += funitcfg.c
+verstage-$(CONFIG_DRIVERS_UART) += uart.c
+verstage-y += ../tegra/gpio.c
+verstage-y += ../tegra/i2c.c
+verstage-y += ../tegra/pinmux.c
+verstage-y += clock.c
+verstage-y += i2c.c
+
+romstage-y += romstage_asm.S
+romstage-y += addressmap.c
+romstage-y += cbmem.c
+romstage-y += ccplex.c
+romstage-y += clock.c
+romstage-y += cpu.c
+romstage-y += reset.c
+romstage-y += spi.c
+romstage-y += i2c.c
+romstage-y += dma.c
+romstage-y += monotonic_timer.c
+romstage-y += padconfig.c
+romstage-y += funitcfg.c
+romstage-y += romstage.c
+romstage-y += power.c
+romstage-y += ram_code.c
+ifneq ($(CONFIG_BOOTROM_SDRAM_INIT),y)
+romstage-y += sdram.c
+ ifeq ($(CONFIG_LP0_SUPPORT),y)
+romstage-y += sdram_lp0.c
+ endif
+endif
+romstage-y += ../tegra/gpio.c
+romstage-y += ../tegra/i2c.c
+romstage-y += ../tegra/pinmux.c
+romstage-y += ../tegra/usb.c
+romstage-$(CONFIG_DRIVERS_UART) += uart.c
+
+ramstage-y += addressmap.c
+ramstage-y += cbmem.c
+ramstage-y += cpu.c
+ramstage-y += cpu_lib.S
+ramstage-y += clock.c
+ramstage-$(CONFIG_MAINBOARD_DO_NATIVE_VGA_INIT) += dc.c
+ramstage-$(CONFIG_MAINBOARD_DO_DSI_INIT) += dsi.c
+ramstage-$(CONFIG_MAINBOARD_DO_DSI_INIT) += mipi_dsi.c
+ramstage-$(CONFIG_MAINBOARD_DO_DSI_INIT) += mipi.c
+ramstage-$(CONFIG_MAINBOARD_DO_DSI_INIT) += mipi-phy.c
+ramstage-$(CONFIG_MAINBOARD_DO_DSI_INIT) += ./jdi_25x18_display/panel-jdi-lpm102a188a.c
+ramstage-$(CONFIG_MAINBOARD_DO_SOR_INIT) += dp.c
+ramstage-$(CONFIG_MAINBOARD_DO_SOR_INIT) += sor.c
+
+ramstage-y += soc.c
+ramstage-y += spi.c
+ramstage-y += i2c.c
+ramstage-y += i2c6.c
+ramstage-y += ape.c
+ramstage-y += power.c
+ramstage-y += dma.c
+ramstage-y += gic.c
+ramstage-y += monotonic_timer.c
+ramstage-y += padconfig.c
+ramstage-y += funitcfg.c
+ramstage-y += reset.c
+ramstage-y += ram_code.c
+ramstage-y += ../tegra/apbmisc.c
+ramstage-y += ../tegra/gpio.c
+ramstage-y += ../tegra/i2c.c
+ramstage-y += ../tegra/pinmux.c
+ramstage-y += ramstage.c
+ramstage-y += mmu_operations.c
+ramstage-$(CONFIG_DRIVERS_UART) += uart.c
+ramstage-y += ../tegra/usb.c
+ramstage-$(CONFIG_ARM64_USE_SECURE_MONITOR) += secmon.c
+ramstage-$(CONFIG_HAVE_MTC) += mtc.c
+
+secmon-y += cpu.c
+secmon-y += cpu_lib.S
+secmon-y += flow_ctrl.c
+secmon-y += power.c
+secmon-y += psci.c
+secmon-y += reset_handler.S
+secmon-y += uart.c
+secmon-y += gic.c
+
+rmodules_arm-y += monotonic_timer.c
+VBOOT_STUB_DEPS += $(obj)/soc/nvidia/tegra210/monotonic_timer.rmodules_arm.o
+
+CPPFLAGS_common += -Isrc/soc/nvidia/tegra210/include/
+
+# We want to grab the bootblock right before it goes into the image and wrap
+# it inside a BCT, but ideally we would do that without making special, one
+# use modifications to the main ARM Makefile. We do this in two ways. First,
+# we copy bootblock.elf to bootblock.raw.elf and allow the %.bin: %.elf
+# template rule to turn it into bootblock.raw.bin. This makes sure whatever
+# processing is supposed to happen to turn an .elf into a .bin happens.
+#
+# Second, we add our own rule for creating bootblock.bin from
+# bootblock.raw.bin which displaces the template rule. When other rules that
+# package up the image pull in bootblock.bin, it will be this wrapped version
+# instead of the raw bootblock.
+
+$(objcbfs)/bootblock.raw.elf: $(objcbfs)/bootblock.elf
+	cp $< $@
+
+$(obj)/generated/bct.bin: $(obj)/generated/bct.cfg $(CBOOTIMAGE)
+	@printf "    CBOOTIMAGE $(subst $(obj)/,,$(@))\n"
+	$(CBOOTIMAGE) -gbct $(CBOOTIMAGE_OPTS) $< $@
+
+BCT_BIN = $(obj)/generated/bct.bin
+BCT_WRAPPER = $(obj)/generated/bct.wrapper
+$(objcbfs)/bootblock.bin: $(objcbfs)/bootblock.raw.bin $(BCT_BIN)
+	echo "Version    = 1;" > $(BCT_WRAPPER)
+	echo "Redundancy = 1;" >> $(BCT_WRAPPER)
+	echo "Bctcopy    = 1;" >> $(BCT_WRAPPER)
+	echo "Bctfile    = $(BCT_BIN);" >> $(BCT_WRAPPER)
+	echo "BootLoader = $<,$(call loadaddr,bootblock),$(call loadaddr,bootblock),Complete;" >> $(BCT_WRAPPER)
+	@printf "    CBOOTIMAGE $(subst $(obj)/,,$(@))\n"
+	$(CBOOTIMAGE) $(CBOOTIMAGE_OPTS) $(BCT_WRAPPER) $@
+
+BL31_MAKEARGS += PLAT=tegra TARGET_SOC=t210
+
+# MTC fw
+MTC_DIR = $(CONFIG_MTC_DIRECTORY)
+MTC_FILE = $(MTC_DIR)/$(CONFIG_MTC_FILE)
+MTC_FILE_CBFS = $(CONFIG_MTC_FILE)
+cbfs-files-$(CONFIG_HAVE_MTC) += $(MTC_FILE_CBFS)
+$(MTC_FILE_CBFS)-file := $(MTC_FILE)
+$(MTC_FILE_CBFS)-type := 0x50
+
+endif
diff --git a/src/soc/nvidia/tegra210/addressmap.c b/src/soc/nvidia/tegra210/addressmap.c
new file mode 100644
index 0000000..76afb5b
--- /dev/null
+++ b/src/soc/nvidia/tegra210/addressmap.c
@@ -0,0 +1,232 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright 2014 Google Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc.
+ */
+
+
+#include <arch/io.h>
+#include <console/console.h>
+#include <soc/addressmap.h>
+#include <soc/id.h>
+#include <soc/mc.h>
+#include <soc/sdram.h>
+#include <stdlib.h>
+#include <symbols.h>
+#include <soc/nvidia/tegra/types.h>
+
+static uintptr_t tz_base_mib;
+static const size_t tz_size_mib = CONFIG_TRUSTZONE_CARVEOUT_SIZE_MB;
+
+/* returns total amount of DRAM (in MB) from memory controller registers */
+int sdram_size_mb(void)
+{
+	struct tegra_mc_regs *mc = (struct tegra_mc_regs *)TEGRA_MC_BASE;
+	static int total_size = 0;
+
+	if (total_size)
+		return total_size;
+
+	/*
+	 * This obtains memory size from the External Memory Aperture
+	 * Configuration register. Nvidia confirmed that it is safe to assume
+	 * this value represents the total physical DRAM size.
+	 */
+	total_size = (read32(&mc->emem_cfg) >>
+			MC_EMEM_CFG_SIZE_MB_SHIFT) & MC_EMEM_CFG_SIZE_MB_MASK;
+
+	return total_size;
+}
+
+static void carveout_from_regs(uintptr_t *base_mib, size_t *size_mib,
+				uint32_t bom, uint32_t bom_hi, uint32_t size)
+{
+
+	/* All size regs of carveouts are in MiB. */
+	if (size == 0)
+		return;
+
+	*size_mib = size;
+	bom >>= 20;
+	bom |= bom_hi << (32 - 20);
+
+	*base_mib = bom;
+}
+
+void carveout_range(int id, uintptr_t *base_mib, size_t *size_mib)
+{
+	*base_mib = 0;
+	*size_mib = 0;
+	struct tegra_mc_regs * const mc = (struct tegra_mc_regs *)TEGRA_MC_BASE;
+	size_t region_size_mb;
+
+	switch (id) {
+	case CARVEOUT_TZ:
+		*base_mib = tz_base_mib;
+		*size_mib = tz_size_mib;
+		break;
+	case CARVEOUT_SEC:
+		carveout_from_regs(base_mib, size_mib,
+					read32(&mc->sec_carveout_bom),
+					read32(&mc->sec_carveout_adr_hi),
+					read32(&mc->sec_carveout_size_mb));
+		break;
+	case CARVEOUT_MTS:
+		carveout_from_regs(base_mib, size_mib,
+					read32(&mc->mts_carveout_bom),
+					read32(&mc->mts_carveout_adr_hi),
+					read32(&mc->mts_carveout_size_mb));
+		break;
+	case CARVEOUT_VPR:
+		carveout_from_regs(base_mib, size_mib,
+					read32(&mc->video_protect_bom),
+					read32(&mc->video_protect_bom_adr_hi),
+					read32(&mc->video_protect_size_mb));
+		break;
+	case CARVEOUT_GPU:
+		/* These carveout regs use 128KB granularity - convert to MB */
+		region_size_mb = DIV_ROUND_UP(read32(&mc->security_carveout2_size_128kb), 8);
+
+		/* BOM address set in gpu_region_init, below */
+		carveout_from_regs(base_mib, size_mib,
+					read32(&mc->security_carveout2_bom),
+					read32(&mc->security_carveout2_bom_hi),
+					region_size_mb);
+		break;
+	default:
+		break;
+	}
+}
+
+static void memory_in_range(uintptr_t *base_mib, uintptr_t *end_mib,
+				int ignore_carveout_id)
+{
+	uintptr_t base;
+	uintptr_t end;
+	int i;
+
+	base = (uintptr_t)_dram / MiB;
+	end = base + sdram_size_mb();
+
+	/* Requested limits out of range. */
+	if (*end_mib <= base || *base_mib >= end) {
+		*end_mib = *base_mib = 0;
+		return;
+	}
+
+	/* Clip region to passed in limits. */
+	if (*end_mib < end)
+		end = *end_mib;
+	if (*base_mib > base)
+		base = *base_mib;
+
+	for (i = 0; i < CARVEOUT_NUM; i++) {
+		uintptr_t carveout_base;
+		uintptr_t carveout_end;
+		size_t carveout_size;
+
+		if (i == ignore_carveout_id)
+			continue;
+
+		carveout_range(i, &carveout_base, &carveout_size);
+
+		if (carveout_size == 0)
+			continue;
+
+		carveout_end = carveout_base + carveout_size;
+
+		/* Bypass carveouts out of requested range. */
+		if (carveout_base >= end || carveout_end <= base)
+			continue;
+
+		/*
+		 * This is crude, but the assumption is that carveouts live
+		 * at the upper range of physical memory. Therefore, update
+		 * the end address to be equal to the base of the carveout.
+		 */
+		end = carveout_base;
+	}
+
+	*base_mib = base;
+	*end_mib = end;
+}
+
+void memory_in_range_below_4gb(uintptr_t *base_mib, uintptr_t *end_mib)
+{
+	*base_mib = 0;
+	*end_mib = 4096;
+	memory_in_range(base_mib, end_mib, CARVEOUT_NUM);
+}
+
+void memory_in_range_above_4gb(uintptr_t *base_mib, uintptr_t *end_mib)
+{
+	*base_mib = 4096;
+	*end_mib = ~0UL;
+	memory_in_range(base_mib, end_mib, CARVEOUT_NUM);
+}
+
+void trustzone_region_init(void)
+{
+	struct tegra_mc_regs * const mc = (void *)(uintptr_t)TEGRA_MC_BASE;
+	uintptr_t end = 4096;
+
+	/* Already has been initialized. */
+	if (tz_size_mib != 0 && tz_base_mib != 0)
+		return;
+
+	/*
+	 * Get memory layout below 4GiB ignoring the TZ carveout because
+	 * that's the one to initialize.
+	 */
+	memory_in_range(&tz_base_mib, &end, CARVEOUT_TZ);
+	tz_base_mib = end - tz_size_mib;
+
+	/* AVP cannot set the TZ registers proper as it is always non-secure. */
+	if (context_avp())
+		return;
+
+	/* Set the carveout region. */
+	write32(&mc->security_cfg0, tz_base_mib << 20);
+	write32(&mc->security_cfg1, tz_size_mib);
+
+	/* Enable SMMU translations */
+	write32(&mc->smmu_config, MC_SMMU_CONFIG_ENABLE);
+}
+
+void gpu_region_init(void)
+{
+	struct tegra_mc_regs * const mc = (void *)(uintptr_t)TEGRA_MC_BASE;
+	uintptr_t gpu_base_mib, end = 4096;
+	size_t gpu_size_mib = GPU_CARVEOUT_SIZE_MB;
+
+	/* Get memory layout below 4GiB */
+	memory_in_range(&gpu_base_mib, &end, CARVEOUT_GPU);
+	gpu_base_mib = end - gpu_size_mib;
+
+	/* Set the carveout2 base address. Everything else has been set in the BCT cfg/inc */
+	write32(&mc->security_carveout2_bom, gpu_base_mib << 20);
+	write32(&mc->security_carveout2_bom_hi, 0);
+
+	/* Set the locked bit. This will lock out any other writes! */
+	setbits_le32(&mc->security_carveout2_cfg0, MC_SECURITY_CARVEOUT_LOCKED);
+
+	/* Set the carveout3 base to 0, unused */
+	write32(&mc->security_carveout3_bom, 0);
+	write32(&mc->security_carveout3_bom_hi, 0);
+
+	/* Set the locked bit. This will lock out any other writes! */
+	setbits_le32(&mc->security_carveout3_cfg0, MC_SECURITY_CARVEOUT_LOCKED);
+}
diff --git a/src/soc/nvidia/tegra210/ape.c b/src/soc/nvidia/tegra210/ape.c
new file mode 100644
index 0000000..b46c11a
--- /dev/null
+++ b/src/soc/nvidia/tegra210/ape.c
@@ -0,0 +1,55 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (c) 2015, NVIDIA CORPORATION.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc.
+ */
+
+#include <delay.h>
+#include <soc/addressmap.h>
+#include <soc/clk_rst.h>
+#include <soc/clock.h>
+#include <soc/padconfig.h>
+#include <soc/power.h>
+
+static void enable_ape_periph_clocks(void)
+{
+	clock_enable(0, 0, 0, CLK_V_APB2APE, 0, 0, CLK_Y_APE);
+
+	/* Give clocks time to stabilize. */
+	udelay(IO_STABILIZATION_DELAY);
+}
+
+static void unreset_ape_periphs(void)
+{
+	clock_clr_reset(0, 0, 0, CLK_V_APB2APE, 0, 0, CLK_Y_APE);
+}
+
+/*
+ * Audio on Tegra210 requires some special init.
+ * The APE block must be unpowergated, and a couple of
+ * audio-based peripherals must be clocked and taken
+ * out of reset so that I2S/AXBAR/APB2APE registers can
+ * be configured to enable audio flow.
+ */
+
+void soc_configure_ape(void)
+{
+	power_ungate_partition(POWER_PARTID_APE);
+
+	enable_ape_periph_clocks();
+	remove_clamps(POWER_PARTID_APE);
+	unreset_ape_periphs();
+}
diff --git a/src/soc/nvidia/tegra210/bootblock.c b/src/soc/nvidia/tegra210/bootblock.c
new file mode 100644
index 0000000..f141927
--- /dev/null
+++ b/src/soc/nvidia/tegra210/bootblock.c
@@ -0,0 +1,97 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright 2014 Google Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc.
+ */
+
+#include <arch/exception.h>
+#include <arch/hlt.h>
+#include <bootblock_common.h>
+#include <console/console.h>
+#include <program_loading.h>
+#include <soc/addressmap.h>
+#include <soc/clock.h>
+#include <soc/nvidia/tegra/apbmisc.h>
+#include <soc/pmc.h>
+#include <soc/power.h>
+#include <timestamp.h>
+
+#define BCT_OFFSET_IN_BIT	0x50
+#define ODMDATA_OFFSET_IN_BCT	0x6A8
+#define TEGRA_SRAM_MAX		(TEGRA_SRAM_BASE + TEGRA_SRAM_SIZE)
+
+static void save_odmdata(void)
+{
+	struct tegra_pmc_regs *pmc = (struct tegra_pmc_regs*)TEGRA_PMC_BASE;
+	uintptr_t bct_offset;
+	u32 odmdata;
+
+	// pmc.odmdata: [18:19]: console type, [15:17]: UART id.
+	// TODO(twarren) ODMDATA is stored in the BCT, from bct/odmdata.cfg.
+	// I use the BCT offset in the BIT in SRAM to locate the BCT, and
+	// pick up the ODMDATA word at BCT offset 0x6A8. I could use a BCT
+	// struct header from cbootimage, but it seems like overkill for this.
+
+	bct_offset = read32((void *)(TEGRA_SRAM_BASE + BCT_OFFSET_IN_BIT));
+	if (bct_offset > TEGRA_SRAM_BASE && bct_offset < TEGRA_SRAM_MAX) {
+		odmdata = read32((void *)(bct_offset + ODMDATA_OFFSET_IN_BCT));
+		write32(&pmc->odmdata, odmdata);
+	}
+}
+
+void __attribute__((weak)) bootblock_mainboard_early_init(void)
+{
+	/* Empty default implementation. */
+}
+
+void main(void)
+{
+	// enable JTAG at the earliest stage
+	enable_jtag();
+
+	clock_early_uart();
+
+	/* Configure mselect clock. */
+	clock_configure_source(mselect, PLLP, 102000);
+
+	/* Enable AVP cache, timer, APB dma, and mselect blocks.  */
+	clock_enable_clear_reset(CLK_L_CACHE2 | CLK_L_TMR,
+				 CLK_H_APBDMA,
+				 0, CLK_V_MSELECT, 0, 0, 0);
+
+	/* Find ODMDATA in IRAM and save it to scratch reg */
+	save_odmdata();
+
+	bootblock_mainboard_early_init();
+
+	if (CONFIG_BOOTBLOCK_CONSOLE) {
+		console_init();
+		exception_init();
+		printk(BIOS_INFO, "T210: Bootblock here\n");
+	}
+
+	clock_init();
+
+	printk(BIOS_INFO, "T210 bootblock: Clock init done\n");
+
+	pmc_print_rst_status();
+
+	bootblock_mainboard_init();
+
+	printk(BIOS_INFO, "T210 bootblock: Mainboard bootblock init done\n");
+
+	run_romstage();
+}
diff --git a/src/soc/nvidia/tegra210/bootblock_asm.S b/src/soc/nvidia/tegra210/bootblock_asm.S
new file mode 100644
index 0000000..766a1b8
--- /dev/null
+++ b/src/soc/nvidia/tegra210/bootblock_asm.S
@@ -0,0 +1,45 @@
+/*
+ * Early initialization code for ARM architecture.
+ *
+ * This file is based off of the OMAP3530/ARM Cortex start.S file from Das
+ * U-Boot, which itself got the file from armboot.
+ *
+ * Copyright (c) 2004	Texas Instruments <r-woodruff2 at ti.com>
+ * Copyright (c) 2001	Marius Gröger <mag at sysgo.de>
+ * Copyright (c) 2002	Alex Züpke <azu at sysgo.de>
+ * Copyright (c) 2002	Gary Jennejohn <garyj at denx.de>
+ * Copyright (c) 2003	Richard Woodruff <r-woodruff2 at ti.com>
+ * Copyright (c) 2003	Kshitij <kshitij at ti.com>
+ * Copyright (c) 2006-2008 Syed Mohammed Khasim <x0khasim at ti.com>
+ * Copyright (c) 2013   The Chromium OS Authors
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; version 2 of
+ * the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc.
+ */
+
+#include <arch/asm.h>
+
+#include "stack.S"
+
+ENTRY(_start)
+	/*
+	 * Set the cpu to System mode with IRQ and FIQ disabled. Prefetch/Data
+	 * aborts may happen early and crash before the abort handlers are
+	 * installed, but at least the problem will show up near the code that
+	 * causes it.
+	 */
+	msr	cpsr_cxf, #0xdf
+
+	stack_init stack_top=_estack stack_bottom=_stack seed=1 func=main
+ENDPROC(_start)
diff --git a/src/soc/nvidia/tegra210/cbmem.c b/src/soc/nvidia/tegra210/cbmem.c
new file mode 100644
index 0000000..c161a36
--- /dev/null
+++ b/src/soc/nvidia/tegra210/cbmem.c
@@ -0,0 +1,40 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright 2014 Google Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc.
+ */
+
+#include <cbmem.h>
+#include <soc/addressmap.h>
+
+void *cbmem_top(void)
+{
+	static uintptr_t addr;
+
+	if (addr == 0) {
+		uintptr_t begin_mib;
+		uintptr_t end_mib;
+
+		memory_in_range_below_4gb(&begin_mib, &end_mib);
+		/* Make sure we consume everything up to 4GIB. */
+		if (end_mib == 4096)
+			addr = ~(uint32_t)0;
+		else
+			addr = end_mib << 20;
+	}
+
+	return (void *)addr;
+}
diff --git a/src/soc/nvidia/tegra210/ccplex.c b/src/soc/nvidia/tegra210/ccplex.c
new file mode 100644
index 0000000..f3c61cb
--- /dev/null
+++ b/src/soc/nvidia/tegra210/ccplex.c
@@ -0,0 +1,122 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright 2014 Google Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc.
+ */
+
+#include <arch/io.h>
+#include <cbfs.h>
+#include <console/console.h>
+#include <soc/addressmap.h>
+#include <soc/clock.h>
+#include <soc/clk_rst.h>
+#include <soc/ccplex.h>
+#include <soc/cpu.h>
+#include <soc/flow.h>
+#include <soc/mc.h>
+#include <soc/pmc.h>
+#include <soc/power.h>
+#include <soc/romstage.h>
+#include <string.h>
+#include <timer.h>
+
+#define PMC_REGS (void *)(uintptr_t)(TEGRA_PMC_BASE)
+
+static void enable_cpu_clocks(void)
+{
+	clock_enable(CLK_ENB_CPU, 0, 0, SET_CLK_ENB_CPUG_ENABLE |
+		     SET_CLK_ENB_CPULP_ENABLE, 0, 0, 0);
+}
+
+static void enable_cpu_power_partitions(void)
+{
+	/* Bring up fast cluster, non-CPU, CPU0, CPU1, CPU2 and CPU3 parts. */
+	power_ungate_partition(POWER_PARTID_CRAIL);
+	power_ungate_partition(POWER_PARTID_C0NC);
+	power_ungate_partition(POWER_PARTID_CE0);
+	if (IS_ENABLED(CONFIG_ARM64_USE_SECURE_MONITOR)) {
+		power_ungate_partition(POWER_PARTID_CE1);
+		power_ungate_partition(POWER_PARTID_CE2);
+		power_ungate_partition(POWER_PARTID_CE3);
+	}
+
+	if (IS_ENABLED(CONFIG_ARM64_USE_ARM_TRUSTED_FIRMWARE)) {
+		/*
+		 * Deassert reset signal of all the secondary CPUs.
+		 * PMC and flow controller will take over the power sequence
+		 * controller in the ATF.
+		 */
+		uint32_t reg = CRC_RST_CPUG_CLR_CPU1 | CRC_RST_CPUG_CLR_DBG1 |
+			       CRC_RST_CPUG_CLR_CORE1 | CRC_RST_CPUG_CLR_CX1 |
+			       CRC_RST_CPUG_CLR_CPU2 | CRC_RST_CPUG_CLR_DBG2 |
+			       CRC_RST_CPUG_CLR_CORE2 | CRC_RST_CPUG_CLR_CX2 |
+			       CRC_RST_CPUG_CLR_CPU3 | CRC_RST_CPUG_CLR_DBG3 |
+			       CRC_RST_CPUG_CLR_CORE3 | CRC_RST_CPUG_CLR_CX3;
+		write32(CLK_RST_REG(rst_cpug_cmplx_clr), reg);
+	}
+}
+
+static void request_ram_repair(void)
+{
+	struct flow_ctlr * const flow = (void *)(uintptr_t)TEGRA_FLOW_BASE;
+	const uint32_t req = 1 << 0;
+	const uint32_t sts = 1 << 1;
+	uint32_t reg;
+	struct stopwatch sw;
+
+	printk(BIOS_DEBUG, "Requesting RAM repair.\n");
+
+	stopwatch_init(&sw);
+
+	/* Perform ram repair */
+	reg = read32(&flow->ram_repair);
+	reg |= req;
+	write32(&flow->ram_repair, reg);
+	while ((read32(&flow->ram_repair) & sts) != sts)
+		;
+
+	printk(BIOS_DEBUG, "RAM repair complete in %ld usecs.\n",
+		stopwatch_duration_usecs(&sw));
+}
+
+void ccplex_cpu_prepare(void)
+{
+	enable_cpu_clocks();
+	enable_cpu_power_partitions();
+
+	mainboard_configure_pmc();
+	mainboard_enable_vdd_cpu();
+
+	request_ram_repair();
+}
+
+static void start_common_clocks(void)
+{
+	/* Clear fast CPU partition reset. */
+	write32(CLK_RST_REG(rst_cpug_cmplx_clr), CRC_RST_CPUG_CLR_NONCPU);
+
+	/* Clear reset of L2 and CoreSight components. */
+	write32(CLK_RST_REG(rst_cpug_cmplx_clr),
+		CRC_RST_CPUG_CLR_L2 | CRC_RST_CPUG_CLR_PDBG);
+}
+
+void ccplex_cpu_start(void *entry_addr)
+{
+	/* Enable common clocks for the shared resources between the cores. */
+	start_common_clocks();
+
+	start_cpu(0, entry_addr);
+}
diff --git a/src/soc/nvidia/tegra210/chip.h b/src/soc/nvidia/tegra210/chip.h
new file mode 100644
index 0000000..efce901
--- /dev/null
+++ b/src/soc/nvidia/tegra210/chip.h
@@ -0,0 +1,99 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright 2015 Google Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc.
+ */
+
+#ifndef __SOC_NVIDIA_TEGRA210_CHIP_H__
+#define __SOC_NVIDIA_TEGRA210_CHIP_H__
+#include <soc/addressmap.h>
+#include <stdint.h>
+#include <soc/nvidia/tegra/dc.h>
+
+struct soc_nvidia_tegra210_config {
+	/* Address to monitor if spintable employed. */
+	uintptr_t spintable_addr;
+
+	/*
+	 * panel resolution
+	 *  The two parameters below provides dc about panel spec.
+	 */
+	u32 xres;		/* the width of H display active area */
+	u32 yres;		/* the height of V display active area */
+	u32 framebuffer_bits_per_pixel;
+	u32 color_depth;	/* color format */
+
+	u64 display_controller;	/* dc block base address */
+	u32 framebuffer_base;
+
+	/*
+	 * Technically, we can compute this. At the same time, some platforms
+	 * might want to specify a specific size for their own reasons. If it
+	 * is zero the soc code will compute it as
+	 * xres*yres*framebuffer_bits_per_pixel/8
+	 */
+	u32 framebuffer_size;
+
+	/*
+	 * Framebuffer resolution
+	 *  The two parameters below provides dc about framebuffer's sdram size.
+	 *  When they are not the same as panel resolution, we need to program
+	 *  dc's DDA_INCREMENT and some other registers to resize dc output.
+	 */
+	u32 display_xres;
+	u32 display_yres;
+
+	int href_to_sync;	/* HSYNC position with respect to line start */
+	int hsync_width;	/* the width of HSYNC pulses */
+	int hback_porch;	/* the distance between HSYNC trailing edge to
+				   beginning of H display active area */
+	int hfront_porch;	/* the distance between end of H display active
+				   area to the leading edge of HSYNC */
+	int vref_to_sync;
+	int vsync_width;
+	int vback_porch;
+	int vfront_porch;
+	int refresh;		/* display refresh rate */
+
+	int pixel_clock;	/* dc pixel clock source rate */
+
+	u32 panel_bits_per_pixel;
+
+	/* dp specific fields */
+	struct {
+		/* pwm to use to set display contrast */
+		int pwm;
+
+		/* HPD related timing */
+		int vdd_to_hpd_delay_ms;
+		int hpd_unplug_min_us;
+		int hpd_plug_min_us;
+		int hpd_irq_min_us;
+
+		/* The minimum link configuraton settings */
+		u32 lane_count;
+		u32 enhanced_framing;
+		u32 link_bw;
+		u32 drive_current;
+		u32 preemphasis;
+		u32 postcursor;
+	} dp;
+
+	int win_opt;
+	void *dc_data;
+};
+
+#endif /* __SOC_NVIDIA_TEGRA210_CHIP_H__ */
diff --git a/src/soc/nvidia/tegra210/clock.c b/src/soc/nvidia/tegra210/clock.c
new file mode 100644
index 0000000..6055c0d
--- /dev/null
+++ b/src/soc/nvidia/tegra210/clock.c
@@ -0,0 +1,786 @@
+/*
+ * Copyright (c) 2013-2015, NVIDIA CORPORATION.  All rights reserved.
+ * Copyright 2014 Google Inc.
+ *
+ * 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 <arch/io.h>
+#include <assert.h>
+#include <console/console.h>
+#include <delay.h>
+#include <stdlib.h>
+#include <soc/addressmap.h>
+#include <soc/clk_rst.h>
+#include <soc/clock.h>
+#include <soc/clst_clk.h>
+#include <soc/flow.h>
+#include <soc/maincpu.h>
+#include <soc/pmc.h>
+#include <soc/sysctr.h>
+
+static struct flow_ctlr *flow = (void *)TEGRA_FLOW_BASE;
+static struct tegra_pmc_regs *pmc = (void *)TEGRA_PMC_BASE;
+static struct sysctr_regs *sysctr = (void *)TEGRA_SYSCTR0_BASE;
+
+enum {
+	PLLX_INDEX,
+	PLLC_INDEX,
+	PLLU_INDEX,
+	PLLDP_INDEX,
+	PLLD_INDEX,
+	PLL_MAX_INDEX,
+};
+
+struct pll_reg_info {
+	u32	*base_reg;
+	u32	*lock_enb_reg;
+	u32	lock_enb_val;
+	u32	*pll_lock_reg;
+	u32	pll_lock_val;
+	u32	*kcp_kvco_reg;
+	u32	n_shift:5;	/* n bits location */
+	u32	m_shift:5;	/* m bits location */
+	u32	p_shift:5;	/* p bits location */
+	u32	kcp_shift:5;	/* kcp bits location */
+	u32	kvco_shift:5;	/* kvco bit location */
+	u32	rsvd:7;
+} static const pll_reg_table[] = {
+	[PLLX_INDEX] = { .base_reg = CLK_RST_REG(pllx_base),
+			 .lock_enb_reg = CLK_RST_REG(pllx_misc),
+			 .lock_enb_val = PLLPAXS_MISC_LOCK_ENABLE,
+			 .pll_lock_reg = CLK_RST_REG(pllx_base),
+			 .pll_lock_val = PLL_BASE_LOCK,
+			 .kcp_kvco_reg = CLK_RST_REG(pllx_misc3),
+			 .n_shift = 8, .m_shift = 0, .p_shift = 20,
+			 .kcp_shift = 1, .kvco_shift = 0, },
+	[PLLC_INDEX] = { .base_reg = CLK_RST_REG(pllc_base),
+			 .lock_enb_reg = CLK_RST_REG(pllc_misc),
+			 .pll_lock_reg = CLK_RST_REG(pllc_base),
+			 .pll_lock_val = PLL_BASE_LOCK,
+			 .n_shift = 10, .m_shift = 0, .p_shift = 20, },
+	[PLLU_INDEX] = { .base_reg = CLK_RST_REG(pllu_base),
+			 .lock_enb_reg = CLK_RST_REG(pllu_misc),
+			 .lock_enb_val = PLLU_MISC_LOCK_ENABLE,
+			 .pll_lock_reg = CLK_RST_REG(pllu_base),
+			 .pll_lock_val = PLL_BASE_LOCK,
+			 .kcp_kvco_reg = CLK_RST_REG(pllu_misc),
+			 .n_shift = 8, .m_shift = 0, .p_shift = 16,
+			 .kcp_shift = 25, .kvco_shift = 24, },
+	[PLLDP_INDEX] = { .base_reg = CLK_RST_REG(plldp_base),
+			  .lock_enb_reg = CLK_RST_REG(plldp_misc),
+			  .lock_enb_val = PLLDPD2_MISC_LOCK_ENABLE,
+			  .pll_lock_reg = CLK_RST_REG(plldp_base),
+			  .pll_lock_val = PLL_BASE_LOCK,
+			  .kcp_kvco_reg = CLK_RST_REG(plldp_misc),
+			  .n_shift = 8, .m_shift = 0, .p_shift = 19,
+			  .kcp_shift = 25, .kvco_shift = 24, },
+	[PLLD_INDEX] = { .base_reg = CLK_RST_REG(plld_base),
+			 .lock_enb_reg = CLK_RST_REG(plld_misc),
+			 .lock_enb_val = PLLD_MISC_LOCK_ENABLE | PLLD_MISC_CLK_ENABLE,
+			 .pll_lock_reg = CLK_RST_REG(plld_base),
+			 .pll_lock_val = PLL_BASE_LOCK,
+			 .kcp_kvco_reg = CLK_RST_REG(plld_misc),
+			 .n_shift = 11, .m_shift = 0, .p_shift = 20,
+			 .kcp_shift = 23, .kvco_shift = 22, },
+};
+
+struct pll_fields {
+	u32	n:8;		/* the feedback divider bits width */
+	u32	m:8;		/* the input divider bits width */
+	u32	p:5;		/* the post divider bits witch */
+	u32	kcp:2;		/* charge pump gain control */
+	u32	kvco:1;	/* vco gain */
+	u32	rsvd:8;
+};
+
+#define PLL_HAS_KCP_KVCO(_n, _m, _p, _kcp, _kvco)	\
+	{.n = _n, .m = _m, .p = _p, .kcp = _kcp, .kvco = _kvco,}
+#define PLL_NO_KCP_KVCO(_n, _m, _p)			\
+	{.n = _n, .m = _m, .p = _p,}
+
+#define PLLX(_n, _m, _p, _kcp, _kvco)					\
+	[PLLX_INDEX] = PLL_HAS_KCP_KVCO(_n, _m, _p, _kcp, _kvco)
+#define PLLC(_n, _m, _p)						\
+	[PLLC_INDEX] = PLL_NO_KCP_KVCO(_n, _m, _p)
+#define PLLU(_n, _m, _p, _kcp, _kvco)					\
+	[PLLU_INDEX] = PLL_HAS_KCP_KVCO(_n, _m, _p, _kcp, _kvco)
+#define PLLDP(_n, _m, _p, _kcp, _kvco)					\
+	[PLLDP_INDEX] = PLL_HAS_KCP_KVCO(_n, _m, _p, _kcp, _kvco)
+#define PLLD(_n, _m, _p, _kcp, _kvco)					\
+	[PLLD_INDEX] = PLL_HAS_KCP_KVCO(_n, _m, _p, _kcp, _kvco)
+
+/* This table defines the frequency dividers for every PLL to turn the external
+ * OSC clock into the frequencies defined by TEGRA_PLL*_KHZ in soc/clock.h.
+ * All PLLs have three dividers (n, m and p), with the governing formula for
+ * the output frequency being CF = (IN / m), VCO = CF * n and OUT = VCO / (2^p).
+ * All divisor configurations must meet the PLL's constraints for VCO and CF:
+ * PLLX:  12 MHz < CF < 50 MHz, 700 MHz < VCO < 3000 MHz
+ * PLLC:  12 MHz < CF   < 50 MHz, 600 MHz < VCO < 1400 MHz
+ * PLLM:  12 MHz < CF < 50 MHz, 400 MHz < VCO < 1066 MHz
+ * PLLP:   1 MHz < CF <  6 MHz, 200 MHz < VCO <  700 MHz
+ * PLLD:   1 MHz < CF <  6 MHz, 500 MHz < VCO < 1000 MHz
+ * PLLU:   1 MHz < CF <  6 MHz, 480 MHz < VCO <  960 MHz
+ * PLLDP: 12 MHz < CF < 38 MHz, 600 MHz < VCO < 1200 MHz
+ * (values taken from Linux' drivers/clk/tegra/clk-tegra124.c).
+ * Target Frequencies:
+ * PLLX = CONFIG_PLLX_KHZ
+ * PLLC = 600 MHz
+ * PLLU = 240 MHz (As per TRM, m and n should be programmed to generate 480MHz
+ * VCO, and p should be programmed to do div-by-2.)
+ * PLLDP = 270 MHz (PLLDP treats p differently (OUT = VCO / (p + 1) for p < 6)).
+ * PLLM is set up dynamically by clock_sdram().
+ * PLLP is hardwired to 408 MHz in HW (unless we set BASE_OVRD).
+ */
+struct {
+	int			khz;
+	struct pll_fields	plls[PLL_MAX_INDEX];
+} static osc_table[16] = {
+	[OSC_FREQ_12]{
+		.khz = 12000,
+		.plls = {
+			PLLX(TEGRA_PLLX_KHZ / 12000, 1, 0, 0, 0),
+			PLLC(50, 1, 0), /* 600 MHz */
+			PLLU(40, 1, 1, 0, 0), /* 240 MHz */
+			PLLDP(90, 1, 2, 0, 0), /* 270 MHz */
+		},
+	},
+	[OSC_FREQ_13]{
+		.khz = 13000,
+		.plls = {
+			PLLX(TEGRA_PLLX_KHZ / 13000, 1, 0, 0, 0),
+			PLLC(46, 1, 0), /* 598.0 MHz */
+			PLLU(74, 2, 1, 0, 0), /* 240.5 MHz */
+			PLLDP(83, 1, 3, 0, 0), /* 269.8 MHz */
+		},
+	},
+	[OSC_FREQ_16P8]{
+		.khz = 16800,
+		.plls = {
+			PLLX(TEGRA_PLLX_KHZ / 16800, 1, 0, 0, 0),
+			PLLC(71, 1, 1), /* 596.4 MHz */
+			PLLU(115, 4, 1, 0, 0), /* 241.5 MHz */
+			PLLDP(64, 1, 2, 0, 0), /* 268.8 MHz */
+		},
+	},
+	[OSC_FREQ_19P2]{
+		.khz = 19200,
+		.plls = {
+			PLLX(TEGRA_PLLX_KHZ / 19200, 1, 0, 0, 0),
+			PLLC(62, 1, 1), /* 595.2 MHz */
+			PLLU(25, 1, 1, 0, 0), /* 240.0 MHz */
+			PLLDP(56, 1, 2, 0, 0), /* 268.8 MHz */
+		},
+	},
+	[OSC_FREQ_26]{
+		.khz = 26000,
+		.plls = {
+			PLLX(TEGRA_PLLX_KHZ / 26000, 1, 0, 0, 0),
+			PLLC(23, 1, 0), /* 598.0 MHz */
+			PLLU(37, 2, 1, 0, 0), /* 240.5 MHz */
+			PLLDP(83, 2, 2, 0, 0), /* 269.8 MHz */
+		},
+	},
+	[OSC_FREQ_38P4]{
+		.khz = 38400,
+		.plls = {
+			PLLX(TEGRA_PLLX_KHZ / 38400, 1, 0, 0, 0),
+			PLLC(62, 2, 1), /* 595.2 MHz */
+			PLLU(25, 2, 1, 0, 0), /* 240 MHz */
+			PLLDP(56, 2, 2, 0, 0), /* 268.8 MHz */
+		},
+	},
+	[OSC_FREQ_48]{
+		.khz = 48000,
+		.plls = {
+			PLLX(TEGRA_PLLX_KHZ / 48000, 1, 0, 0, 0),
+			PLLC(50, 2, 1), /* 600 MHz */
+			PLLU(40, 4, 1, 0, 0), /* 240 MHz */
+			PLLDP(90, 2, 3, 0, 0), /* 270 MHz */
+		},
+	},
+};
+
+/* Get the oscillator frequency, from the corresponding hardware
+ * configuration field. This is actually a per-soc thing. Avoid the
+ * temptation to make it common.
+ */
+static u32 clock_get_osc_bits(void)
+{
+	return (read32(CLK_RST_REG(osc_ctrl)) & OSC_FREQ_MASK) >> OSC_FREQ_SHIFT;
+}
+
+int clock_get_osc_khz(void)
+{
+	return osc_table[clock_get_osc_bits()].khz;
+}
+
+int clock_get_pll_input_khz(void)
+{
+	u32 osc_ctrl = read32(CLK_RST_REG(osc_ctrl));
+	u32 osc_bits = (osc_ctrl & OSC_FREQ_MASK) >> OSC_FREQ_SHIFT;
+	u32 pll_ref_div = (osc_ctrl & OSC_PREDIV_MASK) >> OSC_PREDIV_SHIFT;
+	return osc_table[osc_bits].khz >> pll_ref_div;
+}
+
+void clock_init_arm_generic_timer(void)
+{
+	uint32_t freq = clock_get_osc_khz() * 1000;
+
+	// Record the system timer frequency.
+	write32(&sysctr->cntfid0, freq);
+	// Enable the system counter.
+	uint32_t cntcr = read32(&sysctr->cntcr);
+	cntcr |= SYSCTR_CNTCR_EN | SYSCTR_CNTCR_HDBG;
+	write32(&sysctr->cntcr, cntcr);
+}
+
+#define SOR0_CLK_SEL0			(1 << 14)
+#define SOR0_CLK_SEL1			(1 << 15)
+
+void sor_clock_stop(void)
+{
+	/* The Serial Output Resource clock has to be off
+	 * before we start the plldp. Learned the hard way.
+	 * FIXME: this has to be cleaned up a bit more.
+	 * Waiting on some new info from Nvidia.
+	 */
+	clrbits_le32(CLK_RST_REG(clk_src_sor), SOR0_CLK_SEL0 | SOR0_CLK_SEL1);
+}
+
+void sor_clock_start(void)
+{
+	/* uses PLLP, has a non-standard bit layout. */
+	setbits_le32(CLK_RST_REG(clk_src_sor), SOR0_CLK_SEL0);
+}
+
+static void init_pll(u32 index, u32 osc)
+{
+	assert(index <= PLL_MAX_INDEX);
+
+	struct pll_fields *pll = &osc_table[osc].plls[index];
+	const struct pll_reg_info *pll_reg = &pll_reg_table[index];
+
+	u32 dividers =  pll->n << pll_reg->n_shift |
+			pll->m << pll_reg->m_shift |
+			pll->p << pll_reg->p_shift;
+
+	/* Write dividers but BYPASS the PLL while we're messing with it. */
+	write32(pll_reg->base_reg, dividers | PLL_BASE_BYPASS);
+
+	/* Set Lock bit if needed. */
+	if (pll_reg->lock_enb_val)
+		setbits_le32(pll_reg->lock_enb_reg, pll_reg->lock_enb_val);
+
+	/* Set KCP/KVCO if needed. */
+	if (pll_reg->kcp_kvco_reg)
+		setbits_le32(pll_reg->kcp_kvco_reg,
+			     pll->kcp << pll_reg->kcp_shift |
+			     pll->kvco << pll_reg->kvco_shift);
+
+	/* Enable PLL and take it back out of BYPASS */
+	write32(pll_reg->base_reg, dividers | PLL_BASE_ENABLE);
+
+	/* Wait for lock ready */
+	if (pll_reg->lock_enb_val)
+		while (!(read32(pll_reg->pll_lock_reg) & pll_reg->pll_lock_val))
+			;
+}
+
+static void init_pllc(u32 osc)
+{
+	/* Clear PLLC reset */
+	clrbits_le32(CLK_RST_REG(pllc_misc), PLLC_MISC_RESET);
+
+	/* Clear PLLC IDDQ */
+	clrbits_le32(CLK_RST_REG(pllc_misc_1), PLLC_MISC_1_IDDQ);
+
+	/* Max out the AVP clock before everything else (need PLLC for that). */
+	init_pll(PLLC_INDEX, osc);
+
+	/* wait for pllc_lock (not the normal bit 27) */
+	while (!(read32(CLK_RST_REG(pllc_base)) & PLLC_BASE_LOCK))
+		;
+}
+
+static void init_pllu(u32 osc)
+{
+	/* Clear PLLU IDDQ */
+	clrbits_le32(CLK_RST_REG(pllu_misc), PLLU_MISC_IDDQ);
+
+	/* Wait 5 us */
+	udelay(5);
+
+	init_pll(PLLU_INDEX, osc);
+}
+
+static void init_utmip_pll(void)
+{
+	int khz = clock_get_pll_input_khz();
+
+	/* Shut off PLL crystal clock while we mess with it */
+	clrbits_le32(CLK_RST_REG(utmip_pll_cfg2), UTMIP_CFG2_PHY_XTAL_CLOCKEN);
+	udelay(1);
+
+	/* CFG0 */
+	u32 div_n = div_round_up(960000, khz);
+	write32(CLK_RST_REG(utmip_pll_cfg0), /* 960 MHz VCO */
+		1 << UTMIP_CFG0_PLL_MDIV_SHIFT |
+		div_n << UTMIP_CFG0_PLL_NDIV_SHIFT);
+
+	/* CFG1 */
+	u32 pllu_enb_ct = div_round_up(khz, 8000); /* pllu_enb_ct / 8 (1us) */
+	u32 phy_stb_ct = div_round_up(khz, 102);  /* phy_stb_ct / 256(2.5ms) */
+	write32(CLK_RST_REG(utmip_pll_cfg1),
+		pllu_enb_ct << UTMIP_CFG1_PLLU_ENABLE_DLY_COUNT_SHIFT |
+		UTMIP_CFG1_FORCE_PLLU_POWERDOWN_DISABLE |
+		UTMIP_CFG1_FORCE_PLL_ENABLE_POWERDOWN_DISABLE |
+		UTMIP_CFG1_FORCE_PLL_ACTIVE_POWERDOWN_DISABLE |
+		phy_stb_ct << UTMIP_CFG1_XTAL_FREQ_COUNT_SHIFT);
+
+	/* CFG2 */
+	u32 pllu_stb_ct = div_round_up(khz, 256); /* pllu_stb_ct / 256 (1ms) */
+	u32 phy_act_ct = div_round_up(khz, 3200); /* phy_act_ct / 16 (5us) */
+	write32(CLK_RST_REG(utmip_pll_cfg2),
+		phy_act_ct << UTMIP_CFG2_PLL_ACTIVE_DLY_COUNT_SHIFT |
+		pllu_stb_ct << UTMIP_CFG2_PLLU_STABLE_COUNT_SHIFT |
+		UTMIP_CFG2_FORCE_PD_SAMP_C_POWERDOWN_DISABLE |
+		UTMIP_CFG2_FORCE_PD_SAMP_B_POWERDOWN_DISABLE |
+		UTMIP_CFG2_FORCE_PD_SAMP_A_POWERDOWN_DISABLE);
+
+	setbits_le32(CLK_RST_REG(utmip_pll_cfg2), UTMIP_CFG2_PHY_XTAL_CLOCKEN);
+}
+
+/* Graphics just has to be different. There's a few more bits we
+ * need to set in here, but it makes sense just to restrict all the
+ * special bits to this one function.
+ */
+static void graphics_pll(void)
+{
+	int osc = clock_get_osc_bits();
+	u32 *cfg = CLK_RST_REG(plldp_ss_cfg);
+	/* the vendor code sets the dither bit (28)
+	 * an undocumented bit (24)
+	 * and clamp while we mess with it (22)
+	 * Dither is pretty important to display port
+	 * so we really do need to handle these bits.
+	 * I'm not willing to not clamp it, even if
+	 * it might "mostly work" with it not set,
+	 * I don't want to find out in a few months
+	 * that it is needed.
+	 */
+	u32 scfg = (1<<28) | (1<<24) | (1<<22);
+	write32(cfg, scfg);
+	init_pll(PLLDP_INDEX, osc);
+	/* leave dither and undoc bits set, release clamp */
+	scfg = (1<<28) | (1<<24);
+	write32(cfg, scfg);
+}
+
+/*
+ * Init PLLD clock source.
+ *
+ * @frequency: the requested plld frequency
+ *
+ * Return the plld frequency if success, otherwise return 0.
+ */
+u32 clock_configure_plld(u32 frequency)
+{
+	/**
+	 * plld (fo) = vco >> p, where 500MHz < vco < 1000MHz
+	 *           = (cf * n) >> p, where 1MHz < cf < 6MHz
+	 *           = ((ref / m) * n) >> p
+	 *
+	 * Iterate the possible values of p (3 bits, 2^7) to find out a minimum
+	 * safe vco, then find best (m, n). since m has only 5 bits, we can
+	 * iterate all possible values.  Note Tegra1xx supports 11 bits for n,
+	 * but our pll_fields has only 10 bits for n.
+	 *
+	 * Note values undershoot or overshoot target output frequency may not
+	 * work if the values are not in "safe" range by panel specification.
+	 */
+	struct pll_fields *plld;
+	u32 ref = clock_get_pll_input_khz() * 1000, m, n, p = 0;
+	u32 cf, vco, rounded_rate = frequency;
+	u32 diff, best_diff;
+	const u32 max_m = 1 << 8, max_n = 1 << 8, max_p = 1 << 3,
+		  mhz = 1000 * 1000, min_vco = 500 * mhz, max_vco = 1000 * mhz,
+		  min_cf = 1 * mhz, max_cf = 6 * mhz;
+	u32 osc = clock_get_osc_bits();
+
+	plld = &osc_table[osc].plls[PLLD_INDEX];
+
+	for (vco = frequency; vco < min_vco && p < max_p; p++)
+		vco <<= 1;
+
+	if (vco < min_vco || vco > max_vco) {
+		printk(BIOS_ERR, "%s: Cannot find out a supported VCO"
+			" for Frequency (%u).\n", __func__, frequency);
+		return 0;
+	}
+
+	plld->p = p;
+	best_diff = vco;
+
+	for (m = 1; m < max_m && best_diff; m++) {
+		cf = ref / m;
+		if (cf < min_cf)
+			break;
+		if (cf > max_cf)
+			continue;
+
+		n = vco / cf;
+		if (n >= max_n)
+			continue;
+
+		diff = vco - n * cf;
+		if (n + 1 < max_n && diff > cf / 2) {
+			n++;
+			diff = cf - diff;
+		}
+
+		if (diff >= best_diff)
+			continue;
+
+		best_diff = diff;
+		plld->m = m;
+		plld->n = n;
+	}
+
+	if (best_diff) {
+		printk(BIOS_WARNING, "%s: Failed to match output frequency %u, "
+		       "best difference is %u.\n", __func__, frequency,
+		       best_diff);
+		rounded_rate = (ref / plld->m * plld->n) >> plld->p;
+	}
+
+	printk(BIOS_DEBUG, "%s: PLLD=%u ref=%u, m/n/p=%u/%u/%u\n",
+	       __func__, rounded_rate, ref, plld->m, plld->n, plld->p);
+
+	/* Write misc1 and misc */
+	write32(CLK_RST_REG(plld_misc1), PLLD_MISC1_SETUP);
+	write32(CLK_RST_REG(plld_misc), (PLLD_MISC_EN_SDM | PLLD_MISC_SDM_DIN));
+
+	/* configure PLLD */
+	init_pll(PLLD_INDEX, osc);
+
+	if (rounded_rate != frequency)
+		printk(BIOS_DEBUG, "PLLD rate: %u vs %u\n", rounded_rate,
+			frequency);
+
+	return rounded_rate;
+}
+
+/*
+ * Initialize the UART and use PLLP as clock source. PLLP is hardwired to 408
+ * MHz in HW (unless we set BASE_OVRD). We override the 16.0 UART divider with
+ * the 15.1 CLK_SOURCE divider to get more precision. The 1843(KHZ) is
+ * calculated thru BAUD_RATE*16/1000, ie, 115200*16/1000.
+ */
+void clock_early_uart(void)
+{
+	write32(CLK_RST_REG(clk_src_uarta),
+		CLK_SRC_DEV_ID(UARTA, PLLP) << CLK_SOURCE_SHIFT |
+		CLK_UART_DIV_OVERRIDE |
+		CLK_DIVIDER(TEGRA_PLLP_KHZ, 1843));
+
+	clock_enable_clear_reset_l(CLK_L_UARTA);
+}
+
+/* Enable output clock (CLK1~3) for external peripherals. */
+void clock_external_output(int clk_id)
+{
+	switch (clk_id) {
+	case 1:
+		setbits_le32(&pmc->clk_out_cntrl, 1 << 2);
+		break;
+	case 2:
+		setbits_le32(&pmc->clk_out_cntrl, 1 << 10);
+		break;
+	case 3:
+		setbits_le32(&pmc->clk_out_cntrl, 1 << 18);
+		break;
+	default:
+		printk(BIOS_CRIT, "ERROR: Unknown output clock id %d\n",
+		       clk_id);
+		break;
+	}
+}
+
+/* Start PLLM for SDRAM. */
+void clock_sdram(u32 m, u32 n, u32 p, u32 setup, u32 kvco, u32 kcp,
+		 u32 stable_time, u32 emc_source, u32 same_freq)
+{
+	u32 misc1 = ((setup << PLLM_MISC1_SETUP_SHIFT)),
+	    misc2 = ((kvco << PLLM_MISC2_KVCO_SHIFT) |
+		     (kcp << PLLM_MISC2_KCP_SHIFT) |
+		     PLLM_EN_LCKDET),
+	    base;
+
+	if (same_freq)
+		emc_source |= CLK_SOURCE_EMC_MC_EMC_SAME_FREQ;
+	else
+		emc_source &= ~CLK_SOURCE_EMC_MC_EMC_SAME_FREQ;
+
+	/*
+	 * Note PLLM_BASE.PLLM_OUT1_RSTN must be in RESET_ENABLE mode, and
+	 * PLLM_BASE.ENABLE must be in DISABLE state (both are the default
+	 * values after coldboot reset).
+	 */
+
+	write32(CLK_RST_REG(pllm_misc1), misc1);
+	write32(CLK_RST_REG(pllm_misc2), misc2);
+
+	/* PLLM.BASE needs BYPASS=0, different from general init_pll */
+	base = read32(CLK_RST_REG(pllm_base));
+	base &= ~(PLLCMX_BASE_DIVN_MASK | PLLCMX_BASE_DIVM_MASK |
+		  PLLM_BASE_DIVP_MASK | PLL_BASE_BYPASS);
+	base |= ((m << PLL_BASE_DIVM_SHIFT) | (n << PLL_BASE_DIVN_SHIFT) |
+		 (p << PLL_BASE_DIVP_SHIFT));
+	write32(CLK_RST_REG(pllm_base), base);
+
+	setbits_le32(CLK_RST_REG(pllm_base), PLL_BASE_ENABLE);
+	/* stable_time is required, before we can start to check lock. */
+	udelay(stable_time);
+
+	while (!(read32(CLK_RST_REG(pllm_base)) & PLL_BASE_LOCK))
+		udelay(1);
+
+	/*
+	 * After PLLM reports being locked, we have to delay 10us before
+	 * enabling PLLM_OUT.
+	 */
+	udelay(10);
+
+	/* Enable and start MEM(MC) and EMC. */
+	clock_enable_clear_reset(0, CLK_H_MEM | CLK_H_EMC, 0, 0, 0, 0, 0);
+	write32(CLK_RST_REG(clk_src_emc), emc_source);
+	udelay(IO_STABILIZATION_DELAY);
+}
+
+void clock_halt_avp(void)
+{
+	for (;;) {
+		write32(&flow->halt_cop_events,
+			FLOW_EVENT_JTAG | FLOW_EVENT_LIC_IRQ |
+			FLOW_EVENT_GIC_IRQ | FLOW_MODE_WAITEVENT);
+	}
+}
+
+void clock_init(void)
+{
+	u32 osc = clock_get_osc_bits();
+
+	init_pllc(osc);
+
+	/* Typical ratios are 1:2:2 or 1:2:3 sclk:hclk:pclk (See: APB DMA
+	 * features section in the TRM). */
+	write32(CLK_RST_REG(clk_sys_rate),	/* pclk = hclk = sclk/2 */
+		1 << HCLK_DIVISOR_SHIFT | 0 << PCLK_DIVISOR_SHIFT);
+	write32(CLK_RST_REG(pllc_out),
+		CLK_DIVIDER(TEGRA_PLLC_KHZ, 300000) << PLL_OUT_RATIO_SHIFT |
+		PLL_OUT_CLKEN | PLL_OUT_RSTN);
+	write32(CLK_RST_REG(sclk_brst_pol),		/* sclk = 300 MHz */
+		SCLK_SYS_STATE_RUN << SCLK_SYS_STATE_SHIFT |
+		SCLK_SOURCE_PLLC_OUT1 << SCLK_RUN_SHIFT);
+
+	/* Change the oscillator drive strength (from U-Boot -- why?) */
+	clrsetbits_le32(CLK_RST_REG(osc_ctrl), OSC_XOFS_MASK,
+			OSC_DRIVE_STRENGTH << OSC_XOFS_SHIFT);
+
+	/*
+	 * Ambiguous quote from u-boot. TODO: what's this mean?
+	 * "should update same value in PMC_OSC_EDPD_OVER XOFS
+	 * field for warmboot "
+	 */
+	clrsetbits_le32(&pmc->osc_edpd_over, PMC_OSC_EDPD_OVER_XOFS_MASK,
+			OSC_DRIVE_STRENGTH << PMC_OSC_EDPD_OVER_XOFS_SHIFT);
+
+	/* Disable IDDQ for PLLX before we set it up (from U-Boot -- why?) */
+	clrbits_le32(CLK_RST_REG(pllx_misc3), PLLX_IDDQ_MASK);
+
+	/* Set up PLLP_OUT(1|2|3|4) divisor to generate (9.6|48|102|204)MHz */
+	write32(CLK_RST_REG(pllp_outa),
+		(CLK_DIVIDER(TEGRA_PLLP_KHZ, 9600) << PLL_OUT_RATIO_SHIFT |
+		PLL_OUT_OVR | PLL_OUT_CLKEN | PLL_OUT_RSTN) << PLL_OUT1_SHIFT |
+		(CLK_DIVIDER(TEGRA_PLLP_KHZ, 48000) << PLL_OUT_RATIO_SHIFT |
+		PLL_OUT_OVR | PLL_OUT_CLKEN | PLL_OUT_RSTN) << PLL_OUT2_SHIFT);
+	write32(CLK_RST_REG(pllp_outb),
+		(CLK_DIVIDER(TEGRA_PLLP_KHZ, TEGRA_PLLP_OUT3_KHZ) <<
+			PLL_OUT_RATIO_SHIFT |
+		PLL_OUT_OVR | PLL_OUT_CLKEN | PLL_OUT_RSTN) << PLL_OUT3_SHIFT |
+		(CLK_DIVIDER(TEGRA_PLLP_KHZ, 204000) << PLL_OUT_RATIO_SHIFT |
+		PLL_OUT_OVR | PLL_OUT_CLKEN | PLL_OUT_RSTN) << PLL_OUT4_SHIFT);
+
+	/* init pllx */
+	init_pll(PLLX_INDEX, osc);
+	write32(CLK_RST_REG(cclk_brst_pol), CCLK_BURST_POLICY_VAL);
+
+	/* init pllu */
+	init_pllu(osc);
+
+	init_utmip_pll();
+	graphics_pll();
+}
+
+void clock_grp_enable_clear_reset(u32 val, u32* clk_enb_set_reg,
+				  u32 *rst_dev_clr_reg)
+{
+	write32(clk_enb_set_reg, val);
+	udelay(IO_STABILIZATION_DELAY);
+	write32(rst_dev_clr_reg, val);
+}
+
+static u32 * const clk_enb_set_arr[DEV_CONFIG_BLOCKS] = {
+	CLK_RST_REG(clk_enb_l_set),
+	CLK_RST_REG(clk_enb_h_set),
+	CLK_RST_REG(clk_enb_u_set),
+	CLK_RST_REG(clk_enb_v_set),
+	CLK_RST_REG(clk_enb_w_set),
+	CLK_RST_REG(clk_enb_x_set),
+	CLK_RST_REG(clk_enb_y_set),
+};
+
+static u32 * const clk_enb_clr_arr[DEV_CONFIG_BLOCKS] = {
+	CLK_RST_REG(clk_enb_l_clr),
+	CLK_RST_REG(clk_enb_h_clr),
+	CLK_RST_REG(clk_enb_u_clr),
+	CLK_RST_REG(clk_enb_v_clr),
+	CLK_RST_REG(clk_enb_w_clr),
+	CLK_RST_REG(clk_enb_x_clr),
+	CLK_RST_REG(clk_enb_y_clr),
+};
+
+static u32 * const rst_dev_set_arr[DEV_CONFIG_BLOCKS] = {
+	CLK_RST_REG(rst_dev_l_set),
+	CLK_RST_REG(rst_dev_h_set),
+	CLK_RST_REG(rst_dev_u_set),
+	CLK_RST_REG(rst_dev_v_set),
+	CLK_RST_REG(rst_dev_w_set),
+	CLK_RST_REG(rst_dev_x_set),
+	CLK_RST_REG(rst_dev_y_set),
+};
+
+static u32 * const rst_dev_clr_arr[DEV_CONFIG_BLOCKS] = {
+	CLK_RST_REG(rst_dev_l_clr),
+	CLK_RST_REG(rst_dev_h_clr),
+	CLK_RST_REG(rst_dev_u_clr),
+	CLK_RST_REG(rst_dev_v_clr),
+	CLK_RST_REG(rst_dev_w_clr),
+	CLK_RST_REG(rst_dev_x_clr),
+	CLK_RST_REG(rst_dev_y_clr),
+};
+
+static void clock_write_regs(u32 * const regs[DEV_CONFIG_BLOCKS],
+			     u32 bits[DEV_CONFIG_BLOCKS])
+{
+	int i = 0;
+
+	for (; i < DEV_CONFIG_BLOCKS; i++)
+		if (bits[i])
+			write32(regs[i], bits[i]);
+}
+
+void clock_enable_regs(u32 bits[DEV_CONFIG_BLOCKS])
+{
+	clock_write_regs(clk_enb_set_arr, bits);
+}
+
+void clock_disable_regs(u32 bits[DEV_CONFIG_BLOCKS])
+{
+	clock_write_regs(clk_enb_clr_arr, bits);
+}
+
+void clock_set_reset_regs(u32 bits[DEV_CONFIG_BLOCKS])
+{
+	clock_write_regs(rst_dev_set_arr, bits);
+}
+
+void clock_clr_reset_regs(u32 bits[DEV_CONFIG_BLOCKS])
+{
+	clock_write_regs(rst_dev_clr_arr, bits);
+}
+
+void clock_enable_clear_reset(u32 l, u32 h, u32 u, u32 v, u32 w, u32 x, u32 y)
+{
+	clock_enable(l, h, u, v, w, x, y);
+
+	/* Give clocks time to stabilize. */
+	udelay(IO_STABILIZATION_DELAY);
+
+	clock_clr_reset(l, h, u, v, w, x, y);
+}
+
+static void clock_reset_dev(u32 *setaddr, u32 *clraddr, u32 bit)
+{
+	write32(setaddr, bit);
+	udelay(LOGIC_STABILIZATION_DELAY);
+	write32(clraddr, bit);
+}
+
+void clock_reset_l(u32 bit)
+{
+	clock_reset_dev(CLK_RST_REG(rst_dev_l_set), CLK_RST_REG(rst_dev_l_clr),
+			bit);
+}
+
+void clock_reset_h(u32 bit)
+{
+	clock_reset_dev(CLK_RST_REG(rst_dev_h_set), CLK_RST_REG(rst_dev_h_clr),
+			bit);
+}
+
+void clock_reset_u(u32 bit)
+{
+	clock_reset_dev(CLK_RST_REG(rst_dev_u_set), CLK_RST_REG(rst_dev_u_clr),
+			bit);
+}
+
+void clock_reset_v(u32 bit)
+{
+	clock_reset_dev(CLK_RST_REG(rst_dev_v_set), CLK_RST_REG(rst_dev_v_clr),
+			bit);
+}
+
+void clock_reset_w(u32 bit)
+{
+	clock_reset_dev(CLK_RST_REG(rst_dev_w_set), CLK_RST_REG(rst_dev_w_clr),
+			bit);
+}
+
+void clock_reset_x(u32 bit)
+{
+	clock_reset_dev(CLK_RST_REG(rst_dev_x_set), CLK_RST_REG(rst_dev_x_clr),
+			bit);
+}
+
+void clock_reset_y(u32 bit)
+{
+	clock_reset_dev(CLK_RST_REG(rst_dev_y_set), CLK_RST_REG(rst_dev_y_clr),
+			bit);
+}
+
+/* Enable/unreset all audio toys under AHUB */
+void clock_enable_audio(void)
+{
+	/*
+	 * As per NVIDIA hardware team, we need to take ALL audio devices
+	 * connected to AHUB (AHUB, APB2APE, I2S, SPDIF, etc.) out of reset
+	 * and clock-enabled, otherwise reading AHUB devices (in our case,
+	 * I2S/APBIF/AUDIO<XBAR>) will hang.
+	 */
+	clock_enable_clear_reset(CLK_L_I2S1 | CLK_L_I2S2 | CLK_L_I2S3 | CLK_L_SPDIF,
+				 0, 0,
+				 CLK_V_I2S4 | CLK_V_I2S5 | CLK_V_AHUB | CLK_V_APB2APE,
+				 0, 0, 0);
+}
diff --git a/src/soc/nvidia/tegra210/cpu.c b/src/soc/nvidia/tegra210/cpu.c
new file mode 100644
index 0000000..6e51a8c
--- /dev/null
+++ b/src/soc/nvidia/tegra210/cpu.c
@@ -0,0 +1,79 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright 2014 Google Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc.
+ */
+
+#include <arch/io.h>
+#include <assert.h>
+#include <console/console.h>
+#include <soc/addressmap.h>
+#include <soc/clk_rst.h>
+#include <soc/cpu.h>
+#include <soc/secure_boot.h>
+
+static void enable_core_clocks(int cpu)
+{
+	const uint32_t cpu_clocks[CONFIG_MAX_CPUS] = {
+		[0] = CRC_RST_CPUG_CLR_CPU0 | CRC_RST_CPUG_CLR_DBG0 |
+		CRC_RST_CPUG_CLR_CORE0 | CRC_RST_CPUG_CLR_CX0,
+		[1] = CRC_RST_CPUG_CLR_CPU1 | CRC_RST_CPUG_CLR_DBG1 |
+		CRC_RST_CPUG_CLR_CORE1 | CRC_RST_CPUG_CLR_CX1,
+		[2] = CRC_RST_CPUG_CLR_CPU2 | CRC_RST_CPUG_CLR_DBG2 |
+		CRC_RST_CPUG_CLR_CORE2 | CRC_RST_CPUG_CLR_CX2,
+		[3] = CRC_RST_CPUG_CLR_CPU3 | CRC_RST_CPUG_CLR_DBG3 |
+		CRC_RST_CPUG_CLR_CORE3 | CRC_RST_CPUG_CLR_CX3,
+	};
+
+	assert (cpu < CONFIG_MAX_CPUS);
+
+	/* Clear reset of CPU components. */
+	write32(CLK_RST_REG(rst_cpug_cmplx_clr), cpu_clocks[cpu]);
+}
+
+void cpu_prepare_startup(void *entry_64)
+{
+	struct tegra_secure_boot *sb =
+		(struct tegra_secure_boot *)TEGRA_SB_BASE;
+
+	/*
+	 * T210 TRM, section 12.4.4.2: "SB_AA64_RESET_LOW_0[0:0] is used to
+	 * decide between CPU boot up in AARCH32 (=0) or AARCH64 (=1) mode.
+	 * This bit .. is sampled only during 'cold reset of CPU'. Before the
+	 * CPU is powered up, the CPU reset vector is loaded in
+	 * EVP_CPU_REST_VECTOR_0 for 32-bit boot mode .... However, the CPU
+	 * decides to boot in 32-/64-bit mode based on
+	 * SB_AA64_RESET_LOW_0[0:0]. If this bit is set (=1), the CPU boots in
+	 * 64-bit mode using SB_AA64_RESET_* as the reset address. If this bit
+	 * is clear (=0), CPU boots in 32-bit mode using EVP_CPU_RESET_VECTOR."
+	 */
+
+	write32(&sb->sb_aa64_reset_low, (uintptr_t)entry_64);
+	setbits_le32(&sb->sb_aa64_reset_low, 1);
+	write32(&sb->sb_aa64_reset_high, 0);
+}
+
+void start_cpu_silent(int cpu, void *entry_64)
+{
+	cpu_prepare_startup(entry_64);
+	enable_core_clocks(cpu);
+}
+
+void start_cpu(int cpu, void *entry_64)
+{
+	printk(BIOS_DEBUG, "Starting CPU%d @ %p.\n", cpu, entry_64);
+	start_cpu_silent(cpu, entry_64);
+}
diff --git a/src/soc/nvidia/tegra210/cpu_lib.S b/src/soc/nvidia/tegra210/cpu_lib.S
new file mode 100644
index 0000000..abfffb1
--- /dev/null
+++ b/src/soc/nvidia/tegra210/cpu_lib.S
@@ -0,0 +1,27 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright 2014 Google Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc.
+ */
+
+
+.text
+.global smp_processor_id
+smp_processor_id:
+	/* Core 0 and 1 are encoded in the Aff0 (7:0) field of MPIDR_EL1. */
+	mrs	x0, mpidr_el1
+	uxtb	w0, w0
+	ret
diff --git a/src/soc/nvidia/tegra210/dc.c b/src/soc/nvidia/tegra210/dc.c
new file mode 100644
index 0000000..f3beece
--- /dev/null
+++ b/src/soc/nvidia/tegra210/dc.c
@@ -0,0 +1,249 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright 2014 Google Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc.
+ */
+#include <console/console.h>
+#include <arch/io.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <edid.h>
+#include <device/device.h>
+#include <soc/nvidia/tegra/dc.h>
+#include "chip.h"
+#include <soc/display.h>
+
+int dump = 0;
+unsigned long READL(void * p)
+{
+        unsigned long value;
+
+	/*
+	 * In case of hard hung on readl(p), we can set dump > 1 to print out
+	 * the address accessed.
+	 */
+        if (dump > 1)
+		printk(BIOS_SPEW, "readl %p\n", p);
+
+        value = read32(p);
+        if (dump)
+		printk(BIOS_SPEW, "readl %p %08lx\n", p, value);
+        return value;
+}
+
+void WRITEL(unsigned long value, void * p)
+{
+        if (dump)
+		printk(BIOS_SPEW, "writel %p %08lx\n", p, value);
+        write32(p, value);
+}
+
+/* return in 1000ths of a Hertz */
+static int tegra_calc_refresh(const struct soc_nvidia_tegra210_config *config)
+{
+	int refresh;
+	int h_total = htotal(config);
+	int v_total = vtotal(config);
+	int pclk = config->pixel_clock;
+
+	if (!pclk || !h_total || !v_total)
+		return 0;
+	refresh = pclk / h_total;
+	refresh *= 1000;
+	refresh /= v_total;
+	return refresh;
+}
+
+static void print_mode(const struct soc_nvidia_tegra210_config *config)
+{
+	if (config) {
+		int refresh = tegra_calc_refresh(config);
+		printk(BIOS_ERR,
+			"Panel Mode: %dx%d@%d.%03uHz pclk=%d\n",
+			config->xres, config->yres,
+			refresh / 1000, refresh % 1000,
+			config->pixel_clock);
+	}
+}
+
+int update_display_mode(struct display_controller *disp_ctrl,
+			       struct soc_nvidia_tegra210_config *config)
+{
+	print_mode(config);
+
+	printk(BIOS_ERR, "config:      xres:yres: %d x %d\n ",
+			config->xres, config->yres);
+	printk(BIOS_ERR, "   href_sync:vref_sync: %d x %d\n ",
+			config->href_to_sync, config->vref_to_sync);
+	printk(BIOS_ERR, " hsyn_width:vsyn_width: %d x %d\n ",
+			config->hsync_width, config->vsync_width);
+	printk(BIOS_ERR, " hfnt_porch:vfnt_porch: %d x %d\n ",
+			config->hfront_porch, config->vfront_porch);
+	printk(BIOS_ERR, "   hbk_porch:vbk_porch: %d x %d\n ",
+			config->hback_porch, config->vback_porch);
+
+	WRITEL(0x0, &disp_ctrl->disp.disp_timing_opt);
+	WRITEL(0x0, &disp_ctrl->disp.disp_color_ctrl);
+
+	/* select win opt */
+	WRITEL(config->win_opt, &disp_ctrl->disp.disp_win_opt);
+
+	WRITEL(config->vref_to_sync << 16 | config->href_to_sync,
+		&disp_ctrl->disp.ref_to_sync);
+
+	WRITEL(config->vsync_width << 16 | config->hsync_width,
+		&disp_ctrl->disp.sync_width);
+
+
+	WRITEL((config->vback_porch << 16) | config->hback_porch,
+		&disp_ctrl->disp.back_porch);
+
+	WRITEL((config->vfront_porch << 16) | config->hfront_porch,
+		&disp_ctrl->disp.front_porch);
+
+	WRITEL(config->xres | (config->yres << 16),
+		&disp_ctrl->disp.disp_active);
+
+	/*
+	 *   PixelClock = (PLLD / 2) / ShiftClockDiv / PixelClockDiv.
+	 *
+	 *   default: Set both shift_clk_div and pixel_clock_div to 1
+	 */
+	update_display_shift_clock_divider(disp_ctrl, SHIFT_CLK_DIVIDER(1));
+
+	return 0;
+}
+
+void update_display_shift_clock_divider(struct display_controller *disp_ctrl,
+			       u32 shift_clock_div)
+{
+	WRITEL((PIXEL_CLK_DIVIDER_PCD1 << PIXEL_CLK_DIVIDER_SHIFT) |
+	       (shift_clock_div & 0xff) << SHIFT_CLK_DIVIDER_SHIFT,
+	       &disp_ctrl->disp.disp_clk_ctrl);
+	printk(BIOS_DEBUG, "%s: ShiftClockDiv=%u\n",
+	       __func__, shift_clock_div);
+}
+
+/*
+ * update_window:
+ *   set up window registers and activate window except two:
+ *   frame buffer base address register (WINBUF_START_ADDR) and
+ *   display enable register (_DISP_DISP_WIN_OPTIONS). This is
+ *   becasue framebuffer is not available until payload stage.
+ */
+void update_window(const struct soc_nvidia_tegra210_config *config)
+{
+	struct display_controller *disp_ctrl =
+			(void *)config->display_controller;
+	u32 val;
+
+	WRITEL(WINDOW_A_SELECT, &disp_ctrl->cmd.disp_win_header);
+
+	WRITEL(((config->yres << 16) | config->xres), &disp_ctrl->win.size);
+
+	WRITEL(((config->display_yres << 16) |
+		(config->display_xres *
+		config->framebuffer_bits_per_pixel / 8)),
+		&disp_ctrl->win.prescaled_size);
+
+	val = ALIGN_UP((config->display_xres *
+		config->framebuffer_bits_per_pixel / 8), 64);
+	WRITEL(val, &disp_ctrl->win.line_stride);
+
+	WRITEL(config->color_depth, &disp_ctrl->win.color_depth);
+	WRITEL(COLOR_BLACK, &disp_ctrl->disp.blend_background_color);
+
+	WRITEL(((DDA_INC(config->display_yres, config->yres) << 16) |
+		DDA_INC(config->display_xres, config->xres)),
+		&disp_ctrl->win.dda_increment);
+
+	WRITEL(DISP_CTRL_MODE_C_DISPLAY, &disp_ctrl->cmd.disp_cmd);
+
+	WRITEL(WRITE_MUX_ACTIVE, &disp_ctrl->cmd.state_access);
+
+	WRITEL(0, &disp_ctrl->win.buffer_addr_mode);
+
+	val = PW0_ENABLE | PW1_ENABLE | PW2_ENABLE | PW3_ENABLE |
+		PW4_ENABLE | PM0_ENABLE | PM1_ENABLE;
+	WRITEL(val, &disp_ctrl->cmd.disp_pow_ctrl);
+
+	val = GENERAL_UPDATE | WIN_A_UPDATE;
+	WRITEL(val, &disp_ctrl->cmd.state_ctrl);
+
+	val = GENERAL_ACT_REQ | WIN_A_ACT_REQ;
+	WRITEL(val, &disp_ctrl->cmd.state_ctrl);
+}
+
+int tegra_dc_init(struct display_controller *disp_ctrl)
+{
+	/* do not accept interrupts during initialization */
+	WRITEL(0x00000000, &disp_ctrl->cmd.int_mask);
+	WRITEL(WRITE_MUX_ASSEMBLY | READ_MUX_ASSEMBLY,
+		&disp_ctrl->cmd.state_access);
+	WRITEL(WINDOW_A_SELECT, &disp_ctrl->cmd.disp_win_header);
+	WRITEL(0x00000000, &disp_ctrl->win.win_opt);
+	WRITEL(0x00000000, &disp_ctrl->win.byte_swap);
+	WRITEL(0x00000000, &disp_ctrl->win.buffer_ctrl);
+
+	WRITEL(0x00000000, &disp_ctrl->win.pos);
+	WRITEL(0x00000000, &disp_ctrl->win.h_initial_dda);
+	WRITEL(0x00000000, &disp_ctrl->win.v_initial_dda);
+	WRITEL(0x00000000, &disp_ctrl->win.dda_increment);
+	WRITEL(0x00000000, &disp_ctrl->win.dv_ctrl);
+
+	WRITEL(0x01000000, &disp_ctrl->win.blend_layer_ctrl);
+	WRITEL(0x00000000, &disp_ctrl->win.blend_match_select);
+	WRITEL(0x00000000, &disp_ctrl->win.blend_nomatch_select);
+	WRITEL(0x00000000, &disp_ctrl->win.blend_alpha_1bit);
+
+	WRITEL(0x00000000, &disp_ctrl->winbuf.start_addr_hi);
+	WRITEL(0x00000000, &disp_ctrl->winbuf.addr_h_offset);
+	WRITEL(0x00000000, &disp_ctrl->winbuf.addr_v_offset);
+
+	WRITEL(0x00000000, &disp_ctrl->com.crc_checksum);
+	WRITEL(0x00000000, &disp_ctrl->com.pin_output_enb[0]);
+	WRITEL(0x00000000, &disp_ctrl->com.pin_output_enb[1]);
+	WRITEL(0x00000000, &disp_ctrl->com.pin_output_enb[2]);
+	WRITEL(0x00000000, &disp_ctrl->com.pin_output_enb[3]);
+	WRITEL(0x00000000, &disp_ctrl->disp.disp_signal_opt0);
+
+	return 0;
+}
+
+/*
+ * Save mode to cb tables
+ */
+void pass_mode_info_to_payload(
+			struct soc_nvidia_tegra210_config *config)
+{
+	struct edid edid;
+	/* Align bytes_per_line to 64 bytes as required by dc */
+	edid.bytes_per_line = ALIGN_UP((config->display_xres *
+				config->framebuffer_bits_per_pixel / 8), 64);
+	edid.x_resolution = edid.bytes_per_line /
+				(config->framebuffer_bits_per_pixel / 8);
+	edid.y_resolution = config->display_yres;
+	edid.framebuffer_bits_per_pixel = config->framebuffer_bits_per_pixel;
+
+	printk(BIOS_INFO, "%s: bytes_per_line: %d, bits_per_pixel: %d\n "
+			"               x_res x y_res: %d x %d, size: %d\n",
+			 __func__, edid.bytes_per_line,
+			edid.framebuffer_bits_per_pixel,
+			edid.x_resolution, edid.y_resolution,
+			(edid.bytes_per_line * edid.y_resolution));
+
+	set_vbe_mode_info_valid(&edid, 0);
+}
diff --git a/src/soc/nvidia/tegra210/dma.c b/src/soc/nvidia/tegra210/dma.c
new file mode 100644
index 0000000..9f04e97
--- /dev/null
+++ b/src/soc/nvidia/tegra210/dma.c
@@ -0,0 +1,147 @@
+/*
+ * (C) Copyright 2010,2011
+ * NVIDIA Corporation <www.nvidia.com>
+ * Copyright 2014 Google Inc.
+ *
+ * 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 <arch/io.h>
+#include <console/console.h>
+#include <inttypes.h>
+#include <soc/addressmap.h>
+#include <soc/dma.h>
+#include <stddef.h>
+#include <stdlib.h>
+
+struct apb_dma * const apb_dma = (struct apb_dma *)TEGRA_APB_DMA_BASE;
+
+#define APB_DMA_OFFSET(n) \
+		(struct apb_dma_channel_regs *)(TEGRA_APB_DMA_BASE + n)
+struct apb_dma_channel apb_dma_channels[] = {
+	{ .num = 0, .regs = APB_DMA_OFFSET(0x1000) },
+	{ .num = 1, .regs = APB_DMA_OFFSET(0x1040) },
+	{ .num = 2, .regs = APB_DMA_OFFSET(0x1080) },
+	{ .num = 3, .regs = APB_DMA_OFFSET(0x10c0) },
+	{ .num = 4, .regs = APB_DMA_OFFSET(0x1100) },
+	{ .num = 5, .regs = APB_DMA_OFFSET(0x1140) },
+	{ .num = 6, .regs = APB_DMA_OFFSET(0x1180) },
+	{ .num = 7, .regs = APB_DMA_OFFSET(0x11c0) },
+	{ .num = 8, .regs = APB_DMA_OFFSET(0x1200) },
+	{ .num = 9, .regs = APB_DMA_OFFSET(0x1240) },
+	{ .num = 10, .regs = APB_DMA_OFFSET(0x1280) },
+	{ .num = 11, .regs = APB_DMA_OFFSET(0x12c0) },
+	{ .num = 12, .regs = APB_DMA_OFFSET(0x1300) },
+	{ .num = 13, .regs = APB_DMA_OFFSET(0x1340) },
+	{ .num = 14, .regs = APB_DMA_OFFSET(0x1380) },
+	{ .num = 15, .regs = APB_DMA_OFFSET(0x13c0) },
+	{ .num = 16, .regs = APB_DMA_OFFSET(0x1400) },
+	{ .num = 17, .regs = APB_DMA_OFFSET(0x1440) },
+	{ .num = 18, .regs = APB_DMA_OFFSET(0x1480) },
+	{ .num = 19, .regs = APB_DMA_OFFSET(0x14c0) },
+	{ .num = 20, .regs = APB_DMA_OFFSET(0x1500) },
+	{ .num = 21, .regs = APB_DMA_OFFSET(0x1540) },
+	{ .num = 22, .regs = APB_DMA_OFFSET(0x1580) },
+	{ .num = 23, .regs = APB_DMA_OFFSET(0x15c0) },
+	{ .num = 24, .regs = APB_DMA_OFFSET(0x1600) },
+	{ .num = 25, .regs = APB_DMA_OFFSET(0x1640) },
+	{ .num = 26, .regs = APB_DMA_OFFSET(0x1680) },
+	{ .num = 27, .regs = APB_DMA_OFFSET(0x16c0) },
+	{ .num = 28, .regs = APB_DMA_OFFSET(0x1700) },
+	{ .num = 29, .regs = APB_DMA_OFFSET(0x1740) },
+	{ .num = 30, .regs = APB_DMA_OFFSET(0x1780) },
+	{ .num = 31, .regs = APB_DMA_OFFSET(0x17c0) },
+};
+
+int dma_busy(struct apb_dma_channel * const channel)
+{
+	/*
+	 * In continuous mode, the BSY_n bit in APB_DMA_STATUS and
+	 * BSY in APBDMACHAN_CHANNEL_n_STA_0 will remain set as '1' so long
+	 * as the channel is enabled. So for this function we'll use the
+	 * DMA_ACTIVITY bit.
+	 */
+	return read32(&channel->regs->sta) & APB_STA_DMA_ACTIVITY ? 1 : 0;
+}
+/* claim a DMA channel */
+struct apb_dma_channel * const dma_claim(void)
+{
+	int i;
+	struct apb_dma_channel_regs *regs = NULL;
+
+	/*
+	 * Set global enable bit, otherwise register access to channel
+	 * DMA registers will not be possible.
+	 */
+	setbits_le32(&apb_dma->command, APB_COMMAND_GEN);
+
+	for (i = 0; i < ARRAY_SIZE(apb_dma_channels); i++) {
+		regs = apb_dma_channels[i].regs;
+
+		if (!apb_dma_channels[i].in_use) {
+			u32 status = read32(&regs->sta);
+			if (status & (1 << i)) {
+				/* FIXME: should this be fatal? */
+				printk(BIOS_DEBUG, "%s: DMA channel %d busy?\n",
+						__func__, i);
+			}
+			break;
+		}
+	}
+
+	if (i == ARRAY_SIZE(apb_dma_channels))
+		return NULL;
+
+	apb_dma_channels[i].in_use = 1;
+	return &apb_dma_channels[i];
+}
+
+/* release a DMA channel */
+void dma_release(struct apb_dma_channel * const channel)
+{
+	int i;
+
+	/* FIXME: make this "thread" friendly */
+	while (dma_busy(channel))
+		;
+
+	channel->in_use = 0;
+
+	/* clear the global enable bit if no channels are in use */
+	for (i = 0; i < ARRAY_SIZE(apb_dma_channels); i++) {
+		if (apb_dma_channels[i].in_use)
+			return;
+	}
+
+	clrbits_le32(&apb_dma->command, APB_COMMAND_GEN);
+}
+
+int dma_start(struct apb_dma_channel * const channel)
+{
+	struct apb_dma_channel_regs *regs = channel->regs;
+
+	/* Set ENB bit for this channel */
+	setbits_le32(&regs->csr, APB_CSR_ENB);
+
+	return 0;
+}
+
+int dma_stop(struct apb_dma_channel * const channel)
+{
+	struct apb_dma_channel_regs *regs = channel->regs;
+
+	/* Clear ENB bit for this channel */
+	clrbits_le32(&regs->csr, APB_CSR_ENB);
+
+	return 0;
+}
diff --git a/src/soc/nvidia/tegra210/dp.c b/src/soc/nvidia/tegra210/dp.c
new file mode 100644
index 0000000..ea6dbca
--- /dev/null
+++ b/src/soc/nvidia/tegra210/dp.c
@@ -0,0 +1,1663 @@
+/*
+ * drivers/video/tegra/dc/dp.c
+ *
+ * Copyright (c) 2011-2015, NVIDIA Corporation.
+ * Copyright 2014 Google Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+#include <arch/io.h>
+#include <console/console.h>
+#include <device/device.h>
+#include <device/i2c.h>
+#include <edid.h>
+#include <stdlib.h>
+#include <string.h>
+#include <delay.h>
+#include <soc/addressmap.h>
+#include <soc/clock.h>
+#include <soc/display.h>
+#include <soc/nvidia/tegra/i2c.h>
+#include <soc/nvidia/tegra/dc.h>
+#include <soc/nvidia/tegra/types.h>
+#include <soc/nvidia/tegra/pwm.h>
+#include <soc/nvidia/tegra/displayport.h>
+#include <soc/sor.h>
+#include "chip.h"
+
+#define DO_FAST_LINK_TRAINING	0
+
+struct tegra_dc dc_data;
+
+enum {
+	DP_LT_SUCCESS = 0,
+	DP_LT_FAILED = -1,
+};
+
+struct tegra_dc_dp_data dp_data;
+
+static inline u32 tegra_dpaux_readl(struct tegra_dc_dp_data *dp, u32 reg)
+{
+	void *addr = dp->aux_base + (u32) (reg << 2);
+	u32 reg_val = READL(addr);
+	return reg_val;
+}
+
+static inline void tegra_dpaux_writel(struct tegra_dc_dp_data *dp,
+					  u32 reg, u32 val)
+{
+	void *addr = dp->aux_base + (u32) (reg << 2);
+	WRITEL(val, addr);
+}
+
+static inline u32 tegra_dc_dpaux_poll_register(struct tegra_dc_dp_data *dp,
+					   u32 reg, u32 mask, u32 exp_val,
+					   u32 poll_interval_us,
+					   u32 timeout_us)
+{
+	u32 reg_val = 0;
+	u32 temp = timeout_us;
+
+	do {
+		udelay(poll_interval_us);
+		reg_val = tegra_dpaux_readl(dp, reg);
+		if (timeout_us > poll_interval_us)
+			timeout_us -= poll_interval_us;
+		else
+			break;
+	} while ((reg_val & mask) != exp_val);
+
+	if ((reg_val & mask) == exp_val)
+		return 0;	/* success */
+	printk(BIOS_ERR,
+		   "dpaux_poll_register 0x%x: timeout: "
+		   "(reg_val)0x%08x & (mask)0x%08x != (exp_val)0x%08x\n",
+		   reg, reg_val, mask, exp_val);
+	return temp;
+}
+
+static inline int tegra_dpaux_wait_transaction(struct tegra_dc_dp_data *dp)
+{
+	/* According to DP spec, each aux transaction needs to finish
+	   within 40ms. */
+	if (tegra_dc_dpaux_poll_register(dp, DPAUX_DP_AUXCTL,
+					 DPAUX_DP_AUXCTL_TRANSACTREQ_MASK,
+					 DPAUX_DP_AUXCTL_TRANSACTREQ_DONE,
+					 100, DP_AUX_TIMEOUT_MS * 1000) != 0) {
+		printk(BIOS_INFO, "dp: DPAUX transaction timeout\n");
+		return -1;
+	}
+	return 0;
+}
+
+static int tegra_dc_dpaux_write_chunk(struct tegra_dc_dp_data *dp, u32 cmd,
+					  u32 addr, u8 *data, u32 *size,
+					  u32 *aux_stat)
+{
+	int i;
+	u32 reg_val;
+	u32 timeout_retries = DP_AUX_TIMEOUT_MAX_TRIES;
+	u32 defer_retries = DP_AUX_DEFER_MAX_TRIES;
+	u32 temp_data;
+
+	if (*size > DP_AUX_MAX_BYTES)
+		return -1;	/* only write one chunk of data */
+
+	/* Make sure the command is write command */
+	switch (cmd) {
+	case DPAUX_DP_AUXCTL_CMD_I2CWR:
+	case DPAUX_DP_AUXCTL_CMD_MOTWR:
+	case DPAUX_DP_AUXCTL_CMD_AUXWR:
+		break;
+	default:
+		printk(BIOS_ERR, "dp: aux write cmd 0x%x is invalid\n",	cmd);
+		return -1;
+	}
+
+	tegra_dpaux_writel(dp, DPAUX_DP_AUXADDR, addr);
+	for (i = 0; i < DP_AUX_MAX_BYTES / 4; ++i) {
+		memcpy(&temp_data, data, 4);
+		tegra_dpaux_writel(dp, DPAUX_DP_AUXDATA_WRITE_W(i), temp_data);
+		data += 4;
+	}
+
+	reg_val = tegra_dpaux_readl(dp, DPAUX_DP_AUXCTL);
+	reg_val &= ~DPAUX_DP_AUXCTL_CMD_MASK;
+	reg_val |= cmd;
+	reg_val &= ~DPAUX_DP_AUXCTL_CMDLEN_FIELD;
+	reg_val |= ((*size - 1) << DPAUX_DP_AUXCTL_CMDLEN_SHIFT);
+
+	while ((timeout_retries > 0) && (defer_retries > 0)) {
+		if ((timeout_retries != DP_AUX_TIMEOUT_MAX_TRIES) ||
+			(defer_retries != DP_AUX_DEFER_MAX_TRIES))
+			udelay(1);
+
+		reg_val |= DPAUX_DP_AUXCTL_TRANSACTREQ_PENDING;
+		tegra_dpaux_writel(dp, DPAUX_DP_AUXCTL, reg_val);
+
+		if (tegra_dpaux_wait_transaction(dp))
+			printk(BIOS_ERR, "dp: aux write transaction timeout\n");
+
+		*aux_stat = tegra_dpaux_readl(dp, DPAUX_DP_AUXSTAT);
+
+		if ((*aux_stat & DPAUX_DP_AUXSTAT_TIMEOUT_ERROR_PENDING) ||
+			(*aux_stat & DPAUX_DP_AUXSTAT_RX_ERROR_PENDING) ||
+			(*aux_stat & DPAUX_DP_AUXSTAT_SINKSTAT_ERROR_PENDING) ||
+			(*aux_stat & DPAUX_DP_AUXSTAT_NO_STOP_ERROR_PENDING)) {
+			if (timeout_retries-- > 0) {
+				printk(BIOS_INFO, "dp: aux write retry (0x%x)"
+					" -- %d\n",
+					*aux_stat, timeout_retries);
+				/* clear the error bits */
+				tegra_dpaux_writel(dp, DPAUX_DP_AUXSTAT,
+					*aux_stat);
+				continue;
+			} else {
+				printk(BIOS_ERR, "dp: aux write got error"
+					" (0x%x)\n", *aux_stat);
+				return -1;
+			}
+		}
+
+		if ((*aux_stat & DPAUX_DP_AUXSTAT_REPLYTYPE_I2CDEFER) ||
+			(*aux_stat & DPAUX_DP_AUXSTAT_REPLYTYPE_DEFER)) {
+			if (defer_retries-- > 0) {
+				printk(BIOS_INFO, "dp: aux write defer (0x%x)"
+					" -- %d\n", *aux_stat, defer_retries);
+				/* clear the error bits */
+				tegra_dpaux_writel(dp, DPAUX_DP_AUXSTAT,
+						*aux_stat);
+				continue;
+			} else {
+				printk(BIOS_ERR, "dp: aux write defer exceeds"
+					" max retries (0x%x)\n", *aux_stat);
+				return -1;
+			}
+		}
+
+		if ((*aux_stat & DPAUX_DP_AUXSTAT_REPLYTYPE_MASK) ==
+			DPAUX_DP_AUXSTAT_REPLYTYPE_ACK) {
+			*size = ((*aux_stat) & DPAUX_DP_AUXSTAT_REPLY_M_MASK);
+			return 0;
+		} else {
+			printk(BIOS_ERR, "dp: aux write failed (0x%x)\n",
+				*aux_stat);
+			return -1;
+		}
+	}
+	/* Should never come to here */
+	return -1;
+}
+
+static int tegra_dc_dpaux_read_chunk(struct tegra_dc_dp_data *dp, u32 cmd,
+					 u32 addr, u8 *data, u32 *size,
+					 u32 *aux_stat)
+{
+	u32 reg_val;
+	u32 timeout_retries = DP_AUX_TIMEOUT_MAX_TRIES;
+	u32 defer_retries = DP_AUX_DEFER_MAX_TRIES;
+
+	if (*size > DP_AUX_MAX_BYTES)
+		return -1;	/* only read one chunk */
+
+	/* Check to make sure the command is read command */
+	switch (cmd) {
+	case DPAUX_DP_AUXCTL_CMD_I2CRD:
+	case DPAUX_DP_AUXCTL_CMD_I2CREQWSTAT:
+	case DPAUX_DP_AUXCTL_CMD_MOTRD:
+	case DPAUX_DP_AUXCTL_CMD_AUXRD:
+		break;
+	default:
+		printk(BIOS_ERR, "dp: aux read cmd 0x%x is invalid\n", cmd);
+		return -1;
+	}
+
+	*aux_stat = tegra_dpaux_readl(dp, DPAUX_DP_AUXSTAT);
+	if (!(*aux_stat & DPAUX_DP_AUXSTAT_HPD_STATUS_PLUGGED)) {
+		printk(BIOS_SPEW, "dp: HPD is not detected\n");
+		return -1;
+	}
+
+	tegra_dpaux_writel(dp, DPAUX_DP_AUXADDR, addr);
+
+	reg_val = tegra_dpaux_readl(dp, DPAUX_DP_AUXCTL);
+	reg_val &= ~DPAUX_DP_AUXCTL_CMD_MASK;
+	reg_val |= cmd;
+	reg_val &= ~DPAUX_DP_AUXCTL_CMDLEN_FIELD;
+	reg_val |= ((*size - 1) << DPAUX_DP_AUXCTL_CMDLEN_SHIFT);
+	while ((timeout_retries > 0) && (defer_retries > 0)) {
+		if ((timeout_retries != DP_AUX_TIMEOUT_MAX_TRIES) ||
+			(defer_retries != DP_AUX_DEFER_MAX_TRIES))
+			udelay(DP_DPCP_RETRY_SLEEP_NS * 2);
+
+		reg_val |= DPAUX_DP_AUXCTL_TRANSACTREQ_PENDING;
+		tegra_dpaux_writel(dp, DPAUX_DP_AUXCTL, reg_val);
+
+		if (tegra_dpaux_wait_transaction(dp))
+			printk(BIOS_INFO, "dp: aux read transaction timeout\n");
+
+		*aux_stat = tegra_dpaux_readl(dp, DPAUX_DP_AUXSTAT);
+
+		if ((*aux_stat & DPAUX_DP_AUXSTAT_TIMEOUT_ERROR_PENDING) ||
+			(*aux_stat & DPAUX_DP_AUXSTAT_RX_ERROR_PENDING) ||
+			(*aux_stat & DPAUX_DP_AUXSTAT_SINKSTAT_ERROR_PENDING) ||
+			(*aux_stat & DPAUX_DP_AUXSTAT_NO_STOP_ERROR_PENDING)) {
+			if (timeout_retries-- > 0) {
+				printk(BIOS_INFO, "dp: aux read retry (0x%x)"
+						" -- %d\n", *aux_stat,
+						timeout_retries);
+				/* clear the error bits */
+				tegra_dpaux_writel(dp, DPAUX_DP_AUXSTAT,
+						*aux_stat);
+				continue;	/* retry */
+			} else {
+				printk(BIOS_ERR, "dp: aux read got error"
+						" (0x%x)\n", *aux_stat);
+				return -1;
+			}
+		}
+
+		if ((*aux_stat & DPAUX_DP_AUXSTAT_REPLYTYPE_I2CDEFER) ||
+			(*aux_stat & DPAUX_DP_AUXSTAT_REPLYTYPE_DEFER)) {
+			if (defer_retries-- > 0) {
+				printk(BIOS_INFO, "dp: aux read defer (0x%x)"
+					" -- %d\n", *aux_stat, defer_retries);
+				/* clear the error bits */
+				tegra_dpaux_writel(dp, DPAUX_DP_AUXSTAT,
+						*aux_stat);
+				continue;
+			} else {
+				printk(BIOS_INFO, "dp: aux read defer exceeds"
+					" max retries (0x%x)\n", *aux_stat);
+				return -1;
+			}
+		}
+
+		if ((*aux_stat & DPAUX_DP_AUXSTAT_REPLYTYPE_MASK) ==
+			DPAUX_DP_AUXSTAT_REPLYTYPE_ACK) {
+			int i;
+			u32 temp_data[4];
+
+			for (i = 0; i < DP_AUX_MAX_BYTES / 4; ++i)
+				temp_data[i] = tegra_dpaux_readl(dp,
+						DPAUX_DP_AUXDATA_READ_W(i));
+
+			*size = ((*aux_stat) & DPAUX_DP_AUXSTAT_REPLY_M_MASK);
+			memcpy(data, temp_data, *size);
+
+			return 0;
+		} else {
+			printk(BIOS_ERR, "dp: aux read failed (0x%x\n",
+					*aux_stat);
+			return -1;
+		}
+	}
+	/* Should never come to here */
+	printk(BIOS_ERR, "%s: can't\n", __func__);
+	return -1;
+}
+
+#if DO_FAST_LINK_TRAINING
+static int tegra_dc_dpaux_read(struct tegra_dc_dp_data *dp, u32 cmd, u32 addr,
+			u8 *data, u32 *size, u32 *aux_stat)
+{
+	u32 finished = 0;
+	u32 cur_size;
+	int ret = 0;
+
+	do {
+		cur_size = *size - finished;
+		if (cur_size > DP_AUX_MAX_BYTES)
+			cur_size = DP_AUX_MAX_BYTES;
+
+		ret = tegra_dc_dpaux_read_chunk(dp, cmd, addr,
+						data, &cur_size, aux_stat);
+		if (ret)
+			break;
+
+		/* cur_size should be the real size returned */
+		addr += cur_size;
+		data += cur_size;
+		finished += cur_size;
+
+	} while (*size > finished);
+
+	*size = finished;
+	return ret;
+}
+#endif /* DO_FAST_LINK_TRAINING */
+
+static int tegra_dc_dp_dpcd_read(struct tegra_dc_dp_data *dp, u32 cmd,
+				 u8 *data_ptr)
+{
+	u32 size = 1;
+	u32 status = 0;
+	int ret;
+
+	ret = tegra_dc_dpaux_read_chunk(dp, DPAUX_DP_AUXCTL_CMD_AUXRD,
+					cmd, data_ptr, &size, &status);
+	if (ret)
+		printk(BIOS_ERR,
+			"dp: Failed to read DPCD data. CMD 0x%x, Status 0x%x\n",
+			cmd, status);
+
+	return ret;
+}
+
+static int tegra_dc_dp_dpcd_write(struct tegra_dc_dp_data *dp, u32 cmd,
+				u8 data)
+{
+	u32 size = 1;
+	u32 status = 0;
+	int ret;
+
+	ret = tegra_dc_dpaux_write_chunk(dp, DPAUX_DP_AUXCTL_CMD_AUXWR,
+					cmd, &data, &size, &status);
+	if (ret)
+		printk(BIOS_ERR,
+		       "dp: Failed to write DPCD data. CMD 0x%x, Status 0x%x\n",
+		       cmd, status);
+	return ret;
+}
+
+static int tegra_dc_i2c_aux_read(struct tegra_dc_dp_data *dp, u32 i2c_addr,
+				 u8 addr, u8 *data, u32 *size, u32 *aux_stat)
+{
+	u32 finished = 0;
+	int ret = 0;
+
+	do {
+		u32 cur_size = MIN(DP_AUX_MAX_BYTES, *size - finished);
+
+		u32 len = 1;
+		ret = tegra_dc_dpaux_write_chunk(
+				dp, DPAUX_DP_AUXCTL_CMD_MOTWR, i2c_addr,
+				&addr, &len, aux_stat);
+		if (ret) {
+			printk(BIOS_ERR, "%s: error sending address to read.\n",
+			       __func__);
+			break;
+		}
+
+		ret = tegra_dc_dpaux_read_chunk(
+				dp, DPAUX_DP_AUXCTL_CMD_I2CRD, i2c_addr,
+				data, &cur_size, aux_stat);
+		if (ret) {
+			printk(BIOS_ERR, "%s: error reading data.\n", __func__);
+			break;
+		}
+
+		/* cur_size should be the real size returned */
+		addr += cur_size;
+		data += cur_size;
+		finished += cur_size;
+	} while (*size > finished);
+
+	*size = finished;
+	return ret;
+}
+
+static void tegra_dc_dpaux_enable(struct tegra_dc_dp_data *dp)
+{
+	/* clear interrupt */
+	tegra_dpaux_writel(dp, DPAUX_INTR_AUX, 0xffffffff);
+	/* do not enable interrupt for now. Enable them when Isr in place */
+	tegra_dpaux_writel(dp, DPAUX_INTR_EN_AUX, 0x0);
+
+	tegra_dpaux_writel(dp, DPAUX_HYBRID_PADCTL,
+		DPAUX_HYBRID_PADCTL_AUX_DRVZ_OHM_50 |
+		DPAUX_HYBRID_PADCTL_AUX_CMH_V0_70 |
+		0x18 << DPAUX_HYBRID_PADCTL_AUX_DRVI_SHIFT |
+		DPAUX_HYBRID_PADCTL_AUX_INPUT_RCV_ENABLE);
+
+	tegra_dpaux_writel(dp, DPAUX_HYBRID_SPARE,
+			DPAUX_HYBRID_SPARE_PAD_PWR_POWERUP);
+}
+
+static void tegra_dc_dp_dump_link_cfg(struct tegra_dc_dp_data *dp,
+	const struct tegra_dc_dp_link_config *link_cfg)
+{
+	printk(BIOS_INFO, "DP config: cfg_name               "
+		"cfg_value\n");
+	printk(BIOS_INFO, "           Lane Count             %d\n",
+		link_cfg->max_lane_count);
+	printk(BIOS_INFO, "           SupportEnhancedFraming %s\n",
+		link_cfg->support_enhanced_framing ? "Y" : "N");
+	printk(BIOS_INFO, "           Bandwidth              %d\n",
+		link_cfg->max_link_bw);
+	printk(BIOS_INFO, "           bpp                    %d\n",
+		link_cfg->bits_per_pixel);
+	printk(BIOS_INFO, "           EnhancedFraming        %s\n",
+		link_cfg->enhanced_framing ? "Y" : "N");
+	printk(BIOS_INFO, "           Scramble_enabled       %s\n",
+		link_cfg->scramble_ena ? "Y" : "N");
+	printk(BIOS_INFO, "           LinkBW                 %d\n",
+		link_cfg->link_bw);
+	printk(BIOS_INFO, "           lane_count             %d\n",
+		link_cfg->lane_count);
+	printk(BIOS_INFO, "           activespolarity        %d\n",
+		link_cfg->activepolarity);
+	printk(BIOS_INFO, "           active_count           %d\n",
+		link_cfg->active_count);
+	printk(BIOS_INFO, "           tu_size                %d\n",
+		link_cfg->tu_size);
+	printk(BIOS_INFO, "           active_frac            %d\n",
+		link_cfg->active_frac);
+	printk(BIOS_INFO, "           watermark              %d\n",
+		link_cfg->watermark);
+	printk(BIOS_INFO, "           hblank_sym             %d\n",
+		link_cfg->hblank_sym);
+	printk(BIOS_INFO, "           vblank_sym             %d\n",
+		link_cfg->vblank_sym);
+}
+
+static int _tegra_dp_lower_link_config(struct tegra_dc_dp_data *dp,
+	struct tegra_dc_dp_link_config *link_cfg)
+{
+
+	switch (link_cfg->link_bw) {
+	case SOR_LINK_SPEED_G1_62:
+		if (link_cfg->max_link_bw > SOR_LINK_SPEED_G1_62)
+			link_cfg->link_bw = SOR_LINK_SPEED_G2_7;
+		link_cfg->lane_count /= 2;
+		break;
+	case SOR_LINK_SPEED_G2_7:
+		link_cfg->link_bw = SOR_LINK_SPEED_G1_62;
+		break;
+	case SOR_LINK_SPEED_G5_4:
+		if (link_cfg->lane_count == 1) {
+			link_cfg->link_bw = SOR_LINK_SPEED_G2_7;
+			link_cfg->lane_count = link_cfg->max_lane_count;
+		} else
+			link_cfg->lane_count /= 2;
+		break;
+	default:
+		printk(BIOS_ERR, "dp: Error link rate %d\n", link_cfg->link_bw);
+		return DP_LT_FAILED;
+	}
+
+	return (link_cfg->lane_count > 0) ? DP_LT_SUCCESS : DP_LT_FAILED;
+}
+
+/* Calcuate if given cfg can meet the mode request. */
+/* Return true if mode is possible, false otherwise. */
+static int tegra_dc_dp_calc_config(struct tegra_dc_dp_data *dp,
+	const struct soc_nvidia_tegra210_config *config,
+	struct tegra_dc_dp_link_config *link_cfg)
+{
+	const u32	link_rate = 27 * link_cfg->link_bw * 1000 * 1000;
+	const u64	f	  = 100000;	/* precision factor */
+
+	u32	num_linkclk_line; /* Number of link clocks per line */
+	u64	ratio_f; /* Ratio of incoming to outgoing data rate */
+
+	u64	frac_f;
+	u64	activesym_f;	/* Activesym per TU */
+	u64	activecount_f;
+	u32	activecount;
+	u32	activepolarity;
+	u64	approx_value_f;
+	u32	activefrac		  = 0;
+	u64	accumulated_error_f	  = 0;
+	u32	lowest_neg_activecount	  = 0;
+	u32	lowest_neg_activepolarity = 0;
+	u32	lowest_neg_tusize	  = 64;
+	u32	num_symbols_per_line;
+	u64	lowest_neg_activefrac	  = 0;
+	u64	lowest_neg_error_f	  = 64 * f;
+	u64	watermark_f;
+
+	int	i;
+	int	neg;
+
+	printk(BIOS_INFO, "dp: %s\n", __func__);
+
+	if (!link_rate || !link_cfg->lane_count || !config->pixel_clock ||
+		!link_cfg->bits_per_pixel)
+		return -1;
+
+	if ((u64)config->pixel_clock * link_cfg->bits_per_pixel >=
+		(u64)link_rate * 8 * link_cfg->lane_count)
+		return -1;
+
+	num_linkclk_line = (u32)((u64)link_rate * (u64)config->xres /
+				config->pixel_clock);
+
+	ratio_f = (u64)config->pixel_clock * link_cfg->bits_per_pixel * f;
+	ratio_f /= 8;
+	ratio_f = (u64)(ratio_f / (link_rate * link_cfg->lane_count));
+
+	for (i = 64; i >= 32; --i) {
+		activesym_f	= ratio_f * i;
+		activecount_f	= (u64)(activesym_f / (u32)f) * f;
+		frac_f		= activesym_f - activecount_f;
+		activecount	= (u32)((u64)(activecount_f / (u32)f));
+
+		if (frac_f < (f / 2)) /* fraction < 0.5 */
+			activepolarity = 0;
+		else {
+			activepolarity = 1;
+			frac_f = f - frac_f;
+		}
+
+		if (frac_f != 0) {
+			frac_f = (u64)((f * f) / frac_f); /* 1/fraction */
+			if (frac_f > (15 * f))
+				activefrac = activepolarity ? 1 : 15;
+			else
+				activefrac = activepolarity ?
+					(u32)((u64)(frac_f / (u32)f)) + 1 :
+					(u32)((u64)(frac_f / (u32)f));
+		}
+
+		if (activefrac == 1)
+			activepolarity = 0;
+
+		if (activepolarity == 1)
+			approx_value_f = activefrac ? (u64)(
+				(activecount_f + (activefrac * f - f) * f) /
+				(activefrac * f)) :
+				activecount_f + f;
+		else
+			approx_value_f = activefrac ?
+				activecount_f + (u64)(f / activefrac) :
+				activecount_f;
+
+		if (activesym_f < approx_value_f) {
+			accumulated_error_f = num_linkclk_line *
+				(u64)((approx_value_f - activesym_f) / i);
+			neg = 1;
+		} else {
+			accumulated_error_f = num_linkclk_line *
+				(u64)((activesym_f - approx_value_f) / i);
+			neg = 0;
+		}
+
+		if ((neg && (lowest_neg_error_f > accumulated_error_f)) ||
+			(accumulated_error_f == 0)) {
+			lowest_neg_error_f = accumulated_error_f;
+			lowest_neg_tusize = i;
+			lowest_neg_activecount = activecount;
+			lowest_neg_activepolarity = activepolarity;
+			lowest_neg_activefrac = activefrac;
+
+			if (accumulated_error_f == 0)
+				break;
+		}
+	}
+
+	if (lowest_neg_activefrac == 0) {
+		link_cfg->activepolarity = 0;
+		link_cfg->active_count   = lowest_neg_activepolarity ?
+			lowest_neg_activecount : lowest_neg_activecount - 1;
+		link_cfg->tu_size	      = lowest_neg_tusize;
+		link_cfg->active_frac    = 1;
+	} else {
+		link_cfg->activepolarity = lowest_neg_activepolarity;
+		link_cfg->active_count   = (u32)lowest_neg_activecount;
+		link_cfg->tu_size	      = lowest_neg_tusize;
+		link_cfg->active_frac    = (u32)lowest_neg_activefrac;
+	}
+
+	watermark_f = (u64)((ratio_f * link_cfg->tu_size * (f - ratio_f)) / f);
+	link_cfg->watermark = (u32)((u64)((watermark_f + lowest_neg_error_f) /
+		f)) + link_cfg->bits_per_pixel / 4 - 1;
+	num_symbols_per_line = (config->xres * link_cfg->bits_per_pixel) /
+		(8 * link_cfg->lane_count);
+
+	if (link_cfg->watermark > 30) {
+		printk(BIOS_INFO,
+			"dp: sor setting: unable to get a good tusize, "
+			"force watermark to 30.\n");
+		link_cfg->watermark = 30;
+		return -1;
+	} else if (link_cfg->watermark > num_symbols_per_line) {
+		printk(BIOS_INFO,
+			"dp: sor setting: force watermark to the number "
+			"of symbols in the line.\n");
+		link_cfg->watermark = num_symbols_per_line;
+		return -1;
+	}
+
+	/* Refer to dev_disp.ref for more information. */
+	/* # symbols/hblank = ((SetRasterBlankEnd.X + SetRasterSize.Width - */
+	/*                      SetRasterBlankStart.X - 7) * link_clk / pclk) */
+	/*                      - 3 * enhanced_framing - Y */
+	/* where Y = (# lanes == 4) 3 : (# lanes == 2) ? 6 : 12 */
+	link_cfg->hblank_sym = (int)((u64)(((u64)(config->hback_porch +
+			config->hfront_porch + config->hsync_width - 7) *
+			link_rate) / config->pixel_clock)) -
+			3 * link_cfg->enhanced_framing -
+			(12 / link_cfg->lane_count);
+
+	if (link_cfg->hblank_sym < 0)
+		link_cfg->hblank_sym = 0;
+
+
+	/* Refer to dev_disp.ref for more information. */
+	/* # symbols/vblank = ((SetRasterBlankStart.X - */
+	/*                      SetRasterBlankEen.X - 25) * link_clk / pclk) */
+	/*                      - Y - 1; */
+	/* where Y = (# lanes == 4) 12 : (# lanes == 2) ? 21 : 39 */
+	link_cfg->vblank_sym = (int)((u64)((u64)(config->xres - 25)
+			* link_rate / config->pixel_clock)) - (36 /
+			link_cfg->lane_count) - 4;
+
+	if (link_cfg->vblank_sym < 0)
+		link_cfg->vblank_sym = 0;
+
+	link_cfg->is_valid = 1;
+	tegra_dc_dp_dump_link_cfg(dp, link_cfg);
+
+	return 0;
+}
+
+static int tegra_dc_dp_init_max_link_cfg(
+			struct soc_nvidia_tegra210_config *config,
+			struct tegra_dc_dp_data *dp,
+			struct tegra_dc_dp_link_config *link_cfg)
+{
+	u8 dpcd_data;
+	int ret;
+
+	printk(BIOS_INFO, "dp: %s\n", __func__);
+
+	CHECK_RET(tegra_dc_dp_dpcd_read(dp, NV_DPCD_MAX_LANE_COUNT,
+			&dpcd_data));
+	link_cfg->max_lane_count = dpcd_data & NV_DPCD_MAX_LANE_COUNT_MASK;
+	link_cfg->tps3_supported = (dpcd_data &
+		NV_DPCD_MAX_LANE_COUNT_TPS3_SUPPORTED_YES) ? 1 : 0;
+
+	link_cfg->support_enhanced_framing =
+		(dpcd_data & NV_DPCD_MAX_LANE_COUNT_ENHANCED_FRAMING_YES) ?
+		1 : 0;
+
+	CHECK_RET(tegra_dc_dp_dpcd_read(dp, NV_DPCD_MAX_DOWNSPREAD,
+			&dpcd_data));
+	link_cfg->downspread = (dpcd_data & NV_DPCD_MAX_DOWNSPREAD_VAL_0_5_PCT)
+				? 1 : 0;
+
+	CHECK_RET(tegra_dc_dp_dpcd_read(dp, NV_DPCD_TRAINING_AUX_RD_INTERVAL,
+			&link_cfg->aux_rd_interval));
+
+	CHECK_RET(tegra_dc_dp_dpcd_read(dp, NV_DPCD_MAX_LINK_BANDWIDTH,
+			&link_cfg->max_link_bw));
+
+	link_cfg->bits_per_pixel = config->panel_bits_per_pixel;
+
+	/*
+	 * Set to a high value for link training and attach.
+	 * Will be re-programmed when dp is enabled.
+	 */
+	link_cfg->drive_current = config->dp.drive_current;
+	link_cfg->preemphasis = config->dp.preemphasis;
+	link_cfg->postcursor = config->dp.postcursor;
+
+	CHECK_RET(tegra_dc_dp_dpcd_read(dp, NV_DPCD_EDP_CONFIG_CAP,
+			&dpcd_data));
+	link_cfg->alt_scramber_reset_cap =
+		(dpcd_data & NV_DPCD_EDP_CONFIG_CAP_ASC_RESET_YES) ?
+		1 : 0;
+	link_cfg->only_enhanced_framing =
+		(dpcd_data & NV_DPCD_EDP_CONFIG_CAP_FRAMING_CHANGE_YES) ?
+		1 : 0;
+
+	link_cfg->lane_count = link_cfg->max_lane_count;
+	link_cfg->link_bw = link_cfg->max_link_bw;
+	link_cfg->enhanced_framing = link_cfg->support_enhanced_framing;
+
+	tegra_dc_dp_calc_config(dp, config, link_cfg);
+	return 0;
+}
+
+static int tegra_dc_dp_set_assr(struct tegra_dc_dp_data *dp, int ena)
+{
+	int ret;
+
+	u8 dpcd_data = ena ?
+		NV_DPCD_EDP_CONFIG_SET_ASC_RESET_ENABLE :
+		NV_DPCD_EDP_CONFIG_SET_ASC_RESET_DISABLE;
+
+	CHECK_RET(tegra_dc_dp_dpcd_write(dp, NV_DPCD_EDP_CONFIG_SET,
+			dpcd_data));
+
+	/* Also reset the scrambler to 0xfffe */
+	tegra_dc_sor_set_internal_panel(&dp->sor, ena);
+	return 0;
+}
+
+static int tegra_dp_set_link_bandwidth(struct tegra_dc_dp_data *dp, u8 link_bw)
+{
+	tegra_dc_sor_set_link_bandwidth(&dp->sor, link_bw);
+
+	/* Sink side */
+	return tegra_dc_dp_dpcd_write(dp, NV_DPCD_LINK_BANDWIDTH_SET, link_bw);
+}
+
+static int tegra_dp_set_lane_count(struct tegra_dc_dp_data *dp,
+	const struct tegra_dc_dp_link_config *link_cfg)
+{
+	u8	dpcd_data;
+	int	ret;
+
+	/* check if panel support enhanched_framing */
+	dpcd_data = link_cfg->lane_count;
+	if (link_cfg->enhanced_framing)
+		dpcd_data |= NV_DPCD_LANE_COUNT_SET_ENHANCEDFRAMING_T;
+	CHECK_RET(tegra_dc_dp_dpcd_write(dp, NV_DPCD_LANE_COUNT_SET,
+			dpcd_data));
+
+	tegra_dc_sor_set_lane_count(&dp->sor, link_cfg->lane_count);
+
+	/* Also power down lanes that will not be used */
+	return 0;
+}
+
+#if DO_FAST_LINK_TRAINING
+static int tegra_dc_dp_link_trained(struct tegra_dc_dp_data *dp,
+	const struct tegra_dc_dp_link_config *link_cfg)
+{
+	u32 lane;
+	u8 mask;
+	u8 data;
+	int ret;
+
+	for (lane = 0; lane < link_cfg->lane_count; ++lane) {
+		CHECK_RET(tegra_dc_dp_dpcd_read(dp, (lane/2) ?
+				NV_DPCD_LANE2_3_STATUS : NV_DPCD_LANE0_1_STATUS,
+				&data));
+		mask = (lane & 1) ?
+			NV_DPCD_STATUS_LANEXPLUS1_CR_DONE_YES |
+			NV_DPCD_STATUS_LANEXPLUS1_CHN_EQ_DONE_YES |
+			NV_DPCD_STATUS_LANEXPLUS1_SYMBOL_LOCKED_YES :
+			NV_DPCD_STATUS_LANEX_CR_DONE_YES |
+			NV_DPCD_STATUS_LANEX_CHN_EQ_DONE_YES |
+			NV_DPCD_STATUS_LANEX_SYMBOL_LOCKED_YES;
+		if ((data & mask) != mask)
+			return -1;
+	}
+	return 0;
+}
+#endif /* DO_FAST_LINK_TRAINING */
+
+static int tegra_dp_channel_eq_status(struct tegra_dc_dp_data *dp)
+{
+	u32 cnt;
+	u32 n_lanes = dp->link_cfg.lane_count;
+	u8 data;
+	u8 ce_done = 1;
+
+	for (cnt = 0; cnt < n_lanes / 2; cnt++) {
+		tegra_dc_dp_dpcd_read(dp, (NV_DPCD_LANE0_1_STATUS + cnt),
+					&data);
+
+		if (n_lanes == 1) {
+			ce_done =
+			 (data & (0x1 << NV_DPCD_STATUS_LANEX_CHN_EQ_DONE_SHIFT)) &&
+			 (data & (0x1 << NV_DPCD_STATUS_LANEX_SYMBOL_LOCKED_SHFIT));
+			break;
+		} else
+		    if (!(data & (0x1 << NV_DPCD_STATUS_LANEX_CHN_EQ_DONE_SHIFT)) ||
+			!(data & (0x1 << NV_DPCD_STATUS_LANEX_SYMBOL_LOCKED_SHFIT)) ||
+			!(data & (0x1 << NV_DPCD_STATUS_LANEXPLUS1_CHN_EQ_DONE_SHIFT)) ||
+			!(data & (0x1 << NV_DPCD_STATUS_LANEXPLUS1_SYMBOL_LOCKED_SHIFT)))
+			return 0;
+	}
+
+	if (ce_done) {
+		tegra_dc_dp_dpcd_read(dp, NV_DPCD_LANE_ALIGN_STATUS_UPDATED,
+			&data);
+		if (!(data & NV_DPCD_LANE_ALIGN_STATUS_UPDATED_DONE_YES))
+			ce_done = 0;
+	}
+
+	return ce_done;
+}
+
+static u8 tegra_dp_clock_recovery_status(struct tegra_dc_dp_data *dp)
+{
+	u32 cnt;
+	u32 n_lanes = dp->link_cfg.lane_count;
+	u8 data_ptr;
+
+	for (cnt = 0; cnt < n_lanes / 2; cnt++) {
+		tegra_dc_dp_dpcd_read(dp,
+			(NV_DPCD_LANE0_1_STATUS + cnt), &data_ptr);
+
+		if (n_lanes == 1)
+			return (data_ptr & NV_DPCD_STATUS_LANEX_CR_DONE_YES) ? 1 : 0;
+		else if (!(data_ptr & NV_DPCD_STATUS_LANEX_CR_DONE_YES) ||
+			!(data_ptr & (NV_DPCD_STATUS_LANEXPLUS1_CR_DONE_YES)))
+			return 0;
+	}
+
+	return 1;
+}
+
+static void tegra_dp_lt_adjust(struct tegra_dc_dp_data *dp,
+				u32 pe[4], u32 vs[4], u32 pc[4],
+				u8 pc_supported)
+{
+	size_t cnt;
+	u8 data_ptr;
+	u32 n_lanes = dp->link_cfg.lane_count;
+
+	for (cnt = 0; cnt < n_lanes / 2; cnt++) {
+		tegra_dc_dp_dpcd_read(dp,
+			(NV_DPCD_LANE0_1_ADJUST_REQ + cnt), &data_ptr);
+		pe[2 * cnt] = (data_ptr & NV_DPCD_ADJUST_REQ_LANEX_PE_MASK) >>
+					NV_DPCD_ADJUST_REQ_LANEX_PE_SHIFT;
+		vs[2 * cnt] = (data_ptr & NV_DPCD_ADJUST_REQ_LANEX_DC_MASK) >>
+					NV_DPCD_ADJUST_REQ_LANEX_DC_SHIFT;
+		pe[1 + 2 * cnt] =
+			(data_ptr & NV_DPCD_ADJUST_REQ_LANEXPLUS1_PE_MASK) >>
+					NV_DPCD_ADJUST_REQ_LANEXPLUS1_PE_SHIFT;
+		vs[1 + 2 * cnt] =
+			(data_ptr & NV_DPCD_ADJUST_REQ_LANEXPLUS1_DC_MASK) >>
+					NV_DPCD_ADJUST_REQ_LANEXPLUS1_DC_SHIFT;
+	}
+	if (pc_supported) {
+		tegra_dc_dp_dpcd_read(dp,
+				NV_DPCD_ADJUST_REQ_POST_CURSOR2, &data_ptr);
+		for (cnt = 0; cnt < n_lanes; cnt++) {
+			pc[cnt] = (data_ptr >>
+			NV_DPCD_ADJUST_REQ_POST_CURSOR2_LANE_SHIFT(cnt)) &
+			NV_DPCD_ADJUST_REQ_POST_CURSOR2_LANE_MASK;
+		}
+	}
+}
+
+static inline u32 tegra_dp_wait_aux_training(struct tegra_dc_dp_data *dp,
+							u8 is_clk_recovery)
+{
+	if (!dp->link_cfg.aux_rd_interval)
+		is_clk_recovery ? udelay(200) :
+					udelay(500);
+	else
+		mdelay(dp->link_cfg.aux_rd_interval * 4);
+
+	return dp->link_cfg.aux_rd_interval;
+}
+
+static void tegra_dp_tpg(struct tegra_dc_dp_data *dp, u32 tp, u32 n_lanes)
+{
+	u8 data = (tp == training_pattern_disabled)
+		? (tp | NV_DPCD_TRAINING_PATTERN_SET_SC_DISABLED_F)
+		: (tp | NV_DPCD_TRAINING_PATTERN_SET_SC_DISABLED_T);
+
+	tegra_dc_sor_set_dp_linkctl(&dp->sor, 1, tp, &dp->link_cfg);
+	tegra_dc_dp_dpcd_write(dp, NV_DPCD_TRAINING_PATTERN_SET, data);
+}
+
+static int tegra_dp_link_config(struct tegra_dc_dp_data *dp,
+	const struct tegra_dc_dp_link_config *link_cfg)
+{
+	u8	dpcd_data;
+	u32	retry;
+
+	if (link_cfg->lane_count == 0) {
+		printk(BIOS_ERR, "dp: error: lane count is 0. "
+				"Can not set link config.\n");
+		return DP_LT_FAILED;
+	}
+
+	/* Set power state if it is not in normal level */
+	if (tegra_dc_dp_dpcd_read(dp, NV_DPCD_SET_POWER, &dpcd_data))
+		return DP_LT_FAILED;
+
+	if (dpcd_data == NV_DPCD_SET_POWER_VAL_D3_PWRDWN) {
+		dpcd_data = NV_DPCD_SET_POWER_VAL_D0_NORMAL;
+
+		/* DP spec requires 3 retries */
+		for (retry = 3; retry > 0; --retry) {
+			if (tegra_dc_dp_dpcd_write(dp, NV_DPCD_SET_POWER,
+				dpcd_data))
+				break;
+			if (retry == 1) {
+				printk(BIOS_ERR, "dp: Failed to set DP panel"
+					" power\n");
+				return DP_LT_FAILED;
+			}
+		}
+	}
+
+	/* Enable ASSR if possible */
+	if (link_cfg->alt_scramber_reset_cap)
+		if (tegra_dc_dp_set_assr(dp, 1))
+			return DP_LT_FAILED;
+
+	if (tegra_dp_set_link_bandwidth(dp, link_cfg->link_bw)) {
+		printk(BIOS_ERR, "dp: Failed to set link bandwidth\n");
+		return DP_LT_FAILED;
+	}
+	if (tegra_dp_set_lane_count(dp, link_cfg)) {
+		printk(BIOS_ERR, "dp: Failed to set lane count\n");
+		return DP_LT_FAILED;
+	}
+	tegra_dc_sor_set_dp_linkctl(&dp->sor, 1, training_pattern_none,
+					link_cfg);
+	return DP_LT_SUCCESS;
+}
+
+static int tegra_dp_lower_link_config(struct tegra_dc_dp_data *dp,
+	struct tegra_dc_dp_link_config *cfg)
+{
+	struct tegra_dc_dp_link_config tmp_cfg;
+
+	tmp_cfg = dp->link_cfg;
+	cfg->is_valid = 0;
+
+	if (_tegra_dp_lower_link_config(dp, cfg))
+		goto fail;
+
+	if (tegra_dc_dp_calc_config(dp, dp->dc->config, cfg))
+		goto fail;
+	tegra_dp_link_config(dp, cfg);
+
+	return DP_LT_SUCCESS;
+fail:
+	dp->link_cfg = tmp_cfg;
+	tegra_dp_link_config(dp, &tmp_cfg);
+	return DP_LT_FAILED;
+}
+
+static void tegra_dp_lt_config(struct tegra_dc_dp_data *dp,
+				u32 pe[4], u32 vs[4], u32 pc[4])
+{
+	struct tegra_dc_sor_data *sor = &dp->sor;
+	u32 n_lanes = dp->link_cfg.lane_count;
+	u8 pc_supported = dp->link_cfg.tps3_supported;
+	u32 cnt;
+	u32 val;
+
+	for (cnt = 0; cnt < n_lanes; cnt++) {
+		u32 mask = 0;
+		u32 pe_reg, vs_reg, pc_reg;
+		u32 shift = 0;
+
+		switch (cnt) {
+		case 0:
+			mask = NV_SOR_PR_LANE2_DP_LANE0_MASK;
+			shift = NV_SOR_PR_LANE2_DP_LANE0_SHIFT;
+			break;
+		case 1:
+			mask = NV_SOR_PR_LANE1_DP_LANE1_MASK;
+			shift = NV_SOR_PR_LANE1_DP_LANE1_SHIFT;
+			break;
+		case 2:
+			mask = NV_SOR_PR_LANE0_DP_LANE2_MASK;
+			shift = NV_SOR_PR_LANE0_DP_LANE2_SHIFT;
+			break;
+		case 3:
+			mask = NV_SOR_PR_LANE3_DP_LANE3_MASK;
+			shift = NV_SOR_PR_LANE3_DP_LANE3_SHIFT;
+			break;
+		default:
+			printk(BIOS_ERR,
+				"dp: incorrect lane cnt\n");
+		}
+
+		pe_reg = tegra_dp_pe_regs[pc[cnt]][vs[cnt]][pe[cnt]];
+		vs_reg = tegra_dp_vs_regs[pc[cnt]][vs[cnt]][pe[cnt]];
+		pc_reg = tegra_dp_pc_regs[pc[cnt]][vs[cnt]][pe[cnt]];
+
+		tegra_dp_set_pe_vs_pc(sor, mask, pe_reg << shift,
+				vs_reg << shift, pc_reg << shift, pc_supported);
+	}
+
+	tegra_dp_disable_tx_pu(&dp->sor);
+	udelay(20);
+
+	for (cnt = 0; cnt < n_lanes; cnt++) {
+		u32 max_vs_flag = tegra_dp_is_max_vs(pe[cnt], vs[cnt]);
+		u32 max_pe_flag = tegra_dp_is_max_pe(pe[cnt], vs[cnt]);
+
+		val = (vs[cnt] << NV_DPCD_TRAINING_LANEX_SET_DC_SHIFT) |
+			(max_vs_flag ?
+			NV_DPCD_TRAINING_LANEX_SET_DC_MAX_REACHED_T :
+			NV_DPCD_TRAINING_LANEX_SET_DC_MAX_REACHED_F) |
+			(pe[cnt] << NV_DPCD_TRAINING_LANEX_SET_PE_SHIFT) |
+			(max_pe_flag ?
+			NV_DPCD_TRAINING_LANEX_SET_PE_MAX_REACHED_T :
+			NV_DPCD_TRAINING_LANEX_SET_PE_MAX_REACHED_F);
+		tegra_dc_dp_dpcd_write(dp,
+			(NV_DPCD_TRAINING_LANE0_SET + cnt), val);
+	}
+
+	if (pc_supported) {
+		for (cnt = 0; cnt < n_lanes / 2; cnt++) {
+			u32 max_pc_flag0 = tegra_dp_is_max_pc(pc[cnt]);
+			u32 max_pc_flag1 = tegra_dp_is_max_pc(pc[cnt + 1]);
+			val = (pc[cnt] << NV_DPCD_LANEX_SET2_PC2_SHIFT) |
+				(max_pc_flag0 ?
+				NV_DPCD_LANEX_SET2_PC2_MAX_REACHED_T :
+				NV_DPCD_LANEX_SET2_PC2_MAX_REACHED_F) |
+				(pc[cnt + 1] <<
+				NV_DPCD_LANEXPLUS1_SET2_PC2_SHIFT) |
+				(max_pc_flag1 ?
+				NV_DPCD_LANEXPLUS1_SET2_PC2_MAX_REACHED_T :
+				NV_DPCD_LANEXPLUS1_SET2_PC2_MAX_REACHED_F);
+			tegra_dc_dp_dpcd_write(dp,
+				(NV_DPCD_TRAINING_LANE0_1_SET2 + cnt), val);
+		}
+	}
+}
+
+static int _tegra_dp_channel_eq(struct tegra_dc_dp_data *dp, u32 pe[4],
+				u32 vs[4], u32 pc[4], u8 pc_supported,
+				u32 n_lanes)
+{
+	u32 retry_cnt;
+
+	for (retry_cnt = 0; retry_cnt < 4; retry_cnt++) {
+		if (retry_cnt) {
+			tegra_dp_lt_adjust(dp, pe, vs, pc, pc_supported);
+			tegra_dp_lt_config(dp, pe, vs, pc);
+		}
+
+		tegra_dp_wait_aux_training(dp, 0);
+
+		if (!tegra_dp_clock_recovery_status(dp)) {
+			printk(BIOS_ERR, "dp: CR failed in channel EQ"
+					" sequence!\n");
+			break;
+		}
+
+		if (tegra_dp_channel_eq_status(dp))
+			return DP_LT_SUCCESS;
+	}
+
+	return DP_LT_FAILED;
+}
+
+static int tegra_dp_channel_eq(struct tegra_dc_dp_data *dp,
+					u32 pe[4], u32 vs[4], u32 pc[4])
+{
+	u32 n_lanes = dp->link_cfg.lane_count;
+	u8 pc_supported = dp->link_cfg.tps3_supported;
+	int err;
+	u32 tp_src = training_pattern_2;
+
+	if (pc_supported)
+		tp_src = training_pattern_3;
+
+	tegra_dp_tpg(dp, tp_src, n_lanes);
+
+	err = _tegra_dp_channel_eq(dp, pe, vs, pc, pc_supported, n_lanes);
+
+	tegra_dp_tpg(dp, training_pattern_disabled, n_lanes);
+
+	return err;
+}
+
+static int _tegra_dp_clk_recovery(struct tegra_dc_dp_data *dp, u32 pe[4],
+					u32 vs[4], u32 pc[4], u8 pc_supported,
+					u32 n_lanes)
+{
+	u32 vs_temp[4];
+	u32 retry_cnt = 0;
+
+	do {
+		tegra_dp_lt_config(dp, pe, vs, pc);
+		tegra_dp_wait_aux_training(dp, 1);
+
+		if (tegra_dp_clock_recovery_status(dp))
+			return DP_LT_SUCCESS;
+
+		memcpy(vs_temp, vs, sizeof(vs_temp));
+		tegra_dp_lt_adjust(dp, pe, vs, pc, pc_supported);
+
+		if (memcmp(vs_temp, vs, sizeof(vs_temp)))
+			retry_cnt = 0;
+		else
+			++retry_cnt;
+	} while (retry_cnt < 5);
+
+	return DP_LT_FAILED;
+}
+
+static int tegra_dp_clk_recovery(struct tegra_dc_dp_data *dp,
+					u32 pe[4], u32 vs[4], u32 pc[4])
+{
+	u32 n_lanes = dp->link_cfg.lane_count;
+	u8 pc_supported = dp->link_cfg.tps3_supported;
+	int err;
+
+	tegra_dp_tpg(dp, training_pattern_1, n_lanes);
+
+	err = _tegra_dp_clk_recovery(dp, pe, vs, pc, pc_supported, n_lanes);
+	if (err < 0)
+		tegra_dp_tpg(dp, training_pattern_disabled, n_lanes);
+
+	return err;
+}
+
+static int tegra_dc_dp_full_link_training(struct tegra_dc_dp_data *dp)
+{
+	struct tegra_dc_sor_data *sor = &dp->sor;
+	int err;
+	u32 pe[4], vs[4], pc[4];
+
+	printk(BIOS_INFO, "dp: %s\n", __func__);
+	tegra_sor_precharge_lanes(sor);
+
+retry_cr:
+	memset(pe, preEmphasis_Disabled, sizeof(pe));
+	memset(vs, driveCurrent_Level0, sizeof(vs));
+	memset(pc, postCursor2_Level0, sizeof(pc));
+
+	err = tegra_dp_clk_recovery(dp, pe, vs, pc);
+	if (err != DP_LT_SUCCESS) {
+		if (!tegra_dp_lower_link_config(dp, &dp->link_cfg))
+			goto retry_cr;
+
+		printk(BIOS_ERR, "dp: clk recovery failed\n");
+		goto fail;
+	}
+
+	err = tegra_dp_channel_eq(dp, pe, vs, pc);
+	if (err != DP_LT_SUCCESS) {
+		if (!tegra_dp_lower_link_config(dp, &dp->link_cfg))
+			goto retry_cr;
+
+		printk(BIOS_ERR,
+			"dp: channel equalization failed\n");
+		goto fail;
+	}
+
+	tegra_dc_dp_dump_link_cfg(dp, &dp->link_cfg);
+
+	return 0;
+
+fail:
+	return err;
+}
+
+/*
+ * All link training functions are ported from kernel dc driver.
+ * See more details at drivers/video/tegra/dc/dp.c
+ */
+#if DO_FAST_LINK_TRAINING
+static int tegra_dc_dp_fast_link_training(struct tegra_dc_dp_data *dp,
+	const struct tegra_dc_dp_link_config *link_cfg)
+{
+	struct tegra_dc_sor_data *sor = &dp->sor;
+	u8	link_bw;
+	u8	lane_count;
+	u16	data16;
+	u32	data32;
+	u32	size;
+	u32	status;
+	int	j;
+	u32	mask = 0xffff >> ((4 - link_cfg->lane_count) * 4);
+
+
+	printk(BIOS_INFO, "dp: %s\n", __func__);
+
+	tegra_dc_sor_set_lane_parm(sor, link_cfg);
+	tegra_dc_dp_dpcd_write(dp, NV_DPCD_MAIN_LINK_CHANNEL_CODING_SET,
+		NV_DPCD_MAIN_LINK_CHANNEL_CODING_SET_ANSI_8B10B);
+
+	/* Send TP1 */
+	tegra_dc_sor_set_dp_linkctl(sor, 1, training_pattern_1, link_cfg);
+	tegra_dc_dp_dpcd_write(dp, NV_DPCD_TRAINING_PATTERN_SET,
+		NV_DPCD_TRAINING_PATTERN_SET_TPS_TP1);
+
+	for (j = 0; j < link_cfg->lane_count; ++j)
+		tegra_dc_dp_dpcd_write(dp, NV_DPCD_TRAINING_LANE0_SET + j,
+			0x24);
+	udelay(520);
+
+	size = sizeof(data16);
+	tegra_dc_dpaux_read(dp, DPAUX_DP_AUXCTL_CMD_AUXRD,
+		NV_DPCD_LANE0_1_STATUS, (u8 *)&data16, &size, &status);
+	status = mask & 0x1111;
+	if ((data16 & status) != status) {
+		printk(BIOS_ERR,
+			"dp: Link training error for TP1 (%#x)\n", data16);
+		return -EFAULT;
+	}
+
+	/* enable ASSR */
+	tegra_dc_dp_set_assr(dp, link_cfg->scramble_ena);
+	tegra_dc_sor_set_dp_linkctl(sor, 1, training_pattern_3, link_cfg);
+
+	tegra_dc_dp_dpcd_write(dp, NV_DPCD_TRAINING_PATTERN_SET,
+		link_cfg->link_bw == 20 ? 0x23 : 0x22);
+	for (j = 0; j < link_cfg->lane_count; ++j)
+		tegra_dc_dp_dpcd_write(dp, NV_DPCD_TRAINING_LANE0_SET + j,
+			0x24);
+	udelay(520);
+
+	size = sizeof(data32);
+	tegra_dc_dpaux_read(dp, DPAUX_DP_AUXCTL_CMD_AUXRD,
+		NV_DPCD_LANE0_1_STATUS, (u8 *)&data32, &size, &status);
+	if ((data32 & mask) != (0x7777 & mask)) {
+		printk(BIOS_ERR,
+			"dp: Link training error for TP2/3 (0x%x)\n", data32);
+		return -EFAULT;
+	}
+
+	tegra_dc_sor_set_dp_linkctl(sor, 1, training_pattern_disabled,
+				link_cfg);
+	tegra_dc_dp_dpcd_write(dp, NV_DPCD_TRAINING_PATTERN_SET, 0);
+
+	if (tegra_dc_dp_link_trained(dp, link_cfg)) {
+		tegra_dc_sor_read_link_config(&dp->sor, &link_bw,
+			&lane_count);
+		printk(BIOS_ERR,
+			"Fast link trainging failed, link bw %d, lane # %d\n",
+			link_bw, lane_count);
+		return -EFAULT;
+	}
+
+	printk(BIOS_INFO,
+		"Fast link trainging succeeded, link bw %d, lane %d\n",
+		link_cfg->link_bw, link_cfg->lane_count);
+
+	return 0;
+}
+#endif /* DO_FAST_LINK_TRAINING */
+
+static int tegra_dp_do_link_training(struct tegra_dc_dp_data *dp,
+	const struct tegra_dc_dp_link_config *link_cfg)
+{
+	u8	link_bw;
+	u8	lane_count;
+#if DO_FAST_LINK_TRAINING
+	int	ret;
+
+	/* Now do the fast link training for eDP */
+	ret = tegra_dc_dp_fast_link_training(dp, link_cfg);
+	if (ret) {
+		printk(BIOS_ERR, "dp: fast link training failed\n");
+
+		/* Try full link training then */
+		if (tegra_dc_dp_full_link_training(dp)) {
+			printk(BIOS_ERR, "dp: full link training failed\n");
+			return ret;
+		}
+	} else {
+		/* set to a known-good drive setting if fast link succeeded */
+		tegra_dc_sor_set_voltage_swing(&dp->sor);
+	}
+#else
+	if (tegra_dc_dp_full_link_training(dp)) {
+		printk(BIOS_ERR, "dp: full link training failed\n");
+		return -EFAULT;
+	}
+#endif
+
+	/* Everything goes well, double check the link config */
+	/* TODO: record edc/c2 data for debugging */
+	tegra_dc_sor_read_link_config(&dp->sor, &link_bw, &lane_count);
+
+	if ((link_cfg->link_bw == link_bw) &&
+		(link_cfg->lane_count == lane_count))
+		return 0;
+	else
+		return -EFAULT;
+}
+
+static int tegra_dc_dp_explore_link_cfg(struct tegra_dc_dp_data *dp,
+	struct tegra_dc_dp_link_config *link_cfg,
+	const struct soc_nvidia_tegra210_config *config)
+{
+	struct tegra_dc_dp_link_config temp_cfg;
+
+	if (!config->pixel_clock || !config->xres || !config->yres) {
+		printk(BIOS_ERR,
+			"dp: error mode configuration");
+		return -EINVAL;
+	}
+	if (!link_cfg->max_link_bw || !link_cfg->max_lane_count) {
+		printk(BIOS_ERR,
+			"dp: error link configuration");
+		return -EINVAL;
+	}
+
+	link_cfg->is_valid = 0;
+
+	memcpy(&temp_cfg, link_cfg, sizeof(temp_cfg));
+
+	temp_cfg.link_bw = temp_cfg.max_link_bw;
+	temp_cfg.lane_count = temp_cfg.max_lane_count;
+
+	/*
+	 * set to max link config
+	 */
+	if ((!tegra_dc_dp_calc_config(dp, config, &temp_cfg)) &&
+		(!tegra_dp_link_config(dp, &temp_cfg)) &&
+		(!tegra_dp_do_link_training(dp, &temp_cfg)))
+		/* the max link cfg is doable */
+		memcpy(link_cfg, &temp_cfg, sizeof(temp_cfg));
+
+	return link_cfg->is_valid ? 0 : -EFAULT;
+}
+
+static void tegra_dp_update_config(struct tegra_dc_dp_data *dp,
+				   struct soc_nvidia_tegra210_config *config)
+{
+	struct edid edid;
+	u8 buf[128] = {0};
+	u32 size = sizeof(buf), aux_stat = 0;
+
+	printk(BIOS_ERR, "%s: enable r/w dump.\n",
+		       __func__);
+
+	tegra_dc_dpaux_enable(dp);
+	if (tegra_dc_i2c_aux_read(dp, TEGRA_EDID_I2C_ADDRESS, 0, buf, &size,
+				  &aux_stat)) {
+		printk(BIOS_ERR, "%s: Failed to read EDID. Use defaults.\n",
+		       __func__);
+		return;
+	}
+
+	if (decode_edid(buf, sizeof(buf), &edid)) {
+		printk(BIOS_ERR, "%s: Failed to decode EDID. Use defaults.\n",
+		       __func__);
+		return;
+	}
+
+	config->xres = config->display_xres = edid.ha;
+	config->yres = config->display_yres = edid.va;
+
+	config->pixel_clock = edid.pixel_clock * 1000;
+
+	config->hfront_porch = edid.hso;
+	config->hsync_width = edid.hspw;
+	config->hback_porch = edid.hbl - edid.hso - edid.hspw;
+
+	config->vfront_porch = edid.vso;
+	config->vsync_width = edid.vspw;
+	config->vback_porch = edid.vbl - edid.vso - edid.vspw;
+
+	/**
+	 * Note edid->framebuffer_bits_per_pixel is currently hard-coded as 32,
+	 * so we should keep the default value in device config.
+	 *
+	 * EDID v1.3 panels may not have color depth info, so we need to check
+	 * if these values are zero before updating config.
+	 */
+	if (edid.panel_bits_per_pixel)
+		config->panel_bits_per_pixel = edid.panel_bits_per_pixel;
+	if (edid.panel_bits_per_color)
+		config->color_depth = edid.panel_bits_per_color;
+	printk(BIOS_SPEW, "%s: configuration updated by EDID.\n", __func__);
+}
+
+void dp_init(void *_config)
+{
+	struct soc_nvidia_tegra210_config *config = (void *)_config;
+	struct tegra_dc *dc = config->dc_data;
+	struct tegra_dc_dp_data *dp = &dp_data;
+
+	/* set up links among config, dc, dp and sor */
+	dp->dc = dc;
+	dc->out = dp;
+	dp->sor.dc = dc;
+
+	dp->sor.power_is_up = 0;
+	dp->sor.base = (void *)TEGRA_ARM_SOR;
+	dp->sor.pmc_base = (void *)TEGRA_PMC_BASE;
+	dp->sor.portnum = 0;
+	dp->sor.link_cfg = &dp->link_cfg;
+	dp->aux_base = (void *)TEGRA_ARM_DPAUX;
+	dp->link_cfg.is_valid = 0;
+	dp->enabled = 0;
+
+	tegra_dp_update_config(dp, config);
+}
+
+static void tegra_dp_hpd_config(struct tegra_dc_dp_data *dp,
+				struct soc_nvidia_tegra210_config *config)
+{
+	u32 val;
+
+	val = config->dp.hpd_plug_min_us |
+		(config->dp.hpd_unplug_min_us <<
+		DPAUX_HPD_CONFIG_UNPLUG_MIN_TIME_SHIFT);
+	tegra_dpaux_writel(dp, DPAUX_HPD_CONFIG, val);
+
+	tegra_dpaux_writel(dp, DPAUX_HPD_IRQ_CONFIG, config->dp.hpd_irq_min_us);
+}
+
+static int tegra_dp_hpd_plug(struct tegra_dc_dp_data *dp, int timeout_ms)
+{
+	u32 val;
+	u32 timeout = timeout_ms * 1000;
+	do {
+		val = tegra_dpaux_readl(dp, DPAUX_DP_AUXSTAT);
+		if (val & DPAUX_DP_AUXSTAT_HPD_STATUS_PLUGGED)
+			return 0;
+		udelay(100);
+		timeout -= 100;
+	} while (timeout > 0);
+	return -1;
+}
+
+static int tegra_dc_dp_sink_out_of_sync(struct tegra_dc_dp_data *dp,
+		u32 delay_ms)
+{
+	u8 dpcd_data;
+	int out_of_sync;
+
+	mdelay(delay_ms);
+	tegra_dc_dp_dpcd_read(dp, NV_DPCD_SINK_STATUS, &dpcd_data);
+
+	out_of_sync = ((dpcd_data & NV_DPCD_SINK_STATUS_PORT0_IN_SYNC) !=
+		NV_DPCD_SINK_STATUS_PORT0_IN_SYNC);
+
+	if (out_of_sync)
+		printk(BIOS_ERR,
+			"SINK receive port 0 is out of synchronization\n");
+	else
+		printk(BIOS_INFO,
+			"SINK is in synchronization\n");
+
+	return out_of_sync;
+}
+
+static void tegra_dc_dp_check_sink(struct tegra_dc_dp_data *dp,
+				struct soc_nvidia_tegra210_config *config)
+{
+
+	u8 max_retry = 3;
+	int delay_frame;
+
+	/* DP TCON may skip some main stream frames, thus we need to wait
+	   some delay before reading the DPCD SINK STATUS register, starting
+	   from 5 */
+	delay_frame = 5;
+
+	while (tegra_dc_dp_sink_out_of_sync(dp, FRAME_IN_MS * delay_frame) &&
+		max_retry--) {
+		tegra_dc_detach(&dp->sor);
+		if (tegra_dc_dp_explore_link_cfg(dp, &dp->link_cfg, config)) {
+			printk(BIOS_ERR, "dp: %s: error to configure link\n",
+				__func__);
+			continue;
+		}
+
+		tegra_dc_sor_set_power_state(&dp->sor, 1);
+		tegra_dc_sor_attach(&dp->sor);
+
+		/* Increase delay_frame for next try in case the sink is
+		   skipping more frames */
+		delay_frame += 10;
+	}
+}
+
+void dp_enable(void *_dp)
+{
+	struct tegra_dc_dp_data *dp = _dp;
+	struct tegra_dc *dc = dp->dc;
+	struct soc_nvidia_tegra210_config *config = dc->config;
+
+	u8      data;
+	u32     retry;
+	int     ret;
+
+	tegra_dc_dpaux_enable(dp);
+
+	tegra_dp_hpd_config(dp, config);
+	if (tegra_dp_hpd_plug(dp, config->dp.vdd_to_hpd_delay_ms) < 0) {
+		printk(BIOS_ERR, "dp: hpd plug failed\n");
+		goto error_enable;
+	}
+
+	if (tegra_dc_dp_init_max_link_cfg(config, dp, &dp->link_cfg)) {
+		printk(BIOS_ERR, "dp: failed to init link configuration\n");
+		goto error_enable;
+	}
+
+	tegra_dc_sor_enable_dp(&dp->sor);
+
+	tegra_dc_sor_set_panel_power(&dp->sor, 1);
+
+	/* Write power on to DPCD */
+	data = NV_DPCD_SET_POWER_VAL_D0_NORMAL;
+	retry = 0;
+	do {
+		ret = tegra_dc_dp_dpcd_write(dp,
+			NV_DPCD_SET_POWER, data);
+	} while ((retry++ < DP_POWER_ON_MAX_TRIES) && ret);
+
+	if (ret || retry >= DP_POWER_ON_MAX_TRIES) {
+		printk(BIOS_ERR,
+			"dp: failed to power on panel (0x%x)\n", ret);
+		goto error_enable;
+	}
+
+	/* Confirm DP is plugging status */
+	if (!(tegra_dpaux_readl(dp, DPAUX_DP_AUXSTAT) &
+			DPAUX_DP_AUXSTAT_HPD_STATUS_PLUGGED)) {
+		printk(BIOS_ERR, "dp: could not detect HPD\n");
+		goto error_enable;
+	}
+
+	/* Check DP version */
+	if (tegra_dc_dp_dpcd_read(dp, NV_DPCD_REV, &dp->revision))
+		printk(BIOS_ERR,
+			"dp: failed to read the revision number from sink\n");
+
+	if (tegra_dc_dp_explore_link_cfg(dp, &dp->link_cfg, config)) {
+		printk(BIOS_ERR, "dp: error to configure link\n");
+		goto error_enable;
+	}
+
+	tegra_dc_sor_set_power_state(&dp->sor, 1);
+	tegra_dc_sor_attach(&dp->sor);
+
+	tegra_dc_dp_check_sink(dp, config);
+
+	/*
+	 * Power down the unused lanes to save power
+	 * (about hundreds milli-watts, varies from boards).
+	 */
+	tegra_dc_sor_power_down_unused_lanes(&dp->sor);
+
+	dp->enabled = 1;
+error_enable:
+	return;
+}
+
+void dp_display_startup(device_t dev)
+{
+	struct soc_nvidia_tegra210_config *config = dev->chip_info;
+	struct display_controller *disp_ctrl =
+			(void *)config->display_controller;
+
+	u32 framebuffer_size_mb = config->framebuffer_size / MiB;
+	u32 framebuffer_base_mb = config->framebuffer_base / MiB;
+
+	struct pwm_controller *pwm = (void *)TEGRA_PWM_BASE;
+	struct tegra_dc	*dc = &dc_data;
+	u32 plld_rate;
+
+	printk(BIOS_INFO, "%s: entry: disp_ctrl: %p.\n",
+		 __func__, disp_ctrl);
+
+	if (disp_ctrl == NULL) {
+		printk(BIOS_ERR, "Error: No dc is assigned by dt.\n");
+		return;
+	}
+
+	dc->base = (void *)disp_ctrl;
+	dc->config = config;
+	config->dc_data = dc;
+
+	/* Note dp_init may read EDID and change some config values. */
+	dp_init(config);
+
+	if (framebuffer_size_mb == 0) {
+		framebuffer_size_mb = ALIGN_UP(config->display_xres *
+			config->display_yres *
+			(config->framebuffer_bits_per_pixel / 8), MiB)/MiB;
+	}
+
+	config->framebuffer_size = framebuffer_size_mb * MiB;
+	config->framebuffer_base = framebuffer_base_mb * MiB;
+
+	/* The plld is programmed with the assumption of the SHIFT_CLK_DIVIDER
+	 * and PIXEL_CLK_DIVIDER are zero (divide by 1). See the
+	 * update_display_mode() for detail.
+	 */
+	plld_rate = clock_configure_plld(config->pixel_clock * 2);
+	if (plld_rate == 0) {
+		printk(BIOS_ERR, "dc: clock init failed\n");
+		return;
+	} else if (plld_rate != config->pixel_clock * 2) {
+		printk(BIOS_WARNING, "dc: plld rounded to %u\n", plld_rate);
+		config->pixel_clock = plld_rate / 2;
+	}
+
+	/* set disp1's clock source to PLLD_OUT0 */
+	clock_configure_source(disp1, PLLD, (plld_rate/KHz)/2);
+
+	/* Init dc */
+	if (tegra_dc_init(disp_ctrl)) {
+		printk(BIOS_ERR, "dc: init failed\n");
+		return;
+	}
+
+	/* Configure dc mode */
+	if (update_display_mode(disp_ctrl, config)) {
+		printk(BIOS_ERR, "dc: failed to configure display mode.\n");
+		return;
+	}
+
+	/* Enable dp */
+	dp_enable(dc->out);
+
+	/* Set up Tegra PWM n (where n is specified in config->dp.pwm) to drive the
+	 * panel backlight.
+	 */
+	printk(BIOS_SPEW, "%s: enable panel backlight pwm\n", __func__);
+	WRITEL(((1 << NV_PWM_CSR_ENABLE_SHIFT) |
+		(220 << NV_PWM_CSR_PULSE_WIDTH_SHIFT) | /* 220/256 */
+		0x02e), /* frequency divider */
+	       &pwm->pwm[config->dp.pwm].csr);
+
+	/* Set up window */
+	update_window(config);
+	printk(BIOS_INFO, "%s: display init done.\n", __func__);
+
+	/* Save panel mode to cb tables */
+	pass_mode_info_to_payload(config);
+
+	/*
+	 * After this point, it is payload's responsibility to allocate
+	 * framebuffer and sets the base address to dc's
+	 * WINBUF_START_ADDR register and enables window by setting dc's
+	 * DISP_DISP_WIN_OPTIONS register.
+	 */
+}
diff --git a/src/soc/nvidia/tegra210/dsi.c b/src/soc/nvidia/tegra210/dsi.c
new file mode 100644
index 0000000..3d0b850
--- /dev/null
+++ b/src/soc/nvidia/tegra210/dsi.c
@@ -0,0 +1,1045 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright 2014 Google Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc.
+ */
+#include <console/console.h>
+#include <arch/io.h>
+#include <stdint.h>
+#include <lib.h>
+#include <stdlib.h>
+#include <delay.h>
+#include <timer.h>
+#include <soc/addressmap.h>
+#include <soc/clock.h>
+#include <device/device.h>
+#include <edid.h>
+#include <soc/nvidia/tegra/types.h>
+#include <soc/nvidia/tegra/dc.h>
+#include "chip.h"
+#include <soc/display.h>
+#include <soc/mipi_dsi.h>
+#include <soc/mipi_display.h>
+#include <soc/tegra_dsi.h>
+#include <soc/mipi-phy.h>
+#include "jdi_25x18_display/panel-jdi-lpm102a188a.h"
+
+struct tegra_mipi_device mipi_device_data[NUM_DSI];
+
+struct tegra_dsi dsi_data[NUM_DSI] = {
+	{
+		.regs = (void *)TEGRA_DSIA_BASE,
+		.channel = 0,
+		.slave = &dsi_data[DSI_B],
+		.master = NULL,
+		.video_fifo_depth = MAX_DSI_VIDEO_FIFO_DEPTH,
+		.host_fifo_depth = MAX_DSI_HOST_FIFO_DEPTH,
+	},
+	{
+		.regs = (void *)TEGRA_DSIB_BASE,
+		.channel = 0,
+		.slave = NULL,
+		.master = &dsi_data[DSI_A],
+		.video_fifo_depth = MAX_DSI_VIDEO_FIFO_DEPTH,
+		.host_fifo_depth = MAX_DSI_HOST_FIFO_DEPTH,
+	},
+};
+
+static const u32 init_reg[] = {
+	DSI_INT_ENABLE,
+	DSI_INT_STATUS,
+	DSI_INT_MASK,
+	DSI_INIT_SEQ_DATA_0,
+	DSI_INIT_SEQ_DATA_1,
+	DSI_INIT_SEQ_DATA_2,
+	DSI_INIT_SEQ_DATA_3,
+	DSI_INIT_SEQ_DATA_4,
+	DSI_INIT_SEQ_DATA_5,
+	DSI_INIT_SEQ_DATA_6,
+	DSI_INIT_SEQ_DATA_7,
+	DSI_INIT_SEQ_DATA_15,
+	DSI_DCS_CMDS,
+	DSI_PKT_SEQ_0_LO,
+	DSI_PKT_SEQ_1_LO,
+	DSI_PKT_SEQ_2_LO,
+	DSI_PKT_SEQ_3_LO,
+	DSI_PKT_SEQ_4_LO,
+	DSI_PKT_SEQ_5_LO,
+	DSI_PKT_SEQ_0_HI,
+	DSI_PKT_SEQ_1_HI,
+	DSI_PKT_SEQ_2_HI,
+	DSI_PKT_SEQ_3_HI,
+	DSI_PKT_SEQ_4_HI,
+	DSI_PKT_SEQ_5_HI,
+	DSI_CONTROL,
+	DSI_HOST_CONTROL,
+	DSI_PAD_CONTROL_0,
+	DSI_PAD_CONTROL_CD,
+	DSI_SOL_DELAY,
+	DSI_MAX_THRESHOLD,
+	DSI_TRIGGER,
+	DSI_TX_CRC,
+	DSI_INIT_SEQ_CONTROL,
+	DSI_PKT_LEN_0_1,
+	DSI_PKT_LEN_2_3,
+	DSI_PKT_LEN_4_5,
+	DSI_PKT_LEN_6_7,
+};
+
+static inline struct tegra_dsi *host_to_tegra(struct mipi_dsi_host *host)
+{
+	return container_of(host, struct tegra_dsi, host);
+}
+
+/*
+ * non-burst mode with sync pulses
+ */
+static const u32 pkt_seq_video_non_burst_sync_pulses[NUM_PKT_SEQ] = {
+	[ 0] = PKT_ID0(MIPI_DSI_V_SYNC_START) | PKT_LEN0(0) |
+	       PKT_ID1(MIPI_DSI_BLANKING_PACKET) | PKT_LEN1(1) |
+	       PKT_ID2(MIPI_DSI_H_SYNC_END) | PKT_LEN2(0) |
+	       PKT_LP,
+	[ 1] = 0,
+	[ 2] = PKT_ID0(MIPI_DSI_V_SYNC_END) | PKT_LEN0(0) |
+	       PKT_ID1(MIPI_DSI_BLANKING_PACKET) | PKT_LEN1(1) |
+	       PKT_ID2(MIPI_DSI_H_SYNC_END) | PKT_LEN2(0) |
+	       PKT_LP,
+	[ 3] = 0,
+	[ 4] = PKT_ID0(MIPI_DSI_H_SYNC_START) | PKT_LEN0(0) |
+	       PKT_ID1(MIPI_DSI_BLANKING_PACKET) | PKT_LEN1(1) |
+	       PKT_ID2(MIPI_DSI_H_SYNC_END) | PKT_LEN2(0) |
+	       PKT_LP,
+	[ 5] = 0,
+	[ 6] = PKT_ID0(MIPI_DSI_H_SYNC_START) | PKT_LEN0(0) |
+	       PKT_ID1(MIPI_DSI_BLANKING_PACKET) | PKT_LEN1(1) |
+	       PKT_ID2(MIPI_DSI_H_SYNC_END) | PKT_LEN2(0),
+	[ 7] = PKT_ID0(MIPI_DSI_BLANKING_PACKET) | PKT_LEN0(2) |
+	       PKT_ID1(MIPI_DSI_PACKED_PIXEL_STREAM_24) | PKT_LEN1(3) |
+	       PKT_ID2(MIPI_DSI_BLANKING_PACKET) | PKT_LEN2(4),
+	[ 8] = PKT_ID0(MIPI_DSI_H_SYNC_START) | PKT_LEN0(0) |
+	       PKT_ID1(MIPI_DSI_BLANKING_PACKET) | PKT_LEN1(1) |
+	       PKT_ID2(MIPI_DSI_H_SYNC_END) | PKT_LEN2(0) |
+	       PKT_LP,
+	[ 9] = 0,
+	[10] = PKT_ID0(MIPI_DSI_H_SYNC_START) | PKT_LEN0(0) |
+	       PKT_ID1(MIPI_DSI_BLANKING_PACKET) | PKT_LEN1(1) |
+	       PKT_ID2(MIPI_DSI_H_SYNC_END) | PKT_LEN2(0),
+	[11] = PKT_ID0(MIPI_DSI_BLANKING_PACKET) | PKT_LEN0(2) |
+	       PKT_ID1(MIPI_DSI_PACKED_PIXEL_STREAM_24) | PKT_LEN1(3) |
+	       PKT_ID2(MIPI_DSI_BLANKING_PACKET) | PKT_LEN2(4),
+};
+
+/*
+ * non-burst mode with sync events
+ */
+static const u32 pkt_seq_video_non_burst_sync_events[NUM_PKT_SEQ] = {
+	[ 0] = PKT_ID0(MIPI_DSI_V_SYNC_START) | PKT_LEN0(0) |
+	       PKT_ID1(MIPI_DSI_END_OF_TRANSMISSION) | PKT_LEN1(7) |
+	       PKT_LP,
+	[ 1] = 0,
+	[ 2] = PKT_ID0(MIPI_DSI_H_SYNC_START) | PKT_LEN0(0) |
+	       PKT_ID1(MIPI_DSI_END_OF_TRANSMISSION) | PKT_LEN1(7) |
+	       PKT_LP,
+	[ 3] = 0,
+	[ 4] = PKT_ID0(MIPI_DSI_H_SYNC_START) | PKT_LEN0(0) |
+	       PKT_ID1(MIPI_DSI_END_OF_TRANSMISSION) | PKT_LEN1(7) |
+	       PKT_LP,
+	[ 5] = 0,
+
+	[ 6] = PKT_ID0(MIPI_DSI_H_SYNC_START) | PKT_LEN0(0) |
+	       PKT_ID1(MIPI_DSI_BLANKING_PACKET) | PKT_LEN1(2) |
+	       PKT_ID2(MIPI_DSI_PACKED_PIXEL_STREAM_24) | PKT_LEN2(3),
+
+	[ 7] = PKT_ID0(MIPI_DSI_BLANKING_PACKET) | PKT_LEN0(4),
+	[ 8] = PKT_ID0(MIPI_DSI_H_SYNC_START) | PKT_LEN0(0) |
+	       PKT_ID1(MIPI_DSI_END_OF_TRANSMISSION) | PKT_LEN1(7) |
+	       PKT_LP,
+	[ 9] = 0,
+
+	[10] = PKT_ID0(MIPI_DSI_H_SYNC_START) | PKT_LEN0(0) |
+	       PKT_ID1(MIPI_DSI_BLANKING_PACKET) | PKT_LEN1(2) |
+	       PKT_ID2(MIPI_DSI_PACKED_PIXEL_STREAM_24) | PKT_LEN2(3),
+
+	[11] = PKT_ID0(MIPI_DSI_BLANKING_PACKET) | PKT_LEN0(4),
+};
+
+static const u32 pkt_seq_command_mode[NUM_PKT_SEQ] = {
+	[ 0] = 0,
+	[ 1] = 0,
+	[ 2] = 0,
+	[ 3] = 0,
+	[ 4] = 0,
+	[ 5] = 0,
+	[ 6] = PKT_ID0(MIPI_DSI_DCS_LONG_WRITE) | PKT_LEN0(3) | PKT_LP,
+	[ 7] = 0,
+	[ 8] = 0,
+	[ 9] = 0,
+	[10] = PKT_ID0(MIPI_DSI_DCS_LONG_WRITE) | PKT_LEN0(5) | PKT_LP,
+	[11] = 0,
+};
+
+static int tegra_dsi_set_phy_timing(struct tegra_dsi *dsi)
+{
+	int err;
+
+	err = mipi_dphy_set_timing(dsi);
+	if (err < 0) {
+		printk(BIOS_ERR, "failed to set D-PHY timing: %d\n", err);
+		return err;
+	}
+
+	if (dsi->slave)
+		tegra_dsi_set_phy_timing(dsi->slave);
+	return 0;
+}
+
+static int tegra_dsi_get_muldiv(enum mipi_dsi_pixel_format format,
+				unsigned int *mulp, unsigned int *divp)
+{
+	switch (format) {
+	case MIPI_DSI_FMT_RGB666_PACKED:
+	case MIPI_DSI_FMT_RGB888:
+		*mulp = 3;
+		*divp = 1;
+		break;
+
+	case MIPI_DSI_FMT_RGB565:
+		*mulp = 2;
+		*divp = 1;
+		break;
+
+	case MIPI_DSI_FMT_RGB666:
+		*mulp = 9;
+		*divp = 4;
+		break;
+
+	default:
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static int tegra_dsi_get_format(enum mipi_dsi_pixel_format format,
+				enum tegra_dsi_format *fmt)
+{
+	switch (format) {
+	case MIPI_DSI_FMT_RGB888:
+		*fmt = TEGRA_DSI_FORMAT_24P;
+		break;
+
+	case MIPI_DSI_FMT_RGB666:
+		*fmt = TEGRA_DSI_FORMAT_18NP;
+		break;
+
+	case MIPI_DSI_FMT_RGB666_PACKED:
+		*fmt = TEGRA_DSI_FORMAT_18P;
+		break;
+
+	case MIPI_DSI_FMT_RGB565:
+		*fmt = TEGRA_DSI_FORMAT_16P;
+		break;
+
+	default:
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static void tegra_dsi_ganged_enable(struct tegra_dsi *dsi, unsigned int start,
+				    unsigned int size)
+{
+	u32 value;
+
+	tegra_dsi_writel(dsi, start, DSI_GANGED_MODE_START);
+	tegra_dsi_writel(dsi, size << 16 | size, DSI_GANGED_MODE_SIZE);
+
+	value = DSI_GANGED_MODE_CONTROL_ENABLE;
+	tegra_dsi_writel(dsi, value, DSI_GANGED_MODE_CONTROL);
+}
+
+static void tegra_dsi_enable(struct tegra_dsi *dsi)
+{
+	u32 value;
+
+	value = tegra_dsi_readl(dsi, DSI_POWER_CONTROL);
+	value |= DSI_POWER_CONTROL_ENABLE;
+	tegra_dsi_writel(dsi, value, DSI_POWER_CONTROL);
+
+	if (dsi->slave)
+		tegra_dsi_enable(dsi->slave);
+}
+
+static int tegra_dsi_configure(struct tegra_dsi *dsi, unsigned int pipe,
+			const struct soc_nvidia_tegra210_config *mode)
+{
+	unsigned int hact, hsw, hbp, hfp, i, mul, div;
+	enum tegra_dsi_format format;
+	const u32 *pkt_seq;
+	u32 value;
+	int err;
+
+	if (dsi->flags & MIPI_DSI_MODE_VIDEO_SYNC_PULSE) {
+		printk(BIOS_SPEW, "Non-burst video mode with sync pulses\n");
+		pkt_seq = pkt_seq_video_non_burst_sync_pulses;
+	} else if (dsi->flags & MIPI_DSI_MODE_VIDEO) {
+		printk(BIOS_SPEW, "Non-burst video mode with sync events\n");
+		pkt_seq = pkt_seq_video_non_burst_sync_events;
+	} else {
+		printk(BIOS_SPEW, "Command mode\n");
+		pkt_seq = pkt_seq_command_mode;
+	}
+
+	err = tegra_dsi_get_muldiv(dsi->format, &mul, &div);
+	if (err < 0)
+		return err;
+
+	err = tegra_dsi_get_format(dsi->format, &format);
+	if (err < 0)
+		return err;
+
+	value = DSI_CONTROL_CHANNEL(0) | DSI_CONTROL_FORMAT(format) |
+		DSI_CONTROL_LANES(dsi->lanes - 1) |
+		DSI_CONTROL_SOURCE(pipe);
+	tegra_dsi_writel(dsi, value, DSI_CONTROL);
+
+	tegra_dsi_writel(dsi, dsi->video_fifo_depth, DSI_MAX_THRESHOLD);
+
+	value = DSI_HOST_CONTROL_HS;
+	tegra_dsi_writel(dsi, value, DSI_HOST_CONTROL);
+
+	value = tegra_dsi_readl(dsi, DSI_CONTROL);
+
+	if (dsi->flags & MIPI_DSI_CLOCK_NON_CONTINUOUS)
+		value |= DSI_CONTROL_HS_CLK_CTRL;
+
+	value &= ~DSI_CONTROL_TX_TRIG(3);
+
+	/* enable DCS commands for command mode */
+	if (dsi->flags & MIPI_DSI_MODE_VIDEO)
+		value &= ~DSI_CONTROL_DCS_ENABLE;
+	else
+		value |= DSI_CONTROL_DCS_ENABLE;
+
+	value |= DSI_CONTROL_VIDEO_ENABLE;
+	value &= ~DSI_CONTROL_HOST_ENABLE;
+	tegra_dsi_writel(dsi, value, DSI_CONTROL);
+
+	for (i = 0; i < NUM_PKT_SEQ; i++)
+		tegra_dsi_writel(dsi, pkt_seq[i], DSI_PKT_SEQ_0_LO + i);
+
+	if (dsi->flags & MIPI_DSI_MODE_VIDEO) {
+		/* horizontal active pixels */
+		hact = mode->xres * mul / div;
+
+		/* horizontal sync width */
+		hsw = (hsync_end(mode) - hsync_start(mode)) * mul / div;
+
+		/* horizontal back porch */
+		hbp = (htotal(mode) - hsync_end(mode)) * mul / div;
+		if ((dsi->flags & MIPI_DSI_MODE_VIDEO_SYNC_PULSE) == 0)
+			hbp += hsw;
+
+		/* horizontal front porch */
+		hfp = (hsync_start(mode) - mode->xres) * mul / div;
+
+		/* subtract packet overhead */
+		hsw -= 10;
+		hbp -= 14;
+		hfp -= 8;
+
+		tegra_dsi_writel(dsi, hsw << 16 | 0, DSI_PKT_LEN_0_1);
+		tegra_dsi_writel(dsi, hact << 16 | hbp, DSI_PKT_LEN_2_3);
+		tegra_dsi_writel(dsi, hfp, DSI_PKT_LEN_4_5);
+		tegra_dsi_writel(dsi, 0x0f0f << 16, DSI_PKT_LEN_6_7);
+
+		/* set SOL delay (for non-burst mode only) */
+		tegra_dsi_writel(dsi, 8 * mul / div, DSI_SOL_DELAY);
+
+		/* TODO: implement ganged mode */
+	} else {
+		u16 bytes;
+		if (dsi->ganged_mode) {
+			/*
+			 * For ganged mode, assume symmetric left-right mode.
+			 */
+			bytes = 1 + (mode->xres / 2) * mul / div;
+		} else {
+			/* 1 byte (DCS command) + pixel data */
+			bytes = 1 + mode->xres * mul / div;
+		}
+
+		tegra_dsi_writel(dsi, 0, DSI_PKT_LEN_0_1);
+		tegra_dsi_writel(dsi, bytes << 16, DSI_PKT_LEN_2_3);
+		tegra_dsi_writel(dsi, bytes << 16, DSI_PKT_LEN_4_5);
+		tegra_dsi_writel(dsi, 0, DSI_PKT_LEN_6_7);
+
+		value = MIPI_DCS_WRITE_MEMORY_START << 8 |
+			MIPI_DCS_WRITE_MEMORY_CONTINUE;
+		tegra_dsi_writel(dsi, value, DSI_DCS_CMDS);
+
+		/* set SOL delay */
+		if (dsi->ganged_mode) {
+			unsigned long delay, bclk, bclk_ganged;
+			unsigned int lanes = dsi->ganged_lanes;
+
+			/* SOL to valid, valid to FIFO and FIFO write delay */
+			delay = 4 + 4 + 2;
+			delay = DIV_ROUND_UP(delay * mul, div * lanes);
+			/* FIFO read delay */
+			delay = delay + 6;
+
+			bclk = DIV_ROUND_UP(htotal(mode) * mul, div * lanes);
+			bclk_ganged = DIV_ROUND_UP(bclk * lanes / 2, lanes);
+			value = bclk - bclk_ganged + delay + 20;
+		} else {
+			/* TODO: revisit for non-ganged mode */
+			value = 8 * mul / div;
+		}
+
+		tegra_dsi_writel(dsi, value, DSI_SOL_DELAY);
+	}
+
+	if (dsi->slave) {
+		err = tegra_dsi_configure(dsi->slave, pipe, mode);
+		if (err < 0)
+			return err;
+
+		/*
+		 * enable ganged mode
+		 */
+		if (dsi->ganged_mode) {
+			tegra_dsi_ganged_enable(dsi, mode->xres / 2,
+					mode->xres / 2);
+			tegra_dsi_ganged_enable(dsi->slave, 0, mode->xres / 2);
+		}
+	}
+	return 0;
+}
+
+static int tegra_output_dsi_enable(struct tegra_dsi *dsi,
+			const struct soc_nvidia_tegra210_config *config)
+{
+	int err;
+
+	if (dsi->enabled)
+		return 0;
+
+	err = tegra_dsi_configure(dsi, 0, config);
+	if (err < 0) {
+		printk(BIOS_ERR, "DSI configuration failed\n");
+		return err;
+	}
+
+	/* enable DSI controller */
+	tegra_dsi_enable(dsi);
+
+	dsi->enabled = true;
+	return 0;
+}
+
+
+static void tegra_dsi_set_timeout(struct tegra_dsi *dsi, unsigned long bclk,
+				  unsigned int vrefresh)
+{
+	unsigned int timeout;
+	u32 value;
+
+	/* one frame high-speed transmission timeout */
+	timeout = (bclk / vrefresh) / 512;
+	value = DSI_TIMEOUT_LRX(0x2000) | DSI_TIMEOUT_HTX(timeout);
+	tegra_dsi_writel(dsi, value, DSI_TIMEOUT_0);
+
+	/* 2 ms peripheral timeout for panel */
+	timeout = 2 * bclk / 512 * 1000;
+	value = DSI_TIMEOUT_PR(timeout) | DSI_TIMEOUT_TA(0x2000);
+	tegra_dsi_writel(dsi, value, DSI_TIMEOUT_1);
+
+	value = DSI_TALLY_TA(0) | DSI_TALLY_LRX(0) | DSI_TALLY_HTX(0);
+	tegra_dsi_writel(dsi, value, DSI_TO_TALLY);
+
+	if (dsi->slave)
+		tegra_dsi_set_timeout(dsi->slave, bclk, vrefresh);
+}
+
+static int tegra_output_dsi_setup_clock(struct tegra_dsi *dsi,
+			const struct soc_nvidia_tegra210_config *config)
+{
+	unsigned int mul, div, num_lanes;
+	unsigned long bclk;
+	unsigned long pclk = config->pixel_clock;
+	int plld;
+	int err;
+	struct display_controller *disp_ctrl =
+			(void *)config->display_controller;
+	unsigned int shift_clk_div;
+
+	err = tegra_dsi_get_muldiv(dsi->format, &mul, &div);
+	if (err < 0)
+		return err;
+
+	/*
+	 * In ganged mode, account for the total number of lanes across both
+	 * DSI channels so that the bit clock is properly computed.
+	 */
+	if (dsi->ganged_mode)
+		num_lanes = dsi->ganged_lanes;
+	else
+		num_lanes = dsi->lanes;
+
+	/* compute byte clock */
+	bclk = (pclk * mul) / (div * num_lanes);
+
+	/*
+	 * Compute bit clock and round up to the next MHz.
+	 */
+	plld = DIV_ROUND_UP(bclk * 8, USECS_PER_SEC) * USECS_PER_SEC;
+
+	/*
+	 * the actual rate on PLLD_OUT0 is 1/2 plld
+	 */
+	dsi->clk_rate = plld / 2;
+	if (dsi->slave)
+		dsi->slave->clk_rate = dsi->clk_rate;
+
+	/* set up plld */
+	plld = clock_configure_plld(plld);
+	if (plld == 0) {
+		printk(BIOS_ERR, "%s: clock init failed\n", __func__);
+		return -1;
+	} else
+		printk(BIOS_INFO, "%s:  plld is configured to: %u\n",
+			 __func__, plld);
+
+	/*
+	 * Derive pixel clock from bit clock using the shift clock divider.
+	 * Note that this is only half of what we would expect, but we need
+	 * that to make up for the fact that we divided the bit clock by a
+	 * factor of two above.
+	 */
+	shift_clk_div = ((8 * mul) / (div * num_lanes)) - 2;
+	update_display_shift_clock_divider(disp_ctrl, shift_clk_div);
+
+	tegra_dsi_set_timeout(dsi, bclk, config->refresh);
+	return plld/1000000;
+}
+
+
+
+static int tegra_dsi_pad_enable(struct tegra_dsi *dsi)
+{
+	unsigned long value;
+
+	value = DSI_PAD_CONTROL_VS1_PULLDN(0) | DSI_PAD_CONTROL_VS1_PDIO(0);
+	tegra_dsi_writel(dsi, value, DSI_PAD_CONTROL_0);
+	return 0;
+}
+
+static int tegra_dsi_pad_calibrate(struct tegra_dsi *dsi)
+{
+	u32 value;
+
+	tegra_dsi_writel(dsi, 0, DSI_PAD_CONTROL_0);
+	tegra_dsi_writel(dsi, 0, DSI_PAD_CONTROL_1);
+	tegra_dsi_writel(dsi, 0, DSI_PAD_CONTROL_2);
+	tegra_dsi_writel(dsi, 0, DSI_PAD_CONTROL_3);
+	tegra_dsi_writel(dsi, 0, DSI_PAD_CONTROL_4);
+
+	/* start calibration */
+	tegra_dsi_pad_enable(dsi);
+
+	value = DSI_PAD_SLEW_UP(0x7) | DSI_PAD_SLEW_DN(0x7) |
+		DSI_PAD_LP_UP(0x1) | DSI_PAD_LP_DN(0x1) |
+		DSI_PAD_OUT_CLK(0x0);
+	tegra_dsi_writel(dsi, value, DSI_PAD_CONTROL_2);
+
+	value = DSI_PAD_PREEMP_PD_CLK(0x3) | DSI_PAD_PREEMP_PU_CLK(0x3) |
+		DSI_PAD_PREEMP_PD(0x03) | DSI_PAD_PREEMP_PU(0x3);
+	tegra_dsi_writel(dsi, value, DSI_PAD_CONTROL_3);
+
+	return tegra_mipi_calibrate(dsi->mipi);
+}
+
+static const char * const error_report[16] = {
+	"SoT Error",
+	"SoT Sync Error",
+	"EoT Sync Error",
+	"Escape Mode Entry Command Error",
+	"Low-Power Transmit Sync Error",
+	"Peripheral Timeout Error",
+	"False Control Error",
+	"Contention Detected",
+	"ECC Error, single-bit",
+	"ECC Error, multi-bit",
+	"Checksum Error",
+	"DSI Data Type Not Recognized",
+	"DSI VC ID Invalid",
+	"Invalid Transmission Length",
+	"Reserved",
+	"DSI Protocol Violation",
+};
+
+static int tegra_dsi_read_response(struct tegra_dsi *dsi,
+				   const struct mipi_dsi_msg *msg,
+				   unsigned int count)
+{
+	u8 *rx = msg->rx_buf;
+	unsigned int i, j, k;
+	size_t size = 0;
+	u16 errors;
+	u32 value;
+
+	/* read and parse packet header */
+	value = tegra_dsi_readl(dsi, DSI_RD_DATA);
+
+	switch (value & 0x3f) {
+	case MIPI_DSI_RX_ACKNOWLEDGE_AND_ERROR_REPORT:
+		errors = (value >> 8) & 0xffff;
+		printk(BIOS_ERR, "Acknowledge and error report: %04x\n",
+			errors);
+		for (i = 0; i < ARRAY_SIZE(error_report); i++)
+			if (errors & BIT(i))
+				printk(BIOS_INFO, "  %2u: %s\n", i,
+					error_report[i]);
+		break;
+
+	case MIPI_DSI_RX_DCS_SHORT_READ_RESPONSE_1BYTE:
+		rx[0] = (value >> 8) & 0xff;
+		break;
+
+	case MIPI_DSI_RX_DCS_SHORT_READ_RESPONSE_2BYTE:
+		rx[0] = (value >>  8) & 0xff;
+		rx[1] = (value >> 16) & 0xff;
+		break;
+
+	case MIPI_DSI_RX_DCS_LONG_READ_RESPONSE:
+		size = ((value >> 8) & 0xff00) | ((value >> 8) & 0xff);
+		break;
+
+	case MIPI_DSI_RX_GENERIC_LONG_READ_RESPONSE:
+		size = ((value >> 8) & 0xff00) | ((value >> 8) & 0xff);
+		break;
+
+	default:
+		printk(BIOS_ERR, "unhandled response type: %02x\n",
+			value & 0x3f);
+		break;
+	}
+
+	size = MIN(size, msg->rx_len);
+
+	if (msg->rx_buf && size > 0) {
+		for (i = 0, j = 0; i < count - 1; i++, j += 4) {
+			value = tegra_dsi_readl(dsi, DSI_RD_DATA);
+
+			for (k = 0; k < 4 && (j + k) < msg->rx_len; k++)
+				rx[j + k] = (value >> (k << 3)) & 0xff;
+		}
+	}
+	return 0;
+}
+
+static int tegra_dsi_transmit(struct tegra_dsi *dsi, unsigned long timeout_ms)
+{
+	u32 poll_interval_us = 2000;
+	u32 timeout_us = timeout_ms * 1000;
+
+	tegra_dsi_writel(dsi, DSI_TRIGGER_HOST, DSI_TRIGGER);
+	udelay(poll_interval_us);
+
+	do {
+		u32 value = tegra_dsi_readl(dsi, DSI_TRIGGER);
+		if ((value & DSI_TRIGGER_HOST) == 0)
+			return 0;
+
+		//usleep_range(1000, 2000);
+		if (timeout_us > poll_interval_us)
+			timeout_us -= poll_interval_us;
+		else
+			break;
+
+		udelay(poll_interval_us);
+	} while (1);
+
+	printk(BIOS_ERR, "%s: ERROR: timeout waiting for transmission"
+			" to complete\n", __func__);
+	return -ETIMEDOUT;
+}
+
+static int tegra_dsi_wait_for_response(struct tegra_dsi *dsi,
+				       unsigned long timeout_ms)
+{
+	u32 poll_interval_us = 2000;
+	u32 timeout_us = timeout_ms * 1000;
+
+	do {
+		u32 value = tegra_dsi_readl(dsi, DSI_STATUS);
+		u8 count = value & 0x1f;
+
+		if (count > 0)
+			return count;
+
+		if (timeout_us > poll_interval_us)
+			timeout_us -= poll_interval_us;
+		else
+			break;
+
+		udelay(poll_interval_us);
+	} while (1);
+
+	printk(BIOS_ERR, "%s: ERROR: timeout\n", __func__);
+
+	return -ETIMEDOUT;
+}
+
+static ssize_t tegra_dsi_host_transfer(struct mipi_dsi_host *host,
+				const struct mipi_dsi_msg *msg)
+{
+	struct tegra_dsi *dsi = host_to_tegra(host);
+	const u8 *tx = msg->tx_buf;
+	unsigned int count, i, j;
+	u32 value;
+	int err;
+
+	if (msg->tx_len > dsi->video_fifo_depth * 4)
+		return -ENOSPC;
+
+	/* reset underflow/overflow flags */
+	value = tegra_dsi_readl(dsi, DSI_STATUS);
+	if (value & (DSI_STATUS_UNDERFLOW | DSI_STATUS_OVERFLOW)) {
+		value = DSI_HOST_CONTROL_FIFO_RESET;
+		tegra_dsi_writel(dsi, value, DSI_HOST_CONTROL);
+		udelay(20);	// usleep_range(10, 20);
+	}
+
+	value = tegra_dsi_readl(dsi, DSI_POWER_CONTROL);
+	value |= DSI_POWER_CONTROL_ENABLE;
+	tegra_dsi_writel(dsi, value, DSI_POWER_CONTROL);
+
+	udelay(7000);	//usleep_range(5000, 10000);
+
+	value = DSI_HOST_CONTROL_CRC_RESET | DSI_HOST_CONTROL_TX_TRIG_HOST |
+		DSI_HOST_CONTROL_CS | DSI_HOST_CONTROL_ECC;
+
+	if ((msg->flags & MIPI_DSI_MSG_USE_LPM) == 0)
+		value |= DSI_HOST_CONTROL_HS;
+
+	/*
+	 * The host FIFO has a maximum of 64 words, so larger transmissions
+	 * need to use the video FIFO.
+	 */
+	if (msg->tx_len > dsi->host_fifo_depth * 4)
+		value |= DSI_HOST_CONTROL_FIFO_SEL;
+
+	tegra_dsi_writel(dsi, value, DSI_HOST_CONTROL);
+
+	/*
+	 * For reads and messages with explicitly requested ACK, generate a
+	 * BTA sequence after the transmission of the packet.
+	 */
+	if ((msg->flags & MIPI_DSI_MSG_REQ_ACK) ||
+	    (msg->rx_buf && msg->rx_len > 0)) {
+		value = tegra_dsi_readl(dsi, DSI_HOST_CONTROL);
+		value |= DSI_HOST_CONTROL_PKT_BTA;
+		tegra_dsi_writel(dsi, value, DSI_HOST_CONTROL);
+	}
+
+	value = DSI_CONTROL_LANES(0) | DSI_CONTROL_HOST_ENABLE;
+	tegra_dsi_writel(dsi, value, DSI_CONTROL);
+
+	/* write packet header */
+	value = ((msg->channel & 0x3) << 6) | (msg->type & 0x3f);
+
+	if (tx && msg->tx_len > 0)
+		value |= tx[0] <<  8;
+
+	if (tx && msg->tx_len > 1)
+		value |= tx[1] << 16;
+
+	tegra_dsi_writel(dsi, value, DSI_WR_DATA);
+
+	/* write payload (if any) */
+	if (msg->tx_len > 2) {
+		for (j = 2; j < msg->tx_len; j += 4) {
+			value = 0;
+
+			for (i = 0; i < 4 && j + i < msg->tx_len; i++)
+				value |= tx[j + i] << (i << 3);
+
+			tegra_dsi_writel(dsi, value, DSI_WR_DATA);
+		}
+	}
+
+	err = tegra_dsi_transmit(dsi, 250);
+	if (err < 0) {
+		printk(BIOS_INFO, "Failed to transmit. %d\n", err);
+		return err;
+	}
+
+	if ((msg->flags & MIPI_DSI_MSG_REQ_ACK) ||
+	    (msg->rx_buf && msg->rx_len > 0)) {
+		err = tegra_dsi_wait_for_response(dsi, 250);
+		if (err < 0) {
+			printk(BIOS_INFO, "Failed to read response. %d\n", err);
+			return err;
+		}
+		count = err;
+
+		value = tegra_dsi_readl(dsi, DSI_RD_DATA);
+		switch (value) {
+		case 0x84:
+			printk(BIOS_INFO, "ACK\n");
+			break;
+
+		case 0x87:
+			printk(BIOS_INFO, "ESCAPE\n");
+			break;
+
+		default:
+			printk(BIOS_INFO, "unknown status: %08x\n", value);
+			break;
+		}
+
+		if (count > 1) {
+			err = tegra_dsi_read_response(dsi, msg, count);
+			if (err < 0)
+				printk(BIOS_INFO,
+					"failed to parse response: %d\n",
+					err);
+			else {
+				/*
+				 * For read commands, return the number of
+				 * bytes returned by the peripheral.
+				 */
+				count = err;
+			}
+		}
+	} else {
+		/*
+		 * For write commands, we have transmitted the 4-byte header
+		 * plus the variable-length payload.
+		 */
+		count = 4 + msg->tx_len;
+	}
+
+	return count;
+}
+
+static int tegra_dsi_ganged_setup(struct tegra_dsi *dsi,
+			  struct tegra_dsi *slave)
+{
+	/*
+	 * The number of ganged lanes is the sum of lanes of all peripherals
+	 * in the gang.
+	 */
+	dsi->slave->ganged_lanes = dsi->lanes + dsi->slave->lanes;
+	dsi->slave->ganged_mode = 1;
+
+	dsi->ganged_lanes = dsi->lanes + dsi->slave->lanes;
+	dsi->ganged_mode = 1;
+	return 0;
+}
+
+static int tegra_dsi_host_attach(struct mipi_dsi_host *host,
+				struct mipi_dsi_device *device)
+{
+	struct tegra_dsi *dsi = host_to_tegra(host);
+	int err;
+
+	dsi->flags = device->mode_flags;
+	dsi->format = device->format;
+	dsi->lanes = device->lanes;
+
+	if (dsi->master) {
+		err = tegra_dsi_ganged_setup(dsi->master, dsi);
+		if (err < 0) {
+			printk(BIOS_ERR, "failed to set up ganged mode: %d\n",
+				err);
+			return err;
+		}
+	}
+	return 0;
+}
+
+static const struct mipi_dsi_host_ops tegra_dsi_host_ops = {
+	.attach = tegra_dsi_host_attach,
+	.transfer = tegra_dsi_host_transfer,
+};
+
+static int dsi_probe_if(int dsi_index,
+			struct soc_nvidia_tegra210_config *config)
+{
+	struct tegra_dsi *dsi = &dsi_data[dsi_index];
+	int err;
+
+	tegra_dsi_writel(dsi, 0, DSI_INIT_SEQ_CONTROL);
+
+	/*
+	 * Set default value. Will be taken from attached device once detected
+	 */
+        dsi->flags = 0;
+        dsi->format = MIPI_DSI_FMT_RGB888;
+        dsi->lanes = 4;
+
+	/* get tegra_mipi_device */
+        dsi->mipi = tegra_mipi_request(&mipi_device_data[dsi_index], dsi_index);
+
+	/* calibrate */
+	err = tegra_dsi_pad_calibrate(dsi);
+	if (err < 0) {
+		printk(BIOS_ERR, "MIPI calibration failed: %d\n", err);
+		return err;
+	}
+
+	dsi->host.ops = &tegra_dsi_host_ops;
+	err = mipi_dsi_host_register(&dsi->host);
+	if (err < 0) {
+		printk(BIOS_ERR, "failed to register DSI host: %d\n", err);
+		return err;
+	}
+
+	/* get panel */
+	dsi->panel = panel_jdi_dsi_probe((struct mipi_dsi_device *)dsi->host.dev);
+	if (IS_ERR_PTR(dsi->panel)) {
+		printk(BIOS_ERR, "failed to get dsi panel\n");
+		return -EPTR;
+	}
+	dsi->panel->mode = config;
+	return 0;
+}
+
+static int dsi_probe(struct soc_nvidia_tegra210_config *config)
+{
+	dsi_probe_if(DSI_A, config);
+	dsi_probe_if(DSI_B, config);
+	return 0;
+}
+
+static void tegra_dsi_init_regs(struct tegra_dsi *dsi)
+{
+	int i;
+	for (i = 0; i < ARRAY_SIZE(init_reg); i++)
+		tegra_dsi_writel(dsi, 0, init_reg[i]);
+
+	if (dsi->slave)
+		tegra_dsi_init_regs(dsi->slave);
+}
+
+static int dsi_enable(struct soc_nvidia_tegra210_config *config)
+{
+	struct tegra_dsi *dsi_a = &dsi_data[DSI_A];
+
+	dsi_probe(config);
+
+	/* set up clock and TimeOutRegisters */
+	tegra_output_dsi_setup_clock(dsi_a, config);
+
+	/* configure APB_MISC_GP_MIPI_PAD_CTRL_0 */
+	write32((unsigned int *)APB_MISC_GP_MIPI_PAD_CTRL_0, DSIB_MODE_DSI);
+
+	/* configure phy interface timing registers */
+	tegra_dsi_set_phy_timing(dsi_a);
+
+	/* Initialize DSI registers */
+	tegra_dsi_init_regs(dsi_a);
+
+	/* prepare panel */
+	panel_jdi_prepare(dsi_a->panel);
+
+	/* enable dsi */
+	if (tegra_output_dsi_enable(dsi_a, config)) {
+		printk(BIOS_ERR,"%s: Error: failed to enable dsi output.\n",
+			__func__);
+		return -1;
+	}
+
+	return 0;
+}
+
+void dsi_display_startup(device_t dev)
+{
+	struct soc_nvidia_tegra210_config *config = dev->chip_info;
+	struct display_controller *disp_ctrl =
+			(void *)config->display_controller;
+	u32 plld_rate;
+
+	u32 framebuffer_size_mb = config->framebuffer_size / MiB;
+	u32 framebuffer_base_mb= config->framebuffer_base / MiB;
+
+	printk(BIOS_INFO, "%s: entry: disp_ctrl: %p.\n",
+		 __func__, disp_ctrl);
+
+	if (disp_ctrl == NULL) {
+		printk(BIOS_ERR, "Error: No dc is assigned by dt.\n");
+		return;
+	}
+
+	if (framebuffer_size_mb == 0){
+		framebuffer_size_mb = ALIGN_UP(config->display_xres *
+			config->display_yres *
+			(config->framebuffer_bits_per_pixel / 8), MiB)/MiB;
+	}
+
+	config->framebuffer_size = framebuffer_size_mb * MiB;
+	config->framebuffer_base = framebuffer_base_mb * MiB;
+
+	/*
+	 * The plld is programmed with the assumption of the SHIFT_CLK_DIVIDER
+	 * and PIXEL_CLK_DIVIDER are zero (divide by 1). See the
+	 * update_display_mode() for detail.
+	 */
+	/* set default plld */
+	plld_rate = clock_configure_plld(config->pixel_clock * 2);
+	if (plld_rate == 0) {
+		printk(BIOS_ERR, "dc: clock init failed\n");
+		return;
+	}
+
+	/* set disp1's clock source to PLLD_OUT0 */
+	clock_configure_source(disp1, PLLD_OUT0, (plld_rate/KHz));
+
+	/* Init dc */
+	if (tegra_dc_init(disp_ctrl)) {
+		printk(BIOS_ERR, "dc: init failed\n");
+		return;
+	}
+
+	/* Configure dc mode */
+	if (update_display_mode(disp_ctrl, config)) {
+		printk(BIOS_ERR, "dc: failed to configure display mode.\n");
+		return;
+	}
+
+	/* Configure and enable dsi controller and panel */
+	if (dsi_enable(config)) {
+		printk(BIOS_ERR, "%s: failed to enable dsi controllers.\n",
+			__func__);
+		return;
+	}
+
+	/* Set up window */
+	update_window(config);
+	printk(BIOS_INFO, "%s: display init done.\n", __func__);
+
+	/* Save panel information to cb tables */
+	pass_mode_info_to_payload(config);
+
+	/*
+	 * After this point, it is payload's responsibility to allocate
+	 * framebuffer and sets the base address to dc's
+	 * WINBUF_START_ADDR register and enables window by setting dc's
+	 * DISP_DISP_WIN_OPTIONS register.
+	 */
+}
diff --git a/src/soc/nvidia/tegra210/flow_ctrl.c b/src/soc/nvidia/tegra210/flow_ctrl.c
new file mode 100644
index 0000000..825274d
--- /dev/null
+++ b/src/soc/nvidia/tegra210/flow_ctrl.c
@@ -0,0 +1,113 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (c) 2014, NVIDIA CORPORATION.  All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc.
+ */
+
+#include <arch/io.h>
+#include <soc/addressmap.h>
+#include <soc/flow_ctrl.h>
+
+#define FLOW_CTRL_HALT_CPU0_EVENTS	0x0
+#define FLOW_CTRL_WAITEVENT		(2 << 29)
+#define FLOW_CTRL_WAIT_FOR_INTERRUPT	(4 << 29)
+#define FLOW_CTRL_HALT_SCLK		(1 << 27)
+#define FLOW_CTRL_HALT_LIC_IRQ		(1 << 11)
+#define FLOW_CTRL_HALT_LIC_FIQ		(1 << 10)
+#define FLOW_CTRL_HALT_GIC_IRQ		(1 << 9)
+#define FLOW_CTRL_HALT_GIC_FIQ		(1 << 8)
+#define FLOW_CTRL_CPU0_CSR		0x8
+#define FLOW_CTRL_CSR_INTR_FLAG		(1 << 15)
+#define FLOW_CTRL_CSR_EVENT_FLAG	(1 << 14)
+#define FLOW_CTRL_CSR_WFI_CPU0		(1 << 8)
+#define FLOW_CTRL_CSR_WFI_BITMAP	(0xF << 8)
+#define FLOW_CTRL_CSR_WFE_BITMAP	(0xF << 4)
+#define FLOW_CTRL_CSR_ENABLE		(1 << 0)
+#define FLOW_CTRL_HALT_CPU1_EVENTS	0x14
+#define FLOW_CTRL_CPU1_CSR		0x18
+#define FLOW_CTRL_CC4_CORE0_CTRL	0x6c
+
+static void *tegra_flowctrl_base = (void*)TEGRA_FLOW_BASE;
+
+static const uint8_t flowctrl_offset_halt_cpu[] = {
+	FLOW_CTRL_HALT_CPU0_EVENTS,
+	FLOW_CTRL_HALT_CPU1_EVENTS,
+	FLOW_CTRL_HALT_CPU1_EVENTS + 8,
+	FLOW_CTRL_HALT_CPU1_EVENTS + 16
+};
+
+static const uint8_t flowctrl_offset_cpu_csr[] = {
+	FLOW_CTRL_CPU0_CSR,
+	FLOW_CTRL_CPU1_CSR,
+	FLOW_CTRL_CPU1_CSR + 8,
+	FLOW_CTRL_CPU1_CSR + 16
+};
+
+static const uint8_t flowctrl_offset_cc4_ctrl[] = {
+	FLOW_CTRL_CC4_CORE0_CTRL,
+	FLOW_CTRL_CC4_CORE0_CTRL + 4,
+	FLOW_CTRL_CC4_CORE0_CTRL + 8,
+	FLOW_CTRL_CC4_CORE0_CTRL + 12
+};
+
+void flowctrl_write_cpu_csr(int cpu, uint32_t val)
+{
+	write32(tegra_flowctrl_base + flowctrl_offset_cpu_csr[cpu], val);
+	val = read32(tegra_flowctrl_base + flowctrl_offset_cpu_csr[cpu]);
+}
+
+void flowctrl_write_cpu_halt(int cpu, uint32_t val)
+{
+	write32(tegra_flowctrl_base + flowctrl_offset_halt_cpu[cpu], val);
+	val = read32(tegra_flowctrl_base + flowctrl_offset_halt_cpu[cpu]);
+}
+
+void flowctrl_write_cc4_ctrl(int cpu, uint32_t val)
+{
+	write32(tegra_flowctrl_base + flowctrl_offset_cc4_ctrl[cpu], val);
+	val = read32(tegra_flowctrl_base + flowctrl_offset_cc4_ctrl[cpu]);
+}
+
+void flowctrl_cpu_off(int cpu)
+{
+	uint32_t val = FLOW_CTRL_CSR_INTR_FLAG | FLOW_CTRL_CSR_EVENT_FLAG |
+		FLOW_CTRL_CSR_ENABLE | (FLOW_CTRL_CSR_WFI_CPU0 << cpu);
+
+	flowctrl_write_cpu_csr(cpu, val);
+	flowctrl_write_cpu_halt(cpu, FLOW_CTRL_WAITEVENT);
+	flowctrl_write_cc4_ctrl(cpu, 0);
+}
+
+void flowctrl_cpu_on(int cpu)
+{
+	flowctrl_write_cpu_csr(cpu, FLOW_CTRL_CSR_ENABLE);
+	flowctrl_write_cpu_halt(cpu, FLOW_CTRL_WAITEVENT |
+				FLOW_CTRL_HALT_SCLK);
+}
+
+void flowctrl_cpu_suspend(int cpu)
+{
+	uint32_t val;
+
+	val = FLOW_CTRL_HALT_GIC_IRQ | FLOW_CTRL_HALT_GIC_FIQ |
+	      FLOW_CTRL_HALT_LIC_IRQ | FLOW_CTRL_HALT_LIC_FIQ |
+	      FLOW_CTRL_WAITEVENT;
+	flowctrl_write_cpu_halt(cpu, val);
+
+	val = FLOW_CTRL_CSR_INTR_FLAG | FLOW_CTRL_CSR_EVENT_FLAG |
+	      FLOW_CTRL_CSR_ENABLE | (FLOW_CTRL_CSR_WFI_CPU0 << cpu);
+	flowctrl_write_cpu_csr(cpu, val);
+}
diff --git a/src/soc/nvidia/tegra210/funitcfg.c b/src/soc/nvidia/tegra210/funitcfg.c
new file mode 100644
index 0000000..96b1204
--- /dev/null
+++ b/src/soc/nvidia/tegra210/funitcfg.c
@@ -0,0 +1,186 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright 2014 Google Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc.
+ */
+
+#include <arch/io.h>
+#include <soc/addressmap.h>
+#include <soc/clock.h>
+#include <soc/funitcfg.h>
+#include <soc/nvidia/tegra/usb.h>
+#include <soc/padconfig.h>
+#include <string.h>
+
+struct clk_dev_control {
+	uint32_t *clk_enb_set;
+	uint32_t *rst_dev_clr;
+};
+
+struct funit_cfg_data {
+	const char *name;
+	void *ctlr_base;
+	uint32_t *clk_src_reg;
+	const struct clk_dev_control * const dev_control;
+	uint32_t clk_enb_val;
+};
+
+enum {
+	CLK_L_SET = 0,
+	CLK_H_SET = 1,
+	CLK_U_SET = 2,
+	CLK_V_SET = 3,
+	CLK_W_SET = 4,
+	CLK_X_SET = 5,
+	CLK_Y_SET = 6,
+};
+
+#define CLK_SET_REGS(x)					\
+	{						\
+		CLK_RST_REG(clk_enb_##x##_set),		\
+		CLK_RST_REG(rst_dev_##x##_clr),		\
+	}
+
+static const struct clk_dev_control clk_data_arr[] = {
+	[CLK_L_SET] = CLK_SET_REGS(l),
+	[CLK_H_SET] = CLK_SET_REGS(h),
+	[CLK_U_SET] = CLK_SET_REGS(u),
+	[CLK_V_SET] = CLK_SET_REGS(v),
+	[CLK_W_SET] = CLK_SET_REGS(w),
+	[CLK_X_SET] = CLK_SET_REGS(x),
+	[CLK_Y_SET] = CLK_SET_REGS(y),
+};
+
+#define FUNIT_DATA(funit_, loname_, clk_set_)				\
+	[FUNIT_INDEX(funit_)] = {					\
+		.name = STRINGIFY(loname_),				\
+		.ctlr_base = (void *)(uintptr_t)TEGRA_##funit_##_BASE,	\
+		.clk_src_reg = CLK_RST_REG(clk_src_##loname_),		\
+		.dev_control = &clk_data_arr[CLK_##clk_set_##_SET],	\
+		.clk_enb_val = CLK_##clk_set_##_##funit_,		\
+	}
+
+#define FUNIT_DATA_USB(funit_, clk_set_)				\
+	[FUNIT_INDEX(funit_)] = {					\
+		.name = STRINGIFY(funit_),				\
+		.ctlr_base = (void *)(uintptr_t)TEGRA_##funit_##_BASE,	\
+		.dev_control = &clk_data_arr[CLK_##clk_set_##_SET],	\
+		.clk_enb_val = CLK_##clk_set_##_##funit_,		\
+	}
+
+static const struct funit_cfg_data funit_data[] =  {
+	FUNIT_DATA(I2C1, i2c1, L),
+	FUNIT_DATA(I2C2, i2c2, H),
+	FUNIT_DATA(I2C3, i2c3, U),
+	FUNIT_DATA(I2C5, i2c5, H),
+	FUNIT_DATA(I2C6, i2c6, X),
+	FUNIT_DATA(SDMMC1, sdmmc1, L),
+	FUNIT_DATA(SDMMC4, sdmmc4, L),
+	FUNIT_DATA_USB(USBD, L),
+	FUNIT_DATA_USB(USB2, H),
+	FUNIT_DATA(QSPI, qspi, Y),
+	FUNIT_DATA(I2S1, i2s1, L),
+};
+_Static_assert(ARRAY_SIZE(funit_data) == FUNIT_INDEX_MAX,
+		"funit_cfg_data array not filled out!");
+
+static inline uint32_t get_clk_src_freq(uint32_t clk_src_freq_id)
+{
+	uint32_t freq = 0;
+
+	switch (clk_src_freq_id) {
+	case CLK_M:
+		freq = TEGRA_CLK_M_KHZ;
+		break;
+	case PLLP:
+		freq = TEGRA_PLLP_KHZ;
+		break;
+	default:
+		printk(BIOS_SPEW, "%s ERROR: Unknown clk_src %d\n",
+		       __func__, clk_src_freq_id);
+	}
+
+	return freq;
+}
+
+static void configure_clock(const struct funit_cfg * const entry,
+				const struct funit_cfg_data * const funit)
+{
+	const char *funit_i2c = "i2c";
+	uint32_t clk_div;
+	uint32_t clk_div_mask;
+	uint32_t clk_src_freq;
+
+	clk_src_freq = get_clk_src_freq(entry->clk_src_freq_id);
+
+	if (strncmp(funit->name, funit_i2c, strlen(funit_i2c)) == 0) {
+		/* I2C funit */
+		clk_div = get_i2c_clk_div(clk_src_freq,
+					entry->clk_dev_freq_khz);
+		clk_div_mask = CLK_DIV_MASK_I2C;
+	} else {
+		/* Non I2C */
+		clk_div = get_clk_div(clk_src_freq, entry->clk_dev_freq_khz);
+		clk_div_mask = CLK_DIV_MASK;
+	}
+
+	_clock_set_div(funit->clk_src_reg, funit->name, clk_div,
+			clk_div_mask, entry->clk_src_id);
+}
+
+static inline int is_usb(uint32_t idx)
+{
+	return (idx == FUNIT_USBD || idx == FUNIT_USB2);
+}
+
+void soc_configure_funits(const struct funit_cfg * const entries, size_t num)
+{
+	size_t i;
+
+	for (i = 0; i < num; i++) {
+		const struct funit_cfg * const entry = &entries[i];
+		const struct funit_cfg_data *funit;
+		const struct clk_dev_control *dev_control;
+		int funit_usb = is_usb(entry->funit_index);
+
+		if (entry->funit_index >= FUNIT_INDEX_MAX) {
+			printk(BIOS_ERR, "Error: Index out of bounds\n");
+			continue;
+		}
+
+		funit = &funit_data[entry->funit_index];
+		dev_control = funit->dev_control;
+
+		/* USB controllers have a fixed clock source. */
+		if (!funit_usb)
+			configure_clock(entry, funit);
+
+		clock_grp_enable_clear_reset(funit->clk_enb_val,
+						dev_control->clk_enb_set,
+						dev_control->rst_dev_clr);
+
+		if (funit_usb)
+			usb_setup_utmip(funit->ctlr_base);
+
+		soc_configure_pads(entry->pad_cfg,entry->pad_cfg_size);
+	}
+}
+
+void __attribute__((weak)) usb_setup_utmip(void *usb_base)
+{
+	/* default empty implementation required if usb.c is not included */
+	printk(BIOS_ERR, "USB setup is not supported in current stage\n");
+}
diff --git a/src/soc/nvidia/tegra210/gic.c b/src/soc/nvidia/tegra210/gic.c
new file mode 100644
index 0000000..c8c09fb
--- /dev/null
+++ b/src/soc/nvidia/tegra210/gic.c
@@ -0,0 +1,31 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright 2014 Google Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc.
+ */
+
+#include <gic.h>
+#include <soc/addressmap.h>
+
+void *gicd_base(void)
+{
+	return (void *)(uintptr_t)TEGRA_GICD_BASE;
+}
+
+void *gicc_base(void)
+{
+	return (void *)(uintptr_t)TEGRA_GICC_BASE;
+}
diff --git a/src/soc/nvidia/tegra210/i2c.c b/src/soc/nvidia/tegra210/i2c.c
new file mode 100644
index 0000000..04a0c00
--- /dev/null
+++ b/src/soc/nvidia/tegra210/i2c.c
@@ -0,0 +1,57 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright 2014 Google Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc.
+ */
+
+#include <soc/addressmap.h>
+#include <soc/clock.h>
+#include <soc/nvidia/tegra/i2c.h>
+
+struct tegra_i2c_bus_info tegra_i2c_info[] = {
+	{
+		.base = (void *)TEGRA_I2C1_BASE,
+		.reset_bit = CLK_L_I2C1,
+		.reset_func = &clock_reset_l
+	},
+	{
+		.base = (void *)TEGRA_I2C2_BASE,
+		.reset_bit = CLK_H_I2C2,
+		.reset_func = &clock_reset_h
+	},
+	{
+		.base = (void *)TEGRA_I2C3_BASE,
+		.reset_bit = CLK_U_I2C3,
+		.reset_func = &clock_reset_u
+	},
+	{
+		.base = (void *)TEGRA_I2C4_BASE,
+		.reset_bit = CLK_V_I2C4,
+		.reset_func = &clock_reset_v
+	},
+	{
+		.base = (void *)TEGRA_I2C5_BASE,
+		.reset_bit = CLK_H_I2C5,
+		.reset_func = &clock_reset_h
+	},
+	{
+		.base = (void *)TEGRA_I2C6_BASE,
+		.reset_bit = CLK_X_I2C6,
+		.reset_func = &clock_reset_x
+	}
+};
+
+unsigned g_num_i2c_buses = ARRAY_SIZE(tegra_i2c_info);
diff --git a/src/soc/nvidia/tegra210/i2c6.c b/src/soc/nvidia/tegra210/i2c6.c
new file mode 100644
index 0000000..915a538
--- /dev/null
+++ b/src/soc/nvidia/tegra210/i2c6.c
@@ -0,0 +1,95 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (c) 2014-2015, NVIDIA CORPORATION.
+ * Copyright 2014 Google Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc.
+ */
+
+#include <delay.h>
+#include <soc/addressmap.h>
+#include <soc/clk_rst.h>
+#include <soc/clock.h>
+#include <soc/nvidia/tegra/i2c.h>
+#include <soc/padconfig.h>
+#include <soc/power.h>
+
+#define I2C6_PADCTL		0xC001
+#define DPAUX_HYBRID_PADCTL	0x545C0124
+#define DPAUX_HYBRID_SPARE	0x545C0134
+
+static void enable_sor_periph_clocks(void)
+{
+	clock_enable(CLK_L_HOST1X, 0, 0, 0, 0, CLK_X_DPAUX, 0);
+
+	/* Give clocks time to stabilize. */
+	udelay(IO_STABILIZATION_DELAY);
+}
+
+static void disable_sor_periph_clocks(void)
+{
+	clock_disable(CLK_L_HOST1X, 0, 0, 0, 0, CLK_X_DPAUX, 0);
+
+	/* Give clocks time to stabilize. */
+	udelay(IO_STABILIZATION_DELAY);
+}
+
+static void unreset_sor_periphs(void)
+{
+	clock_clr_reset(CLK_L_HOST1X, 0, 0, 0, 0, CLK_X_DPAUX, 0);
+}
+
+void soc_configure_i2c6pad(void)
+{
+	/*
+	 * I2C6 on Tegra1xx requires some special init.
+	 * The SOR block must be unpowergated, and a couple of
+	 * display-based peripherals must be clocked and taken
+	 * out of reset so that a DPAUX register can be
+	 * configured to enable the I2C6 mux routing.
+	 * Afterwards, we can disable clocks to the display blocks
+	 * and put Host1X back in reset. DPAUX must remain out of
+	 * reset and the SOR partition must remained unpowergated.
+	 */
+	soc_configure_host1x();
+
+	/* Now we can write the I2C6 mux in DPAUX */
+	write32((void *)DPAUX_HYBRID_PADCTL, I2C6_PADCTL);
+	/* Finally, power up the pads */
+	write32((void *)DPAUX_HYBRID_SPARE, 0);
+
+	/*
+	 * Delay before turning off Host1X/DPAUX clocks.
+	 * This delay is needed to keep the sequence from
+	 * hanging the system.
+	 */
+	udelay(CLOCK_PLL_STABLE_DELAY_US);
+
+	/* Stop Host1X/DPAUX clocks and reset Host1X */
+	disable_sor_periph_clocks();
+	clock_set_reset_l(CLK_L_HOST1X);
+}
+
+void soc_configure_host1x(void)
+{
+	power_ungate_partition(POWER_PARTID_SOR);
+
+	/* Host1X needs a valid clock source so DPAUX can be accessed. */
+	clock_configure_source(host1x, PLLP, 204000);
+
+	enable_sor_periph_clocks();
+	remove_clamps(POWER_PARTID_SOR);
+	unreset_sor_periphs();
+}
diff --git a/src/soc/nvidia/tegra210/include/soc/addressmap.h b/src/soc/nvidia/tegra210/include/soc/addressmap.h
new file mode 100644
index 0000000..19611da
--- /dev/null
+++ b/src/soc/nvidia/tegra210/include/soc/addressmap.h
@@ -0,0 +1,142 @@
+/*
+ * Copyright (c) 2013-2015, NVIDIA CORPORATION.  All rights reserved.
+ * Copyright 2014 Google Inc.
+ *
+ * (C) Copyright 2010,2011
+ * NVIDIA Corporation <www.nvidia.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __SOC_NVIDIA_TEGRA210_INCLUDE_SOC_ADDRESS_MAP_H__
+#define __SOC_NVIDIA_TEGRA210_INCLUDE_SOC_ADDRESS_MAP_H__
+
+#include <stddef.h>
+#include <stdint.h>
+
+enum {
+	TEGRA_SRAM_BASE = 0x40000000,
+	TEGRA_SRAM_SIZE = 0x40000
+};
+
+enum {
+	TEGRA_ARM_PERIPHBASE =		0x50040000,
+	TEGRA_GICD_BASE =		0x50041000,
+	TEGRA_GICC_BASE =		0x50042000,
+	TEGRA_ARM_DISPLAYA =            0x54200000,
+	TEGRA_ARM_DISPLAYB =            0x54240000,
+	TEGRA_DSIA_BASE =               0x54300000,
+	TEGRA_DSIB_BASE =               0x54400000,
+	TEGRA_ARM_SOR =                 0x54540000,
+	TEGRA_ARM_DPAUX =               0x545c0000,
+	TEGRA_PG_UP_BASE =		0x60000000,
+	TEGRA_TMRUS_BASE =		0x60005010,
+	TEGRA_CLK_RST_BASE =		0x60006000,
+	TEGRA_FLOW_BASE =		0x60007000,
+	TEGRA_SB_BASE =			0x6000C200,
+	TEGRA_GPIO_BASE =		0x6000D000,
+	TEGRA_EVP_BASE =		0x6000F000,
+	TEGRA_APB_DMA_BASE =		0x60020000,
+	TEGRA_APB_MISC_BASE =		0x70000000,
+	TEGRA_APB_MISC_GP_BASE =	TEGRA_APB_MISC_BASE + 0x0800,
+	TEGRA_APB_PINGROUP_BASE =	TEGRA_APB_MISC_BASE + 0x0868,
+	TEGRA_APB_PINMUX_BASE =		TEGRA_APB_MISC_BASE + 0x3000,
+	TEGRA_APB_UARTA_BASE =		TEGRA_APB_MISC_BASE + 0x6000,
+	TEGRA_APB_UARTB_BASE =		TEGRA_APB_MISC_BASE + 0x6040,
+	TEGRA_APB_UARTC_BASE =		TEGRA_APB_MISC_BASE + 0x6200,
+	TEGRA_APB_UARTD_BASE =		TEGRA_APB_MISC_BASE + 0x6300,
+	TEGRA_APB_UARTE_BASE =		TEGRA_APB_MISC_BASE + 0x6400,
+	TEGRA_NAND_BASE =		TEGRA_APB_MISC_BASE + 0x8000,
+	TEGRA_PWM_BASE =		TEGRA_APB_MISC_BASE + 0xA000,
+	TEGRA_I2C1_BASE =		TEGRA_APB_MISC_BASE + 0xC000,
+	TEGRA_SPI_BASE =		TEGRA_APB_MISC_BASE + 0xC380,
+	TEGRA_I2C2_BASE =		TEGRA_APB_MISC_BASE + 0xC400,
+	TEGRA_I2C3_BASE =		TEGRA_APB_MISC_BASE + 0xC500,
+	TEGRA_I2C4_BASE =		TEGRA_APB_MISC_BASE + 0xC700,
+	TEGRA_I2C5_BASE =		TEGRA_APB_MISC_BASE + 0xD000,
+	TEGRA_I2C6_BASE =		TEGRA_APB_MISC_BASE + 0xD100,
+	TEGRA_SPI1_BASE =		TEGRA_APB_MISC_BASE + 0xD400,
+	TEGRA_SPI2_BASE =		TEGRA_APB_MISC_BASE + 0xD600,
+	TEGRA_SPI3_BASE =		TEGRA_APB_MISC_BASE + 0xD800,
+	TEGRA_SPI4_BASE =		TEGRA_APB_MISC_BASE + 0xDA00,
+	TEGRA_SPI5_BASE =		TEGRA_APB_MISC_BASE + 0xDC00,
+	TEGRA_SPI6_BASE =		TEGRA_APB_MISC_BASE + 0xDE00,
+	TEGRA_SBC1_BASE =		TEGRA_SPI1_BASE,
+	TEGRA_SBC2_BASE =		TEGRA_SPI2_BASE,
+	TEGRA_SBC3_BASE =		TEGRA_SPI3_BASE,
+	TEGRA_SBC4_BASE =		TEGRA_SPI4_BASE,
+	TEGRA_SBC5_BASE =		TEGRA_SPI5_BASE,
+	TEGRA_SBC6_BASE =		TEGRA_SPI6_BASE,
+	TEGRA_PMC_BASE =		TEGRA_APB_MISC_BASE + 0xE400,
+	TEGRA_FUSE_BASE =		TEGRA_APB_MISC_BASE + 0xF800,
+	TEGRA_MC_BASE =			0x70019000,
+	TEGRA_EMC_BASE =		0x7001B000,
+	TEGRA_CLUSTER_CLOCK_BASE =	0x70040000,
+	TEGRA_QSPI_BASE =		0x70410000,
+	TEGRA_CSITE_BASE =		0x70800000,
+	TEGRA_SDMMC_BASE =		0x700b0000,
+	TEGRA_SDMMC1_BASE =		TEGRA_SDMMC_BASE + 0x0000,
+	TEGRA_SDMMC2_BASE =		TEGRA_SDMMC_BASE + 0x0200,
+	TEGRA_SDMMC3_BASE =		TEGRA_SDMMC_BASE + 0x0400,
+	TEGRA_SDMMC4_BASE =		TEGRA_SDMMC_BASE + 0x0600,
+	TEGRA_MIPI_CAL_BASE =		0x700E3000,
+	TEGRA_SYSCTR0_BASE =		0x700F0000,
+	TEGRA_I2S1_BASE =		0x70301100,
+	TEGRA_USBD_BASE =		0x7D000000,
+	TEGRA_USB2_BASE =		0x7D004000,
+	TEGRA_USB3_BASE =		0x7D008000,
+};
+
+enum {
+	TEGRA_I2C_BASE_COUNT = 6,
+};
+
+#define GPU_CARVEOUT_SIZE_MB            1
+
+/* Return total size of DRAM memory configured on the platform. */
+int sdram_size_mb(void);
+
+/* Find memory below and above 4GiB boundary repsectively. All units 1MiB. */
+void memory_in_range_below_4gb(uintptr_t *base_mib, uintptr_t *end_mib);
+void memory_in_range_above_4gb(uintptr_t *base_mib, uintptr_t *end_mib);
+
+enum {
+	CARVEOUT_TZ,
+	CARVEOUT_SEC,
+	CARVEOUT_MTS,
+	CARVEOUT_VPR,
+	CARVEOUT_GPU,
+	CARVEOUT_NUM,
+};
+
+/* Provided the careout id, obtain the base and size in 1MiB units. */
+void carveout_range(int id, uintptr_t *base_mib, size_t *size_mib);
+
+/*
+ * Add any board-specific memory ranges to the address map when executing
+ * on aarchv8 core.
+ */
+struct memranges;
+void mainboard_add_memory_ranges(struct memranges *map);
+
+/*
+ * There are complications accessing the Trust Zone carveout region. The
+ * AVP cannot access these registers and the CPU can't access this register
+ * as a non-secure access. When the page tables live in non-secure memory
+ * these registers cannot be accessed either. Thus, this function handles
+ * both the AVP case and non-secured access case by keeping global state.
+ */
+void trustzone_region_init(void);
+void gpu_region_init(void);
+
+#endif /* __SOC_NVIDIA_TEGRA210_INCLUDE_SOC_ADDRESS_MAP_H__ */
diff --git a/src/soc/nvidia/tegra210/include/soc/ccplex.h b/src/soc/nvidia/tegra210/include/soc/ccplex.h
new file mode 100644
index 0000000..d1aaa8b
--- /dev/null
+++ b/src/soc/nvidia/tegra210/include/soc/ccplex.h
@@ -0,0 +1,33 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright 2014 Google Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc.
+ */
+
+#ifndef __SOC_NVIDIA_TEGRA210_CCPLEX_H__
+#define __SOC_NVIDIA_TEGRA210_CCPLEX_H__
+
+#include <stdint.h>
+
+#define MTS_LOAD_ADDRESS 0x82000000
+
+/* Prepare the clocks and rails to start the cpu. */
+void ccplex_cpu_prepare(void);
+
+/* Start cpu0 and have it start executing at entry_addr */
+void ccplex_cpu_start(void *entry_addr);
+
+#endif /* __SOC_NVIDIA_TEGRA210_CCPLEX_H__ */
diff --git a/src/soc/nvidia/tegra210/include/soc/clk_rst.h b/src/soc/nvidia/tegra210/include/soc/clk_rst.h
new file mode 100644
index 0000000..aa25c87
--- /dev/null
+++ b/src/soc/nvidia/tegra210/include/soc/clk_rst.h
@@ -0,0 +1,599 @@
+/*
+ * Copyright (c) 2013-2015, NVIDIA CORPORATION.  All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _TEGRA210_CLK_RST_H_
+#define _TEGRA210_CLK_RST_H_
+#include <stdint.h>
+#include <stddef.h>
+
+/* Clock/Reset Controller (CLK_RST_CONTROLLER_) regs */
+struct  __attribute__ ((__packed__)) clk_rst_ctlr {
+	u32 rst_src;			/* _RST_SOURCE,             0x000 */
+	u32 rst_dev_l;			/* _RST_DEVICES_L,          0x004 */
+	u32 rst_dev_h;			/* _RST_DEVICES_H,          0x008 */
+	u32 rst_dev_u;			/* _RST_DEVICES_U,          0x00c */
+	u32 clk_out_enb_l;		/* _CLK_OUT_ENB_L,          0x010 */
+	u32 clk_out_enb_h;		/* _CLK_OUT_ENB_H,          0x014 */
+	u32 clk_out_enb_u;		/* _CLK_OUT_ENB_U,          0x018 */
+	u32 _rsv0;			/*                          0x01c */
+	u32 cclk_brst_pol;		/* _CCLK_BURST_POLICY,      0x020 */
+	u32 super_cclk_div;		/* _SUPER_CCLK_DIVIDER,     0x024 */
+	u32 sclk_brst_pol;		/* _SCLK_BURST_POLICY,      0x028 */
+	u32 super_sclk_div;		/* _SUPER_SCLK_DIVIDER,     0x02C */
+	u32 clk_sys_rate;		/* _CLK_SYSTEM_RATE,        0x030 */
+	u32 _rsv1[3];			/*                      0x034-03c */
+	u32 cop_clk_skip_plcy;		/* _COP_CLK_SKIP_POLICY,    0x040 */
+	u32 clk_mask_arm;		/* _CLK_MASK_ARM,           0x044 */
+	u32 misc_clk_enb;		/* _MISC_CLK_ENB,           0x048 */
+	u32 clk_cpu_cmplx;		/* _CLK_CPU_CMPLX,          0x04C */
+	u32 osc_ctrl;			/* _OSC_CTRL,               0x050 */
+	u32 pll_lfsr;			/* _PLL_LFSR,               0x054 */
+	u32 osc_freq_det;		/* _OSC_FREQ_DET,           0x058 */
+	u32 osc_freq_det_stat;		/* _OSC_FREQ_DET_STATUS,    0x05C */
+	u32 _rsv2[8];			/*                      0x060-07C */
+	u32 pllc_base;			/* _PLLC_BASE,              0x080 */
+	u32 pllc_out;			/* _PLLC_OUT,               0x084 */
+	u32 pllc_misc;			/* _PLLC_MISC,              0x088 */
+	u32 pllc_misc_1;		/* _PLLC_MISC_1,            0x08c */
+	u32 pllm_base;			/* _PLLM_BASE,              0x090 */
+	u32 pllm_out;			/* _PLLM_OUT,               0x094 */
+	u32 pllm_misc1;			/* _PLLM_MISC1,             0x098 */
+	u32 pllm_misc2;			/* _PLLM_MISC2,             0x09c */
+	u32 pllp_base;			/* _PLLP_BASE,              0x0a0 */
+	u32 pllp_outa;			/* _PLLP_OUTA,              0x0a4 */
+	u32 pllp_outb;			/* _PLLP_OUTB,              0x0a8 */
+	u32 pllp_misc;			/* _PLLP_MISC,              0x0ac */
+	u32 plla_base;			/* _PLLA_BASE,              0x0b0 */
+	u32 plla_out;			/* _PLLA_OUT,               0x0b4 */
+	u32 _rsv3;			/*                          0x0b8 */
+	u32 plla_misc;			/* _PLLA_MISC,              0x0bc */
+	u32 pllu_base;			/* _PLLU_BASE,              0x0c0 */
+	u32 _rsv4[2];			/*                      0x0c4-0c8 */
+	u32 pllu_misc;			/* _PLLU_MISC,              0x0cc */
+	u32 plld_base;			/* _PLLD_BASE,              0x0d0 */
+	u32 _rsv5[1];			/*                          0x0d4 */
+	u32 plld_misc1;			/* _PLLD_MISC1,             0x0d8 */
+	u32 plld_misc;			/* _PLLD_MISC,              0x0dc */
+	u32 pllx_base;			/* _PLLX_BASE,              0x0e0 */
+	u32 pllx_misc;			/* _PLLX_MISC,              0x0e4 */
+	u32 plle_base;			/* _PLLE_BASE,              0x0e8 */
+	u32 plle_misc;			/* _PLLE_MISC,              0x0ec */
+	u32 plls_base;			/* _PLLS_BASE,              0x0f0 */
+	u32 plls_misc;			/* _PLLS_MISC,              0x0f4 */
+	u32 _rsv6[2];			/*                      0x0f8-0fc */
+        u32 clk_src_i2s1;		/* _CLK_SOURCE_I2S1,        0x100 */
+        u32 clk_src_i2s2;		/* _CLK_SOURCE_I2S2,        0x104 */
+        u32 clk_src_spdif_out;		/* _CLK_SOURCE_SPDIF_OUT,   0x108 */
+        u32 clk_src_spdif_in;		/* _CLK_SOURCE_SPDIF_IN,    0x10c */
+        u32 clk_src_pwm;		/* _CLK_SOURCE_PWM,         0x110 */
+        u32 _rsv7;			/*                          0x114 */
+        u32 clk_src_sbc2;		/* _CLK_SOURCE_SBC2,        0x118 */
+        u32 clk_src_sbc3;		/* _CLK_SOURCE_SBC3,        0x11c */
+        u32 _rsv8;			/*                          0x120 */
+        u32 clk_src_i2c1;		/* _CLK_SOURCE_I2C1,        0x124 */
+        u32 clk_src_i2c5;		/* _CLK_SOURCE_I2C5,        0x128 */
+        u32 _rsv9[2];			/*                      0x12c-130 */
+        u32 clk_src_sbc1;		/* _CLK_SOURCE_SBC1,        0x134 */
+        u32 clk_src_disp1;		/* _CLK_SOURCE_DISP1,       0x138 */
+        u32 clk_src_disp2;		/* _CLK_SOURCE_DISP2,       0x13c */
+        u32 _rsv10[2];			/*                      0x140-144 */
+        u32 clk_src_vi;			/* _CLK_SOURCE_VI,          0x148 */
+        u32 _rsv11;			/*                          0x14c */
+        u32 clk_src_sdmmc1;		/* _CLK_SOURCE_SDMMC1,      0x150 */
+        u32 clk_src_sdmmc2;		/* _CLK_SOURCE_SDMMC2,      0x154 */
+        u32 clk_src_g3d;		/* _CLK_SOURCE_G3D,         0x158 */
+        u32 clk_src_g2d;		/* _CLK_SOURCE_G2D,         0x15c */
+        u32 clk_src_ndflash;		/* _CLK_SOURCE_NDFLASH,     0x160 */
+        u32 clk_src_sdmmc4;		/* _CLK_SOURCE_SDMMC4,      0x164 */
+        u32 clk_src_vfir;		/* _CLK_SOURCE_VFIR,        0x168 */
+        u32 clk_src_epp;		/* _CLK_SOURCE_EPP,         0x16c */
+        u32 clk_src_mpe;		/* _CLK_SOURCE_MPE,         0x170 */
+        u32 clk_src_hsi;		/* _CLK_SOURCE_HSI,         0x174 */
+        u32 clk_src_uarta;		/* _CLK_SOURCE_UARTA,       0x178 */
+        u32 clk_src_uartb;		/* _CLK_SOURCE_UARTB,       0x17c */
+        u32 clk_src_host1x;		/* _CLK_SOURCE_HOST1X,      0x180 */
+        u32 _rsv12[2];			/*                      0x184-188 */
+        u32 clk_src_hdmi;		/* _CLK_SOURCE_HDMI,        0x18c */
+        u32 _rsv13[2];			/*                      0x190-194 */
+        u32 clk_src_i2c2;		/* _CLK_SOURCE_I2C2,        0x198 */
+        u32 clk_src_emc;		/* _CLK_SOURCE_EMC,         0x19c */
+        u32 clk_src_uartc;		/* _CLK_SOURCE_UARTC,       0x1a0 */
+	u32 _rsv14;			/*                          0x1a4 */
+        u32 clk_src_vi_sensor;		/* _CLK_SOURCE_VI_SENSOR,   0x1a8 */
+        u32 _rsv15[2];			/*                      0x1ac-1b0 */
+        u32 clk_src_sbc4;		/* _CLK_SOURCE_SBC4,        0x1b4 */
+        u32 clk_src_i2c3;		/* _CLK_SOURCE_I2C3,        0x1b8 */
+        u32 clk_src_sdmmc3;		/* _CLK_SOURCE_SDMMC3,      0x1bc */
+        u32 clk_src_uartd;		/* _CLK_SOURCE_UARTD,       0x1c0 */
+        u32 clk_src_uarte;		/* _CLK_SOURCE_UARTE,       0x1c4 */
+        u32 clk_src_vde;		/* _CLK_SOURCE_VDE,         0x1c8 */
+        u32 clk_src_owr;		/* _CLK_SOURCE_OWR,         0x1cc */
+        u32 clk_src_nor;		/* _CLK_SOURCE_NOR,         0x1d0 */
+        u32 clk_src_csite;		/* _CLK_SOURCE_CSITE,       0x1d4 */
+        u32 clk_src_i2s0;		/* _CLK_SOURCE_I2S0,        0x1d8 */
+        u32 clk_src_dtv;		/* _CLK_SOURCE_DTV,         0x1dc */
+        u32 _rsv16[4];			/*                      0x1e0-1ec */
+        u32 clk_src_msenc;		/* _CLK_SOURCE_MSENC,       0x1f0 */
+        u32 clk_src_tsec;		/* _CLK_SOURCE_TSEC,        0x1f4 */
+	u32 _rsv17;			/*                          0x1f8 */
+        u32 clk_src_osc;		/* _CLK_SOURCE_OSC,         0x1fc */
+	u32 _rsv18[32];			/*                      0x200-27c */
+	u32 clk_out_enb_x;		/* _CLK_OUT_ENB_X_0,        0x280 */
+	u32 clk_enb_x_set;		/* _CLK_ENB_X_SET_0,        0x284 */
+	u32 clk_enb_x_clr;		/* _CLK_ENB_X_CLR_0,        0x288 */
+	u32 rst_dev_x;			/* _RST_DEVICES_X_0,        0x28c */
+	u32 rst_dev_x_set;		/* _RST_DEV_X_SET_0,        0x290 */
+	u32 rst_dev_x_clr;		/* _RST_DEV_X_CLR_0,        0x294 */
+	u32 clk_out_enb_y;		/* _CLK_OUT_ENB_Y_0,        0x298 */
+	u32 clk_enb_y_set;		/* _CLK_ENB_Y_SET_0,        0x29C */
+	u32 clk_enb_y_clr;		/* _CLK_ENB_Y_CLR_0,        0x2A0 */
+	u32 rst_dev_y;			/* _RST_DEVICES_Y_0,        0x2A4 */
+	u32 rst_dev_y_set;		/* _RST_DEV_Y_SET_0,        0x2A8 */
+	u32 rst_dev_y_clr;		/* _RST_DEV_Y_CLR_0,        0x2AC */
+	u32 _rsv19[17];		/*                      0x2B0-2f0 */
+	u32 dfll_base;			/* _DFLL_BASE_0,            0x2f4 */
+	u32 _rsv20[2];			/*                      0x2f8-2fc */
+	u32 rst_dev_l_set;		/* _RST_DEV_L_SET           0x300 */
+	u32 rst_dev_l_clr;		/* _RST_DEV_L_CLR           0x304 */
+	u32 rst_dev_h_set;		/* _RST_DEV_H_SET           0x308 */
+	u32 rst_dev_h_clr;		/* _RST_DEV_H_CLR           0x30c */
+	u32 rst_dev_u_set;		/* _RST_DEV_U_SET           0x310 */
+	u32 rst_dev_u_clr;		/* _RST_DEV_U_CLR           0x314 */
+	u32 _rsv21[2];			/*                      0x318-31c */
+	u32 clk_enb_l_set;		/* _CLK_ENB_L_SET           0x320 */
+	u32 clk_enb_l_clr;		/* _CLK_ENB_L_CLR           0x324 */
+	u32 clk_enb_h_set;		/* _CLK_ENB_H_SET           0x328 */
+	u32 clk_enb_h_clr;		/* _CLK_ENB_H_CLR           0x32c */
+	u32 clk_enb_u_set;		/* _CLK_ENB_U_SET           0x330 */
+	u32 clk_enb_u_clr;		/* _CLK_ENB_U_CLR           0x334 */
+	u32 _rsv22;			/*                          0x338 */
+	u32 ccplex_pg_sm_ovrd;		/* _CCPLEX_PG_SM_OVRD,      0x33c */
+	u32 rst_cpu_cmplx_set;		/* _RST_CPU_CMPLX_SET,      0x340 */
+	u32 rst_cpu_cmplx_clr;		/* _RST_CPU_CMPLX_CLR,      0x344 */
+	u32 clk_cpu_cmplx_set;		/* _CLK_CPU_CMPLX_SET,      0x348 */
+	u32 clk_cpu_cmplx_clr;		/* _CLK_CPU_CMPLX_SET,      0x34c */
+	u32 _rsv23[2];			/*                      0x350-354 */
+	u32 rst_dev_v;			/* _RST_DEVICES_V,          0x358 */
+	u32 rst_dev_w;			/* _RST_DEVICES_W,          0x35c */
+	u32 clk_out_enb_v;		/* _CLK_OUT_ENB_V,          0x360 */
+	u32 clk_out_enb_w;		/* _CLK_OUT_ENB_W,          0x364 */
+	u32 cclkg_brst_pol;		/* _CCLKG_BURST_POLICY,     0x368 */
+	u32 super_cclkg_div;		/* _SUPER_CCLKG_DIVIDER,    0x36c */
+	u32 cclklp_brst_pol;		/* _CCLKLP_BURST_POLICY,    0x370 */
+	u32 super_cclkp_div;		/* _SUPER_CCLKLP_DIVIDER,   0x374 */
+	u32 clk_cpug_cmplx;		/* _CLK_CPUG_CMPLX,         0x378 */
+	u32 clk_cpulp_cmplx;		/* _CLK_CPULP_CMPLX,        0x37c */
+	u32 cpu_softrst_ctrl;		/* _CPU_SOFTRST_CTRL,       0x380 */
+	u32 cpu_softrst_ctrl1;		/* _CPU_SOFTRST_CTRL1,      0x384 */
+	u32 cpu_softrst_ctrl2;		/* _CPU_SOFTRST_CTRL2,      0x388 */
+	u32 _rsv24[9];			/*                      0x38c-3ac */
+	u32 clk_src_g3d2;		/* _CLK_SOURCE_G3D2,        0x3b0 */
+	u32 clk_src_mselect;		/* _CLK_SOURCE_MSELECT,     0x3b4 */
+	u32 clk_src_tsensor;		/* _CLK_SOURCE_TSENSOR,     0x3b8 */
+	u32 clk_src_i2s3;		/* _CLK_SOURCE_I2S3,        0x3bc */
+	u32 clk_src_i2s4;		/* _CLK_SOURCE_I2S4,        0x3c0 */
+	u32 clk_src_i2c4;		/* _CLK_SOURCE_I2C4,        0x3c4 */
+	u32 clk_src_sbc5;		/* _CLK_SOURCE_SBC5,        0x3c8 */
+	u32 clk_src_sbc6;		/* _CLK_SOURCE_SBC6,        0x3cc */
+	u32 clk_src_audio;		/* _CLK_SOURCE_AUDIO,       0x3d0 */
+	u32 _rsv25;			/*                          0x3d4 */
+	u32 clk_src_dam0;		/* _CLK_SOURCE_DAM0,        0x3d8 */
+	u32 clk_src_dam1;		/* _CLK_SOURCE_DAM1,        0x3dc */
+	u32 clk_src_dam2;		/* _CLK_SOURCE_DAM2,        0x3e0 */
+	u32 clk_src_hda2codec_2x;	/* _CLK_SOURCE_HDA2CODEC_2X,0x3e4 */
+	u32 clk_src_actmon;		/* _CLK_SOURCE_ACTMON,      0x3e8 */
+	u32 clk_src_extperiph1;		/* _CLK_SOURCE_EXTPERIPH1,  0x3ec */
+	u32 clk_src_extperiph2;		/* _CLK_SOURCE_EXTPERIPH2,  0x3f0 */
+	u32 clk_src_extperiph3;		/* _CLK_SOURCE_EXTPERIPH3,  0x3f4 */
+	u32 clk_src_nand_speed;		/* _CLK_SOURCE_NAND_SPEED,  0x3f8 */
+	u32 clk_src_i2c_slow;		/* _CLK_SOURCE_I2C_SLOW,    0x3fc */
+	u32 clk_src_sys;		/* _CLK_SOURCE_SYS,         0x400 */
+	u32 _rsv26[4];			/*                      0x404-410 */
+	u32 clk_src_sor;		/* _CLK_SOURCE_SOR_0,       0x414 */
+	u32 _rsv261[2];			/*                      0x404-410 */
+	u32 clk_src_sata_oob;		/* _CLK_SOURCE_SATA_OOB,    0x420 */
+	u32 clk_src_sata;		/* _CLK_SOURCE_SATA,        0x424 */
+	u32 clk_src_hda;		/* _CLK_SOURCE_HDA,         0x428 */
+	u32 _rsv27;			/*                          0x42c */
+	u32 rst_dev_v_set;		/* _RST_DEV_V_SET,          0x430 */
+	u32 rst_dev_v_clr;		/* _RST_DEV_V_CLR,          0x434 */
+	u32 rst_dev_w_set;		/* _RST_DEV_W_SET,          0x438 */
+	u32 rst_dev_w_clr;		/* _RST_DEV_W_CLR,          0x43c */
+	u32 clk_enb_v_set;		/* _CLK_ENB_V_SET,          0x440 */
+	u32 clk_enb_v_clr;		/* _CLK_ENB_V_CLR,          0x444 */
+	u32 clk_enb_w_set;		/* _CLK_ENB_W_SET,          0x448 */
+	u32 clk_enb_w_clr;		/* _CLK_ENB_W_CLR,          0x44c */
+	u32 rst_cpug_cmplx_set;		/* _RST_CPUG_CMPLX_SET,     0x450 */
+	u32 rst_cpug_cmplx_clr;		/* _RST_CPUG_CMPLX_CLR,     0x454 */
+	u32 rst_cpulp_cmplx_set;	/* _RST_CPULP_CMPLX_SET,    0x458 */
+	u32 rst_cpulp_cmplx_clr;	/* _RST_CPULP_CMPLX_CLR,    0x45C */
+	u32 clk_cpug_cmplx_set;		/* _CLK_CPUG_CMPLX_SET,     0x460 */
+	u32 clk_cpug_cmplx_clr;		/* _CLK_CPUG_CMPLX_CLR,     0x464 */
+	u32 clk_cpulp_cmplx_set;	/* _CLK_CPULP_CMPLX_SET,    0x468 */
+	u32 clk_cpulp_cmplx_clr;	/* _CLK_CPULP_CMPLX_CLR,    0x46c */
+	u32 cpu_cmplx_status;		/* _CPU_CMPLX_STATUS,       0x470 */
+	u32 _rsv28;			/*                          0x474 */
+	u32 intstatus;			/* _INTSTATUS,              0x478 */
+	u32 intmask;			/* _INTMASK,                0x47c */
+	u32 utmip_pll_cfg0;		/* _UTMIP_PLL_CFG0,         0x480 */
+	u32 utmip_pll_cfg1;		/* _UTMIP_PLL_CFG1,         0x484 */
+	u32 utmip_pll_cfg2;		/* _UTMIP_PLL_CFG2,         0x488 */
+	u32 plle_aux;			/* _PLLE_AUX,               0x48c */
+	u32 sata_pll_cfg0;		/* _SATA_PLL_CFG0,          0x490 */
+	u32 sata_pll_cfg1;		/* _SATA_PLL_CFG1,          0x494 */
+	u32 pcie_pll_cfg0;		/* _PCIE_PLL_CFG0,          0x498 */
+	u32 prog_audio_dly_clk;		/* _PROG_AUDIO_DLY_CLK,     0x49c */
+	u32 audio_sync_clk_i2s0;	/* _AUDIO_SYNC_CLK_I2S0,    0x4a0 */
+	u32 audio_sync_clk_i2s1;	/* _AUDIO_SYNC_CLK_I2S1,    0x4a4 */
+	u32 audio_sync_clk_i2s2;	/* _AUDIO_SYNC_CLK_I2S2,    0x4a8 */
+	u32 audio_sync_clk_i2s3;	/* _AUDIO_SYNC_CLK_I2S3,    0x4ac */
+	u32 audio_sync_clk_i2s4;	/* _AUDIO_SYNC_CLK_I2S4,    0x4b0 */
+	u32 audio_sync_clk_spdif;	/* _AUDIO_SYNC_CLK_SPDIF,   0x4b4 */
+	u32 plld2_base;			/* _PLLD2_BASE,             0x4b8 */
+	u32 plld2_misc;			/* _PLLD2_MISC,             0x4bc */
+	u32 utmip_pll_cfg3;		/* _UTMIP_PLL_CFG3,         0x4c0 */
+	u32 pllrefe_base;		/* _PLLREFE_BASE,           0x4c4 */
+	u32 pllrefe_misc;		/* _PLLREFE_MISC,           0x4c8 */
+	u32 _rsv29[7];			/*                      0x4cc-4e4 */
+	u32 pllc2_base;			/* _PLLC2_BASE,             0x4e8 */
+	u32 pllc2_misc0;		/* _PLLC2_MISC_0,           0x4ec */
+	u32 pllc2_misc1;		/* _PLLC2_MISC_1,           0x4f0 */
+	u32 pllc2_misc2;		/* _PLLC2_MISC_2,           0x4f4 */
+	u32 pllc2_misc3;		/* _PLLC2_MISC_3,           0x4f8 */
+	u32 pllc3_base;			/* _PLLC3_BASE,             0x4fc */
+	u32 pllc3_misc0;		/* _PLLC3_MISC_0,           0x500 */
+	u32 pllc3_misc1;		/* _PLLC3_MISC_1,           0x504 */
+	u32 pllc3_misc2;		/* _PLLC3_MISC_2,           0x508 */
+	u32 pllc3_misc3;		/* _PLLC3_MISC_3,           0x50c */
+	u32 pllx_misc1;			/* _PLLX_MISC_1,            0x510 */
+	u32 pllx_misc2;			/* _PLLX_MISC_2,            0x514 */
+	u32 pllx_misc3;			/* _PLLX_MISC_3,            0x518 */
+	u32 xusbio_pll_cfg0;		/* _XUSBIO_PLL_CFG0,        0x51c */
+	u32 xusbio_pll_cfg1;		/* _XUSBIO_PLL_CFG1,        0x520 */
+	u32 plle_aux1;			/* _PLLE_AUX1,              0x524 */
+	u32 pllp_reshift;		/* _PLLP_RESHIFT,           0x528 */
+	u32 utmipll_hw_pwrdn_cfg0;	/* _UTMIPLL_HW_PWRDN_CFG0,  0x52c */
+	u32 pllu_hw_pwrdn_cfg0;		/* _PLLU_HW_PWRDN_CFG0,     0x530 */
+	u32 xusb_pll_cfg0;		/* _XUSB_PLL_CFG0,          0x534 */
+	u32 _rsv30;			/*                          0x538 */
+	u32 clk_cpu_misc;		/* _CLK_CPU_MISC,           0x53c */
+	u32 clk_cpug_misc;		/* _CLK_CPUG_MISC,          0x540 */
+	u32 clk_cpulp_misc;		/* _CLK_CPULP_MISC,         0x544 */
+	u32 pllx_hw_ctrl_cfg;		/* _PLLX_HW_CTRL_CFG,       0x548 */
+	u32 pllx_sw_ramp_cfg;		/* _PLLX_SW_RAMP_CFG,       0x54c */
+	u32 pllx_hw_ctrl_status;	/* _PLLX_HW_CTRL_STATUS,    0x550 */
+	u32 _rsv31;			/*                          0x554 */
+	u32 super_gr3d_clk_div;		/* _SUPER_GR3D_CLK_DIVIDER, 0x558 */
+	u32 spare_reg0;			/* _SPARE_REG0,             0x55c */
+	u32 _rsv32[4];                  /*                    0x560-0x56c */
+	u32 plld2_ss_cfg;               /* _PLLD2_SS_CFG            0x570 */
+	u32 _rsv32_1[7];		/*                      0x574-58c */
+	u32 plldp_base;			/* _PLLDP_BASE,             0x590 */
+	u32 plldp_misc;			/* _PLLDP_MISC,             0x594 */
+	u32 plldp_ss_cfg;		/* _PLLDP_SS_CFG,           0x598 */
+	u32 _rsrv32_2[25];
+	u32 clk_src_xusb_core_host;	/* _CLK_SOURCE_XUSB_CORE_HOST 0x600 */
+	u32 clk_src_xusb_falcon;	/* _CLK_SOURCE_XUSB_FALCON  0x604 */
+	u32 clk_src_xusb_fs;		/* _CLK_SOURCE_XUSB_FS      0x608 */
+	u32 clk_src_xusb_core_dev;	/* _CLK_SOURCE_XUSB_CORE_DEV 0x60c */
+	u32 clk_src_xusb_ss;		/* _CLK_SOURCE_XUSB_SS      0x610 */
+	u32 clk_src_cilab;		/* _CLK_SOURCE_CILAB        0x614 */
+	u32 clk_src_cilcd;		/* _CLK_SOURCE_CILCD        0x618 */
+	u32 clk_src_cile;		/* _CLK_SOURCE_CILE         0x61c */
+	u32 clk_src_dsia_lp;		/* _CLK_SOURCE_DSIA_LP      0x620 */
+	u32 clk_src_dsib_lp;		/* _CLK_SOURCE_DSIB_LP      0x624 */
+	u32 clk_src_entropy;		/* _CLK_SOURCE_ENTROPY      0x628 */
+	u32 clk_src_dvfs_ref;		/* _CLK_SOURCE_DVFS_REF     0x62c */
+	u32 clk_src_dvfs_soc;		/* _CLK_SOURCE_DVFS_SOC     0x630 */
+	u32 clk_src_traceclkin;		/* _CLK_SOURCE_TRACECLKIN   0x634 */
+	u32 clk_src_adx0;		/* _CLK_SOURCE_ADX0         0x638 */
+	u32 clk_src_amx0;		/* _CLK_SOURCE_AMX0         0x63c */
+	u32 clk_src_emc_latency;	/* _CLK_SOURCE_EMC_LATENCY  0x640 */
+	u32 clk_src_soc_therm;		/* _CLK_SOURCE_SOC_THERM    0x644 */
+	u32 _rsv33[5];			/*                      0x648-658 */
+	u32 clk_src_i2c6;		/* _CLK_SOURCE_I2C6,        0x65c */
+	u32 clk_src_mipibif;		/* _CLK_SOURCE_MIPIBIF,     0x660 */
+	u32 clk_src_emc_dll;		/* _CLK_SOURCE_EMC_DLL,     0x664 */
+	u32 _rsv34;			/*                          0x668 */
+	u32 clk_src_uart_fst_mipi_cal;	/* _CLK_SOURCE_UART_FST_MIP_CAL, 0x66c */
+	u32 _rsv35[21];			/*                      0x670-6c0 */
+	u32 clk_src_qspi;		/* _CLK_SOURCE_QSPI         0x6C4 */
+};
+check_member(clk_rst_ctlr, clk_src_qspi, 0x6C4);
+
+#define CLK_RST_REG(field_)					\
+	(&(((struct clk_rst_ctlr *)TEGRA_CLK_RST_BASE)->field_))
+
+/* L, H, U, V, W, X, Y */
+#define DEV_CONFIG_BLOCKS               7
+
+#define TEGRA_DEV_L			0
+#define TEGRA_DEV_H			1
+#define TEGRA_DEV_U			2
+#define TEGRA_DEV_V			0
+#define TEGRA_DEV_W			1
+
+#define SIMPLE_PLLX		(CLOCK_ID_XCPU - CLOCK_ID_FIRST_SIMPLE)
+
+/* Bits to enable/reset modules */
+#define CLK_ENB_CPU			(1 << 0)
+#define SWR_TRIG_SYS_RST		(1 << 2)
+#define SWR_CSITE_RST			(1 << 9)
+#define CLK_ENB_CSITE			(1 << 9)
+#define CLK_ENB_EMC_DLL			(1 << 14)
+
+/* _CCLK_BURST_POLICY 0x20 */
+#define CCLK_BURST_POLICY_VAL		0x20008888
+
+/* CRC_SUPER_CCLK_DIVIDER_0 0x24 */
+#define SUPER_CDIV_ENB_ENABLE		(1 << 31)
+
+/* CLK_RST_CONTROLLER_MISC_CLK_ENB 0x48 */
+#define EN_PPSB_STOPCLK			(1 << 0)
+
+/* CLK_RST_CONTROLLER_CLK_CPU_CMPLX_0 (0x4C) */
+#define CPU3_CLK_STP_SHIFT		11
+#define CPU2_CLK_STP_SHIFT		10
+#define CPU1_CLK_STP_SHIFT		9
+#define CPU0_CLK_STP_SHIFT		8
+#define CPU0_CLK_STP_MASK		(1U << CPU0_CLK_STP_SHIFT)
+
+/* CRC_OSC_CTRL_0 0x50 */
+#define OSC_FREQ_SHIFT			28
+#define OSC_FREQ_MASK			(0xf << OSC_FREQ_SHIFT)
+#define OSC_PREDIV_SHIFT		26
+#define OSC_PREDIV_MASK			(0x3 << OSC_PREDIV_SHIFT)
+#define OSC_XOFS_SHIFT			4
+#define OSC_XOFS_MASK			(0x3F << OSC_XOFS_SHIFT)
+#define OSC_DRIVE_STRENGTH		7
+#define OSC_XOBP			(1 << 1)
+#define OSC_XOE				(1 << 0)
+
+enum {
+	OSC_FREQ_12	= 8,	/* 12.0MHz */
+	OSC_FREQ_13	= 0,	/* 13.0MHz */
+	OSC_FREQ_16P8	= 1,	/* 16.8MHz */
+	OSC_FREQ_19P2	= 4,	/* 19.2MHz */
+	OSC_FREQ_26	= 12,	/* 26.0MHz */
+	OSC_FREQ_38P4	= 5,	/* 38.4MHz */
+	OSC_FREQ_48	= 9,	/* 48.0MHz */
+};
+
+/* CLK_RST_CONTROLLER_PLL*_BASE_0 */
+#define PLL_BASE_BYPASS			(1U << 31)
+#define PLL_BASE_ENABLE			(1U << 30)
+#define PLL_BASE_REF_DIS		(1U << 29)
+#define PLL_BASE_OVRRIDE		(1U << 28)
+#define PLL_BASE_LOCK			(1U << 27)
+#define PLLC_BASE_LOCK			(1U << 26)
+
+#define PLL_BASE_DIVP_SHIFT		20
+#define PLL_BASE_DIVP_MASK		(7U << PLL_BASE_DIVP_SHIFT)
+
+#define PLL_BASE_DIVN_SHIFT		8
+#define PLL_BASE_DIVN_MASK		(0x3ffU << PLL_BASE_DIVN_SHIFT)
+
+#define PLL_BASE_DIVM_SHIFT		0
+#define PLL_BASE_DIVM_MASK		(0x1f << PLL_BASE_DIVM_SHIFT)
+
+/* SPECIAL CASE: PLLM, PLLC and PLLX use different-sized fields here */
+#define PLLCX_BASE_DIVP_MASK		(0xfU << PLL_BASE_DIVP_SHIFT)
+#define PLLM_BASE_DIVP_MASK		(0x1fU << PLL_BASE_DIVP_SHIFT)
+#define PLLCMX_BASE_DIVN_MASK		(0xffU << PLL_BASE_DIVN_SHIFT)
+#define PLLCMX_BASE_DIVM_MASK		(0xffU << PLL_BASE_DIVM_SHIFT)
+
+/* Added based on T210 TRM */
+#define PLLC_MISC_RESET			(1U << 30)
+#define PLLC_MISC_1_IDDQ		(1U << 27)
+#define PLLD_N_SHIFT			11
+#define PLLD_M_SHIFT			0
+#define PLLD_P_SHIFT			20
+#define PLLD_MISC1_SETUP		0x20
+#define PLLD_MISC_EN_SDM		(1 << 16)
+#define PLLD_MISC_SDM_DIN		0x9aa
+
+/* PLLM specific registers */
+#define PLLM_MISC1_SETUP_SHIFT		0
+#define PLLM_MISC1_PD_LSHIFT_PH45_SHIFT		28
+#define PLLM_MISC1_PD_LSHIFT_PH90_SHIFT		29
+#define PLLM_MISC1_PD_LSHIFT_PH135_SHIFT	30
+#define PLLM_MISC2_KCP_SHIFT		1
+#define PLLM_MISC2_KVCO_SHIFT		0
+#define PLLM_OUT1_RSTN_RESET_DISABLE	(1 << 0)
+#define PLLM_EN_LCKDET          	(1 << 4)
+
+/* PLLU specific registers */
+#define PLLU_MISC_IDDQ			(1U << 31)
+
+/* UTMIP PLL specific registers */
+#define UTMIP_CFG0_PLL_MDIV_SHIFT			(8)
+#define UTMIP_CFG0_PLL_NDIV_SHIFT			(16)
+#define UTMIP_CFG1_XTAL_FREQ_COUNT_SHIFT		(0)
+#define UTMIP_CFG1_FORCE_PLL_ACTIVE_POWERDOWN_DISABLE	(0 << 12)
+#define UTMIP_CFG1_FORCE_PLL_ENABLE_POWERDOWN_DISABLE	(0 << 14)
+#define UTMIP_CFG1_FORCE_PLLU_POWERDOWN_DISABLE	(0 << 16)
+#define UTMIP_CFG1_PLLU_ENABLE_DLY_COUNT_SHIFT		(27)
+#define UTMIP_CFG2_FORCE_PD_SAMP_A_POWERDOWN_DISABLE	(0 << 0)
+#define UTMIP_CFG2_FORCE_PD_SAMP_B_POWERDOWN_DISABLE	(0 << 2)
+#define UTMIP_CFG2_FORCE_PD_SAMP_C_POWERDOWN_DISABLE	(0 << 4)
+#define UTMIP_CFG2_PLLU_STABLE_COUNT_SHIFT		(6)
+#define UTMIP_CFG2_PLL_ACTIVE_DLY_COUNT_SHIFT		(18)
+#define UTMIP_CFG2_PHY_XTAL_CLOCKEN		(1U << 30)
+
+/* Generic, indiscriminate divisor mask. May catch some innocent bystander bits
+ * on the side that we don't particularly care about. */
+#define PLL_BASE_DIV_MASK		(0xffffff)
+
+/* CLK_RST_CONTROLLER_PLL*_OUT*_0 */
+#define PLL_OUT_RSTN			(1 << 0)
+#define PLL_OUT_CLKEN			(1 << 1)
+#define PLL_OUT_OVR			(1 << 2)
+
+#define PLL_OUT_RATIO_SHIFT		8
+#define PLL_OUT_RATIO_MASK		(0xffU << PLL_OUT_RATIO_SHIFT)
+
+#define PLL_OUT1_SHIFT			0
+#define PLL_OUT2_SHIFT			16
+#define PLL_OUT3_SHIFT			0
+#define PLL_OUT4_SHIFT			16
+
+/* This bit is different all over the place. */
+#define PLLDPD2_MISC_LOCK_ENABLE	(1 << 30)
+#define PLLU_MISC_LOCK_ENABLE		(1 << 29)
+#define PLLD_MISC_LOCK_ENABLE		(1 << 18)
+#define PLLD_MISC_CLK_ENABLE		(1 << 21)
+#define PLLPAXS_MISC_LOCK_ENABLE	(1 << 18)
+#define PLLE_MISC_LOCK_ENABLE		(1 << 9)
+
+/* PLLX_BASE_0 0xe0 */
+#define PLLX_BASE_PLLX_ENABLE		(1 << 30)
+
+/* CLK_RST_CONTROLLER_PLLX_MISC_3 */
+#define PLLX_IDDQ_SHIFT			3
+#define PLLX_IDDQ_MASK			(1U << PLLX_IDDQ_SHIFT)
+
+#define CLK_DIVISOR_MASK		(0xffff)
+
+#define CLK_SOURCE_SHIFT		29
+#define CLK_SOURCE_MASK			(0x7 << CLK_SOURCE_SHIFT)
+
+#define CLK_SOURCE_EMC_MC_EMC_SAME_FREQ (1 << 16)
+#define EMC_2X_CLK_SRC_SHIFT		29
+#define PLLM_UD				4
+
+#define CLK_UART_DIV_OVERRIDE		(1 << 24)
+
+/* CLK_RST_CONTROLLER_SCLK_BURST_POLICY */
+#define SCLK_SYS_STATE_SHIFT		28U
+#define SCLK_SYS_STATE_MASK		(15U << SCLK_SYS_STATE_SHIFT)
+enum {
+	SCLK_SYS_STATE_STDBY,
+	SCLK_SYS_STATE_IDLE,
+	SCLK_SYS_STATE_RUN,
+	SCLK_SYS_STATE_IRQ = 4U,
+	SCLK_SYS_STATE_FIQ = 8U,
+};
+#define SCLK_COP_FIQ_MASK		(1 << 27)
+#define SCLK_CPU_FIQ_MASK		(1 << 26)
+#define SCLK_COP_IRQ_MASK		(1 << 25)
+#define SCLK_CPU_IRQ_MASK		(1 << 24)
+
+#define SCLK_FIQ_SHIFT			12
+#define SCLK_FIQ_MASK			(7 << SCLK_FIQ_SHIFT)
+#define SCLK_IRQ_SHIFT			8
+#define SCLK_IRQ_MASK			(7 << SCLK_FIQ_SHIFT)
+#define SCLK_RUN_SHIFT			4
+#define SCLK_RUN_MASK			(7 << SCLK_FIQ_SHIFT)
+#define SCLK_IDLE_SHIFT			0
+#define SCLK_IDLE_MASK			(7 << SCLK_FIQ_SHIFT)
+enum {
+	SCLK_SOURCE_CLKM,
+	SCLK_SOURCE_PLLC_OUT1,
+	SCLK_SOURCE_PLLP_OUT4,
+	SCLK_SOURCE_PLLP_OUT3,
+	SCLK_SOURCE_PLLP_OUT2,
+	SCLK_SOURCE_PLLC_OUT0,
+	SCLK_SOURCE_CLKS,
+	SCLK_SOURCE_PLLM_OUT1,
+};
+
+/* CLK_RST_CONTROLLER_SUPER_SCLK_DIVIDER 0x2c */
+#define SCLK_DIV_ENB			(1 << 31)
+#define SCLK_DIVIDEND_SHIFT		8
+#define SCLK_DIVIDEND_MASK		(0xff << SCLK_DIVIDEND_SHIFT)
+#define SCLK_DIVISOR_SHIFT		0
+#define SCLK_DIVISOR_MASK		(0xff << SCLK_DIVISOR_SHIFT)
+
+/* CLK_RST_CONTROLLER_CLK_SYSTEM_RATE 0x30 */
+#define HCLK_DISABLE 			(1 << 7)
+#define HCLK_DIVISOR_SHIFT    		4
+#define HCLK_DIVISOR_MASK     		(3 << AHB_RATE_SHIFT)
+#define PCLK_DISABLE 			(1 << 3)
+#define PCLK_DIVISOR_SHIFT    		0
+#define PCLK_DIVISOR_MASK     		(3 << AHB_RATE_SHIFT)
+
+/* CRC_CLK_SOURCE_MSELECT_0 0x3b4 */
+#define MSELECT_CLK_SRC_PLLP_OUT0	(0 << 29)
+
+/* CRC_CLK_ENB_V_SET_0 0x440 */
+#define SET_CLK_ENB_CPUG_ENABLE		(1 << 0)
+#define SET_CLK_ENB_CPULP_ENABLE	(1 << 1)
+#define SET_CLK_ENB_MSELECT_ENABLE	(1 << 3)
+
+/* CLK_RST_CONTROLLER_UTMIP_PLL_CFG1_0 0x484 */
+#define PLLU_POWERDOWN			(1 << 16)
+#define PLL_ENABLE_POWERDOWN		(1 << 14)
+#define PLL_ACTIVE_POWERDOWN		(1 << 12)
+
+/* CLK_RST_CONTROLLER_UTMIP_PLL_CFG2_0 0x488 */
+#define UTMIP_FORCE_PD_SAMP_C_POWERDOWN	(1 << 4)
+#define UTMIP_FORCE_PD_SAMP_B_POWERDOWN	(1 << 2)
+#define UTMIP_FORCE_PD_SAMP_A_POWERDOWN	(1 << 0)
+
+// CCLK_BRST_POL
+enum {
+	CRC_CCLK_BRST_POL_PLLX_OUT0 = 0x8,
+	CRC_CCLK_BRST_POL_CPU_STATE_RUN = 0x2
+};
+
+// SUPER_CCLK_DIVIDER
+enum {
+	CRC_SUPER_CCLK_DIVIDER_SUPER_CDIV_ENB = 1 << 31
+};
+
+// CLK_CPU_CMPLX_CLR
+enum {
+	CRC_CLK_CLR_CPU0_STP = 0x1 << 8,
+	CRC_CLK_CLR_CPU1_STP = 0x1 << 9,
+	CRC_CLK_CLR_CPU2_STP = 0x1 << 10,
+	CRC_CLK_CLR_CPU3_STP = 0x1 << 11
+};
+
+// RST_CPUG_CMPLX_CLR
+enum {
+	CRC_RST_CPUG_CLR_CPU0 = 0x1 << 0,
+	CRC_RST_CPUG_CLR_CPU1 = 0x1 << 1,
+	CRC_RST_CPUG_CLR_CPU2 = 0x1 << 2,
+	CRC_RST_CPUG_CLR_CPU3 = 0x1 << 3,
+	CRC_RST_CPUG_CLR_DBG0 = 0x1 << 12,
+	CRC_RST_CPUG_CLR_DBG1 = 0x1 << 13,
+	CRC_RST_CPUG_CLR_DBG2 = 0x1 << 14,
+	CRC_RST_CPUG_CLR_DBG3 = 0x1 << 15,
+	CRC_RST_CPUG_CLR_CORE0 = 0x1 << 16,
+	CRC_RST_CPUG_CLR_CORE1 = 0x1 << 17,
+	CRC_RST_CPUG_CLR_CORE2 = 0x1 << 18,
+	CRC_RST_CPUG_CLR_CORE3 = 0x1 << 19,
+	CRC_RST_CPUG_CLR_CX0 = 0x1 << 20,
+	CRC_RST_CPUG_CLR_CX1 = 0x1 << 21,
+	CRC_RST_CPUG_CLR_CX2 = 0x1 << 22,
+	CRC_RST_CPUG_CLR_CX3 = 0x1 << 23,
+	CRC_RST_CPUG_CLR_L2 = 0x1 << 24,
+	CRC_RST_CPUG_CLR_NONCPU = 0x1 << 29,
+	CRC_RST_CPUG_CLR_PDBG = 0x1 << 30,
+};
+
+// RST_CPULP_CMPLX_CLR
+enum {
+	CRC_RST_CPULP_CLR_CPU0 = 0x1 << 0,
+	CRC_RST_CPULP_CLR_DBG0 = 0x1 << 12,
+	CRC_RST_CPULP_CLR_CORE0 = 0x1 << 16,
+	CRC_RST_CPULP_CLR_CX0 = 0x1 << 20,
+	CRC_RST_CPULP_CLR_L2 = 0x1 << 24,
+	CRC_RST_CPULP_CLR_NONCPU = 0x1 << 29,
+	CRC_RST_CPULP_CLR_PDBG = 0x1 << 30,
+};
+
+#endif	/* _TEGRA210_CLK_RST_H_ */
diff --git a/src/soc/nvidia/tegra210/include/soc/clock.h b/src/soc/nvidia/tegra210/include/soc/clock.h
new file mode 100644
index 0000000..456dab2
--- /dev/null
+++ b/src/soc/nvidia/tegra210/include/soc/clock.h
@@ -0,0 +1,442 @@
+/*
+ * Copyright 2014 Google Inc.
+ * Copyright (c) 2013-2015, NVIDIA CORPORATION.  All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __SOC_NVIDIA_TEGRA210_CLOCK_H__
+#define __SOC_NVIDIA_TEGRA210_CLOCK_H__
+
+#include <arch/hlt.h>
+#include <arch/io.h>
+#include <console/console.h>
+#include <soc/clk_rst.h>
+#include <stdint.h>
+#include <stdlib.h>
+
+enum {
+	CLK_L_CPU = 0x1 << 0,
+	CLK_L_COP = 0x1 << 1,
+	CLK_L_TRIG_SYS = 0x1 << 2,
+	CLK_L_RTC = 0x1 << 4,
+	CLK_L_TMR = 0x1 << 5,
+	CLK_L_UARTA = 0x1 << 6,
+	CLK_L_UARTB = 0x1 << 7,
+	CLK_L_GPIO = 0x1 << 8,
+	CLK_L_SDMMC2 = 0x1 << 9,
+	CLK_L_SPDIF = 0x1 << 10,
+	CLK_L_I2S2 = 0x1 << 11,
+	CLK_L_I2C1 = 0x1 << 12,
+	CLK_L_NDFLASH = 0x1 << 13,
+	CLK_L_SDMMC1 = 0x1 << 14,
+	CLK_L_SDMMC4 = 0x1 << 15,
+	CLK_L_PWM = 0x1 << 17,
+	CLK_L_I2S3 = 0x1 << 18,
+	CLK_L_EPP = 0x1 << 19,
+	CLK_L_VI = 0x1 << 20,
+	CLK_L_2D = 0x1 << 21,
+	CLK_L_USBD = 0x1 << 22,
+	CLK_L_ISP = 0x1 << 23,
+	CLK_L_3D = 0x1 << 24,
+	CLK_L_DISP2 = 0x1 << 26,
+	CLK_L_DISP1 = 0x1 << 27,
+	CLK_L_HOST1X = 0x1 << 28,
+	CLK_L_VCP = 0x1 << 29,
+	CLK_L_I2S1 = 0x1 << 30,
+	CLK_L_CACHE2 = 0x1 << 31,
+
+	CLK_H_MEM = 0x1 << 0,
+	CLK_H_AHBDMA = 0x1 << 1,
+	CLK_H_APBDMA = 0x1 << 2,
+	CLK_H_KBC = 0x1 << 4,
+	CLK_H_STAT_MON = 0x1 << 5,
+	CLK_H_PMC = 0x1 << 6,
+	CLK_H_FUSE = 0x1 << 7,
+	CLK_H_KFUSE = 0x1 << 8,
+	CLK_H_SBC1 = 0x1 << 9,
+	CLK_H_SNOR = 0x1 << 10,
+	CLK_H_JTAG2TBC = 0x1 << 11,
+	CLK_H_SBC2 = 0x1 << 12,
+	CLK_H_SBC3 = 0x1 << 14,
+	CLK_H_I2C5 = 0x1 << 15,
+	CLK_H_DSI = 0x1 << 16,
+	CLK_H_HSI = 0x1 << 18,
+	CLK_H_HDMI = 0x1 << 19,
+	CLK_H_CSI = 0x1 << 20,
+	CLK_H_I2C2 = 0x1 << 22,
+	CLK_H_UARTC = 0x1 << 23,
+	CLK_H_MIPI_CAL = 0x1 << 24,
+	CLK_H_EMC = 0x1 << 25,
+	CLK_H_USB2 = 0x1 << 26,
+	CLK_H_USB3 = 0x1 << 27,
+	CLK_H_MPE = 0x1 << 28,
+	CLK_H_VDE = 0x1 << 29,
+	CLK_H_BSEA = 0x1 << 30,
+	CLK_H_BSEV = 0x1 << 31,
+
+	CLK_U_UARTD = 0x1 << 1,
+	CLK_U_UARTE = 0x1 << 2,
+	CLK_U_I2C3 = 0x1 << 3,
+	CLK_U_SBC4 = 0x1 << 4,
+	CLK_U_SDMMC3 = 0x1 << 5,
+	CLK_U_PCIE = 0x1 << 6,
+	CLK_U_OWR = 0x1 << 7,
+	CLK_U_AFI = 0x1 << 8,
+	CLK_U_CSITE = 0x1 << 9,
+	CLK_U_PCIEXCLK = 0x1 << 10,
+	CLK_U_AVPUCQ = 0x1 << 11,
+	CLK_U_TRACECLKIN = 0x1 << 13,
+	CLK_U_SOC_THERM = 0x1 << 14,
+	CLK_U_DTV = 0x1 << 15,
+	CLK_U_NAND_SPEED = 0x1 << 16,
+	CLK_U_I2C_SLOW = 0x1 << 17,
+	CLK_U_DSIB = 0x1 << 18,
+	CLK_U_TSEC = 0x1 << 19,
+	CLK_U_IRAMA = 0x1 << 20,
+	CLK_U_IRAMB = 0x1 << 21,
+	CLK_U_IRAMC = 0x1 << 22,
+
+	// Clock reset.
+	CLK_U_EMUCIF = 0x1 << 23,
+	// Clock enable.
+	CLK_U_IRAMD = 0x1 << 23,
+
+	CLK_U_CRAM2 = 0x2 << 24,
+	CLK_U_XUSB_HOST = 0x1 << 25,
+	CLK_U_MSENC = 0x1 << 27,
+	CLK_U_SUS_OUT = 0x1 << 28,
+	CLK_U_DEV2_OUT = 0x1 << 29,
+	CLK_U_DEV1_OUT = 0x1 << 30,
+	CLK_U_XUSB_DEV = 0x1 << 31,
+
+	CLK_V_CPUG = 0x1 << 0,
+	CLK_V_CPULP = 0x1 << 1,
+	CLK_V_3D2 = 0x1 << 2,
+	CLK_V_MSELECT = 0x1 << 3,
+	CLK_V_I2S4 = 0x1 << 5,
+	CLK_V_I2S5 = 0x1 << 6,
+	CLK_V_I2C4 = 0x1 << 7,
+	CLK_V_SBC5 = 0x1 << 8,
+	CLK_V_SBC6 = 0x1 << 9,
+	CLK_V_AHUB = 0x1 << 10,
+	CLK_V_APB2APE = 0x1 << 11,
+	CLK_V_HDA2CODEC_2X = 0x1 << 15,
+	CLK_V_ATOMICS = 0x1 << 16,
+	CLK_V_ACTMON = 0x1 << 23,
+	CLK_V_EXTPERIPH1 = 0x1 << 24,
+	CLK_V_SATA = 0x1 << 28,
+	CLK_V_HDA = 0x1 << 29,
+
+	CLK_W_HDA2HDMICODEC = 0x1 << 0,
+	CLK_W_SATACOLD = 0x1 << 1,
+	CLK_W_CEC = 0x1 << 8,
+	CLK_W_XUSB_PADCTL = 0x1 << 14,
+	CLK_W_ENTROPY = 0x1 << 21,
+	CLK_W_DVFS = 0x1 << 27,
+	CLK_W_XUSB_SS = 0x1 << 28,
+
+	CLK_X_GPU = 0x1 << 24,
+	CLK_X_SOR1 = 0x1 << 23,
+	CLK_X_SOR0 = 0x1 << 22,
+	CLK_X_DPAUX = 0x1 << 21,
+	CLK_X_VIC = 0x1 << 18,
+	CLK_X_UART_FST_MIPI_CAL = 0x1 << 17,
+	CLK_X_MIPIBIF = 0x1 << 13,
+	CLK_X_I2C6 = 0x1 << 6,
+	CLK_X_ETR = 0x1 << 3,
+	CLK_X_SPARE = 0x1 << 0,
+
+	CLK_Y_APE = 0x1 << 6,
+	CLK_Y_QSPI = 0x1 << 19,
+};
+
+enum {
+	PLLP = 0,
+	PLLC2 = 1,
+	PLLC = 2,
+	PLLC_OUT1 = 3,
+	PLLM = 4,
+	CLK_M = 5,
+	CLK_S = 6,
+	PLLE = 7,
+	PLLA = 8,
+	PLLD = 9,
+	PLLD2 = 10,
+	PLLC4_OUT0 = 11,
+	PLLC4_OUT1 = 12,
+	PLLC4_OUT2 = 13,
+	PLLC4_OUT3 = 14,
+	PLLC4_OUT0_L = 15,
+	PLLC4_OUT1_L = 16,
+	PLLC4_OUT2_L = 17,
+	PLLD_OUT0 = 18,
+	PLLP_OUT3 = 19,
+	PLLC2_OUT0 = 20,
+	UNUSED0 = 100,
+	UNUSED1 = 101,
+	UNUSED2 = 102,
+	UNUSED3 = 103,
+	UNUSED4 = 104,
+	UNUSED5 = 105,
+	UNUSED6 = 106,
+	UNUSED7 = 107,
+};
+
+#define CLK_SRC_DEV_ID(dev, src)	CLK_SRC_##dev##_##src
+#define CLK_SRC_FREQ_ID(dev, src)	CLK_SRC_FREQ_##dev##_##src
+
+#define CLK_SRC_DEVICE(dev, a, b, c, d, e, f, g, h)	\
+	CLK_SRC_DEV_ID(dev, a) = 0,		 \
+	CLK_SRC_DEV_ID(dev, b) = 1,		 \
+	CLK_SRC_DEV_ID(dev, c) = 2,		 \
+	CLK_SRC_DEV_ID(dev, d) = 3,		 \
+	CLK_SRC_DEV_ID(dev, e) = 4,		 \
+	CLK_SRC_DEV_ID(dev, f) = 5,		 \
+	CLK_SRC_DEV_ID(dev, g) = 6,	         \
+	CLK_SRC_DEV_ID(dev, h) = 7,	         \
+	CLK_SRC_FREQ_ID(dev, a) = a,		 \
+	CLK_SRC_FREQ_ID(dev, b) = b,		 \
+	CLK_SRC_FREQ_ID(dev, c) = c,		 \
+	CLK_SRC_FREQ_ID(dev, d) = d,		 \
+	CLK_SRC_FREQ_ID(dev, e) = e,		 \
+	CLK_SRC_FREQ_ID(dev, f) = f,		 \
+	CLK_SRC_FREQ_ID(dev, g) = g,		 \
+	CLK_SRC_FREQ_ID(dev, h) = h
+
+enum {
+	CLK_SRC_DEVICE(disp1, PLLP, PLLD, PLLD_OUT0, UNUSED3, UNUSED4, PLLD2,
+		       CLK_M, UNUSED7),
+	CLK_SRC_DEVICE(host1x, PLLC4_OUT1, PLLC2, PLLC, PLLC4_OUT2, PLLP, CLK_M,
+		       PLLA, PLLC4_OUT0),
+	CLK_SRC_DEVICE(I2C1, PLLP, PLLC2, PLLC, PLLC4_OUT0, UNUSED4, PLLC4_OUT1,
+		       CLK_M, PLLC4_OUT2),
+	CLK_SRC_DEVICE(I2C2, PLLP, PLLC2, PLLC, PLLC4_OUT0, UNUSED4, PLLC4_OUT1,
+		       CLK_M, PLLC4_OUT2),
+	CLK_SRC_DEVICE(I2C3, PLLP, PLLC2, PLLC, PLLC4_OUT0, UNUSED4, PLLC4_OUT1,
+		       CLK_M, PLLC4_OUT2),
+	CLK_SRC_DEVICE(I2C5, PLLP, PLLC2, PLLC, PLLC4_OUT0, UNUSED4, PLLC4_OUT1,
+		       CLK_M, PLLC4_OUT2),
+	CLK_SRC_DEVICE(I2C6, PLLP, PLLC2, PLLC, PLLC4_OUT0, UNUSED4, PLLC4_OUT1,
+		       CLK_M, PLLC4_OUT2),
+	CLK_SRC_DEVICE(I2S1, PLLA, UNUSED1, CLK_S, UNUSED3, PLLP, UNUSED5,
+		       CLK_M, UNUSED7),
+	CLK_SRC_DEVICE(mselect, PLLP, PLLC2, PLLC, PLLC4_OUT2, PLLC4_OUT1,
+		       CLK_S, CLK_M, PLLC4_OUT0),
+	CLK_SRC_DEVICE(SPI1, PLLP, PLLC2, PLLC, PLLC4_OUT0, UNUSED4, PLLC4_OUT1,
+		       CLK_M, PLLC4_OUT2),
+	CLK_SRC_DEVICE(SPI4, PLLP, PLLC2, PLLC, PLLC4_OUT0, UNUSED4, PLLC4_OUT1,
+		       CLK_M, PLLC4_OUT2),
+	CLK_SRC_DEVICE(SDMMC1, PLLP, PLLA, PLLC, PLLC4_OUT2, PLLM, PLLE, CLK_M,
+		       PLLC4_OUT0),
+	CLK_SRC_DEVICE(SDMMC4, PLLP, PLLC4_OUT2_L, PLLC4_OUT0_L, PLLC4_OUT2,
+		       PLLC4_OUT1, PLLC4_OUT1_L, CLK_M, PLLC4_OUT0),
+	CLK_SRC_DEVICE(UARTA, PLLP, PLLC2, PLLC, PLLC4_OUT0, UNUSED4,
+		       PLLC4_OUT1, CLK_M, PLLC4_OUT2),
+	CLK_SRC_DEVICE(i2s1, PLLA, UNUSED1, CLK_S, UNUSED3, PLLP, UNUSED5,
+		       CLK_M, UNUSED7),
+	CLK_SRC_DEVICE(extperiph1, PLLA, CLK_S, PLLP, CLK_M, PLLE, UNUSED5,
+		       UNUSED6, UNUSED7),
+	CLK_SRC_DEVICE(QSPI, PLLP, PLLC_OUT1, PLLC, UNUSED3, PLLC4_OUT2,
+		       PLLC4_OUT1, CLK_M, PLLC4_OUT0),
+	CLK_SRC_DEVICE(uart_fst_mipi_cal, PLLP_OUT3, PLLP, PLLC, UNUSED3, PLLC2_OUT0,
+			UNUSED5, CLK_M, UNUSED7),
+};
+
+/* PLL stabilization delay in usec */
+#define CLOCK_PLL_STABLE_DELAY_US 300
+
+#define IO_STABILIZATION_DELAY (2)
+#define LOGIC_STABILIZATION_DELAY (2)
+
+/* Calculate clock fractional divider value from ref and target frequencies.
+ * This is for a U7.1 format. This is not well written up in the book and
+ * there have been some questions about this macro, so here we go.
+ * U7.1 format is defined as (ddddddd+1) + (h*.5)
+ * The lowest order bit is actually a fractional bit.
+ * Hence, the divider can be thought of as 9 bits.
+ * So:
+ * divider = ((ref/freq) << 1 - 1) (upper 7 bits) |
+ *	(ref/freq & 1) (low order half-bit)
+ * however we can't do fractional arithmetic ... these are integers!
+ * So we normalize by shifting the result left 1 bit, and extracting
+ * ddddddd and h directly to the returned u8.
+ * divider = 2*(ref/freq);
+ * We want to
+ * preserve 7 bits of divisor and one bit of fraction, in 8 bits, as well as
+ * subtract one from ddddddd. Since we computed ref*2, the dddddd is now nicely
+ * situated in the upper 7 bits, and the h is sitting there in the low order
+ * bit. To subtract 1 from ddddddd, just subtract 2 from the 8-bit number
+ * and voila, upper 7 bits are (ref/freq-1), and lowest bit is h. Since you
+ * will assign this to a u8, it gets nicely truncated for you.
+ */
+#define CLK_DIVIDER(REF, FREQ)	(div_round_up(((REF) * 2), (FREQ)) - 2)
+
+/* Calculate clock frequency value from reference and clock divider value
+ * The discussion in the book is pretty lacking.
+ * The idea is that we need to divide a ref clock by a divisor
+ * in U7.1 format, where 7 upper bits are the integer
+ * and lowest order bit is a fraction.
+ * from the book, U7.1 is (ddddddd+1) + (h*.5)
+ * To normalize to an actual number, we might do this:
+ * ((d>>7+1)&0x7f) + (d&1 >> 1)
+ * but as you might guess, the low order bit would be lost.
+ * Since we can't express the fractional bit, we need to multiply it all by 2.
+ * ((d + 2)&0xfe) + (d & 1)
+ * Since we're just adding +2, the lowest order bit is preserved. Hence
+ * (d+2) is the same as ((d + 2)&0xfe) + (d & 1)
+ *
+ * Since you multiply denominator * 2 (by NOT shifting it),
+ * you multiply numerator * 2 to cancel it out.
+ */
+#define CLK_FREQUENCY(REF, REG)	(((REF) * 2) / ((REG) + 2))
+
+static inline void _clock_set_div(u32 *reg, const char *name, u32 div,
+				  u32 div_mask, u32 src)
+{
+	// The I2C and UART divisors are 16 bit while all the others are 8 bit.
+	// The I2C clocks are handled by the specialized macro below, but the
+	// UART clocks aren't. Don't use this function on UART clocks.
+	if (div & ~div_mask) {
+		printk(BIOS_ERR, "%s clock divisor overflow!", name);
+		hlt();
+	}
+	clrsetbits_le32(reg, CLK_SOURCE_MASK | CLK_DIVISOR_MASK,
+			src << CLK_SOURCE_SHIFT | div);
+}
+
+#define get_i2c_clk_div(src,freq) (div_round_up(src, (freq) * (0x19 + 1) * 8) - 1)
+#define get_clk_div(src,freq)     CLK_DIVIDER(src,freq)
+#define CLK_DIV_MASK              0xff
+#define CLK_DIV_MASK_I2C          0xffff
+
+#define clock_configure_source(device, src, freq)			\
+	_clock_set_div(CLK_RST_REG(clk_src_##device), #device,		\
+		       get_clk_div(TEGRA_##src##_KHZ, freq), CLK_DIV_MASK, \
+		       CLK_SRC_DEV_ID(device, src))
+
+/* soc-specific */
+#define TEGRA_CLK_M_KHZ	 clock_get_osc_khz()
+#define TEGRA_PLLX_KHZ   CONFIG_PLLX_KHZ
+#define TEGRA_PLLP_KHZ   (408000)
+#define TEGRA_PLLP_OUT3_KHZ	(68000)
+#define TEGRA_PLLC_KHZ   (600000)
+#define TEGRA_PLLD_KHZ   (925000)
+#define TEGRA_PLLD_OUT0_KHZ   (TEGRA_PLLD_KHZ/2)
+#define TEGRA_PLLU_KHZ   (960000)
+
+#define clock_enable(l, h, u, v, w, x, y)				\
+	do {								\
+		u32 bits[DEV_CONFIG_BLOCKS] = {l, h, u, v, w, x, y};	\
+		clock_enable_regs(bits);				\
+	} while (0)
+
+#define clock_disable(l, h, u, v, w, x, y)				\
+	do {								\
+		u32 bits[DEV_CONFIG_BLOCKS] = {l, h, u, v, w, x, y};	\
+		clock_disable_regs(bits);				\
+	} while (0)
+
+#define clock_set_reset(l, h, u, v, w, x, y)				\
+	do {								\
+		u32 bits[DEV_CONFIG_BLOCKS] = {l, h, u, v, w, x, y};	\
+		clock_set_reset_regs(bits);				\
+	} while (0)
+
+#define clock_clr_reset(l, h, u, v, w, x, y)				\
+	do {								\
+		u32 bits[DEV_CONFIG_BLOCKS] = {l, h, u, v, w, x, y};	\
+		clock_clr_reset_regs(bits);				\
+	} while (0)
+
+#define clock_enable_l(l)               clock_enable(l, 0, 0, 0, 0, 0, 0)
+#define clock_enable_h(h)               clock_enable(0, h, 0, 0, 0, 0, 0)
+#define clock_enable_u(u)               clock_enable(0, 0, u, 0, 0, 0, 0)
+#define clock_enable_v(v)               clock_enable(0, 0, 0, v, 0, 0, 0)
+#define clock_enable_w(w)               clock_enable(0, 0, 0, 0, w, 0, 0)
+#define clock_enable_x(x)               clock_enable(0, 0, 0, 0, 0, x, 0)
+#define clock_enable_y(y)               clock_enable(0, 0, 0, 0, 0, 0, y)
+
+#define clock_disable_l(l)              clock_disable(l, 0, 0, 0, 0, 0, 0)
+#define clock_disable_h(h)              clock_disable(0, h, 0, 0, 0, 0, 0)
+#define clock_disable_u(u)              clock_disable(0, 0, u, 0, 0, 0, 0)
+#define clock_disable_v(v)              clock_disable(0, 0, 0, v, 0, 0, 0)
+#define clock_disable_w(w)              clock_disable(0, 0, 0, 0, w, 0, 0)
+#define clock_disable_x(x)              clock_disable(0, 0, 0, 0, 0, x, 0)
+#define clock_disable_y(y)              clock_disable(0, 0, 0, 0, 0, 0, y)
+
+#define clock_set_reset_l(l)            clock_set_reset(l, 0, 0, 0, 0, 0, 0)
+#define clock_set_reset_h(h)            clock_set_reset(0, h, 0, 0, 0, 0, 0)
+#define clock_set_reset_u(u)            clock_set_reset(0, 0, u, 0, 0, 0, 0)
+#define clock_set_reset_v(v)            clock_set_reset(0, 0, 0, v, 0, 0, 0)
+#define clock_set_reset_w(w)            clock_set_reset(0, 0, 0, 0, w, 0, 0)
+#define clock_set_reset_x(x)            clock_set_reset(0, 0, 0, 0, 0, x, 0)
+#define clock_set_reset_y(x)            clock_set_reset(0, 0, 0, 0, 0, y, 0)
+
+#define clock_clr_reset_l(l)            clock_clr_reset(l, 0, 0, 0, 0, 0, 0)
+#define clock_clr_reset_h(h)            clock_clr_reset(0, h, 0, 0, 0, 0, 0)
+#define clock_clr_reset_u(u)            clock_clr_reset(0, 0, u, 0, 0, 0, 0)
+#define clock_clr_reset_v(v)            clock_clr_reset(0, 0, 0, v, 0, 0, 0)
+#define clock_clr_reset_w(w)            clock_clr_reset(0, 0, 0, 0, w, 0, 0)
+#define clock_clr_reset_x(x)            clock_clr_reset(0, 0, 0, 0, 0, x, 0)
+#define clock_clr_reset_y(y)            clock_clr_reset(0, 0, 0, 0, 0, 0, y)
+
+#define clock_enable_clear_reset_l(l)			\
+	clock_enable_clear_reset(l, 0, 0, 0, 0, 0, 0)
+#define clock_enable_clear_reset_h(h)			\
+	clock_enable_clear_reset(0, h, 0, 0, 0, 0, 0)
+#define clock_enable_clear_reset_u(u)			\
+	clock_enable_clear_reset(0, 0, u, 0, 0, 0, 0)
+#define clock_enable_clear_reset_v(v)			\
+	clock_enable_clear_reset(0, 0, 0, v, 0, 0, 0)
+#define clock_enable_clear_reset_w(w)			\
+	clock_enable_clear_reset(0, 0, 0, 0, w, 0, 0)
+#define clock_enable_clear_reset_x(x)			\
+	clock_enable_clear_reset(0, 0, 0, 0, 0, x, 0)
+#define clock_enable_clear_reset_y(y)			\
+	clock_enable_clear_reset(0, 0, 0, 0, 0, 0, y)
+
+int clock_get_osc_khz(void);
+int clock_get_pll_input_khz(void);
+/*
+ * Configure PLLD to requested frequency. Returned value is closest match
+ * within the PLLD's constraints or 0 if an error.
+ */
+u32 clock_configure_plld(u32 frequency);
+void clock_early_uart(void);
+void clock_external_output(int clk_id);
+void clock_sdram(u32 m, u32 n, u32 p, u32 setup, u32 kvco, u32 kcp,
+		 u32 stable_time, u32 emc_source, u32 same_freq);
+void clock_cpu0_config(void);
+void clock_halt_avp(void);
+void clock_enable_regs(u32 bits[DEV_CONFIG_BLOCKS]);
+void clock_disable_regs(u32 bits[DEV_CONFIG_BLOCKS]);
+void clock_set_reset_regs(u32 bits[DEV_CONFIG_BLOCKS]);
+void clock_clr_reset_regs(u32 bits[DEV_CONFIG_BLOCKS]);
+void clock_enable_clear_reset(u32 l, u32 h, u32 u, u32 v, u32 w, u32 x, u32 y);
+void clock_grp_enable_clear_reset(u32 val, u32* clk_enb_set_reg, u32* rst_dev_clr_reg);
+void clock_reset_l(u32 l);
+void clock_reset_h(u32 h);
+void clock_reset_u(u32 u);
+void clock_reset_v(u32 v);
+void clock_reset_w(u32 w);
+void clock_reset_x(u32 x);
+void clock_reset_y(u32 y);
+void clock_init(void);
+void clock_init_arm_generic_timer(void);
+void sor_clock_stop(void);
+void sor_clock_start(void);
+void clock_enable_audio(void);
+
+#endif /* __SOC_NVIDIA_TEGRA210_CLOCK_H__ */
+
diff --git a/src/soc/nvidia/tegra210/include/soc/clst_clk.h b/src/soc/nvidia/tegra210/include/soc/clst_clk.h
new file mode 100644
index 0000000..e0de867
--- /dev/null
+++ b/src/soc/nvidia/tegra210/include/soc/clst_clk.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2014-2015, NVIDIA CORPORATION.  All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _TEGRA210_CLST_CLK_H_
+#define _TEGRA210_CLST_CLK_H_
+
+/* Cluster Clock (CLUSTER_CLOCKS_PUBLIC_) regs */
+struct  __attribute__ ((__packed__)) clst_clk_ctlr {
+	u32 pllx_base;			/* _PLLX_BASE,              0x000 */
+	u32 pllx_misc;			/* _PLLX_MISC,              0x004 */
+	u32 pllx_misc1;			/* _PLLX_MISC_1,            0x008 */
+	u32 pllx_misc2;			/* _PLLX_MISC_2,            0x00c */
+	u32 pllx_misc3;			/* _PLLX_MISC_3,            0x010 */
+	u32 pllx_hw_ctrl_cfg;		/* _PLLX_HW_CTRL_CFG,       0x014 */
+	u32 pllx_sw_ramp_cfg;		/* _PLLX_SW_RAMP_CFG,       0x018 */
+	u32 pllx_hw_ctrl_status;	/* _PLLX_HW_CTRL_STATUS,    0x01c */
+	u32 cclk_brst_pol;		/* _CCLK_BURST_POLICY,      0x020 */
+	u32 super_cclk_div;		/* _SUPER_CCLK_DIVIDER,     0x024 */
+	u32 _rsv1[10];			/*                      0x028-04c */
+	u32 shaper;			/* _SHAPER,                 0x050 */
+	u32 shaper1;			/* _SHAPER_1,               0x054 */
+	u32 _rsv2[80];			/*                      0x058-194 */
+	u32 misc_ctrl;			/* _MISC_CTRL,              0x198 */
+};
+check_member(clst_clk_ctlr, misc_ctrl, 0x198);
+
+/* CC_CCLK_BRST_POL */
+enum {
+	CC_CCLK_BRST_POL_PLLX_OUT0_LJ = 0x8,
+};
+
+/* CC_SUPER_CCLK_DIVIDER */
+enum {
+	CC_SUPER_CCLK_DIVIDER_SUPER_CDIV_ENB = 1 << 31
+};
+
+/* PLLX_MISC3 */
+enum {
+	PLLX_IDDQ = 1 << 3,
+};
+
+/* MISC_CTRL */
+enum {
+	CLK_SWITCH_MATCH = 1 << 5,
+};
+
+#define CLK_SWITCH_TIMEOUT_US	1000
+#endif	/* _TEGRA210_CLST_CLK_H_ */
diff --git a/src/soc/nvidia/tegra210/include/soc/cpu.h b/src/soc/nvidia/tegra210/include/soc/cpu.h
new file mode 100644
index 0000000..f6ae137
--- /dev/null
+++ b/src/soc/nvidia/tegra210/include/soc/cpu.h
@@ -0,0 +1,33 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright 2014 Google Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc.
+ */
+
+#ifndef __SOC_NVIDIA_TEGRA210_CPU_H__
+#define __SOC_NVIDIA_TEGRA210_CPU_H__
+
+/*
+ * Start a core in 64-bit mode at the entry_64 address. Note that entry_64
+ * should be a 32-bit address.
+ */
+void start_cpu(int cpu, void *entry_64);
+/* Start CPU wthout any log messages. */
+void start_cpu_silent(int cpu, void *entry_64);
+/* Prepare SoC for starting a CPU. Initialize the global state of the SoC. */
+void cpu_prepare_startup(void *entry_64);
+
+#endif /* __SOC_NVIDIA_TEGRA210_CPU_H__ */
diff --git a/src/soc/nvidia/tegra210/include/soc/display.h b/src/soc/nvidia/tegra210/include/soc/display.h
new file mode 100644
index 0000000..fdc630b
--- /dev/null
+++ b/src/soc/nvidia/tegra210/include/soc/display.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2014 Google Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __SOC_NVIDIA_TEGRA210_INCLUDE_SOC_DISPLAY_H__
+#define __SOC_NVIDIA_TEGRA210_INCLUDE_SOC_DISPLAY_H__
+
+#define COLOR_WHITE	0xFFFFFF
+#define COLOR_BLACK	0x000000
+
+#define hsync_start(mode)	\
+	(mode->xres + mode->hfront_porch)
+
+#define hsync_end(mode)	\
+	(mode->xres + mode->hfront_porch + mode->hsync_width)
+
+#define htotal(mode)	\
+	(mode->xres + mode->hfront_porch + \
+	mode->hsync_width + mode->hback_porch)
+
+#define vtotal(mode)	\
+	(mode->yres + mode->vfront_porch + \
+	mode->vsync_width + mode->vback_porch)
+
+enum {
+	/* norrin64 */
+	TEGRA_EDID_I2C_ADDRESS = 0x50,
+};
+
+/* refresh rate = 60/s */
+#define FRAME_IN_MS 17
+
+/* forward declaration */
+struct soc_nvidia_tegra210_config;
+struct display_controller;
+
+void dsi_display_startup(device_t dev);
+void dp_display_startup(device_t dev);
+
+int tegra_dc_init(struct display_controller *disp_ctrl);
+int update_display_mode(struct display_controller *disp_ctrl,
+			struct soc_nvidia_tegra210_config *config);
+void update_window(const struct soc_nvidia_tegra210_config *config);
+void update_display_shift_clock_divider(struct display_controller *disp_ctrl,
+			u32 shift_clock_div);
+void pass_mode_info_to_payload(
+			struct soc_nvidia_tegra210_config *config);
+#endif /* __SOC_NVIDIA_TEGRA210_INCLUDE_SOC_DISPLAY_H__ */
diff --git a/src/soc/nvidia/tegra210/include/soc/dma.h b/src/soc/nvidia/tegra210/include/soc/dma.h
new file mode 100644
index 0000000..d191af2
--- /dev/null
+++ b/src/soc/nvidia/tegra210/include/soc/dma.h
@@ -0,0 +1,189 @@
+/*
+ * (C) Copyright 2010-2015 NVIDIA Corporation <www.nvidia.com>
+ *  Copyright (C) 2014 Google Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __NVIDIA_TEGRA210_DMA_H__
+#define __NVIDIA_TEGRA210_DMA_H__
+
+#include <inttypes.h>
+#include <soc/addressmap.h>
+
+/*
+ * The DMA engine operates on 4 bytes at a time, so make sure any data
+ * passed via DMA is aligned to avoid underrun/overrun.
+ */
+#define TEGRA_DMA_ALIGN_BYTES	4
+
+/*
+ * Note: Many APB DMA controller registers are laid out such that each
+ * bit controls or represents the status for the corresponding channel.
+ * So we will not bother to list each individual bit in this case.
+ */
+#define APB_COMMAND_GEN			(1 << 31)
+
+#define APB_CNTRL_REG_COUNT_VALUE_MASK	0xffff
+#define APB_CNTRL_REG_COUNT_VALUE_SHIFT	0
+
+/*
+ * Note: Many APB DMA controller registers are laid out such that each
+ * bit controls or represents the status for the corresponding channel.
+ * So we will not bother to list each individual bit in this case.
+ */
+#define APB_COMMAND_GEN			(1 << 31)
+
+#define APB_CNTRL_REG_COUNT_VALUE_MASK	0xffff
+#define APB_CNTRL_REG_COUNT_VALUE_SHIFT	0
+struct apb_dma {
+	u32 command;		/* 0x00 */
+	u32 status;		/* 0x04 */
+	u32 rsvd1[2];
+	u32 cntrl_reg;		/* 0x10 */
+	u32 irq_sta_cpu;	/* 0x14 */
+	u32 irq_sta_cop;	/* 0x18 */
+	u32 irq_mask;		/* 0x1c */
+	u32 irq_mask_set;	/* 0x20 */
+	u32 irq_mask_clr;	/* 0x24 */
+	u32 trig_reg;		/* 0x28 */
+	u32 channel_trig_reg;	/* 0x2c */
+	u32 dma_status;		/* 0x30 */
+	u32 channel_en_reg;	/* 0x34 */
+	u32 security_reg;	/* 0x38 */
+	u32 channel_swid;	/* 0x3c */
+	u32 rsvd[1];
+	u32 chan_wt_reg0;	/* 0x44 */
+	u32 chan_wt_reg1;	/* 0x48 */
+	u32 chan_wt_reg2;	/* 0x4c */
+	u32 chan_wr_reg3;	/* 0x50 */
+	u32 channel_swid1;	/* 0x54 */
+} __attribute__((packed));
+check_member(apb_dma, channel_swid1, 0x54);
+
+/*
+ * Naming in the doc included a superfluous _CHANNEL_n_ for
+ * each entry and was left out for the sake of conciseness.
+ */
+#define APB_CSR_ENB			(1 << 31)
+#define APB_CSR_IE_EOC			(1 << 30)
+#define APB_CSR_HOLD			(1 << 29)
+#define APB_CSR_DIR			(1 << 28)
+#define APB_CSR_ONCE			(1 << 27)
+#define APB_CSR_FLOW			(1 << 21)
+#define APB_CSR_REQ_SEL_MASK		0x1f
+#define APB_CSR_REQ_SEL_SHIFT		16
+
+enum apbdmachan_req_sel {
+	APBDMA_SLAVE_CNTR_REQ	= 0,
+	APBDMA_SLAVE_APBIF_CH0	= 1,
+	APBDMA_SLAVE_APBIF_CH1	= 2,
+	APBDMA_SLAVE_APBIF_CH2	= 3,
+	APBDMA_SLAVE_APBIF_CH3	= 4,
+	APBDMA_SLAVE_QSPI	= 5,
+	APBDMA_SLAVE_APBIF_CH4	= 6,
+	APBDMA_SLAVE_APBIF_CH5	= 7,
+	APBDMA_SLAVE_UART_A	= 8,
+	APBDMA_SLAVE_UART_B	= 9,
+	APBDMA_SLAVE_UART_C	= 10,
+	APBDMA_SLAVE_DTV	= 11,
+	APBDMA_SLAVE_APBIF_CH6	= 12,
+	APBDMA_SLAVE_APBIF_CH7	= 13,
+	APBDMA_SLAVE_APBIF_CH8	= 14,
+	APBDMA_SLAVE_SL2B1	= 15,
+	APBDMA_SLAVE_SL2B2	= 16,
+	APBDMA_SLAVE_SL2B3	= 17,
+	APBDMA_SLAVE_SL2B4	= 18,
+	APBDMA_SLAVE_UART_D	= 19,
+	APBDMA_SLAVE_UART_E	= 20,
+	APBDMA_SLAVE_I2C	= 21,
+	APBDMA_SLAVE_I2C2	= 22,
+	APBDMA_SLAVE_I2C3	= 23,
+	APBDMA_SLAVE_DVC_I2C	= 24,
+	APBDMA_SLAVE_OWR	= 25,
+	APBDMA_SLAVE_I2C4	= 26,
+	APBDMA_SLAVE_SL2B5	= 27,
+	APBDMA_SLAVE_SL2B6	= 28,
+	APBDMA_SLAVE_APBIF_CH9	= 29,
+	APBDMA_SLAVE_I2C6	= 30,
+	APBDMA_SLAVE_NA31	= 31,
+};
+
+#define APB_STA_BSY			(1 << 31)
+#define APB_STA_ISE_EOC			(1 << 30)
+#define APB_STA_HALT			(1 << 29)
+#define APB_STA_PING_PONG_STA		(1 << 28)
+#define APB_STA_DMA_ACTIVITY		(1 << 27)
+#define APB_STA_CHANNEL_PAUSE		(1 << 26)
+
+#define APB_CSRE_CHANNEL_PAUSE		(1 << 31)
+#define APB_CSRE_TRIG_SEL_MASK		0x3f
+#define APB_CSRE_TRIG_SEL_SHIFT		14
+
+#define AHB_PTR_MASK			(0x3fffffff)
+#define AHB_PTR_SHIFT			2
+
+#define AHB_SEQ_INTR_ENB		(1 << 31)
+#define AHB_BUS_WIDTH_MASK		0x7
+#define AHB_BUS_WIDTH_SHIFT		28
+#define AHB_DATA_SWAP			(1 << 27)
+#define AHB_BURST_MASK			0x7
+#define AHB_BURST_SHIFT			24
+#define AHB_SEQ_DBL_BUF			(1 << 19)
+#define AHB_SEQ_WRAP_MASK		0x7
+#define AHB_SEQ_WRAP_SHIFT		16
+
+#define APB_PTR_MASK			0x3fffffff
+#define APB_PTR_SHIFT			2
+
+#define APB_BUS_WIDTH_MASK		0x7
+#define APB_BUS_WIDTH_SHIFT		28
+#define APB_DATA_SWAP			(1 << 27)
+#define APB_ADDR_WRAP_MASK		0x7
+#define APB_ADDR_WRAP_SHIFT		16
+
+#define APB_WORD_TRANSFER_MASK		0x0fffffff
+#define APB_WORD_TRANSFER_SHIFT		2
+
+struct apb_dma_channel_regs {
+	u32 csr;		/* 0x00 */
+	u32 sta;		/* 0x04 */
+	u32 dma_byte_sta;	/* 0x08 */
+	u32 csre;		/* 0x0c */
+	u32 ahb_ptr;		/* 0x10 */
+	u32 ahb_seq;		/* 0x14 */
+	u32 apb_ptr;		/* 0x18 */
+	u32 apb_seq;		/* 0x1c */
+	u32 wcount;		/* 0x20 */
+	u32 word_transfer;	/* 0x24 */
+} __attribute__((packed));
+check_member(apb_dma_channel_regs, word_transfer, 0x24);
+
+struct apb_dma_channel {
+	const int num;
+	struct apb_dma_channel_regs *regs;
+
+	/*
+	 * Basic high-level semaphore that can be used to "claim"
+	 * a DMA channel e.g. by SPI, I2C, or other peripheral driver.
+	 */
+	int in_use;
+};
+
+struct apb_dma_channel * const dma_claim(void);
+void dma_release(struct apb_dma_channel * const channel);
+int dma_start(struct apb_dma_channel * const channel);
+int dma_stop(struct apb_dma_channel * const channel);
+int dma_busy(struct apb_dma_channel * const channel);
+
+#endif	/* __NVIDIA_TEGRA210_DMA_H__ */
diff --git a/src/soc/nvidia/tegra210/include/soc/emc.h b/src/soc/nvidia/tegra210/include/soc/emc.h
new file mode 100644
index 0000000..b24c14d
--- /dev/null
+++ b/src/soc/nvidia/tegra210/include/soc/emc.h
@@ -0,0 +1,475 @@
+/*
+ * Copyright (c) 2013-2015, NVIDIA CORPORATION.  All rights reserved.
+ * Copyright (C) 2014 Google Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __SOC_NVIDIA_TEGRA210_EMC_H__
+#define __SOC_NVIDIA_TEGRA210_EMC_H__
+
+#include <stddef.h>
+#include <stdint.h>
+
+enum {
+	EMC_PIN_RESET_MASK = 1 << 8,
+	EMC_PIN_RESET_ACTIVE = 0 << 8,
+	EMC_PIN_RESET_INACTIVE = 1 << 8,
+	EMC_PIN_DQM_MASK = 1 << 4,
+	EMC_PIN_DQM_NORMAL = 0 << 4,
+	EMC_PIN_DQM_INACTIVE = 1 << 4,
+	EMC_PIN_CKE_MASK = 1 << 0,
+	EMC_PIN_CKE_POWERDOWN = 0 << 0,
+	EMC_PIN_CKE_NORMAL = 1 << 0,
+
+	EMC_REF_CMD_MASK = 1 << 0,
+	EMC_REF_CMD_REFRESH = 1 << 0,
+	EMC_REF_NORMAL_MASK = 1 << 1,
+	EMC_REF_NORMAL_INIT = 0 << 1,
+	EMC_REF_NORMAL_ENABLED = 1 << 1,
+	EMC_REF_NUM_SHIFT = 8,
+	EMC_REF_NUM_MASK = 0xFF << EMC_REF_NUM_SHIFT,
+	EMC_REF_DEV_SELECTN_SHIFT = 30,
+	EMC_REF_DEV_SELECTN_MASK = 3 << EMC_REF_DEV_SELECTN_SHIFT,
+
+	EMC_REFCTRL_REF_VALID_MASK = 1 << 31,
+	EMC_REFCTRL_REF_VALID_DISABLED = 0 << 31,
+	EMC_REFCTRL_REF_VALID_ENABLED = 1 << 31,
+
+	EMC_CFG_EMC2PMACRO_CFG_BYPASS_ADDRPIPE_MASK = 1 << 1,
+	EMC_CFG_EMC2PMACRO_CFG_BYPASS_DATAPIPE1_MASK = 1 << 2,
+	EMC_CFG_EMC2PMACRO_CFG_BYPASS_DATAPIPE2_MASK = 1 << 3,
+
+	EMC_NOP_CMD_SHIFT = 0,
+	EMC_NOP_CMD_MASK = 1 << EMC_NOP_CMD_SHIFT,
+	EMC_NOP_DEV_SELECTN_SHIFT = 30,
+	EMC_NOP_DEV_SELECTN_MASK = 3 << EMC_NOP_DEV_SELECTN_SHIFT,
+
+	EMC_TIMING_CONTROL_TIMING_UPDATE = 1,
+
+	EMC_PIN_GPIOEN_SHIFT = 16,
+	EMC_PIN_GPIO_SHIFT = 12,
+	EMC_PMACRO_BRICK_CTRL_RFU1_RESET_VAL = 0x1FFF1FFF,
+
+	AUTOCAL_MEASURE_STALL_ENABLE = 1 << 9,
+	WRITE_MUX_ACTIVE = 1 << 1,
+	CFG_ADR_EN_LOCKED = 1 << 1,
+};
+
+struct tegra_emc_regs {
+	uint32_t intstatus;		/* 0x0 */
+	uint32_t intmask;		/* 0x4 */
+	uint32_t dbg;			/* 0x8 */
+	uint32_t cfg;			/* 0xc */
+	uint32_t adr_cfg;		/* 0x10 */
+	uint32_t rsvd_0x14[3];		/* 0x14-0x1C */
+
+	uint32_t refctrl;		/* 0x20 */
+	uint32_t pin;			/* 0x24 */
+	uint32_t timing_control;	/* 0x28 */
+	uint32_t rc;			/* 0x2c */
+	uint32_t rfc;			/* 0x30 */
+	uint32_t ras;			/* 0x34 */
+	uint32_t rp;			/* 0x38 */
+	uint32_t r2w;			/* 0x3c */
+	uint32_t w2r;			/* 0x40 */
+	uint32_t r2p;			/* 0x44 */
+	uint32_t w2p;			/* 0x48 */
+	uint32_t rd_rcd;		/* 0x4c */
+	uint32_t wr_rcd;		/* 0x50 */
+	uint32_t rrd;			/* 0x54 */
+	uint32_t rext;			/* 0x58 */
+	uint32_t wdv;			/* 0x5c */
+	uint32_t quse;			/* 0x60 */
+	uint32_t qrst;			/* 0x64 */
+	uint32_t qsafe;			/* 0x68 */
+	uint32_t rdv;			/* 0x6c */
+	uint32_t refresh;		/* 0x70 */
+	uint32_t burst_refresh_num;	/* 0x74 */
+	uint32_t pdex2wr;		/* 0x78 */
+	uint32_t pdex2rd;		/* 0x7c */
+	uint32_t pchg2pden;		/* 0x80 */
+	uint32_t act2pden;		/* 0x84 */
+	uint32_t ar2pden;		/* 0x88 */
+	uint32_t rw2pden;		/* 0x8c */
+	uint32_t txsr;			/* 0x90 */
+	uint32_t tcke;			/* 0x94 */
+	uint32_t tfaw;			/* 0x98 */
+	uint32_t trpab;			/* 0x9c */
+	uint32_t tclkstable;		/* 0xa0 */
+	uint32_t tclkstop;		/* 0xa4 */
+	uint32_t trefbw;		/* 0xa8 */
+	uint32_t tppd;			/* 0xac */
+	uint32_t odt_write;		/* 0xb0 */
+	uint32_t pdex2mrr;		/* 0xb4 */
+	uint32_t wext;			/* 0xb8 */
+	uint32_t ctt;			/* 0xbc */
+	uint32_t rfc_slr;		/* 0xc0 */
+	uint32_t mrs_wait_cnt2;		/* 0xc4 */
+	uint32_t mrs_wait_cnt;		/* 0xc8 */
+	uint32_t mrs;			/* 0xcc */
+	uint32_t emrs;			/* 0xd0 */
+	uint32_t ref;			/* 0xd4 */
+	uint32_t pre;			/* 0xd8 */
+	uint32_t nop;			/* 0xdc */
+	uint32_t self_ref;		/* 0xe0 */
+	uint32_t dpd;			/* 0xe4 */
+	uint32_t mrw;			/* 0xe8 */
+	uint32_t mrr;			/* 0xec */
+	uint32_t cmdq;			/* 0xf0 */
+	uint32_t mc2emcq;		/* 0xf4 */
+	uint32_t xm2dqspadctrl3;	/* 0xf8 */
+	uint32_t rsvd_0xfc[1];		/* 0xfc */
+	uint32_t fbio_spare;		/* 0x100 */
+	uint32_t fbio_cfg5;		/* 0x104 */
+	uint32_t fbio_wrptr_eq_2;	/* 0x108 */
+	uint32_t rsvd_0x10c[2];		/* 0x10c-0x110 */
+
+	uint32_t fbio_cfg6;		/* 0x114 */
+	uint32_t pdex2cke;		/* 0x118 */
+	uint32_t cke2pden;		/* 0x11C */
+	uint32_t cfg_rsv;		/* 0x120 */
+	uint32_t acpd_control;		/* 0x124 */
+	uint32_t rsvd_0x128[1];		/* 0x128 */
+	uint32_t emrs2;			/* 0x12c */
+	uint32_t emrs3;			/* 0x130 */
+	uint32_t mrw2;			/* 0x134 */
+	uint32_t mrw3;			/* 0x138 */
+	uint32_t mrw4;			/* 0x13c */
+	uint32_t clken_override;	/* 0x140 */
+	uint32_t r2r;			/* 0x144 */
+	uint32_t w2w;			/* 0x148 */
+	uint32_t einput;		/* 0x14c */
+	uint32_t einput_duration;	/* 0x150 */
+	uint32_t puterm_extra;		/* 0x154 */
+	uint32_t tckesr;		/* 0x158 */
+	uint32_t tpd;			/* 0x15c */
+	uint32_t rsvd_0x160[81];	/* 0x160-0x2A0 */
+
+	uint32_t auto_cal_config;	/* 0x2a4 */
+	uint32_t auto_cal_interval;	/* 0x2a8 */
+	uint32_t auto_cal_status;	/* 0x2ac */
+	uint32_t req_ctrl;		/* 0x2b0 */
+	uint32_t status;		/* 0x2b4 */
+	uint32_t cfg_2;			/* 0x2b8 */
+	uint32_t cfg_dig_dll;		/* 0x2bc */
+	uint32_t cfg_dig_dll_period;	/* 0x2c0 */
+	uint32_t dig_dll_status;	/* 0x2C4 */
+	uint32_t cfg_dig_dll_1;		/* 0x2C8 */
+	uint32_t rdv_mask;		/* 0x2cc */
+	uint32_t wdv_mask;		/* 0x2d0 */
+	uint32_t rdv_early_mask;	/* 0x2d4 */
+	uint32_t rdv_early;		/* 0x2d8 */
+	uint32_t auto_cal_config8;	/* 0x2DC */
+	uint32_t zcal_interval;		/* 0x2e0 */
+	uint32_t zcal_wait_cnt;		/* 0x2e4 */
+	uint32_t zcal_mrw_cmd;		/* 0x2e8 */
+	uint32_t zq_cal;		/* 0x2ec */
+	uint32_t xm2cmdpadctrl;		/* 0x2f0 */
+	uint32_t xm2comppadctrl3;	/* 0x2f4 */
+	uint32_t auto_cal_vref_sel0;	/* 0x2f8 */
+	uint32_t xm2dqspadctrl2;	/* 0x2fc */
+	uint32_t auto_cal_vref_sel1;	/* 0x300 */
+	uint32_t xm2dqpadctrl2;		/* 0x304 */
+	uint32_t xm2clkpadctrl;		/* 0x308 */
+	uint32_t xm2comppadctrl;	/* 0x30c */
+	uint32_t fdpd_ctrl_dq;		/* 0x310 */
+	uint32_t fdpd_ctrl_cmd;		/* 0x314 */
+	uint32_t pmacro_cmd_brick_ctrl_fdpd;	/* 0x318 */
+	uint32_t pmacro_data_brick_ctrl_fdpd;	/* 0x31c */
+	uint32_t xm2dqspadctrl4;	/* 0x320 */
+	uint32_t scratch0;		/* 0x324 */
+	uint32_t rsvd_0x328[2];		/* 0x328-0x32C */
+
+	uint32_t pmacro_brick_ctrl_rfu1; /* 0x330 */
+	uint32_t pmacro_brick_ctrl_rfu2; /* 0x334 */
+	uint32_t rsvd_0x338[18];	/* 0x338-0x37C */
+
+	uint32_t cmd_mapping_cmd0_0;	/* 0x380 */
+	uint32_t cmd_mapping_cmd0_1;	/* 0x384 */
+	uint32_t cmd_mapping_cmd0_2;	/* 0x388 */
+	uint32_t cmd_mapping_cmd1_0;	/* 0x38c */
+	uint32_t cmd_mapping_cmd1_1;	/* 0x390 */
+	uint32_t cmd_mapping_cmd1_2;	/* 0x394 */
+	uint32_t cmd_mapping_cmd2_0;	/* 0x398 */
+	uint32_t cmd_mapping_cmd2_1;	/* 0x39C */
+	uint32_t cmd_mapping_cmd2_2;	/* 0x3A0 */
+	uint32_t cmd_mapping_cmd3_0;	/* 0x3A4 */
+	uint32_t cmd_mapping_cmd3_1;	/* 0x3A8 */
+	uint32_t cmd_mapping_cmd3_2;	/* 0x3AC */
+	uint32_t cmd_mapping_byte;	/* 0x3B0 */
+	uint32_t tr_timing_0;		/* 0x3B4 */
+	uint32_t tr_ctrl_0;		/* 0x3B8 */
+	uint32_t tr_ctrl_1;		/* 0x3BC */
+	uint32_t switch_back_ctrl;	/* 0x3C0 */
+	uint32_t tr_rdv;		/* 0x3C4 */
+	uint32_t stall_then_exe_before_clkchange;	/* 0x3c8 */
+	uint32_t stall_then_exe_after_clkchange;	/* 0x3cc */
+	uint32_t unstall_rw_after_clkchange;		/* 0x3d0 */
+	uint32_t auto_cal_clk_status;	/* 0x3d4 */
+	uint32_t sel_dpd_ctrl;		/* 0x3d8 */
+	uint32_t pre_refresh_req_cnt;	/* 0x3dc */
+	uint32_t dyn_self_ref_control;	/* 0x3e0 */
+	uint32_t txsrdll;		/* 0x3e4 */
+	uint32_t ccfifo_addr;		/* 0x3e8 */
+	uint32_t ccfifo_data;		/* 0x3ec */
+	uint32_t ccfifo_status;		/* 0x3f0 */
+	uint32_t cdb_cntl_1;		/* 0x3f4 */
+	uint32_t cdb_cntl_2;		/* 0x3f8 */
+	uint32_t xm2clkpadctrl2;	/* 0x3fc */
+	uint32_t swizzle_rank0_byte_cfg; /* 0x400 */
+	uint32_t swizzle_rank0_byte0;	/* 0x404 */
+	uint32_t swizzle_rank0_byte1;	/* 0x408 */
+	uint32_t swizzle_rank0_byte2;	/* 0x40c */
+	uint32_t swizzle_rank0_byte3;	/* 0x410 */
+	uint32_t swizzle_rank1_byte_cfg; /* 0x414 */
+	uint32_t swizzle_rank1_byte0;	/* 0x418 */
+	uint32_t swizzle_rank1_byte1;	/* 0x41c */
+	uint32_t swizzle_rank1_byte2;	/* 0x420 */
+	uint32_t swizzle_rank1_byte3;	/* 0x424 */
+	uint32_t issue_qrst;		/* 0x428 */
+	uint32_t rsvd_0x42C[5];		/* 0x42C-0x43C */
+	uint32_t pmc_scratch1;		/* 0x440 */
+	uint32_t pmc_scratch2;		/* 0x444 */
+	uint32_t pmc_scratch3;		/* 0x448 */
+	uint32_t rsvd_0x44C[3];		/* 0x44C-0x454 */
+	uint32_t auto_cal_config2;	/* 0x458 */
+	uint32_t auto_cal_config3;	/* 0x45c */
+	uint32_t auto_cal_status2;	/* 0x460 */
+	uint32_t auto_cal_channel;	/* 0x464 */
+	uint32_t ibdly;			/* 0x468 */
+	uint32_t obdly;			/* 0x46c */
+	uint32_t rsvd_0x470[3];		/* 0x470-0x478 */
+
+	uint32_t dsr_vttgen_drv;	/* 0x47c */
+	uint32_t txdsrvttgen;		/* 0x480 */
+	uint32_t xm2cmdpadctrl4;	/* 0x484 */
+	uint32_t xm2cmdpadctrl5;	/* 0x488 */
+	uint32_t we_duration;		/* 0x48C */
+	uint32_t ws_duration;		/* 0x490 */
+	uint32_t wev;			/* 0x494 */
+	uint32_t wsv;			/* 0x498 */
+	uint32_t cfg_3;			/* 0x49C */
+	uint32_t mrw5;			/* 0x4A0 */
+	uint32_t mrw6;			/* 0x4A4 */
+	uint32_t mrw7;			/* 0x4A8 */
+	uint32_t mrw8;			/* 0x4AC */
+	uint32_t mrw9;			/* 0x4B0 */
+	uint32_t mrw10;			/* 0x4B4 */
+	uint32_t mrw11;			/* 0x4B8 */
+	uint32_t mrw12;			/* 0x4BC */
+	uint32_t mrw13;			/* 0x4C0 */
+	uint32_t mrw14;			/* 0x4C4 */
+	uint32_t rsvd_0x4c8[2];		/* 0x4C8-0x4CC */
+
+	uint32_t mrw15;			/* 0x4D0 */
+	uint32_t cfg_sync;		/* 0x4D4 */
+	uint32_t fdpd_ctrl_cmd_no_ramp;	/* 0x4D8 */
+	uint32_t rsvd_0x4dc[1];		/* 0x4DC */
+	uint32_t wdv_chk;		/* 0x4E0 */
+	uint32_t rsvd_0x4e4[28];	/* 0x4E4-0x550 */
+
+	uint32_t cfg_pipe2;		/* 0x554 */
+	uint32_t cfg_pipe_clk;		/* 0x558 */
+	uint32_t cfg_pipe1;		/* 0x55C */
+	uint32_t cfg_pipe;		/* 0x560 */
+	uint32_t qpop;			/* 0x564 */
+	uint32_t quse_width;		/* 0x568 */
+	uint32_t puterm_width;		/* 0x56c */
+	uint32_t bgbias_ctl0;		/* 0x570 */
+	uint32_t auto_cal_config7;	/* 0x574 */
+	uint32_t xm2comppadctrl2;	/* 0x578 */
+	uint32_t comppadswctrl;		/* 0x57C */
+	uint32_t refctrl2;		/* 0x580 */
+	uint32_t fbio_cfg7;		/* 0x584 */
+	uint32_t data_brlshft_0;	/* 0x588 */
+	uint32_t data_brlshft_1;	/* 0x58C */
+	uint32_t rfcpb;			/* 0x590 */
+	uint32_t dqs_brlshft_0;		/* 0x594 */
+	uint32_t dqs_brlshft_1;		/* 0x598 */
+	uint32_t cmd_brlshft_0;		/* 0x59C */
+	uint32_t cmd_brlshft_1;		/* 0x5A0 */
+	uint32_t cmd_brlshft_2;		/* 0x5A4 */
+	uint32_t cmd_brlshft_3;		/* 0x5A8 */
+	uint32_t quse_brlshft_0;	/* 0x5AC */
+	uint32_t auto_cal_config4;	/* 0x5B0 */
+	uint32_t auto_cal_config5;	/* 0x5B4 */
+	uint32_t quse_brlshft_1;	/* 0x5B8 */
+	uint32_t quse_brlshft_2;	/* 0x5BC */
+	uint32_t ccdmw;			/* 0x5C0 */
+	uint32_t quse_brlshft_3;	/* 0x5C4 */
+	uint32_t fbio_cfg8;		/* 0x5C8 */
+	uint32_t auto_cal_config6;	/* 0x5CC */
+	uint32_t protobist_config_addr_1; /* 0x5D0 */
+	uint32_t protobist_config_addr_2; /* 0x5D4 */
+	uint32_t protobist_misc;	/* 0x5D8 */
+	uint32_t protobist_wdata_lower;	/* 0x5DC */
+	uint32_t protobist_wdata_upper;	/* 0x5E0 */
+	uint32_t dll_cfg0;		/* 0x5E4 */
+	uint32_t dll_cfg1;		/* 0x5E8 */
+	uint32_t protobist_rdata;	/* 0x5EC */
+	uint32_t config_sample_delay;	/* 0x5F0 */
+	uint32_t cfg_update;		/* 0x5F4 */
+	uint32_t rsvd_0x5f8[2];		/* 0x5F8-0x5FC */
+
+	uint32_t pmacro_quse_ddll_rank0_0;	/* 0x600 */
+	uint32_t pmacro_quse_ddll_rank0_1;	/* 0x604 */
+	uint32_t pmacro_quse_ddll_rank0_2;	/* 0x608 */
+	uint32_t pmacro_quse_ddll_rank0_3;	/* 0x60C */
+	uint32_t pmacro_quse_ddll_rank0_4;	/* 0x610 */
+	uint32_t pmacro_quse_ddll_rank0_5;	/* 0x614 */
+	uint32_t rsvd_0x618[2];		/* 0x618-0x61C */
+
+	uint32_t pmacro_quse_ddll_rank1_0;	/* 0x620 */
+	uint32_t pmacro_quse_ddll_rank1_1;	/* 0x624 */
+	uint32_t pmacro_quse_ddll_rank1_2;	/* 0x628 */
+	uint32_t pmacro_quse_ddll_rank1_3;	/* 0x62C */
+	uint32_t pmacro_quse_ddll_rank1_4;	/* 0x630 */
+	uint32_t pmacro_quse_ddll_rank1_5;	/* 0x634 */
+	uint32_t rsvd_0x638[2];		/* 0x638-0x63C */
+
+	uint32_t pmacro_ob_ddll_long_dq_rank0_0;	/* 0x640 */
+	uint32_t pmacro_ob_ddll_long_dq_rank0_1;	/* 0x644 */
+	uint32_t pmacro_ob_ddll_long_dq_rank0_2;	/* 0x648 */
+	uint32_t pmacro_ob_ddll_long_dq_rank0_3;	/* 0x64C */
+	uint32_t pmacro_ob_ddll_long_dq_rank0_4;	/* 0x650 */
+	uint32_t pmacro_ob_ddll_long_dq_rank0_5;	/* 0x654 */
+	uint32_t rsvd_0x658[2];		/* 0x658-0x65C */
+
+	uint32_t pmacro_ob_ddll_long_dq_rank1_0;	/* 0x660 */
+	uint32_t pmacro_ob_ddll_long_dq_rank1_1;	/* 0x664 */
+	uint32_t pmacro_ob_ddll_long_dq_rank1_2;	/* 0x668 */
+	uint32_t pmacro_ob_ddll_long_dq_rank1_3;	/* 0x66C */
+	uint32_t pmacro_ob_ddll_long_dq_rank1_4;	/* 0x670 */
+	uint32_t pmacro_ob_ddll_long_dq_rank1_5;	/* 0x674 */
+	uint32_t rsvd_0x678[2];		/* 0x678-0x67C */
+
+	uint32_t pmacro_ob_ddll_long_dqs_rank0_0;	/* 0x680 */
+	uint32_t pmacro_ob_ddll_long_dqs_rank0_1;	/* 0x684 */
+	uint32_t pmacro_ob_ddll_long_dqs_rank0_2;	/* 0x688 */
+	uint32_t pmacro_ob_ddll_long_dqs_rank0_3;	/* 0x68C */
+	uint32_t pmacro_ob_ddll_long_dqs_rank0_4;	/* 0x690 */
+	uint32_t pmacro_ob_ddll_long_dqs_rank0_5;	/* 0x694 */
+	uint32_t rsvd_0x698[2];		/* 0x698-0x69C */
+
+	uint32_t pmacro_ob_ddll_long_dqs_rank1_0;	/* 0x6A0 */
+	uint32_t pmacro_ob_ddll_long_dqs_rank1_1;	/* 0x6A4 */
+	uint32_t pmacro_ob_ddll_long_dqs_rank1_2;	/* 0x6A8 */
+	uint32_t pmacro_ob_ddll_long_dqs_rank1_3;	/* 0x6AC */
+	uint32_t pmacro_ob_ddll_long_dqs_rank1_4;	/* 0x6B0 */
+	uint32_t pmacro_ob_ddll_long_dqs_rank1_5;	/* 0x6B4 */
+	uint32_t rsvd_0x6B8[2];		/* 0x6B8-0x6BC */
+
+	uint32_t pmacro_ib_ddll_long_dqs_rank0_0;	/* 0x6C0 */
+	uint32_t pmacro_ib_ddll_long_dqs_rank0_1;	/* 0x6C4 */
+	uint32_t pmacro_ib_ddll_long_dqs_rank0_2;	/* 0x6C8 */
+	uint32_t pmacro_ib_ddll_long_dqs_rank0_3;	/* 0x6CC */
+	uint32_t pmacro_ib_ddll_long_dqs_rank0_4;	/* 0x6D0 */
+	uint32_t pmacro_ib_ddll_long_dqs_rank0_5;	/* 0x6D4 */
+	uint32_t rsvd_0x6D8[2];		/* 0x6D8-0x6DC */
+
+	uint32_t pmacro_ib_ddll_long_dqs_rank1_0;	/* 0x6E0 */
+	uint32_t pmacro_ib_ddll_long_dqs_rank1_1;	/* 0x6E4 */
+	uint32_t pmacro_ib_ddll_long_dqs_rank1_2;	/* 0x6E8 */
+	uint32_t pmacro_ib_ddll_long_dqs_rank1_3;	/* 0x6EC */
+	uint32_t pmacro_ib_ddll_long_dqs_rank1_4;	/* 0x6F0 */
+	uint32_t pmacro_ib_ddll_long_dqs_rank1_5;	/* 0x6F4 */
+	uint32_t rsvd_0x6F8[2];		/* 0x6F8-0x6FC */
+
+	uint32_t pmacro_autocal_cfg0;	/* 0x700 */
+	uint32_t pmacro_autocal_cfg1;	/* 0x704 */
+	uint32_t pmacro_autocal_cfg2;	/* 0x708 */
+	uint32_t rsvd_0x70C[5];		/* 0x70C-0x71C */
+
+	uint32_t pmacro_tx_pwrd_0;	/* 0x720 */
+	uint32_t pmacro_tx_pwrd_1;	/* 0x724 */
+	uint32_t pmacro_tx_pwrd_2;	/* 0x728 */
+	uint32_t pmacro_tx_pwrd_3;	/* 0x72C */
+	uint32_t pmacro_tx_pwrd_4;	/* 0x730 */
+	uint32_t pmacro_tx_pwrd_5;	/* 0x734 */
+	uint32_t rsvd_0x738[2];		/* 0x738-0x73C */
+
+	uint32_t pmacro_tx_sel_clk_src_0;	/* 0x740 */
+	uint32_t pmacro_tx_sel_clk_src_1;	/* 0x744 */
+	uint32_t pmacro_tx_sel_clk_src_2;	/* 0x748 */
+	uint32_t pmacro_tx_sel_clk_src_3;	/* 0x74C */
+	uint32_t pmacro_tx_sel_clk_src_4;	/* 0x750 */
+	uint32_t pmacro_tx_sel_clk_src_5;	/* 0x754 */
+	uint32_t rsvd_0x758[2];		/* 0x758-0x75C */
+
+	uint32_t pmacro_ddll_bypass;	/* 0x760 */
+	uint32_t rsvd_0x764[3];		/* 0x764-0x76C */
+
+	uint32_t pmacro_ddll_pwrd_0;	/* 0x770 */
+	uint32_t pmacro_ddll_pwrd_1;	/* 0x774 */
+	uint32_t pmacro_ddll_pwrd_2;	/* 0x778 */
+	uint32_t rsvd_0x77C[1];		/* 0x77C */
+	uint32_t pmacro_cmd_ctrl_0;	/* 0x780 */
+	uint32_t pmacro_cmd_ctrl_1;	/* 0x784 */
+	uint32_t pmacro_cmd_ctrl_2;	/* 0x788 */
+	uint32_t rsvd_0x78C[277];	/* 0x78C-0xBDC */
+
+	uint32_t pmacro_ib_vref_dq_0;		/* 0xBE0 */
+	uint32_t pmacro_ib_vref_dq_1;		/* 0xBE4 */
+	uint32_t pmacro_ib_vref_dq_2;		/* 0xBE8 */
+	uint32_t rsvd_0xBEC[1];			/* 0xBEC */
+	uint32_t pmacro_ib_vref_dqs_0;		/* 0xBF0 */
+	uint32_t pmacro_ib_vref_dqs_1;		/* 0xBF4 */
+	uint32_t pmacro_ib_vref_dqs_2;		/* 0xBF8 */
+	uint32_t rsvd_0xBFC[1];			/* 0xBFC */
+	uint32_t pmacro_ddll_long_cmd_0;	/* 0xC00 */
+	uint32_t pmacro_ddll_long_cmd_1;	/* 0xC04 */
+	uint32_t pmacro_ddll_long_cmd_2;	/* 0xC08 */
+	uint32_t pmacro_ddll_long_cmd_3;	/* 0xC0C */
+	uint32_t pmacro_ddll_long_cmd_4;	/* 0xC10 */
+	uint32_t pmacro_ddll_long_cmd_5;	/* 0xC14 */
+	uint32_t rsvd_0xC18[2];			/* 0xC18-0xC1C */
+
+	uint32_t pmacro_ddll_short_cmd_0;	/* 0xC20 */
+	uint32_t pmacro_ddll_short_cmd_1;	/* 0xC24 */
+	uint32_t pmacro_ddll_short_cmd_2;	/* 0xC28 */
+	uint32_t rsvd_0xC2C[2];			/* 0xC2C-0xC30 */
+
+	uint32_t pmacro_vttgen_ctrl0;		/* 0xC34 */
+	uint32_t pmacro_vttgen_ctrl1;		/* 0xC38 */
+	uint32_t pmacro_bg_bias_ctrl_0;		/* 0xC3C */
+	uint32_t pmacro_pad_cfg_ctrl;		/* 0xC40 */
+	uint32_t pmacro_zctrl;			/* 0xC44 */
+	uint32_t pmacro_rx_term;		/* 0xC48 */
+	uint32_t pmacro_cmd_tx_drv;		/* 0xC4C */
+	uint32_t pmacro_cmd_pad_rx_ctrl;	/* 0xC50 */
+	uint32_t pmacro_data_pad_rx_ctrl;	/* 0xC54 */
+	uint32_t pmacro_cmd_rx_term_mode;	/* 0xC58 */
+	uint32_t pmacro_data_rx_term_mode;	/* 0xC5C */
+	uint32_t pmacro_cmd_pad_tx_ctrl;	/* 0xC60 */
+	uint32_t pmacro_data_pad_tx_ctrl;	/* 0xC64 */
+	uint32_t pmacro_common_pad_tx_ctrl;	/* 0xC68 */
+	uint32_t rsvd_0xC6C[1];			/* 0xC6C */
+	uint32_t pmacro_dq_tx_drv;		/* 0xC70 */
+	uint32_t pmacro_ca_tx_drv;		/* 0xC74 */
+	uint32_t pmacro_autocal_cfg_common;	/* 0xC78 */
+	uint32_t rsvd_0xC7C[1];			/* 0xC7C */
+	uint32_t pmacro_brick_mapping0;		/* 0xC80 */
+	uint32_t pmacro_brick_mapping1;		/* 0xC84 */
+	uint32_t pmacro_brick_mapping2;		/* 0xC88 */
+	uint32_t rsvd_0xC8C[25];		/* 0xC8C-0xCEC */
+
+	uint32_t pmacro_vttgen_ctrl2;		/* 0xCF0 */
+	uint32_t pmacro_ib_rxrt;		/* 0xCF4 */
+	uint32_t pmacro_training_ctrl0;		/* 0xCF8 */
+	uint32_t pmacro_training_ctrl1;		/* 0xCFC */
+} __attribute__((packed));
+
+check_member(tegra_emc_regs, pmacro_training_ctrl1, 0xCFC);
+
+#endif /* __SOC_NVIDIA_TEGRA210_EMC_H__ */
diff --git a/src/soc/nvidia/tegra210/include/soc/flow.h b/src/soc/nvidia/tegra210/include/soc/flow.h
new file mode 100644
index 0000000..a3eccf8
--- /dev/null
+++ b/src/soc/nvidia/tegra210/include/soc/flow.h
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2010-2015, NVIDIA CORPORATION.  All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _TEGRA210_FLOW_H_
+#define _TEGRA210_FLOW_H_
+
+struct flow_ctlr {
+	u32 halt_cpu_events;	/* offset 0x00 */
+	u32 halt_cop_events;	/* offset 0x04 */
+	u32 cpu_csr;		/* offset 0x08 */
+	u32 cop_csr;		/* offset 0x0c */
+	u32 xrq_events;		/* offset 0x10 */
+	u32 halt_cpu1_events;	/* offset 0x14 */
+	u32 cpu1_csr;		/* offset 0x18 */
+	u32 halt_cpu2_events;	/* offset 0x1c */
+	u32 cpu2_csr;		/* offset 0x20 */
+	u32 halt_cpu3_events;	/* offset 0x24 */
+	u32 cpu3_csr;		/* offset 0x28 */
+	u32 cluster_control;	/* offset 0x2c */
+	u32 halt_cop1_events;	/* offset 0x30 */
+	u32 halt_cop1_csr;	/* offset 0x34 */
+	u32 cpu_pwr_csr;	/* offset 0x38 */
+	u32 mpid;		/* offset 0x3c */
+	u32 ram_repair;		/* offset 0x40 */
+	u32 flow_dbg_sel;	/* offset 0x44 */
+	u32 flow_dbg_cnt0;	/* offset 0x48 */
+	u32 flow_dbg_cnt1;	/* offset 0x4c */
+	u32 flow_dbg_qual;	/* offset 0x50 */
+	u32 flow_ctlr_spare;	/* offset 0x54 */
+	u32 reserved;		/* offset 0x58 */
+	u32 fc_seq_intercept;	/* offset 0x5c */
+};
+check_member(flow_ctlr, fc_seq_intercept, 0x5c);
+
+enum {
+	FLOW_MODE_SHIFT = 29,
+	FLOW_MODE_MASK = 0x7 << FLOW_MODE_SHIFT,
+
+	FLOW_MODE_NONE = 0 << FLOW_MODE_SHIFT,
+	FLOW_MODE_RUN_AND_INT = 1 << FLOW_MODE_SHIFT,
+	FLOW_MODE_WAITEVENT = 2 << FLOW_MODE_SHIFT,
+	FLOW_MODE_WAITEVENT_AND_INT = 3 << FLOW_MODE_SHIFT,
+	FLOW_MODE_STOP_UNTIL_IRQ = 4 << FLOW_MODE_SHIFT,
+	FLOW_MODE_STOP_UNTIL_IRQ_AND_INT = 5 << FLOW_MODE_SHIFT,
+	FLOW_MODE_STOP_UNTIL_EVENT_AND_IRQ = 6 << FLOW_MODE_SHIFT,
+};
+
+/* HALT_COP_EVENTS_0, 0x04 */
+enum {
+	FLOW_EVENT_GIC_FIQ = 1 << 8,
+	FLOW_EVENT_GIC_IRQ = 1 << 9,
+	FLOW_EVENT_LIC_FIQ = 1 << 10,
+	FLOW_EVENT_LIC_IRQ = 1 << 11,
+	FLOW_EVENT_IBF = 1 << 12,
+	FLOW_EVENT_IBE = 1 << 13,
+	FLOW_EVENT_OBF = 1 << 14,
+	FLOW_EVENT_OBE = 1 << 15,
+	FLOW_EVENT_XRQ_A = 1 << 16,
+	FLOW_EVENT_XRQ_B = 1 << 17,
+	FLOW_EVENT_XRQ_C = 1 << 18,
+	FLOW_EVENT_XRQ_D = 1 << 19,
+	FLOW_EVENT_SMP30 = 1 << 20,
+	FLOW_EVENT_SMP31 = 1 << 21,
+	FLOW_EVENT_X_RDY = 1 << 22,
+	FLOW_EVENT_SEC = 1 << 23,
+	FLOW_EVENT_MSEC = 1 << 24,
+	FLOW_EVENT_USEC = 1 << 25,
+	FLOW_EVENT_X32K = 1 << 26,
+	FLOW_EVENT_SCLK = 1 << 27,
+	FLOW_EVENT_JTAG = 1 << 28
+};
+
+#endif	/*  _TEGRA210_FLOW_H_ */
diff --git a/src/soc/nvidia/tegra210/include/soc/flow_ctrl.h b/src/soc/nvidia/tegra210/include/soc/flow_ctrl.h
new file mode 100644
index 0000000..47d68b0
--- /dev/null
+++ b/src/soc/nvidia/tegra210/include/soc/flow_ctrl.h
@@ -0,0 +1,30 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (c) 2014-2015, NVIDIA CORPORATION.  All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc.
+ */
+
+#ifndef _TEGRA210_FLOW_CTRL_H_
+#define _TEGRA210_FLOW_CTRL_H_
+
+void flowctrl_cpu_off(int cpu);
+void flowctrl_cpu_on(int cpu);
+void flowctrl_cpu_suspend(int cpu);
+void flowctrl_write_cc4_ctrl(int cpu, uint32_t val);
+void flowctrl_write_cpu_csr(int cpu, uint32_t val);
+void flowctrl_write_cpu_halt(int cpu, uint32_t val);
+
+#endif
diff --git a/src/soc/nvidia/tegra210/include/soc/funitcfg.h b/src/soc/nvidia/tegra210/include/soc/funitcfg.h
new file mode 100644
index 0000000..d51b13f
--- /dev/null
+++ b/src/soc/nvidia/tegra210/include/soc/funitcfg.h
@@ -0,0 +1,94 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright 2014 Google Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc.
+ */
+
+#ifndef __SOC_NVIDIA_TEGRA210_FUNIT_CFG_H
+#define __SOC_NVIDIA_TEGRA210_FUNIT_CFG_H
+
+#include <soc/clock.h>
+#include <soc/padconfig.h>
+#include <soc/pinmux.h>
+#include <stdint.h>
+
+#define FUNIT_INDEX(_name)  FUNIT_##_name
+
+enum {
+	FUNIT_INDEX(I2C1),
+	FUNIT_INDEX(I2C2),
+	FUNIT_INDEX(I2C3),
+	FUNIT_INDEX(I2C5),
+	FUNIT_INDEX(I2C6),
+	FUNIT_INDEX(SDMMC1),
+	FUNIT_INDEX(SDMMC4),
+	FUNIT_INDEX(USBD),
+	FUNIT_INDEX(USB2),
+	FUNIT_INDEX(QSPI),
+	FUNIT_INDEX(I2S1),
+	FUNIT_INDEX_MAX,
+};
+
+/*
+ * Note: these bus numbers are dependent on the driver implementations, and
+ * currently the I2C is 0-based and SPI is 1-based in its indexing.
+ */
+enum {
+
+	I2C1_BUS = 0,
+	I2C2_BUS = 1,
+	I2C3_BUS = 2,
+	I2C5_BUS = 4,
+	I2CPWR_BUS = I2C5_BUS,
+	I2C6_BUS = 5,
+	QSPI_BUS = 7,
+
+	SPI1_BUS = 1,
+	SPI4_BUS = 4,
+};
+
+struct funit_cfg {
+	uint32_t funit_index;
+	uint32_t clk_src_id;
+	uint32_t clk_src_freq_id;
+	uint32_t clk_dev_freq_khz;
+	struct pad_config const* pad_cfg;
+	size_t pad_cfg_size;
+};
+
+#define FUNIT_CFG(_funit,_clk_src,_clk_freq,_cfg,_cfg_size)		\
+	{								\
+		.funit_index = FUNIT_INDEX(_funit),			\
+		.clk_src_id = CLK_SRC_DEV_ID(_funit, _clk_src),		\
+		.clk_src_freq_id = CLK_SRC_FREQ_ID(_funit, _clk_src),	\
+		.clk_dev_freq_khz = _clk_freq,				\
+		.pad_cfg = _cfg,					\
+		.pad_cfg_size = _cfg_size,				\
+	}
+
+#define FUNIT_CFG_USB(_funit)						\
+	{								\
+		.funit_index = FUNIT_INDEX(_funit),			\
+		.pad_cfg = NULL,					\
+		.pad_cfg_size = 0,					\
+	}
+
+/*
+ * Configure the funits associated with entry according to the configuration.
+ */
+void soc_configure_funits(const struct funit_cfg * const entries, size_t num);
+
+#endif /* __SOC_NVIDIA_TEGRA210_FUNIT_CFG_H */
diff --git a/src/soc/nvidia/tegra210/include/soc/gpio.h b/src/soc/nvidia/tegra210/include/soc/gpio.h
new file mode 100644
index 0000000..f4c236a
--- /dev/null
+++ b/src/soc/nvidia/tegra210/include/soc/gpio.h
@@ -0,0 +1,25 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright 2014 Google Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc.
+ */
+
+#ifndef __SOC_NVIDIA_TEGRA210_GPIO_H__
+#define __SOC_NVIDIA_TEGRA210_GPIO_H__
+
+#include <soc/pinmux.h>
+
+#endif	/* __SOC_NVIDIA_TEGRA210_GPIO_H__ */
diff --git a/src/soc/nvidia/tegra210/include/soc/id.h b/src/soc/nvidia/tegra210/include/soc/id.h
new file mode 100644
index 0000000..5090a31
--- /dev/null
+++ b/src/soc/nvidia/tegra210/include/soc/id.h
@@ -0,0 +1,35 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright 2014 Google Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc.
+ */
+
+#ifndef __SOC_NVIDIA_TEGRA210_INCLUDE_SOC_ID_H__
+#define __SOC_NVIDIA_TEGRA210_INCLUDE_SOC_ID_H__
+
+
+#include <arch/io.h>
+#include <soc/addressmap.h>
+
+static inline int context_avp(void)
+{
+	const uint32_t avp_id = 0xaaaaaaaa;
+	void * const uptag = (void *)(uintptr_t)TEGRA_PG_UP_BASE;
+
+	return read32(uptag) == avp_id;
+}
+
+#endif /* define __SOC_NVIDIA_TEGRA210_INCLUDE_SOC_ID_H__ */
diff --git a/src/soc/nvidia/tegra210/include/soc/maincpu.h b/src/soc/nvidia/tegra210/include/soc/maincpu.h
new file mode 100644
index 0000000..813caba
--- /dev/null
+++ b/src/soc/nvidia/tegra210/include/soc/maincpu.h
@@ -0,0 +1,29 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright 2014 Google Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc.
+ */
+
+#ifndef __SOC_NVIDIA_TEGRA210_MAINCPU_H__
+#define __SOC_NVIDIA_TEGRA210_MAINCPU_H__
+
+#include <stdint.h>
+
+extern u32 maincpu_stack_pointer;
+extern u32 maincpu_entry_point;
+void maincpu_setup(void);
+
+#endif	/* __SOC_NVIDIA_TEGRA210_MAINCPU_H__ */
diff --git a/src/soc/nvidia/tegra210/include/soc/mc.h b/src/soc/nvidia/tegra210/include/soc/mc.h
new file mode 100644
index 0000000..51ae827
--- /dev/null
+++ b/src/soc/nvidia/tegra210/include/soc/mc.h
@@ -0,0 +1,231 @@
+/*
+ * Copyright (c) 2010-2015, NVIDIA CORPORATION.  All rights reserved.
+ * Copyright (C) 2014 Google Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __SOC_NVIDIA_TEGRA210_MC_H__
+#define __SOC_NVIDIA_TEGRA210_MC_H__
+
+#include <stddef.h>
+#include <stdint.h>
+
+// Memory Controller registers we need/care about
+
+struct tegra_mc_regs {
+	uint32_t rsvd_0x0[4];			/* 0x00 */
+	uint32_t smmu_config;			/* 0x10 */
+	uint32_t smmu_tlb_config;		/* 0x14 */
+	uint32_t smmu_ptc_config;		/* 0x18 */
+	uint32_t smmu_ptb_asid;			/* 0x1c */
+	uint32_t smmu_ptb_data;			/* 0x20 */
+	uint32_t rsvd_0x24[3];			/* 0x24 */
+	uint32_t smmu_tlb_flush;		/* 0x30 */
+	uint32_t smmu_ptc_flush;		/* 0x34 */
+	uint32_t rsvd_0x38[6];			/* 0x38 */
+	uint32_t emem_cfg;			/* 0x50 */
+	uint32_t emem_adr_cfg;			/* 0x54 */
+	uint32_t emem_adr_cfg_dev0;		/* 0x58 */
+	uint32_t emem_adr_cfg_dev1;		/* 0x5c */
+	uint32_t emem_adr_cfg_channel_mask;	/* 0x60 */
+	uint32_t emem_adr_cfg_bank_mask_0;	/* 0x64 */
+	uint32_t emem_adr_cfg_bank_mask_1;	/* 0x68 */
+	uint32_t emem_adr_cfg_bank_mask_2;	/* 0x6c */
+	uint32_t security_cfg0;			/* 0x70 */
+	uint32_t security_cfg1;			/* 0x74 */
+	uint32_t rsvd_0x78[6];			/* 0x78 */
+	uint32_t emem_arb_cfg;			/* 0x90 */
+	uint32_t emem_arb_outstanding_req;	/* 0x94 */
+	uint32_t emem_arb_timing_rcd;		/* 0x98 */
+	uint32_t emem_arb_timing_rp;		/* 0x9c */
+	uint32_t emem_arb_timing_rc;		/* 0xa0 */
+	uint32_t emem_arb_timing_ras;		/* 0xa4 */
+	uint32_t emem_arb_timing_faw;		/* 0xa8 */
+	uint32_t emem_arb_timing_rrd;		/* 0xac */
+	uint32_t emem_arb_timing_rap2pre;	/* 0xb0 */
+	uint32_t emem_arb_timing_wap2pre;	/* 0xb4 */
+	uint32_t emem_arb_timing_r2r;		/* 0xb8 */
+	uint32_t emem_arb_timing_w2w;		/* 0xbc */
+	uint32_t emem_arb_timing_r2w;		/* 0xc0 */
+	uint32_t emem_arb_timing_w2r;		/* 0xc4 */
+	uint32_t emem_arb_misc2;		/* 0xC8 */
+	uint32_t rsvd_0xcc[1];			/* 0xCC */
+	uint32_t emem_arb_da_turns;		/* 0xd0 */
+	uint32_t emem_arb_da_covers;		/* 0xd4 */
+	uint32_t emem_arb_misc0;		/* 0xd8 */
+	uint32_t emem_arb_misc1;		/* 0xdc */
+	uint32_t emem_arb_ring1_throttle;	/* 0xe0 */
+	uint32_t emem_arb_ring3_throttle;	/* 0xe4 */
+	uint32_t emem_arb_override;		/* 0xe8 */
+	uint32_t emem_arb_rsv;			/* 0xec */
+	uint32_t rsvd_0xf0[1];			/* 0xf0 */
+	uint32_t clken_override;		/* 0xf4 */
+	uint32_t timing_control_dbg;		/* 0xf8 */
+	uint32_t timing_control;		/* 0xfc */
+	uint32_t stat_control;			/* 0x100 */
+	uint32_t rsvd_0x104[65];		/* 0x104 */
+	uint32_t emem_arb_isochronous_0;	/* 0x208 */
+	uint32_t emem_arb_isochronous_1;	/* 0x20c */
+	uint32_t emem_arb_isochronous_2;	/* 0x210 */
+	uint32_t rsvd_0x214[38];		/* 0x214 */
+	uint32_t dis_extra_snap_levels;		/* 0x2ac */
+	uint32_t rsvd_0x2b0[90];		/* 0x2b0 */
+	uint32_t video_protect_vpr_override;	/* 0x418 */
+	uint32_t rsvd_0x41c[93];		/* 0x41c */
+	uint32_t video_protect_vpr_override1;	/* 0x590 */
+	uint32_t rsvd_0x594[29];		/* 0x594 */
+	uint32_t display_snap_ring;		/* 0x608 */
+	uint32_t rsvd_0x60c[15];		/* 0x60c */
+	uint32_t video_protect_bom;		/* 0x648 */
+	uint32_t video_protect_size_mb;		/* 0x64c */
+	uint32_t video_protect_reg_ctrl;	/* 0x650 */
+	uint32_t rsvd_0x654[4];			/* 0x654 */
+	uint32_t emem_cfg_access_ctrl;		/* 0x664 */
+	uint32_t rsvd_0x668[2];			/* 0x668 */
+	uint32_t sec_carveout_bom;		/* 0x670 */
+	uint32_t sec_carveout_size_mb;		/* 0x674 */
+	uint32_t sec_carveout_reg_ctrl;		/* 0x678 */
+	uint32_t rsvd_0x67c[17];		/* 0x67C-0x6BC */
+
+	uint32_t emem_arb_timing_rfcpb;		/* 0x6C0 */
+	uint32_t emem_arb_timing_ccdmw;		/* 0x6C4 */
+	uint32_t rsvd_0x6c8[10];		/* 0x6C8-0x6EC */
+
+	uint32_t emem_arb_refpb_hp_ctrl;	/* 0x6F0 */
+	uint32_t emem_arb_refpb_bank_ctrl;	/* 0x6F4 */
+	uint32_t rsvd_0x6f8[156];		/* 0x6F8-0x964 */
+
+	uint32_t emem_arb_override_1;		/* 0x968 */
+	uint32_t rsvd_0x96c[3];			/* 0x96c */
+	uint32_t video_protect_bom_adr_hi;	/* 0x978 */
+	uint32_t rsvd_0x97c[2];			/* 0x97c */
+	uint32_t video_protect_gpu_override_0;	/* 0x984 */
+	uint32_t video_protect_gpu_override_1;	/* 0x988 */
+	uint32_t rsvd_0x98c[5];			/* 0x98c */
+	uint32_t mts_carveout_bom;		/* 0x9a0 */
+	uint32_t mts_carveout_size_mb;		/* 0x9a4 */
+	uint32_t mts_carveout_adr_hi;		/* 0x9a8 */
+	uint32_t mts_carveout_reg_ctrl;		/* 0x9ac */
+	uint32_t rsvd_0x9b0[4];			/* 0x9b0 */
+	uint32_t emem_bank_swizzle_cfg0;	/* 0x9c0 */
+	uint32_t emem_bank_swizzle_cfg1;	/* 0x9c4 */
+	uint32_t emem_bank_swizzle_cfg2;	/* 0x9c8 */
+	uint32_t emem_bank_swizzle_cfg3;	/* 0x9cc */
+	uint32_t rsvd_0x9d0[1];			/* 0x9d0 */
+	uint32_t sec_carveout_adr_hi;		/* 0x9d4 */
+	uint32_t rsvd_0x9d8;			/* 0x9D8 */
+	uint32_t da_config0;			/* 0x9DC */
+	uint32_t rsvd_0x9c0[138];		/* 0x9E0-0xc04 */
+
+	uint32_t security_carveout1_cfg0;	/* 0xc08 */
+	uint32_t security_carveout1_bom;	/* 0xc0c */
+	uint32_t security_carveout1_bom_hi;	/* 0xc10 */
+	uint32_t security_carveout1_size_128kb;	/* 0xc14 */
+	uint32_t security_carveout1_ca0;	/* 0xc18 */
+	uint32_t security_carveout1_ca1;	/* 0xc1c */
+	uint32_t security_carveout1_ca2;	/* 0xc20 */
+	uint32_t security_carveout1_ca3;	/* 0xc24 */
+	uint32_t security_carveout1_ca4;	/* 0xc28 */
+	uint32_t security_carveout1_cfia0;	/* 0xc2c */
+	uint32_t security_carveout1_cfia1;	/* 0xc30 */
+	uint32_t security_carveout1_cfia2;	/* 0xc34 */
+	uint32_t security_carveout1_cfia3;	/* 0xc38 */
+	uint32_t security_carveout1_cfia4;	/* 0xc3c */
+	uint32_t rsvd_0xc40[6];			/* 0xc40-0xc54 */
+
+	uint32_t security_carveout2_cfg0;	/* 0xc58 */
+	uint32_t security_carveout2_bom;	/* 0xc5c */
+	uint32_t security_carveout2_bom_hi;	/* 0xc60 */
+	uint32_t security_carveout2_size_128kb;	/* 0xc64 */
+	uint32_t security_carveout2_ca0;	/* 0xc68 */
+	uint32_t security_carveout2_ca1;	/* 0xc6c */
+	uint32_t security_carveout2_ca2;	/* 0xc70 */
+	uint32_t security_carveout2_ca3;	/* 0xc74 */
+	uint32_t security_carveout2_ca4;	/* 0xc78 */
+	uint32_t security_carveout2_cfia0;	/* 0xc7c */
+	uint32_t security_carveout2_cfia1;	/* 0xc80 */
+	uint32_t security_carveout2_cfia2;	/* 0xc84 */
+	uint32_t security_carveout2_cfia3;	/* 0xc88 */
+	uint32_t security_carveout2_cfia4;	/* 0xc8c */
+	uint32_t rsvd_0xc90[6];			/* 0xc90-0xca4 */
+
+	uint32_t security_carveout3_cfg0;	/* 0xca8 */
+	uint32_t security_carveout3_bom;	/* 0xcac */
+	uint32_t security_carveout3_bom_hi;	/* 0xcb0 */
+	uint32_t security_carveout3_size_128kb;	/* 0xcb4 */
+	uint32_t security_carveout3_ca0;	/* 0xcb8 */
+	uint32_t security_carveout3_ca1;	/* 0xcbc */
+	uint32_t security_carveout3_ca2;	/* 0xcc0 */
+	uint32_t security_carveout3_ca3;	/* 0xcc4 */
+	uint32_t security_carveout3_ca4;	/* 0xcc8 */
+	uint32_t security_carveout3_cfia0;	/* 0xccc */
+	uint32_t security_carveout3_cfia1;	/* 0xcd0 */
+	uint32_t security_carveout3_cfia2;	/* 0xcd4 */
+	uint32_t security_carveout3_cfia3;	/* 0xcd8 */
+	uint32_t security_carveout3_cfia4;	/* 0xcdc */
+	uint32_t rsvd_0xce0[6];			/* 0xce0-0xcf4 */
+
+	uint32_t security_carveout4_cfg0;	/* 0xcf8 */
+	uint32_t security_carveout4_bom;	/* 0xcfc */
+	uint32_t security_carveout4_bom_hi;	/* 0xd00 */
+	uint32_t security_carveout4_size_128kb;	/* 0xd04 */
+	uint32_t security_carveout4_ca0;	/* 0xd08 */
+	uint32_t security_carveout4_ca1;	/* 0xd0c */
+	uint32_t security_carveout4_ca2;	/* 0xd10 */
+	uint32_t security_carveout4_ca3;	/* 0xd14 */
+	uint32_t security_carveout4_ca4;	/* 0xd18 */
+	uint32_t security_carveout4_cfia0;	/* 0xd1c */
+	uint32_t security_carveout4_cfia1;	/* 0xd20 */
+	uint32_t security_carveout4_cfia2;	/* 0xd24 */
+	uint32_t security_carveout4_cfia3;	/* 0xd28 */
+	uint32_t security_carveout4_cfia4;	/* 0xd2c */
+	uint32_t rsvd_0xd30[6];			/* 0xd30-0xd44 */
+
+	uint32_t security_carveout5_cfg0;	/* 0xd48 */
+	uint32_t security_carveout5_bom;	/* 0xd4c */
+	uint32_t security_carveout5_bom_hi;	/* 0xd50 */
+	uint32_t security_carveout5_size_128kb;	/* 0xd54 */
+	uint32_t security_carveout5_ca0;	/* 0xd58 */
+	uint32_t security_carveout5_ca1;	/* 0xd5c */
+	uint32_t security_carveout5_ca2;	/* 0xd60 */
+	uint32_t security_carveout5_ca3;	/* 0xd64 */
+	uint32_t security_carveout5_ca4;	/* 0xd68 */
+	uint32_t security_carveout5_cfia0;	/* 0xd6c */
+	uint32_t security_carveout5_cfia1;	/* 0xd70 */
+	uint32_t security_carveout5_cfia2;	/* 0xd74 */
+	uint32_t security_carveout5_cfia3;	/* 0xd78 */
+	uint32_t security_carveout5_cfia4;	/* 0xd7c */
+};
+
+enum {
+	MC_SMMU_CONFIG_ENABLE = 1,
+
+	MC_EMEM_CFG_SIZE_MB_SHIFT = 0,
+	MC_EMEM_CFG_SIZE_MB_MASK = 0x3fff,
+
+	MC_EMEM_ARB_MISC0_MC_EMC_SAME_FREQ_SHIFT = 27,
+	MC_EMEM_ARB_MISC0_MC_EMC_SAME_FREQ_MASK = 1 << 27,
+
+	MC_EMEM_CFG_ACCESS_CTRL_WRITE_ACCESS_DISABLED = 1,
+
+	MC_TIMING_CONTROL_TIMING_UPDATE = 1,
+};
+
+#define MC_SECURITY_CARVEOUT_LOCKED		(1 << 1)
+#define MC_VPR_WR_ACCESS_DISABLE		(1 << 0)
+#define MC_VPR_ALLOW_TZ_WR_ACCESS_ENABLE	(1 << 1)
+
+check_member(tegra_mc_regs, security_carveout5_cfia4, 0xd7c);
+
+#endif	/* __SOC_NVIDIA_TEGRA210_MC_H__ */
diff --git a/src/soc/nvidia/tegra210/include/soc/memlayout.ld b/src/soc/nvidia/tegra210/include/soc/memlayout.ld
new file mode 100644
index 0000000..df9eed5
--- /dev/null
+++ b/src/soc/nvidia/tegra210/include/soc/memlayout.ld
@@ -0,0 +1,44 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright 2014 Google Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc.
+ */
+
+#include <memlayout.h>
+
+#include <arch/header.ld>
+
+/*
+ * Note: The BootROM uses the address range [0x4000_0000:0x4000_E000) itself,
+ * so the bootblock loading address must be placed after that. After the
+ * handoff that area may be reclaimed for other uses, e.g. CBFS cache.
+ * TODO: Did this change on Tegra210? What's the new valid range?
+ */
+
+SECTIONS
+{
+	SRAM_START(0x40000000)
+	PRERAM_CBMEM_CONSOLE(0x40000000, 8K)
+	PRERAM_CBFS_CACHE(0x40002000, 84K)
+	STACK(0x40017000, 16K)
+	BOOTBLOCK(0x4001B000, 26K)
+	ROMSTAGE(0x40022000, 120K)
+	SRAM_END(0x40040000)
+
+	DRAM_START(0x80000000)
+	POSTRAM_CBFS_CACHE(0x80100000, 1M)
+	RAMSTAGE(0x80200000, 256K)
+}
diff --git a/src/soc/nvidia/tegra210/include/soc/memlayout_vboot2.ld b/src/soc/nvidia/tegra210/include/soc/memlayout_vboot2.ld
new file mode 100644
index 0000000..7aa98e0
--- /dev/null
+++ b/src/soc/nvidia/tegra210/include/soc/memlayout_vboot2.ld
@@ -0,0 +1,47 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright 2014 Google Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc.
+ */
+
+#include <memlayout.h>
+#include <vendorcode/google/chromeos/memlayout.h>
+
+#include <arch/header.ld>
+
+/*
+ * Note: The BootROM uses the address range [0x4000_0000:0x4000_E000) itself,
+ * so the bootblock loading address must be placed after that. After the
+ * handoff that area may be reclaimed for other uses, e.g. CBFS cache.
+ * TODO: Did this change on Tegra210? What's the new valid range?
+ */
+
+SECTIONS
+{
+	SRAM_START(0x40000000)
+	PRERAM_CBMEM_CONSOLE(0x40000000, 8K)
+	PRERAM_CBFS_CACHE(0x40002000, 72K)
+	VBOOT2_WORK(0x40014000, 16K)
+	STACK(0x40018000, 2K)
+	BOOTBLOCK(0x40019000, 24K)
+	VERSTAGE(0x4001F000, 56K)
+	ROMSTAGE(0x4002D000, 76K)
+	SRAM_END(0x40040000)
+
+	DRAM_START(0x80000000)
+	POSTRAM_CBFS_CACHE(0x80100000, 1M)
+	RAMSTAGE(0x80200000, 256K)
+}
diff --git a/src/soc/nvidia/tegra210/include/soc/mipi-phy.h b/src/soc/nvidia/tegra210/include/soc/mipi-phy.h
new file mode 100644
index 0000000..eb81719
--- /dev/null
+++ b/src/soc/nvidia/tegra210/include/soc/mipi-phy.h
@@ -0,0 +1,46 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright 2014 Google Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc.
+ */
+#ifndef _TEGRA_MIPI_PHY_H
+#define _TEGRA_MIPI_PHY_H
+
+#include <stdlib.h>
+
+/*
+ * Macros for calculating the phy timings
+ */
+/* Period of one bit time in nano seconds */
+#define DSI_TBIT_Factorized(Freq)    (((1000) * (1000))/(Freq))
+#define DSI_TBIT(Freq)       (DSI_TBIT_Factorized(Freq)/(1000))
+
+//#define NV_MAX(a,b) (((a) > (b)) ? (a) : (b))
+
+/* Period of one byte time in nano seconds */
+#define DSI_TBYTE(Freq)    ((DSI_TBIT_Factorized(Freq)) * (8))
+#define DSI_PHY_TIMING_DIV(X, Freq) ((X*1000) / (DSI_TBYTE(Freq)))
+
+/*
+ * As per Mipi spec (minimum):
+ * (3 + MAX(8 * DSI_TBIT, 60 + 4 * DSI_TBIT) / DSI_TBYTE)
+ */
+#define DSI_THSTRAIL_VAL(Freq) \
+     (MAX(((8) * (DSI_TBIT(Freq))), ((60) + ((4) * (DSI_TBIT(Freq))))))
+
+int mipi_dphy_set_timing(struct tegra_dsi *dsi);
+
+#endif
diff --git a/src/soc/nvidia/tegra210/include/soc/mipi_display.h b/src/soc/nvidia/tegra210/include/soc/mipi_display.h
new file mode 100644
index 0000000..2e2e453
--- /dev/null
+++ b/src/soc/nvidia/tegra210/include/soc/mipi_display.h
@@ -0,0 +1,148 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright 2014 Google Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc.
+ */
+/*
+ * Defines for Mobile Industry Processor Interface (MIPI(R))
+ * Display Working Group standards: DSI, DCS, DBI, DPI
+ *
+ * Copyright (C) 2010 Guennadi Liakhovetski <g.liakhovetski at gmx.de>
+ * Copyright (C) 2006 Nokia Corporation
+ * Author: Imre Deak <imre.deak at nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#ifndef MIPI_DISPLAY_H
+#define MIPI_DISPLAY_H
+
+/* MIPI DSI Processor-to-Peripheral transaction types */
+enum {
+	MIPI_DSI_V_SYNC_START				= 0x01,
+	MIPI_DSI_V_SYNC_END				= 0x11,
+	MIPI_DSI_H_SYNC_START				= 0x21,
+	MIPI_DSI_H_SYNC_END				= 0x31,
+
+	MIPI_DSI_COLOR_MODE_OFF				= 0x02,
+	MIPI_DSI_COLOR_MODE_ON				= 0x12,
+	MIPI_DSI_SHUTDOWN_PERIPHERAL			= 0x22,
+	MIPI_DSI_TURN_ON_PERIPHERAL			= 0x32,
+
+	MIPI_DSI_GENERIC_SHORT_WRITE_0_PARAM		= 0x03,
+	MIPI_DSI_GENERIC_SHORT_WRITE_1_PARAM		= 0x13,
+	MIPI_DSI_GENERIC_SHORT_WRITE_2_PARAM		= 0x23,
+
+	MIPI_DSI_GENERIC_READ_REQUEST_0_PARAM		= 0x04,
+	MIPI_DSI_GENERIC_READ_REQUEST_1_PARAM		= 0x14,
+	MIPI_DSI_GENERIC_READ_REQUEST_2_PARAM		= 0x24,
+
+	MIPI_DSI_DCS_SHORT_WRITE			= 0x05,
+	MIPI_DSI_DCS_SHORT_WRITE_PARAM			= 0x15,
+
+	MIPI_DSI_DCS_READ				= 0x06,
+
+	MIPI_DSI_SET_MAXIMUM_RETURN_PACKET_SIZE		= 0x37,
+
+	MIPI_DSI_END_OF_TRANSMISSION			= 0x08,
+
+	MIPI_DSI_NULL_PACKET				= 0x09,
+	MIPI_DSI_BLANKING_PACKET			= 0x19,
+	MIPI_DSI_GENERIC_LONG_WRITE			= 0x29,
+	MIPI_DSI_DCS_LONG_WRITE				= 0x39,
+
+	MIPI_DSI_LOOSELY_PACKED_PIXEL_STREAM_YCBCR20	= 0x0c,
+	MIPI_DSI_PACKED_PIXEL_STREAM_YCBCR24		= 0x1c,
+	MIPI_DSI_PACKED_PIXEL_STREAM_YCBCR16		= 0x2c,
+
+	MIPI_DSI_PACKED_PIXEL_STREAM_30			= 0x0d,
+	MIPI_DSI_PACKED_PIXEL_STREAM_36			= 0x1d,
+	MIPI_DSI_PACKED_PIXEL_STREAM_YCBCR12		= 0x3d,
+
+	MIPI_DSI_PACKED_PIXEL_STREAM_16			= 0x0e,
+	MIPI_DSI_PACKED_PIXEL_STREAM_18			= 0x1e,
+	MIPI_DSI_PIXEL_STREAM_3BYTE_18			= 0x2e,
+	MIPI_DSI_PACKED_PIXEL_STREAM_24			= 0x3e,
+};
+
+/* MIPI DSI Peripheral-to-Processor transaction types */
+enum {
+	MIPI_DSI_RX_ACKNOWLEDGE_AND_ERROR_REPORT	= 0x02,
+	MIPI_DSI_RX_END_OF_TRANSMISSION			= 0x08,
+	MIPI_DSI_RX_GENERIC_SHORT_READ_RESPONSE_1BYTE	= 0x11,
+	MIPI_DSI_RX_GENERIC_SHORT_READ_RESPONSE_2BYTE	= 0x12,
+	MIPI_DSI_RX_GENERIC_LONG_READ_RESPONSE		= 0x1a,
+	MIPI_DSI_RX_DCS_LONG_READ_RESPONSE		= 0x1c,
+	MIPI_DSI_RX_DCS_SHORT_READ_RESPONSE_1BYTE	= 0x21,
+	MIPI_DSI_RX_DCS_SHORT_READ_RESPONSE_2BYTE	= 0x22,
+};
+
+/* MIPI DCS commands */
+enum {
+	MIPI_DCS_NOP			= 0x00,
+	MIPI_DCS_SOFT_RESET		= 0x01,
+	MIPI_DCS_GET_DISPLAY_ID		= 0x04,
+	MIPI_DCS_GET_RED_CHANNEL	= 0x06,
+	MIPI_DCS_GET_GREEN_CHANNEL	= 0x07,
+	MIPI_DCS_GET_BLUE_CHANNEL	= 0x08,
+	MIPI_DCS_GET_DISPLAY_STATUS	= 0x09,
+	MIPI_DCS_GET_POWER_MODE		= 0x0A,
+	MIPI_DCS_GET_ADDRESS_MODE	= 0x0B,
+	MIPI_DCS_GET_PIXEL_FORMAT	= 0x0C,
+	MIPI_DCS_GET_DISPLAY_MODE	= 0x0D,
+	MIPI_DCS_GET_SIGNAL_MODE	= 0x0E,
+	MIPI_DCS_GET_DIAGNOSTIC_RESULT	= 0x0F,
+	MIPI_DCS_ENTER_SLEEP_MODE	= 0x10,
+	MIPI_DCS_EXIT_SLEEP_MODE	= 0x11,
+	MIPI_DCS_ENTER_PARTIAL_MODE	= 0x12,
+	MIPI_DCS_ENTER_NORMAL_MODE	= 0x13,
+	MIPI_DCS_EXIT_INVERT_MODE	= 0x20,
+	MIPI_DCS_ENTER_INVERT_MODE	= 0x21,
+	MIPI_DCS_SET_GAMMA_CURVE	= 0x26,
+	MIPI_DCS_SET_DISPLAY_OFF	= 0x28,
+	MIPI_DCS_SET_DISPLAY_ON		= 0x29,
+	MIPI_DCS_SET_COLUMN_ADDRESS	= 0x2A,
+	MIPI_DCS_SET_PAGE_ADDRESS	= 0x2B,
+	MIPI_DCS_WRITE_MEMORY_START	= 0x2C,
+	MIPI_DCS_WRITE_LUT		= 0x2D,
+	MIPI_DCS_READ_MEMORY_START	= 0x2E,
+	MIPI_DCS_SET_PARTIAL_AREA	= 0x30,
+	MIPI_DCS_SET_SCROLL_AREA	= 0x33,
+	MIPI_DCS_SET_TEAR_OFF		= 0x34,
+	MIPI_DCS_SET_TEAR_ON		= 0x35,
+	MIPI_DCS_SET_ADDRESS_MODE	= 0x36,
+	MIPI_DCS_SET_SCROLL_START	= 0x37,
+	MIPI_DCS_EXIT_IDLE_MODE		= 0x38,
+	MIPI_DCS_ENTER_IDLE_MODE	= 0x39,
+	MIPI_DCS_SET_PIXEL_FORMAT	= 0x3A,
+	MIPI_DCS_WRITE_MEMORY_CONTINUE	= 0x3C,
+	MIPI_DCS_READ_MEMORY_CONTINUE	= 0x3E,
+	MIPI_DCS_SET_TEAR_SCANLINE	= 0x44,
+	MIPI_DCS_GET_SCANLINE		= 0x45,
+	MIPI_DCS_READ_DDB_START		= 0xA1,
+	MIPI_DCS_READ_DDB_CONTINUE	= 0xA8,
+};
+
+/* MIPI DCS pixel formats */
+#define MIPI_DCS_PIXEL_FMT_24BIT	7
+#define MIPI_DCS_PIXEL_FMT_18BIT	6
+#define MIPI_DCS_PIXEL_FMT_16BIT	5
+#define MIPI_DCS_PIXEL_FMT_12BIT	3
+#define MIPI_DCS_PIXEL_FMT_8BIT		2
+#define MIPI_DCS_PIXEL_FMT_3BIT		1
+
+#endif
diff --git a/src/soc/nvidia/tegra210/include/soc/mipi_dsi.h b/src/soc/nvidia/tegra210/include/soc/mipi_dsi.h
new file mode 100644
index 0000000..2d1e8b1
--- /dev/null
+++ b/src/soc/nvidia/tegra210/include/soc/mipi_dsi.h
@@ -0,0 +1,316 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright 2014 Google Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc.
+ */
+/*
+ * MIPI DSI Bus
+ *
+ * Copyright (C) 2012-2013, Samsung Electronics, Co., Ltd.
+ * Andrzej Hajda <a.hajda at samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __MIPI_DSI_H__
+#define __MIPI_DSI_H__
+
+struct mipi_dsi_host;
+struct mipi_dsi_device;
+
+/* request ACK from peripheral */
+#define MIPI_DSI_MSG_REQ_ACK	BIT(0)
+/* use Low Power Mode to transmit message */
+#define MIPI_DSI_MSG_USE_LPM	BIT(1)
+
+/**
+ * struct mipi_dsi_msg - read/write DSI buffer
+ * @channel: virtual channel id
+ * @type: payload data type
+ * @flags: flags controlling this message transmission
+ * @tx_len: length of @tx_buf
+ * @tx_buf: data to be written
+ * @rx_len: length of @rx_buf
+ * @rx_buf: data to be read, or NULL
+ */
+struct mipi_dsi_msg {
+	u8 channel;
+	u8 type;
+	u16 flags;
+
+	size_t tx_len;
+	const void *tx_buf;
+
+	size_t rx_len;
+	void *rx_buf;
+};
+
+/**
+ * struct mipi_dsi_host_ops - DSI bus operations
+ * @attach: attach DSI device to DSI host
+ * @detach: detach DSI device from DSI host
+ * @transfer: transmit a DSI packet
+ *
+ * DSI packets transmitted by .transfer() are passed in as mipi_dsi_msg
+ * structures. This structure contains information about the type of packet
+ * being transmitted as well as the transmit and receive buffers. When an
+ * error is encountered during transmission, this function will return a
+ * negative error code. On success it shall return the number of bytes
+ * transmitted for write packets or the number of bytes received for read
+ * packets.
+ *
+ * Note that typically DSI packet transmission is atomic, so the .transfer()
+ * function will seldomly return anything other than the number of bytes
+ * contained in the transmit buffer on success.
+ */
+struct mipi_dsi_host_ops {
+	int (*attach)(struct mipi_dsi_host *host,
+		      struct mipi_dsi_device *dsi);
+	int (*detach)(struct mipi_dsi_host *host,
+		      struct mipi_dsi_device *dsi);
+	ssize_t (*transfer)(struct mipi_dsi_host *host,
+			    const struct mipi_dsi_msg *msg);
+};
+
+/**
+ * struct mipi_dsi_host - DSI host device
+ * @dev: driver model device node for this DSI host
+ * @ops: DSI host operations
+ */
+struct mipi_dsi_host {
+	//struct device *dev;
+	void *dev;
+	const struct mipi_dsi_host_ops *ops;
+};
+
+int mipi_dsi_host_register(struct mipi_dsi_host *host);
+
+/* DSI mode flags */
+
+/* video mode */
+#define MIPI_DSI_MODE_VIDEO		BIT(0)
+/* video burst mode */
+#define MIPI_DSI_MODE_VIDEO_BURST	BIT(1)
+/* video pulse mode */
+#define MIPI_DSI_MODE_VIDEO_SYNC_PULSE	BIT(2)
+/* enable auto vertical count mode */
+#define MIPI_DSI_MODE_VIDEO_AUTO_VERT	BIT(3)
+/* enable hsync-end packets in vsync-pulse and v-porch area */
+#define MIPI_DSI_MODE_VIDEO_HSE		BIT(4)
+/* disable hfront-porch area */
+#define MIPI_DSI_MODE_VIDEO_HFP		BIT(5)
+/* disable hback-porch area */
+#define MIPI_DSI_MODE_VIDEO_HBP		BIT(6)
+/* disable hsync-active area */
+#define MIPI_DSI_MODE_VIDEO_HSA		BIT(7)
+/* flush display FIFO on vsync pulse */
+#define MIPI_DSI_MODE_VSYNC_FLUSH	BIT(8)
+/* disable EoT packets in HS mode */
+#define MIPI_DSI_MODE_EOT_PACKET	BIT(9)
+/* device supports non-continuous clock behavior (DSI spec 5.6.1) */
+#define MIPI_DSI_CLOCK_NON_CONTINUOUS	BIT(10)
+
+enum mipi_dsi_pixel_format {
+	MIPI_DSI_FMT_RGB888,
+	MIPI_DSI_FMT_RGB666,
+	MIPI_DSI_FMT_RGB666_PACKED,
+	MIPI_DSI_FMT_RGB565,
+};
+
+struct mipi_dsi_master_ops {
+	int (*enslave)(struct mipi_dsi_device *master,
+		       struct mipi_dsi_device *slave);
+	int (*liberate)(struct mipi_dsi_device *master,
+			struct mipi_dsi_device *slave);
+};
+
+/**
+ * struct mipi_dsi_device - DSI peripheral device
+ * @host: DSI host for this peripheral
+ * @dev: driver model device node for this peripheral
+ * @channel: virtual channel assigned to the peripheral
+ * @format: pixel format for video mode
+ * @lanes: number of active data lanes
+ * @mode_flags: DSI operation mode related flags
+ * @ops: callbacks for master/slave setup
+ * @master: master interface for dual-channel peripherals
+ * @slave: slave interface for dual-channel peripherals
+ *
+ * For dual-channel interfaces, the master interface can be identified by the
+ * fact that it's .slave field is set to non-NULL. The slave interface will
+ * have the .master field set to non-NULL.
+ */
+struct mipi_dsi_device {
+	struct mipi_dsi_host *host;
+
+	unsigned int channel;
+	unsigned int lanes;
+	enum mipi_dsi_pixel_format format;
+	unsigned long mode_flags;
+
+	const struct mipi_dsi_master_ops *ops;
+	struct mipi_dsi_device *master;
+	struct mipi_dsi_device *slave;
+};
+
+int mipi_dsi_attach(struct mipi_dsi_device *dsi);
+int mipi_dsi_detach(struct mipi_dsi_device *dsi);
+int mipi_dsi_enslave(struct mipi_dsi_device *master,
+		     struct mipi_dsi_device *slave);
+int mipi_dsi_liberate(struct mipi_dsi_device *master,
+		      struct mipi_dsi_device *slave);
+
+/**
+ * enum mipi_dsi_dcs_tear_mode - Tearing Effect Output Line mode
+ * @MIPI_DSI_DCS_TEAR_MODE_VBLANK: the TE output line consists of V-Blanking
+ *    information only
+ * @MIPI_DSI_DCS_TEAR_MODE_VHBLANK : the TE output line consists of both
+ *    V-Blanking and H-Blanking information
+ */
+enum mipi_dsi_dcs_tear_mode {
+	MIPI_DSI_DCS_TEAR_MODE_VBLANK,
+	MIPI_DSI_DCS_TEAR_MODE_VHBLANK,
+};
+
+#define MIPI_DSI_DCS_POWER_MODE_DISPLAY (1 << 2)
+#define MIPI_DSI_DCS_POWER_MODE_NORMAL  (1 << 3)
+#define MIPI_DSI_DCS_POWER_MODE_SLEEP   (1 << 4)
+#define MIPI_DSI_DCS_POWER_MODE_PARTIAL (1 << 5)
+#define MIPI_DSI_DCS_POWER_MODE_IDLE    (1 << 6)
+
+ssize_t mipi_dsi_dcs_write(struct mipi_dsi_device *dsi, u8 cmd,
+			   const void *data, size_t len);
+int mipi_dsi_dcs_exit_sleep_mode(struct mipi_dsi_device *dsi);
+int mipi_dsi_dcs_set_display_on(struct mipi_dsi_device *dsi);
+int mipi_dsi_dcs_set_column_address(struct mipi_dsi_device *dsi, u16 start,
+				    u16 end);
+int mipi_dsi_dcs_set_page_address(struct mipi_dsi_device *dsi, u16 start,
+				  u16 end);
+int mipi_dsi_dcs_set_address_mode(struct mipi_dsi_device *dsi,
+				  bool reverse_page_address,
+				  bool reverse_col_address,
+				  bool reverse_page_col_address,
+				  bool refresh_from_bottom,
+				  bool reverse_rgb,
+				  bool latch_right_to_left,
+				  bool flip_horizontal,
+				  bool flip_vertical);
+int mipi_dsi_dcs_set_tear_on(struct mipi_dsi_device *dsi,
+			     enum mipi_dsi_dcs_tear_mode mode);
+int mipi_dsi_dcs_set_pixel_format(struct mipi_dsi_device *dsi, u8 format);
+
+#define MIPI_CAL_CTRL			0x00
+#define MIPI_CAL_CTRL_NOISE_FILTER(x)	(((x) & 0xf) << 26)
+#define MIPI_CAL_CTRL_PRESCALE(x)	(((x) & 0x3) << 24)
+#define MIPI_CAL_CTRL_CLKEN_OVR		(1 << 4)
+#define MIPI_CAL_CTRL_START		(1 << 0)
+
+#define MIPI_CAL_AUTOCAL_CTRL		0x01
+
+#define MIPI_CAL_STATUS			0x02
+#define MIPI_CAL_STATUS_DONE		(1 << 16)
+#define MIPI_CAL_STATUS_ACTIVE		(1 <<  0)
+
+#define MIPI_CAL_CONFIG_CSIA		0x05
+#define MIPI_CAL_CONFIG_CSIB		0x06
+#define MIPI_CAL_CONFIG_CSIC		0x07
+#define MIPI_CAL_CONFIG_CSID		0x08
+#define MIPI_CAL_CONFIG_CSIE		0x09
+#define MIPI_CAL_CONFIG_CSIF		0x0a
+#define MIPI_CAL_CONFIG_DSIA		0x0e
+#define MIPI_CAL_CONFIG_DSIB		0x0f
+#define MIPI_CAL_CONFIG_DSIC		0x10
+#define MIPI_CAL_CONFIG_DSID		0x11
+
+#define MIPI_CAL_CONFIG_DSIA_CLK	0x19
+#define MIPI_CAL_CONFIG_DSIB_CLK	0x1a
+#define MIPI_CAL_CONFIG_CSIAB_CLK	0x1b
+#define MIPI_CAL_CONFIG_DSIC_CLK	0x1c
+#define MIPI_CAL_CONFIG_CSICD_CLK	0x1c
+#define MIPI_CAL_CONFIG_DSID_CLK	0x1d
+#define MIPI_CAL_CONFIG_CSIE_CLK	0x1d
+
+/* for data and clock lanes */
+#define MIPI_CAL_CONFIG_SELECT		(1 << 21)
+
+/* for data lanes */
+#define MIPI_CAL_CONFIG_HSPDOS(x)	(((x) & 0x1f) << 16)
+#define MIPI_CAL_CONFIG_HSPUOS(x)	(((x) & 0x1f) <<  8)
+#define MIPI_CAL_CONFIG_TERMOS(x)	(((x) & 0x1f) <<  0)
+
+/* for clock lanes */
+#define MIPI_CAL_CONFIG_HSCLKPDOSD(x)	(((x) & 0x1f) <<  8)
+#define MIPI_CAL_CONFIG_HSCLKPUOSD(x)	(((x) & 0x1f) <<  0)
+
+#define MIPI_CAL_BIAS_PAD_CFG0		0x16
+#define MIPI_CAL_BIAS_PAD_PDVCLAMP	(1 << 1)
+#define MIPI_CAL_BIAS_PAD_E_VCLAMP_REF	(1 << 0)
+
+#define MIPI_CAL_BIAS_PAD_CFG1		0x17
+#define MIPI_CAL_BIAS_PAD_DRV_DN_REF(x) (((x) & 0x7) << 16)
+#define MIPI_CAL_BIAS_PAD_DRV_UP_REF(x) (((x) & 0x7) << 8)
+
+#define MIPI_CAL_BIAS_PAD_CFG2		0x18
+#define MIPI_CAL_BIAS_PAD_VCLAMP(x)	(((x) & 0x7) << 16)
+#define MIPI_CAL_BIAS_PAD_VAUXP(x)	(((x) & 0x7) << 4)
+#define MIPI_CAL_BIAS_PAD_PDVREG	(1 << 1)
+
+struct tegra_mipi_pad {
+	unsigned long data;
+	unsigned long clk;
+};
+
+struct tegra_mipi_soc {
+	int has_clk_lane;
+	const struct tegra_mipi_pad *pads;
+	unsigned int num_pads;
+
+	int clock_enable_override;
+	int needs_vclamp_ref;
+
+	/* bias pad configuration settings */
+	u8 pad_drive_down_ref;
+	u8 pad_drive_up_ref;
+
+	u8 pad_vclamp_level;
+	u8 pad_vauxp_level;
+
+	/* calibration settings for data lanes */
+	u8 hspdos;
+	u8 hspuos;
+	u8 termos;
+
+	/* calibration settings for clock lanes */
+	u8 hsclkpdos;
+	u8 hsclkpuos;
+};
+
+struct tegra_mipi {
+	const struct tegra_mipi_soc *soc;
+	void *regs;
+};
+
+struct tegra_mipi_device {
+	struct tegra_mipi *mipi;
+	unsigned long pads;
+};
+
+struct tegra_mipi_device *tegra_mipi_request(struct tegra_mipi_device *device,
+						int device_index);
+int tegra_mipi_calibrate(struct tegra_mipi_device *device);
+#endif /* __MIPI_DSI_H__ */
diff --git a/src/soc/nvidia/tegra210/include/soc/mmu_operations.h b/src/soc/nvidia/tegra210/include/soc/mmu_operations.h
new file mode 100644
index 0000000..6a81e7c
--- /dev/null
+++ b/src/soc/nvidia/tegra210/include/soc/mmu_operations.h
@@ -0,0 +1,28 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright 2014 Google Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc.
+ */
+
+#ifndef __SOC_NVIDIA_TEGRA210_MMU_OPERATIONS_H__
+#define __SOC_NVIDIA_TEGRA210_MMU_OPERATIONS_H__
+
+void tegra210_mmu_init(void);
+
+/* Default ttb size of 4MiB */
+#define TTB_SIZE 0x4
+
+#endif //__SOC_NVIDIA_TEGRA210_MMU_OPERATIONS_H__
diff --git a/src/soc/nvidia/tegra210/include/soc/mtc.h b/src/soc/nvidia/tegra210/include/soc/mtc.h
new file mode 100644
index 0000000..c94d79b
--- /dev/null
+++ b/src/soc/nvidia/tegra210/include/soc/mtc.h
@@ -0,0 +1,37 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright 2015 Google Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc.
+ */
+
+#ifndef __SOC_NVIDIA_TEGRA210_MTC_H__
+#define __SOC_NVIDIA_TEGRA210_MTC_H__
+
+#include <boot/coreboot_tables.h>
+
+#if CONFIG_HAVE_MTC
+
+int tegra210_run_mtc(void);
+void soc_add_mtc(struct lb_header *header);
+
+#else
+
+static inline int tegra210_run_mtc(void) { return -1; }
+static inline void soc_add_mtc(struct lb_header *header) {}
+
+#endif /* CONFIG_HAVE_MTC */
+
+#endif /* __SOC_NVIDIA_TEGRA210_MTC_H__ */
diff --git a/src/soc/nvidia/tegra210/include/soc/padconfig.h b/src/soc/nvidia/tegra210/include/soc/padconfig.h
new file mode 100644
index 0000000..01cd72a
--- /dev/null
+++ b/src/soc/nvidia/tegra210/include/soc/padconfig.h
@@ -0,0 +1,94 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright 2014 Google Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc.
+ */
+
+#ifndef __SOC_NVIDIA_TEGRA210_PAD_CFG_H
+#define __SOC_NVIDIA_TEGRA210_PAD_CFG_H
+
+#include <stdint.h>
+#include <soc/pinmux.h>
+
+struct pad_config {
+	uint16_t pinmux_flags;	/* PU/PU, OD, INPUT, SFIO, etc */
+	uint8_t gpio_index;		/* bank, port, index */
+	uint16_t pinmux_index:9;
+	uint16_t unused:1;
+	uint16_t sfio:1;
+	uint16_t gpio_out0:1;
+	uint16_t gpio_out1:1;
+	uint16_t pad_has_gpio:1;
+	uint16_t por_pullup:1;
+};
+
+#define PAD_CFG_GPIO_INPUT(ball_, pinmux_flgs_)		\
+	{						\
+		.pinmux_flags = pinmux_flgs_ | PINMUX_INPUT_ENABLE,	\
+		.gpio_index = PAD_TO_GPIO_##ball_,	\
+		.pinmux_index = PINMUX_##ball_##_INDEX,	\
+		.sfio = 0,				\
+		.pad_has_gpio = PAD_HAS_GPIO_##ball_,	\
+	}
+
+#define PAD_CFG_GPIO_OUT0(ball_, pinmux_flgs_)		\
+	{						\
+		.pinmux_flags = pinmux_flgs_,		\
+		.gpio_index = PAD_TO_GPIO_##ball_,	\
+		.pinmux_index = PINMUX_##ball_##_INDEX,	\
+		.sfio = 0,				\
+		.gpio_out0 = 1,				\
+		.pad_has_gpio = PAD_HAS_GPIO_##ball_,	\
+	}
+
+#define PAD_CFG_GPIO_OUT1(ball_, pinmux_flgs_)		\
+	{						\
+		.pinmux_flags = pinmux_flgs_,		\
+		.gpio_index = PAD_TO_GPIO_##ball_,	\
+		.pinmux_index = PINMUX_##ball_##_INDEX,	\
+		.sfio = 0,				\
+		.gpio_out1 = 1,				\
+		.pad_has_gpio = PAD_HAS_GPIO_##ball_,	\
+	}
+
+#define PAD_CFG_SFIO(ball_, pinmux_flgs_, sfio_)	\
+	{						\
+		.pinmux_flags = pinmux_flgs_ |		\
+				PINMUX_##ball_##_FUNC_##sfio_,	\
+		.gpio_index = PAD_TO_GPIO_##ball_,	\
+		.pinmux_index = PINMUX_##ball_##_INDEX,	\
+		.sfio = 1,				\
+		.pad_has_gpio = PAD_HAS_GPIO_##ball_,	\
+	}
+
+#define PAD_CFG_UNUSED(ball_)				\
+	{						\
+		.gpio_index = PAD_TO_GPIO_##ball_,	\
+		.pinmux_index = PINMUX_##ball_##_INDEX,	\
+		.unused = 1,				\
+		.pad_has_gpio = PAD_HAS_GPIO_##ball_,	\
+	}
+/*
+ * Configure the pads associated with entry according to the configuration.
+ */
+void soc_configure_pads(const struct pad_config * const entries, size_t num);
+/* I2C6 requires special init as its pad lives int the SOR/DPAUX block */
+void soc_configure_i2c6pad(void);
+void soc_configure_host1x(void);
+/* APE (Audio Processing Engine) requires special init */
+void soc_configure_ape(void);
+
+#endif /* __SOC_NVIDIA_TEGRA210_PAD_CFG_H */
diff --git a/src/soc/nvidia/tegra210/include/soc/pinmux.h b/src/soc/nvidia/tegra210/include/soc/pinmux.h
new file mode 100644
index 0000000..ab59fbf
--- /dev/null
+++ b/src/soc/nvidia/tegra210/include/soc/pinmux.h
@@ -0,0 +1,285 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright 2014 Google Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc.
+ */
+
+#ifndef __SOC_NVIDIA_TEGRA210_PINMUX_H__
+#define __SOC_NVIDIA_TEGRA210_PINMUX_H__
+
+#include <stdint.h>
+#include <soc/nvidia/tegra/gpio.h>
+#include <soc/nvidia/tegra/pinmux.h>
+
+enum {
+	PINMUX_FUNC_MASK = 3 << 0,
+
+	PINMUX_PULL_MASK = 3 << 2,
+	PINMUX_PULL_NONE = 0 << 2,
+	PINMUX_PULL_DOWN = 1 << 2,
+	PINMUX_PULL_UP = 2 << 2,
+
+	PINMUX_TRISTATE = 1 << 4,
+	PINMUX_PARKED = 1 << 5,
+	PINMUX_INPUT_ENABLE = 1 << 6,
+	PINMUX_LOCK = 1 << 7,
+	PINMUX_LPDR = 1 << 8,
+	PINMUX_HSM = 1 << 9,
+	PINMUX_IO_HV = 1 << 10,
+	PINMUX_OPEN_DRAIN = 1 << 11,
+	PINMUX_SCHMT = 1 << 12,
+};
+
+/* GPIO index constants. */
+
+#define GPIO_PORT_CONSTANTS(port) \
+	GPIO_##port##0_INDEX, GPIO_##port##1_INDEX, GPIO_##port##2_INDEX, \
+	GPIO_##port##3_INDEX, GPIO_##port##4_INDEX, GPIO_##port##5_INDEX, \
+	GPIO_##port##6_INDEX, GPIO_##port##7_INDEX
+
+enum {
+	GPIO_PORT_CONSTANTS(A),
+	GPIO_PORT_CONSTANTS(B),
+	GPIO_PORT_CONSTANTS(C),
+	GPIO_PORT_CONSTANTS(D),
+	GPIO_PORT_CONSTANTS(E),
+	GPIO_PORT_CONSTANTS(F),
+	GPIO_PORT_CONSTANTS(G),
+	GPIO_PORT_CONSTANTS(H),
+	GPIO_PORT_CONSTANTS(I),
+	GPIO_PORT_CONSTANTS(J),
+	GPIO_PORT_CONSTANTS(K),
+	GPIO_PORT_CONSTANTS(L),
+	GPIO_PORT_CONSTANTS(M),
+	GPIO_PORT_CONSTANTS(N),
+	GPIO_PORT_CONSTANTS(O),
+	GPIO_PORT_CONSTANTS(P),
+	GPIO_PORT_CONSTANTS(Q),
+	GPIO_PORT_CONSTANTS(R),
+	GPIO_PORT_CONSTANTS(S),
+	GPIO_PORT_CONSTANTS(T),
+	GPIO_PORT_CONSTANTS(U),
+	GPIO_PORT_CONSTANTS(V),
+	GPIO_PORT_CONSTANTS(W),
+	GPIO_PORT_CONSTANTS(X),
+	GPIO_PORT_CONSTANTS(Y),
+	GPIO_PORT_CONSTANTS(Z),
+	GPIO_PORT_CONSTANTS(AA),
+	GPIO_PORT_CONSTANTS(BB),
+	GPIO_PORT_CONSTANTS(CC),
+	GPIO_PORT_CONSTANTS(DD),
+	GPIO_PORT_CONSTANTS(EE),
+	GPIO_PORT_CONSTANTS(FF),
+	GPIO_NONE_INDEX = 0,
+};
+
+#define PINMUX_CONSTANTS_GPIO(name, gpio) \
+	PINMUX_GPIO_##gpio = PINMUX_##name##_INDEX
+
+#define PINMUX_CONSTANTS(index, name, por_pu, gpio, has_gpio, \
+				func0, func1, func2, func3) \
+	PINMUX_##name##_INDEX = index, \
+	PINMUX_##name##_FUNC_##func0 = 0, \
+	PINMUX_##name##_FUNC_##func1 = 1, \
+	PINMUX_##name##_FUNC_##func2 = 2, \
+	PINMUX_##name##_FUNC_##func3 = 3, \
+	PAD_TO_GPIO_##name = GPIO_##gpio##_INDEX, \
+	PAD_HAS_GPIO_##name = has_gpio, \
+	PAD_POR_PU_##name = por_pu
+
+#define PAD_GPIO(index, name, por_pu, gpio, func0, func1, func2, func3) \
+	PINMUX_CONSTANTS(index, name, por_pu, gpio, 1, \
+				func0, func1, func2, func3), \
+	PINMUX_CONSTANTS_GPIO(name, gpio)
+
+#define PAD_NO_GPIO(index, name, por_pu, func0, func1, func2, func3) \
+	PINMUX_CONSTANTS(index, name, por_pu, NONE, 0, \
+				func0, func1, func2, func3)
+
+enum {
+	/* Power-on-reset pull states. */
+	POR_PU = 2,
+	POR_PD = 1,
+	POR_NP = 0,
+
+	PAD_GPIO(0, SDMMC1_CLK,  POR_PD, M0, SDMMC1, RES1, RES2, RES3),
+	PAD_GPIO(1, SDMMC1_CMD,  POR_PU, M1, SDMMC1, RES1, RES2, RES3),
+	PAD_GPIO(2, SDMMC1_DAT3, POR_PU, M2, SDMMC1, RES1, RES2, RES3),
+	PAD_GPIO(3, SDMMC1_DAT2, POR_PU, M3, SDMMC1, RES1, RES2, RES3),
+	PAD_GPIO(4, SDMMC1_DAT1, POR_PU, M4, SDMMC1, RES1, RES2, RES3),
+	PAD_GPIO(5, SDMMC1_DAT0, POR_PU, M5, SDMMC1, RES1, RES2, RES3),
+	PAD_GPIO(6, SDMMC3_CLK,  POR_PD, P0, SDMMC3, RES1, RES2, RES3),
+	PAD_GPIO(7, SDMMC3_CMD,  POR_PU, P1, SDMMC3, RES1, RES2, RES3),
+	PAD_GPIO(8, SDMMC3_DAT0, POR_PU, P2, SDMMC3, RES1, RES2, RES3),
+	PAD_GPIO(9, SDMMC3_DAT1, POR_PU, P3, SDMMC3, RES1, RES2, RES3),
+	PAD_GPIO(10, SDMMC3_DAT2, POR_PU, P4, SDMMC3, RES1, RES2, RES3),
+	PAD_GPIO(11, SDMMC3_DAT3, POR_PU, P5, SDMMC3, RES1, RES2, RES3),
+	/* GPIO12 - unused */
+	/* GPIO13 - unused */
+	PAD_GPIO(14, PEX_L0_RST_N, POR_NP, A0, PE0, RES1, RES2, RES3),
+	PAD_GPIO(15, PEX_L0_CLKREQ_N, POR_NP, A1, PE0, RES1, RES2, RES3),
+	PAD_GPIO(16, PEX_WAKE_N, POR_NP, A2, PE, RES1, RES2, RES3),
+	PAD_GPIO(17, PEX_L1_RST_N, POR_NP, A3, PE1, RES1, RES2, RES3),
+	PAD_GPIO(18, PEX_L1_CLKREQ_N, POR_NP, A4, PE1, RES1, RES2, RES3),
+	PAD_GPIO(19, SATA_LED_ACTIVE, POR_NP, A5, SATA, RES1, RES2, RES3),
+	PAD_GPIO(20, SPI1_MOSI, POR_PD, C0, SPI1, RES1, RES2, RES3),
+	PAD_GPIO(21, SPI1_MISO, POR_PD, C1, SPI1, RES1, RES2, RES3),
+	PAD_GPIO(22, SPI1_SCK, POR_PD, C2, SPI1, RES1, RES2, RES3),
+	PAD_GPIO(23, SPI1_CS0, POR_PU, C3, SPI1, RES1, RES2, RES3),
+	PAD_GPIO(24, SPI1_CS1, POR_PU, C4, SPI1, RES1, RES2, RES3),
+	PAD_GPIO(25, SPI2_MOSI, POR_PD, B4, SPI2, DTV, RES2, RES3),
+	PAD_GPIO(26, SPI2_MISO, POR_PD, B5, SPI2, DTV, RES2, RES3),
+	PAD_GPIO(27, SPI2_SCK, POR_PD, B6, SPI2, DTV, RES2, RES3),
+	PAD_GPIO(28, SPI2_CS0, POR_PU, B7, SPI2, DTV, RES2, RES3),
+	PAD_GPIO(29, SPI2_CS1, POR_PU, DD0, SPI2, RES1, RES2, RES3),
+	PAD_GPIO(30, SPI4_MOSI, POR_PD, C7, SPI4, RES1, RES2, RES3),
+	PAD_GPIO(31, SPI4_MISO, POR_PD, D0, SPI4, RES1, RES2, RES3),
+	PAD_GPIO(32, SPI4_SCK, POR_PD, C5, SPI4, RES1, RES2, RES3),
+	PAD_GPIO(33, SPI4_CS0, POR_PU, C6, SPI4, RES1, RES2, RES3),
+	PAD_GPIO(34, QSPI_SCK, POR_PU, EE0, QSPI, RES1, RES2, RES3),
+	PAD_GPIO(35, QSPI_CS_N, POR_PU, EE1, QSPI, RES1, RES2, RES3),
+	PAD_GPIO(36, QSPI_IO0, POR_PU, EE2, QSPI, RES1, RES2, RES3),
+	PAD_GPIO(37, QSPI_IO1, POR_PU, EE3, QSPI, RES1, RES2, RES3),
+	PAD_GPIO(38, QSPI_IO2, POR_PU, EE4, QSPI, RES1, RES2, RES3),
+	PAD_GPIO(39, QSPI_IO3, POR_PU, EE5, QSPI, RES1, RES2, RES3),
+	/* GPIO40 - unused */
+	PAD_GPIO(41, DMIC1_CLK, POR_PD, E0, DMIC1, I2S3, RES2, RES3),
+	PAD_GPIO(42, DMIC1_DAT, POR_PD, E1, DMIC1, I2S3, RES2, RES3),
+	PAD_GPIO(43, DMIC2_CLK, POR_PD, E2, DMIC2, I2S3, RES2, RES3),
+	PAD_GPIO(44, DMIC2_DAT, POR_PD, E3, DMIC2, I2S3, RES2, RES3),
+	PAD_GPIO(45, DMIC3_CLK, POR_PD, E4, DMIC3, I2S5A, RES2, RES3),
+	PAD_GPIO(46, DMIC3_DAT, POR_PD, E5, DMIC3, I2S5A, RES2, RES3),
+	PAD_GPIO(47, GEN1_I2C_SDA, POR_NP, J0, I2C1, RES1, RES2, RES3),
+	PAD_GPIO(48, GEN1_I2C_SCL, POR_NP, J1, I2C1, RES1, RES2, RES3),
+	PAD_GPIO(49, GEN2_I2C_SCL, POR_NP, J2, I2C2, RES1, RES2, RES3),
+	PAD_GPIO(50, GEN2_I2C_SDA, POR_NP, J3, I2C2, RES1, RES2, RES3),
+	PAD_GPIO(51, GEN3_I2C_SCL, POR_NP, F0, I2C3, RES1, RES2, RES3),
+	PAD_GPIO(52, GEN3_I2C_SDA, POR_NP, F1, I2C3, RES1, RES2, RES3),
+	PAD_GPIO(53, CAM_I2C_SCL, POR_NP, S2, I2C3, I2CVI, RES2, RES3),
+	PAD_GPIO(54, CAM_I2C_SDA, POR_NP, S3, I2C3, I2CVI, RES2, RES3),
+	PAD_GPIO(55, PWR_I2C_SCL, POR_NP, Y3, I2CPMU, RES1, RES2, RES3),
+	PAD_GPIO(56, PWR_I2C_SDA, POR_NP, Y4, I2CPMU, RES1, RES2, RES3),
+	PAD_GPIO(57, UART1_TX, POR_PD, U0, UARTA, RES1, RES2, RES3),
+	PAD_GPIO(58, UART1_RX, POR_PD, U1, UARTA, RES1, RES2, RES3),
+	PAD_GPIO(59, UART1_RTS, POR_PD, U2, UARTA, RES1, RES2, RES3),
+	PAD_GPIO(60, UART1_CTS, POR_PD, U3, UARTA, RES1, RES2, RES3),
+	PAD_GPIO(61, UART2_TX, POR_PD, G0, UARTB, I2S4A, SPDIF, UART),
+	PAD_GPIO(62, UART2_RX, POR_PD, G1, UARTB, I2S4A, SPDIF, UART),
+	PAD_GPIO(63, UART2_RTS, POR_PD, G2, UARTB, I2S4A, RES2, UART),
+	PAD_GPIO(64, UART2_CTS, POR_PD, G3, UARTB, I2S4A, RES2, UART),
+	PAD_GPIO(65, UART3_TX, POR_PD, D1, UARTC, SPI4, RES2, RES3),
+	PAD_GPIO(66, UART3_RX, POR_PD, D2, UARTC, SPI4, RES2, RES3),
+	PAD_GPIO(67, UART3_RTS, POR_PD, D3, UARTC, SPI4, RES2, RES3),
+	PAD_GPIO(68, UART3_CTS, POR_PD, D4, UARTC, SPI4, RES2, RES3),
+	PAD_GPIO(69, UART4_TX, POR_PD, I4, UARTD, UART, RES2, RES3),
+	PAD_GPIO(70, UART4_RX, POR_PD, I5, UARTD, UART, RES2, RES3),
+	PAD_GPIO(71, UART4_RTS, POR_PD, I6, UARTD, UART, RES2, RES3),
+	PAD_GPIO(72, UART4_CTS, POR_PD, I7, UARTD, UART, RES2, RES3),
+	PAD_GPIO(73, DAP1_FS, POR_PD, B0, I2S1, RES1, RES2, RES3),
+	PAD_GPIO(74, DAP1_DIN, POR_PD, B1, I2S1, RES1, RES2, RES3),
+	PAD_GPIO(75, DAP1_DOUT, POR_PD, B2, I2S1, RES1, RES2, RES3),
+	PAD_GPIO(76, DAP1_SCLK, POR_PD, B3, I2S1, RES1, RES2, RES3),
+	PAD_GPIO(77, DAP2_FS, POR_PD, AA0, I2S2, RES1, RES2, RES3),
+	PAD_GPIO(78, DAP2_DIN, POR_PD, AA1, I2S2, RES1, RES2, RES3),
+	PAD_GPIO(79, DAP2_DOUT, POR_PD, AA2, I2S2, RES1, RES2, RES3),
+	PAD_GPIO(80, DAP2_SCLK, POR_PD, AA3, I2S2, RES1, RES2, RES3),
+	PAD_GPIO(81, DAP4_FS, POR_PD, J4, I2S4B, RES1, RES2, RES3),
+	PAD_GPIO(82, DAP4_DIN, POR_PD, J5, I2S4B, RES1, RES2, RES3),
+	PAD_GPIO(83, DAP4_DOUT, POR_PD, J6, I2S4B, RES1, RES2, RES3),
+	PAD_GPIO(84, DAP4_SCLK, POR_PD, J7, I2S4B, RES1, RES2, RES3),
+	PAD_GPIO(85, CAM1_MCLK, POR_PD, S0, EXTPERIPH3, RES1, RES2, RES3),
+	PAD_GPIO(86, CAM2_MCLK, POR_PD, S1, EXTPERIPH3, RES1, RES2, RES3),
+	PAD_NO_GPIO(87, JTAG_RTCK, POR_PU, JTAG, RES1, RES2, RES3),
+	PAD_NO_GPIO(88, CLK_32K_IN, POR_NP, CLK_32K_IN, RES1, RES2, RES3),
+	PAD_GPIO(89, CLK_32K_OUT, POR_PD, Y5, SOC, BLINK, RES2, RES3),
+	PAD_NO_GPIO(90, BATT_BCL, POR_NP, BCL, RES1, RES2, RES3),
+	PAD_NO_GPIO(91, CLK_REQ, POR_NP, CLK_REQ, RES1, RES2, RES3),
+	PAD_NO_GPIO(92, CPU_PWR_REQ, POR_NP, CPU, RES1, RES2, RES3),
+	PAD_NO_GPIO(93, PWR_INT_N, POR_NP, PMI, RES1, RES2, RES3),
+	PAD_NO_GPIO(94, SHUTDOWN, POR_NP, SHUTDOWN, RES1, RES2, RES3),
+	PAD_NO_GPIO(95, CORE_PWR_REQ, POR_NP, PWRON, RES1, RES2, RES3),
+	PAD_GPIO(96, AUD_MCLK, POR_PD, BB0, AUD, RES1, RES2, RES3),
+	PAD_GPIO(97, DVFS_PWM, POR_PD, BB1, RES0, CLDVFS, SPI3, RES3),
+	PAD_GPIO(98, DVFS_CLK, POR_PU, BB2, RES0, CLDVFS, SPI3, RES3),
+	PAD_GPIO(99, GPIO_X1_AUD, POR_PD, BB3, RES0, RES1, SPI3, RES3),
+	PAD_GPIO(100, GPIO_X3_AUD, POR_PU, BB4, RES0, RES1, SPI3, RES3),
+	PAD_NO_GPIO(101, GPIO_PCC7, POR_NP, RES0, RES1, RES2, RES3),
+	PAD_GPIO(102, HDMI_CEC, POR_NP, CC0, CEC, RES1, RES2, RES3),
+	PAD_GPIO(103, HDMI_INT_DP_HPD, POR_PD, CC1, DP, RES1, RES2, RES3),
+	PAD_GPIO(104, SPDIF_OUT, POR_PU, CC2, SPDIF, RES1, RES2, I2C3),
+	PAD_GPIO(105, SPDIF_IN, POR_PD, CC3, SPDIF, RES1, RES2, I2C3),
+	PAD_GPIO(106, USB_VBUS_EN0, POR_NP, CC4, USB, RES1, RES2, RES3),
+	PAD_GPIO(107, USB_VBUS_EN1, POR_NP, CC5, USB, RES1, RES2, RES3),
+	PAD_GPIO(108, DP_HPD0, POR_PD, CC6, DP, RES1, RES2, RES3),
+	PAD_GPIO(109, WIFI_EN, POR_PD, H0, RES0, RES1, RES2, RES3),
+	PAD_GPIO(110, WIFI_RST, POR_PD, H1, RES0, RES1, RES2, RES3),
+	PAD_GPIO(111, WIFI_WAKE_AP, POR_PD, H2, RES0, RES1, RES2, RES3),
+	PAD_GPIO(112, AP_WAKE_BT, POR_PD, H3, RES0, UARTB, SPDIF, RES3),
+	PAD_GPIO(113, BT_RST, POR_PD, H4, RES0, UARTB, SPDIF, RES3),
+	PAD_GPIO(114, BT_WAKE_AP, POR_PD, H5, RES0, RES1, RES2, RES3),
+	PAD_GPIO(115, AP_WAKE_NFC, POR_PD, H7, RES0, RES1, RES2, RES3),
+	PAD_GPIO(116, NFC_EN, POR_PD, I0, RES0, RES1, RES2, RES3),
+	PAD_GPIO(117, NFC_INT, POR_PD, I1, RES0, RES1, RES2, RES3),
+	PAD_GPIO(118, GPS_EN, POR_PD, I2, RES0, RES1, RES2, RES3),
+	PAD_GPIO(119, GPS_RST, POR_PD, I3, RES0, RES1, RES2, RES3),
+	PAD_GPIO(120, CAM_RST, POR_PD, S4, VGP1, RES1, RES2, RES3),
+	PAD_GPIO(121, CAM_AF_EN, POR_PD, S5, VIMCLK, VGP2, RES2, RES3),
+	PAD_GPIO(122, CAM_FLASH_EN, POR_PD, S6, VIMCLK, VGP3, RES2, RES3),
+	PAD_GPIO(123, CAM1_PWDN, POR_PD, S7, VGP4, RES1, RES2, RES3),
+	PAD_GPIO(124, CAM2_PWDN, POR_PD, T0, VGP5, RES1, RES2, RES3),
+	PAD_GPIO(125, CAM1_STROBE, POR_PD, T1, VGP6, RES1, RES2, RES3),
+	PAD_GPIO(126, LCD_TE, POR_PD, Y2, DISPLAYA, RES1, RES2, RES3),
+	PAD_GPIO(127, LCD_BL_PWM, POR_PD, V0, DISPLAYA, PWM0, SOR0, RES3),
+	PAD_GPIO(128, LCD_BL_EN, POR_PD, V1, RES0, RES1, RES2, RES3),
+	PAD_GPIO(129, LCD_RST, POR_PD, V2, RES0, RES1, RES2, RES3),
+	PAD_GPIO(130, LCD_GPIO1, POR_PD, V3, DISPLAYB, RES1, RES2, RES3),
+	PAD_GPIO(131, LCD_GPIO2, POR_PD, V4, DISPLAYB, PWM1, RES2, SOR1),
+	PAD_GPIO(132, AP_READY, POR_PD, V5, RES0, RES1, RES2, RES3),
+	PAD_GPIO(133, TOUCH_RST, POR_PD, V6, RES0, RES1, RES2, RES3),
+	PAD_GPIO(134, TOUCH_CLK, POR_PD, V7, TOUCH, RES1, RES2, RES3),
+	PAD_GPIO(135, MODEM_WAKE_AP, POR_PD, X0, RES0, RES1, RES2, RES3),
+	PAD_GPIO(136, TOUCH_INT, POR_PD, X1, RES0, RES1, RES2, RES3),
+	PAD_GPIO(137, MOTION_INT, POR_PD, X2, RES0, RES1, RES2, RES3),
+	PAD_GPIO(138, ALS_PROX_INT, POR_PD, X3, RES0, RES1, RES2, RES3),
+	PAD_GPIO(139, TEMP_ALERT, POR_PD, X4, RES0, RES1, RES2, RES3),
+	PAD_GPIO(140, BUTTON_POWER_ON, POR_PU, X5, RES0, RES1, RES2, RES3),
+	PAD_GPIO(141, BUTTON_VOL_UP, POR_PU, X6, RES0, RES1, RES2, RES3),
+	PAD_GPIO(142, BUTTON_VOL_DOWN, POR_PU, X7, RES0, RES1, RES2, RES3),
+	PAD_GPIO(143, BUTTON_SLIDE_SW, POR_PU, Y0, RES0, RES1, RES2, RES3),
+	PAD_GPIO(144, BUTTON_HOME, POR_PU, Y1, RES0, RES1, RES2, RES3),
+	PAD_NO_GPIO(145, GPIO_PA6, POR_NP, SATA, RES1, RES2, RES3),
+	PAD_NO_GPIO(146, GPIO_PE6, POR_PD, RES0, I2S5A, PWM2, RES3),
+	PAD_NO_GPIO(147, GPIO_PE7, POR_PD, RES0, I2S5A, PWM3, RES3),
+	PAD_NO_GPIO(148, GPIO_PH6, POR_PD, RES0, RES1, RES2, RES3),
+	PAD_GPIO(149, GPIO_PK0, POR_PD, K0, IQC0, I2S5B, RES2, RES3),
+	PAD_GPIO(150, GPIO_PK1, POR_PD, K1, IQC0, I2S5B, RES2, RES3),
+	PAD_GPIO(151, GPIO_PK2, POR_PD, K2, IQC0, I2S5B, RES2, RES3),
+	PAD_NO_GPIO(152, GPIO_PK3, POR_PD, IQC0, I2S5B, RES2, RES3),
+	PAD_NO_GPIO(153, GPIO_PK4, POR_PD, IQC1, RES1, RES2, RES3),
+	PAD_NO_GPIO(154, GPIO_PK5, POR_PD, IQC1, RES1, RES2, RES3),
+	PAD_NO_GPIO(155, GPIO_PK6, POR_PD, IQC1, RES1, RES2, RES3),
+	PAD_NO_GPIO(156, GPIO_PK7, POR_PD, IQC1, RES1, RES2, RES3),
+	PAD_NO_GPIO(157, GPIO_PL0, POR_PD, RES0, RES1, RES2, RES3),
+	PAD_NO_GPIO(158, GPIO_PL1, POR_PD, SOC, RES1, RES2, RES3),
+	PAD_NO_GPIO(159, GPIO_PZ0, POR_PD, VIMCLK2, RES1, RES2, RES3),
+	PAD_GPIO(160, GPIO_PZ1, POR_PD, Z1, VIMCLK2, SDMMC1, RES2, RES3),
+	PAD_NO_GPIO(161, GPIO_PZ2, POR_PD, SDMMC3, CCLA, RES2, RES3),
+	PAD_NO_GPIO(162, GPIO_PZ3, POR_PD, SDMMC3, RES1, RES2, RES3),
+	PAD_GPIO(163, GPIO_PZ4, POR_PD, Z4, SDMMC1, RES1, RES2, RES3),
+	PAD_NO_GPIO(164, GPIO_PZ5, POR_PD, SOC, RES1, RES2, RES3),
+};
+
+#endif	/* __SOC_NVIDIA_TEGRA210_PINMUX_H__ */
diff --git a/src/soc/nvidia/tegra210/include/soc/pmc.h b/src/soc/nvidia/tegra210/include/soc/pmc.h
new file mode 100644
index 0000000..c652235
--- /dev/null
+++ b/src/soc/nvidia/tegra210/include/soc/pmc.h
@@ -0,0 +1,680 @@
+/*
+ * Copyright (c) 2010-2015, NVIDIA CORPORATION.  All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _TEGRA210_PMC_H_
+#define _TEGRA210_PMC_H_
+
+#include <stdint.h>
+
+enum {
+	POWER_PARTID_CRAIL = 0,
+	POWER_PARTID_TD = 1,
+	POWER_PARTID_VE = 2,
+	POWER_PARTID_PCX = 3,
+	POWER_PARTID_C0L2 = 5,
+	POWER_PARTID_MPE = 6,
+	POWER_PARTID_HEG = 7,
+	POWER_PARTID_SAX = 8,
+	POWER_PARTID_CE1 = 9,
+	POWER_PARTID_CE2 = 10,
+	POWER_PARTID_CE3 = 11,
+	POWER_PARTID_CELP = 12,
+	POWER_PARTID_CE0 = 14,
+	POWER_PARTID_C0NC = 15,
+	POWER_PARTID_C1NC = 16,
+	POWER_PARTID_SOR = 17,
+	POWER_PARTID_DIS = 18,
+	POWER_PARTID_DISB = 19,
+	POWER_PARTID_XUSBA = 20,
+	POWER_PARTID_XUSBB = 21,
+	POWER_PARTID_XUSBC = 22,
+	POWER_PARTID_VIC = 23,
+	POWER_PARTID_IRAM = 24,
+	POWER_PARTID_NVDEC = 25,
+	POWER_PARTID_NVJPG = 26,
+	POWER_PARTID_APE = 27,
+	POWER_PARTID_DFD = 28,
+	POWER_PARTID_VE2 = 29,
+};
+
+struct tegra_pmc_regs {
+	u32 cntrl;
+	u32 sec_disable;
+	u32 pmc_swrst;
+	u32 wake_mask;
+	u32 wake_lvl;
+	u32 wake_status;
+	u32 sw_wake_status;
+	u32 dpd_pads_oride;
+	u32 dpd_sample;
+	u32 dpd_enable;
+	u32 pwrgate_timer_off;
+	u32 clamp_status;
+	u32 pwrgate_toggle;
+	u32 remove_clamping_cmd;
+	u32 pwrgate_status;
+	u32 pwrgood_timer;
+	u32 blink_timer;
+	u32 no_iopower;
+	u32 pwr_det;
+	u32 pwr_det_latch;
+	u32 scratch0;
+	u32 scratch1;
+	u32 scratch2;
+	u32 scratch3;
+	u32 scratch4;
+	u32 scratch5;
+	u32 scratch6;
+	u32 scratch7;
+	u32 scratch8;
+	u32 scratch9;
+	u32 scratch10;
+	u32 scratch11;
+	u32 scratch12;
+	u32 scratch13;
+	u32 scratch14;
+	u32 scratch15;
+	u32 scratch16;
+	u32 scratch17;
+	u32 scratch18;
+	u32 scratch19;
+	u32 odmdata;
+	u32 scratch21;
+	u32 scratch22;
+	u32 scratch23;
+	u32 secure_scratch0;
+	u32 secure_scratch1;
+	u32 secure_scratch2;
+	u32 secure_scratch3;
+	u32 secure_scratch4;
+	u32 secure_scratch5;
+	u32 cpupwrgood_timer;
+	u32 cpupwroff_timer;
+	u32 pg_mask;
+	u32 pg_mask_1;
+	u32 auto_wake_lvl;
+	u32 auto_wake_lvl_mask;
+	u32 wake_delay;
+	u32 pwr_det_val;
+	u32 ddr_pwr;
+	u32 usb_debounce_del;
+	u32 usb_a0;
+	u32 crypto_op;
+	u32 pllp_wb0_override;
+	u32 scratch24;
+	u32 scratch25;
+	u32 scratch26;
+	u32 scratch27;
+	u32 scratch28;
+	u32 scratch29;
+	u32 scratch30;
+	u32 scratch31;
+	u32 scratch32;
+	u32 scratch33;
+	u32 scratch34;
+	u32 scratch35;
+	u32 scratch36;
+	u32 scratch37;
+	u32 scratch38;
+	u32 scratch39;
+	u32 scratch40;
+	u32 scratch41;
+	u32 scratch42;
+	u32 bondout_mirror[3];
+	u32 sys_33v_en;
+	u32 bondout_mirror_access;
+	u32 gate;
+	u32 wake2_mask;
+	u32 wake2_lvl;
+	u32 wake2_status;
+	u32 sw_wake2_status;
+	u32 auto_wake2_lvl_mask;
+	u32 pg_mask_2;
+	u32 pg_mask_ce1;
+	u32 pg_mask_ce2;
+	u32 pg_mask_ce3;
+	u32 pwrgate_timer_ce[7];
+	u32 pcx_edpd_cntrl;
+	u32 osc_edpd_over;
+	u32 clk_out_cntrl;
+	u32 sata_pwrgt;
+	u32 sensor_ctrl;
+	u32 rst_status;
+	u32 io_dpd_req;
+	u32 io_dpd_status;
+	u32 io_dpd2_req;
+	u32 io_dpd2_status;
+	u32 sel_dpd_tim;
+	u32 vddp_sel;
+	u32 ddr_cfg;
+	u32 e_no_vttgen;
+	u8 _rsv0[4];
+	u32 pllm_wb0_override_freq;
+	u32 test_pwrgate;
+	u32 pwrgate_timer_mult;
+	u32 dis_sel_dpd;
+	u32 utmip_uhsic_triggers;
+	u32 utmip_uhsic_saved_state;
+	u32 utmip_pad_cfg;
+	u32 utmip_term_pad_cfg;
+	u32 utmip_uhsic_sleep_cfg;
+	u32 utmip_uhsic_sleepwalk_cfg;
+	u32 utmip_sleepwalk_p[3];
+	u32 uhsic_sleepwalk_p0;
+	u32 utmip_uhsic_status;
+	u32 utmip_uhsic_fake;
+	u32 bondout_mirror3[5 - 3];
+	u32 secure_scratch6;
+	u32 secure_scratch7;
+	u32 scratch43;
+	u32 scratch44;
+	u32 scratch45;
+	u32 scratch46;
+	u32 scratch47;
+	u32 scratch48;
+	u32 scratch49;
+	u32 scratch50;
+	u32 scratch51;
+	u32 scratch52;
+	u32 scratch53;
+	u32 scratch54;
+	u32 scratch55;
+	u32 scratch0_eco;
+	u32 por_dpd_ctrl;
+	u32 scratch2_eco;
+	u32 utmip_uhsic_line_wakeup;
+	u32 utmip_bias_master_cntrl;
+	u32 utmip_master_config;
+	u32 td_pwrgate_inter_part_timer;
+	u32 utmip_uhsic2_triggers;
+	u32 utmip_uhsic2_saved_state;
+	u32 utmip_uhsic2_sleep_cfg;
+	u32 utmip_uhsic2_sleepwalk_cfg;
+	u32 uhsic2_sleepwalk_p1;
+	u32 utmip_uhsic2_status;
+	u32 utmip_uhsic2_fake;
+	u32 utmip_uhsic2_line_wakeup;
+	u32 utmip_master2_config;
+	u32 utmip_uhsic_rpd_cfg;
+	u32 pg_mask_ce0;
+	u32 pg_mask3[5 - 3];
+	u32 pllm_wb0_override2;
+	u32 tsc_mult;
+	u32 cpu_vsense_override;
+	u32 glb_amap_cfg;
+	u32 sticky_bits;
+	u32 sec_disable2;
+	u32 weak_bias;
+	u32 reg_short;
+	u32 pg_mask_andor;
+	u8 _rsv1[0x2c];
+	u32 secure_scratch8;	/* offset 0x300 */
+	u32 secure_scratch9;
+	u32 secure_scratch10;
+	u32 secure_scratch11;
+	u32 secure_scratch12;
+	u32 secure_scratch13;
+	u32 secure_scratch14;
+	u32 secure_scratch15;
+	u32 secure_scratch16;
+	u32 secure_scratch17;
+	u32 secure_scratch18;
+	u32 secure_scratch19;
+	u32 secure_scratch20;
+	u32 secure_scratch21;
+	u32 secure_scratch22;
+	u32 secure_scratch23;
+	u32 secure_scratch24;
+	u32 secure_scratch25;
+	u32 secure_scratch26;
+	u32 secure_scratch27;
+	u32 secure_scratch28;
+	u32 secure_scratch29;
+	u32 secure_scratch30;
+	u32 secure_scratch31;
+	u32 secure_scratch32;
+	u32 secure_scratch33;
+	u32 secure_scratch34;
+	u32 secure_scratch35;
+	u32 secure_scratch36;
+	u32 secure_scratch37;
+	u32 secure_scratch38;
+	u32 secure_scratch39;
+	u32 secure_scratch40;
+	u32 secure_scratch41;
+	u32 secure_scratch42;
+	u32 secure_scratch43;
+	u32 secure_scratch44;
+	u32 secure_scratch45;
+	u32 secure_scratch46;
+	u32 secure_scratch47;
+	u32 secure_scratch48;
+	u32 secure_scratch49;
+	u32 secure_scratch50;
+	u32 secure_scratch51;
+	u32 secure_scratch52;
+	u32 secure_scratch53;
+	u32 secure_scratch54;
+	u32 secure_scratch55;
+	u32 secure_scratch56;
+	u32 secure_scratch57;
+	u32 secure_scratch58;
+	u32 secure_scratch59;
+	u32 secure_scratch60;
+	u32 secure_scratch61;
+	u32 secure_scratch62;
+	u32 secure_scratch63;
+	u32 secure_scratch64;
+	u32 secure_scratch65;
+	u32 secure_scratch66;
+	u32 secure_scratch67;
+	u32 secure_scratch68;
+	u32 secure_scratch69;
+	u32 secure_scratch70;
+	u32 secure_scratch71;
+	u32 secure_scratch72;
+	u32 secure_scratch73;
+	u32 secure_scratch74;
+	u32 secure_scratch75;
+	u32 secure_scratch76;
+	u32 secure_scratch77;
+	u32 secure_scratch78;
+	u32 secure_scratch79;
+	u32 _rsv0x420[8];
+	u32 cntrl2;			/* 0x440 */
+	u32 _rsv0x444[2];
+	u32 event_counter;	/* 0x44C */
+	u32 fuse_control;
+	u32 scratch1_eco;
+	u32 _rsv0x458[1];
+	u32 io_dpd3_req;	/* 0x45C */
+	u32 io_dpd3_status;
+	u32 io_dpd4_req;
+	u32 io_dpd4_status;
+	u32 _rsv0x46C[30];
+	u32 ddr_cntrl;		/* 0x4E4 */
+	u32 _rsv0x4E8[70];
+	u32 scratch56;		/* 0x600 */
+	u32 scratch57;
+	u32 scratch58;
+	u32 scratch59;
+	u32 scratch60;
+	u32 scratch61;
+	u32 scratch62;
+	u32 scratch63;
+	u32 scratch64;
+	u32 scratch65;
+	u32 scratch66;
+	u32 scratch67;
+	u32 scratch68;
+	u32 scratch69;
+	u32 scratch70;
+	u32 scratch71;
+	u32 scratch72;
+	u32 scratch73;
+	u32 scratch74;
+	u32 scratch75;
+	u32 scratch76;
+	u32 scratch77;
+	u32 scratch78;
+	u32 scratch79;
+	u32 scratch80;
+	u32 scratch81;
+	u32 scratch82;
+	u32 scratch83;
+	u32 scratch84;
+	u32 scratch85;
+	u32 scratch86;
+	u32 scratch87;
+	u32 scratch88;
+	u32 scratch89;
+	u32 scratch90;
+	u32 scratch91;
+	u32 scratch92;
+	u32 scratch93;
+	u32 scratch94;
+	u32 scratch95;
+	u32 scratch96;
+	u32 scratch97;
+	u32 scratch98;
+	u32 scratch99;
+	u32 scratch100;
+	u32 scratch101;
+	u32 scratch102;
+	u32 scratch103;
+	u32 scratch104;
+	u32 scratch105;
+	u32 scratch106;
+	u32 scratch107;
+	u32 scratch108;
+	u32 scratch109;
+	u32 scratch110;
+	u32 scratch111;
+	u32 scratch112;
+	u32 scratch113;
+	u32 scratch114;
+	u32 scratch115;
+	u32 scratch116;
+	u32 scratch117;
+	u32 scratch118;
+	u32 scratch119;
+	u32 scratch120;		/* 0x700 */
+	u32 scratch121;
+	u32 scratch122;
+	u32 scratch123;
+	u32 scratch124;
+	u32 scratch125;
+	u32 scratch126;
+	u32 scratch127;
+	u32 scratch128;
+	u32 scratch129;
+	u32 scratch130;
+	u32 scratch131;
+	u32 scratch132;
+	u32 scratch133;
+	u32 scratch134;
+	u32 scratch135;
+	u32 scratch136;
+	u32 scratch137;
+	u32 scratch138;
+	u32 scratch139;
+	u32 scratch140;
+	u32 scratch141;
+	u32 scratch142;
+	u32 scratch143;
+	u32 scratch144;
+	u32 scratch145;
+	u32 scratch146;
+	u32 scratch147;
+	u32 scratch148;
+	u32 scratch149;
+	u32 scratch150;
+	u32 scratch151;
+	u32 scratch152;
+	u32 scratch153;
+	u32 scratch154;
+	u32 scratch155;
+	u32 scratch156;
+	u32 scratch157;
+	u32 scratch158;
+	u32 scratch159;
+	u32 scratch160;
+	u32 scratch161;
+	u32 scratch162;
+	u32 scratch163;
+	u32 scratch164;
+	u32 scratch165;
+	u32 scratch166;
+	u32 scratch167;
+	u32 scratch168;
+	u32 scratch169;
+	u32 scratch170;
+	u32 scratch171;
+	u32 scratch172;
+	u32 scratch173;
+	u32 scratch174;
+	u32 scratch175;
+	u32 scratch176;
+	u32 scratch177;
+	u32 scratch178;
+	u32 scratch179;
+	u32 scratch180;
+	u32 scratch181;
+	u32 scratch182;
+	u32 scratch183;
+	u32 scratch184;
+	u32 scratch185;
+	u32 scratch186;
+	u32 scratch187;
+	u32 scratch188;
+	u32 scratch189;
+	u32 scratch190;
+	u32 scratch191;
+	u32 scratch192;
+	u32 scratch193;
+	u32 scratch194;
+	u32 scratch195;
+	u32 scratch196;
+	u32 scratch197;
+	u32 scratch198;
+	u32 scratch199;
+	u32 scratch200;
+	u32 scratch201;
+	u32 scratch202;
+	u32 scratch203;
+	u32 scratch204;
+	u32 scratch205;
+	u32 scratch206;
+	u32 scratch207;
+	u32 scratch208;
+	u32 scratch209;
+	u32 scratch210;
+	u32 scratch211;
+	u32 scratch212;
+	u32 scratch213;
+	u32 scratch214;
+	u32 scratch215;
+	u32 scratch216;
+	u32 scratch217;
+	u32 scratch218;
+	u32 scratch219;
+	u32 scratch220;
+	u32 scratch221;
+	u32 scratch222;
+	u32 scratch223;
+	u32 scratch224;
+	u32 scratch225;
+	u32 scratch226;
+	u32 scratch227;
+	u32 scratch228;
+	u32 scratch229;
+	u32 scratch230;
+	u32 scratch231;
+	u32 scratch232;
+	u32 scratch233;
+	u32 scratch234;
+	u32 scratch235;
+	u32 scratch236;
+	u32 scratch237;
+	u32 scratch238;
+	u32 scratch239;
+	u32 scratch240;
+	u32 scratch241;
+	u32 scratch242;
+	u32 scratch243;
+	u32 scratch244;
+	u32 scratch245;
+	u32 scratch246;
+	u32 scratch247;
+	u32 scratch248;
+	u32 scratch249;
+	u32 scratch250;
+	u32 scratch251;
+	u32 scratch252;
+	u32 scratch253;
+	u32 scratch254;
+	u32 scratch255;
+	u32 scratch256;
+	u32 scratch257;
+	u32 scratch258;
+	u32 scratch259;
+	u32 scratch260;
+	u32 scratch261;
+	u32 scratch262;
+	u32 scratch263;
+	u32 scratch264;
+	u32 scratch265;
+	u32 scratch266;
+	u32 scratch267;
+	u32 scratch268;
+	u32 scratch269;
+	u32 scratch270;
+	u32 scratch271;
+	u32 scratch272;
+	u32 scratch273;
+	u32 scratch274;
+	u32 scratch275;
+	u32 scratch276;
+	u32 scratch277;
+	u32 scratch278;
+	u32 scratch279;
+	u32 scratch280;
+	u32 scratch281;
+	u32 scratch282;
+	u32 scratch283;
+	u32 scratch284;
+	u32 scratch285;
+	u32 scratch286;
+	u32 scratch287;
+	u32 scratch288;
+	u32 scratch289;
+	u32 scratch290;
+	u32 scratch291;
+	u32 scratch292;
+	u32 scratch293;
+	u32 scratch294;
+	u32 scratch295;
+	u32 scratch296;
+	u32 scratch297;
+	u32 scratch298;
+	u32 scratch299;			/* 0x9CC */
+	u32 _rsv0x9D0[50];
+	u32 secure_scratch80;	/* 0xa98 */
+	u32 secure_scratch81;
+	u32 secure_scratch82;
+	u32 secure_scratch83;
+	u32 secure_scratch84;
+	u32 secure_scratch85;
+	u32 secure_scratch86;
+	u32 secure_scratch87;
+	u32 secure_scratch88;
+	u32 secure_scratch89;
+	u32 secure_scratch90;
+	u32 secure_scratch91;
+	u32 secure_scratch92;
+	u32 secure_scratch93;
+	u32 secure_scratch94;
+	u32 secure_scratch95;
+	u32 secure_scratch96;
+	u32 secure_scratch97;
+	u32 secure_scratch98;
+	u32 secure_scratch99;
+	u32 secure_scratch100;
+	u32 secure_scratch101;
+	u32 secure_scratch102;
+	u32 secure_scratch103;
+	u32 secure_scratch104;
+	u32 secure_scratch105;
+	u32 secure_scratch106;
+	u32 secure_scratch107;
+	u32 secure_scratch108;
+	u32 secure_scratch109;
+	u32 secure_scratch110;
+	u32 secure_scratch111;
+	u32 secure_scratch112;
+	u32 secure_scratch113;
+	u32 secure_scratch114;
+	u32 secure_scratch115;
+	u32 secure_scratch116;
+	u32 secure_scratch117;
+	u32 secure_scratch118;
+	u32 secure_scratch119;
+};
+
+check_member(tegra_pmc_regs, secure_scratch119, 0xB34);
+
+enum {
+	PMC_RST_STATUS_SOURCE_MASK = 0x7,
+	PMC_RST_STATUS_SOURCE_POR = 0x0,
+	PMC_RST_STATUS_SOURCE_WATCHDOG = 0x1,
+	PMC_RST_STATUS_SOURCE_SENSOR = 0x2,
+	PMC_RST_STATUS_SOURCE_SW_MAIN = 0x3,
+	PMC_RST_STATUS_SOURCE_LP0 = 0x4,
+	PMC_RST_STATUS_NUM_SOURCES = 0x5,
+};
+
+enum {
+	PMC_PWRGATE_TOGGLE_PARTID_MASK = 0x1f,
+	PMC_PWRGATE_TOGGLE_PARTID_SHIFT = 0,
+	PMC_PWRGATE_TOGGLE_START = 0x1 << 8
+};
+
+enum {
+	PMC_CNTRL_KBC_CLK_DIS = 0x1 << 0,
+	PMC_CNTRL_RTC_CLK_DIS = 0x1 << 1,
+	PMC_CNTRL_RTC_RST = 0x1 << 2,
+	PMC_CNTRL_KBC_RST = 0x1 << 3,
+	PMC_CNTRL_MAIN_RST = 0x1 << 4,
+	PMC_CNTRL_LATCHWAKE_EN = 0x1 << 5,
+	PMC_CNTRL_GLITCHDET_DIS = 0x1 << 6,
+	PMC_CNTRL_BLINK_EN = 0x1 << 7,
+	PMC_CNTRL_PWRREQ_POLARITY = 0x1 << 8,
+	PMC_CNTRL_PWRREQ_OE = 0x1 << 9,
+	PMC_CNTRL_SYSCLK_POLARITY = 0x1 << 10,
+	PMC_CNTRL_SYSCLK_OE = 0x1 << 11,
+	PMC_CNTRL_PWRGATE_DIS = 0x1 << 12,
+	PMC_CNTRL_AOINIT = 0x1 << 13,
+	PMC_CNTRL_SIDE_EFFECT_LP0 = 0x1 << 14,
+	PMC_CNTRL_CPUPWRREQ_POLARITY = 0x1 << 15,
+	PMC_CNTRL_CPUPWRREQ_OE = 0x1 << 16,
+	PMC_CNTRL_INTR_POLARITY = 0x1 << 17,
+	PMC_CNTRL_FUSE_OVERRIDE = 0x1 << 18,
+	PMC_CNTRL_CPUPWRGOOD_EN = 0x1 << 19,
+	PMC_CNTRL_CPUPWRGOOD_SEL_SHIFT = 20,
+	PMC_CNTRL_CPUPWRGOOD_SEL_MASK =
+		0x3 << PMC_CNTRL_CPUPWRGOOD_SEL_SHIFT
+};
+
+enum {
+	PMC_DDR_PWR_EMMC_MASK = 1 << 1,
+	PMC_DDR_PWR_VAL_MASK = 1 << 0,
+};
+
+enum {
+	PMC_DDR_CFG_PKG_MASK = 1 << 0,
+	PMC_DDR_CFG_IF_MASK = 1 << 1,
+	PMC_DDR_CFG_XM0_RESET_TRI_MASK = 1 << 12,
+	PMC_DDR_CFG_XM0_RESET_DPDIO_MASK = 1 << 13,
+};
+
+enum {
+	PMC_NO_IOPOWER_MEM_MASK = 1 << 7,
+	PMC_NO_IOPOWER_MEM_COMP_MASK = 1 << 16,
+};
+
+enum {
+	PMC_POR_DPD_CTRL_MEM0_ADDR0_CLK_SEL_DPD_MASK = 1 << 0,
+	PMC_POR_DPD_CTRL_MEM0_ADDR1_CLK_SEL_DPD_MASK = 1 << 1,
+	PMC_POR_DPD_CTRL_MEM0_HOLD_CKE_LOW_OVR_MASK = 1 << 31,
+};
+
+enum {
+	PMC_CNTRL2_HOLD_CKE_LOW_EN = 0x1 << 12
+};
+
+enum {
+	PMC_OSC_EDPD_OVER_XOFS_SHIFT = 1,
+	PMC_OSC_EDPD_OVER_XOFS_MASK =
+		0x3f << PMC_OSC_EDPD_OVER_XOFS_SHIFT
+};
+
+enum {
+	PMC_CMD_HOLD_LOW_BR00_11_MASK = 0x0007FF80,
+	DPD_OFF = 1 << 30,
+	DPD_ON = 2 << 30,
+};
+
+#endif	/* _TEGRA210_PMC_H_ */
diff --git a/src/soc/nvidia/tegra210/include/soc/power.h b/src/soc/nvidia/tegra210/include/soc/power.h
new file mode 100644
index 0000000..b5fcffb
--- /dev/null
+++ b/src/soc/nvidia/tegra210/include/soc/power.h
@@ -0,0 +1,32 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright 2014 Google Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc.
+ */
+
+#ifndef __SOC_NVIDIA_TEGRA210_POWER_H__
+#define __SOC_NVIDIA_TEGRA210_POWER_H__
+
+#include <soc/pmc.h>
+
+void power_ungate_partition(uint32_t id);
+void power_gate_partition(uint32_t id);
+
+uint8_t pmc_rst_status(void);
+void pmc_print_rst_status(void);
+void remove_clamps(int id);
+
+#endif	/* __SOC_NVIDIA_TEGRA210_POWER_H__ */
diff --git a/src/soc/nvidia/tegra210/include/soc/romstage.h b/src/soc/nvidia/tegra210/include/soc/romstage.h
new file mode 100644
index 0000000..d4ab982
--- /dev/null
+++ b/src/soc/nvidia/tegra210/include/soc/romstage.h
@@ -0,0 +1,29 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright 2014 Google Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc.
+ */
+
+#ifndef __SOC_NVIDIA_TEGRA210_SOC_ROMSTAGE_H__
+#define __SOC_NVIDIA_TEGRA210_SOC_ROMSTAGE_H__
+
+void romstage(void);
+void romstage_mainboard_init(void);
+
+void mainboard_configure_pmc(void);
+void mainboard_enable_vdd_cpu(void);
+
+#endif /* __SOC_NVIDIA_TEGRA210_SOC_ROMSTAGE_H__ */
diff --git a/src/soc/nvidia/tegra210/include/soc/sdram.h b/src/soc/nvidia/tegra210/include/soc/sdram.h
new file mode 100644
index 0000000..a8dec82
--- /dev/null
+++ b/src/soc/nvidia/tegra210/include/soc/sdram.h
@@ -0,0 +1,31 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright 2014 Google Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc.
+ */
+
+#ifndef __SOC_NVIDIA_TEGRA210_SDRAM_H__
+#define __SOC_NVIDIA_TEGRA210_SDRAM_H__
+
+#include <soc/sdram_param.h>
+
+uint32_t sdram_get_ram_code(void);
+void sdram_init(const struct sdram_params *param);
+
+/* Save params to PMC scratch registers for use by BootROM on LP0 resume. */
+void sdram_lp0_save_params(const struct sdram_params *sdram);
+
+#endif /* __SOC_NVIDIA_TEGRA210_SDRAM_H__ */
diff --git a/src/soc/nvidia/tegra210/include/soc/sdram_configs.h b/src/soc/nvidia/tegra210/include/soc/sdram_configs.h
new file mode 100644
index 0000000..905ff9c
--- /dev/null
+++ b/src/soc/nvidia/tegra210/include/soc/sdram_configs.h
@@ -0,0 +1,28 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright 2014 Google Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc.
+ */
+
+#ifndef __SOC_NVIDIA_TEGRA210_SDRAM_CONFIGS_H__
+#define __SOC_NVIDIA_TEGRA210_SDRAM_CONFIGS_H__
+
+#include <soc/sdram.h>
+
+/* Loads SDRAM configurations for current system. */
+const struct sdram_params *get_sdram_config(void);
+
+#endif  /* __SOC_NVIDIA_TEGRA210_SDRAM_CONFIGS_H__ */
diff --git a/src/soc/nvidia/tegra210/include/soc/sdram_param.h b/src/soc/nvidia/tegra210/include/soc/sdram_param.h
new file mode 100644
index 0000000..018101e
--- /dev/null
+++ b/src/soc/nvidia/tegra210/include/soc/sdram_param.h
@@ -0,0 +1,979 @@
+/*
+ * Copyright (c) 2013-2015, NVIDIA CORPORATION.  All rights reserved.
+ * Copyright 2014 Google Inc.
+ *
+ * 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/>.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ */
+
+/**
+ * Defines the SDRAM parameter structure.
+ *
+ * Note that PLLM is used by EMC. The field names are in camel case to ease
+ * directly converting BCT config files (*.cfg) into C structure.
+ */
+
+#ifndef __SOC_NVIDIA_TEGRA210_SDRAM_PARAM_H__
+#define __SOC_NVIDIA_TEGRA210_SDRAM_PARAM_H__
+
+#include <stddef.h>
+#include <stdint.h>
+
+enum {
+	/* Specifies the memory type to be undefined */
+	NvBootMemoryType_None = 0,
+
+	/* Specifies the memory type to be DDR SDRAM */
+	NvBootMemoryType_Ddr = 0,
+
+	/* Specifies the memory type to be LPDDR SDRAM */
+	NvBootMemoryType_LpDdr = 0,
+
+	/* Specifies the memory type to be DDR2 SDRAM */
+	NvBootMemoryType_Ddr2 = 0,
+
+	/* Specifies the memory type to be LPDDR2 SDRAM */
+	NvBootMemoryType_LpDdr2,
+
+	/* Specifies the memory type to be DDR3 SDRAM */
+	NvBootMemoryType_Ddr3,
+
+	/* Specifies the memory type to be LPDDR4 SDRAM */
+	NvBootMemoryType_LpDdr4,
+
+	NvBootMemoryType_Num,
+
+	/* Specifies an entry in the ram_code table that's not in use */
+	NvBootMemoryType_Unused = 0X7FFFFFF,
+};
+
+enum {
+	BOOT_ROM_PATCH_CONTROL_ENABLE_MASK = 0x1 << 31,
+	BOOT_ROM_PATCH_CONTROL_OFFSET_SHIFT = 0,
+	BOOT_ROM_PATCH_CONTROL_OFFSET_MASK = 0x7FFFFFFF << 0,
+	BOOT_ROM_PATCH_CONTROL_BASE_ADDRESS = 0x70000000,
+
+	EMC_ZCAL_WARM_COLD_BOOT_ENABLES_COLDBOOT_MASK = 1 << 0,
+};
+
+/**
+ * Defines the SDRAM parameter structure
+ */
+struct sdram_params {
+
+	/* Specifies the type of memory device */
+	uint32_t MemoryType;
+
+	/* MC/EMC clock source configuration */
+
+	/* Specifies the M value for PllM */
+	uint32_t PllMInputDivider;
+	/* Specifies the N value for PllM */
+	uint32_t PllMFeedbackDivider;
+	/* Specifies the time to wait for PLLM to lock (in microseconds) */
+	uint32_t PllMStableTime;
+	/* Specifies misc. control bits */
+	uint32_t PllMSetupControl;
+	/* Specifies the P value for PLLM */
+	uint32_t PllMPostDivider;
+	/* Specifies value for Charge Pump Gain Control */
+	uint32_t PllMKCP;
+	/* Specifies VCO gain */
+	uint32_t PllMKVCO;
+	/* Spare BCT param */
+	uint32_t EmcBctSpare0;
+	/* Spare BCT param */
+	uint32_t EmcBctSpare1;
+	/* Spare BCT param */
+	uint32_t EmcBctSpare2;
+	/* Spare BCT param */
+	uint32_t EmcBctSpare3;
+	/* Spare BCT param */
+	uint32_t EmcBctSpare4;
+	/* Spare BCT param */
+	uint32_t EmcBctSpare5;
+	/* Spare BCT param */
+	uint32_t EmcBctSpare6;
+	/* Spare BCT param */
+	uint32_t EmcBctSpare7;
+	/* Spare BCT param */
+	uint32_t EmcBctSpare8;
+	/* Spare BCT param */
+	uint32_t EmcBctSpare9;
+	/* Spare BCT param */
+	uint32_t EmcBctSpare10;
+	/* Spare BCT param */
+	uint32_t EmcBctSpare11;
+	/* Spare BCT param */
+	uint32_t EmcBctSpare12;
+	/* Spare BCT param */
+	uint32_t EmcBctSpare13;
+
+	/* Defines EMC_2X_CLK_SRC, EMC_2X_CLK_DIVISOR, EMC_INVERT_DCD */
+	uint32_t EmcClockSource;
+	uint32_t EmcClockSourceDll;
+
+	/* Defines possible override for PLLLM_MISC2 */
+	uint32_t ClkRstControllerPllmMisc2Override;
+	/* enables override for PLLLM_MISC2 */
+	uint32_t ClkRstControllerPllmMisc2OverrideEnable;
+	/* defines CLK_ENB_MC1 in register clk_rst_controller_clk_enb_w_clr */
+	uint32_t ClearClk2Mc1;
+
+	/* Auto-calibration of EMC pads */
+
+	/* Specifies the value for EMC_AUTO_CAL_INTERVAL */
+	uint32_t EmcAutoCalInterval;
+	/*
+	 * Specifies the value for EMC_AUTO_CAL_CONFIG
+	 * Note: Trigger bits are set by the SDRAM code.
+	 */
+	uint32_t EmcAutoCalConfig;
+
+	/* Specifies the value for EMC_AUTO_CAL_CONFIG2 */
+	uint32_t EmcAutoCalConfig2;
+
+	/* Specifies the value for EMC_AUTO_CAL_CONFIG3 */
+	uint32_t EmcAutoCalConfig3;
+
+	/* Specifies the values for EMC_AUTO_CAL_CONFIG4-8 */
+	uint32_t EmcAutoCalConfig4;
+	uint32_t EmcAutoCalConfig5;
+	uint32_t EmcAutoCalConfig6;
+	uint32_t EmcAutoCalConfig7;
+	uint32_t EmcAutoCalConfig8;
+
+	/* Specifies the value for EMC_AUTO_CAL_VREF_SEL_0 */
+	uint32_t EmcAutoCalVrefSel0;
+	uint32_t EmcAutoCalVrefSel1;
+
+	/* Specifies the value for EMC_AUTO_CAL_CHANNEL */
+	uint32_t EmcAutoCalChannel;
+
+	/* Specifies the value for EMC_PMACRO_AUTOCAL_CFG_0 */
+	uint32_t EmcPmacroAutocalCfg0;
+	uint32_t EmcPmacroAutocalCfg1;
+	uint32_t EmcPmacroAutocalCfg2;
+	uint32_t EmcPmacroRxTerm;
+	uint32_t EmcPmacroDqTxDrv;
+	uint32_t EmcPmacroCaTxDrv;
+	uint32_t EmcPmacroCmdTxDrv;
+	uint32_t EmcPmacroAutocalCfgCommon;
+	uint32_t EmcPmacroZctrl;
+
+	/*
+	 * Specifies the time for the calibration
+	 * to stabilize (in microseconds)
+	 */
+	uint32_t EmcAutoCalWait;
+
+	uint32_t EmcXm2CompPadCtrl;
+	uint32_t EmcXm2CompPadCtrl2;
+	uint32_t EmcXm2CompPadCtrl3;
+
+	/*
+	 * DRAM size information
+	 * Specifies the value for EMC_ADR_CFG
+	 */
+	uint32_t EmcAdrCfg;
+
+	/*
+	 * Specifies the time to wait after asserting pin
+	 * CKE (in microseconds)
+	 */
+	uint32_t EmcPinProgramWait;
+	/* Specifies the extra delay before/after pin RESET/CKE command */
+	uint32_t EmcPinExtraWait;
+
+	uint32_t EmcPinGpioEn;
+	uint32_t EmcPinGpio;
+
+	/*
+	 * Specifies the extra delay after the first writing
+	 * of EMC_TIMING_CONTROL
+	 */
+	uint32_t EmcTimingControlWait;
+
+	/* Timing parameters required for the SDRAM */
+
+	/* Specifies the value for EMC_RC */
+	uint32_t EmcRc;
+	/* Specifies the value for EMC_RFC */
+	uint32_t EmcRfc;
+	/* Specifies the value for EMC_RFC_PB */
+	uint32_t EmcRfcPb;
+	/* Specifies the value for EMC_RFC_CTRL2 */
+	uint32_t EmcRefctrl2;
+	/* Specifies the value for EMC_RFC_SLR */
+	uint32_t EmcRfcSlr;
+	/* Specifies the value for EMC_RAS */
+	uint32_t EmcRas;
+	/* Specifies the value for EMC_RP */
+	uint32_t EmcRp;
+	/* Specifies the value for EMC_R2R */
+	uint32_t EmcR2r;
+	/* Specifies the value for EMC_W2W */
+	uint32_t EmcW2w;
+	/* Specifies the value for EMC_R2W */
+	uint32_t EmcR2w;
+	/* Specifies the value for EMC_W2R */
+	uint32_t EmcW2r;
+	/* Specifies the value for EMC_R2P */
+	uint32_t EmcR2p;
+	/* Specifies the value for EMC_W2P */
+	uint32_t EmcW2p;
+
+	uint32_t EmcTppd;
+	uint32_t EmcCcdmw;
+
+	/* Specifies the value for EMC_RD_RCD */
+	uint32_t EmcRdRcd;
+	/* Specifies the value for EMC_WR_RCD */
+	uint32_t EmcWrRcd;
+	/* Specifies the value for EMC_RRD */
+	uint32_t EmcRrd;
+	/* Specifies the value for EMC_REXT */
+	uint32_t EmcRext;
+	/* Specifies the value for EMC_WEXT */
+	uint32_t EmcWext;
+	/* Specifies the value for EMC_WDV */
+	uint32_t EmcWdv;
+
+	uint32_t EmcWdvChk;
+	uint32_t EmcWsv;
+	uint32_t EmcWev;
+
+	/* Specifies the value for EMC_WDV_MASK */
+	uint32_t EmcWdvMask;
+
+	uint32_t EmcWsDuration;
+	uint32_t EmcWeDuration;
+
+	/* Specifies the value for EMC_QUSE */
+	uint32_t EmcQUse;
+	/* Specifies the value for EMC_QUSE_WIDTH */
+	uint32_t EmcQuseWidth;
+	/* Specifies the value for EMC_IBDLY */
+	uint32_t EmcIbdly;
+	/* Specifies the value for EMC_OBDLY */
+	uint32_t EmcObdly;
+	/* Specifies the value for EMC_EINPUT */
+	uint32_t EmcEInput;
+	/* Specifies the value for EMC_EINPUT_DURATION */
+	uint32_t EmcEInputDuration;
+	/* Specifies the value for EMC_PUTERM_EXTRA */
+	uint32_t EmcPutermExtra;
+	/* Specifies the value for EMC_PUTERM_WIDTH */
+	uint32_t EmcPutermWidth;
+	/* Specifies the value for EMC_PUTERM_ADJ */
+	uint32_t EmcPutermAdj;
+
+	/* Specifies the value for EMC_QRST */
+	uint32_t EmcQRst;
+	/* Specifies the value for EMC_QSAFE */
+	uint32_t EmcQSafe;
+	/* Specifies the value for EMC_RDV */
+	uint32_t EmcRdv;
+	/* Specifies the value for EMC_RDV_MASK */
+	uint32_t EmcRdvMask;
+	/* Specifies the value for EMC_RDV_EARLY */
+	uint32_t EmcRdvEarly;
+	/* Specifies the value for EMC_RDV_EARLY_MASK */
+	uint32_t EmcRdvEarlyMask;
+	/* Specifies the value for EMC_QPOP */
+	uint32_t EmcQpop;
+
+	/* Specifies the value for EMC_REFRESH */
+	uint32_t EmcRefresh;
+	/* Specifies the value for EMC_BURST_REFRESH_NUM */
+	uint32_t EmcBurstRefreshNum;
+	/* Specifies the value for EMC_PRE_REFRESH_REQ_CNT */
+	uint32_t EmcPreRefreshReqCnt;
+	/* Specifies the value for EMC_PDEX2WR */
+	uint32_t EmcPdEx2Wr;
+	/* Specifies the value for EMC_PDEX2RD */
+	uint32_t EmcPdEx2Rd;
+	/* Specifies the value for EMC_PCHG2PDEN */
+	uint32_t EmcPChg2Pden;
+	/* Specifies the value for EMC_ACT2PDEN */
+	uint32_t EmcAct2Pden;
+	/* Specifies the value for EMC_AR2PDEN */
+	uint32_t EmcAr2Pden;
+	/* Specifies the value for EMC_RW2PDEN */
+	uint32_t EmcRw2Pden;
+	/* Specifies the value for EMC_CKE2PDEN */
+	uint32_t EmcCke2Pden;
+	/* Specifies the value for EMC_PDEX2CKE */
+	uint32_t EmcPdex2Cke;
+	/* Specifies the value for EMC_PDEX2MRR */
+	uint32_t EmcPdex2Mrr;
+	/* Specifies the value for EMC_TXSR */
+	uint32_t EmcTxsr;
+	/* Specifies the value for EMC_TXSRDLL */
+	uint32_t EmcTxsrDll;
+	/* Specifies the value for EMC_TCKE */
+	uint32_t EmcTcke;
+	/* Specifies the value for EMC_TCKESR */
+	uint32_t EmcTckesr;
+	/* Specifies the value for EMC_TPD */
+	uint32_t EmcTpd;
+	/* Specifies the value for EMC_TFAW */
+	uint32_t EmcTfaw;
+	/* Specifies the value for EMC_TRPAB */
+	uint32_t EmcTrpab;
+	/* Specifies the value for EMC_TCLKSTABLE */
+	uint32_t EmcTClkStable;
+	/* Specifies the value for EMC_TCLKSTOP */
+	uint32_t EmcTClkStop;
+	/* Specifies the value for EMC_TREFBW */
+	uint32_t EmcTRefBw;
+
+	/* FBIO configuration values */
+
+	/* Specifies the value for EMC_FBIO_CFG5 */
+	uint32_t EmcFbioCfg5;
+	/* Specifies the value for EMC_FBIO_CFG7 */
+	uint32_t EmcFbioCfg7;
+	/* Specifies the value for EMC_FBIO_CFG8 */
+	uint32_t EmcFbioCfg8;
+
+	/* Command mapping for CMD brick 0 */
+	uint32_t EmcCmdMappingCmd0_0;
+	uint32_t EmcCmdMappingCmd0_1;
+	uint32_t EmcCmdMappingCmd0_2;
+	uint32_t EmcCmdMappingCmd1_0;
+	uint32_t EmcCmdMappingCmd1_1;
+	uint32_t EmcCmdMappingCmd1_2;
+	uint32_t EmcCmdMappingCmd2_0;
+	uint32_t EmcCmdMappingCmd2_1;
+	uint32_t EmcCmdMappingCmd2_2;
+	uint32_t EmcCmdMappingCmd3_0;
+	uint32_t EmcCmdMappingCmd3_1;
+	uint32_t EmcCmdMappingCmd3_2;
+	uint32_t EmcCmdMappingByte;
+
+	/* Specifies the value for EMC_FBIO_SPARE */
+	uint32_t EmcFbioSpare;
+
+	/* Specifies the value for EMC_CFG_RSV */
+	uint32_t EmcCfgRsv;
+
+	/* MRS command values */
+
+	/* Specifies the value for EMC_MRS */
+	uint32_t EmcMrs;
+	/* Specifies the MP0 command to initialize mode registers */
+	uint32_t EmcEmrs;
+	/* Specifies the MP2 command to initialize mode registers */
+	uint32_t EmcEmrs2;
+	/* Specifies the MP3 command to initialize mode registers */
+	uint32_t EmcEmrs3;
+	/* Specifies the programming to LPDDR2 Mode Register 1 at cold boot */
+	uint32_t EmcMrw1;
+	/* Specifies the programming to LPDDR2 Mode Register 2 at cold boot */
+	uint32_t EmcMrw2;
+	/* Specifies the programming to LPDDR2 Mode Register 3 at cold boot */
+	uint32_t EmcMrw3;
+	/* Specifies the programming to LPDDR2 Mode Register 11 at cold boot */
+	uint32_t EmcMrw4;
+	/* Specifies the programming to LPDDR2 Mode Register 3? at cold boot */
+	uint32_t EmcMrw6;
+	/* Specifies the programming to LPDDR2 Mode Register 11 at cold boot */
+	uint32_t EmcMrw8;
+	/* Specifies the programming to LPDDR2 Mode Register 11? at cold boot */
+	uint32_t EmcMrw9;
+	/* Specifies the programming to LPDDR2 Mode Register 12 at cold boot */
+	uint32_t EmcMrw10;
+	/* Specifies the programming to LPDDR2 Mode Register 14 at cold boot */
+	uint32_t EmcMrw12;
+	/* Specifies the programming to LPDDR2 Mode Register 14? at cold boot */
+	uint32_t EmcMrw13;
+	/* Specifies the programming to LPDDR2 Mode Register 22 at cold boot */
+	uint32_t EmcMrw14;
+	/*
+	 * Specifies the programming to extra LPDDR2 Mode Register
+	 * at cold boot
+	 */
+	uint32_t EmcMrwExtra;
+	/*
+	 * Specifies the programming to extra LPDDR2 Mode Register
+	 * at warm boot
+	 */
+	uint32_t EmcWarmBootMrwExtra;
+	/*
+	 * Specify the enable of extra Mode Register programming at
+	 * warm boot
+	 */
+	uint32_t EmcWarmBootExtraModeRegWriteEnable;
+	/*
+	 * Specify the enable of extra Mode Register programming at
+	 * cold boot
+	 */
+	uint32_t EmcExtraModeRegWriteEnable;
+
+	/* Specifies the EMC_MRW reset command value */
+	uint32_t EmcMrwResetCommand;
+	/* Specifies the EMC Reset wait time (in microseconds) */
+	uint32_t EmcMrwResetNInitWait;
+	/* Specifies the value for EMC_MRS_WAIT_CNT */
+	uint32_t EmcMrsWaitCnt;
+	/* Specifies the value for EMC_MRS_WAIT_CNT2 */
+	uint32_t EmcMrsWaitCnt2;
+
+	/* EMC miscellaneous configurations */
+
+	/* Specifies the value for EMC_CFG */
+	uint32_t EmcCfg;
+	/* Specifies the value for EMC_CFG_2 */
+	uint32_t EmcCfg2;
+	/* Specifies the pipe bypass controls */
+	uint32_t EmcCfgPipe;
+	uint32_t EmcCfgPipeClk;
+	uint32_t EmcFdpdCtrlCmdNoRamp;
+	uint32_t EmcCfgUpdate;
+
+	/* Specifies the value for EMC_DBG */
+	uint32_t EmcDbg;
+	uint32_t EmcDbgWriteMux;
+
+	/* Specifies the value for EMC_CMDQ */
+	uint32_t EmcCmdQ;
+	/* Specifies the value for EMC_MC2EMCQ */
+	uint32_t EmcMc2EmcQ;
+	/* Specifies the value for EMC_DYN_SELF_REF_CONTROL */
+	uint32_t EmcDynSelfRefControl;
+
+	/* Specifies the value for MEM_INIT_DONE */
+	uint32_t AhbArbitrationXbarCtrlMemInitDone;
+
+	/* Specifies the value for EMC_CFG_DIG_DLL */
+	uint32_t EmcCfgDigDll;
+	uint32_t EmcCfgDigDll_1;
+	/* Specifies the value for EMC_CFG_DIG_DLL_PERIOD */
+	uint32_t EmcCfgDigDllPeriod;
+	/* Specifies the value of *DEV_SELECTN of various EMC registers */
+	uint32_t EmcDevSelect;
+
+	/* Specifies the value for EMC_SEL_DPD_CTRL */
+	uint32_t EmcSelDpdCtrl;
+
+	/* Pads trimmer delays */
+	uint32_t EmcFdpdCtrlDq;
+	uint32_t EmcFdpdCtrlCmd;
+	uint32_t EmcPmacroIbVrefDq_0;
+	uint32_t EmcPmacroIbVrefDq_1;
+	uint32_t EmcPmacroIbVrefDqs_0;
+	uint32_t EmcPmacroIbVrefDqs_1;
+	uint32_t EmcPmacroIbRxrt;
+	uint32_t EmcCfgPipe1;
+	uint32_t EmcCfgPipe2;
+
+	/* Specifies the value for EMC_PMACRO_QUSE_DDLL_RANK0_0 */
+	uint32_t EmcPmacroQuseDdllRank0_0;
+	uint32_t EmcPmacroQuseDdllRank0_1;
+	uint32_t EmcPmacroQuseDdllRank0_2;
+	uint32_t EmcPmacroQuseDdllRank0_3;
+	uint32_t EmcPmacroQuseDdllRank0_4;
+	uint32_t EmcPmacroQuseDdllRank0_5;
+	uint32_t EmcPmacroQuseDdllRank1_0;
+	uint32_t EmcPmacroQuseDdllRank1_1;
+	uint32_t EmcPmacroQuseDdllRank1_2;
+	uint32_t EmcPmacroQuseDdllRank1_3;
+	uint32_t EmcPmacroQuseDdllRank1_4;
+	uint32_t EmcPmacroQuseDdllRank1_5;
+
+	uint32_t EmcPmacroObDdllLongDqRank0_0;
+	uint32_t EmcPmacroObDdllLongDqRank0_1;
+	uint32_t EmcPmacroObDdllLongDqRank0_2;
+	uint32_t EmcPmacroObDdllLongDqRank0_3;
+	uint32_t EmcPmacroObDdllLongDqRank0_4;
+	uint32_t EmcPmacroObDdllLongDqRank0_5;
+	uint32_t EmcPmacroObDdllLongDqRank1_0;
+	uint32_t EmcPmacroObDdllLongDqRank1_1;
+	uint32_t EmcPmacroObDdllLongDqRank1_2;
+	uint32_t EmcPmacroObDdllLongDqRank1_3;
+	uint32_t EmcPmacroObDdllLongDqRank1_4;
+	uint32_t EmcPmacroObDdllLongDqRank1_5;
+
+	uint32_t EmcPmacroObDdllLongDqsRank0_0;
+	uint32_t EmcPmacroObDdllLongDqsRank0_1;
+	uint32_t EmcPmacroObDdllLongDqsRank0_2;
+	uint32_t EmcPmacroObDdllLongDqsRank0_3;
+	uint32_t EmcPmacroObDdllLongDqsRank0_4;
+	uint32_t EmcPmacroObDdllLongDqsRank0_5;
+	uint32_t EmcPmacroObDdllLongDqsRank1_0;
+	uint32_t EmcPmacroObDdllLongDqsRank1_1;
+	uint32_t EmcPmacroObDdllLongDqsRank1_2;
+	uint32_t EmcPmacroObDdllLongDqsRank1_3;
+	uint32_t EmcPmacroObDdllLongDqsRank1_4;
+	uint32_t EmcPmacroObDdllLongDqsRank1_5;
+
+	uint32_t EmcPmacroIbDdllLongDqsRank0_0;
+	uint32_t EmcPmacroIbDdllLongDqsRank0_1;
+	uint32_t EmcPmacroIbDdllLongDqsRank0_2;
+	uint32_t EmcPmacroIbDdllLongDqsRank0_3;
+	uint32_t EmcPmacroIbDdllLongDqsRank1_0;
+	uint32_t EmcPmacroIbDdllLongDqsRank1_1;
+	uint32_t EmcPmacroIbDdllLongDqsRank1_2;
+	uint32_t EmcPmacroIbDdllLongDqsRank1_3;
+
+	uint32_t EmcPmacroDdllLongCmd_0;
+	uint32_t EmcPmacroDdllLongCmd_1;
+	uint32_t EmcPmacroDdllLongCmd_2;
+	uint32_t EmcPmacroDdllLongCmd_3;
+	uint32_t EmcPmacroDdllLongCmd_4;
+	uint32_t EmcPmacroDdllShortCmd_0;
+	uint32_t EmcPmacroDdllShortCmd_1;
+	uint32_t EmcPmacroDdllShortCmd_2;
+
+	/*
+	 * Specifies the delay after asserting CKE pin during a WarmBoot0
+	 * sequence (in microseconds)
+	 */
+	uint32_t WarmBootWait;
+
+	/* Specifies the value for EMC_ODT_WRITE */
+	uint32_t EmcOdtWrite;
+
+	/* Periodic ZQ calibration */
+
+	/*
+	 * Specifies the value for EMC_ZCAL_INTERVAL
+	 * Value 0 disables ZQ calibration
+	 */
+	uint32_t EmcZcalInterval;
+	/* Specifies the value for EMC_ZCAL_WAIT_CNT */
+	uint32_t EmcZcalWaitCnt;
+	/* Specifies the value for EMC_ZCAL_MRW_CMD */
+	uint32_t EmcZcalMrwCmd;
+
+	/* DRAM initialization sequence flow control */
+
+	/* Specifies the MRS command value for resetting DLL */
+	uint32_t EmcMrsResetDll;
+	/* Specifies the command for ZQ initialization of device 0 */
+	uint32_t EmcZcalInitDev0;
+	/* Specifies the command for ZQ initialization of device 1 */
+	uint32_t EmcZcalInitDev1;
+	/*
+	 * Specifies the wait time after programming a ZQ initialization
+	 * command (in microseconds)
+	 */
+	uint32_t EmcZcalInitWait;
+	/*
+	 * Specifies the enable for ZQ calibration at cold boot [bit 0]
+	 * and warm boot [bit 1]
+	 */
+	uint32_t EmcZcalWarmColdBootEnables;
+
+	/*
+	 * Specifies the MRW command to LPDDR2 for ZQ calibration
+	 * on warmboot
+	 */
+	/* Is issued to both devices separately */
+	uint32_t EmcMrwLpddr2ZcalWarmBoot;
+	/*
+	 * Specifies the ZQ command to DDR3 for ZQ calibration on warmboot
+	 * Is issued to both devices separately
+	 */
+	uint32_t EmcZqCalDdr3WarmBoot;
+	uint32_t EmcZqCalLpDdr4WarmBoot;
+	/*
+	 * Specifies the wait time for ZQ calibration on warmboot
+	 * (in microseconds)
+	 */
+	uint32_t EmcZcalWarmBootWait;
+	/*
+	 * Specifies the enable for DRAM Mode Register programming
+	 * at warm boot
+	 */
+	uint32_t EmcMrsWarmBootEnable;
+	/*
+	 * Specifies the wait time after sending an MRS DLL reset command
+	 * in microseconds)
+	 */
+	uint32_t EmcMrsResetDllWait;
+	/* Specifies the extra MRS command to initialize mode registers */
+	uint32_t EmcMrsExtra;
+	/* Specifies the extra MRS command at warm boot */
+	uint32_t EmcWarmBootMrsExtra;
+	/* Specifies the EMRS command to enable the DDR2 DLL */
+	uint32_t EmcEmrsDdr2DllEnable;
+	/* Specifies the MRS command to reset the DDR2 DLL */
+	uint32_t EmcMrsDdr2DllReset;
+	/* Specifies the EMRS command to set OCD calibration */
+	uint32_t EmcEmrsDdr2OcdCalib;
+	/*
+	 * Specifies the wait between initializing DDR and setting OCD
+	 * calibration (in microseconds)
+	 */
+	uint32_t EmcDdr2Wait;
+	/* Specifies the value for EMC_CLKEN_OVERRIDE */
+	uint32_t EmcClkenOverride;
+
+	/*
+	 * Specifies LOG2 of the extra refresh numbers after booting
+	 * Program 0 to disable
+	 */
+	uint32_t EmcExtraRefreshNum;
+	/* Specifies the master override for all EMC clocks */
+	uint32_t EmcClkenOverrideAllWarmBoot;
+	/* Specifies the master override for all MC clocks */
+	uint32_t McClkenOverrideAllWarmBoot;
+	/* Specifies digital dll period, choosing between 4 to 64 ms */
+	uint32_t EmcCfgDigDllPeriodWarmBoot;
+
+	/* Pad controls */
+
+	/* Specifies the value for PMC_VDDP_SEL */
+	uint32_t PmcVddpSel;
+	/* Specifies the wait time after programming PMC_VDDP_SEL */
+	uint32_t PmcVddpSelWait;
+	/* Specifies the value for PMC_DDR_PWR */
+	uint32_t PmcDdrPwr;
+	/* Specifies the value for PMC_DDR_CFG */
+	uint32_t PmcDdrCfg;
+	/* Specifies the value for PMC_IO_DPD3_REQ */
+	uint32_t PmcIoDpd3Req;
+	/* Specifies the wait time after programming PMC_IO_DPD3_REQ */
+	uint32_t PmcIoDpd3ReqWait;
+	uint32_t PmcIoDpd4ReqWait;
+
+	/* Specifies the value for PMC_REG_SHORT */
+	uint32_t PmcRegShort;
+	/* Specifies the value for PMC_NO_IOPOWER */
+	uint32_t PmcNoIoPower;
+
+	uint32_t PmcDdrCntrlWait;
+	uint32_t PmcDdrCntrl;
+
+	/* Specifies the value for EMC_ACPD_CONTROL */
+	uint32_t EmcAcpdControl;
+
+	/* Specifies the value for EMC_SWIZZLE_RANK0_BYTE_CFG */
+	uint32_t EmcSwizzleRank0ByteCfg;
+	/* Specifies the value for EMC_SWIZZLE_RANK0_BYTE0 */
+	uint32_t EmcSwizzleRank0Byte0;
+	/* Specifies the value for EMC_SWIZZLE_RANK0_BYTE1 */
+	uint32_t EmcSwizzleRank0Byte1;
+	/* Specifies the value for EMC_SWIZZLE_RANK0_BYTE2 */
+	uint32_t EmcSwizzleRank0Byte2;
+	/* Specifies the value for EMC_SWIZZLE_RANK0_BYTE3 */
+	uint32_t EmcSwizzleRank0Byte3;
+	/* Specifies the value for EMC_SWIZZLE_RANK1_BYTE_CFG */
+	uint32_t EmcSwizzleRank1ByteCfg;
+	/* Specifies the value for EMC_SWIZZLE_RANK1_BYTE0 */
+	uint32_t EmcSwizzleRank1Byte0;
+	/* Specifies the value for EMC_SWIZZLE_RANK1_BYTE1 */
+	uint32_t EmcSwizzleRank1Byte1;
+	/* Specifies the value for EMC_SWIZZLE_RANK1_BYTE2 */
+	uint32_t EmcSwizzleRank1Byte2;
+	/* Specifies the value for EMC_SWIZZLE_RANK1_BYTE3 */
+	uint32_t EmcSwizzleRank1Byte3;
+
+	/* Specifies the value for EMC_TXDSRVTTGEN */
+	uint32_t EmcTxdsrvttgen;
+
+	/* Specifies the value for EMC_DATA_BRLSHFT_0 */
+	uint32_t EmcDataBrlshft0;
+	uint32_t EmcDataBrlshft1;
+
+	uint32_t EmcDqsBrlshft0;
+	uint32_t EmcDqsBrlshft1;
+
+	uint32_t EmcCmdBrlshft0;
+	uint32_t EmcCmdBrlshft1;
+	uint32_t EmcCmdBrlshft2;
+	uint32_t EmcCmdBrlshft3;
+
+	uint32_t EmcQuseBrlshft0;
+	uint32_t EmcQuseBrlshft1;
+	uint32_t EmcQuseBrlshft2;
+	uint32_t EmcQuseBrlshft3;
+
+	uint32_t EmcDllCfg0;
+	uint32_t EmcDllCfg1;
+
+	uint32_t EmcPmcScratch1;
+	uint32_t EmcPmcScratch2;
+	uint32_t EmcPmcScratch3;
+
+	uint32_t EmcPmacroPadCfgCtrl;
+
+	uint32_t EmcPmacroVttgenCtrl0;
+	uint32_t EmcPmacroVttgenCtrl1;
+	uint32_t EmcPmacroVttgenCtrl2;
+
+	uint32_t EmcPmacroBrickCtrlRfu1;
+	uint32_t EmcPmacroCmdBrickCtrlFdpd;
+	uint32_t EmcPmacroBrickCtrlRfu2;
+	uint32_t EmcPmacroDataBrickCtrlFdpd;
+	uint32_t EmcPmacroBgBiasCtrl0;
+	uint32_t EmcPmacroDataPadRxCtrl;
+	uint32_t EmcPmacroCmdPadRxCtrl;
+	uint32_t EmcPmacroDataRxTermMode;
+	uint32_t EmcPmacroCmdRxTermMode;
+	uint32_t EmcPmacroDataPadTxCtrl;
+	uint32_t EmcPmacroCommonPadTxCtrl;
+	uint32_t EmcPmacroCmdPadTxCtrl;
+	uint32_t EmcCfg3;
+
+	uint32_t EmcPmacroTxPwrd0;
+	uint32_t EmcPmacroTxPwrd1;
+	uint32_t EmcPmacroTxPwrd2;
+	uint32_t EmcPmacroTxPwrd3;
+	uint32_t EmcPmacroTxPwrd4;
+	uint32_t EmcPmacroTxPwrd5;
+
+	uint32_t EmcConfigSampleDelay;
+
+	uint32_t EmcPmacroBrickMapping0;
+	uint32_t EmcPmacroBrickMapping1;
+	uint32_t EmcPmacroBrickMapping2;
+
+	uint32_t EmcPmacroTxSelClkSrc0;
+	uint32_t EmcPmacroTxSelClkSrc1;
+	uint32_t EmcPmacroTxSelClkSrc2;
+	uint32_t EmcPmacroTxSelClkSrc3;
+	uint32_t EmcPmacroTxSelClkSrc4;
+	uint32_t EmcPmacroTxSelClkSrc5;
+
+	uint32_t EmcPmacroDdllBypass;
+
+	uint32_t EmcPmacroDdllPwrd0;
+	uint32_t EmcPmacroDdllPwrd1;
+	uint32_t EmcPmacroDdllPwrd2;
+
+	uint32_t EmcPmacroCmdCtrl0;
+	uint32_t EmcPmacroCmdCtrl1;
+	uint32_t EmcPmacroCmdCtrl2;
+
+	/* DRAM size information */
+
+	/* Specifies the value for MC_EMEM_ADR_CFG */
+	uint32_t McEmemAdrCfg;
+	/* Specifies the value for MC_EMEM_ADR_CFG_DEV0 */
+	uint32_t McEmemAdrCfgDev0;
+	/* Specifies the value for MC_EMEM_ADR_CFG_DEV1 */
+	uint32_t McEmemAdrCfgDev1;
+	uint32_t McEmemAdrCfgChannelMask;
+
+	/* Specifies the value for MC_EMEM_BANK_SWIZZLECfg0 */
+	uint32_t McEmemAdrCfgBankMask0;
+	/* Specifies the value for MC_EMEM_BANK_SWIZZLE_CFG1 */
+	uint32_t McEmemAdrCfgBankMask1;
+	/* Specifies the value for MC_EMEM_BANK_SWIZZLE_CFG2 */
+	uint32_t McEmemAdrCfgBankMask2;
+
+	/*
+	 * Specifies the value for MC_EMEM_CFG which holds the external memory
+	 * size (in KBytes)
+	 */
+	uint32_t McEmemCfg;
+
+	/* MC arbitration configuration */
+
+	/* Specifies the value for MC_EMEM_ARB_CFG */
+	uint32_t McEmemArbCfg;
+	/* Specifies the value for MC_EMEM_ARB_OUTSTANDING_REQ */
+	uint32_t McEmemArbOutstandingReq;
+
+	uint32_t McEmemArbRefpbHpCtrl;
+	uint32_t McEmemArbRefpbBankCtrl;
+
+	/* Specifies the value for MC_EMEM_ARB_TIMING_RCD */
+	uint32_t McEmemArbTimingRcd;
+	/* Specifies the value for MC_EMEM_ARB_TIMING_RP */
+	uint32_t McEmemArbTimingRp;
+	/* Specifies the value for MC_EMEM_ARB_TIMING_RC */
+	uint32_t McEmemArbTimingRc;
+	/* Specifies the value for MC_EMEM_ARB_TIMING_RAS */
+	uint32_t McEmemArbTimingRas;
+	/* Specifies the value for MC_EMEM_ARB_TIMING_FAW */
+	uint32_t McEmemArbTimingFaw;
+	/* Specifies the value for MC_EMEM_ARB_TIMING_RRD */
+	uint32_t McEmemArbTimingRrd;
+	/* Specifies the value for MC_EMEM_ARB_TIMING_RAP2PRE */
+	uint32_t McEmemArbTimingRap2Pre;
+	/* Specifies the value for MC_EMEM_ARB_TIMING_WAP2PRE */
+	uint32_t McEmemArbTimingWap2Pre;
+	/* Specifies the value for MC_EMEM_ARB_TIMING_R2R */
+	uint32_t McEmemArbTimingR2R;
+	/* Specifies the value for MC_EMEM_ARB_TIMING_W2W */
+	uint32_t McEmemArbTimingW2W;
+	/* Specifies the value for MC_EMEM_ARB_TIMING_R2W */
+	uint32_t McEmemArbTimingR2W;
+	/* Specifies the value for MC_EMEM_ARB_TIMING_W2R */
+	uint32_t McEmemArbTimingW2R;
+
+	uint32_t McEmemArbTimingRFCPB;
+
+	/* Specifies the value for MC_EMEM_ARB_DA_TURNS */
+	uint32_t McEmemArbDaTurns;
+	/* Specifies the value for MC_EMEM_ARB_DA_COVERS */
+	uint32_t McEmemArbDaCovers;
+	/* Specifies the value for MC_EMEM_ARB_MISC0 */
+	uint32_t McEmemArbMisc0;
+	/* Specifies the value for MC_EMEM_ARB_MISC1 */
+	uint32_t McEmemArbMisc1;
+	uint32_t McEmemArbMisc2;
+
+	/* Specifies the value for MC_EMEM_ARB_RING1_THROTTLE */
+	uint32_t McEmemArbRing1Throttle;
+	/* Specifies the value for MC_EMEM_ARB_OVERRIDE */
+	uint32_t McEmemArbOverride;
+	/* Specifies the value for MC_EMEM_ARB_OVERRIDE_1 */
+	uint32_t McEmemArbOverride1;
+	/* Specifies the value for MC_EMEM_ARB_RSV */
+	uint32_t McEmemArbRsv;
+
+	uint32_t McDaCfg0;
+	uint32_t McEmemArbTimingCcdmw;
+
+	/* Specifies the value for MC_CLKEN_OVERRIDE */
+	uint32_t McClkenOverride;
+
+	/* Specifies the value for MC_STAT_CONTROL */
+	uint32_t McStatControl;
+
+	/* Specifies the value for MC_VIDEO_PROTECT_BOM */
+	uint32_t McVideoProtectBom;
+	/* Specifies the value for MC_VIDEO_PROTECT_BOM_ADR_HI */
+	uint32_t McVideoProtectBomAdrHi;
+	/* Specifies the value for MC_VIDEO_PROTECT_SIZE_MB */
+	uint32_t McVideoProtectSizeMb;
+	/* Specifies the value for MC_VIDEO_PROTECT_VPR_OVERRIDE */
+	uint32_t McVideoProtectVprOverride;
+	/* Specifies the value for MC_VIDEO_PROTECT_VPR_OVERRIDE1 */
+	uint32_t McVideoProtectVprOverride1;
+	/* Specifies the value for MC_VIDEO_PROTECT_GPU_OVERRIDE_0 */
+	uint32_t McVideoProtectGpuOverride0;
+	/* Specifies the value for MC_VIDEO_PROTECT_GPU_OVERRIDE_1 */
+	uint32_t McVideoProtectGpuOverride1;
+	/* Specifies the value for MC_SEC_CARVEOUT_BOM */
+	uint32_t McSecCarveoutBom;
+	/* Specifies the value for MC_SEC_CARVEOUT_ADR_HI */
+	uint32_t McSecCarveoutAdrHi;
+	/* Specifies the value for MC_SEC_CARVEOUT_SIZE_MB */
+	uint32_t McSecCarveoutSizeMb;
+	/* Specifies the value for MC_VIDEO_PROTECT_REG_CTRL.
+	   VIDEO_PROTECT_WRITEAccess */
+	uint32_t McVideoProtectWriteAccess;
+	/* Specifies the value for MC_SEC_CARVEOUT_REG_CTRL.
+	   SEC_CARVEOUT_WRITEAccess */
+	uint32_t McSecCarveoutProtectWriteAccess;
+
+	/* Write-Protect Regions (WPR) */
+	uint32_t McGeneralizedCarveout1Bom;
+	uint32_t McGeneralizedCarveout1BomHi;
+	uint32_t McGeneralizedCarveout1Size128kb;
+	uint32_t McGeneralizedCarveout1Access0;
+	uint32_t McGeneralizedCarveout1Access1;
+	uint32_t McGeneralizedCarveout1Access2;
+	uint32_t McGeneralizedCarveout1Access3;
+	uint32_t McGeneralizedCarveout1Access4;
+	uint32_t McGeneralizedCarveout1ForceInternalAccess0;
+	uint32_t McGeneralizedCarveout1ForceInternalAccess1;
+	uint32_t McGeneralizedCarveout1ForceInternalAccess2;
+	uint32_t McGeneralizedCarveout1ForceInternalAccess3;
+	uint32_t McGeneralizedCarveout1ForceInternalAccess4;
+	uint32_t McGeneralizedCarveout1Cfg0;
+
+	uint32_t McGeneralizedCarveout2Bom;
+	uint32_t McGeneralizedCarveout2BomHi;
+	uint32_t McGeneralizedCarveout2Size128kb;
+	uint32_t McGeneralizedCarveout2Access0;
+	uint32_t McGeneralizedCarveout2Access1;
+	uint32_t McGeneralizedCarveout2Access2;
+	uint32_t McGeneralizedCarveout2Access3;
+	uint32_t McGeneralizedCarveout2Access4;
+	uint32_t McGeneralizedCarveout2ForceInternalAccess0;
+	uint32_t McGeneralizedCarveout2ForceInternalAccess1;
+	uint32_t McGeneralizedCarveout2ForceInternalAccess2;
+	uint32_t McGeneralizedCarveout2ForceInternalAccess3;
+	uint32_t McGeneralizedCarveout2ForceInternalAccess4;
+	uint32_t McGeneralizedCarveout2Cfg0;
+
+	uint32_t McGeneralizedCarveout3Bom;
+	uint32_t McGeneralizedCarveout3BomHi;
+	uint32_t McGeneralizedCarveout3Size128kb;
+	uint32_t McGeneralizedCarveout3Access0;
+	uint32_t McGeneralizedCarveout3Access1;
+	uint32_t McGeneralizedCarveout3Access2;
+	uint32_t McGeneralizedCarveout3Access3;
+	uint32_t McGeneralizedCarveout3Access4;
+	uint32_t McGeneralizedCarveout3ForceInternalAccess0;
+	uint32_t McGeneralizedCarveout3ForceInternalAccess1;
+	uint32_t McGeneralizedCarveout3ForceInternalAccess2;
+	uint32_t McGeneralizedCarveout3ForceInternalAccess3;
+	uint32_t McGeneralizedCarveout3ForceInternalAccess4;
+	uint32_t McGeneralizedCarveout3Cfg0;
+
+	uint32_t McGeneralizedCarveout4Bom;
+	uint32_t McGeneralizedCarveout4BomHi;
+	uint32_t McGeneralizedCarveout4Size128kb;
+	uint32_t McGeneralizedCarveout4Access0;
+	uint32_t McGeneralizedCarveout4Access1;
+	uint32_t McGeneralizedCarveout4Access2;
+	uint32_t McGeneralizedCarveout4Access3;
+	uint32_t McGeneralizedCarveout4Access4;
+	uint32_t McGeneralizedCarveout4ForceInternalAccess0;
+	uint32_t McGeneralizedCarveout4ForceInternalAccess1;
+	uint32_t McGeneralizedCarveout4ForceInternalAccess2;
+	uint32_t McGeneralizedCarveout4ForceInternalAccess3;
+	uint32_t McGeneralizedCarveout4ForceInternalAccess4;
+	uint32_t McGeneralizedCarveout4Cfg0;
+
+	uint32_t McGeneralizedCarveout5Bom;
+	uint32_t McGeneralizedCarveout5BomHi;
+	uint32_t McGeneralizedCarveout5Size128kb;
+	uint32_t McGeneralizedCarveout5Access0;
+	uint32_t McGeneralizedCarveout5Access1;
+	uint32_t McGeneralizedCarveout5Access2;
+	uint32_t McGeneralizedCarveout5Access3;
+	uint32_t McGeneralizedCarveout5Access4;
+	uint32_t McGeneralizedCarveout5ForceInternalAccess0;
+	uint32_t McGeneralizedCarveout5ForceInternalAccess1;
+	uint32_t McGeneralizedCarveout5ForceInternalAccess2;
+	uint32_t McGeneralizedCarveout5ForceInternalAccess3;
+	uint32_t McGeneralizedCarveout5ForceInternalAccess4;
+	uint32_t McGeneralizedCarveout5Cfg0;
+
+	/* Specifies enable for CA training */
+	uint32_t EmcCaTrainingEnable;
+
+	/* Set if bit 6 select is greater than bit 7 select; uses aremc.
+	   spec packet SWIZZLE_BIT6_GT_BIT7 */
+	uint32_t SwizzleRankByteEncode;
+	/* Specifies enable and offset for patched boot rom write */
+	uint32_t BootRomPatchControl;
+	/* Specifies data for patched boot rom write */
+	uint32_t BootRomPatchData;
+
+	/* Specifies the value for MC_MTS_CARVEOUT_BOM */
+	uint32_t McMtsCarveoutBom;
+	/* Specifies the value for MC_MTS_CARVEOUT_ADR_HI */
+	uint32_t McMtsCarveoutAdrHi;
+	/* Specifies the value for MC_MTS_CARVEOUT_SIZE_MB */
+	uint32_t McMtsCarveoutSizeMb;
+	/* Specifies the value for MC_MTS_CARVEOUT_REG_CTRL */
+	uint32_t McMtsCarveoutRegCtrl;
+
+	/* End */
+};
+
+check_member(sdram_params, McMtsCarveoutRegCtrl, 0x770);
+
+#endif /* __SOC_NVIDIA_TEGRA210_SDRAM_PARAM_H__ */
diff --git a/src/soc/nvidia/tegra210/include/soc/secure_boot.h b/src/soc/nvidia/tegra210/include/soc/secure_boot.h
new file mode 100644
index 0000000..306eac7
--- /dev/null
+++ b/src/soc/nvidia/tegra210/include/soc/secure_boot.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2010-2015, NVIDIA CORPORATION.  All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _TEGRA210_SECURE_BOOT_H_
+#define _TEGRA210_SECURE_BOOT_H_
+
+struct tegra_secure_boot {
+	u32 sb_csr;		/* offset 0x00 */
+	u32 sb_pirom_start;	/* offset 0x04 */
+	u32 sb_pfcfg;		/* offset 0x08 */
+	u32 sb_secure_spare_0;	/* offset 0x0c */
+	u32 sb_secure_spare_1;	/* offset 0x10 */
+	u32 sb_secure_spare_2;	/* offset 0x14 */
+	u32 sb_secure_spare_3;	/* offset 0x18 */
+	u32 sb_secure_spare_4;	/* offset 0x1c */
+	u32 sb_secure_spare_5;	/* offset 0x20 */
+	u32 sb_secure_spare_6;	/* offset 0x24 */
+	u32 sb_secure_spare_7;	/* offset 0x28 */
+	u32 rsvd;		/* offset 0x2c */
+	u32 sb_aa64_reset_low;	/* offset 0x30 */
+	u32 sb_aa64_reset_high;	/* offset 0x3c */
+};
+
+#endif	/* _TEGRA210_SECURE_BOOT_H_ */
diff --git a/src/soc/nvidia/tegra210/include/soc/sor.h b/src/soc/nvidia/tegra210/include/soc/sor.h
new file mode 100644
index 0000000..5d1d663
--- /dev/null
+++ b/src/soc/nvidia/tegra210/include/soc/sor.h
@@ -0,0 +1,930 @@
+/*
+ * drivers/video/tegra/dc/sor_regs.h
+ *
+ * Copyright (c) 2011-2015, NVIDIA Corporation.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef __TEGRA210_SOR_H__
+#define __TEGRA210_SOR_H__
+
+#define NV_SOR_SUPER_STATE0					(0x1)
+#define NV_SOR_SUPER_STATE0_UPDATE_SHIFT			(0)
+#define NV_SOR_SUPER_STATE0_UPDATE_DEFAULT_MASK			(0x1)
+#define NV_SOR_SUPER_STATE1					(0x2)
+#define NV_SOR_SUPER_STATE1_ATTACHED_SHIFT			(3)
+#define NV_SOR_SUPER_STATE1_ATTACHED_NO				(0 << 3)
+#define NV_SOR_SUPER_STATE1_ATTACHED_YES			(1 << 3)
+#define NV_SOR_SUPER_STATE1_ASY_ORMODE_SHIFT			(2)
+#define NV_SOR_SUPER_STATE1_ASY_ORMODE_SAFE			(0 << 2)
+#define NV_SOR_SUPER_STATE1_ASY_ORMODE_NORMAL			(1 << 2)
+#define NV_SOR_SUPER_STATE1_ASY_HEAD_OP_SHIFT			(0)
+#define NV_SOR_SUPER_STATE1_ASY_HEAD_OP_DEFAULT_MASK		(0x3)
+#define NV_SOR_SUPER_STATE1_ASY_HEAD_OP_SLEEP			(0)
+#define NV_SOR_SUPER_STATE1_ASY_HEAD_OP_SNOOZE			(1)
+#define NV_SOR_SUPER_STATE1_ASY_HEAD_OP_AWAKE			(2)
+#define NV_SOR_STATE0						(0x3)
+#define NV_SOR_STATE0_UPDATE_SHIFT				(0)
+#define NV_SOR_STATE0_UPDATE_DEFAULT_MASK			(0x1)
+#define NV_SOR_STATE1						(0x4)
+#define NV_SOR_STATE1_ASY_PIXELDEPTH_SHIFT			(17)
+#define NV_SOR_STATE1_ASY_PIXELDEPTH_DEFAULT_MASK		(0xf << 17)
+#define NV_SOR_STATE1_ASY_PIXELDEPTH_BPP_16_422			(1 << 17)
+#define NV_SOR_STATE1_ASY_PIXELDEPTH_BPP_18_444			(2 << 17)
+#define NV_SOR_STATE1_ASY_PIXELDEPTH_BPP_20_422			(3 << 17)
+#define NV_SOR_STATE1_ASY_PIXELDEPTH_BPP_24_422			(4 << 17)
+#define NV_SOR_STATE1_ASY_PIXELDEPTH_BPP_24_444			(5 << 17)
+#define NV_SOR_STATE1_ASY_PIXELDEPTH_BPP_30_444			(6 << 17)
+#define NV_SOR_STATE1_ASY_PIXELDEPTH_BPP_32_422			(7 << 17)
+#define NV_SOR_STATE1_ASY_PIXELDEPTH_BPP_36_444			(8 << 17)
+#define NV_SOR_STATE1_ASY_PIXELDEPTH_BPP_48_444			(9 << 17)
+#define NV_SOR_STATE1_ASY_REPLICATE_SHIFT			(15)
+#define NV_SOR_STATE1_ASY_REPLICATE_DEFAULT_MASK		(0x3 << 15)
+#define NV_SOR_STATE1_ASY_REPLICATE_OFF				(0 << 15)
+#define NV_SOR_STATE1_ASY_REPLICATE_X2				(1 << 15)
+#define NV_SOR_STATE1_ASY_REPLICATE_X4				(2 << 15)
+#define NV_SOR_STATE1_ASY_DEPOL_SHIFT				(14)
+#define NV_SOR_STATE1_ASY_DEPOL_DEFAULT_MASK			(0x1 << 14)
+#define NV_SOR_STATE1_ASY_DEPOL_POSITIVE_TRUE			(0 << 14)
+#define NV_SOR_STATE1_ASY_DEPOL_NEGATIVE_TRUE			(1 << 14)
+#define NV_SOR_STATE1_ASY_VSYNCPOL_SHIFT			(13)
+#define NV_SOR_STATE1_ASY_VSYNCPOL_DEFAULT_MASK			(0x1 << 13)
+#define NV_SOR_STATE1_ASY_VSYNCPOL_POSITIVE_TRUE		(0 << 13)
+#define NV_SOR_STATE1_ASY_VSYNCPOL_NEGATIVE_TRUE		(1 << 13)
+#define NV_SOR_STATE1_ASY_HSYNCPOL_SHIFT			(12)
+#define NV_SOR_STATE1_ASY_HSYNCPOL_DEFAULT_MASK			(0x1 << 12)
+#define NV_SOR_STATE1_ASY_HSYNCPOL_POSITIVE_TRUE		(0 << 12)
+#define NV_SOR_STATE1_ASY_HSYNCPOL_NEGATIVE_TRUE		(1 << 12)
+#define NV_SOR_STATE1_ASY_PROTOCOL_SHIFT			(8)
+#define NV_SOR_STATE1_ASY_PROTOCOL_DEFAULT_MASK			(0xf << 8)
+#define NV_SOR_STATE1_ASY_PROTOCOL_LVDS_CUSTOM			(0 << 8)
+#define NV_SOR_STATE1_ASY_PROTOCOL_DP_A				(8 << 8)
+#define NV_SOR_STATE1_ASY_PROTOCOL_DP_B				(9 << 8)
+#define NV_SOR_STATE1_ASY_PROTOCOL_CUSTOM			(15 << 8)
+#define NV_SOR_STATE1_ASY_CRCMODE_SHIFT				(6)
+#define NV_SOR_STATE1_ASY_CRCMODE_DEFAULT_MASK			(0x3 << 6)
+#define NV_SOR_STATE1_ASY_CRCMODE_ACTIVE_RASTER			(0 << 6)
+#define NV_SOR_STATE1_ASY_CRCMODE_COMPLETE_RASTER		(1 << 6)
+#define NV_SOR_STATE1_ASY_CRCMODE_NON_ACTIVE_RASTER		(2 << 6)
+#define NV_SOR_STATE1_ASY_SUBOWNER_SHIFT			(4)
+#define NV_SOR_STATE1_ASY_SUBOWNER_DEFAULT_MASK			(0x3 << 4)
+#define NV_SOR_STATE1_ASY_SUBOWNER_NONE				(0 << 4)
+#define NV_SOR_STATE1_ASY_SUBOWNER_SUBHEAD0			(1 << 4)
+#define NV_SOR_STATE1_ASY_SUBOWNER_SUBHEAD1			(2 << 4)
+#define NV_SOR_STATE1_ASY_SUBOWNER_BOTH				(3 << 4)
+#define NV_SOR_STATE1_ASY_OWNER_SHIFT				(0)
+#define NV_SOR_STATE1_ASY_OWNER_DEFAULT_MASK			(0xf)
+#define NV_SOR_STATE1_ASY_OWNER_NONE				(0)
+#define NV_SOR_STATE1_ASY_OWNER_HEAD0				(1)
+#define NV_SOR_STATE1_ASY_OWNER_HEAD1				(2)
+#define NV_HEAD_STATE0(i)					(0x5)
+#define NV_HEAD_STATE0_INTERLACED_SHIFT				(4)
+#define NV_HEAD_STATE0_INTERLACED_DEFAULT_MASK			(0x3 << 4)
+#define NV_HEAD_STATE0_INTERLACED_PROGRESSIVE			(0 << 4)
+#define NV_HEAD_STATE0_INTERLACED_INTERLACED			(1 << 4)
+#define NV_HEAD_STATE0_RANGECOMPRESS_SHIFT			(3)
+#define NV_HEAD_STATE0_RANGECOMPRESS_DEFAULT_MASK		(0x1 << 3)
+#define NV_HEAD_STATE0_RANGECOMPRESS_DISABLE			(0 << 3)
+#define NV_HEAD_STATE0_RANGECOMPRESS_ENABLE			(1 << 3)
+#define NV_HEAD_STATE0_DYNRANGE_SHIFT				(2)
+#define NV_HEAD_STATE0_DYNRANGE_DEFAULT_MASK			(0x1 << 2)
+#define NV_HEAD_STATE0_DYNRANGE_VESA				(0 << 2)
+#define NV_HEAD_STATE0_DYNRANGE_CEA				(1 << 2)
+#define NV_HEAD_STATE0_COLORSPACE_SHIFT				(0)
+#define NV_HEAD_STATE0_COLORSPACE_DEFAULT_MASK			(0x3)
+#define NV_HEAD_STATE0_COLORSPACE_RGB				(0)
+#define NV_HEAD_STATE0_COLORSPACE_YUV_601			(1)
+#define NV_HEAD_STATE0_COLORSPACE_YUV_709			(2)
+#define NV_HEAD_STATE1(i)					(0x7 + i)
+#define NV_HEAD_STATE1_VTOTAL_SHIFT				(16)
+#define NV_HEAD_STATE1_VTOTAL_DEFAULT_MASK			(0x7fff	 << 16)
+#define NV_HEAD_STATE1_HTOTAL_SHIFT				(0)
+#define NV_HEAD_STATE1_HTOTAL_DEFAULT_MASK			(0x7fff)
+#define NV_HEAD_STATE2(i)					(0x9 + i)
+#define NV_HEAD_STATE2_VSYNC_END_SHIFT				(16)
+#define NV_HEAD_STATE2_VSYNC_END_DEFAULT_MASK			(0x7fff << 16)
+#define NV_HEAD_STATE2_HSYNC_END_SHIFT				(0)
+#define NV_HEAD_STATE2_HSYNC_END_DEFAULT_MASK			(0x7fff)
+#define NV_HEAD_STATE3(i)					(0xb + i)
+#define NV_HEAD_STATE3_VBLANK_END_SHIFT				(16)
+#define NV_HEAD_STATE3_VBLANK_END_DEFAULT_MASK			(0x7fff << 16)
+#define NV_HEAD_STATE3_HBLANK_END_SHIFT				(0)
+#define NV_HEAD_STATE3_HBLANK_END_DEFAULT_MASK			(0x7fff)
+#define NV_HEAD_STATE4(i)					(0xd + i)
+#define NV_HEAD_STATE4_VBLANK_START_SHIFT			(16)
+#define NV_HEAD_STATE4_VBLANK_START_DEFAULT_MASK		(0x7fff << 16)
+#define NV_HEAD_STATE4_HBLANK_START_SHIFT			(0)
+#define NV_HEAD_STATE4_HBLANK_START_DEFAULT_MASK		(0x7fff)
+#define NV_HEAD_STATE5(i)					(0xf + i)
+#define NV_SOR_CRC_CNTRL					(0x11)
+#define NV_SOR_CRC_CNTRL_ARM_CRC_ENABLE_SHIFT			(0)
+#define NV_SOR_CRC_CNTRL_ARM_CRC_ENABLE_NO			(0)
+#define NV_SOR_CRC_CNTRL_ARM_CRC_ENABLE_YES			(1)
+#define NV_SOR_CRC_CNTRL_ARM_CRC_ENABLE_DIS			(0)
+#define NV_SOR_CRC_CNTRL_ARM_CRC_ENABLE_EN			(1)
+#define NV_SOR_CLK_CNTRL					(0x13)
+#define NV_SOR_CLK_CNTRL_DP_CLK_SEL_SHIFT			(0)
+#define NV_SOR_CLK_CNTRL_DP_CLK_SEL_MASK			(0x3)
+#define NV_SOR_CLK_CNTRL_DP_CLK_SEL_SINGLE_PCLK			(0)
+#define NV_SOR_CLK_CNTRL_DP_CLK_SEL_DIFF_PCLK			(1)
+#define NV_SOR_CLK_CNTRL_DP_CLK_SEL_SINGLE_DPCLK		(2)
+#define NV_SOR_CLK_CNTRL_DP_CLK_SEL_DIFF_DPCLK			(3)
+#define NV_SOR_CLK_CNTRL_DP_LINK_SPEED_SHIFT			(2)
+#define NV_SOR_CLK_CNTRL_DP_LINK_SPEED_MASK			(0x1f << 2)
+#define NV_SOR_CLK_CNTRL_DP_LINK_SPEED_G1_62			(6 << 2)
+#define NV_SOR_CLK_CNTRL_DP_LINK_SPEED_G2_7			(10 << 2)
+#define NV_SOR_CLK_CNTRL_DP_LINK_SPEED_LVDS			(7 << 2)
+#define NV_SOR_CAP						(0x14)
+#define NV_SOR_CAP_DP_A_SHIFT					(24)
+#define NV_SOR_CAP_DP_A_DEFAULT_MASK				(0x1 << 24)
+#define NV_SOR_CAP_DP_A_FALSE					(0 << 24)
+#define NV_SOR_CAP_DP_A_TRUE					(1 << 24)
+#define NV_SOR_CAP_DP_B_SHIFT					(25)
+#define NV_SOR_CAP_DP_B_DEFAULT_MASK				(0x1 << 24)
+#define NV_SOR_CAP_DP_B_FALSE					(0 << 24)
+#define NV_SOR_CAP_DP_B_TRUE					(1 << 24)
+#define NV_SOR_PWR						(0x15)
+#define NV_SOR_PWR_SETTING_NEW_SHIFT				(31)
+#define NV_SOR_PWR_SETTING_NEW_DEFAULT_MASK			(0x1 << 31)
+#define NV_SOR_PWR_SETTING_NEW_DONE				(0 << 31)
+#define NV_SOR_PWR_SETTING_NEW_PENDING				(1 << 31)
+#define NV_SOR_PWR_SETTING_NEW_TRIGGER				(1 << 31)
+#define NV_SOR_PWR_MODE_SHIFT					(28)
+#define NV_SOR_PWR_MODE_DEFAULT_MASK				(0x1 << 28)
+#define NV_SOR_PWR_MODE_NORMAL					(0 << 28)
+#define NV_SOR_PWR_MODE_SAFE					(1 << 28)
+#define NV_SOR_PWR_HALT_DELAY_SHIFT				(24)
+#define NV_SOR_PWR_HALT_DELAY_DEFAULT_MASK			(0x1 << 24)
+#define NV_SOR_PWR_HALT_DELAY_DONE				(0 << 24)
+#define NV_SOR_PWR_HALT_DELAY_ACTIVE				(1 << 24)
+#define NV_SOR_PWR_SAFE_START_SHIFT				(17)
+#define NV_SOR_PWR_SAFE_START_DEFAULT_MASK			(0x1 << 17)
+#define NV_SOR_PWR_SAFE_START_NORMAL				(0 << 17)
+#define NV_SOR_PWR_SAFE_START_ALT				(1 << 17)
+#define NV_SOR_PWR_SAFE_STATE_SHIFT				(16)
+#define NV_SOR_PWR_SAFE_STATE_DEFAULT_MASK			(0x1 << 16)
+#define NV_SOR_PWR_SAFE_STATE_PD				(0 << 16)
+#define NV_SOR_PWR_SAFE_STATE_PU				(1 << 16)
+#define NV_SOR_PWR_NORMAL_START_SHIFT				(1)
+#define NV_SOR_PWR_NORMAL_START_DEFAULT_MASK			(0x1 << 1)
+#define NV_SOR_PWR_NORMAL_START_NORMAL				(0 << 16)
+#define NV_SOR_PWR_NORMAL_START_ALT				(1 << 16)
+#define NV_SOR_PWR_NORMAL_STATE_SHIFT				(0)
+#define NV_SOR_PWR_NORMAL_STATE_DEFAULT_MASK			(0x1)
+#define NV_SOR_PWR_NORMAL_STATE_PD				(0)
+#define NV_SOR_PWR_NORMAL_STATE_PU				(1)
+#define NV_SOR_TEST						(0x16)
+#define NV_SOR_TEST_TESTMUX_SHIFT				(24)
+#define NV_SOR_TEST_TESTMUX_DEFAULT_MASK			(0xff << 24)
+#define NV_SOR_TEST_TESTMUX_AVSS				(0 << 24)
+#define NV_SOR_TEST_TESTMUX_CLOCKIN				(2 << 24)
+#define NV_SOR_TEST_TESTMUX_PLL_VOL				(4 << 24)
+#define NV_SOR_TEST_TESTMUX_SLOWCLKINT				(8 << 24)
+#define NV_SOR_TEST_TESTMUX_AVDD				(16 << 24)
+#define NV_SOR_TEST_TESTMUX_VDDREG				(32 << 24)
+#define NV_SOR_TEST_TESTMUX_REGREF_VDDREG			(64 << 24)
+#define NV_SOR_TEST_TESTMUX_REGREF_AVDD				(128 << 24)
+#define NV_SOR_TEST_CRC_SHIFT					(23)
+#define NV_SOR_TEST_CRC_PRE_SERIALIZE				(0 << 23)
+#define NV_SOR_TEST_CRC_POST_DESERIALIZE			(1 << 23)
+#define NV_SOR_TEST_TPAT_SHIFT					(20)
+#define NV_SOR_TEST_TPAT_DEFAULT_MASK				(0x7 << 20)
+#define NV_SOR_TEST_TPAT_LO					(0 << 20)
+#define NV_SOR_TEST_TPAT_TDAT					(1 << 20)
+#define NV_SOR_TEST_TPAT_RAMP					(2 << 20)
+#define NV_SOR_TEST_TPAT_WALK					(3 << 20)
+#define NV_SOR_TEST_TPAT_MAXSTEP				(4 << 20)
+#define NV_SOR_TEST_TPAT_MINSTEP				(5 << 20)
+#define NV_SOR_TEST_DSRC_SHIFT					(16)
+#define NV_SOR_TEST_DSRC_DEFAULT_MASK				(0x3 << 16)
+#define NV_SOR_TEST_DSRC_NORMAL					(0 << 16)
+#define NV_SOR_TEST_DSRC_DEBUG					(1 << 16)
+#define NV_SOR_TEST_DSRC_TGEN					(2 << 16)
+#define NV_SOR_TEST_HEAD_NUMBER_SHIFT				(12)
+#define NV_SOR_TEST_HEAD_NUMBER_DEFAULT_MASK			(0x3 << 12)
+#define NV_SOR_TEST_HEAD_NUMBER_NONE				(0 << 12)
+#define NV_SOR_TEST_HEAD_NUMBER_HEAD0				(1 << 12)
+#define NV_SOR_TEST_HEAD_NUMBER_HEAD1				(2 << 12)
+#define NV_SOR_TEST_ATTACHED_SHIFT				(10)
+#define NV_SOR_TEST_ATTACHED_DEFAULT_MASK			(0x1  << 10)
+#define NV_SOR_TEST_ATTACHED_FALSE				(0 << 10)
+#define NV_SOR_TEST_ATTACHED_TRUE				(1 << 10)
+#define NV_SOR_TEST_ACT_HEAD_OPMODE_SHIFT			(8)
+#define NV_SOR_TEST_ACT_HEAD_OPMODE_DEFAULT_MASK		(0x3 << 8)
+#define NV_SOR_TEST_ACT_HEAD_OPMODE_SLEEP			(0 << 8)
+#define NV_SOR_TEST_ACT_HEAD_OPMODE_SNOOZE			(1 << 8)
+#define NV_SOR_TEST_ACT_HEAD_OPMODE_AWAKE			(2 << 8)
+#define NV_SOR_TEST_INVD_SHIFT					(6)
+#define NV_SOR_TEST_INVD_DISABLE				(0 << 6)
+#define NV_SOR_TEST_INVD_ENABLE					(1 << 6)
+#define NV_SOR_TEST_TEST_ENABLE_SHIFT				(1)
+#define NV_SOR_TEST_TEST_ENABLE_DISABLE				(0 << 1)
+#define NV_SOR_TEST_TEST_ENABLE_ENABLE				(1 << 1)
+#define NV_SOR_PLL0						(0x17)
+#define NV_SOR_PLL0_ICHPMP_SHFIT				(24)
+#define NV_SOR_PLL0_ICHPMP_DEFAULT_MASK				(0xf << 24)
+#define NV_SOR_PLL0_VCOCAP_SHIFT				(8)
+#define NV_SOR_PLL0_VCOCAP_DEFAULT_MASK				(0xf << 8)
+#define NV_SOR_PLL0_PLLREG_LEVEL_SHIFT				(6)
+#define NV_SOR_PLL0_PLLREG_LEVEL_DEFAULT_MASK			(0x3 << 6)
+#define NV_SOR_PLL0_PLLREG_LEVEL_V25				(0 << 6)
+#define NV_SOR_PLL0_PLLREG_LEVEL_V15				(1 << 6)
+#define NV_SOR_PLL0_PLLREG_LEVEL_V35				(2 << 6)
+#define NV_SOR_PLL0_PLLREG_LEVEL_V45				(3 << 6)
+#define NV_SOR_PLL0_PULLDOWN_SHIFT				(5)
+#define NV_SOR_PLL0_PULLDOWN_DEFAULT_MASK			(0x1 << 5)
+#define NV_SOR_PLL0_PULLDOWN_DISABLE				(0 << 5)
+#define NV_SOR_PLL0_PULLDOWN_ENABLE				(1 << 5)
+#define NV_SOR_PLL0_RESISTORSEL_SHIFT				(4)
+#define NV_SOR_PLL0_RESISTORSEL_DEFAULT_MASK			(0x1 << 4)
+#define NV_SOR_PLL0_RESISTORSEL_INT				(0 << 4)
+#define NV_SOR_PLL0_RESISTORSEL_EXT				(1 << 4)
+#define NV_SOR_PLL0_VCOPD_SHIFT					(2)
+#define NV_SOR_PLL0_VCOPD_MASK					(1 << 2)
+#define NV_SOR_PLL0_VCOPD_RESCIND				(0 << 2)
+#define NV_SOR_PLL0_VCOPD_ASSERT				(1 << 2)
+#define NV_SOR_PLL0_PWR_SHIFT					(0)
+#define NV_SOR_PLL0_PWR_MASK					(1)
+#define NV_SOR_PLL0_PWR_ON					(0)
+#define NV_SOR_PLL0_PWR_OFF					(1)
+#define NV_SOR_PLL1_TMDS_TERM_SHIFT				(8)
+#define NV_SOR_PLL1_TMDS_TERM_DISABLE				(0 << 8)
+#define NV_SOR_PLL1_TMDS_TERM_ENABLE				(1 << 8)
+#define NV_SOR_PLL1						(0x18)
+#define NV_SOR_PLL1_TERM_COMPOUT_SHIFT				(15)
+#define NV_SOR_PLL1_TERM_COMPOUT_LOW				(0 << 15)
+#define NV_SOR_PLL1_TERM_COMPOUT_HIGH				(1 << 15)
+#define NV_SOR_PLL2						(0x19)
+#define NV_SOR_PLL2_DCIR_PLL_RESET_SHIFT			(0)
+#define NV_SOR_PLL2_DCIR_PLL_RESET_OVERRIDE			(0 << 0)
+#define NV_SOR_PLL2_DCIR_PLL_RESET_ALLOW			(1 << 0)
+#define NV_SOR_PLL2_AUX1_SHIFT					(17)
+#define NV_SOR_PLL2_AUX1_SEQ_MASK				(1 << 17)
+#define NV_SOR_PLL2_AUX1_SEQ_PLLCAPPD_ALLOW			(0 << 17)
+#define NV_SOR_PLL2_AUX1_SEQ_PLLCAPPD_OVERRIDE			(1 << 17)
+#define NV_SOR_PLL2_AUX2_SHIFT					(18)
+#define NV_SOR_PLL2_AUX2_MASK					(1 << 18)
+#define NV_SOR_PLL2_AUX2_OVERRIDE_POWERDOWN			(0 << 18)
+#define NV_SOR_PLL2_AUX2_ALLOW_POWERDOWN			(1 << 18)
+#define NV_SOR_PLL2_AUX6_SHIFT					(22)
+#define NV_SOR_PLL2_AUX6_BANDGAP_POWERDOWN_MASK			(1 << 22)
+#define NV_SOR_PLL2_AUX6_BANDGAP_POWERDOWN_DISABLE		(0 << 22)
+#define NV_SOR_PLL2_AUX6_BANDGAP_POWERDOWN_ENABLE		(1 << 22)
+#define NV_SOR_PLL2_AUX7_SHIFT					(23)
+#define NV_SOR_PLL2_AUX7_PORT_POWERDOWN_MASK			(1 << 23)
+#define NV_SOR_PLL2_AUX7_PORT_POWERDOWN_DISABLE			(0 << 23)
+#define NV_SOR_PLL2_AUX7_PORT_POWERDOWN_ENABLE			(1 << 23)
+#define NV_SOR_PLL2_AUX8_SHIFT					(24)
+#define NV_SOR_PLL2_AUX8_SEQ_PLLCAPPD_ENFORCE_MASK		(1 << 24)
+#define NV_SOR_PLL2_AUX8_SEQ_PLLCAPPD_ENFORCE_DISABLE		(0 << 24)
+#define NV_SOR_PLL2_AUX8_SEQ_PLLCAPPD_ENFORCE_ENABLE		(1 << 24)
+#define NV_SOR_PLL2_AUX9_SHIFT					(25)
+#define NV_SOR_PLL2_AUX9_LVDSEN_ALLOW				(0 << 25)
+#define NV_SOR_PLL2_AUX9_LVDSEN_OVERRIDE			(1 << 25)
+#define NV_SOR_PLL3						(0x1a)
+#define NV_SOR_PLL3_PLLVDD_MODE_SHIFT				(13)
+#define NV_SOR_PLL3_PLLVDD_MODE_MASK				(1 << 13)
+#define NV_SOR_PLL3_PLLVDD_MODE_V1_8				(0 << 13)
+#define NV_SOR_PLL3_PLLVDD_MODE_V3_3				(1 << 13)
+#define NV_SOR_CSTM						(0x1b)
+#define NV_SOR_CSTM_ROTDAT_SHIFT				(28)
+#define NV_SOR_CSTM_ROTDAT_DEFAULT_MASK				(0x7 << 28)
+#define NV_SOR_CSTM_ROTCLK_SHIFT				(24)
+#define NV_SOR_CSTM_ROTCLK_DEFAULT_MASK				(0xf << 24)
+#define NV_SOR_CSTM_LVDS_EN_SHIFT				(16)
+#define NV_SOR_CSTM_LVDS_EN_DISABLE				(0 << 16)
+#define NV_SOR_CSTM_LVDS_EN_ENABLE				(1 << 16)
+#define NV_SOR_CSTM_LINKACTB_SHIFT				(15)
+#define NV_SOR_CSTM_LINKACTB_DISABLE				(0 << 15)
+#define NV_SOR_CSTM_LINKACTB_ENABLE				(1 << 15)
+#define NV_SOR_CSTM_LINKACTA_SHIFT				(14)
+#define NV_SOR_CSTM_LINKACTA_DISABLE				(0 << 14)
+#define NV_SOR_CSTM_LINKACTA_ENABLE				(1 << 14)
+#define NV_SOR_LVDS						(0x1c)
+#define NV_SOR_LVDS_ROTDAT_SHIFT				(28)
+#define NV_SOR_LVDS_ROTDAT_DEFAULT_MASK				(0x7 << 28)
+#define NV_SOR_LVDS_ROTDAT_RST					(0 << 28)
+#define NV_SOR_LVDS_ROTCLK_SHIFT				(24)
+#define NV_SOR_LVDS_ROTCLK_DEFAULT_MASK				(0xf << 24)
+#define NV_SOR_LVDS_ROTCLK_RST					(0 << 24)
+#define NV_SOR_LVDS_PLLDIV_SHIFT				(21)
+#define NV_SOR_LVDS_PLLDIV_DEFAULT_MASK				(0x1 << 21)
+#define NV_SOR_LVDS_PLLDIV_BY_7					(0 << 21)
+#define NV_SOR_LVDS_BALANCED_SHIFT				(19)
+#define NV_SOR_LVDS_BALANCED_DEFAULT_MASK			(0x1 << 19)
+#define NV_SOR_LVDS_BALANCED_DISABLE				(0 << 19)
+#define NV_SOR_LVDS_BALANCED_ENABLE				(1 << 19)
+#define NV_SOR_LVDS_NEW_MODE_SHIFT				(18)
+#define NV_SOR_LVDS_NEW_MODE_DEFAULT_MASK			(0x1 << 18)
+#define NV_SOR_LVDS_NEW_MODE_DISABLE				(0 << 18)
+#define NV_SOR_LVDS_NEW_MODE_ENABLE				(1 << 18)
+#define NV_SOR_LVDS_DUP_SYNC_SHIFT				(17)
+#define NV_SOR_LVDS_DUP_SYNC_DEFAULT_MASK			(0x1 << 17)
+#define NV_SOR_LVDS_DUP_SYNC_DISABLE				(0 << 17)
+#define NV_SOR_LVDS_DUP_SYNC_ENABLE				(1 << 17)
+#define NV_SOR_LVDS_LVDS_EN_SHIFT				(16)
+#define NV_SOR_LVDS_LVDS_EN_DEFAULT_MASK			(0x1 << 16)
+#define NV_SOR_LVDS_LVDS_EN_ENABLE				(1 << 16)
+#define NV_SOR_LVDS_LINKACTB_SHIFT				(15)
+#define NV_SOR_LVDS_LINKACTB_DEFAULT_MASK			(0x1 << 15)
+#define NV_SOR_LVDS_LINKACTB_DISABLE				(0 << 15)
+#define NV_SOR_LVDS_LINKACTB_ENABLE				(1 << 15)
+#define NV_SOR_LVDS_LINKACTA_SHIFT				(14)
+#define NV_SOR_LVDS_LINKACTA_DEFAULT_MASK			(0x1 << 14)
+#define NV_SOR_LVDS_LINKACTA_ENABLE				(1 << 14)
+#define NV_SOR_LVDS_MODE_SHIFT					(12)
+#define NV_SOR_LVDS_MODE_DEFAULT_MASK				(0x3 << 12)
+#define NV_SOR_LVDS_MODE_LVDS					(0 << 12)
+#define NV_SOR_LVDS_UPPER_SHIFT					(11)
+#define NV_SOR_LVDS_UPPER_DEFAULT_MASK				(0x1 << 11)
+#define NV_SOR_LVDS_UPPER_FALSE					(0 << 11)
+#define NV_SOR_LVDS_UPPER_TRUE					(1 << 11)
+#define NV_SOR_LVDS_PD_TXCB_SHIFT				(9)
+#define NV_SOR_LVDS_PD_TXCB_DEFAULT_MASK			(0x1 << 9)
+#define NV_SOR_LVDS_PD_TXCB_ENABLE				(0 << 9)
+#define NV_SOR_LVDS_PD_TXCB_DISABLE				(1 << 9)
+#define NV_SOR_LVDS_PD_TXCA_SHIFT				(8)
+#define NV_SOR_LVDS_PD_TXCA_DEFAULT_MASK			(0x1 << 8)
+#define NV_SOR_LVDS_PD_TXCA_ENABLE				(0 << 8)
+#define NV_SOR_LVDS_PD_TXDB_3_SHIFT				(7)
+#define NV_SOR_LVDS_PD_TXDB_3_DEFAULT_MASK			(0x1 << 7)
+#define NV_SOR_LVDS_PD_TXDB_3_ENABLE				(0 << 7)
+#define NV_SOR_LVDS_PD_TXDB_3_DISABLE				(1 << 7)
+#define NV_SOR_LVDS_PD_TXDB_2_SHIFT				(6)
+#define NV_SOR_LVDS_PD_TXDB_2_DEFAULT_MASK			(0x1 << 6)
+#define NV_SOR_LVDS_PD_TXDB_2_ENABLE				(0 << 6)
+#define NV_SOR_LVDS_PD_TXDB_2_DISABLE				(1 << 6)
+#define NV_SOR_LVDS_PD_TXDB_1_SHIFT				(5)
+#define NV_SOR_LVDS_PD_TXDB_1_DEFAULT_MASK			(0x1 << 5)
+#define NV_SOR_LVDS_PD_TXDB_1_ENABLE				(0 << 5)
+#define NV_SOR_LVDS_PD_TXDB_1_DISABLE				(1 << 5)
+#define NV_SOR_LVDS_PD_TXDB_0_SHIFT				(4)
+#define NV_SOR_LVDS_PD_TXDB_0_DEFAULT_MASK			(0x1 << 4)
+#define NV_SOR_LVDS_PD_TXDB_0_ENABLE				(0 << 4)
+#define NV_SOR_LVDS_PD_TXDB_0_DISABLE				(1 << 4)
+#define NV_SOR_LVDS_PD_TXDA_3_SHIFT				(3)
+#define NV_SOR_LVDS_PD_TXDA_3_DEFAULT_MASK			(0x1 << 3)
+#define NV_SOR_LVDS_PD_TXDA_3_ENABLE				(0 << 3)
+#define NV_SOR_LVDS_PD_TXDA_3_DISABLE				(1 << 3)
+#define NV_SOR_LVDS_PD_TXDA_2_SHIFT				(2)
+#define NV_SOR_LVDS_PD_TXDA_2_DEFAULT_MASK			(0x1 << 2)
+#define NV_SOR_LVDS_PD_TXDA_2_ENABLE				(0 << 2)
+#define NV_SOR_LVDS_PD_TXDA_1_SHIFT				(1)
+#define NV_SOR_LVDS_PD_TXDA_1_DEFAULT_MASK			(0x1 << 1)
+#define NV_SOR_LVDS_PD_TXDA_1_ENABLE				(0 << 1)
+#define NV_SOR_LVDS_PD_TXDA_0_SHIFT				(0)
+#define NV_SOR_LVDS_PD_TXDA_0_DEFAULT_MASK			(0x1)
+#define NV_SOR_LVDS_PD_TXDA_0_ENABLE				(0)
+#define NV_SOR_CRCA						(0x1d)
+#define NV_SOR_CRCA_VALID_FALSE					(0)
+#define NV_SOR_CRCA_VALID_TRUE					(1)
+#define NV_SOR_CRCA_VALID_RST					(1)
+#define NV_SOR_CRCB						(0x1e)
+#define NV_SOR_CRCB_CRC_DEFAULT_MASK				(0xffffffff)
+#define NV_SOR_SEQ_CTL						(0x20)
+#define NV_SOR_SEQ_CTL_SWITCH_SHIFT				(30)
+#define NV_SOR_SEQ_CTL_SWITCH_MASK				(0x1 << 30)
+#define NV_SOR_SEQ_CTL_SWITCH_WAIT				(0 << 30)
+#define NV_SOR_SEQ_CTL_SWITCH_FORCE				(1 << 30)
+#define NV_SOR_SEQ_CTL_STATUS_SHIFT				(28)
+#define NV_SOR_SEQ_CTL_STATUS_MASK				(0x1 << 28)
+#define NV_SOR_SEQ_CTL_STATUS_STOPPED				(0 << 28)
+#define NV_SOR_SEQ_CTL_STATUS_RUNNING				(1 << 28)
+#define NV_SOR_SEQ_CTL_PC_SHIFT					(16)
+#define NV_SOR_SEQ_CTL_PC_MASK					(0xf << 16)
+#define NV_SOR_SEQ_CTL_PD_PC_ALT_SHIFT				(12)
+#define NV_SOR_SEQ_CTL_PD_PC_ALT_MASK				(0xf << 12)
+#define NV_SOR_SEQ_CTL_PD_PC_SHIFT				(8)
+#define NV_SOR_SEQ_CTL_PD_PC_MASK				(0xf << 8)
+#define NV_SOR_SEQ_CTL_PU_PC_ALT_SHIFT				(4)
+#define NV_SOR_SEQ_CTL_PU_PC_ALT_MASK				(0xf << 4)
+#define NV_SOR_SEQ_CTL_PU_PC_SHIFT				(0)
+#define NV_SOR_SEQ_CTL_PU_PC_MASK				(0xf)
+#define NV_SOR_LANE_SEQ_CTL					(0x21)
+#define NV_SOR_LANE_SEQ_CTL_SETTING_NEW_SHIFT			(31)
+#define NV_SOR_LANE_SEQ_CTL_SETTING_MASK			(1 << 31)
+#define NV_SOR_LANE_SEQ_CTL_SETTING_NEW_DONE			(0 << 31)
+#define NV_SOR_LANE_SEQ_CTL_SETTING_NEW_PENDING			(1 << 31)
+#define NV_SOR_LANE_SEQ_CTL_SETTING_NEW_TRIGGER			(1 << 31)
+#define NV_SOR_LANE_SEQ_CTL_SEQ_STATE_SHIFT			(28)
+#define NV_SOR_LANE_SEQ_CTL_SEQ_STATE_IDLE			(0 << 28)
+#define NV_SOR_LANE_SEQ_CTL_SEQ_STATE_BUSY			(1 << 28)
+#define NV_SOR_LANE_SEQ_CTL_SEQUENCE_SHIFT			(20)
+#define NV_SOR_LANE_SEQ_CTL_SEQUENCE_UP				(0 << 20)
+#define NV_SOR_LANE_SEQ_CTL_SEQUENCE_DOWN			(1 << 20)
+#define NV_SOR_LANE_SEQ_CTL_NEW_POWER_STATE_SHIFT		(16)
+#define NV_SOR_LANE_SEQ_CTL_NEW_POWER_STATE_PU			(0 << 16)
+#define NV_SOR_LANE_SEQ_CTL_NEW_POWER_STATE_PD			(1 << 16)
+#define NV_SOR_LANE_SEQ_CTL_DELAY_SHIFT				(12)
+#define NV_SOR_LANE_SEQ_CTL_DELAY_DEFAULT_MASK			(0xf << 12)
+#define NV_SOR_LANE_SEQ_CTL_LANE9_STATE_SHIFT			(9)
+#define NV_SOR_LANE_SEQ_CTL_LANE9_STATE_POWERUP			(0 << 9)
+#define NV_SOR_LANE_SEQ_CTL_LANE9_STATE_POWERDOWN		(1 << 9)
+#define NV_SOR_LANE_SEQ_CTL_LANE8_STATE_SHIFT			(8)
+#define NV_SOR_LANE_SEQ_CTL_LANE8_STATE_POWERUP			(0 << 8)
+#define NV_SOR_LANE_SEQ_CTL_LANE8_STATE_POWERDOWN		(1 << 8)
+#define NV_SOR_LANE_SEQ_CTL_LANE7_STATE_SHIFT			(7)
+#define NV_SOR_LANE_SEQ_CTL_LANE7_STATE_POWERUP			(0 << 7)
+#define NV_SOR_LANE_SEQ_CTL_LANE7_STATE_POWERDOWN		(1 << 7)
+#define NV_SOR_LANE_SEQ_CTL_LANE6_STATE_SHIFT			(6)
+#define NV_SOR_LANE_SEQ_CTL_LANE6_STATE_POWERUP			(0 << 6)
+#define NV_SOR_LANE_SEQ_CTL_LANE6_STATE_POWERDOWN		(1 << 6)
+#define NV_SOR_LANE_SEQ_CTL_LANE5_STATE_SHIFT			(5)
+#define NV_SOR_LANE_SEQ_CTL_LANE5_STATE_POWERUP			(0 << 5)
+#define NV_SOR_LANE_SEQ_CTL_LANE5_STATE_POWERDOWN		(1 << 5)
+#define NV_SOR_LANE_SEQ_CTL_LANE4_STATE_SHIFT			(4)
+#define NV_SOR_LANE_SEQ_CTL_LANE4_STATE_POWERUP			(0 << 4)
+#define NV_SOR_LANE_SEQ_CTL_LANE4_STATE_POWERDOWN		(1 << 4)
+#define NV_SOR_LANE_SEQ_CTL_LANE3_STATE_SHIFT			(3)
+#define NV_SOR_LANE_SEQ_CTL_LANE3_STATE_POWERUP			(0 << 3)
+#define NV_SOR_LANE_SEQ_CTL_LANE3_STATE_POWERDOWN		(1 << 3)
+#define NV_SOR_LANE_SEQ_CTL_LANE2_STATE_SHIFT			(2)
+#define NV_SOR_LANE_SEQ_CTL_LANE2_STATE_POWERUP			(0 << 2)
+#define NV_SOR_LANE_SEQ_CTL_LANE2_STATE_POWERDOWN		(1 << 2)
+#define NV_SOR_LANE_SEQ_CTL_LANE1_STATE_SHIFT			(1)
+#define NV_SOR_LANE_SEQ_CTL_LANE1_STATE_POWERUP			(0 << 1)
+#define NV_SOR_LANE_SEQ_CTL_LANE1_STATE_POWERDOWN		(1 << 1)
+#define NV_SOR_LANE_SEQ_CTL_LANE0_STATE_SHIFT			(0)
+#define NV_SOR_LANE_SEQ_CTL_LANE0_STATE_POWERUP			(0)
+#define NV_SOR_LANE_SEQ_CTL_LANE0_STATE_POWERDOWN		(1)
+#define NV_SOR_SEQ_INST(i)					(0x22 + i)
+#define NV_SOR_SEQ_INST_PLL_PULLDOWN_SHIFT			(31)
+#define NV_SOR_SEQ_INST_PLL_PULLDOWN_DISABLE			(0 << 31)
+#define NV_SOR_SEQ_INST_PLL_PULLDOWN_ENABLE			(1 << 31)
+#define NV_SOR_SEQ_INST_POWERDOWN_MACRO_SHIFT			(30)
+#define NV_SOR_SEQ_INST_POWERDOWN_MACRO_NORMAL			(0 << 30)
+#define NV_SOR_SEQ_INST_POWERDOWN_MACRO_POWERDOWN		(1 << 30)
+#define NV_SOR_SEQ_INST_ASSERT_PLL_RESET_SHIFT			(29)
+#define NV_SOR_SEQ_INST_ASSERT_PLL_RESET_NORMAL			(0 << 29)
+#define NV_SOR_SEQ_INST_ASSERT_PLL_RESET_RST			(1 << 29)
+#define NV_SOR_SEQ_INST_BLANK_V_SHIFT				(28)
+#define NV_SOR_SEQ_INST_BLANK_V_NORMAL				(0 << 28)
+#define NV_SOR_SEQ_INST_BLANK_V_INACTIVE			(1 << 28)
+#define NV_SOR_SEQ_INST_BLANK_H_SHIFT				(27)
+#define NV_SOR_SEQ_INST_BLANK_H_NORMAL				(0 << 27)
+#define NV_SOR_SEQ_INST_BLANK_H_INACTIVE			(1 << 27)
+#define NV_SOR_SEQ_INST_BLANK_DE_SHIFT				(26)
+#define NV_SOR_SEQ_INST_BLANK_DE_NORMAL				(0 << 26)
+#define NV_SOR_SEQ_INST_BLANK_DE_INACTIVE			(1 << 26)
+#define NV_SOR_SEQ_INST_BLACK_DATA_SHIFT			(25)
+#define NV_SOR_SEQ_INST_BLACK_DATA_NORMAL			(0 << 25)
+#define NV_SOR_SEQ_INST_BLACK_DATA_BLACK			(1 << 25)
+#define NV_SOR_SEQ_INST_TRISTATE_IOS_SHIFT			(24)
+#define NV_SOR_SEQ_INST_TRISTATE_IOS_ENABLE_PINS		(0 << 24)
+#define NV_SOR_SEQ_INST_TRISTATE_IOS_TRISTATE			(1 << 24)
+#define NV_SOR_SEQ_INST_DRIVE_PWM_OUT_LO_SHIFT			(23)
+#define NV_SOR_SEQ_INST_DRIVE_PWM_OUT_LO_FALSE			(0 << 23)
+#define NV_SOR_SEQ_INST_DRIVE_PWM_OUT_LO_TRUE			(1 << 23)
+#define NV_SOR_SEQ_INST_PIN_B_SHIFT				(22)
+#define NV_SOR_SEQ_INST_PIN_B_LOW				(0 << 22)
+#define NV_SOR_SEQ_INST_PIN_B_HIGH				(1 << 22)
+#define NV_SOR_SEQ_INST_PIN_A_SHIFT				(21)
+#define NV_SOR_SEQ_INST_PIN_A_LOW				(0 << 21)
+#define NV_SOR_SEQ_INST_PIN_A_HIGH				(1 << 21)
+#define NV_SOR_SEQ_INST_SEQUENCE_SHIFT				(19)
+#define NV_SOR_SEQ_INST_SEQUENCE_UP				(0 << 19)
+#define NV_SOR_SEQ_INST_SEQUENCE_DOWN				(1 << 19)
+#define NV_SOR_SEQ_INST_LANE_SEQ_SHIFT				(18)
+#define NV_SOR_SEQ_INST_LANE_SEQ_STOP				(0 << 18)
+#define NV_SOR_SEQ_INST_LANE_SEQ_RUN				(1 << 18)
+#define NV_SOR_SEQ_INST_PDPORT_SHIFT				(17)
+#define NV_SOR_SEQ_INST_PDPORT_NO				(0 << 17)
+#define NV_SOR_SEQ_INST_PDPORT_YES				(1 << 17)
+#define NV_SOR_SEQ_INST_PDPLL_SHIFT				(16)
+#define NV_SOR_SEQ_INST_PDPLL_NO				(0 << 16)
+#define NV_SOR_SEQ_INST_PDPLL_YES				(1 << 16)
+#define NV_SOR_SEQ_INST_HALT_SHIFT				(15)
+#define NV_SOR_SEQ_INST_HALT_FALSE				(0 << 15)
+#define NV_SOR_SEQ_INST_HALT_TRUE				(1 << 15)
+#define NV_SOR_SEQ_INST_WAIT_UNITS_SHIFT			(12)
+#define NV_SOR_SEQ_INST_WAIT_UNITS_DEFAULT_MASK			(0x3 << 12)
+#define NV_SOR_SEQ_INST_WAIT_UNITS_US				(0 << 12)
+#define NV_SOR_SEQ_INST_WAIT_UNITS_MS				(1 << 12)
+#define NV_SOR_SEQ_INST_WAIT_UNITS_VSYNC			(2 << 12)
+#define NV_SOR_SEQ_INST_WAIT_TIME_SHIFT				(0)
+#define NV_SOR_SEQ_INST_WAIT_TIME_DEFAULT_MASK			(0x3ff)
+#define NV_SOR_PWM_DIV						(0x32)
+#define NV_SOR_PWM_DIV_DIVIDE_DEFAULT_MASK			(0xffffff)
+#define NV_SOR_PWM_CTL						(0x33)
+#define NV_SOR_PWM_CTL_SETTING_NEW_SHIFT			(31)
+#define NV_SOR_PWM_CTL_SETTING_NEW_DONE				(0 << 31)
+#define NV_SOR_PWM_CTL_SETTING_NEW_PENDING			(1 << 31)
+#define NV_SOR_PWM_CTL_SETTING_NEW_TRIGGER			(1 << 31)
+#define NV_SOR_PWM_CTL_CLKSEL_SHIFT				(30)
+#define NV_SOR_PWM_CTL_CLKSEL_PCLK				(0 << 30)
+#define NV_SOR_PWM_CTL_CLKSEL_XTAL				(1 << 30)
+#define NV_SOR_PWM_CTL_DUTY_CYCLE_SHIFT				(0)
+#define NV_SOR_PWM_CTL_DUTY_CYCLE_MASK				(0xffffff)
+#define NV_SOR_MSCHECK						(0x49)
+#define NV_SOR_MSCHECK_CTL_SHIFT				(31)
+#define NV_SOR_MSCHECK_CTL_CLEAR				(0 << 31)
+#define NV_SOR_MSCHECK_CTL_RUN					(1 << 31)
+#define NV_SOR_XBAR_CTRL					(0x4a)
+#define NV_SOR_DP_LINKCTL(i)					(0x4c + (i))
+#define NV_SOR_DP_LINKCTL_FORCE_IDLEPTTRN_SHIFT			(31)
+#define NV_SOR_DP_LINKCTL_FORCE_IDLEPTTRN_NO			(0 << 31)
+#define NV_SOR_DP_LINKCTL_FORCE_IDLEPTTRN_YES			(1 << 31)
+#define NV_SOR_DP_LINKCTL_COMPLIANCEPTTRN_SHIFT			(28)
+#define NV_SOR_DP_LINKCTL_COMPLIANCEPTTRN_NOPATTERN		(0 << 28)
+#define NV_SOR_DP_LINKCTL_COMPLIANCEPTTRN_COLORSQARE		(1 << 28)
+#define NV_SOR_DP_LINKCTL_LANECOUNT_SHIFT			(16)
+#define NV_SOR_DP_LINKCTL_LANECOUNT_MASK			(0x1f << 16)
+#define NV_SOR_DP_LINKCTL_LANECOUNT_ZERO			(0 << 16)
+#define NV_SOR_DP_LINKCTL_LANECOUNT_ONE				(1 << 16)
+#define NV_SOR_DP_LINKCTL_LANECOUNT_TWO				(3 << 16)
+#define NV_SOR_DP_LINKCTL_LANECOUNT_FOUR			(15 << 16)
+#define NV_SOR_DP_LINKCTL_ENHANCEDFRAME_SHIFT			(14)
+#define NV_SOR_DP_LINKCTL_ENHANCEDFRAME_DISABLE			(0 << 14)
+#define NV_SOR_DP_LINKCTL_ENHANCEDFRAME_ENABLE			(1 << 14)
+#define NV_SOR_DP_LINKCTL_SYNCMODE_SHIFT			(10)
+#define NV_SOR_DP_LINKCTL_SYNCMODE_DISABLE			(0 << 10)
+#define NV_SOR_DP_LINKCTL_SYNCMODE_ENABLE			(1 << 10)
+#define NV_SOR_DP_LINKCTL_TUSIZE_SHIFT				(2)
+#define NV_SOR_DP_LINKCTL_TUSIZE_MASK				(0x7f << 2)
+#define NV_SOR_DP_LINKCTL_ENABLE_SHIFT				(0)
+#define NV_SOR_DP_LINKCTL_ENABLE_NO				(0)
+#define NV_SOR_DP_LINKCTL_ENABLE_YES				(1)
+#define NV_SOR_DC(i)						(0x4e + (i))
+#define NV_SOR_DC_LANE3_DP_LANE3_SHIFT				(24)
+#define NV_SOR_DC_LANE3_DP_LANE3_MASK				(0xff << 24)
+#define NV_SOR_DC_LANE3_DP_LANE3_P0_LEVEL0			(17 << 24)
+#define NV_SOR_DC_LANE3_DP_LANE3_P1_LEVEL0			(21 << 24)
+#define NV_SOR_DC_LANE3_DP_LANE3_P2_LEVEL0			(26 << 24)
+#define NV_SOR_DC_LANE3_DP_LANE3_P3_LEVEL0			(34 << 24)
+#define NV_SOR_DC_LANE3_DP_LANE3_P0_LEVEL1			(26 << 24)
+#define NV_SOR_DC_LANE3_DP_LANE3_P1_LEVEL1			(32 << 24)
+#define NV_SOR_DC_LANE3_DP_LANE3_P2_LEVEL1			(39 << 24)
+#define NV_SOR_DC_LANE3_DP_LANE3_P0_LEVEL2			(34 << 24)
+#define NV_SOR_DC_LANE3_DP_LANE3_P1_LEVEL2			(43 << 24)
+#define NV_SOR_DC_LANE3_DP_LANE3_P0_LEVEL3			(51 << 24)
+#define NV_SOR_DC_LANE2_DP_LANE0_SHIFT				(16)
+#define NV_SOR_DC_LANE2_DP_LANE0_MASK				(0xff << 16)
+#define NV_SOR_DC_LANE2_DP_LANE0_P0_LEVEL0			(17 << 16)
+#define NV_SOR_DC_LANE2_DP_LANE0_P1_LEVEL0			(21 << 16)
+#define NV_SOR_DC_LANE2_DP_LANE0_P2_LEVEL0			(26 << 16)
+#define NV_SOR_DC_LANE2_DP_LANE0_P3_LEVEL0			(34 << 16)
+#define NV_SOR_DC_LANE2_DP_LANE0_P0_LEVEL1			(26 << 16)
+#define NV_SOR_DC_LANE2_DP_LANE0_P1_LEVEL1			(32 << 16)
+#define NV_SOR_DC_LANE2_DP_LANE0_P2_LEVEL1			(39 << 16)
+#define NV_SOR_DC_LANE2_DP_LANE0_P0_LEVEL2			(34 << 16)
+#define NV_SOR_DC_LANE2_DP_LANE0_P1_LEVEL2			(43 << 16)
+#define NV_SOR_DC_LANE2_DP_LANE0_P0_LEVEL3			(51 << 16)
+#define NV_SOR_DC_LANE1_DP_LANE1_SHIFT				(8)
+#define NV_SOR_DC_LANE1_DP_LANE1_MASK				(0xff << 8)
+#define NV_SOR_DC_LANE1_DP_LANE1_P0_LEVEL0			(17 << 8)
+#define NV_SOR_DC_LANE1_DP_LANE1_P1_LEVEL0			(21 << 8)
+#define NV_SOR_DC_LANE1_DP_LANE1_P2_LEVEL0			(26 << 8)
+#define NV_SOR_DC_LANE1_DP_LANE1_P3_LEVEL0			(34 << 8)
+#define NV_SOR_DC_LANE1_DP_LANE1_P0_LEVEL1			(26 << 8)
+#define NV_SOR_DC_LANE1_DP_LANE1_P1_LEVEL1			(32 << 8)
+#define NV_SOR_DC_LANE1_DP_LANE1_P2_LEVEL1			(39 << 8)
+#define NV_SOR_DC_LANE1_DP_LANE1_P0_LEVEL2			(34 << 8)
+#define NV_SOR_DC_LANE1_DP_LANE1_P1_LEVEL2			(43 << 8)
+#define NV_SOR_DC_LANE1_DP_LANE1_P0_LEVEL3			(51 << 8)
+#define NV_SOR_DC_LANE0_DP_LANE2_SHIFT				(0)
+#define NV_SOR_DC_LANE0_DP_LANE2_MASK				(0xff)
+#define NV_SOR_DC_LANE0_DP_LANE2_P0_LEVEL0			(17)
+#define NV_SOR_DC_LANE0_DP_LANE2_P1_LEVEL0			(21)
+#define NV_SOR_DC_LANE0_DP_LANE2_P2_LEVEL0			(26)
+#define NV_SOR_DC_LANE0_DP_LANE2_P3_LEVEL0			(34)
+#define NV_SOR_DC_LANE0_DP_LANE2_P0_LEVEL1			(26)
+#define NV_SOR_DC_LANE0_DP_LANE2_P1_LEVEL1			(32)
+#define NV_SOR_DC_LANE0_DP_LANE2_P2_LEVEL1			(39)
+#define NV_SOR_DC_LANE0_DP_LANE2_P0_LEVEL2			(34)
+#define NV_SOR_DC_LANE0_DP_LANE2_P1_LEVEL2			(43)
+#define NV_SOR_DC_LANE0_DP_LANE2_P0_LEVEL3			(51)
+#define NV_SOR_LANE_DRIVE_CURRENT(i)				(0x4e + (i))
+#define NV_SOR_PR(i)						(0x52 + (i))
+#define NV_SOR_PR_LANE3_DP_LANE3_SHIFT				(24)
+#define NV_SOR_PR_LANE3_DP_LANE3_MASK				(0xff << 24)
+#define NV_SOR_PR_LANE3_DP_LANE3_D0_LEVEL0			(0 << 24)
+#define NV_SOR_PR_LANE3_DP_LANE3_D1_LEVEL0			(0 << 24)
+#define NV_SOR_PR_LANE3_DP_LANE3_D2_LEVEL0			(0 << 24)
+#define NV_SOR_PR_LANE3_DP_LANE3_D3_LEVEL0			(0 << 24)
+#define NV_SOR_PR_LANE3_DP_LANE3_D0_LEVEL1			(4 << 24)
+#define NV_SOR_PR_LANE3_DP_LANE3_D1_LEVEL1			(6 << 24)
+#define NV_SOR_PR_LANE3_DP_LANE3_D2_LEVEL1			(17 << 24)
+#define NV_SOR_PR_LANE3_DP_LANE3_D0_LEVEL2			(8 << 24)
+#define NV_SOR_PR_LANE3_DP_LANE3_D1_LEVEL2			(13 << 24)
+#define NV_SOR_PR_LANE3_DP_LANE3_D0_LEVEL3			(17 << 24)
+#define NV_SOR_PR_LANE2_DP_LANE0_SHIFT				(16)
+#define NV_SOR_PR_LANE2_DP_LANE0_MASK				(0xff << 16)
+#define NV_SOR_PR_LANE2_DP_LANE0_D0_LEVEL0			(0 << 16)
+#define NV_SOR_PR_LANE2_DP_LANE0_D1_LEVEL0			(0 << 16)
+#define NV_SOR_PR_LANE2_DP_LANE0_D2_LEVEL0			(0 << 16)
+#define NV_SOR_PR_LANE2_DP_LANE0_D3_LEVEL0			(0 << 16)
+#define NV_SOR_PR_LANE2_DP_LANE0_D0_LEVEL1			(4 << 16)
+#define NV_SOR_PR_LANE2_DP_LANE0_D1_LEVEL1			(6 << 16)
+#define NV_SOR_PR_LANE2_DP_LANE0_D2_LEVEL1			(17 << 16)
+#define NV_SOR_PR_LANE2_DP_LANE0_D0_LEVEL2			(8 << 16)
+#define NV_SOR_PR_LANE2_DP_LANE0_D1_LEVEL2			(13 << 16)
+#define NV_SOR_PR_LANE2_DP_LANE0_D0_LEVEL3			(17 << 16)
+#define NV_SOR_PR_LANE1_DP_LANE1_SHIFT				(8)
+#define NV_SOR_PR_LANE1_DP_LANE1_MASK				(0xff >> 8)
+#define NV_SOR_PR_LANE1_DP_LANE1_D0_LEVEL0			(0 >> 8)
+#define NV_SOR_PR_LANE1_DP_LANE1_D1_LEVEL0			(0 >> 8)
+#define NV_SOR_PR_LANE1_DP_LANE1_D2_LEVEL0			(0 >> 8)
+#define NV_SOR_PR_LANE1_DP_LANE1_D3_LEVEL0			(0 >> 8)
+#define NV_SOR_PR_LANE1_DP_LANE1_D0_LEVEL1			(4 >> 8)
+#define NV_SOR_PR_LANE1_DP_LANE1_D1_LEVEL1			(6 >> 8)
+#define NV_SOR_PR_LANE1_DP_LANE1_D2_LEVEL1			(17 >> 8)
+#define NV_SOR_PR_LANE1_DP_LANE1_D0_LEVEL2			(8 >> 8)
+#define NV_SOR_PR_LANE1_DP_LANE1_D1_LEVEL2			(13 >> 8)
+#define NV_SOR_PR_LANE1_DP_LANE1_D0_LEVEL3			(17 >> 8)
+#define NV_SOR_PR_LANE0_DP_LANE2_SHIFT				(0)
+#define NV_SOR_PR_LANE0_DP_LANE2_MASK				(0xff)
+#define NV_SOR_PR_LANE0_DP_LANE2_D0_LEVEL0			(0)
+#define NV_SOR_PR_LANE0_DP_LANE2_D1_LEVEL0			(0)
+#define NV_SOR_PR_LANE0_DP_LANE2_D2_LEVEL0			(0)
+#define NV_SOR_PR_LANE0_DP_LANE2_D3_LEVEL0			(0)
+#define NV_SOR_PR_LANE0_DP_LANE2_D0_LEVEL1			(4)
+#define NV_SOR_PR_LANE0_DP_LANE2_D1_LEVEL1			(6)
+#define NV_SOR_PR_LANE0_DP_LANE2_D2_LEVEL1			(17)
+#define NV_SOR_PR_LANE0_DP_LANE2_D0_LEVEL2			(8)
+#define NV_SOR_PR_LANE0_DP_LANE2_D1_LEVEL2			(13)
+#define NV_SOR_PR_LANE0_DP_LANE2_D0_LEVEL3			(17)
+#define NV_SOR_LANE4_PREEMPHASIS(i)				(0x54 + (i))
+#define NV_SOR_POSTCURSOR(i)					(0x56 + (i))
+#define NV_SOR_DP_CONFIG(i)					(0x58 + (i))
+#define NV_SOR_DP_CONFIG_RD_RESET_VAL_SHIFT			(31)
+#define NV_SOR_DP_CONFIG_RD_RESET_VAL_POSITIVE			(0 << 31)
+#define NV_SOR_DP_CONFIG_RD_RESET_VAL_NEGATIVE			(1 << 31)
+#define NV_SOR_DP_CONFIG_IDLE_BEFORE_ATTACH_SHIFT		(28)
+#define NV_SOR_DP_CONFIG_IDLE_BEFORE_ATTACH_DISABLE		(0 << 28)
+#define NV_SOR_DP_CONFIG_IDLE_BEFORE_ATTACH_ENABLE		(1 << 28)
+#define NV_SOR_DP_CONFIG_ACTIVESYM_CNTL_SHIFT			(26)
+#define NV_SOR_DP_CONFIG_ACTIVESYM_CNTL_DISABLE			(0 << 26)
+#define NV_SOR_DP_CONFIG_ACTIVESYM_CNTL_ENABLE			(1 << 26)
+#define NV_SOR_DP_CONFIG_ACTIVESYM_POLARITY_SHIFT		(24)
+#define NV_SOR_DP_CONFIG_ACTIVESYM_POLARITY_NEGATIVE		(0 << 24)
+#define NV_SOR_DP_CONFIG_ACTIVESYM_POLARITY_POSITIVE		(1 << 24)
+#define NV_SOR_DP_CONFIG_ACTIVESYM_FRAC_SHIFT			(16)
+#define NV_SOR_DP_CONFIG_ACTIVESYM_FRAC_MASK			(0xf << 16)
+#define NV_SOR_DP_CONFIG_ACTIVESYM_COUNT_SHIFT			(8)
+#define NV_SOR_DP_CONFIG_ACTIVESYM_COUNT_MASK			(0x7f << 8)
+#define NV_SOR_DP_CONFIG_WATERMARK_SHIFT			(0)
+#define NV_SOR_DP_CONFIG_WATERMARK_MASK				(0x3f)
+#define NV_SOR_DP_MN(i)						(0x5a + i)
+#define NV_SOR_DP_MN_M_MOD_SHIFT				(30)
+#define NV_SOR_DP_MN_M_MOD_DEFAULT_MASK				(0x3 << 30)
+#define NV_SOR_DP_MN_M_MOD_NONE					(0 << 30)
+#define NV_SOR_DP_MN_M_MOD_INC					(1 << 30)
+#define NV_SOR_DP_MN_M_MOD_DEC					(2 << 30)
+#define NV_SOR_DP_MN_M_DELTA_SHIFT				(24)
+#define NV_SOR_DP_MN_M_DELTA_DEFAULT_MASK			(0xf << 24)
+#define NV_SOR_DP_MN_N_VAL_SHIFT				(0)
+#define NV_SOR_DP_MN_N_VAL_DEFAULT_MASK				(0xffffff)
+#define NV_SOR_DP_PADCTL(i)					(0x5c + (i))
+#define NV_SOR_DP_PADCTL_SPARE_SHIFT				(25)
+#define NV_SOR_DP_PADCTL_SPARE_DEFAULT_MASK			(0x7f << 25)
+#define NV_SOR_DP_PADCTL_VCO_2X_SHIFT				(24)
+#define NV_SOR_DP_PADCTL_VCO_2X_DISABLE				(0 << 24)
+#define NV_SOR_DP_PADCTL_VCO_2X_ENABLE				(1 << 24)
+#define NV_SOR_DP_PADCTL_PAD_CAL_PD_SHIFT			(23)
+#define NV_SOR_DP_PADCTL_PAD_CAL_PD_POWERUP			(0 << 23)
+#define NV_SOR_DP_PADCTL_PAD_CAL_PD_POWERDOWN			(1 << 23)
+#define NV_SOR_DP_PADCTL_TX_PU_SHIFT				(22)
+#define NV_SOR_DP_PADCTL_TX_PU_DISABLE				(0 << 22)
+#define NV_SOR_DP_PADCTL_TX_PU_ENABLE				(1 << 22)
+#define NV_SOR_DP_PADCTL_TX_PU_MASK				(1 << 22)
+#define NV_SOR_DP_PADCTL_REG_CTRL_SHIFT				(20)
+#define NV_SOR_DP_PADCTL_REG_CTRL_DEFAULT_MASK			(0x3 << 20)
+#define NV_SOR_DP_PADCTL_VCMMODE_SHIFT				(16)
+#define NV_SOR_DP_PADCTL_VCMMODE_DEFAULT_MASK			(0xf << 16)
+#define NV_SOR_DP_PADCTL_VCMMODE_TRISTATE			(0 << 16)
+#define NV_SOR_DP_PADCTL_VCMMODE_TEST_MUX			(1 << 16)
+#define NV_SOR_DP_PADCTL_VCMMODE_WEAK_PULLDOWN			(2 << 16)
+#define NV_SOR_DP_PADCTL_VCMMODE_STRONG_PULLDOWN		(4 << 16)
+#define NV_SOR_DP_PADCTL_TX_PU_VALUE_SHIFT			(8)
+#define NV_SOR_DP_PADCTL_TX_PU_VALUE_DEFAULT_MASK		(0xff << 8)
+#define NV_SOR_DP_PADCTL_COMODE_TXD_3_DP_TXD_3_SHIFT		(7)
+#define NV_SOR_DP_PADCTL_COMODE_TXD_3_DP_TXD_3_DISABLE		(0 << 7)
+#define NV_SOR_DP_PADCTL_COMODE_TXD_3_DP_TXD_3_ENABLE		(1 << 7)
+#define NV_SOR_DP_PADCTL_COMODE_TXD_2_DP_TXD_0_SHIFT		(6)
+#define NV_SOR_DP_PADCTL_COMODE_TXD_2_DP_TXD_0_DISABLE		(0 << 6)
+#define NV_SOR_DP_PADCTL_COMODE_TXD_2_DP_TXD_0_ENABLE		(1 << 6)
+#define NV_SOR_DP_PADCTL_COMODE_TXD_1_DP_TXD_1_SHIFT		(5)
+#define NV_SOR_DP_PADCTL_COMODE_TXD_1_DP_TXD_1_DISABLE		(0 << 5)
+#define NV_SOR_DP_PADCTL_COMODE_TXD_1_DP_TXD_1_ENABLE		(1 << 5)
+#define NV_SOR_DP_PADCTL_COMODE_TXD_0_DP_TXD_2_SHIFT		(4)
+#define NV_SOR_DP_PADCTL_COMODE_TXD_0_DP_TXD_2_DISABLE		(0 << 4)
+#define NV_SOR_DP_PADCTL_COMODE_TXD_0_DP_TXD_2_ENABLE		(1 << 4)
+#define NV_SOR_DP_PADCTL_PD_TXD_3_SHIFT				(3)
+#define NV_SOR_DP_PADCTL_PD_TXD_3_YES				(0 << 3)
+#define NV_SOR_DP_PADCTL_PD_TXD_3_NO				(1 << 3)
+#define NV_SOR_DP_PADCTL_PD_TXD_0_SHIFT				(2)
+#define NV_SOR_DP_PADCTL_PD_TXD_0_YES				(0 << 2)
+#define NV_SOR_DP_PADCTL_PD_TXD_0_NO				(1 << 2)
+#define NV_SOR_DP_PADCTL_PD_TXD_1_SHIFT				(1)
+#define NV_SOR_DP_PADCTL_PD_TXD_1_YES				(0 << 1)
+#define NV_SOR_DP_PADCTL_PD_TXD_1_NO				(1 << 1)
+#define NV_SOR_DP_PADCTL_PD_TXD_2_SHIFT				(0)
+#define NV_SOR_DP_PADCTL_PD_TXD_2_YES				(0)
+#define NV_SOR_DP_PADCTL_PD_TXD_2_NO				(1)
+#define NV_SOR_DP_DEBUG(i)					(0x5e + i)
+#define NV_SOR_DP_SPARE(i)					(0x60 + (i))
+#define NV_SOR_DP_SPARE_REG_SHIFT				(3)
+#define NV_SOR_DP_SPARE_REG_DEFAULT_MASK			(0x1fffffff << 3)
+#define NV_SOR_DP_SPARE_SOR_CLK_SEL_SHIFT			(2)
+#define NV_SOR_DP_SPARE_SOR_CLK_SEL_DEFAULT_MASK		(0x1 << 2)
+#define NV_SOR_DP_SPARE_SOR_CLK_SEL_SAFE_SORCLK			(0 << 2)
+#define NV_SOR_DP_SPARE_SOR_CLK_SEL_MACRO_SORCLK		(1 << 2)
+#define NV_SOR_DP_SPARE_PANEL_SHIFT				(1)
+#define NV_SOR_DP_SPARE_PANEL_EXTERNAL				(0 << 1)
+#define NV_SOR_DP_SPARE_PANEL_INTERNAL				(1 << 1)
+#define NV_SOR_DP_SPARE_SEQ_ENABLE_SHIFT			(0)
+#define NV_SOR_DP_SPARE_SEQ_ENABLE_NO				(0)
+#define NV_SOR_DP_SPARE_SEQ_ENABLE_YES				(1)
+#define NV_SOR_DP_AUDIO_CTRL					(0x62)
+#define NV_SOR_DP_AUDIO_HBLANK_SYMBOLS				(0x63)
+#define NV_SOR_DP_AUDIO_HBLANK_SYMBOLS_MASK			(0x1ffff)
+#define NV_SOR_DP_AUDIO_HBLANK_SYMBOLS_VALUE_SHIFT		(0)
+#define NV_SOR_DP_AUDIO_VBLANK_SYMBOLS				(0x64)
+#define NV_SOR_DP_AUDIO_VBLANK_SYMBOLS_MASK			(0x1ffff)
+#define NV_SOR_DP_AUDIO_VBLANK_SYMBOLS_SHIFT			(0)
+#define NV_SOR_DP_GENERIC_INFOFRAME_HEADER			(0x65)
+#define NV_SOR_DP_GENERIC_INFOFRAME_SUBPACK(i)			(0x66 + (i))
+#define NV_SOR_DP_TPG						(0x6d)
+#define NV_SOR_DP_TPG_LANE3_CHANNELCODING_SHIFT			(30)
+#define NV_SOR_DP_TPG_LANE3_CHANNELCODING_DISABLE		(0 << 30)
+#define NV_SOR_DP_TPG_LANE3_CHANNELCODING_ENABLE		(1 << 30)
+#define NV_SOR_DP_TPG_LANE3_SCRAMBLEREN_SHIFT			(28)
+#define NV_SOR_DP_TPG_LANE3_SCRAMBLEREN_ENABLE_GALIOS		(1 << 28)
+#define NV_SOR_DP_TPG_LANE3_SCRAMBLEREN_ENABLE_FIBONACCI	(2 << 28)
+#define NV_SOR_DP_TPG_LANE3_PATTERN_SHIFT			(24)
+#define NV_SOR_DP_TPG_LANE3_PATTERN_DEFAULT_MASK		(0xf << 24)
+#define NV_SOR_DP_TPG_LANE3_PATTERN_NOPATTERN			(0 << 24)
+#define NV_SOR_DP_TPG_LANE3_PATTERN_TRAINING1			(1 << 24)
+#define NV_SOR_DP_TPG_LANE3_PATTERN_TRAINING2			(2 << 24)
+#define NV_SOR_DP_TPG_LANE3_PATTERN_TRAINING3			(3 << 24)
+#define NV_SOR_DP_TPG_LANE3_PATTERN_D102			(4 << 24)
+#define NV_SOR_DP_TPG_LANE3_PATTERN_SBLERRRATE			(5 << 24)
+#define NV_SOR_DP_TPG_LANE3_PATTERN_PRBS7			(6 << 24)
+#define NV_SOR_DP_TPG_LANE3_PATTERN_CSTM			(7 << 24)
+#define NV_SOR_DP_TPG_LANE3_PATTERN_HBR2_COMPLIANCE		(8 << 24)
+#define NV_SOR_DP_TPG_LANE2_CHANNELCODING_SHIFT			(22)
+#define NV_SOR_DP_TPG_LANE2_CHANNELCODING_DISABLE		(0 << 22)
+#define NV_SOR_DP_TPG_LANE2_CHANNELCODING_ENABLE		(1 << 22)
+#define NV_SOR_DP_TPG_LANE2_SCRAMBLEREN_SHIFT			(20)
+#define NV_SOR_DP_TPG_LANE2_SCRAMBLEREN_DEFAULT_MASK		(0x3 << 20)
+#define NV_SOR_DP_TPG_LANE2_SCRAMBLEREN_DISABLE			(0 << 20)
+#define NV_SOR_DP_TPG_LANE2_SCRAMBLEREN_ENABLE_GALIOS		(1 << 20)
+#define NV_SOR_DP_TPG_LANE2_SCRAMBLEREN_ENABLE_FIBONACCI	(2 << 20)
+#define NV_SOR_DP_TPG_LANE2_PATTERN_SHIFT			(16)
+#define NV_SOR_DP_TPG_LANE2_PATTERN_DEFAULT_MASK		(0xf << 16)
+#define NV_SOR_DP_TPG_LANE2_PATTERN_NOPATTERN			(0 << 16)
+#define NV_SOR_DP_TPG_LANE2_PATTERN_TRAINING1			(1 << 16)
+#define NV_SOR_DP_TPG_LANE2_PATTERN_TRAINING2			(2 << 16)
+#define NV_SOR_DP_TPG_LANE2_PATTERN_TRAINING3			(3 << 16)
+#define NV_SOR_DP_TPG_LANE2_PATTERN_D102			(4 << 16)
+#define NV_SOR_DP_TPG_LANE2_PATTERN_SBLERRRATE			(5 << 16)
+#define NV_SOR_DP_TPG_LANE2_PATTERN_PRBS7			(6 << 16)
+#define NV_SOR_DP_TPG_LANE2_PATTERN_CSTM			(7 << 16)
+#define NV_SOR_DP_TPG_LANE2_PATTERN_HBR2_COMPLIANCE		(8 << 16)
+#define NV_SOR_DP_TPG_LANE1_CHANNELCODING_SHIFT			(14)
+#define NV_SOR_DP_TPG_LANE1_CHANNELCODING_DISABLE		(0 << 14)
+#define NV_SOR_DP_TPG_LANE1_CHANNELCODING_ENABLE		(1 << 14)
+#define NV_SOR_DP_TPG_LANE1_SCRAMBLEREN_SHIFT			(12)
+#define NV_SOR_DP_TPG_LANE1_SCRAMBLEREN_DEFAULT_MASK		(0x3 << 12)
+#define NV_SOR_DP_TPG_LANE1_SCRAMBLEREN_DISABLE			(0 << 12)
+#define NV_SOR_DP_TPG_LANE1_SCRAMBLEREN_ENABLE_GALIOS		(1 << 12)
+#define NV_SOR_DP_TPG_LANE1_SCRAMBLEREN_ENABLE_FIBONACCI	(2 << 12)
+#define NV_SOR_DP_TPG_LANE1_PATTERN_SHIFT			(8)
+#define NV_SOR_DP_TPG_LANE1_PATTERN_DEFAULT_MASK		(0xf << 8)
+#define NV_SOR_DP_TPG_LANE1_PATTERN_NOPATTERN			(0 << 8)
+#define NV_SOR_DP_TPG_LANE1_PATTERN_TRAINING1			(1 << 8)
+#define NV_SOR_DP_TPG_LANE1_PATTERN_TRAINING2			(2 << 8)
+#define NV_SOR_DP_TPG_LANE1_PATTERN_TRAINING3			(3 << 8)
+#define NV_SOR_DP_TPG_LANE1_PATTERN_D102			(4 << 8)
+#define NV_SOR_DP_TPG_LANE1_PATTERN_SBLERRRATE			(5 << 8)
+#define NV_SOR_DP_TPG_LANE1_PATTERN_PRBS7			(6 << 8)
+#define NV_SOR_DP_TPG_LANE1_PATTERN_CSTM			(7 << 8)
+#define NV_SOR_DP_TPG_LANE1_PATTERN_HBR2_COMPLIANCE		(8 << 8)
+#define NV_SOR_DP_TPG_LANE0_CHANNELCODING_SHIFT			(6)
+#define NV_SOR_DP_TPG_LANE0_CHANNELCODING_DISABLE		(0 << 6)
+#define NV_SOR_DP_TPG_LANE0_CHANNELCODING_ENABLE		(1 << 6)
+#define NV_SOR_DP_TPG_LANE0_SCRAMBLEREN_SHIFT			(4)
+#define NV_SOR_DP_TPG_LANE0_SCRAMBLEREN_DEFAULT_MASK		(0x3 << 4)
+#define NV_SOR_DP_TPG_LANE0_SCRAMBLEREN_DISABLE			(0 << 4)
+#define NV_SOR_DP_TPG_LANE0_SCRAMBLEREN_ENABLE_GALIOS		(1 << 4)
+#define NV_SOR_DP_TPG_LANE0_SCRAMBLEREN_ENABLE_FIBONACCI	(2 << 4)
+#define NV_SOR_DP_TPG_LANE0_PATTERN_SHIFT			(0)
+#define NV_SOR_DP_TPG_LANE0_PATTERN_DEFAULT_MASK		(0xf)
+#define NV_SOR_DP_TPG_LANE0_PATTERN_NOPATTERN			(0)
+#define NV_SOR_DP_TPG_LANE0_PATTERN_TRAINING1			(1)
+#define NV_SOR_DP_TPG_LANE0_PATTERN_TRAINING2			(2)
+#define NV_SOR_DP_TPG_LANE0_PATTERN_TRAINING3			(3)
+#define NV_SOR_DP_TPG_LANE0_PATTERN_D102			(4)
+#define NV_SOR_DP_TPG_LANE0_PATTERN_SBLERRRATE			(5)
+#define NV_SOR_DP_TPG_LANE0_PATTERN_PRBS7			(6)
+#define NV_SOR_DP_TPG_LANE0_PATTERN_CSTM			(7)
+#define NV_SOR_DP_TPG_LANE0_PATTERN_HBR2_COMPLIANCE		(8)
+
+enum {
+	training_pattern_disabled	= 0,
+	training_pattern_1		= 1,
+	training_pattern_2		= 2,
+	training_pattern_3		= 3,
+	training_pattern_none		= 0xff
+};
+
+enum tegra_dc_sor_protocol {
+	SOR_DP,
+	SOR_LVDS,
+};
+
+#define SOR_LINK_SPEED_G1_62	6
+#define SOR_LINK_SPEED_G2_7	10
+#define SOR_LINK_SPEED_G5_4	20
+#define SOR_LINK_SPEED_LVDS	7
+
+/* todo: combine this and the intel_dp struct into one struct. */
+struct tegra_dc_dp_link_config {
+	int	is_valid;
+
+	/* Supported configuration */
+	u8	max_link_bw;
+	u8	max_lane_count;
+	int	downspread;
+	int	support_enhanced_framing;
+	u32	bits_per_pixel;
+	int	alt_scramber_reset_cap; /* true for eDP */
+	int	only_enhanced_framing;	/* enhanced_frame_en ignored */
+
+	/* Actual configuration */
+	u8	link_bw;
+	u8	lane_count;
+	int	enhanced_framing;
+	int	scramble_ena;
+
+	u32	activepolarity;
+	u32	active_count;
+	u32	tu_size;
+	u32	active_frac;
+	u32	watermark;
+
+	s32	hblank_sym;
+	s32	vblank_sym;
+
+	/* Training data */
+	u32	drive_current;
+	u32     preemphasis;
+	u32	postcursor;
+	u8	aux_rd_interval;
+	u8	tps3_supported;
+};
+
+/* TODO: just pull these up into one struct? Need to see how this impacts
+ * having two channels.
+ */
+struct tegra_dc_sor_data {
+	struct tegra_dc			*dc;
+	void				*base;
+	void				*pmc_base;
+	u8				 portnum;	/* 0 or 1 */
+	struct tegra_dc_dp_link_config *link_cfg;
+	int   power_is_up;
+};
+
+#define TEGRA_SOR_TIMEOUT_MS		1000
+#define TEGRA_SOR_ATTACH_TIMEOUT_MS	1000
+#define TEGRA_DC_POLL_TIMEOUT_MS	50
+
+#define CHECK_RET(x)			\
+	do {				\
+		ret = (x);		\
+		if (ret != 0)		\
+			return ret;	\
+	} while (0)
+
+void tegra_dc_sor_enable_dp(struct tegra_dc_sor_data *sor);
+int tegra_dc_sor_set_power_state(struct tegra_dc_sor_data *sor, int pu_pd);
+void tegra_dc_sor_set_dp_linkctl(struct tegra_dc_sor_data *sor, int ena,
+	u8 training_pattern, const struct tegra_dc_dp_link_config *link_cfg);
+void tegra_dc_sor_set_link_bandwidth(struct tegra_dc_sor_data *sor, u8 link_bw);
+void tegra_dc_sor_set_lane_count(struct tegra_dc_sor_data *sor, u8 lane_count);
+void tegra_dc_sor_set_panel_power(struct tegra_dc_sor_data *sor,
+				  int power_up);
+void tegra_dc_sor_set_internal_panel(struct tegra_dc_sor_data *sor, int is_int);
+void tegra_dc_sor_read_link_config(struct tegra_dc_sor_data *sor, u8 *link_bw,
+				   u8 *lane_count);
+void tegra_dc_sor_attach(struct tegra_dc_sor_data *sor);
+void tegra_dc_sor_set_lane_parm(struct tegra_dc_sor_data *sor,
+			const struct tegra_dc_dp_link_config *link_cfg);
+void tegra_dc_sor_power_down_unused_lanes(struct tegra_dc_sor_data *sor);
+void tegra_dc_sor_set_voltage_swing(struct tegra_dc_sor_data *sor);
+void tegra_sor_precharge_lanes(struct tegra_dc_sor_data *sor);
+void tegra_dp_disable_tx_pu(struct tegra_dc_sor_data *sor);
+void tegra_dp_set_pe_vs_pc(struct tegra_dc_sor_data *sor, u32 mask,
+			u32 pe_reg, u32 vs_reg, u32 pc_reg, u8 pc_supported);
+void tegra_dc_detach(struct tegra_dc_sor_data *sor);
+#endif /*__TEGRA210_SOR_H__ */
diff --git a/src/soc/nvidia/tegra210/include/soc/spi.h b/src/soc/nvidia/tegra210/include/soc/spi.h
new file mode 100644
index 0000000..b76622a
--- /dev/null
+++ b/src/soc/nvidia/tegra210/include/soc/spi.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright 2014 Google Inc.
+ * Copyright (c) 2013-2015, NVIDIA CORPORATION.  All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __NVIDIA_TEGRA210_SPI_H__
+#define __NVIDIA_TEGRA210_SPI_H__
+
+#include <soc/dma.h>
+#include <spi-generic.h>
+#include <stddef.h>
+
+struct tegra_spi_regs {
+	u32 command1;		/* 0x000: SPI_COMMAND1 */
+	u32 command2;		/* 0x004: SPI_COMMAND2 */
+	u32 timing1;		/* 0x008: SPI_CS_TIM1 */
+	u32 timing2;		/* 0x00c: SPI_CS_TIM2 */
+	u32 trans_status;	/* 0x010: SPI_TRANS_STATUS */
+	u32 fifo_status;	/* 0x014: SPI_FIFO_STATUS */
+	u32 tx_data;		/* 0x018: SPI_TX_DATA */
+	u32 rx_data;		/* 0x01c: SPI_RX_DATA */
+	u32 dma_ctl;		/* 0x020: SPI_DMA_CTL */
+	u32 dma_blk;		/* 0x024: SPI_DMA_BLK */
+	u32 rsvd[56];		/* 0x028-0x107: reserved */
+	u32 tx_fifo;		/* 0x108: SPI_FIFO1 */
+	u32 rsvd2[31];		/* 0x10c-0x187 reserved */
+	u32 rx_fifo;		/* 0x188: SPI_FIFO2 */
+	u32 spare_ctl;		/* 0x18c: SPI_SPARE_CTRL */
+} __attribute__((packed));
+check_member(tegra_spi_regs, spare_ctl, 0x18c);
+
+enum spi_xfer_mode {
+	XFER_MODE_NONE = 0,
+	XFER_MODE_PIO,
+	XFER_MODE_DMA,
+};
+
+struct tegra_spi_channel {
+	struct tegra_spi_regs *regs;
+
+	/* static configuration */
+	struct spi_slave slave;
+	unsigned int req_sel;
+
+	int dual_mode;		/* for x2 transfers with bit interleaving */
+
+	/* context (used internally) */
+	u8 *in_buf, *out_buf;
+	struct apb_dma_channel *dma_out, *dma_in;
+	enum spi_xfer_mode xfer_mode;
+};
+
+struct tegra_spi_channel *tegra_spi_init(unsigned int bus);
+
+#endif	/* __NVIDIA_TEGRA210_SPI_H__ */
diff --git a/src/soc/nvidia/tegra210/include/soc/sysctr.h b/src/soc/nvidia/tegra210/include/soc/sysctr.h
new file mode 100644
index 0000000..e5a894c
--- /dev/null
+++ b/src/soc/nvidia/tegra210/include/soc/sysctr.h
@@ -0,0 +1,55 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright 2014 Google Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc.
+ */
+
+#ifndef __SOC_NVIDIA_TEGRA210_SYSCTR_H__
+#define __SOC_NVIDIA_TEGRA210_SYSCTR_H__
+
+#include <stdint.h>
+
+enum {
+	SYSCTR_CNTCR_EN = 1 << 0,
+	SYSCTR_CNTCR_HDBG = 1 << 1,
+	SYSCTR_CNTCR_FCREQ = 1 << 8
+};
+
+struct sysctr_regs {
+	uint32_t cntcr;
+	uint32_t cntsr;
+	uint32_t cntcv0;
+	uint32_t cntcv1;
+	uint8_t _rsv0[0x10];
+	uint32_t cntfid0;
+	uint32_t cntfid1;
+	uint8_t _rsv1[0xfa8];
+	uint32_t counterid4;
+	uint32_t counterid5;
+	uint32_t counterid6;
+	uint32_t counterid7;
+	uint32_t counterid0;
+	uint32_t counterid1;
+	uint32_t counterid2;
+	uint32_t counterid3;
+	uint32_t counterid8;
+	uint32_t counterid9;
+	uint32_t counterid10;
+	uint32_t counterid11;
+};
+check_member(sysctr_regs, counterid11, 0xffc);
+
+#endif	/* __SOC_NVIDIA_TEGRA210_SYSCTR_H__ */
diff --git a/src/soc/nvidia/tegra210/include/soc/tegra_dsi.h b/src/soc/nvidia/tegra210/include/soc/tegra_dsi.h
new file mode 100644
index 0000000..058e26f
--- /dev/null
+++ b/src/soc/nvidia/tegra210/include/soc/tegra_dsi.h
@@ -0,0 +1,223 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright 2014 Google Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc.
+ */
+#ifndef __TEGRA_DSI_H__
+#define __TEGRA_DSI_H__
+
+#define DSI_INCR_SYNCPT			0x00
+#define DSI_INCR_SYNCPT_CONTROL		0x01
+#define DSI_INCR_SYNCPT_ERROR		0x02
+#define DSI_CTXSW			0x08
+#define DSI_RD_DATA			0x09
+#define DSI_WR_DATA			0x0a
+#define DSI_POWER_CONTROL		0x0b
+#define DSI_POWER_CONTROL_ENABLE	(1 << 0)
+#define DSI_INT_ENABLE			0x0c
+#define DSI_INT_STATUS			0x0d
+#define DSI_INT_MASK			0x0e
+#define DSI_HOST_CONTROL		0x0f
+#define DSI_HOST_CONTROL_FIFO_RESET	(1 << 21)
+#define DSI_HOST_CONTROL_CRC_RESET	(1 << 20)
+#define DSI_HOST_CONTROL_TX_TRIG_SOL	(0 << 12)
+#define DSI_HOST_CONTROL_TX_TRIG_FIFO	(1 << 12)
+#define DSI_HOST_CONTROL_TX_TRIG_HOST	(2 << 12)
+#define DSI_HOST_CONTROL_RAW		(1 << 6)
+#define DSI_HOST_CONTROL_HS		(1 << 5)
+#define DSI_HOST_CONTROL_FIFO_SEL	(1 << 4)
+#define DSI_HOST_CONTROL_IMM_BTA	(1 << 3)
+#define DSI_HOST_CONTROL_PKT_BTA	(1 << 2)
+#define DSI_HOST_CONTROL_CS		(1 << 1)
+#define DSI_HOST_CONTROL_ECC		(1 << 0)
+#define DSI_CONTROL			0x10
+#define DSI_CONTROL_HS_CLK_CTRL		(1 << 20)
+#define DSI_CONTROL_CHANNEL(c)		(((c) & 0x3) << 16)
+#define DSI_CONTROL_FORMAT(f)		(((f) & 0x3) << 12)
+#define DSI_CONTROL_TX_TRIG(x)		(((x) & 0x3) <<  8)
+#define DSI_CONTROL_LANES(n)		(((n) & 0x3) <<  4)
+#define DSI_CONTROL_DCS_ENABLE		(1 << 3)
+#define DSI_CONTROL_SOURCE(s)		(((s) & 0x1) <<  2)
+#define DSI_CONTROL_VIDEO_ENABLE	(1 << 1)
+#define DSI_CONTROL_HOST_ENABLE		(1 << 0)
+#define DSI_SOL_DELAY			0x11
+#define DSI_MAX_THRESHOLD		0x12
+#define DSI_TRIGGER			0x13
+#define DSI_TRIGGER_HOST		(1 << 1)
+#define DSI_TRIGGER_VIDEO		(1 << 0)
+#define DSI_TX_CRC			0x14
+#define DSI_STATUS			0x15
+#define DSI_STATUS_IDLE			(1 << 10)
+#define DSI_STATUS_UNDERFLOW		(1 <<  9)
+#define DSI_STATUS_OVERFLOW		(1 <<  8)
+#define DSI_INIT_SEQ_CONTROL		0x1a
+#define DSI_INIT_SEQ_DATA_0		0x1b
+#define DSI_INIT_SEQ_DATA_1		0x1c
+#define DSI_INIT_SEQ_DATA_2		0x1d
+#define DSI_INIT_SEQ_DATA_3		0x1e
+#define DSI_INIT_SEQ_DATA_4		0x1f
+#define DSI_INIT_SEQ_DATA_5		0x20
+#define DSI_INIT_SEQ_DATA_6		0x21
+#define DSI_INIT_SEQ_DATA_7		0x22
+#define DSI_PKT_SEQ_0_LO		0x23
+#define DSI_PKT_SEQ_0_HI		0x24
+#define DSI_PKT_SEQ_1_LO		0x25
+#define DSI_PKT_SEQ_1_HI		0x26
+#define DSI_PKT_SEQ_2_LO		0x27
+#define DSI_PKT_SEQ_2_HI		0x28
+#define DSI_PKT_SEQ_3_LO		0x29
+#define DSI_PKT_SEQ_3_HI		0x2a
+#define DSI_PKT_SEQ_4_LO		0x2b
+#define DSI_PKT_SEQ_4_HI		0x2c
+#define DSI_PKT_SEQ_5_LO		0x2d
+#define DSI_PKT_SEQ_5_HI		0x2e
+#define DSI_DCS_CMDS			0x33
+#define DSI_PKT_LEN_0_1			0x34
+#define DSI_PKT_LEN_2_3			0x35
+#define DSI_PKT_LEN_4_5			0x36
+#define DSI_PKT_LEN_6_7			0x37
+#define DSI_PHY_TIMING_0		0x3c
+#define DSI_PHY_TIMING_1		0x3d
+#define DSI_PHY_TIMING_2		0x3e
+#define DSI_BTA_TIMING			0x3f
+
+#define DSI_TIMING_FIELD(value, period, hwinc) \
+	((DIV_ROUND_CLOSEST(value, period) - (hwinc)) & 0xff)
+
+#define DSI_TIMEOUT_0			0x44
+#define DSI_TIMEOUT_LRX(x)		(((x) & 0xffff) << 16)
+#define DSI_TIMEOUT_HTX(x)		(((x) & 0xffff) <<  0)
+#define DSI_TIMEOUT_1			0x45
+#define DSI_TIMEOUT_PR(x)		(((x) & 0xffff) << 16)
+#define DSI_TIMEOUT_TA(x)		(((x) & 0xffff) <<  0)
+#define DSI_TO_TALLY			0x46
+#define DSI_TALLY_TA(x)			(((x) & 0xff) << 16)
+#define DSI_TALLY_LRX(x)		(((x) & 0xff) <<  8)
+#define DSI_TALLY_HTX(x)		(((x) & 0xff) <<  0)
+#define DSI_PAD_CONTROL_0		0x4b
+#define DSI_PAD_CONTROL_VS1_PDIO(x)	(((x) & 0xf) <<  0)
+#define DSI_PAD_CONTROL_VS1_PDIO_CLK	(1 <<  8)
+#define DSI_PAD_CONTROL_VS1_PULLDN(x)	(((x) & 0xf) << 16)
+#define DSI_PAD_CONTROL_VS1_PULLDN_CLK	(1 << 24)
+#define DSI_PAD_CONTROL_CD		0x4c
+#define DSI_PAD_CD_STATUS		0x4d
+#define DSI_VIDEO_MODE_CONTROL		0x4e
+#define DSI_PAD_CONTROL_1		0x4f
+#define DSI_PAD_CONTROL_2		0x50
+#define DSI_PAD_OUT_CLK(x)		(((x) & 0x7) <<  0)
+#define DSI_PAD_LP_DN(x)		(((x) & 0x7) <<  4)
+#define DSI_PAD_LP_UP(x)		(((x) & 0x7) <<  8)
+#define DSI_PAD_SLEW_DN(x)		(((x) & 0x7) << 12)
+#define DSI_PAD_SLEW_UP(x)		(((x) & 0x7) << 16)
+#define DSI_PAD_CONTROL_3		0x51
+#define DSI_PAD_PREEMP_PD_CLK(x)	(((x) & 0x3) << 12)
+#define DSI_PAD_PREEMP_PU_CLK(x)	(((x) & 0x3) << 8)
+#define DSI_PAD_PREEMP_PD(x)		(((x) & 0x3) << 4)
+#define DSI_PAD_PREEMP_PU(x)		(((x) & 0x3) << 0)
+#define DSI_PAD_CONTROL_4		0x52
+#define DSI_GANGED_MODE_CONTROL		0x53
+#define DSI_GANGED_MODE_CONTROL_ENABLE	(1 << 0)
+#define DSI_GANGED_MODE_START		0x54
+#define DSI_GANGED_MODE_SIZE		0x55
+#define DSI_RAW_DATA_BYTE_COUNT		0x56
+#define DSI_ULTRA_LOW_POWER_CONTROL	0x57
+#define DSI_INIT_SEQ_DATA_8		0x58
+#define DSI_INIT_SEQ_DATA_9		0x59
+#define DSI_INIT_SEQ_DATA_10		0x5a
+#define DSI_INIT_SEQ_DATA_11		0x5b
+#define DSI_INIT_SEQ_DATA_12		0x5c
+#define DSI_INIT_SEQ_DATA_13		0x5d
+#define DSI_INIT_SEQ_DATA_14		0x5e
+#define DSI_INIT_SEQ_DATA_15		0x5f
+
+#define PKT_ID0(id)	((((id) & 0x3f) <<  3) | (1 <<  9))
+#define PKT_LEN0(len)	(((len) & 0x07) <<  0)
+#define PKT_ID1(id)	((((id) & 0x3f) << 13) | (1 << 19))
+#define PKT_LEN1(len)	(((len) & 0x07) << 10)
+#define PKT_ID2(id)	((((id) & 0x3f) << 23) | (1 << 29))
+#define PKT_LEN2(len)	(((len) & 0x07) << 20)
+
+#define PKT_LP		(1 << 30)
+#define NUM_PKT_SEQ	12
+
+#define APB_MISC_GP_MIPI_PAD_CTRL_0 	(TEGRA_APB_MISC_GP_BASE + 0x20)
+#define DSIB_MODE_SHIFT			1
+#define DSIB_MODE_CSI			(0 << DSIB_MODE_SHIFT)
+#define DSIB_MODE_DSI			(1 << DSIB_MODE_SHIFT)
+
+/*
+ * pixel format as used in the DSI_CONTROL_FORMAT field
+ */
+enum tegra_dsi_format {
+	TEGRA_DSI_FORMAT_16P,
+	TEGRA_DSI_FORMAT_18NP,
+	TEGRA_DSI_FORMAT_18P,
+	TEGRA_DSI_FORMAT_24P,
+};
+
+enum dsi_dev {
+        DSI_A = 0,
+        DSI_B,
+        NUM_DSI,
+};
+
+struct panel_jdi;
+struct tegra_mipi_device;
+struct mipi_dsi_host;
+struct mipi_dsi_msg;
+
+#define MAX_DSI_VIDEO_FIFO_DEPTH	96
+#define MAX_DSI_HOST_FIFO_DEPTH		64
+
+struct tegra_dsi {
+	struct panel_jdi *panel;
+	//struct tegra_output output;
+	void   *regs;
+	u8     channel;
+	unsigned long clk_rate;
+
+	unsigned long flags;
+	enum mipi_dsi_pixel_format format;
+	unsigned int lanes;
+
+	struct tegra_mipi_device *mipi;
+	struct mipi_dsi_host host;
+	bool enabled;
+
+	unsigned int video_fifo_depth;
+	unsigned int host_fifo_depth;
+
+	/* for ganged-mode support */
+	unsigned int ganged_lanes;
+	struct tegra_dsi *slave;
+	int ganged_mode;
+
+	struct tegra_dsi *master;
+};
+
+static inline unsigned long tegra_dsi_readl(struct tegra_dsi *dsi,
+			unsigned long reg)
+{
+	return read32(dsi->regs + (reg << 2));
+}
+
+static inline void tegra_dsi_writel(struct tegra_dsi *dsi, unsigned long value,
+			unsigned long reg)
+{
+	write32(dsi->regs + (reg << 2), value);
+}
+
+#endif /* __TEGRA_DSI_H__ */
diff --git a/src/soc/nvidia/tegra210/include/soc/verstage.h b/src/soc/nvidia/tegra210/include/soc/verstage.h
new file mode 100644
index 0000000..6c37218
--- /dev/null
+++ b/src/soc/nvidia/tegra210/include/soc/verstage.h
@@ -0,0 +1,25 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright 2014 Google Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc.
+ */
+
+#ifndef __SOC_NVIDIA_TEGRA210_SOC_VERSTAGE_H__
+#define __SOC_NVIDIA_TEGRA210_SOC_VERSTAGE_H__
+
+void verstage_mainboard_init(void);
+
+#endif /* __SOC_NVIDIA_TEGRA210_SOC_VERSTAGE_H__ */
diff --git a/src/soc/nvidia/tegra210/jdi_25x18_display/panel-jdi-lpm102a188a.c b/src/soc/nvidia/tegra210/jdi_25x18_display/panel-jdi-lpm102a188a.c
new file mode 100644
index 0000000..2149ca9
--- /dev/null
+++ b/src/soc/nvidia/tegra210/jdi_25x18_display/panel-jdi-lpm102a188a.c
@@ -0,0 +1,215 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright 2015 Google Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc.
+ */
+#include <console/console.h>
+#include <arch/io.h>
+#include <stdint.h>
+#include <lib.h>
+#include <stdlib.h>
+#include <delay.h>
+#include <soc/addressmap.h>
+#include <soc/clock.h>
+#include <device/device.h>
+#include <soc/nvidia/tegra/types.h>
+#include "../chip.h"
+#include <soc/display.h>
+#include <soc/mipi_dsi.h>
+#include <soc/tegra_dsi.h>
+#include "panel-jdi-lpm102a188a.h"
+
+struct panel_jdi jdi_data[NUM_DSI];
+
+int panel_jdi_prepare(struct panel_jdi *jdi)
+{
+	int ret;
+	u8 data;
+
+	if (jdi->enabled)
+		return 0;
+
+	ret = mipi_dsi_dcs_set_column_address(jdi->dsi, 0,
+				jdi->mode->xres / 2 - 1); // 2560/2
+	if (ret < 0)
+		printk(BIOS_ERR, "failed to set column address: %d\n", ret);
+
+	ret = mipi_dsi_dcs_set_column_address(jdi->dsi->slave, 0,
+				jdi->mode->xres / 2 - 1);
+	if (ret < 0)
+		printk(BIOS_ERR, "failed to set column address: %d\n", ret);
+
+	ret = mipi_dsi_dcs_set_page_address(jdi->dsi, 0,
+				jdi->mode->yres - 1);
+	if (ret < 0)
+		printk(BIOS_ERR, "failed to set page address: %d\n", ret);
+
+	ret = mipi_dsi_dcs_set_page_address(jdi->dsi->slave, 0,
+				jdi->mode->yres - 1);
+	if (ret < 0)
+		printk(BIOS_ERR, "failed to set page address: %d\n", ret);
+
+	ret = mipi_dsi_dcs_set_tear_on(jdi->dsi, MIPI_DSI_DCS_TEAR_MODE_VBLANK);
+	if (ret < 0)
+		printk(BIOS_ERR, "failed to set tear on: %d\n", ret);
+
+	ret = mipi_dsi_dcs_set_tear_on(jdi->dsi->slave,
+			MIPI_DSI_DCS_TEAR_MODE_VBLANK);
+	if (ret < 0)
+		printk(BIOS_ERR, "failed to set tear on: %d\n", ret);
+
+	ret = mipi_dsi_dcs_set_address_mode(jdi->dsi, false, false, false,
+			false, false, false, false, false);
+	if (ret < 0)
+		printk(BIOS_ERR, "failed to set address mode: %d\n", ret);
+
+	ret = mipi_dsi_dcs_set_address_mode(jdi->dsi->slave, false, false,
+			false, false, false, false, false, false);
+	if (ret < 0)
+		printk(BIOS_ERR, "failed to set address mode: %d\n", ret);
+
+	ret = mipi_dsi_dcs_set_pixel_format(jdi->dsi, 0x77);
+	if (ret < 0)
+		printk(BIOS_ERR, "failed to set pixel format: %d\n", ret);
+
+	ret = mipi_dsi_dcs_set_pixel_format(jdi->dsi->slave, 0x77);
+	if (ret < 0)
+		printk(BIOS_ERR, "failed to set pixel format: %d\n", ret);
+
+	data = 0xFF;
+	ret = mipi_dsi_dcs_write(jdi->dsi, 0x51, &data, 1);
+	if (ret < 0)
+		printk(BIOS_ERR, "failed to set 0x51: %d\n", ret);
+
+	data = 0xFF;
+	ret = mipi_dsi_dcs_write(jdi->dsi->slave, 0x51, &data, 1);
+	if (ret < 0)
+		printk(BIOS_ERR, "failed to set 0x51: %d\n", ret);
+
+	data = 0x24;
+	ret = mipi_dsi_dcs_write(jdi->dsi, 0x53, &data, 1);
+	if (ret < 0)
+		printk(BIOS_ERR, "failed to set 0x53: %d\n", ret);
+
+	data = 0x24;
+	ret = mipi_dsi_dcs_write(jdi->dsi->slave, 0x53, &data, 1);
+	if (ret < 0)
+		printk(BIOS_ERR, "failed to set 0x53: %d\n", ret);
+
+	data = 0x00;
+	ret = mipi_dsi_dcs_write(jdi->dsi, 0x55, &data, 1);
+	if (ret < 0)
+		printk(BIOS_ERR, "failed to set 0x55: %d\n", ret);
+
+	data = 0x00;
+	ret = mipi_dsi_dcs_write(jdi->dsi->slave, 0x55, &data, 1);
+	if (ret < 0)
+		printk(BIOS_ERR, "failed to set 0x55: %d\n", ret);
+
+	ret = mipi_dsi_dcs_exit_sleep_mode(jdi->dsi);
+	if (ret < 0)
+		printk(BIOS_ERR, "failed to exit sleep mode: %d\n", ret);
+
+	ret = mipi_dsi_dcs_exit_sleep_mode(jdi->dsi->slave);
+	if (ret < 0)
+		printk(BIOS_ERR, "failed to exit sleep mode: %d\n", ret);
+	mdelay(150);
+
+	ret = mipi_dsi_dcs_set_display_on(jdi->dsi);
+	if (ret < 0)
+		printk(BIOS_ERR, "failed to set display on: %d\n", ret);
+
+	ret = mipi_dsi_dcs_set_display_on(jdi->dsi->slave);
+	if (ret < 0)
+		printk(BIOS_ERR, "failed to set display on: %d\n", ret);
+	mdelay(50);
+
+	jdi->enabled = true;
+
+	return 0;
+}
+
+static int panel_jdi_enslave(struct mipi_dsi_device *master,
+			struct mipi_dsi_device *slave)
+{
+	int ret;
+
+	ret = mipi_dsi_attach(master);
+	if (ret < 0)
+		return ret;
+
+	return ret;
+}
+
+static int panel_jdi_liberate(struct mipi_dsi_device *master,
+			struct mipi_dsi_device *slave)
+{
+	int ret;
+
+	ret = mipi_dsi_detach(master);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+static const struct mipi_dsi_master_ops panel_jdi_master_ops = {
+	.enslave = panel_jdi_enslave,
+	.liberate = panel_jdi_liberate,
+};
+
+struct panel_jdi *panel_jdi_dsi_probe(struct mipi_dsi_device *dsi)
+{
+	static int index = 0;
+	struct panel_jdi *jdi;
+	int ret;
+
+	if (index >= NUM_DSI)
+		return (void *)-EPTR;
+
+	jdi = &jdi_data[index++];
+
+	jdi->dsi = dsi;
+
+	dsi->lanes = 4;
+	dsi->format = MIPI_DSI_FMT_RGB888;
+	dsi->mode_flags = 0;
+
+	if (dsi->master) {
+		ret = mipi_dsi_attach(dsi);
+		if (ret < 0) {
+			printk(BIOS_ERR, "mipi_dsi_attach() failed: %d\n", ret);
+			return (void *)-EPTR;
+		}
+
+		ret = mipi_dsi_enslave(dsi->master, dsi);
+		if (ret < 0) {
+			printk(BIOS_ERR, "mipi_dsi_enslave() failed: %d\n",
+				ret);
+			return (void *)-EPTR;
+		}
+
+		return jdi;
+	}
+
+	dsi->ops = &panel_jdi_master_ops;
+
+	jdi->enabled = 0;
+	jdi->width_mm = 211;
+	jdi->height_mm = 148;
+
+	return jdi;
+}
diff --git a/src/soc/nvidia/tegra210/jdi_25x18_display/panel-jdi-lpm102a188a.h b/src/soc/nvidia/tegra210/jdi_25x18_display/panel-jdi-lpm102a188a.h
new file mode 100644
index 0000000..b345971
--- /dev/null
+++ b/src/soc/nvidia/tegra210/jdi_25x18_display/panel-jdi-lpm102a188a.h
@@ -0,0 +1,131 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright 2015 Google Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc.
+ */
+#ifndef _PANEL_JDI_LPM102A188A_H_
+#define _PANEL_JDI_LPM102A188A_H_
+
+#define LP8557_MAX_BRIGHTNESS				0xFFF;
+
+#define LP8557_COMMAND					0x00
+#define LP8557_COMMAND_ON				(1 << 0)
+
+#define LP8557_BRIGHTNESS_LOW				0x03
+#define LP8557_BRIGHTNESS_LOW_MASK(x)			(((x) & 0xF) << 4)
+
+#define LP8557_BRIGHTNESS_HIGH				0x04
+#define LP8557_BRIGHTNESS_HIGH_MASK(x)			(((x) & 0xFF0) >> 4)
+
+enum lp8557_config_brightness_mode {
+	LP8557_CONFIG_BRTMODE_PWM			= 0x0,
+	LP8557_CONFIG_BRTMODE_REG,
+	LP8557_CONFIG_BRTMODE_PWM_REG_SHAPE_PWM,
+	LP8557_CONFIG_BRTMODE_PWM_REG_SHAPE_BRIGHTNESS,
+	LP8557_CONFIG_BRTMODE_MAX,
+};
+#define LP8557_CONFIG					0x10
+#define LP8557_CONFIG_BRTMODE(x)			(((x) & 0x3) << 0)
+#define LP8557_CONFIG_AUTO_DETECT_LED			(1 << 2)
+#define LP8557_CONFIG_PWM_STANDBY			(1 << 7)
+
+enum lp8557_current {
+	LP8557_CURRENT_5_MA				= 0x0,
+	LP8557_CURRENT_10_MA,
+	LP8557_CURRENT_13_MA,
+	LP8557_CURRENT_15_MA,
+	LP8557_CURRENT_18_MA,
+	LP8557_CURRENT_20_MA,
+	LP8557_CURRENT_23_MA,
+	LP8557_CURRENT_25_MA,
+	LP8557_CURRENT_MAX,
+};
+#define LP8557_CURRENT					0x11
+#define LP8557_CURRENT_MAXCURR(x)			(((x) & 0x7) << 0)
+#define LP8557_CURRENT_ISET				(1 << 7)
+
+enum lp8557_pgen_frequency {
+	LP8557_PGEN_FREQ_4_9_KHZ			= 0x0,
+	LP8557_PGEN_FREQ_9_8_KHZ,
+	LP8557_PGEN_FREQ_14_6_KHZ,
+	LP8557_PGEN_FREQ_19_5_KHZ,
+	LP8557_PGEN_FREQ_24_4_KHZ,
+	LP8557_PGEN_FREQ_29_3_KHZ,
+	LP8557_PGEN_FREQ_34_2_KHZ,
+	LP8557_PGEN_FREQ_39_1_KHZ,
+	LP8557_PGEN_FREQ_MAX,
+};
+#define LP8557_PGEN					0x12
+#define LP8557_PGEN_FREQ(x)				(((x) & 0x7) << 0)
+#define LP8557_PGEN_MAGIC				(5 << 3)
+#define LP8557_PGEN_FSET				(1 << 7)
+
+enum lp8557_boost_freq {
+	LP8557_BOOST_FREQ_500_KHZ			= 0x0,
+	LP8557_BOOST_FREQ_1_MHZ,
+	LP8557_BOOST_FREQ_MAX,
+};
+enum lp8557_boost_bcomp {
+	LP8557_BOOST_BCOMP_OPTION_0			= 0x0,
+	LP8557_BOOST_BCOMP_OPTION_1,
+	LP8557_BOOST_BCOMP_MAX,
+};
+#define LP8557_BOOST					0x13
+#define LP8557_BOOST_FREQ(x)				(((x) & 0x1) << 0)
+#define LP8557_BOOST_BCOMP(x)				(((x) & 0x1) << 1)
+#define LP8557_BOOST_BCSET				(1 << 6)
+#define LP8557_BOOST_BFSET				(1 << 7)
+
+#define LP8557_LED_ENABLE				0x14
+#define LP8557_LED_ENABLE_SINKS(x)			(((x) & 0x3F) << 0)
+#define LP8557_LED_ENABLE_MAGIC				(2 << 6)
+
+enum lp8557_step_ramp {
+	LP8557_STEP_RAMP_0_MS				= 0x0,
+	LP8557_STEP_RAMP_50_MS,
+	LP8557_STEP_RAMP_100_MS,
+	LP8557_STEP_RAMP_200_MS,
+	LP8557_STEP_RAMP_MAX,
+};
+enum lp8557_step_smoothing {
+	LP8557_STEP_SMOOTHING_NONE			= 0x0,
+	LP8557_STEP_SMOOTHING_LIGHT,
+	LP8557_STEP_SMOOTHING_MEDIUM,
+	LP8557_STEP_SMOOTHING_HEAVY,
+	LP8557_STEP_SMOOTHING_MAX,
+};
+#define LP8557_STEP					0x15
+#define LP8557_STEP_RAMP(x)				(((x) & 0x3) << 0)
+#define LP8557_STEP_SMOOTHING(x)			(((x) & 0x3) << 6)
+
+struct mipi_dsi_device;
+struct soc_nvidia_tegra210_config;
+
+struct panel_jdi {
+	struct mipi_dsi_device *dsi;
+	const struct soc_nvidia_tegra210_config *mode;
+
+	/* Physical size */
+	unsigned int width_mm;
+	unsigned int height_mm;
+
+	int enabled;
+};
+
+struct panel_jdi *panel_jdi_dsi_probe(struct mipi_dsi_device *dsi);
+int panel_jdi_prepare(struct panel_jdi *jdi);
+
+#endif
diff --git a/src/soc/nvidia/tegra210/lp0/Makefile b/src/soc/nvidia/tegra210/lp0/Makefile
new file mode 100644
index 0000000..9dfe4b4
--- /dev/null
+++ b/src/soc/nvidia/tegra210/lp0/Makefile
@@ -0,0 +1,58 @@
+################################################################################
+##
+## Copyright 2014 Google Inc.
+##
+## This program is free software; you can redistribute it and/or modify
+## it under the terms of the GNU General Public License as published by
+## the Free Software Foundation; version 2 of the License.
+##
+## This program is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+## GNU General Public License for more details.
+##
+## You should have received a copy of the GNU General Public License
+## along with this program; if not, write to the Free Software
+## Foundation, Inc.
+##
+################################################################################
+
+CC = $(GCC_PREFIX)gcc
+NM = $(GCC_PREFIX)nm
+OBJCOPY = $(GCC_PREFIX)objcopy
+
+OPENSSL = openssl
+DD = dd
+CP = cp
+MV = mv
+RM = rm
+
+SIGKEY = 00000000000000000000000000000000
+
+.PHONY: all
+all: tegra_lp0_resume.fw
+
+tegra_lp0_resume.elf: tegra_lp0_resume.ld tegra_lp0_resume.c
+	$(CC) -marm -march=armv4t -mno-unaligned-access -nostdlib -static \
+		-Os -fpie -Wl,--build-id=none -ggdb3 -T tegra_lp0_resume.ld \
+		-o $@ $(filter %.c,$+)
+
+tegra_lp0_resume.fw: tegra_lp0_resume.elf
+	@# Get rid of any files we're about to create.
+	$(RM) -f $@.nosig $@.sig $@.tosig
+	@# Convert the ELF image into a binary image.
+	$(OBJCOPY) -O binary $< $@.nosig
+	@# Extract the part of the binary which needs to be signed.
+	$(DD) bs=1 skip=544 if=$@.nosig of=$@.tosig
+	@# Calculate a signature for that part.
+	$(OPENSSL) dgst -mac cmac -macopt cipher:aes-128-cbc \
+		-macopt hexkey:$(SIGKEY) -md5 -binary \
+		$@.tosig > $@.sig
+	@# Inject the signature into the binary image's header.
+	$(DD) conv=notrunc bs=1 seek=272 count=16 if=$@.sig of=$@.nosig
+	@# Copy the signed binary to the target file name.
+	$(MV) $@.nosig $@
+
+clean:
+	$(RM) -f tegra_lp0_resume.fw tegra_lp0_resume.fw.sig
+	$(RM) -f tegra_lp0_resume.fw.tosig tegra_lp0_resume.elf
diff --git a/src/soc/nvidia/tegra210/lp0/tegra_lp0_resume.c b/src/soc/nvidia/tegra210/lp0/tegra_lp0_resume.c
new file mode 100644
index 0000000..2011529
--- /dev/null
+++ b/src/soc/nvidia/tegra210/lp0/tegra_lp0_resume.c
@@ -0,0 +1,691 @@
+/*
+ * Copyright 2014 Google Inc.
+ * Copyright 2013-2015, 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 <stdint.h>
+
+/* Function unit addresses. */
+enum {
+	UP_TAG_BASE = 0X60000000,
+	TIMER_BASE = 0X60005000,
+	CLK_RST_BASE = 0X60006000,
+	FLOW_CTLR_BASE = 0X60007000,
+	TEGRA_EVP_BASE = 0x6000f000,
+	APB_MISC_BASE = 0x70000000,
+	PMC_CTLR_BASE = 0X7000e400,
+	MC_CTLR_BASE = 0X70019000,
+};
+
+
+
+/* UP tag registers. */
+static uint32_t *up_tag_ptr = (void *)(UP_TAG_BASE + 0x0);
+enum {
+	UP_TAG_AVP = 0xaaaaaaaa
+};
+
+
+/*  APB Misc JTAG Configuration Register */
+static uint32_t *misc_pp_config_ctl_ptr = (void *)(APB_MISC_BASE + 0x24);
+enum {
+	PP_CONFIG_CTL_JTAG = 0x1 << 6
+};
+
+
+/* Timer registers. */
+static uint32_t *timer_us_ptr = (void *)(TIMER_BASE + 0x10);
+
+
+
+/* Clock and reset controller registers. */
+static uint32_t *clk_rst_rst_devices_l_ptr = (void *)(CLK_RST_BASE + 0x4);
+enum {
+	SWR_TRIG_SYS_RST = 0x1 << 2
+};
+
+static uint32_t *clk_rst_cclk_burst_policy_ptr = (void *)(CLK_RST_BASE + 0x20);
+enum {
+	CCLK_PLLP_BURST_POLICY = 0x20004444
+};
+
+static uint32_t *clk_rst_super_cclk_div_ptr = (void *)(CLK_RST_BASE + 0x24);
+enum {
+	SUPER_CDIV_ENB = 0x1 << 31
+};
+
+static uint32_t *clk_rst_osc_ctrl_ptr = (void *)(CLK_RST_BASE + 0x50);
+enum {
+	OSC_XOE = 0x1 << 0,
+	OSC_XOFS_SHIFT = 4,
+	OSC_XOFS_MASK = 0x3f << OSC_XOFS_SHIFT,
+	OSC_FREQ_SHIFT = 28,
+	OSC_FREQ_MASK = 0xf << OSC_FREQ_SHIFT
+};
+enum {
+	OSC_FREQ_13 = 0,
+	OSC_FREQ_16P8 = 1,
+	OSC_FREQ_19P2 = 4,
+	OSC_FREQ_38P4 = 5,
+	OSC_FREQ_12 = 8,
+	OSC_FREQ_48 = 9,
+	OSC_FREQ_26 = 12
+};
+
+static uint32_t *clk_rst_pllu_base_ptr = (void *)(CLK_RST_BASE + 0xc0);
+enum {
+	PLLU_DIVM_SHIFT = 0,
+	PLLU_DIVN_SHIFT = 8,
+	PLLU_OVERRIDE = 0x1 << 24,
+	PLLU_ENABLE = 0x1 << 30,
+	PLLU_BYPASS = 0x1 << 31
+};
+
+static uint32_t *clk_rst_pllu_misc_ptr = (void *)(CLK_RST_BASE + 0xcc);
+enum {
+	PLLU_LFCON_SHIFT = 4,
+	PLLU_CPCON_SHIFT = 8,
+	PLLU_LOCK_ENABLE = 22
+};
+
+static uint32_t *clk_rst_pllx_base_ptr = (void *)(CLK_RST_BASE + 0xe0);
+enum {
+	PLLX_ENABLE = 0x1 << 30
+};
+
+static uint32_t *clk_rst_rst_dev_u_clr_ptr = (void *)(CLK_RST_BASE + 0x314);
+enum {
+	SWR_CSITE_RST = 0x1 << 9
+};
+
+static uint32_t *clk_rst_clk_enb_l_set_ptr = (void *)(CLK_RST_BASE + 0x320);
+enum {
+	CLK_ENB_CPU = 0x1 << 0
+};
+
+static uint32_t *clk_rst_clk_out_enb_u_set_ptr =
+	(void *)(CLK_RST_BASE + 0x330);
+enum {
+	CLK_ENB_CSITE = 0x1 << 9
+};
+
+static uint32_t *clk_rst_cpu_softrst_ctrl2_ptr =
+	(void *)(CLK_RST_BASE + 0x388);
+enum {
+	CAR2PMC_CPU_ACK_WIDTH_SHIFT = 0,
+	CAR2PMC_CPU_ACK_WIDTH_MASK = 0xfff << CAR2PMC_CPU_ACK_WIDTH_SHIFT
+};
+
+static uint32_t *clk_rst_clk_enb_v_set_ptr = (void *)(CLK_RST_BASE + 0x440);
+enum {
+	CLK_ENB_CPUG = 0x1 << 0,
+	CLK_ENB_CPULP = 0x1 << 1,
+};
+
+static uint32_t *clk_rst_rst_cpulp_cmplx_set_ptr =
+	(void *)(CLK_RST_BASE + 0x450);
+enum {
+	SET_CXRESET0 = 0x1 << 20,
+	SET_CXRESET1 = 0x1 << 21
+};
+static uint32_t *clk_rst_rst_cpug_cmplx_clr_ptr =
+	(void *)(CLK_RST_BASE + 0x454);
+enum {
+	CLR_CPURESET0 = 0x1 << 0,
+	CLR_CPURESET1 = 0x1 << 1,
+	CLR_CPURESET2 = 0x1 << 2,
+	CLR_CPURESET3 = 0x1 << 3,
+	CLR_DBGRESET0 = 0x1 << 12,
+	CLR_DBGRESET1 = 0x1 << 13,
+	CLR_DBGRESET2 = 0x1 << 14,
+	CLR_DBGRESET3 = 0x1 << 15,
+	CLR_CORERESET0 = 0x1 << 16,
+	CLR_CORERESET1 = 0x1 << 17,
+	CLR_CORERESET2 = 0x1 << 18,
+	CLR_CORERESET3 = 0x1 << 19,
+	CLR_CXRESET0 = 0x1 << 20,
+	CLR_CXRESET1 = 0x1 << 21,
+	CLR_CXRESET2 = 0x1 << 22,
+	CLR_CXRESET3 = 0x1 << 23,
+	CLR_L2RESET = 0x1 << 24,
+	CLR_NONCPURESET = 0x1 << 29,
+	CLR_PRESETDBG = 0x1 << 30
+};
+
+
+/* Reset vector. */
+
+static uint32_t *evp_cpu_reset_ptr = (void *)(TEGRA_EVP_BASE + 0x100);
+
+
+
+/* Flow controller registers. */
+static uint32_t *flow_ctlr_halt_cop_events_ptr =
+	(void *)(FLOW_CTLR_BASE + 0x4);
+enum {
+	EVENT_MSEC = 0x1 << 24,
+	EVENT_JTAG = 0x1 << 28,
+	FLOW_MODE_SHIFT = 29,
+	FLOW_MODE_STOP = 2 << FLOW_MODE_SHIFT,
+};
+
+static uint32_t *flow_ctlr_cluster_control_ptr =
+	(void *)(FLOW_CTLR_BASE + 0x2c);
+enum {
+	FLOW_CLUSTER_ACTIVE_LP = 0x1 << 0
+};
+
+static uint32_t *flow_ctlr_ram_repair_ptr =
+	(void *)(FLOW_CTLR_BASE + 0x40);
+static uint32_t *flow_ctlr_ram_repair_cluster1_ptr =
+	(void *)(FLOW_CTLR_BASE + 0x58);
+enum {
+	RAM_REPAIR_REQ = 0x1 << 0,
+	RAM_REPAIR_STS = 0x1 << 1,
+};
+
+
+/* Power management controller registers. */
+enum {
+	PARTID_CRAIL = 0,
+	PARTID_CE0 = 14,
+	PARTID_C0NC = 15,
+};
+
+static uint32_t *pmc_ctlr_clamp_status_ptr = (void *)(PMC_CTLR_BASE + 0x2c);
+
+static uint32_t *pmc_ctlr_pwrgate_toggle_ptr = (void *)(PMC_CTLR_BASE + 0x30);
+enum {
+	PWRGATE_TOGGLE_START = 0x1 << 8
+};
+
+static uint32_t *pmc_ctlr_pwrgate_status_ptr = (void *)(PMC_CTLR_BASE + 0x38);
+
+static uint32_t *pmc_ctlr_cpupwrgood_timer_ptr =
+	(void *)(PMC_CTLR_BASE + 0xc8);
+
+static uint32_t *pmc_odmdata_ptr = (void *)(PMC_CTLR_BASE + 0xa0);
+
+static uint32_t *pmc_ctlr_scratch41_ptr = (void *)(PMC_CTLR_BASE + 0x140);
+static uint32_t *pmc_ctlr_secure_scratch34_ptr = (void *)(PMC_CTLR_BASE + 0x368);
+static uint32_t *pmc_ctlr_secure_scratch35_ptr = (void *)(PMC_CTLR_BASE + 0x36c);
+
+static uint32_t *pmc_ctlr_osc_edpd_over_ptr = (void *)(PMC_CTLR_BASE + 0x1a4);
+enum {
+	PMC_XOFS_SHIFT = 1,
+	PMC_XOFS_MASK = 0x3f << PMC_XOFS_SHIFT
+};
+
+
+
+/* Memory controller registers. */
+static uint32_t *mc_video_protect_size_mb_ptr = (void *)(MC_CTLR_BASE + 0x64c);
+
+static uint32_t *mc_video_protect_reg_ctrl_ptr =
+	(void *)(MC_CTLR_BASE + 0x650);
+enum {
+	VIDEO_PROTECT_WRITE_ACCESS_DISABLE = 0x1 << 0,
+	VIDEO_PROTECT_ALLOW_TZ_WRITE_ACCESS = 0x1 << 1
+};
+
+
+/* Utility functions. */
+
+static inline void __attribute__((always_inline))
+		   __attribute__((noreturn)) halt(void)
+{
+	for (;;);
+}
+
+inline static uint32_t read32(const void *addr)
+{
+	return *(volatile uint32_t *)addr;
+}
+
+inline static void write32(uint32_t val, void *addr)
+{
+	*(volatile uint32_t *)addr = val;
+}
+
+inline static void setbits32(uint32_t bits, void *addr)
+{
+	write32(addr, read32(addr) | bits);
+}
+
+inline static void clrbits32(uint32_t bits, void *addr)
+{
+	write32(addr, read32(addr) & ~bits);
+}
+
+static void __attribute__((noreturn)) reset(void)
+{
+	write32(clk_rst_rst_devices_l_ptr, SWR_TRIG_SYS_RST);
+	halt();
+}
+
+static void udelay(unsigned usecs)
+{
+	uint32_t start = read32(timer_us_ptr);
+	while (read32(timer_us_ptr) - start < usecs)
+		;
+}
+
+/* UART related defines */
+static uint32_t *uart_clk_out_enb_regs[4] = {
+	(uint32_t *)0x60006010,
+	(uint32_t *)0x60006010,
+	(uint32_t *)0x60006014,
+	(uint32_t *)0x60006018
+};
+
+static uint32_t *uart_rst_devices_regs[4] = {
+	(uint32_t *)0x60006004,
+	(uint32_t *)0x60006004,
+	(uint32_t *)0x60006008,
+	(uint32_t *)0x6000600c
+};
+
+static uint32_t uart_enable_mask[4] = {
+	1 << 6,
+	1 << 7,
+	1 << 23,
+	1 << 1
+};
+
+static uint32_t *uart_clk_source_regs[4] = {
+	(uint32_t *)0x60006178,
+	(uint32_t *)0x6000617c,
+	(uint32_t *)0x600061a0,
+	(uint32_t *)0x600061c0,
+};
+
+static uint32_t *uart_base_regs[4] = {
+	(uint32_t *)0x70006000,
+	(uint32_t *)0x70006040,
+	(uint32_t *)0x70006200,
+	(uint32_t *)0x70006300,
+};
+enum {
+	UART_THR_DLAB = 0x0,
+	UART_IER_DLAB = 0x1,
+	UART_IIR_FCR = 0x2,
+	UART_LCR = 0x3
+};
+enum {
+	UART_RATE_115200 = (408000000/115200/16), /* based on 408000000 PLLP */
+	FCR_TX_CLR = 0x4,	/* bit 2 of FCR : clear TX FIFO */
+	FCR_RX_CLR = 0x2,	/* bit 1 of FCR : clear RX FIFO */
+	FCR_EN_FIFO = 0x1,	/* bit 0 of FCR : enable TX & RX FIFO */
+	LCR_DLAB = 0x80,	/* bit 7 of LCR : Divisor Latch Access Bit */
+	LCR_WD_SIZE_8 = 0x3,	/* bit 1:0 of LCR : word length of 8 */
+};
+
+static void enable_uart(void)
+{
+	uint32_t *uart_clk_enb_reg;
+	uint32_t *uart_rst_reg;
+	uint32_t *uart_clk_source;
+	uint32_t uart_port;
+	uint32_t uart_mask;
+	uint32_t *uart_base;
+
+	/*
+	 * Read odmdata (stored in pmc->odmdata) to determine debug uart port.
+	 *
+	 * Bits 15-17 of odmdata contains debug uart port.
+	 *  0 : UARTA
+	 *  1 : UARTB
+	 *  2 : UARTC
+	 *  3 : UARTD
+	 */
+	uart_port = (read32(pmc_odmdata_ptr) >> 15) & 0x7;
+
+	/* Default to UARTA if uart_port is out of range */
+	if (uart_port >= 4)
+		uart_port = 0;
+
+	uart_clk_enb_reg = uart_clk_out_enb_regs[uart_port];
+	uart_rst_reg = uart_rst_devices_regs[uart_port];
+	uart_mask = uart_enable_mask[uart_port];
+	uart_clk_source = uart_clk_source_regs[uart_port];
+	uart_base = uart_base_regs[uart_port];
+
+	/* Enable UART clock */
+	setbits32(uart_mask, uart_clk_enb_reg);
+
+	/* Reset and unreset UART */
+	setbits32(uart_mask, uart_rst_reg);
+	clrbits32(uart_mask, uart_rst_reg);
+
+	/* Program UART clock source: PLLP (408000000) */
+	write32(uart_clk_source, 0);
+
+	/* Program 115200n8 to the uart port */
+	/* baud-rate of 115200 */
+	write32((uart_base + UART_LCR), LCR_DLAB);
+	write32((uart_base + UART_THR_DLAB), (UART_RATE_115200 & 0xff));
+	write32((uart_base + UART_IER_DLAB), (UART_RATE_115200 >> 8));
+	/* 8-bit and no parity */
+	write32((uart_base + UART_LCR), LCR_WD_SIZE_8);
+	/* enable and clear RX/TX FIFO */
+	write32((uart_base + UART_IIR_FCR),
+		(FCR_TX_CLR + FCR_RX_CLR + FCR_EN_FIFO));
+}
+
+/* Accessors. */
+
+static uint32_t get_wakeup_vector(void)
+{
+	return read32(pmc_ctlr_scratch41_ptr);
+}
+
+static unsigned get_osc_freq(void)
+{
+	return (read32(clk_rst_osc_ctrl_ptr) & OSC_FREQ_MASK) >> OSC_FREQ_SHIFT;
+}
+
+
+/* Jtag configuration. */
+
+static void enable_jtag(void)
+{
+	write32(misc_pp_config_ctl_ptr, PP_CONFIG_CTL_JTAG);
+}
+
+/* Clock configuration. */
+
+static void config_oscillator(void)
+{
+	// Read oscillator drive strength from OSC_EDPD_OVER.XOFS and copy
+	// to OSC_CTRL.XOFS and set XOE.
+	uint32_t xofs = (read32(pmc_ctlr_osc_edpd_over_ptr) &
+		    PMC_XOFS_MASK) >> PMC_XOFS_SHIFT;
+
+	uint32_t osc_ctrl = read32(clk_rst_osc_ctrl_ptr);
+	osc_ctrl &= ~OSC_XOFS_MASK;
+	osc_ctrl |= (xofs << OSC_XOFS_SHIFT);
+	osc_ctrl |= OSC_XOE;
+	write32(clk_rst_osc_ctrl_ptr, osc_ctrl);
+}
+
+static void config_pllu(void)
+{
+	// Figure out what parameters to use for PLLU.
+	uint32_t divm, divn, cpcon, lfcon;
+	switch (get_osc_freq()) {
+	case OSC_FREQ_12:
+	case OSC_FREQ_48:
+		divm = 0x0c;
+		divn = 0x3c0;
+		cpcon = 0x0c;
+		lfcon = 0x02;
+		break;
+	case OSC_FREQ_16P8:
+		divm = 0x07;
+		divn = 0x190;
+		cpcon = 0x05;
+		lfcon = 0x02;
+		break;
+	case OSC_FREQ_19P2:
+	case OSC_FREQ_38P4:
+		divm = 0x04;
+		divn = 0xc8;
+		cpcon = 0x03;
+		lfcon = 0x02;
+		break;
+	case OSC_FREQ_26:
+		divm = 0x1a;
+		divn = 0x3c0;
+		cpcon = 0x0c;
+		lfcon = 0x02;
+		break;
+	default:
+		// Map anything that's not recognized to 13MHz.
+		divm = 0x0d;
+		divn = 0x3c0;
+		cpcon = 0x0c;
+		lfcon = 0x02;
+	}
+
+	// Configure PLLU.
+	uint32_t base = PLLU_BYPASS | PLLU_OVERRIDE |
+			(divn << PLLU_DIVN_SHIFT) | (divm << PLLU_DIVM_SHIFT);
+	write32(clk_rst_pllu_base_ptr, base);
+	uint32_t misc = (cpcon << PLLU_CPCON_SHIFT) |
+			(lfcon << PLLU_LFCON_SHIFT);
+	write32(clk_rst_pllu_misc_ptr, misc);
+
+	// Enable PLLU.
+	base &= ~PLLU_BYPASS;
+	base |= PLLU_ENABLE;
+	write32(clk_rst_pllu_base_ptr, base);
+	misc |= PLLU_LOCK_ENABLE;
+	write32(clk_rst_pllu_misc_ptr, misc);
+}
+
+static void enable_cpu_clocks(void)
+{
+	// Enable the CPU complex clock.
+	write32(clk_rst_clk_enb_l_set_ptr, CLK_ENB_CPU);
+	write32(clk_rst_clk_enb_v_set_ptr, CLK_ENB_CPUG | CLK_ENB_CPULP);
+}
+
+
+
+/* Function unit configuration. */
+
+static void config_core_sight(void)
+{
+	// Enable the CoreSight clock.
+	write32(clk_rst_clk_out_enb_u_set_ptr, CLK_ENB_CSITE);
+
+	/*
+	 * 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.
+	 */
+	write32(clk_rst_rst_dev_u_clr_ptr, SWR_CSITE_RST);
+}
+
+
+/* Resets. */
+
+static void clear_cpu_resets(void)
+{
+	/* Hold CPU1 in reset */
+	setbits32(SET_CXRESET1, clk_rst_rst_cpulp_cmplx_set_ptr);
+
+	write32(clk_rst_rst_cpug_cmplx_clr_ptr,
+		CLR_NONCPURESET | CLR_L2RESET | CLR_PRESETDBG);
+
+	write32(clk_rst_rst_cpug_cmplx_clr_ptr,
+		CLR_CPURESET0 | CLR_DBGRESET0 | CLR_CORERESET0 | CLR_CXRESET0);
+}
+
+
+
+/* RAM repair */
+
+void ram_repair(void)
+{
+	// Request Cluster0 RAM repair.
+	setbits32(RAM_REPAIR_REQ, flow_ctlr_ram_repair_ptr);
+	// Poll for Cluster0 RAM repair status.
+	while (!(read32(flow_ctlr_ram_repair_ptr) & RAM_REPAIR_STS))
+		;
+
+	// Request Cluster1 RAM repair.
+	setbits32(RAM_REPAIR_REQ, flow_ctlr_ram_repair_cluster1_ptr);
+	// Poll for Cluster1 RAM repair status.
+	while (!(read32(flow_ctlr_ram_repair_cluster1_ptr) & RAM_REPAIR_STS))
+		;
+}
+
+
+/* Power. */
+
+static void power_on_partition(unsigned id)
+{
+	uint32_t bit = 0x1 << id;
+	if (!(read32(pmc_ctlr_pwrgate_status_ptr) & bit)) {
+		// Partition is not on. Turn it on.
+		write32(pmc_ctlr_pwrgate_toggle_ptr,
+			id | PWRGATE_TOGGLE_START);
+
+		// Wait until the partition is powerd on.
+		while (!(read32(pmc_ctlr_pwrgate_status_ptr) & bit))
+			;
+
+		// Wait until clamp is off.
+		while (read32(pmc_ctlr_clamp_status_ptr) & bit)
+			;
+	}
+}
+
+static void power_on_main_cpu(void)
+{
+	/*
+	 * Reprogram PMC_CPUPWRGOOD_TIMER register:
+	 *
+	 * XXX This is a fragile assumption. XXX
+	 * The kernel prepares PMC_CPUPWRGOOD_TIMER based on a 32768Hz clock.
+	 * Note that PMC_CPUPWRGOOD_TIMER is running at pclk.
+	 *
+	 * We need to reprogram PMC_CPUPWRGOOD_TIMER based on the current pclk
+	 * which is at 204Mhz (pclk = sclk = pllp_out2) after BootROM. Multiply
+	 * PMC_CPUPWRGOOD_TIMER by 204M / 32K.
+	 *
+	 * Save the original PMC_CPUPWRGOOD_TIMER register which we need to
+	 * restore after the CPU is powered up.
+	 */
+	uint32_t orig_timer = read32(pmc_ctlr_cpupwrgood_timer_ptr);
+
+	write32(pmc_ctlr_cpupwrgood_timer_ptr,
+		orig_timer * (204000000 / 32768));
+
+	power_on_partition(PARTID_CRAIL);
+	power_on_partition(PARTID_C0NC);
+	power_on_partition(PARTID_CE0);
+
+	// Restore the original PMC_CPUPWRGOOD_TIMER.
+	write32(pmc_ctlr_cpupwrgood_timer_ptr, orig_timer);
+}
+
+
+static void aarch64_trampoline(void)
+{
+	uint32_t val = 3;	/* bit1: to warm reset; bit0: AARCH64*/
+
+	asm volatile ("mcr p15, 0, %0, c12, c0, 2" : : "r" (val));
+
+	/* unreachable */
+	halt();
+}
+
+
+/* Entry point. */
+
+void lp0_resume(void)
+{
+	// If not on the AVP, reset.
+	if (read32(up_tag_ptr) != UP_TAG_AVP)
+		reset();
+
+	// Enable JTAG
+	enable_jtag();
+
+	config_oscillator();
+
+	// Program SUPER_CCLK_DIVIDER.
+	write32(clk_rst_super_cclk_div_ptr, SUPER_CDIV_ENB);
+
+	config_core_sight();
+
+	enable_uart();
+
+	config_pllu();
+
+	/*
+	 * Set the CPU reset vector.
+	 *
+	 * T210 always resets to AARCH32 and SW needs to write RMR_EL3
+	 * to bootstrap into AARCH64.
+	 */
+	write32(pmc_ctlr_secure_scratch34_ptr, get_wakeup_vector());
+	write32(pmc_ctlr_secure_scratch35_ptr, 0);
+	write32(evp_cpu_reset_ptr, (uint32_t)aarch64_trampoline);
+
+	// Select CPU complex clock source.
+	write32(clk_rst_cclk_burst_policy_ptr, CCLK_PLLP_BURST_POLICY);
+
+	// Disable PLLX since it isn't used as CPU clock source.
+	clrbits32(PLLX_ENABLE, clk_rst_pllx_base_ptr);
+
+	// Set CAR2PMC_CPU_ACK_WIDTH to 408.
+	uint32_t ack_width = read32(clk_rst_cpu_softrst_ctrl2_ptr);
+	ack_width &= ~CAR2PMC_CPU_ACK_WIDTH_MASK;
+	ack_width |= 408 << CAR2PMC_CPU_ACK_WIDTH_SHIFT;
+	write32(clk_rst_cpu_softrst_ctrl2_ptr, ack_width);
+
+	// Disable VPR.
+	write32(mc_video_protect_size_mb_ptr, 0);
+	write32(mc_video_protect_reg_ctrl_ptr,
+		VIDEO_PROTECT_WRITE_ACCESS_DISABLE);
+
+	enable_cpu_clocks();
+
+	power_on_main_cpu();
+
+	// Perform ram repair after cpu is powered on.
+	ram_repair();
+
+	clear_cpu_resets();
+
+	// Halt the AVP.
+	while (1)
+		write32(flow_ctlr_halt_cop_events_ptr,
+		        FLOW_MODE_STOP | EVENT_JTAG);
+}
+
+
+
+/* Header. */
+
+extern uint8_t blob_data;
+extern uint8_t blob_data_size;
+extern uint8_t blob_total_size;
+
+struct lp0_header {
+	uint32_t length_insecure;	// Insecure total length.
+	uint32_t reserved[3];
+	uint8_t rsa_modulus[256];	// RSA key modulus.
+	uint8_t aes_signature[16];	// AES signature.
+	uint8_t rsa_signature[256];	// RSA-PSS signature.
+	uint8_t random_aes_block[16];	// Random data, may be zero.
+	uint32_t length_secure;		// Secure total length.
+	uint32_t destination;		// Where to load the blob in iRAM.
+	uint32_t entry_point;		// Entry point for the blob.
+	uint32_t code_length;		// Length of just the data.
+} __attribute__((packed));
+
+struct lp0_header header __attribute__((section(".header"))) =
+{
+	.length_insecure = (uintptr_t)&blob_total_size,
+	.length_secure = (uintptr_t)&blob_total_size,
+	.destination = (uintptr_t)&blob_data,
+	.entry_point = (uintptr_t)&lp0_resume,
+	.code_length = (uintptr_t)&blob_data_size
+};
diff --git a/src/soc/nvidia/tegra210/lp0/tegra_lp0_resume.ld b/src/soc/nvidia/tegra210/lp0/tegra_lp0_resume.ld
new file mode 100644
index 0000000..26cacbd
--- /dev/null
+++ b/src/soc/nvidia/tegra210/lp0/tegra_lp0_resume.ld
@@ -0,0 +1,73 @@
+/*
+ * Copyright 2014 Google Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc.
+ */
+
+/* We use ELF as output format. So that we can debug the code in some form. */
+OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
+OUTPUT_ARCH(arm)
+
+PHDRS
+{
+	to_load PT_LOAD;
+}
+
+ENTRY(lp0_resume)
+SECTIONS
+{
+	. = 0x40020000 - 0x240;
+
+	/*
+	 * The lp0 blob header is built as a static data structure and put
+	 * in the .header section.
+	 */
+	.header_start = .;
+	.header . : {
+		*(.header);
+	} : to_load = 0xff
+	.header_end = .;
+
+	. = 0x40020000;
+
+	/* The actual lp0 blob code. */
+	.data_start = .;
+	.data . : {
+		*(.text);
+		*(.text.*);
+		*(.rodata);
+		*(.rodata.*);
+		*(.data);
+		*(.data.*);
+		*(.bss);
+		*(.bss.*);
+		*(.sbss);
+		*(.sbss.*);
+		. = ALIGN(16);
+	}
+	.data_end = .;
+
+	/* Some values we need in the header. */
+	blob_data = .data_start;
+	blob_data_size = .data_end - .data_start;
+	blob_total_size = .data_end - .header_start;
+
+	/DISCARD/ : {
+		*(.comment)
+		*(.note)
+		*(.comment.*)
+		*(.note.*)
+		*(.ARM.*)
+	}
+}
diff --git a/src/soc/nvidia/tegra210/maincpu.S b/src/soc/nvidia/tegra210/maincpu.S
new file mode 100644
index 0000000..898d821
--- /dev/null
+++ b/src/soc/nvidia/tegra210/maincpu.S
@@ -0,0 +1,55 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright 2013 Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <arch/asm.h>
+
+ENTRY(maincpu_setup)
+	/*
+	 * Set the cpu to System mode with IRQ and FIQ disabled. Prefetch/Data
+	 * aborts may happen early and crash before the abort handlers are
+	 * installed, but at least the problem will show up near the code that
+	 * causes it.
+	 */
+	msr	cpsr, #0xdf
+
+	ldr	sp, maincpu_stack_pointer
+	eor	lr, lr
+	ldr	r0, maincpu_entry_point
+	bx	r0
+ENDPROC(maincpu_setup)
+
+	.align 2
+
+	.global maincpu_stack_pointer
+maincpu_stack_pointer:
+	.word 0
+
+	.global maincpu_entry_point
+maincpu_entry_point:
+	.word 0
diff --git a/src/soc/nvidia/tegra210/mipi-phy.c b/src/soc/nvidia/tegra210/mipi-phy.c
new file mode 100644
index 0000000..fc9d9de
--- /dev/null
+++ b/src/soc/nvidia/tegra210/mipi-phy.c
@@ -0,0 +1,92 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright 2014 Google Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc.
+ */
+#include <console/console.h>
+#include <arch/io.h>
+#include <stdint.h>
+#include <lib.h>
+#include <stdlib.h>
+
+#include <soc/addressmap.h>
+#include <soc/clock.h>
+#include <device/device.h>
+#include <soc/nvidia/tegra/types.h>
+#include <soc/display.h>
+#include <soc/mipi_dsi.h>
+#include <soc/mipi_display.h>
+#include <soc/tegra_dsi.h>
+#include <soc/mipi-phy.h>
+
+int mipi_dphy_set_timing(struct tegra_dsi *dsi)
+{
+
+	u32 freq = (dsi->clk_rate * 2) / 1000000;
+
+	u32 thsdexit = (DSI_PHY_TIMING_DIV(120, (freq)));
+	u32 thstrial = (((3) + (DSI_PHY_TIMING_DIV((DSI_THSTRAIL_VAL(freq)),
+			freq))));
+	u32 tdatzero = DSI_PHY_TIMING_DIV(((145) + (5 * (DSI_TBIT(freq)))),
+			(freq));
+	u32 thsprepare = DSI_PHY_TIMING_DIV((65 + (5*(DSI_TBIT(freq)))), freq);
+	u32 tclktrial = (DSI_PHY_TIMING_DIV(80, freq));
+	u32 tclkpost = ((DSI_PHY_TIMING_DIV(((70) + ((52) * (DSI_TBIT(freq)))),
+			freq)));
+	u32 tclkzero = (DSI_PHY_TIMING_DIV(260, freq));
+	u32 ttlpx = (DSI_PHY_TIMING_DIV(60, freq)) ;
+	u32 tclkprepare = (DSI_PHY_TIMING_DIV(60, freq));
+	u32 tclkpre = 1; //min = 8*UI per mipi spec, tclk_pre=0 should be ok, but using 1 value
+	u32 twakeup = 0x7F; //min = 1ms
+
+	u32 ttaget;
+	u32 ttassure;
+	u32 ttago;
+	u32 value;
+
+	if (!ttlpx) {
+		ttaget = 5;
+		ttassure = 2;
+		ttago = 4;
+	} else {
+		ttaget = 5 * ttlpx;
+		ttassure = 2 * ttlpx;
+		ttago = 4 * ttlpx;
+	}
+
+	value = (thsdexit << 24) |
+		(thstrial << 16) |
+		(tdatzero << 8) |
+		(thsprepare << 0);
+	tegra_dsi_writel(dsi, value, DSI_PHY_TIMING_0);
+
+	value = (tclktrial << 24) |
+		(tclkpost << 16)  |
+		(tclkzero << 8) |
+		(ttlpx << 0);
+	tegra_dsi_writel(dsi, value, DSI_PHY_TIMING_1);
+
+	value = (tclkprepare << 16) |
+		(tclkpre << 8) |
+		(twakeup << 0);
+	tegra_dsi_writel(dsi, value, DSI_PHY_TIMING_2);
+
+	value = (ttaget << 16) |
+		(ttassure << 8) |
+		(ttago << 0),
+	tegra_dsi_writel(dsi, value, DSI_BTA_TIMING);
+	return 0;
+}
diff --git a/src/soc/nvidia/tegra210/mipi.c b/src/soc/nvidia/tegra210/mipi.c
new file mode 100644
index 0000000..0035308
--- /dev/null
+++ b/src/soc/nvidia/tegra210/mipi.c
@@ -0,0 +1,204 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright 2014 Google Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc.
+ */
+#include <console/console.h>
+#include <arch/io.h>
+#include <stdint.h>
+#include <lib.h>
+#include <stdlib.h>
+#include <delay.h>
+#include <soc/addressmap.h>
+#include <soc/clock.h>
+#include <device/device.h>
+#include <soc/nvidia/tegra/types.h>
+#include <soc/display.h>
+#include <soc/mipi_dsi.h>
+#include <soc/tegra_dsi.h>
+#include "jdi_25x18_display/panel-jdi-lpm102a188a.h"
+
+static unsigned long dsi_pads[] = {
+	0x0c0, /* DSIA channel A & B pads */
+	0x300, /* DSIB channel A & B pads */
+};
+
+static struct tegra_mipi mipi_data = {
+	.regs = (void *)TEGRA_MIPI_CAL_BASE,
+};
+
+static inline unsigned long tegra_mipi_readl(struct tegra_mipi *mipi,
+					     unsigned long reg)
+{
+	return read32(mipi->regs + (reg << 2));
+}
+
+static inline void tegra_mipi_writel(struct tegra_mipi *mipi,
+				     unsigned long value, unsigned long reg)
+{
+	write32(mipi->regs + (reg << 2), value);
+}
+
+static const struct tegra_mipi_pad tegra210_mipi_pads[] = {
+	{ .data = MIPI_CAL_CONFIG_CSIA, .clk = 0 },
+	{ .data = MIPI_CAL_CONFIG_CSIB, .clk = 0 },
+	{ .data = MIPI_CAL_CONFIG_CSIC, .clk = 0 },
+	{ .data = MIPI_CAL_CONFIG_CSID, .clk = 0 },
+	{ .data = MIPI_CAL_CONFIG_CSIE, .clk = 0 },
+	{ .data = MIPI_CAL_CONFIG_CSIF, .clk = 0 },
+	{ .data = MIPI_CAL_CONFIG_DSIA, .clk = MIPI_CAL_CONFIG_DSIA_CLK },
+	{ .data = MIPI_CAL_CONFIG_DSIB, .clk = MIPI_CAL_CONFIG_DSIB_CLK },
+	{ .data = MIPI_CAL_CONFIG_DSIC, .clk = MIPI_CAL_CONFIG_DSIC_CLK },
+	{ .data = MIPI_CAL_CONFIG_DSID, .clk = MIPI_CAL_CONFIG_DSID_CLK },
+};
+
+static const struct tegra_mipi_soc tegra210_mipi_soc = {
+	.has_clk_lane = 1,
+	.pads = tegra210_mipi_pads,
+	.num_pads = ARRAY_SIZE(tegra210_mipi_pads),
+	.clock_enable_override = 1,
+	.needs_vclamp_ref = 0,
+	.pad_drive_down_ref = 0x0,
+	.pad_drive_up_ref = 0x3,
+	.pad_vclamp_level = 0x1,
+	.pad_vauxp_level = 0x1,
+	.hspdos = 0x0,
+	.hspuos = 0x2,
+	.termos = 0x0,
+	.hsclkpdos = 0x0,
+	.hsclkpuos = 0x2,
+};
+
+struct tegra_mipi_device *tegra_mipi_request(struct tegra_mipi_device *device,
+						int device_index)
+{
+	device->mipi = &mipi_data;
+	device->mipi->soc = &tegra210_mipi_soc;
+	device->pads = dsi_pads[device_index];
+
+	return device;
+}
+
+static int tegra_mipi_wait(struct tegra_mipi *mipi)
+{
+	u32 poll_interval_us = 1000;
+	u32 timeout_us = 250 * 1000;
+	unsigned long value;
+
+	do {
+		value = tegra_mipi_readl(mipi, MIPI_CAL_STATUS);
+		if ((value & MIPI_CAL_STATUS_ACTIVE) == 0 &&
+		    (value & MIPI_CAL_STATUS_DONE) != 0)
+			return 0;
+
+		if (timeout_us > poll_interval_us)
+			timeout_us -= poll_interval_us;
+		else
+			break;
+
+		udelay(poll_interval_us);
+	} while (1);
+
+	printk(BIOS_ERR, "%s: ERROR: timeout\n", __func__);
+	return -ETIMEDOUT;
+}
+
+int tegra_mipi_calibrate(struct tegra_mipi_device *device)
+{
+	const struct tegra_mipi_soc *soc = device->mipi->soc;
+	unsigned int i;
+	u32 value;
+	int err;
+
+	value = tegra_mipi_readl(device->mipi, MIPI_CAL_BIAS_PAD_CFG0);
+	value &= ~MIPI_CAL_BIAS_PAD_PDVCLAMP;
+
+	if (soc->needs_vclamp_ref)
+		value |= MIPI_CAL_BIAS_PAD_E_VCLAMP_REF;
+
+	tegra_mipi_writel(device->mipi, value, MIPI_CAL_BIAS_PAD_CFG0);
+
+	value = MIPI_CAL_BIAS_PAD_DRV_DN_REF(soc->pad_drive_down_ref) |
+		MIPI_CAL_BIAS_PAD_DRV_UP_REF(soc->pad_drive_up_ref);
+	tegra_mipi_writel(device->mipi, value, MIPI_CAL_BIAS_PAD_CFG1);
+
+	value = tegra_mipi_readl(device->mipi, MIPI_CAL_BIAS_PAD_CFG2);
+	value &= ~MIPI_CAL_BIAS_PAD_PDVREG;
+	tegra_mipi_writel(device->mipi, value, MIPI_CAL_BIAS_PAD_CFG2);
+
+	value = tegra_mipi_readl(device->mipi, MIPI_CAL_BIAS_PAD_CFG2);
+	value &= ~MIPI_CAL_BIAS_PAD_VCLAMP(0x7);
+	value &= ~MIPI_CAL_BIAS_PAD_VAUXP(0x7);
+	value |= MIPI_CAL_BIAS_PAD_VCLAMP(soc->pad_vclamp_level);
+	value |= MIPI_CAL_BIAS_PAD_VAUXP(soc->pad_vauxp_level);
+	tegra_mipi_writel(device->mipi, value, MIPI_CAL_BIAS_PAD_CFG2);
+
+	for (i = 0; i < soc->num_pads; i++) {
+		u32 clk = 0, data = 0;
+
+		if (device->pads & BIT(i)) {
+			data = MIPI_CAL_CONFIG_SELECT |
+			       MIPI_CAL_CONFIG_HSPDOS(soc->hspdos) |
+			       MIPI_CAL_CONFIG_HSPUOS(soc->hspuos) |
+			       MIPI_CAL_CONFIG_TERMOS(soc->termos);
+			clk = MIPI_CAL_CONFIG_SELECT |
+			      MIPI_CAL_CONFIG_HSCLKPDOSD(soc->hsclkpdos) |
+			      MIPI_CAL_CONFIG_HSCLKPUOSD(soc->hsclkpuos);
+		}
+
+		tegra_mipi_writel(device->mipi, data, soc->pads[i].data);
+
+		if (soc->has_clk_lane && soc->pads[i].clk != 0)
+			tegra_mipi_writel(device->mipi, clk, soc->pads[i].clk);
+	}
+
+	value = tegra_mipi_readl(device->mipi, MIPI_CAL_CTRL);
+	value &= ~MIPI_CAL_CTRL_NOISE_FILTER(0xf);
+	value &= ~MIPI_CAL_CTRL_PRESCALE(0x3);
+	value |= MIPI_CAL_CTRL_NOISE_FILTER(0xa);
+	value |= MIPI_CAL_CTRL_PRESCALE(0x2);
+
+	if (!soc->clock_enable_override)
+		value &= ~MIPI_CAL_CTRL_CLKEN_OVR;
+	else
+		value |= MIPI_CAL_CTRL_CLKEN_OVR;
+
+	tegra_mipi_writel(device->mipi, value, MIPI_CAL_CTRL);
+
+	/* clear any pending status bits */
+	value = tegra_mipi_readl(device->mipi, MIPI_CAL_STATUS);
+	tegra_mipi_writel(device->mipi, value, MIPI_CAL_STATUS);
+
+	value = tegra_mipi_readl(device->mipi, MIPI_CAL_CTRL);
+	value |= MIPI_CAL_CTRL_START;
+	tegra_mipi_writel(device->mipi, value, MIPI_CAL_CTRL);
+
+	err = tegra_mipi_wait(device->mipi);
+	if (err < 0)
+		printk(BIOS_ERR, "failed to calibrate MIPI pads: %d\n", err);
+	else
+		printk(BIOS_INFO, "MIPI calibration done\n");
+
+	value = tegra_mipi_readl(device->mipi, MIPI_CAL_BIAS_PAD_CFG0);
+
+	if (soc->needs_vclamp_ref)
+		value &= ~MIPI_CAL_BIAS_PAD_E_VCLAMP_REF;
+
+	value |= MIPI_CAL_BIAS_PAD_PDVCLAMP;
+	tegra_mipi_writel(device->mipi, value, MIPI_CAL_BIAS_PAD_CFG0);
+
+	return err;
+}
diff --git a/src/soc/nvidia/tegra210/mipi_dsi.c b/src/soc/nvidia/tegra210/mipi_dsi.c
new file mode 100644
index 0000000..5e4cf55
--- /dev/null
+++ b/src/soc/nvidia/tegra210/mipi_dsi.c
@@ -0,0 +1,431 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright 2014 Google Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc.
+ */
+/*
+ * MIPI DSI Bus
+ *
+ * Copyright (C) 2012-2013, Samsung Electronics, Co., Ltd.
+ * Andrzej Hajda <a.hajda at samsung.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+#include <console/console.h>
+#include <arch/io.h>
+#include <stdint.h>
+#include <lib.h>
+#include <stdlib.h>
+#include <delay.h>
+#include <string.h>
+#include <soc/addressmap.h>
+#include <soc/clock.h>
+#include <device/device.h>
+#include <soc/nvidia/tegra/types.h>
+#include <soc/display.h>
+#include <soc/mipi_dsi.h>
+#include <soc/mipi_display.h>
+#include <soc/tegra_dsi.h>
+
+struct mipi_dsi_device mipi_dsi_device_data[NUM_DSI] = {
+	{
+		.master = NULL,
+		.slave = &mipi_dsi_device_data[DSI_B],
+	},
+	{
+		.master = &mipi_dsi_device_data[DSI_A],
+		.slave = NULL,
+	},
+};
+
+static struct mipi_dsi_device *
+mipi_dsi_device_alloc(struct mipi_dsi_host *host)
+{
+	static int index = 0;
+	struct mipi_dsi_device *dsi;
+
+	if (index >= NUM_DSI)
+		return (void *)-EPTR;
+
+	dsi = &mipi_dsi_device_data[index++];
+	dsi->host = host;
+	return dsi;
+}
+
+static struct mipi_dsi_device *
+of_mipi_dsi_device_add(struct mipi_dsi_host *host)
+{
+	struct mipi_dsi_device *dsi;
+	u32 reg = 0;
+
+	dsi = mipi_dsi_device_alloc(host);
+	if (IS_ERR_PTR(dsi)) {
+		printk(BIOS_ERR, "failed to allocate DSI device\n");
+		return dsi;
+	}
+
+	dsi->channel = reg;
+	host->dev = (void *)dsi;
+
+	return dsi;
+}
+
+int mipi_dsi_host_register(struct mipi_dsi_host *host)
+{
+	of_mipi_dsi_device_add(host);
+	return 0;
+}
+
+/**
+ * mipi_dsi_attach - attach a DSI device to its DSI host
+ * @dsi: DSI peripheral
+ */
+int mipi_dsi_attach(struct mipi_dsi_device *dsi)
+{
+	const struct mipi_dsi_host_ops *ops = dsi->host->ops;
+
+	if (!ops || !ops->attach)
+		return -ENOSYS;
+
+	return ops->attach(dsi->host, dsi);
+}
+
+/**
+ * mipi_dsi_detach - detach a DSI device from its DSI host
+ * @dsi: DSI peripheral
+ */
+int mipi_dsi_detach(struct mipi_dsi_device *dsi)
+{
+	const struct mipi_dsi_host_ops *ops = dsi->host->ops;
+
+	if (!ops || !ops->detach)
+		return -ENOSYS;
+
+	return ops->detach(dsi->host, dsi);
+}
+
+/**
+ * mipi_dsi_enslave() - use a MIPI DSI peripheral as slave for dual-channel
+ *    operation
+ * @master: master DSI peripheral device
+ * @slave: slave DSI peripheral device
+ *
+ * Return: 0 on success or a negative error code on failure.
+ */
+int mipi_dsi_enslave(struct mipi_dsi_device *master,
+		     struct mipi_dsi_device *slave)
+{
+	int err = 0;
+
+	slave->master = master;
+	master->slave = slave;
+
+	if (master->ops && master->ops->enslave)
+		err = master->ops->enslave(master, slave);
+
+	return err;
+}
+
+/**
+ * mipi_dsi_liberate() - stop using a MIPI DSI peripheral as slave for dual-
+ *    channel operation
+ * @master: master DSI peripheral device
+ * @slave: slave DSI peripheral device
+ *
+ * Return: 0 on success or a negative error code on failure.
+ */
+int mipi_dsi_liberate(struct mipi_dsi_device *master,
+		      struct mipi_dsi_device *slave)
+{
+	int err = 0;
+
+	if (master->ops && master->ops->liberate)
+		err = master->ops->liberate(master, slave);
+
+	master->slave = NULL;
+	slave->master = NULL;
+
+	return err;
+}
+
+/**
+ * mipi_dsi_dcs_write() - send DCS write command
+ * @dsi: DSI peripheral device
+ * @cmd: DCS command
+ * @data: buffer containing the command payload
+ * @len: command payload length
+ *
+ * This function will automatically choose the right data type depending on
+ * the command payload length.
+ *
+ * Return: The number of bytes successfully transmitted or a negative error
+ * code on failure.
+ */
+ssize_t mipi_dsi_dcs_write(struct mipi_dsi_device *dsi, u8 cmd,
+			   const void *data, size_t len)
+{
+	struct mipi_dsi_msg msg;
+	ssize_t err;
+	size_t size;
+
+	u8 buffer[MAX_DSI_HOST_FIFO_DEPTH + 4];
+	u8 *tx = buffer;
+
+	if (len > MAX_DSI_HOST_FIFO_DEPTH) {
+		printk(BIOS_ERR, "%s: Error: too large payload length: %zu\n",
+			__func__, len);
+
+		return -EINVAL;
+	}
+
+	if (len > 0) {
+		unsigned int offset = 0;
+
+		/*
+		 * DCS long write packets contain the word count in the header
+		 * bytes 1 and 2 and have a payload containing the DCS command
+		 * byte folowed by word count minus one bytes.
+		 *
+		 * DCS short write packets encode the DCS command and up to
+		 * one parameter in header bytes 1 and 2.
+		 */
+		if (len > 1)
+			size = 3 + len;
+		else
+			size = 1 + len;
+
+		/* write word count to header for DCS long write packets */
+		if (len > 1) {
+			tx[offset++] = ((1 + len) >> 0) & 0xff;
+			tx[offset++] = ((1 + len) >> 8) & 0xff;
+		}
+
+		/* write the DCS command byte followed by the payload */
+		tx[offset++] = cmd;
+		memcpy(tx + offset, data, len);
+	} else {
+		tx = &cmd;
+		size = 1;
+	}
+
+	memset(&msg, 0, sizeof(msg));
+	msg.flags = MIPI_DSI_MSG_USE_LPM;
+	msg.channel = dsi->channel;
+	msg.tx_len = size;
+	msg.tx_buf = tx;
+
+	switch (len) {
+	case 0:
+		msg.type = MIPI_DSI_DCS_SHORT_WRITE;
+		break;
+	case 1:
+		msg.type = MIPI_DSI_DCS_SHORT_WRITE_PARAM;
+		break;
+	default:
+		msg.type = MIPI_DSI_DCS_LONG_WRITE;
+		break;
+	}
+
+	err = dsi->host->ops->transfer(dsi->host, &msg);
+
+	return err;
+}
+
+/**
+ * mipi_dsi_dcs_exit_sleep_mode() - enable all blocks inside the display
+ *    module
+ * @dsi: DSI peripheral device
+ *
+ * Return: 0 on success or a negative error code on failure.
+ */
+int mipi_dsi_dcs_exit_sleep_mode(struct mipi_dsi_device *dsi)
+{
+	ssize_t err;
+
+	err = mipi_dsi_dcs_write(dsi, MIPI_DCS_EXIT_SLEEP_MODE, NULL, 0);
+	if (err < 0)
+		return err;
+
+	return 0;
+}
+
+/**
+ * mipi_dsi_dcs_set_display_on() - start displaying the image data on the
+ *    display device
+ * @dsi: DSI peripheral device
+ *
+ * Return: 0 on success or a negative error code on failure
+ */
+int mipi_dsi_dcs_set_display_on(struct mipi_dsi_device *dsi)
+{
+	ssize_t err;
+
+	err = mipi_dsi_dcs_write(dsi, MIPI_DCS_SET_DISPLAY_ON, NULL, 0);
+	if (err < 0)
+		return err;
+
+	return 0;
+}
+
+/**
+ * mipi_dsi_dcs_set_column_address() - define the column extent of the frame
+ *    memory accessed by the host processor
+ * @dsi: DSI peripheral device
+ * @start: first column of frame memory
+ * @end: last column of frame memory
+ *
+ * Return: 0 on success or a negative error code on failure.
+ */
+int mipi_dsi_dcs_set_column_address(struct mipi_dsi_device *dsi, u16 start,
+				    u16 end)
+{
+	u8 payload[4] = { start >> 8, start & 0xff, end >> 8, end & 0xff };
+	ssize_t err;
+
+	err = mipi_dsi_dcs_write(dsi, MIPI_DCS_SET_COLUMN_ADDRESS, payload,
+				 sizeof(payload));
+	if (err < 0)
+		return err;
+
+	return 0;
+}
+
+/**
+ * mipi_dsi_dcs_set_page_address() - define the page extent of the frame
+ *    memory accessed by the host processor
+ * @dsi: DSI peripheral device
+ * @start: first page of frame memory
+ * @end: last page of frame memory
+ *
+ * Return: 0 on success or a negative error code on failure.
+ */
+int mipi_dsi_dcs_set_page_address(struct mipi_dsi_device *dsi, u16 start,
+				  u16 end)
+{
+	u8 payload[4] = { start >> 8, start & 0xff, end >> 8, end & 0xff };
+	ssize_t err;
+
+	err = mipi_dsi_dcs_write(dsi, MIPI_DCS_SET_PAGE_ADDRESS, payload,
+				 sizeof(payload));
+	if (err < 0)
+		return err;
+
+	return 0;
+}
+
+/**
+ * mipi_dsi_dcs_set_tear_on() - turn on the display module's Tearing Effect
+ *    output signal on the TE signal line.
+ * @dsi: DSI peripheral device
+ * @mode: the Tearing Effect Output Line mode
+ *
+ * Return: 0 on success or a negative error code on failure
+ */
+int mipi_dsi_dcs_set_tear_on(struct mipi_dsi_device *dsi,
+			     enum mipi_dsi_dcs_tear_mode mode)
+{
+	u8 value = mode;
+	ssize_t err;
+
+	err = mipi_dsi_dcs_write(dsi, MIPI_DCS_SET_TEAR_ON, &value,
+				 sizeof(value));
+	if (err < 0)
+		return err;
+
+	return 0;
+}
+
+/**
+ * mipi_dsi_dcs_set_pixel_format() - sets the pixel format for the RGB image
+ *    data used by the interface
+ * @dsi: DSI peripheral device
+ * @format: pixel format
+ *
+ * Return: 0 on success or a negative error code on failure.
+ */
+int mipi_dsi_dcs_set_pixel_format(struct mipi_dsi_device *dsi, u8 format)
+{
+	ssize_t err;
+
+	err = mipi_dsi_dcs_write(dsi, MIPI_DCS_SET_PIXEL_FORMAT, &format,
+				 sizeof(format));
+	if (err < 0)
+		return err;
+
+	return 0;
+}
+
+/**
+ * mipi_dsi_dcs_set_address_mode() - sets the data order for forward transfers
+ *    from the host to the peripheral
+ * @dsi: DSI peripheral device
+ * @reverse_page_address: reverses the page addressing to bottom->top
+ * @reverse_col_address: reverses the column addressing to right->left
+ * @reverse_page_col_address: reverses the page/column addressing order
+ * @refresh_from_bottom: refresh the display bottom to top
+ * @reverse_rgb: send pixel data bgr instead of rgb
+ * @latch_right_to_left: latch the incoming display data right to left
+ * @flip_horizontal: flip the image horizontally, left to right
+ * @flip_vertical: flip the image vertically, top to bottom
+ *
+ * Return: 0 on success or a negative error code on failure.
+ */
+int mipi_dsi_dcs_set_address_mode(struct mipi_dsi_device *dsi,
+			bool reverse_page_address,
+			bool reverse_col_address,
+			bool reverse_page_col_address,
+			bool refresh_from_bottom,
+			bool reverse_rgb,
+			bool latch_right_to_left,
+			bool flip_horizontal,
+			bool flip_vertical)
+{
+	ssize_t err;
+	u8 data;
+
+	data = ((flip_vertical ? 1 : 0) << 0) |
+		((flip_horizontal ? 1 : 0) << 1) |
+		((latch_right_to_left ? 1 : 0) << 2) |
+		((reverse_rgb ? 1 : 0) << 3) |
+		((refresh_from_bottom ? 1 : 0) << 4) |
+		((reverse_page_col_address ? 1 : 0) << 5) |
+		((reverse_col_address ? 1 : 0) << 6) |
+		((reverse_page_address ? 1 : 0) << 7);
+
+	err = mipi_dsi_dcs_write(dsi, MIPI_DCS_SET_ADDRESS_MODE, &data, 1);
+	if (err < 0)
+		return err;
+
+	return 0;
+}
diff --git a/src/soc/nvidia/tegra210/mmu_operations.c b/src/soc/nvidia/tegra210/mmu_operations.c
new file mode 100644
index 0000000..b399e14
--- /dev/null
+++ b/src/soc/nvidia/tegra210/mmu_operations.c
@@ -0,0 +1,81 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright 2014 Google Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc.
+ */
+
+#include <arch/mmu.h>
+#include <memrange.h>
+#include <soc/addressmap.h>
+#include <soc/mmu_operations.h>
+#include <stdlib.h>
+#include <stdint.h>
+
+/* This structure keeps track of all the mmap memory ranges for t210 */
+static struct memranges t210_mmap_ranges;
+
+static void tegra210_memrange_init(struct memranges *map)
+{
+	uint64_t start,end;
+	const unsigned long devmem = MA_DEV | MA_S | MA_RW;
+	const unsigned long cachedmem = MA_MEM | MA_NS | MA_RW;
+	const unsigned long secure_mem = MA_MEM | MA_S | MA_RW;
+	uintptr_t tz_base_mib;
+	size_t tz_size_mib;
+
+	memranges_init_empty(map);
+
+	memory_in_range_below_4gb(&start,&end);
+
+	/* Device memory below DRAM */
+	memranges_insert(map, 0, start * MiB, devmem);
+
+	/* DRAM */
+	memranges_insert(map, start * MiB, (end-start) * MiB, cachedmem);
+
+	memory_in_range_above_4gb(&start,&end);
+
+	memranges_insert(map, start * MiB, (end-start) * MiB, cachedmem);
+
+	/* SRAM */
+	memranges_insert(map, TEGRA_SRAM_BASE, TEGRA_SRAM_SIZE, cachedmem);
+
+	/* Add TZ carveout. */
+	carveout_range(CARVEOUT_TZ, &tz_base_mib, &tz_size_mib);
+	memranges_insert(map, tz_base_mib * MiB, tz_size_mib * MiB, secure_mem);
+}
+
+void __attribute__((weak)) mainboard_add_memory_ranges(struct memranges *map)
+{
+	/* Don't add any ranges by default. */
+}
+
+void tegra210_mmu_init(void)
+{
+	uintptr_t tz_base_mib;
+	size_t tz_size_mib;
+	size_t ttb_size_mib;
+	struct memranges *map = &t210_mmap_ranges;
+
+	tegra210_memrange_init(map);
+	mainboard_add_memory_ranges(map);
+	/* Place page tables at the base of the trust zone region. */
+	carveout_range(CARVEOUT_TZ, &tz_base_mib, &tz_size_mib);
+	tz_base_mib *= MiB;
+	ttb_size_mib = TTB_SIZE * MiB;
+	mmu_init(map, (void *)tz_base_mib, ttb_size_mib);
+	mmu_enable();
+}
diff --git a/src/soc/nvidia/tegra210/monotonic_timer.c b/src/soc/nvidia/tegra210/monotonic_timer.c
new file mode 100644
index 0000000..560a7a5
--- /dev/null
+++ b/src/soc/nvidia/tegra210/monotonic_timer.c
@@ -0,0 +1,27 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright 2014 Google Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc.
+ */
+
+#include <arch/io.h>
+#include <soc/addressmap.h>
+#include <timer.h>
+
+void timer_monotonic_get(struct mono_time *mt)
+{
+	mono_time_set_usecs(mt, read32((void *)TEGRA_TMRUS_BASE));
+}
diff --git a/src/soc/nvidia/tegra210/mtc.c b/src/soc/nvidia/tegra210/mtc.c
new file mode 100644
index 0000000..fb6c9cb
--- /dev/null
+++ b/src/soc/nvidia/tegra210/mtc.c
@@ -0,0 +1,89 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright 2015 Google Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc.
+ */
+
+#include <cbfs.h>
+#include <cbmem.h>
+#include <console/console.h>
+#include <soc/mtc.h>
+#include <string.h>
+
+static size_t mtc_table_size;
+
+#define MAX_MTC_TABLE_ENTRIES	20
+#define MTC_TABLE_ENTRY_SIZE	4880
+#define MTC_TABLE_MAX_SIZE	(MAX_MTC_TABLE_ENTRIES * MTC_TABLE_ENTRY_SIZE)
+
+int tegra210_run_mtc(void)
+{
+	ssize_t nread;
+	struct region_device fh;
+
+	void * const mtc = (void *)(uintptr_t)CONFIG_MTC_ADDRESS;
+	void *dvfs_table;
+	size_t (*mtc_fw)(void **dvfs_table) = (void *)mtc;
+
+	if (cbfs_boot_locate(&fh, "tegra_mtc.bin", NULL)) {
+		printk(BIOS_ERR, "MTC file not found: tegra_mtc.bin\n");
+		return -1;
+	}
+
+	/* Read MTC file into predefined region. */
+	nread = rdev_readat(&fh, mtc, 0, region_device_sz(&fh));
+
+	if (nread != region_device_sz(&fh)) {
+		printk(BIOS_ERR, "MTC bytes read (%zu) != file length(%zu)!\n",
+		       nread, region_device_sz(&fh));
+		return -1;
+	}
+
+	printk(BIOS_INFO, "MTC: %zu bytes loaded @ %p\n", nread, mtc);
+
+	mtc_table_size = (*mtc_fw)(&dvfs_table);
+
+	if ((mtc_table_size == 0) || (mtc_table_size > MTC_TABLE_MAX_SIZE)) {
+		printk(BIOS_ERR, "MTC Training table size is invalid.!\n");
+		return -1;
+	}
+
+	printk(BIOS_INFO, "MTC: Done. Entries size 0x%zx located at %p\n",
+	       mtc_table_size, dvfs_table);
+
+	void *cbmem_tab = cbmem_add(CBMEM_ID_MTC, mtc_table_size);
+	if (cbmem_tab == NULL) {
+		printk(BIOS_ERR, "MTC table allocation in cbmem failed!\n");
+		return -1;
+	}
+
+	memcpy(cbmem_tab, dvfs_table, mtc_table_size);
+	printk(BIOS_INFO, "MTC: Copied 0x%zx bytes from %p to %p\n",
+	       mtc_table_size, dvfs_table, cbmem_tab);
+
+	return 0;
+}
+
+void soc_add_mtc(struct lb_header *header)
+{
+	struct lb_range *mtc;
+	mtc = (struct lb_range *)lb_new_record(header);
+	mtc->tag = LB_TAG_MTC;
+	mtc->size = sizeof(*mtc);
+
+	mtc->range_start = (uintptr_t)cbmem_find(CBMEM_ID_MTC);
+	mtc->range_size = mtc_table_size;
+}
diff --git a/src/soc/nvidia/tegra210/padconfig.c b/src/soc/nvidia/tegra210/padconfig.c
new file mode 100644
index 0000000..ab93454
--- /dev/null
+++ b/src/soc/nvidia/tegra210/padconfig.c
@@ -0,0 +1,137 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright 2014 Google Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc.
+ */
+
+#include <arch/io.h>
+#include <soc/addressmap.h>
+#include <soc/padconfig.h>
+
+static uint32_t * const pinmux_regs = (void *)(uintptr_t)TEGRA_APB_PINMUX_BASE;
+static struct gpio_bank * const gpio_regs = (void *)(uintptr_t)TEGRA_GPIO_BASE;
+
+static inline struct gpio_bank * const get_gpio_bank_regs(int index)
+{
+	return &gpio_regs[gpio_index_to_bank(index)];
+}
+
+static inline uint32_t pad_get_pinmux(int index)
+{
+	return read32(&pinmux_regs[index]);
+}
+
+static inline void pad_set_pinmux(int index, uint32_t reg)
+{
+	return write32(&pinmux_regs[index], reg);
+}
+
+static inline void pad_set_gpio_out(int gpio_index, int val)
+{
+	struct gpio_bank * const regs = get_gpio_bank_regs(gpio_index);
+	int port = gpio_index_to_port(gpio_index);
+	int bit = gpio_to_bit(gpio_index);
+
+	write32(&regs->out_value_mask[port],
+		(1 << (bit + GPIO_GPIOS_PER_PORT)) | (val << bit));
+	write32(&regs->out_enable_mask[port],
+		(1 << (bit + GPIO_GPIOS_PER_PORT)) | (1 << bit));
+}
+
+static inline void pad_set_mode(int gpio_index, int sfio_or_gpio)
+{
+	struct gpio_bank * const regs = get_gpio_bank_regs(gpio_index);
+	int port = gpio_index_to_port(gpio_index);
+	int bit = gpio_to_bit(gpio_index);
+
+	write32(&regs->config_mask[port],
+		(1 << (bit + GPIO_GPIOS_PER_PORT)) | (sfio_or_gpio << bit));
+}
+
+static inline void pad_set_gpio_mode(int gpio_index)
+{
+	pad_set_mode(gpio_index, 1);
+}
+
+static inline void pad_set_sfio_mode(int gpio_index)
+{
+	pad_set_mode(gpio_index, 0);
+}
+
+static void configure_unused_pad(const struct pad_config * const entry)
+{
+	uint32_t reg;
+
+	/*
+	 * Tristate the pad and disable input. If power-on-reset state is a
+	 * pullup maintain that. Otherwise enable pulldown.
+	 */
+	reg = pad_get_pinmux(entry->pinmux_index);
+	reg &= ~PINMUX_INPUT_ENABLE;
+	reg |= PINMUX_TRISTATE;
+	reg &= ~PINMUX_PULL_MASK;
+	if (entry->por_pullup)
+		reg |= PINMUX_PULL_UP;
+	else
+		reg |= PINMUX_PULL_DOWN;
+	pad_set_pinmux(entry->pinmux_index, reg);
+
+	/*
+	 * Set to GPIO mode if GPIO available to bypass collisions of
+	 * controller signals going to more than one pad.
+	 */
+	if (entry->pad_has_gpio)
+		pad_set_gpio_mode(entry->gpio_index);
+}
+
+static void configure_sfio_pad(const struct pad_config * const entry)
+{
+	pad_set_pinmux(entry->pinmux_index, entry->pinmux_flags);
+	pad_set_sfio_mode(entry->gpio_index);
+}
+
+static void configure_gpio_pad(const struct pad_config * const entry)
+{
+	uint32_t reg;
+
+	if (entry->gpio_out0 || entry->gpio_out1)
+		pad_set_gpio_out(entry->gpio_index, entry->gpio_out1 ? 1 : 0);
+
+	/* Keep the original SFIO selection. */
+	reg = pinmux_get_config(entry->pinmux_index);
+	reg &= PINMUX_FUNC_MASK;
+	reg |= entry->pinmux_flags;
+
+	pad_set_pinmux(entry->pinmux_index, reg);
+	pad_set_gpio_mode(entry->gpio_index);
+}
+
+void soc_configure_pads(const struct pad_config * const entries, size_t num)
+{
+	size_t i;
+
+	for (i = 0; i < num; i++) {
+		const struct pad_config * const entry = &entries[i];
+
+		if (entry->unused) {
+			configure_unused_pad(entry);
+		} else if (entry->sfio) {
+			configure_sfio_pad(entry);
+		} else {
+			configure_gpio_pad(entry);
+		}
+	}
+}
diff --git a/src/soc/nvidia/tegra210/power.c b/src/soc/nvidia/tegra210/power.c
new file mode 100644
index 0000000..6951e11
--- /dev/null
+++ b/src/soc/nvidia/tegra210/power.c
@@ -0,0 +1,129 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright 2013 Google Inc.
+ * Copyright (c) 2013, NVIDIA CORPORATION.  All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc.
+ */
+
+#include <arch/io.h>
+#include <assert.h>
+#include <console/console.h>
+#include <soc/addressmap.h>
+#include <soc/pmc.h>
+#include <soc/power.h>
+
+static struct tegra_pmc_regs * const pmc = (void *)TEGRA_PMC_BASE;
+
+enum {
+	POWER_GATE = 0,
+	POWER_UNGATE = 1,
+};
+
+static int partition_powered(int id)
+{
+	if (read32(&pmc->pwrgate_status) & (0x1 << id))
+		return POWER_UNGATE;
+
+	return POWER_GATE;
+}
+
+static const char * const power_gate_string[] = {
+	[POWER_GATE] = "Gat",
+	[POWER_UNGATE] = "Ungat",
+};
+
+static void power_gate_toggle_request(uint32_t id, int request)
+{
+	printk(BIOS_INFO, "%sing power partition %d.\n",
+	       power_gate_string[request], id);
+
+	int part_powered = partition_powered(id);
+
+	if (request == part_powered) {
+		printk(BIOS_INFO, "Partition %d already %sed.\n", id,
+		       power_gate_string[request]);
+		return;
+	}
+
+	uint32_t pwrgate_toggle = read32(&pmc->pwrgate_toggle);
+	pwrgate_toggle &= ~(PMC_PWRGATE_TOGGLE_PARTID_MASK);
+	pwrgate_toggle |= (id << PMC_PWRGATE_TOGGLE_PARTID_SHIFT);
+	pwrgate_toggle |= PMC_PWRGATE_TOGGLE_START;
+	write32(&pmc->pwrgate_toggle, pwrgate_toggle);
+
+	// Wait for the request to be accepted.
+	while (read32(&pmc->pwrgate_toggle) & PMC_PWRGATE_TOGGLE_START)
+		;
+	printk(BIOS_INFO, "Power gate toggle request accepted.\n");
+
+	while (1) {
+		part_powered = partition_powered(id);
+		if (request == part_powered) {
+			printk(BIOS_INFO, "Partition %d %sed.\n", id,
+			       power_gate_string[request]);
+			return;
+		}
+	}
+}
+
+void power_gate_partition(uint32_t id)
+{
+	power_gate_toggle_request(id, POWER_GATE);
+}
+
+void power_ungate_partition(uint32_t id)
+{
+	power_gate_toggle_request(id, POWER_UNGATE);
+}
+
+uint8_t pmc_rst_status(void)
+{
+	return read32(&pmc->rst_status) & PMC_RST_STATUS_SOURCE_MASK;
+}
+
+static const char *pmc_rst_status_str[PMC_RST_STATUS_NUM_SOURCES] = {
+	[PMC_RST_STATUS_SOURCE_POR] = "POR",
+	[PMC_RST_STATUS_SOURCE_WATCHDOG] = "Watchdog",
+	[PMC_RST_STATUS_SOURCE_SENSOR] = "Sensor",
+	[PMC_RST_STATUS_SOURCE_SW_MAIN] = "SW Main",
+	[PMC_RST_STATUS_SOURCE_LP0] = "LP0",
+};
+
+void pmc_print_rst_status(void)
+{
+	uint8_t rst_status = pmc_rst_status();
+	assert(rst_status < PMC_RST_STATUS_NUM_SOURCES);
+	printk(BIOS_INFO, "PMC Reset Status: %s\n",
+	       pmc_rst_status_str[rst_status]);
+}
+
+static int partition_clamp_on(int id)
+{
+	return read32(&pmc->clamp_status) & (1 << id);
+}
+
+void remove_clamps(int id)
+{
+	if (!partition_clamp_on(id))
+		return;
+
+	/* Remove clamp */
+	write32(&pmc->remove_clamping_cmd, (1 << id));
+
+	/* Wait for clamp off */
+	while (partition_clamp_on(id))
+		;
+}
diff --git a/src/soc/nvidia/tegra210/psci.c b/src/soc/nvidia/tegra210/psci.c
new file mode 100644
index 0000000..25a899e
--- /dev/null
+++ b/src/soc/nvidia/tegra210/psci.c
@@ -0,0 +1,194 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright 2014 Google Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc.
+ */
+
+#include <assert.h>
+#include <arch/cpu.h>
+#include <arch/io.h>
+#include <arch/psci.h>
+#include <soc/addressmap.h>
+#include <soc/clk_rst.h>
+#include <soc/cpu.h>
+#include <soc/flow_ctrl.h>
+#include <soc/power.h>
+#include <stdlib.h>
+
+#include <console/console.h>
+
+extern void tegra210_reset_handler(void);
+
+#define TEGRA210_PM_STATE_C7	7
+
+static void *cpu_on_entry_point;
+
+void psci_soc_init(uintptr_t cpu_on_entry)
+{
+	/*
+	 * Stash secmon entry point for CPUs starting up. The 32-bit reset
+	 * vector register is accessible in < EL3 so one has to attempt to
+	 * plug the potential race for that register being changed out from
+	 * under us. Therefore, we set the appropriate registers here, but
+	 * it is also done on each CPU_ON request.
+	 */
+	cpu_on_entry_point = tegra210_reset_handler;
+	cpu_prepare_startup(cpu_on_entry_point);
+}
+
+static size_t children_at_level(int parent_level, uint64_t mpidr)
+{
+	if (mpidr != 0)
+		return 0;
+
+	/*
+	 * T210 has 2 clusters. Each cluster has 4 cores. Currently we are
+	 * concentrating only on one of the clusters i.e. A57 cluster. For A53
+	 * bringup, correct the cluster details for A53 cluster as well.
+	 * Since, A57 cluster has 4 cores, level 1 has 4 children at level 0.
+	 * TODO(furquan): Update for A53.
+	 */
+	switch (parent_level) {
+	case PSCI_AFFINITY_ROOT:
+		return 1;
+	case PSCI_AFFINITY_LEVEL_3:
+		return 1;
+	case PSCI_AFFINITY_LEVEL_2:
+		return 1;
+	case PSCI_AFFINITY_LEVEL_1:
+		return 4;
+	case PSCI_AFFINITY_LEVEL_0:
+		return 0;
+	default:
+		return 0;
+	}
+}
+
+static void prepare_cpu_on(int cpu)
+{
+	cpu_prepare_startup(cpu_on_entry_point);
+}
+
+static void prepare_cpu_suspend(int cpu, uint32_t state_id)
+{
+	flowctrl_write_cc4_ctrl(cpu, 0xffffffff);
+	switch (state_id) {
+	case TEGRA210_PM_STATE_C7:
+		flowctrl_cpu_suspend(cpu);
+		break;
+	default:
+		return;
+	}
+}
+
+static void prepare_cpu_resume(int cpu)
+{
+	flowctrl_write_cpu_csr(cpu, 0);
+	flowctrl_write_cpu_halt(cpu, 0);
+	flowctrl_write_cc4_ctrl(cpu, 0);
+}
+
+static void cpu_suspend_commit(int cpu, uint32_t state_id)
+{
+	int l2_flush;
+
+	switch (state_id) {
+	case TEGRA210_PM_STATE_C7:
+		l2_flush = NO_L2_FLUSH;
+		break;
+	default:
+		return;
+	}
+
+	cortex_a57_cpu_power_down(l2_flush);
+	/* should never be here */
+}
+
+static int cmd_prepare(struct psci_cmd *cmd)
+{
+	int ret;
+	struct cpu_info *ci;
+
+	ci = cmd->target->cpu_state.ci;
+
+	switch (cmd->type) {
+	case PSCI_CMD_SUSPEND:
+		cmd->state_id = cmd->state->id;
+		prepare_cpu_on(ci->id);
+		prepare_cpu_suspend(ci->id, cmd->state_id);
+		ret = PSCI_RET_SUCCESS;
+		break;
+	case PSCI_CMD_RESUME:
+		prepare_cpu_resume(ci->id);
+		ret = PSCI_RET_SUCCESS;
+		break;
+	case PSCI_CMD_ON:
+		prepare_cpu_on(ci->id);
+		ret = PSCI_RET_SUCCESS;
+		break;
+	case PSCI_CMD_OFF:
+		if (cmd->state_id != -1) {
+			ret = PSCI_RET_INVALID_PARAMETERS;
+			break;
+		}
+		ret = PSCI_RET_SUCCESS;
+		break;
+	default:
+		ret = PSCI_RET_NOT_SUPPORTED;
+		break;
+	}
+	return ret;
+}
+
+static int cmd_commit(struct psci_cmd *cmd)
+{
+	int ret;
+	struct cpu_info *ci;
+
+	ci = cmd->target->cpu_state.ci;
+
+	switch (cmd->type) {
+	case PSCI_CMD_SUSPEND:
+		cpu_suspend_commit(ci->id, cmd->state_id);
+		ret = PSCI_RET_SUCCESS;
+		break;
+	case PSCI_CMD_RESUME:
+		ret = PSCI_RET_SUCCESS;
+		break;
+	case PSCI_CMD_ON:
+		/* Take CPU out of reset */
+		flowctrl_cpu_on(ci->id);
+		ret = PSCI_RET_SUCCESS;
+		break;
+	case PSCI_CMD_OFF:
+		flowctrl_cpu_off(ci->id);
+		cortex_a57_cpu_power_down(NO_L2_FLUSH);
+		/* Never reach here */
+		ret = PSCI_RET_NOT_SUPPORTED;
+		printk(BIOS_ERR, "t210 CPU%d PSCI_CMD_OFF fail\n", ci->id);
+		break;
+	default:
+		ret = PSCI_RET_NOT_SUPPORTED;
+		break;
+	}
+	return ret;
+}
+
+struct psci_soc_ops soc_psci_ops = {
+	.children_at_level = &children_at_level,
+	.cmd_prepare = &cmd_prepare,
+	.cmd_commit = &cmd_commit,
+};
diff --git a/src/soc/nvidia/tegra210/ram_code.c b/src/soc/nvidia/tegra210/ram_code.c
new file mode 100644
index 0000000..8715410
--- /dev/null
+++ b/src/soc/nvidia/tegra210/ram_code.c
@@ -0,0 +1,29 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright 2014 Google Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <arch/io.h>
+#include <soc/addressmap.h>
+#include <soc/sdram.h>
+#include <soc/nvidia/tegra/apbmisc.h>
+
+uint32_t sdram_get_ram_code(void)
+{
+	struct apbmisc *misc = (struct apbmisc *)TEGRA_APB_MISC_BASE;
+
+	return (read32(&misc->pp_strapping_opt_a) &
+		PP_STRAPPING_OPT_A_RAM_CODE_MASK) >>
+		PP_STRAPPING_OPT_A_RAM_CODE_SHIFT;
+}
diff --git a/src/soc/nvidia/tegra210/ramstage.c b/src/soc/nvidia/tegra210/ramstage.c
new file mode 100644
index 0000000..7838c69
--- /dev/null
+++ b/src/soc/nvidia/tegra210/ramstage.c
@@ -0,0 +1,39 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright 2014 Google Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc.
+ */
+
+#include <arch/clock.h>
+#include <arch/cpu.h>
+#include <arch/stages.h>
+#include <soc/addressmap.h>
+#include <soc/clock.h>
+#include <soc/mmu_operations.h>
+
+void arm64_arch_timer_init(void)
+{
+	uint32_t freq = clock_get_osc_khz() * 1000;
+	// Set the cntfrq register.
+	set_cntfrq(freq);
+}
+
+void arm64_soc_init(void)
+{
+	trustzone_region_init();
+
+	tegra210_mmu_init();
+}
diff --git a/src/soc/nvidia/tegra210/reset.c b/src/soc/nvidia/tegra210/reset.c
new file mode 100644
index 0000000..dee2786
--- /dev/null
+++ b/src/soc/nvidia/tegra210/reset.c
@@ -0,0 +1,29 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright 2014 Google Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc.
+ */
+
+#include <reset.h>
+
+/*
+ * Promote cpu_reset() to a hard_reset(). A shallower reset can be added,
+ * if needed, at a later time.
+ */
+void cpu_reset(void)
+{
+	hard_reset();
+}
diff --git a/src/soc/nvidia/tegra210/reset_handler.S b/src/soc/nvidia/tegra210/reset_handler.S
new file mode 100644
index 0000000..53622b1
--- /dev/null
+++ b/src/soc/nvidia/tegra210/reset_handler.S
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2015, NVIDIA CORPORATION.  All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <arch/asm.h>
+
+#define CPUACTLR_EL1 s3_1_c15_c2_0
+
+CPU_RESET_ENTRY(tegra210_reset_handler)
+	/*
+	 * Invalidate BTB along with I$ to remove any stale entries
+	 * from the branch predictor array.
+	 */
+	mrs	x0, CPUACTLR_EL1
+	orr	x0, x0, #1
+	msr	CPUACTLR_EL1, x0	/* invalidate BTB and I$ together */
+	dsb	sy
+	isb
+	ic	iallu			/* invalidate */
+	dsb	sy
+	isb
+
+	bic	x0, x0, #1
+	msr	CPUACTLR_EL1, x0	/* restore original CPUACTLR_EL1 */
+	dsb	sy
+	isb
+
+	.rept 7
+	nop                            /* wait */
+	.endr
+
+	/*
+	 * Extract OSLK bit and check if it is '1'. This bit remains '0'
+	 * for A53. If '1', turn off regional clock gating and request
+	 * warm reset.
+	 */
+	mrs	x0, oslsr_el1
+	and	x0, x0, #2		/* extract oslk bit */
+	mrs	x1, mpidr_el1
+	bics	xzr, x0, x1, lsr #7	/* 0 if slow cluster */
+	b.eq	__restore_oslock
+	mov	x0, xzr
+	msr	oslar_el1, x0		/* os lock stays 0 across warm reset */
+	mov	x3, #3
+	movz	x4, #0x8000, lsl #48
+	msr	CPUACTLR_EL1, x4	/* turn off RCG */
+	isb
+	msr	rmr_el3, x3		/* request warm reset */
+	isb
+	dsb	sy
+	wfi
+
+	/*
+	 * These nops are here so that speculative execution won't harm us
+	 * before we are done warm reset.
+	 */
+	.rept 65
+	nop
+	.endr
+
+__restore_oslock:
+	mov	x0, #1
+	msr	oslar_el1, x0
+
+	b	arm64_cpu_startup_resume
+ENDPROC(tegra210_reset_handler)
diff --git a/src/soc/nvidia/tegra210/romstage.c b/src/soc/nvidia/tegra210/romstage.c
new file mode 100644
index 0000000..7c4db86
--- /dev/null
+++ b/src/soc/nvidia/tegra210/romstage.c
@@ -0,0 +1,90 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright 2014 Google Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc.
+ */
+
+#include <arch/exception.h>
+#include <arch/stages.h>
+#include <cbfs.h>
+#include <cbmem.h>
+#include <console/cbmem_console.h>
+#include <console/console.h>
+#include <program_loading.h>
+#include <soc/addressmap.h>
+#include <soc/ccplex.h>
+#include <soc/clock.h>
+#include <soc/sdram.h>
+#include <soc/sdram_configs.h>
+#include <soc/romstage.h>
+#include <soc/nvidia/tegra/apbmisc.h>
+#include <timer.h>
+#include <timestamp.h>
+#include <vendorcode/google/chromeos/chromeos.h>
+
+void __attribute__((weak)) romstage_mainboard_init(void)
+{
+	/* Default empty implementation. */
+}
+
+void romstage(void)
+{
+	console_init();
+	exception_init();
+
+	printk(BIOS_INFO, "T210: romstage here\n");
+
+#if CONFIG_BOOTROM_SDRAM_INIT
+	printk(BIOS_INFO, "T210 romstage: SDRAM init done by BootROM, RAMCODE = %d\n",
+		sdram_get_ram_code());
+#else
+	sdram_init(get_sdram_config());
+	printk(BIOS_INFO, "T210 romstage: sdram_init done\n");
+#endif
+
+	/* Setup carveout for GPU firmware first */
+	gpu_region_init();
+
+	/*
+	 * Trust Zone needs to be initialized after the DRAM initialization
+	 * because carveout registers are programmed during DRAM init.
+	 * cbmem_initialize() is dependent on the Trust Zone region
+	 * initalization because CBMEM lives right below the Trust Zone which
+	 * needs to be properly identified.
+	 */
+	trustzone_region_init();
+
+	/*
+	 * When romstage is running it's always on the reboot path -- never a
+	 * resume path where cbmem recovery is required. Therefore, always
+	 * initialize the cbmem area to be empty.
+	 */
+	cbmem_initialize_empty();
+
+	ccplex_cpu_prepare();
+	printk(BIOS_INFO, "T210 romstage: cpu prepare done\n");
+
+	romstage_mainboard_init();
+
+	run_ramstage();
+}
+
+void platform_prog_run(struct prog *prog)
+{
+	ccplex_cpu_start(prog_entry(prog));
+
+	clock_halt_avp();
+}
diff --git a/src/soc/nvidia/tegra210/romstage_asm.S b/src/soc/nvidia/tegra210/romstage_asm.S
new file mode 100644
index 0000000..350934d
--- /dev/null
+++ b/src/soc/nvidia/tegra210/romstage_asm.S
@@ -0,0 +1,27 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright 2014 Google Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc.
+ */
+
+#include <arch/asm.h>
+#include "stack.S"
+
+        .section ".text", "ax", %progbits
+
+ENTRY(main)
+	stack_init stack_top=_estack stack_bottom=_stack seed=0 func=romstage
+ENDPROC(main)
diff --git a/src/soc/nvidia/tegra210/sdram.c b/src/soc/nvidia/tegra210/sdram.c
new file mode 100644
index 0000000..786caa4
--- /dev/null
+++ b/src/soc/nvidia/tegra210/sdram.c
@@ -0,0 +1,1082 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright 2014 Google Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <arch/io.h>
+#include <console/console.h>
+#include <delay.h>
+#include <soc/addressmap.h>
+#include <soc/clock.h>
+#include <soc/emc.h>
+#include <soc/mc.h>
+#include <soc/pmc.h>
+#include <soc/sdram.h>
+#include <stdlib.h>
+#include <soc/nvidia/tegra/apbmisc.h>
+
+static void sdram_patch(uintptr_t addr, uint32_t value)
+{
+	if (addr)
+		write32((uint32_t *)addr, value);
+}
+
+static void writebits(uint32_t value, uint32_t *addr, uint32_t mask)
+{
+	clrsetbits_le32(addr, mask, (value & mask));
+}
+
+static void sdram_trigger_emc_timing_update(struct tegra_emc_regs *regs)
+{
+	write32(&regs->timing_control, EMC_TIMING_CONTROL_TIMING_UPDATE);
+}
+
+/* PMC must be configured before clock-enable and de-reset of MC/EMC. */
+static void sdram_configure_pmc(const struct sdram_params *param,
+				struct tegra_pmc_regs *regs)
+{
+	/* VDDP Select */
+	write32(&regs->vddp_sel, param->PmcVddpSel);
+	udelay(param->PmcVddpSelWait);
+
+	/* Set DDR pad voltage */
+	writebits(param->PmcDdrPwr, &regs->ddr_pwr, PMC_DDR_PWR_VAL_MASK);
+
+	/* Turn on MEM IO Power */
+	writebits(param->PmcNoIoPower, &regs->no_iopower,
+		  (PMC_NO_IOPOWER_MEM_MASK | PMC_NO_IOPOWER_MEM_COMP_MASK));
+
+	write32(&regs->reg_short, param->PmcRegShort);
+	write32(&regs->ddr_cntrl, param->PmcDdrCntrl);
+}
+
+static void sdram_set_ddr_control(const struct sdram_params *param,
+				  struct tegra_pmc_regs *regs)
+{
+	u32 ddrcntrl = read32(&regs->ddr_cntrl);
+
+	/* Deassert HOLD_CKE_LOW */
+	ddrcntrl &= ~PMC_CMD_HOLD_LOW_BR00_11_MASK;
+	write32(&regs->ddr_cntrl, ddrcntrl);
+	udelay(param->PmcDdrCntrlWait);
+}
+
+static void sdram_start_clocks(const struct sdram_params *param,
+			       struct tegra_emc_regs *regs)
+{
+	struct clk_rst_ctlr *clk_rst = (void *)TEGRA_CLK_RST_BASE;
+
+	u32 is_same_freq = (param->McEmemArbMisc0 &
+			    MC_EMEM_ARB_MISC0_MC_EMC_SAME_FREQ_MASK) ? 1 : 0;
+	u32 clk_source_emc = param->EmcClockSource;
+
+	/* Enable the clocks for EMC and MC */
+	setbits_le32(&clk_rst->clk_enb_h_set, (1 << 25));	// ENB_EMC
+	setbits_le32(&clk_rst->clk_enb_h_set, (1 << 0));	// ENB_MC
+
+	if ((clk_source_emc >> EMC_2X_CLK_SRC_SHIFT) != PLLM_UD)
+		setbits_le32(&clk_rst->clk_enb_x_set, CLK_ENB_EMC_DLL);
+
+	/* Remove the EMC and MC controllers from reset */
+	clrbits_le32(&clk_rst->rst_dev_h, (1 << 25));		// SWR_EMC
+	clrbits_le32(&clk_rst->rst_dev_h, (1 << 0));		// SWR_MC
+
+	clk_source_emc |= (is_same_freq << 16);
+
+	write32(&clk_rst->clk_src_emc, clk_source_emc);
+	write32(&clk_rst->clk_src_emc_dll, param->EmcClockSourceDll);
+
+	clock_sdram(param->PllMInputDivider, param->PllMFeedbackDivider,
+		    param->PllMPostDivider, param->PllMSetupControl,
+		    param->PllMKVCO, param->PllMKCP, param->PllMStableTime,
+		    param->EmcClockSource, is_same_freq);
+
+	if (param->ClkRstControllerPllmMisc2OverrideEnable)
+		write32(&clk_rst->pllm_misc2,
+			param->ClkRstControllerPllmMisc2Override);
+
+	/* Wait for enough time for clk switch to take place */
+	udelay(5);
+
+	write32(&clk_rst->clk_enb_w_clr, param->ClearClk2Mc1);
+}
+
+static void sdram_set_swizzle(const struct sdram_params *param,
+			      struct tegra_emc_regs *regs)
+{
+	write32(&regs->swizzle_rank0_byte0, param->EmcSwizzleRank0Byte0);
+	write32(&regs->swizzle_rank0_byte1, param->EmcSwizzleRank0Byte1);
+	write32(&regs->swizzle_rank0_byte2, param->EmcSwizzleRank0Byte2);
+	write32(&regs->swizzle_rank0_byte3, param->EmcSwizzleRank0Byte3);
+
+	write32(&regs->swizzle_rank1_byte0, param->EmcSwizzleRank1Byte0);
+	write32(&regs->swizzle_rank1_byte1, param->EmcSwizzleRank1Byte1);
+	write32(&regs->swizzle_rank1_byte2, param->EmcSwizzleRank1Byte2);
+	write32(&regs->swizzle_rank1_byte3, param->EmcSwizzleRank1Byte3);
+}
+
+static void sdram_set_pad_controls(const struct sdram_params *param,
+				   struct tegra_emc_regs *regs)
+{
+	/* Program the pad controls */
+	write32(&regs->xm2comppadctrl, param->EmcXm2CompPadCtrl);
+	write32(&regs->xm2comppadctrl2, param->EmcXm2CompPadCtrl2);
+	write32(&regs->xm2comppadctrl3, param->EmcXm2CompPadCtrl3);
+}
+
+static void sdram_set_pad_macros(const struct sdram_params *param,
+				 struct tegra_emc_regs *regs)
+{
+	u32 rfu_reset, rfu_mask1, rfu_mask2, rfu_step1, rfu_step2;
+	u32 cpm_reset_settings, cpm_mask1, cpm_step1;
+
+	write32(&regs->pmacro_vttgen_ctrl0, param->EmcPmacroVttgenCtrl0);
+	write32(&regs->pmacro_vttgen_ctrl1, param->EmcPmacroVttgenCtrl1);
+	write32(&regs->pmacro_vttgen_ctrl2, param->EmcPmacroVttgenCtrl2);
+	/* Trigger timing update so above writes take place */
+	sdram_trigger_emc_timing_update(regs);
+	/* Add a wait to ensure the regulators settle */
+	udelay(10);
+
+	write32(&regs->dbg,
+		param->EmcDbg | (param->EmcDbgWriteMux & WRITE_MUX_ACTIVE));
+
+	rfu_reset = EMC_PMACRO_BRICK_CTRL_RFU1_RESET_VAL;
+	rfu_mask1 = 0x01120112;
+	rfu_mask2 = 0x01BF01BF;
+
+	rfu_step1 = rfu_reset & (param->EmcPmacroBrickCtrlRfu1 | ~rfu_mask1);
+	rfu_step2 = rfu_reset & (param->EmcPmacroBrickCtrlRfu1 | ~rfu_mask2);
+
+	/* common pad macro (cpm) */
+	cpm_reset_settings = 0x0000000F;
+	cpm_mask1 = 0x00000001;
+	cpm_step1 = cpm_reset_settings;
+	cpm_step1 &= (param->EmcPmacroCommonPadTxCtrl | ~cpm_mask1);
+
+	/* Patch 2 using BCT spare variables */
+	sdram_patch(param->EmcBctSpare2, param->EmcBctSpare3);
+
+	/*
+	 * Program CMD mapping. Required before brick mapping, else
+	 * we can't gaurantee CK will be differential at all times.
+	 */
+	write32(&regs->fbio_cfg7, param->EmcFbioCfg7);
+
+	write32(&regs->cmd_mapping_cmd0_0, param->EmcCmdMappingCmd0_0);
+	write32(&regs->cmd_mapping_cmd0_1, param->EmcCmdMappingCmd0_1);
+	write32(&regs->cmd_mapping_cmd0_2, param->EmcCmdMappingCmd0_2);
+	write32(&regs->cmd_mapping_cmd1_0, param->EmcCmdMappingCmd1_0);
+	write32(&regs->cmd_mapping_cmd1_1, param->EmcCmdMappingCmd1_1);
+	write32(&regs->cmd_mapping_cmd1_2, param->EmcCmdMappingCmd1_2);
+	write32(&regs->cmd_mapping_cmd2_0, param->EmcCmdMappingCmd2_0);
+	write32(&regs->cmd_mapping_cmd2_1, param->EmcCmdMappingCmd2_1);
+	write32(&regs->cmd_mapping_cmd2_2, param->EmcCmdMappingCmd2_2);
+	write32(&regs->cmd_mapping_cmd3_0, param->EmcCmdMappingCmd3_0);
+	write32(&regs->cmd_mapping_cmd3_1, param->EmcCmdMappingCmd3_1);
+	write32(&regs->cmd_mapping_cmd3_2, param->EmcCmdMappingCmd3_2);
+	write32(&regs->cmd_mapping_byte, param->EmcCmdMappingByte);
+
+	/* Program brick mapping. */
+	write32(&regs->pmacro_brick_mapping0, param->EmcPmacroBrickMapping0);
+	write32(&regs->pmacro_brick_mapping1, param->EmcPmacroBrickMapping1);
+	write32(&regs->pmacro_brick_mapping2, param->EmcPmacroBrickMapping2);
+
+	write32(&regs->pmacro_brick_ctrl_rfu1, rfu_step1);
+
+	/* This is required to do any reads from the pad macros */
+	write32(&regs->config_sample_delay, param->EmcConfigSampleDelay);
+
+	write32(&regs->fbio_cfg8, param->EmcFbioCfg8);
+
+	sdram_set_swizzle(param, regs);
+
+	/* Patch 4 using BCT spare variables */
+	sdram_patch(param->EmcBctSpare6, param->EmcBctSpare7);
+
+	sdram_set_pad_controls(param, regs);
+
+	/* Program Autocal controls with shadowed register fields */
+	write32(&regs->auto_cal_config2, param->EmcAutoCalConfig2);
+	write32(&regs->auto_cal_config3, param->EmcAutoCalConfig3);
+	write32(&regs->auto_cal_config4, param->EmcAutoCalConfig4);
+	write32(&regs->auto_cal_config5, param->EmcAutoCalConfig5);
+	write32(&regs->auto_cal_config6, param->EmcAutoCalConfig6);
+	write32(&regs->auto_cal_config7, param->EmcAutoCalConfig7);
+	write32(&regs->auto_cal_config8, param->EmcAutoCalConfig8);
+
+	write32(&regs->pmacro_rx_term, param->EmcPmacroRxTerm);
+	write32(&regs->pmacro_dq_tx_drv, param->EmcPmacroDqTxDrv);
+	write32(&regs->pmacro_ca_tx_drv, param->EmcPmacroCaTxDrv);
+	write32(&regs->pmacro_cmd_tx_drv, param->EmcPmacroCmdTxDrv);
+	write32(&regs->pmacro_autocal_cfg_common,
+		param->EmcPmacroAutocalCfgCommon);
+	write32(&regs->auto_cal_channel, param->EmcAutoCalChannel);
+	write32(&regs->pmacro_zctrl, param->EmcPmacroZctrl);
+
+	write32(&regs->dll_cfg0, param->EmcDllCfg0);
+	write32(&regs->dll_cfg1, param->EmcDllCfg1);
+	write32(&regs->cfg_dig_dll_1, param->EmcCfgDigDll_1);
+
+	write32(&regs->data_brlshft_0, param->EmcDataBrlshft0);
+	write32(&regs->data_brlshft_1, param->EmcDataBrlshft1);
+	write32(&regs->dqs_brlshft_0, param->EmcDqsBrlshft0);
+	write32(&regs->dqs_brlshft_1, param->EmcDqsBrlshft1);
+	write32(&regs->cmd_brlshft_0, param->EmcCmdBrlshft0);
+	write32(&regs->cmd_brlshft_1, param->EmcCmdBrlshft1);
+	write32(&regs->cmd_brlshft_2, param->EmcCmdBrlshft2);
+	write32(&regs->cmd_brlshft_3, param->EmcCmdBrlshft3);
+	write32(&regs->quse_brlshft_0, param->EmcQuseBrlshft0);
+	write32(&regs->quse_brlshft_1, param->EmcQuseBrlshft1);
+	write32(&regs->quse_brlshft_2, param->EmcQuseBrlshft2);
+	write32(&regs->quse_brlshft_3, param->EmcQuseBrlshft3);
+
+	write32(&regs->pmacro_brick_ctrl_rfu1, rfu_step2);
+	write32(&regs->pmacro_pad_cfg_ctrl, param->EmcPmacroPadCfgCtrl);
+
+	write32(&regs->pmacro_pad_cfg_ctrl, param->EmcPmacroPadCfgCtrl);
+	write32(&regs->pmacro_cmd_brick_ctrl_fdpd,
+		param->EmcPmacroCmdBrickCtrlFdpd);
+	write32(&regs->pmacro_brick_ctrl_rfu2,
+		param->EmcPmacroBrickCtrlRfu2 & 0xFF7FFF7F);
+	write32(&regs->pmacro_data_brick_ctrl_fdpd,
+		param->EmcPmacroDataBrickCtrlFdpd);
+	write32(&regs->pmacro_bg_bias_ctrl_0, param->EmcPmacroBgBiasCtrl0);
+	write32(&regs->pmacro_data_pad_rx_ctrl, param->EmcPmacroDataPadRxCtrl);
+	write32(&regs->pmacro_cmd_pad_rx_ctrl, param->EmcPmacroCmdPadRxCtrl);
+	write32(&regs->pmacro_data_pad_tx_ctrl, param->EmcPmacroDataPadTxCtrl);
+	write32(&regs->pmacro_data_rx_term_mode,
+		param->EmcPmacroDataRxTermMode);
+	write32(&regs->pmacro_cmd_rx_term_mode, param->EmcPmacroCmdRxTermMode);
+	write32(&regs->pmacro_cmd_pad_tx_ctrl, param->EmcPmacroCmdPadTxCtrl);
+
+	write32(&regs->cfg_3, param->EmcCfg3);
+	write32(&regs->pmacro_tx_pwrd_0, param->EmcPmacroTxPwrd0);
+	write32(&regs->pmacro_tx_pwrd_1, param->EmcPmacroTxPwrd1);
+	write32(&regs->pmacro_tx_pwrd_2, param->EmcPmacroTxPwrd2);
+	write32(&regs->pmacro_tx_pwrd_3, param->EmcPmacroTxPwrd3);
+	write32(&regs->pmacro_tx_pwrd_4, param->EmcPmacroTxPwrd4);
+	write32(&regs->pmacro_tx_pwrd_5, param->EmcPmacroTxPwrd5);
+	write32(&regs->pmacro_tx_sel_clk_src_0, param->EmcPmacroTxSelClkSrc0);
+	write32(&regs->pmacro_tx_sel_clk_src_1, param->EmcPmacroTxSelClkSrc1);
+	write32(&regs->pmacro_tx_sel_clk_src_2, param->EmcPmacroTxSelClkSrc2);
+	write32(&regs->pmacro_tx_sel_clk_src_3, param->EmcPmacroTxSelClkSrc3);
+	write32(&regs->pmacro_tx_sel_clk_src_4, param->EmcPmacroTxSelClkSrc4);
+	write32(&regs->pmacro_tx_sel_clk_src_5, param->EmcPmacroTxSelClkSrc5);
+	write32(&regs->pmacro_ddll_bypass, param->EmcPmacroDdllBypass);
+	write32(&regs->pmacro_ddll_pwrd_0, param->EmcPmacroDdllPwrd0);
+	write32(&regs->pmacro_ddll_pwrd_1, param->EmcPmacroDdllPwrd1);
+	write32(&regs->pmacro_ddll_pwrd_2, param->EmcPmacroDdllPwrd2);
+	write32(&regs->pmacro_cmd_ctrl_0, param->EmcPmacroCmdCtrl0);
+	write32(&regs->pmacro_cmd_ctrl_1, param->EmcPmacroCmdCtrl1);
+	write32(&regs->pmacro_cmd_ctrl_2, param->EmcPmacroCmdCtrl2);
+	write32(&regs->pmacro_ib_vref_dq_0, param->EmcPmacroIbVrefDq_0);
+	write32(&regs->pmacro_ib_vref_dq_1, param->EmcPmacroIbVrefDq_1);
+	write32(&regs->pmacro_ib_vref_dqs_0, param->EmcPmacroIbVrefDqs_0);
+	write32(&regs->pmacro_ib_vref_dqs_1, param->EmcPmacroIbVrefDqs_1);
+	write32(&regs->pmacro_ib_rxrt, param->EmcPmacroIbRxrt);
+	write32(&regs->pmacro_quse_ddll_rank0_0,
+		param->EmcPmacroQuseDdllRank0_0);
+	write32(&regs->pmacro_quse_ddll_rank0_1,
+		param->EmcPmacroQuseDdllRank0_1);
+	write32(&regs->pmacro_quse_ddll_rank0_2,
+		param->EmcPmacroQuseDdllRank0_2);
+	write32(&regs->pmacro_quse_ddll_rank0_3,
+		param->EmcPmacroQuseDdllRank0_3);
+	write32(&regs->pmacro_quse_ddll_rank0_4,
+		param->EmcPmacroQuseDdllRank0_4);
+	write32(&regs->pmacro_quse_ddll_rank0_5,
+		param->EmcPmacroQuseDdllRank0_5);
+	write32(&regs->pmacro_quse_ddll_rank1_0,
+		param->EmcPmacroQuseDdllRank1_0);
+	write32(&regs->pmacro_quse_ddll_rank1_1,
+		param->EmcPmacroQuseDdllRank1_1);
+	write32(&regs->pmacro_quse_ddll_rank1_2,
+		param->EmcPmacroQuseDdllRank1_2);
+	write32(&regs->pmacro_quse_ddll_rank1_3,
+		param->EmcPmacroQuseDdllRank1_3);
+	write32(&regs->pmacro_quse_ddll_rank1_4,
+		param->EmcPmacroQuseDdllRank1_4);
+	write32(&regs->pmacro_quse_ddll_rank1_5,
+		param->EmcPmacroQuseDdllRank1_5);
+	write32(&regs->pmacro_brick_ctrl_rfu1, param->EmcPmacroBrickCtrlRfu1);
+	write32(&regs->pmacro_ob_ddll_long_dq_rank0_0,
+		param->EmcPmacroObDdllLongDqRank0_0);
+	write32(&regs->pmacro_ob_ddll_long_dq_rank0_1,
+		param->EmcPmacroObDdllLongDqRank0_1);
+	write32(&regs->pmacro_ob_ddll_long_dq_rank0_2,
+		param->EmcPmacroObDdllLongDqRank0_2);
+	write32(&regs->pmacro_ob_ddll_long_dq_rank0_3,
+		param->EmcPmacroObDdllLongDqRank0_3);
+	write32(&regs->pmacro_ob_ddll_long_dq_rank0_4,
+		param->EmcPmacroObDdllLongDqRank0_4);
+	write32(&regs->pmacro_ob_ddll_long_dq_rank0_5,
+		param->EmcPmacroObDdllLongDqRank0_5);
+	write32(&regs->pmacro_ob_ddll_long_dq_rank1_0,
+		param->EmcPmacroObDdllLongDqRank1_0);
+	write32(&regs->pmacro_ob_ddll_long_dq_rank1_1,
+		param->EmcPmacroObDdllLongDqRank1_1);
+	write32(&regs->pmacro_ob_ddll_long_dq_rank1_2,
+		param->EmcPmacroObDdllLongDqRank1_2);
+	write32(&regs->pmacro_ob_ddll_long_dq_rank1_3,
+		param->EmcPmacroObDdllLongDqRank1_3);
+	write32(&regs->pmacro_ob_ddll_long_dq_rank1_4,
+		param->EmcPmacroObDdllLongDqRank1_4);
+	write32(&regs->pmacro_ob_ddll_long_dq_rank1_5,
+		param->EmcPmacroObDdllLongDqRank1_5);
+
+	write32(&regs->pmacro_ob_ddll_long_dqs_rank0_0,
+		param->EmcPmacroObDdllLongDqsRank0_0);
+	write32(&regs->pmacro_ob_ddll_long_dqs_rank0_1,
+		param->EmcPmacroObDdllLongDqsRank0_1);
+	write32(&regs->pmacro_ob_ddll_long_dqs_rank0_2,
+		param->EmcPmacroObDdllLongDqsRank0_2);
+	write32(&regs->pmacro_ob_ddll_long_dqs_rank0_3,
+		param->EmcPmacroObDdllLongDqsRank0_3);
+	write32(&regs->pmacro_ob_ddll_long_dqs_rank0_4,
+		param->EmcPmacroObDdllLongDqsRank0_4);
+	write32(&regs->pmacro_ob_ddll_long_dqs_rank0_5,
+		param->EmcPmacroObDdllLongDqsRank0_5);
+	write32(&regs->pmacro_ob_ddll_long_dqs_rank1_0,
+		param->EmcPmacroObDdllLongDqsRank1_0);
+	write32(&regs->pmacro_ob_ddll_long_dqs_rank1_1,
+		param->EmcPmacroObDdllLongDqsRank1_1);
+	write32(&regs->pmacro_ob_ddll_long_dqs_rank1_2,
+		param->EmcPmacroObDdllLongDqsRank1_2);
+	write32(&regs->pmacro_ob_ddll_long_dqs_rank1_3,
+		param->EmcPmacroObDdllLongDqsRank1_3);
+	write32(&regs->pmacro_ob_ddll_long_dqs_rank1_4,
+		param->EmcPmacroObDdllLongDqsRank1_4);
+	write32(&regs->pmacro_ob_ddll_long_dqs_rank1_5,
+		param->EmcPmacroObDdllLongDqsRank1_5);
+	write32(&regs->pmacro_ib_ddll_long_dqs_rank0_0,
+		param->EmcPmacroIbDdllLongDqsRank0_0);
+	write32(&regs->pmacro_ib_ddll_long_dqs_rank0_1,
+		param->EmcPmacroIbDdllLongDqsRank0_1);
+	write32(&regs->pmacro_ib_ddll_long_dqs_rank0_2,
+		param->EmcPmacroIbDdllLongDqsRank0_2);
+	write32(&regs->pmacro_ib_ddll_long_dqs_rank0_3,
+		param->EmcPmacroIbDdllLongDqsRank0_3);
+	write32(&regs->pmacro_ib_ddll_long_dqs_rank1_0,
+		param->EmcPmacroIbDdllLongDqsRank1_0);
+	write32(&regs->pmacro_ib_ddll_long_dqs_rank1_1,
+		param->EmcPmacroIbDdllLongDqsRank1_1);
+	write32(&regs->pmacro_ib_ddll_long_dqs_rank1_2,
+		param->EmcPmacroIbDdllLongDqsRank1_2);
+	write32(&regs->pmacro_ib_ddll_long_dqs_rank1_3,
+		param->EmcPmacroIbDdllLongDqsRank1_3);
+	write32(&regs->pmacro_ddll_long_cmd_0, param->EmcPmacroDdllLongCmd_0);
+	write32(&regs->pmacro_ddll_long_cmd_1, param->EmcPmacroDdllLongCmd_1);
+	write32(&regs->pmacro_ddll_long_cmd_2, param->EmcPmacroDdllLongCmd_2);
+	write32(&regs->pmacro_ddll_long_cmd_3, param->EmcPmacroDdllLongCmd_3);
+	write32(&regs->pmacro_ddll_long_cmd_4, param->EmcPmacroDdllLongCmd_4);
+	write32(&regs->pmacro_ddll_short_cmd_0, param->EmcPmacroDdllShortCmd_0);
+	write32(&regs->pmacro_ddll_short_cmd_1, param->EmcPmacroDdllShortCmd_1);
+	write32(&regs->pmacro_ddll_short_cmd_2, param->EmcPmacroDdllShortCmd_2);
+	write32(&regs->pmacro_common_pad_tx_ctrl, cpm_step1);
+}
+
+static void sdram_setup_wpr_carveouts(const struct sdram_params *param,
+				      struct tegra_mc_regs *regs)
+{
+	/* Program the 5 WPR carveouts with initial BCT settings. */
+	write32(&regs->security_carveout1_bom,
+		param->McGeneralizedCarveout1Bom);
+	write32(&regs->security_carveout1_bom_hi,
+		param->McGeneralizedCarveout1BomHi);
+	write32(&regs->security_carveout1_size_128kb,
+		param->McGeneralizedCarveout1Size128kb);
+	write32(&regs->security_carveout1_ca0,
+		param->McGeneralizedCarveout1Access0);
+	write32(&regs->security_carveout1_ca1,
+		param->McGeneralizedCarveout1Access1);
+	write32(&regs->security_carveout1_ca2,
+		param->McGeneralizedCarveout1Access2);
+	write32(&regs->security_carveout1_ca3,
+		param->McGeneralizedCarveout1Access3);
+	write32(&regs->security_carveout1_ca4,
+		param->McGeneralizedCarveout1Access4);
+	write32(&regs->security_carveout1_cfia0,
+		param->McGeneralizedCarveout1ForceInternalAccess0);
+	write32(&regs->security_carveout1_cfia1,
+		param->McGeneralizedCarveout1ForceInternalAccess1);
+	write32(&regs->security_carveout1_cfia2,
+		param->McGeneralizedCarveout1ForceInternalAccess2);
+	write32(&regs->security_carveout1_cfia3,
+		param->McGeneralizedCarveout1ForceInternalAccess3);
+	write32(&regs->security_carveout1_cfia4,
+		param->McGeneralizedCarveout1ForceInternalAccess4);
+	write32(&regs->security_carveout1_cfg0,
+		param->McGeneralizedCarveout1Cfg0);
+
+	write32(&regs->security_carveout2_bom,
+		param->McGeneralizedCarveout2Bom);
+	write32(&regs->security_carveout2_bom_hi,
+		param->McGeneralizedCarveout2BomHi);
+	write32(&regs->security_carveout2_size_128kb,
+		param->McGeneralizedCarveout2Size128kb);
+	write32(&regs->security_carveout2_ca0,
+		param->McGeneralizedCarveout2Access0);
+	write32(&regs->security_carveout2_ca1,
+		param->McGeneralizedCarveout2Access1);
+	write32(&regs->security_carveout2_ca2,
+		param->McGeneralizedCarveout2Access2);
+	write32(&regs->security_carveout2_ca3,
+		param->McGeneralizedCarveout2Access3);
+	write32(&regs->security_carveout2_ca4,
+		param->McGeneralizedCarveout2Access4);
+	write32(&regs->security_carveout2_cfia0,
+		param->McGeneralizedCarveout2ForceInternalAccess0);
+	write32(&regs->security_carveout2_cfia1,
+		param->McGeneralizedCarveout2ForceInternalAccess1);
+	write32(&regs->security_carveout2_cfia2,
+		param->McGeneralizedCarveout2ForceInternalAccess2);
+	write32(&regs->security_carveout2_cfia3,
+		param->McGeneralizedCarveout2ForceInternalAccess3);
+	write32(&regs->security_carveout2_cfia4,
+		param->McGeneralizedCarveout2ForceInternalAccess4);
+	write32(&regs->security_carveout2_cfg0,
+		param->McGeneralizedCarveout2Cfg0);
+
+	write32(&regs->security_carveout3_bom,
+		param->McGeneralizedCarveout3Bom);
+	write32(&regs->security_carveout3_bom_hi,
+		param->McGeneralizedCarveout3BomHi);
+	write32(&regs->security_carveout3_size_128kb,
+		param->McGeneralizedCarveout3Size128kb);
+	write32(&regs->security_carveout3_ca0,
+		param->McGeneralizedCarveout3Access0);
+	write32(&regs->security_carveout3_ca1,
+		param->McGeneralizedCarveout3Access1);
+	write32(&regs->security_carveout3_ca2,
+		param->McGeneralizedCarveout3Access2);
+	write32(&regs->security_carveout3_ca3,
+		param->McGeneralizedCarveout3Access3);
+	write32(&regs->security_carveout3_ca4,
+		param->McGeneralizedCarveout3Access4);
+	write32(&regs->security_carveout3_cfia0,
+		param->McGeneralizedCarveout3ForceInternalAccess0);
+	write32(&regs->security_carveout3_cfia1,
+		param->McGeneralizedCarveout3ForceInternalAccess1);
+	write32(&regs->security_carveout3_cfia2,
+		param->McGeneralizedCarveout3ForceInternalAccess2);
+	write32(&regs->security_carveout3_cfia3,
+		param->McGeneralizedCarveout3ForceInternalAccess3);
+	write32(&regs->security_carveout3_cfia4,
+		param->McGeneralizedCarveout3ForceInternalAccess4);
+	write32(&regs->security_carveout3_cfg0,
+		param->McGeneralizedCarveout3Cfg0);
+
+	write32(&regs->security_carveout4_bom,
+		param->McGeneralizedCarveout4Bom);
+	write32(&regs->security_carveout4_bom_hi,
+		param->McGeneralizedCarveout4BomHi);
+	write32(&regs->security_carveout4_size_128kb,
+		param->McGeneralizedCarveout4Size128kb);
+	write32(&regs->security_carveout4_ca0,
+		param->McGeneralizedCarveout4Access0);
+	write32(&regs->security_carveout4_ca1,
+		param->McGeneralizedCarveout4Access1);
+	write32(&regs->security_carveout4_ca2,
+		param->McGeneralizedCarveout4Access2);
+	write32(&regs->security_carveout4_ca3,
+		param->McGeneralizedCarveout4Access3);
+	write32(&regs->security_carveout4_ca4,
+		param->McGeneralizedCarveout4Access4);
+	write32(&regs->security_carveout4_cfia0,
+		param->McGeneralizedCarveout4ForceInternalAccess0);
+	write32(&regs->security_carveout4_cfia1,
+		param->McGeneralizedCarveout4ForceInternalAccess1);
+	write32(&regs->security_carveout4_cfia2,
+		param->McGeneralizedCarveout4ForceInternalAccess2);
+	write32(&regs->security_carveout4_cfia3,
+		param->McGeneralizedCarveout4ForceInternalAccess3);
+	write32(&regs->security_carveout4_cfia4,
+		param->McGeneralizedCarveout4ForceInternalAccess4);
+	write32(&regs->security_carveout4_cfg0,
+		param->McGeneralizedCarveout4Cfg0);
+
+	write32(&regs->security_carveout5_bom,
+		param->McGeneralizedCarveout5Bom);
+	write32(&regs->security_carveout5_bom_hi,
+		param->McGeneralizedCarveout5BomHi);
+	write32(&regs->security_carveout5_size_128kb,
+		param->McGeneralizedCarveout5Size128kb);
+	write32(&regs->security_carveout5_ca0,
+		param->McGeneralizedCarveout5Access0);
+	write32(&regs->security_carveout5_ca1,
+		param->McGeneralizedCarveout5Access1);
+	write32(&regs->security_carveout5_ca2,
+		param->McGeneralizedCarveout5Access2);
+	write32(&regs->security_carveout5_ca3,
+		param->McGeneralizedCarveout5Access3);
+	write32(&regs->security_carveout5_ca4,
+		param->McGeneralizedCarveout5Access4);
+	write32(&regs->security_carveout5_cfia0,
+		param->McGeneralizedCarveout5ForceInternalAccess0);
+	write32(&regs->security_carveout5_cfia1,
+		param->McGeneralizedCarveout5ForceInternalAccess1);
+	write32(&regs->security_carveout5_cfia2,
+		param->McGeneralizedCarveout5ForceInternalAccess2);
+	write32(&regs->security_carveout5_cfia3,
+		param->McGeneralizedCarveout5ForceInternalAccess3);
+	write32(&regs->security_carveout5_cfia4,
+		param->McGeneralizedCarveout5ForceInternalAccess4);
+	write32(&regs->security_carveout5_cfg0,
+		param->McGeneralizedCarveout5Cfg0);
+}
+
+static void sdram_init_mc(const struct sdram_params *param,
+			  struct tegra_mc_regs *regs)
+{
+	/* Initialize MC VPR settings */
+	write32(&regs->video_protect_bom, param->McVideoProtectBom);
+	write32(&regs->video_protect_bom_adr_hi,
+		param->McVideoProtectBomAdrHi);
+	write32(&regs->video_protect_size_mb, param->McVideoProtectSizeMb);
+	write32(&regs->video_protect_vpr_override,
+		param->McVideoProtectVprOverride);
+	write32(&regs->video_protect_vpr_override1,
+		param->McVideoProtectVprOverride1);
+	write32(&regs->video_protect_gpu_override_0,
+		param->McVideoProtectGpuOverride0);
+	write32(&regs->video_protect_gpu_override_1,
+		param->McVideoProtectGpuOverride1);
+
+	/* Program SDRAM geometry paarameters */
+	write32(&regs->emem_adr_cfg, param->McEmemAdrCfg);
+	write32(&regs->emem_adr_cfg_dev0, param->McEmemAdrCfgDev0);
+	write32(&regs->emem_adr_cfg_dev1, param->McEmemAdrCfgDev1);
+	write32(&regs->emem_adr_cfg_channel_mask,
+		param->McEmemAdrCfgChannelMask);
+
+	/* Program bank swizzling */
+	write32(&regs->emem_adr_cfg_bank_mask_0, param->McEmemAdrCfgBankMask0);
+	write32(&regs->emem_adr_cfg_bank_mask_1, param->McEmemAdrCfgBankMask1);
+	write32(&regs->emem_adr_cfg_bank_mask_2, param->McEmemAdrCfgBankMask2);
+
+	/* Program external memory aperature (base and size) */
+	write32(&regs->emem_cfg, param->McEmemCfg);
+
+	/* Program SEC carveout (base and size) */
+	write32(&regs->sec_carveout_bom, param->McSecCarveoutBom);
+	write32(&regs->sec_carveout_adr_hi, param->McSecCarveoutAdrHi);
+	write32(&regs->sec_carveout_size_mb, param->McSecCarveoutSizeMb);
+
+	/* Program MTS carveout (base and size) */
+	write32(&regs->mts_carveout_bom, param->McMtsCarveoutBom);
+	write32(&regs->mts_carveout_adr_hi, param->McMtsCarveoutAdrHi);
+	write32(&regs->mts_carveout_size_mb, param->McMtsCarveoutSizeMb);
+
+	/* Initialize the WPR carveouts */
+	sdram_setup_wpr_carveouts(param, regs);
+
+	/* Program the memory arbiter */
+	write32(&regs->emem_arb_cfg, param->McEmemArbCfg);
+	write32(&regs->emem_arb_outstanding_req,
+		param->McEmemArbOutstandingReq);
+	write32(&regs->emem_arb_refpb_hp_ctrl, param->McEmemArbRefpbHpCtrl);
+	write32(&regs->emem_arb_refpb_bank_ctrl, param->McEmemArbRefpbBankCtrl);
+	write32(&regs->emem_arb_timing_rcd, param->McEmemArbTimingRcd);
+	write32(&regs->emem_arb_timing_rp, param->McEmemArbTimingRp);
+	write32(&regs->emem_arb_timing_rc, param->McEmemArbTimingRc);
+	write32(&regs->emem_arb_timing_ras, param->McEmemArbTimingRas);
+	write32(&regs->emem_arb_timing_faw, param->McEmemArbTimingFaw);
+	write32(&regs->emem_arb_timing_rrd, param->McEmemArbTimingRrd);
+	write32(&regs->emem_arb_timing_rap2pre, param->McEmemArbTimingRap2Pre);
+	write32(&regs->emem_arb_timing_wap2pre, param->McEmemArbTimingWap2Pre);
+	write32(&regs->emem_arb_timing_r2r, param->McEmemArbTimingR2R);
+	write32(&regs->emem_arb_timing_w2w, param->McEmemArbTimingW2W);
+	write32(&regs->emem_arb_timing_ccdmw, param->McEmemArbTimingCcdmw);
+	write32(&regs->emem_arb_timing_r2w, param->McEmemArbTimingR2W);
+	write32(&regs->emem_arb_timing_w2r, param->McEmemArbTimingW2R);
+	write32(&regs->emem_arb_timing_rfcpb, param->McEmemArbTimingRFCPB);
+	write32(&regs->emem_arb_da_turns, param->McEmemArbDaTurns);
+	write32(&regs->emem_arb_da_covers, param->McEmemArbDaCovers);
+	write32(&regs->emem_arb_misc0, param->McEmemArbMisc0);
+	write32(&regs->emem_arb_misc1, param->McEmemArbMisc1);
+	write32(&regs->emem_arb_misc2, param->McEmemArbMisc2);
+	write32(&regs->emem_arb_ring1_throttle, param->McEmemArbRing1Throttle);
+	write32(&regs->emem_arb_override, param->McEmemArbOverride);
+	write32(&regs->emem_arb_override_1, param->McEmemArbOverride1);
+	write32(&regs->emem_arb_rsv, param->McEmemArbRsv);
+	write32(&regs->da_config0, param->McDaCfg0);
+
+	/* Trigger MC timing update */
+	write32(&regs->timing_control, EMC_TIMING_CONTROL_TIMING_UPDATE);
+
+	/* Program second-level clock enable overrides */
+	write32(&regs->clken_override, param->McClkenOverride);
+
+	/* Program statistics gathering */
+	write32(&regs->stat_control, param->McStatControl);
+}
+
+static void sdram_init_emc(const struct sdram_params *param,
+			   struct tegra_emc_regs *regs)
+{
+	/* Program SDRAM geometry parameters */
+	write32(&regs->adr_cfg, param->EmcAdrCfg);
+
+	/* Program second-level clock enable overrides */
+	write32(&regs->clken_override, param->EmcClkenOverride);
+
+	/* Program EMC pad auto calibration */
+	write32(&regs->pmacro_autocal_cfg0, param->EmcPmacroAutocalCfg0);
+	write32(&regs->pmacro_autocal_cfg1, param->EmcPmacroAutocalCfg1);
+	write32(&regs->pmacro_autocal_cfg2, param->EmcPmacroAutocalCfg2);
+
+	write32(&regs->auto_cal_vref_sel0, param->EmcAutoCalVrefSel0);
+	write32(&regs->auto_cal_vref_sel1, param->EmcAutoCalVrefSel1);
+
+	write32(&regs->auto_cal_interval, param->EmcAutoCalInterval);
+	write32(&regs->auto_cal_config, param->EmcAutoCalConfig);
+	udelay(param->EmcAutoCalWait);
+}
+
+static void sdram_set_emc_timing(const struct sdram_params *param,
+				 struct tegra_emc_regs *regs)
+{
+	/* Program EMC timing configuration */
+	write32(&regs->cfg_2, param->EmcCfg2);
+	write32(&regs->cfg_pipe, param->EmcCfgPipe);
+	write32(&regs->cfg_pipe1, param->EmcCfgPipe1);
+	write32(&regs->cfg_pipe2, param->EmcCfgPipe2);
+	write32(&regs->cmdq, param->EmcCmdQ);
+	write32(&regs->mc2emcq, param->EmcMc2EmcQ);
+	write32(&regs->mrs_wait_cnt, param->EmcMrsWaitCnt);
+	write32(&regs->mrs_wait_cnt2, param->EmcMrsWaitCnt2);
+	write32(&regs->fbio_cfg5, param->EmcFbioCfg5);
+	write32(&regs->rc, param->EmcRc);
+	write32(&regs->rfc, param->EmcRfc);
+	write32(&regs->rfcpb, param->EmcRfcPb);
+	write32(&regs->refctrl2, param->EmcRefctrl2);
+	write32(&regs->rfc_slr, param->EmcRfcSlr);
+	write32(&regs->ras, param->EmcRas);
+	write32(&regs->rp, param->EmcRp);
+	write32(&regs->tppd, param->EmcTppd);
+	write32(&regs->r2r, param->EmcR2r);
+	write32(&regs->w2w, param->EmcW2w);
+	write32(&regs->r2w, param->EmcR2w);
+	write32(&regs->w2r, param->EmcW2r);
+	write32(&regs->r2p, param->EmcR2p);
+	write32(&regs->w2p, param->EmcW2p);
+	write32(&regs->ccdmw, param->EmcCcdmw);
+	write32(&regs->rd_rcd, param->EmcRdRcd);
+	write32(&regs->wr_rcd, param->EmcWrRcd);
+	write32(&regs->rrd, param->EmcRrd);
+	write32(&regs->rext, param->EmcRext);
+	write32(&regs->wext, param->EmcWext);
+	write32(&regs->wdv, param->EmcWdv);
+	write32(&regs->wdv_chk, param->EmcWdvChk);
+	write32(&regs->wsv, param->EmcWsv);
+	write32(&regs->wev, param->EmcWev);
+	write32(&regs->wdv_mask, param->EmcWdvMask);
+	write32(&regs->ws_duration, param->EmcWsDuration);
+	write32(&regs->we_duration, param->EmcWeDuration);
+	write32(&regs->quse, param->EmcQUse);
+	write32(&regs->quse_width, param->EmcQuseWidth);
+	write32(&regs->ibdly, param->EmcIbdly);
+	write32(&regs->obdly, param->EmcObdly);
+	write32(&regs->einput, param->EmcEInput);
+	write32(&regs->einput_duration, param->EmcEInputDuration);
+	write32(&regs->puterm_extra, param->EmcPutermExtra);
+	write32(&regs->puterm_width, param->EmcPutermWidth);
+
+	write32(&regs->pmacro_common_pad_tx_ctrl,
+		param->EmcPmacroCommonPadTxCtrl);
+	write32(&regs->dbg, param->EmcDbg);
+	write32(&regs->qrst, param->EmcQRst);
+	write32(&regs->issue_qrst, 1);
+	write32(&regs->issue_qrst, 0);
+	write32(&regs->qsafe, param->EmcQSafe);
+	write32(&regs->rdv, param->EmcRdv);
+	write32(&regs->rdv_mask, param->EmcRdvMask);
+	write32(&regs->rdv_early, param->EmcRdvEarly);
+	write32(&regs->rdv_early_mask, param->EmcRdvEarlyMask);
+	write32(&regs->qpop, param->EmcQpop);
+	write32(&regs->refresh, param->EmcRefresh);
+	write32(&regs->burst_refresh_num, param->EmcBurstRefreshNum);
+	write32(&regs->pre_refresh_req_cnt, param->EmcPreRefreshReqCnt);
+	write32(&regs->pdex2wr, param->EmcPdEx2Wr);
+	write32(&regs->pdex2rd, param->EmcPdEx2Rd);
+	write32(&regs->pchg2pden, param->EmcPChg2Pden);
+	write32(&regs->act2pden, param->EmcAct2Pden);
+	write32(&regs->ar2pden, param->EmcAr2Pden);
+	write32(&regs->rw2pden, param->EmcRw2Pden);
+	write32(&regs->cke2pden, param->EmcCke2Pden);
+	write32(&regs->pdex2cke, param->EmcPdex2Cke);
+	write32(&regs->pdex2mrr, param->EmcPdex2Mrr);
+	write32(&regs->txsr, param->EmcTxsr);
+	write32(&regs->txsrdll, param->EmcTxsrDll);
+	write32(&regs->tcke, param->EmcTcke);
+	write32(&regs->tckesr, param->EmcTckesr);
+	write32(&regs->tpd, param->EmcTpd);
+	write32(&regs->tfaw, param->EmcTfaw);
+	write32(&regs->trpab, param->EmcTrpab);
+	write32(&regs->tclkstable, param->EmcTClkStable);
+	write32(&regs->tclkstop, param->EmcTClkStop);
+	write32(&regs->trefbw, param->EmcTRefBw);
+	write32(&regs->odt_write, param->EmcOdtWrite);
+	write32(&regs->cfg_dig_dll, param->EmcCfgDigDll);
+	write32(&regs->cfg_dig_dll_period, param->EmcCfgDigDllPeriod);
+
+	/* Don't write CFG_ADR_EN (bit 1) here - lock bit written later */
+	write32(&regs->fbio_spare, param->EmcFbioSpare & ~CFG_ADR_EN_LOCKED);
+	write32(&regs->cfg_rsv, param->EmcCfgRsv);
+	write32(&regs->pmc_scratch1, param->EmcPmcScratch1);
+	write32(&regs->pmc_scratch2, param->EmcPmcScratch2);
+	write32(&regs->pmc_scratch3, param->EmcPmcScratch3);
+	write32(&regs->acpd_control, param->EmcAcpdControl);
+	write32(&regs->txdsrvttgen, param->EmcTxdsrvttgen);
+
+	/*
+	 * Set pipe bypass enable bits before sending any DRAM commands.
+	 * Note other bits in EMC_CFG must be set AFTER REFCTRL is configured.
+	 */
+	writebits(param->EmcCfg, &regs->cfg,
+		  (EMC_CFG_EMC2PMACRO_CFG_BYPASS_ADDRPIPE_MASK |
+		   EMC_CFG_EMC2PMACRO_CFG_BYPASS_DATAPIPE1_MASK |
+		   EMC_CFG_EMC2PMACRO_CFG_BYPASS_DATAPIPE2_MASK));
+}
+
+static void sdram_patch_bootrom(const struct sdram_params *param,
+				struct tegra_mc_regs *regs)
+{
+	if (param->BootRomPatchControl & BOOT_ROM_PATCH_CONTROL_ENABLE_MASK) {
+		uintptr_t addr = ((param->BootRomPatchControl &
+				  BOOT_ROM_PATCH_CONTROL_OFFSET_MASK) >>
+				  BOOT_ROM_PATCH_CONTROL_OFFSET_SHIFT);
+		addr = BOOT_ROM_PATCH_CONTROL_BASE_ADDRESS + (addr << 2);
+		write32((uint32_t *)addr, param->BootRomPatchData);
+		write32(&regs->timing_control,
+			EMC_TIMING_CONTROL_TIMING_UPDATE);
+	}
+}
+
+static void sdram_rel_dpd(const struct sdram_params *param,
+			  struct tegra_pmc_regs *regs)
+{
+	u32 dpd3_val, dpd3_val_sel_dpd;
+
+	/* Release SEL_DPD_CMD */
+	dpd3_val = (param->EmcPmcScratch1 & 0x3FFFFFFF) | DPD_OFF;
+	dpd3_val_sel_dpd = dpd3_val & 0xCFFF0000;
+	write32(&regs->io_dpd3_req, dpd3_val_sel_dpd);
+	udelay(param->PmcIoDpd3ReqWait);
+}
+
+/* Program DPD3/DPD4 regs (coldboot path) */
+static void sdram_set_dpd(const struct sdram_params *param,
+			  struct tegra_pmc_regs *regs)
+{
+	u32 dpd3_val, dpd3_val_sel_dpd;
+	u32 dpd4_val, dpd4_val_e_dpd, dpd4_val_e_dpd_vttgen;
+
+	/* Enable sel_dpd on unused pins */
+	dpd3_val = (param->EmcPmcScratch1 & 0x3FFFFFFF) | DPD_ON;
+	dpd3_val_sel_dpd = (dpd3_val ^ 0x0000FFFF) & 0xC000FFFF;
+	write32(&regs->io_dpd3_req, dpd3_val_sel_dpd);
+	udelay(param->PmcIoDpd3ReqWait);
+
+	dpd4_val = dpd3_val;
+	/* Disable e_dpd_vttgen */
+	dpd4_val_e_dpd_vttgen = (dpd4_val ^ 0x3FFF0000) & 0xFFFF0000;
+	write32(&regs->io_dpd4_req, dpd4_val_e_dpd_vttgen);
+	udelay(param->PmcIoDpd4ReqWait);
+
+	/* Disable e_dpd_bg */
+	dpd4_val_e_dpd = (dpd4_val ^ 0x0000FFFF) & 0xC000FFFF;
+	write32(&regs->io_dpd4_req, dpd4_val_e_dpd);
+	udelay(param->PmcIoDpd4ReqWait);
+
+	write32(&regs->weak_bias, 0);
+	/* Add a wait to make sure clock switch takes place */
+	udelay(1);
+}
+
+static void sdram_set_clock_enable_signal(const struct sdram_params *param,
+					  struct tegra_emc_regs *regs)
+{
+	volatile uint32_t dummy = 0;
+	uint32_t val = 0;
+
+	if (param->MemoryType == NvBootMemoryType_LpDdr4) {
+
+		val = (param->EmcPinGpioEn << EMC_PIN_GPIOEN_SHIFT) |
+		      (param->EmcPinGpio << EMC_PIN_GPIO_SHIFT);
+		write32(&regs->pin, val);
+
+		clrbits_le32(&regs->pin,
+			     (EMC_PIN_RESET_MASK | EMC_PIN_DQM_MASK |
+			      EMC_PIN_CKE_MASK));
+		/*
+		 * Assert dummy read of PIN register to ensure above write goes
+		 * through. Wait an additional 200us here as per NVIDIA.
+		 */
+		dummy |= read32(&regs->pin);
+		udelay(param->EmcPinExtraWait + 200);
+
+		/* Deassert reset */
+		setbits_le32(&regs->pin, EMC_PIN_RESET_INACTIVE);
+
+		/*
+		 * Assert dummy read of PIN register to ensure above write goes
+		 * through. Wait an additional 2000us here as per NVIDIA.
+		 */
+		dummy |= read32(&regs->pin);
+		udelay(param->EmcPinExtraWait + 2000);
+	}
+
+	/* Enable clock enable signal */
+	setbits_le32(&regs->pin, EMC_PIN_CKE_NORMAL);
+
+	/* Dummy read of PIN register to ensure final write goes through */
+	dummy |= read32(&regs->pin);
+	udelay(param->EmcPinProgramWait);
+
+	if (!dummy)
+		die("Failed to program EMC pin.");
+
+	if (param->MemoryType != NvBootMemoryType_LpDdr4) {
+
+		/* Send NOP (trigger just needs to be non-zero) */
+		writebits(((1 << EMC_NOP_CMD_SHIFT) |
+			  (param->EmcDevSelect << EMC_NOP_DEV_SELECTN_SHIFT)),
+			  &regs->nop,
+			  EMC_NOP_CMD_MASK | EMC_NOP_DEV_SELECTN_MASK);
+	}
+
+	/* On coldboot w/LPDDR2/3, wait 200 uSec after asserting CKE high */
+	if (param->MemoryType == NvBootMemoryType_LpDdr2)
+		udelay(param->EmcPinExtraWait + 200);
+}
+
+static void sdram_init_lpddr3(const struct sdram_params *param,
+			      struct tegra_emc_regs *regs)
+{
+	/* Precharge all banks. DEV_SELECTN = 0 => Select all devices */
+	write32(&regs->pre,
+		((param->EmcDevSelect << EMC_REF_DEV_SELECTN_SHIFT) | 1));
+
+	/* Send Reset MRW command */
+	write32(&regs->mrw, param->EmcMrwResetCommand);
+	udelay(param->EmcMrwResetNInitWait);
+
+	write32(&regs->mrw, param->EmcZcalInitDev0);
+	udelay(param->EmcZcalInitWait);
+
+	if ((param->EmcDevSelect & 2) == 0) {
+		write32(&regs->mrw, param->EmcZcalInitDev1);
+		udelay(param->EmcZcalInitWait);
+	}
+
+	/* Write mode registers */
+	write32(&regs->mrw2, param->EmcMrw2);
+	write32(&regs->mrw, param->EmcMrw1);
+	write32(&regs->mrw3, param->EmcMrw3);
+	write32(&regs->mrw4, param->EmcMrw4);
+
+	/* Patch 6 using BCT spare variables */
+	sdram_patch(param->EmcBctSpare10, param->EmcBctSpare11);
+
+	if (param->EmcExtraModeRegWriteEnable)
+		write32(&regs->mrw, param->EmcMrwExtra);
+}
+
+static void sdram_init_lpddr4(const struct sdram_params *param,
+			      struct tegra_emc_regs *regs)
+{
+	/* Patch 6 using BCT spare variables */
+	sdram_patch(param->EmcBctSpare10, param->EmcBctSpare11);
+
+	/* Write mode registers */
+	write32(&regs->mrw2, param->EmcMrw2);
+	write32(&regs->mrw, param->EmcMrw1);
+	write32(&regs->mrw3, param->EmcMrw3);
+	write32(&regs->mrw4, param->EmcMrw4);
+	write32(&regs->mrw6, param->EmcMrw6);
+	write32(&regs->mrw14, param->EmcMrw14);
+
+	write32(&regs->mrw8, param->EmcMrw8);
+	write32(&regs->mrw12, param->EmcMrw12);
+	write32(&regs->mrw9, param->EmcMrw9);
+	write32(&regs->mrw13, param->EmcMrw13);
+
+	/* Issue ZQCAL start, device 0 */
+	write32(&regs->zq_cal, param->EmcZcalInitDev0);
+	udelay(param->EmcZcalInitWait);
+	/* Issue ZQCAL latch */
+	write32(&regs->zq_cal, (param->EmcZcalInitDev0 ^ 0x3));
+
+	if ((param->EmcDevSelect & 2) == 0) {
+		/* Same for device 1 */
+		write32(&regs->zq_cal, param->EmcZcalInitDev1);
+		udelay(param->EmcZcalInitWait);
+		write32(&regs->zq_cal, (param->EmcZcalInitDev1 ^ 0x3));
+	}
+}
+
+static void sdram_init_zq_calibration(const struct sdram_params *param,
+				      struct tegra_emc_regs *regs)
+{
+	if (param->MemoryType == NvBootMemoryType_LpDdr2)
+		sdram_init_lpddr3(param, regs);
+	else if (param->MemoryType == NvBootMemoryType_LpDdr4)
+		sdram_init_lpddr4(param, regs);
+}
+
+static void sdram_set_zq_calibration(const struct sdram_params *param,
+				     struct tegra_emc_regs *regs)
+{
+	if (param->EmcAutoCalInterval == 0)
+		write32(&regs->auto_cal_config,
+			param->EmcAutoCalConfig | AUTOCAL_MEASURE_STALL_ENABLE);
+
+	write32(&regs->pmacro_brick_ctrl_rfu2, param->EmcPmacroBrickCtrlRfu2);
+
+	/* ZQ CAL setup (not actually issuing ZQ CAL now) */
+	if (param->MemoryType == NvBootMemoryType_LpDdr4) {
+		write32(&regs->zcal_wait_cnt, param->EmcZcalWaitCnt);
+		write32(&regs->zcal_mrw_cmd, param->EmcZcalMrwCmd);
+	}
+
+	sdram_trigger_emc_timing_update(regs);
+	udelay(param->EmcTimingControlWait);
+}
+
+static void sdram_set_refresh(const struct sdram_params *param,
+			      struct tegra_emc_regs *regs)
+{
+	/* Insert burst refresh */
+	if (param->EmcExtraRefreshNum > 0) {
+		uint32_t refresh_num = (1 << param->EmcExtraRefreshNum) - 1;
+
+		writebits((EMC_REF_CMD_REFRESH | EMC_REF_NORMAL_ENABLED |
+			   (refresh_num << EMC_REF_NUM_SHIFT) |
+			   (param->EmcDevSelect << EMC_REF_DEV_SELECTN_SHIFT)),
+			  &regs->ref, (EMC_REF_CMD_MASK | EMC_REF_NORMAL_MASK |
+				       EMC_REF_NUM_MASK |
+				       EMC_REF_DEV_SELECTN_MASK));
+	}
+
+	/* Enable refresh */
+	write32(&regs->refctrl,
+		(param->EmcDevSelect | EMC_REFCTRL_REF_VALID_ENABLED));
+
+	/*
+	 * NOTE: Programming CFG must happen after REFCTRL to delay
+	 * active power-down to after init (DDR2 constraint).
+	 */
+	write32(&regs->dyn_self_ref_control, param->EmcDynSelfRefControl);
+	write32(&regs->cfg_update, param->EmcCfgUpdate);
+	write32(&regs->cfg, param->EmcCfg);
+	write32(&regs->fdpd_ctrl_dq, param->EmcFdpdCtrlDq);
+	write32(&regs->fdpd_ctrl_cmd, param->EmcFdpdCtrlCmd);
+	write32(&regs->sel_dpd_ctrl, param->EmcSelDpdCtrl);
+
+	/* Write addr swizzle lock bit */
+	write32(&regs->fbio_spare, param->EmcFbioSpare | CFG_ADR_EN_LOCKED);
+
+	/* Re-trigger timing to latch power saving functions */
+	sdram_trigger_emc_timing_update(regs);
+
+	/* Enable EMC pipe clock gating */
+	write32(&regs->cfg_pipe_clk, param->EmcCfgPipeClk);
+	/* Depending on freqency, enable CMD/CLK fdpd */
+	write32(&regs->fdpd_ctrl_cmd_no_ramp, param->EmcFdpdCtrlCmdNoRamp);
+}
+
+#define AHB_ARB_XBAR_CTRL	0x6000C0E0
+
+static void sdram_enable_arbiter(const struct sdram_params *param)
+{
+	/* TODO(hungte) Move values here to standalone header file. */
+	uint32_t *ahb_arbitration_xbar_ctrl = (uint32_t *)(AHB_ARB_XBAR_CTRL);
+
+	setbits_le32(ahb_arbitration_xbar_ctrl,
+		     param->AhbArbitrationXbarCtrlMemInitDone << 16);
+}
+
+static void sdram_lock_carveouts(const struct sdram_params *param,
+				 struct tegra_mc_regs *regs)
+{
+	/* Lock carveouts, and emem_cfg registers */
+	write32(&regs->video_protect_reg_ctrl,
+		param->McVideoProtectWriteAccess);
+	write32(&regs->sec_carveout_reg_ctrl,
+		param->McSecCarveoutProtectWriteAccess);
+	write32(&regs->mts_carveout_reg_ctrl, param->McMtsCarveoutRegCtrl);
+
+	/* Write this last, locks access */
+	write32(&regs->emem_cfg_access_ctrl,
+		MC_EMEM_CFG_ACCESS_CTRL_WRITE_ACCESS_DISABLED);
+}
+
+void sdram_init(const struct sdram_params *param)
+{
+	struct tegra_pmc_regs *pmc = (struct tegra_pmc_regs *)TEGRA_PMC_BASE;
+	struct tegra_mc_regs *mc = (struct tegra_mc_regs *)TEGRA_MC_BASE;
+	struct tegra_emc_regs *emc = (struct tegra_emc_regs *)TEGRA_EMC_BASE;
+
+	printk(BIOS_DEBUG, "Initializing SDRAM of type %d with %dKHz\n",
+		param->MemoryType, clock_get_pll_input_khz() *
+		param->PllMFeedbackDivider / param->PllMInputDivider /
+		(1 + param->PllMPostDivider));
+	if (param->MemoryType != NvBootMemoryType_LpDdr4 &&
+	    param->MemoryType != NvBootMemoryType_LpDdr2)
+		die("Unsupported memory type!\n");
+
+	sdram_configure_pmc(param, pmc);
+	sdram_patch(param->EmcBctSpare0, param->EmcBctSpare1);
+
+	sdram_set_dpd(param, pmc);
+	sdram_start_clocks(param, emc);
+	sdram_set_pad_macros(param, emc);
+	sdram_patch(param->EmcBctSpare4, param->EmcBctSpare5);
+
+	sdram_trigger_emc_timing_update(emc);
+	sdram_init_mc(param, mc);
+	sdram_init_emc(param, emc);
+	sdram_patch(param->EmcBctSpare8, param->EmcBctSpare9);
+
+	sdram_set_emc_timing(param, emc);
+	sdram_patch_bootrom(param, mc);
+	sdram_rel_dpd(param, pmc);
+	sdram_set_zq_calibration(param, emc);
+	sdram_set_ddr_control(param, pmc);
+	sdram_set_clock_enable_signal(param, emc);
+
+	sdram_init_zq_calibration(param, emc);
+
+	/* Set package and DPD pad control */
+	write32(&pmc->ddr_cfg, param->PmcDdrCfg);
+
+	/* Start periodic ZQ calibration (LPDDRx only) */
+	if (param->MemoryType == NvBootMemoryType_LpDdr4 ||
+	    param->MemoryType == NvBootMemoryType_LpDdr2) {
+		write32(&emc->zcal_interval, param->EmcZcalInterval);
+		write32(&emc->zcal_wait_cnt, param->EmcZcalWaitCnt);
+		write32(&emc->zcal_mrw_cmd, param->EmcZcalMrwCmd);
+	}
+	sdram_patch(param->EmcBctSpare12, param->EmcBctSpare13);
+
+	sdram_trigger_emc_timing_update(emc);
+	sdram_set_refresh(param, emc);
+	sdram_enable_arbiter(param);
+	sdram_lock_carveouts(param, mc);
+#if defined(CONFIG_LP0)
+	sdram_lp0_save_params(param);
+#endif
+}
diff --git a/src/soc/nvidia/tegra210/sdram_lp0.c b/src/soc/nvidia/tegra210/sdram_lp0.c
new file mode 100644
index 0000000..c63b823
--- /dev/null
+++ b/src/soc/nvidia/tegra210/sdram_lp0.c
@@ -0,0 +1,628 @@
+/*
+ * Copyright (c) 2013, NVIDIA CORPORATION.  All rights reserved.
+ * Copyright 2014 Google Inc.
+ *
+ * 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 <arch/cache.h>
+#include <console/console.h>
+#include <soc/addressmap.h>
+#include <soc/clk_rst.h>
+#include <soc/pmc.h>
+#include <soc/sdram.h>
+#include <stdlib.h>
+
+/*
+ * This function reads SDRAM parameters (and a few CLK_RST regsiter values) from
+ * the common BCT format and writes them into PMC scratch registers (where the
+ * BootROM expects them on LP0 resume). Since those store the same values in a
+ * different format, we follow a "translation table" taken from Nvidia's U-Boot
+ * implementation to shift bits into the right position.
+ *
+ * Contrary to U-Boot, we transform the same macros directly into hardcoded
+ * assignments (without any pesky function calls or volatile qualifiers) to give
+ * the compiler as much room for optimization as possible. For that reason, we
+ * also intentionally avoid <arch/io.h> read/write macros, under the assumption
+ * that PMC scratch register accesses should not have side effects and can be
+ * arbitrarily reordered. For the few accesses that do have side-effects, the
+ * code must contain explicit memory barriers.
+ */
+void sdram_lp0_save_params(const struct sdram_params *sdram)
+{
+	struct tegra_pmc_regs * pmc = (void *)TEGRA_PMC_BASE;
+	struct clk_rst_ctlr * clk_rst = (void *)TEGRA_CLK_RST_BASE;
+
+#define pack(src, src_bits, dst, dst_bits) { \
+	_Static_assert((1 ? src_bits) >= (0 ? src_bits) && (1 ? dst_bits) >= \
+		(0 ? dst_bits), "byte range flipped (must be MSB:LSB)" ); \
+	_Static_assert((1 ? src_bits) - (0 ? src_bits) == (1 ? dst_bits) - \
+		(0 ? dst_bits), "src and dst byte range lengths differ" ); \
+	u32 mask = 0xffffffff >> (31 - ((1 ? src_bits) - (0 ? src_bits))); \
+	dst &= ~(mask << (0 ? dst_bits)); \
+	dst |= ((src >> (0 ? src_bits)) & mask) << (0 ? dst_bits); \
+}
+
+#define s(param, src_bits, pmcreg, dst_bits) \
+	pack(sdram->param, src_bits, pmc->pmcreg, dst_bits)
+
+#define m(clkreg, src_bits, pmcreg, dst_bits) \
+	pack(clk_rst->clkreg, src_bits, pmc->pmcreg, dst_bits)
+
+#define c(value, pmcreg, dst_bits) \
+	pack(value, (1 ? dst_bits) - (0 ? dst_bits) : 0, pmc->pmcreg, dst_bits)
+
+	s(EmcClockSource, 7:0, scratch6, 15:8);
+	s(EmcClockSource, 31:29, scratch6, 18:16);
+	s(EmcClockSource, 26:26, scratch6, 19:19);
+	s(EmcOdtWrite, 5:0, scratch6, 25:20);
+	s(EmcOdtWrite, 11:8, scratch6, 29:26);
+	s(EmcOdtWrite, 30:30, scratch6, 30:30);
+	s(EmcOdtWrite, 31:31, scratch6, 31:31);
+	s(EmcXm2DqPadCtrl2, 18:16, scratch7, 22:20);
+	s(EmcXm2DqPadCtrl2, 22:20, scratch7, 25:23);
+	s(EmcXm2DqPadCtrl2, 26:24, scratch7, 28:26);
+	s(EmcXm2DqPadCtrl2, 30:28, scratch7, 31:29);
+	s(EmcXm2DqPadCtrl3, 18:16, scratch8, 22:20);
+	s(EmcXm2DqPadCtrl3, 22:20, scratch8, 25:23);
+	s(EmcXm2DqPadCtrl3, 26:24, scratch8, 28:26);
+	s(EmcXm2DqPadCtrl3, 30:28, scratch8, 31:29);
+	s(EmcTxsrDll, 11:0, scratch9, 31:20);
+	c(0, scratch10, 31:0);
+	s(EmcDsrVttgenDrv, 5:0, scratch10, 25:20);
+	s(EmcDsrVttgenDrv, 18:16, scratch10, 28:26);
+	s(EmcDsrVttgenDrv, 26:24, scratch10, 31:29);
+	s(EmcFbioSpare, 31:24, scratch11, 7:0);
+	s(EmcFbioSpare, 23:16, scratch11, 15:8);
+	s(EmcFbioSpare, 15:8, scratch11, 23:16);
+	s(EmcFbioSpare, 7:0, scratch11, 31:24);
+	s(EmcCfgRsv, 31:0, scratch12, 31:0);
+	s(EmcCdbCntl2, 31:0, scratch13, 31:0);
+	s(McEmemArbDaTurns, 31:0, scratch14, 31:0);
+	s(EmcCfgDigDll, 0:0, scratch17, 0:0);
+	s(EmcCfgDigDll, 25:2, scratch17, 24:1);
+	s(EmcCfgDigDll, 31:27, scratch17, 29:25);
+	s(EmcCdbCntl1, 29:0, scratch18, 29:0);
+	s(McEmemArbMisc0, 14:0, scratch19, 14:0);
+	s(McEmemArbMisc0, 30:16, scratch19, 29:15);
+	s(EmcXm2DqsPadCtrl, 4:0, scratch22, 4:0);
+	s(EmcXm2DqsPadCtrl, 12:8, scratch22, 9:5);
+	s(EmcXm2DqsPadCtrl, 31:14, scratch22, 27:10);
+	s(EmcRrd, 3:0, scratch22, 31:28);
+	s(EmcXm2DqPadCtrl, 31:4, scratch23, 27:0);
+	s(EmcRext, 3:0, scratch23, 31:28);
+	s(EmcXm2CompPadCtrl, 16:0, scratch24, 16:0);
+	s(EmcXm2CompPadCtrl, 24:20, scratch24, 21:17);
+	s(EmcXm2CompPadCtrl, 27:27, scratch24, 22:22);
+	s(EmcXm2CompPadCtrl, 31:28, scratch24, 26:23);
+	s(EmcR2w, 4:0, scratch24, 31:27);
+	s(EmcCfg, 9:1, scratch25, 8:0);
+	s(EmcCfg, 26:16, scratch25, 19:9);
+	s(EmcCfg, 31:28, scratch25, 23:20);
+	s(EmcXm2VttGenPadCtrl, 0:0, scratch25, 24:24);
+	s(EmcXm2VttGenPadCtrl, 2:2, scratch25, 25:25);
+	s(EmcXm2VttGenPadCtrl, 18:16, scratch25, 28:26);
+	s(EmcXm2VttGenPadCtrl, 26:24, scratch25, 31:29);
+	s(EmcZcalInterval, 23:10, scratch26, 13:0);
+	s(EmcZcalInterval, 9:0, scratch26, 23:14);
+	s(EmcSelDpdCtrl, 5:2, scratch26, 27:24);
+	s(EmcSelDpdCtrl, 8:8, scratch26, 28:28);
+	s(EmcSelDpdCtrl, 18:16, scratch26, 31:29);
+	s(EmcXm2VttGenPadCtrl3, 22:0, scratch27, 22:0);
+	s(EmcXm2VttGenPadCtrl3, 24:24, scratch27, 23:23);
+	s(EmcSwizzleRank0ByteCfg, 1:0, scratch27, 25:24);
+	s(EmcSwizzleRank0ByteCfg, 5:4, scratch27, 27:26);
+	s(EmcSwizzleRank0ByteCfg, 9:8, scratch27, 29:28);
+	s(EmcSwizzleRank0ByteCfg, 13:12, scratch27, 31:30);
+	s(EmcXm2ClkPadCtrl2, 5:0, scratch28, 5:0);
+	s(EmcXm2ClkPadCtrl2, 13:8, scratch28, 11:6);
+	s(EmcXm2ClkPadCtrl2, 20:16, scratch28, 16:12);
+	s(EmcXm2ClkPadCtrl2, 23:23, scratch28, 17:17);
+	s(EmcXm2ClkPadCtrl2, 28:24, scratch28, 22:18);
+	s(EmcXm2ClkPadCtrl2, 31:31, scratch28, 23:23);
+	s(EmcSwizzleRank1ByteCfg, 1:0, scratch28, 25:24);
+	s(EmcSwizzleRank1ByteCfg, 5:4, scratch28, 27:26);
+	s(EmcSwizzleRank1ByteCfg, 9:8, scratch28, 29:28);
+	s(EmcSwizzleRank1ByteCfg, 13:12, scratch28, 31:30);
+	s(McEmemArbDaCovers, 23:0, scratch29, 23:0);
+	s(McEmemArbRsv, 7:0, scratch29, 31:24);
+	s(EmcAutoCalConfig, 4:0, scratch30, 4:0);
+	s(EmcAutoCalConfig, 12:8, scratch30, 9:5);
+	s(EmcAutoCalConfig, 18:16, scratch30, 12:10);
+	s(EmcAutoCalConfig, 25:20, scratch30, 18:13);
+	s(EmcAutoCalConfig, 31:28, scratch30, 22:19);
+	s(EmcRfc, 8:0, scratch30, 31:23);
+	s(EmcXm2DqsPadCtrl2, 21:0, scratch31, 21:0);
+	s(EmcXm2DqsPadCtrl2, 24:24, scratch31, 22:22);
+	s(EmcAr2Pden, 8:0, scratch31, 31:23);
+	s(EmcXm2ClkPadCtrl, 0:0, scratch32, 0:0);
+	s(EmcXm2ClkPadCtrl, 4:2, scratch32, 3:1);
+	s(EmcXm2ClkPadCtrl, 7:7, scratch32, 4:4);
+	s(EmcXm2ClkPadCtrl, 31:14, scratch32, 22:5);
+	s(EmcRfcSlr, 8:0, scratch32, 31:23);
+	s(EmcXm2DqsPadCtrl3, 0:0, scratch33, 0:0);
+	s(EmcXm2DqsPadCtrl3, 5:5, scratch33, 1:1);
+	s(EmcXm2DqsPadCtrl3, 12:8, scratch33, 6:2);
+	s(EmcXm2DqsPadCtrl3, 18:14, scratch33, 11:7);
+	s(EmcXm2DqsPadCtrl3, 24:20, scratch33, 16:12);
+	s(EmcXm2DqsPadCtrl3, 30:26, scratch33, 21:17);
+	s(EmcTxsr, 9:0, scratch33, 31:22);
+	s(McEmemArbCfg, 8:0, scratch40, 8:0);
+	s(McEmemArbCfg, 20:16, scratch40, 13:9);
+	s(McEmemArbCfg, 27:24, scratch40, 17:14);
+	s(McEmemArbCfg, 31:28, scratch40, 21:18);
+	s(EmcMc2EmcQ, 2:0, scratch40, 24:22);
+	s(EmcMc2EmcQ, 10:8, scratch40, 27:25);
+	s(EmcMc2EmcQ, 27:24, scratch40, 31:28);
+	s(EmcAutoCalInterval, 20:0, scratch42, 20:0);
+	s(McEmemArbOutstandingReq, 8:0, scratch42, 29:21);
+	s(McEmemArbOutstandingReq, 31:30, scratch42, 31:30);
+	s(EmcMrsWaitCnt2, 9:0, scratch44, 9:0);
+	s(EmcMrsWaitCnt2, 25:16, scratch44, 19:10);
+	s(EmcTxdsrvttgen, 11:0, scratch44, 31:20);
+	s(EmcMrsWaitCnt, 9:0, scratch45, 9:0);
+	s(EmcMrsWaitCnt, 25:16, scratch45, 19:10);
+	s(EmcCfgPipe, 1:0, scratch45, 21:20);
+	s(EmcCfgPipe, 9:4, scratch45, 27:22);
+	s(EmcCfgPipe, 15:12, scratch45, 31:28);
+	s(EmcXm2DqsPadCtrl4, 22:18, scratch46, 4:0);
+	s(EmcXm2DqsPadCtrl4, 16:12, scratch46, 9:5);
+	s(EmcXm2DqsPadCtrl4, 10:6, scratch46, 14:10);
+	s(EmcXm2DqsPadCtrl4, 4:0, scratch46, 19:15);
+	s(EmcZcalWaitCnt, 9:0, scratch46, 29:20);
+	s(EmcXm2DqsPadCtrl5, 22:18, scratch47, 4:0);
+	s(EmcXm2DqsPadCtrl5, 16:12, scratch47, 9:5);
+	s(EmcXm2DqsPadCtrl5, 10:6, scratch47, 14:10);
+	s(EmcXm2DqsPadCtrl5, 4:0, scratch47, 19:15);
+	s(EmcXm2VttGenPadCtrl2, 5:0, scratch47, 25:20);
+	s(EmcXm2VttGenPadCtrl2, 31:28, scratch47, 29:26);
+	s(EmcXm2DqsPadCtrl6, 12:8, scratch48, 4:0);
+	s(EmcXm2DqsPadCtrl6, 18:14, scratch48, 9:5);
+	s(EmcXm2DqsPadCtrl6, 24:20, scratch48, 14:10);
+	s(EmcXm2DqsPadCtrl6, 30:26, scratch48, 19:15);
+	s(EmcAutoCalConfig3, 4:0, scratch48, 24:20);
+	s(EmcAutoCalConfig3, 12:8, scratch48, 29:25);
+	s(EmcFbioCfg5, 1:0, scratch48, 31:30);
+	s(EmcDllXformQUse8, 4:0, scratch50, 4:0);
+	s(EmcDllXformQUse8, 22:8, scratch50, 19:5);
+	s(McEmemArbRing1Throttle, 4:0, scratch50, 24:20);
+	s(McEmemArbRing1Throttle, 20:16, scratch50, 29:25);
+	s(EmcFbioCfg5, 3:2, scratch50, 31:30);
+	s(EmcDllXformQUse9, 4:0, scratch51, 4:0);
+	s(EmcDllXformQUse9, 22:8, scratch51, 19:5);
+	s(EmcCttTermCtrl, 2:0, scratch51, 22:20);
+	s(EmcCttTermCtrl, 12:8, scratch51, 27:23);
+	s(EmcCttTermCtrl, 31:31, scratch51, 28:28);
+	s(EmcFbioCfg6, 2:0, scratch51, 31:29);
+	s(EmcDllXformQUse10, 4:0, scratch56, 4:0);
+	s(EmcDllXformQUse10, 22:8, scratch56, 19:5);
+	s(EmcXm2CmdPadCtrl, 10:3, scratch56, 27:20);
+	s(EmcXm2CmdPadCtrl, 28:28, scratch56, 28:28);
+	s(EmcPutermAdj, 1:0, scratch56, 30:29);
+	s(EmcPutermAdj, 7:7, scratch56, 31:31);
+	s(EmcDllXformQUse11, 4:0, scratch57, 4:0);
+	s(EmcDllXformQUse11, 22:8, scratch57, 19:5);
+	s(EmcWdv, 3:0, scratch57, 31:28);
+	s(EmcDllXformQUse12, 4:0, scratch58, 4:0);
+	s(EmcDllXformQUse12, 22:8, scratch58, 19:5);
+	s(EmcBurstRefreshNum, 3:0, scratch58, 31:28);
+	s(EmcDllXformQUse13, 4:0, scratch59, 4:0);
+	s(EmcDllXformQUse13, 22:8, scratch59, 19:5);
+	s(EmcWext, 3:0, scratch59, 31:28);
+	s(EmcDllXformQUse14, 4:0, scratch60, 4:0);
+	s(EmcDllXformQUse14, 22:8, scratch60, 19:5);
+	s(EmcClkenOverride, 3:1, scratch60, 30:28);
+	s(EmcClkenOverride, 6:6, scratch60, 31:31);
+	s(EmcDllXformQUse15, 4:0, scratch61, 4:0);
+	s(EmcDllXformQUse15, 22:8, scratch61, 19:5);
+	s(EmcR2r, 3:0, scratch61, 31:28);
+	s(EmcDllXformDq4, 4:0, scratch62, 4:0);
+	s(EmcDllXformDq4, 22:8, scratch62, 19:5);
+	s(EmcRc, 6:0, scratch62, 26:20);
+	s(EmcW2r, 4:0, scratch62, 31:27);
+	s(EmcDllXformDq5, 4:0, scratch63, 4:0);
+	s(EmcDllXformDq5, 22:8, scratch63, 19:5);
+	s(EmcTfaw, 6:0, scratch63, 26:20);
+	s(EmcR2p, 4:0, scratch63, 31:27);
+	s(EmcDllXformDq6, 4:0, scratch64, 4:0);
+	s(EmcDllXformDq6, 22:8, scratch64, 19:5);
+	s(EmcDliTrimTxDqs0, 6:0, scratch64, 26:20);
+	s(EmcQSafe, 4:0, scratch64, 31:27);
+	s(EmcDllXformDq7, 4:0, scratch65, 4:0);
+	s(EmcDllXformDq7, 22:8, scratch65, 19:5);
+	s(EmcDliTrimTxDqs1, 6:0, scratch65, 26:20);
+	s(EmcTClkStable, 4:0, scratch65, 31:27);
+	s(EmcAutoCalConfig2, 4:0, scratch66, 4:0);
+	s(EmcAutoCalConfig2, 12:8, scratch66, 9:5);
+	s(EmcAutoCalConfig2, 20:16, scratch66, 14:10);
+	s(EmcAutoCalConfig2, 28:24, scratch66, 19:15);
+	s(EmcDliTrimTxDqs2, 6:0, scratch66, 26:20);
+	s(EmcTClkStop, 4:0, scratch66, 31:27);
+	s(McEmemArbMisc1, 1:0, scratch67, 1:0);
+	s(McEmemArbMisc1, 12:4, scratch67, 10:2);
+	s(McEmemArbMisc1, 25:21, scratch67, 15:11);
+	s(McEmemArbMisc1, 31:28, scratch67, 19:16);
+	s(EmcDliTrimTxDqs3, 6:0, scratch67, 26:20);
+	s(EmcEInputDuration, 4:0, scratch67, 31:27);
+	s(EmcZcalMrwCmd, 7:0, scratch68, 7:0);
+	s(EmcZcalMrwCmd, 23:16, scratch68, 15:8);
+	s(EmcZcalMrwCmd, 31:30, scratch68, 17:16);
+	s(EmcTRefBw, 13:0, scratch68, 31:18);
+	s(EmcXm2CmdPadCtrl2, 31:14, scratch69, 17:0);
+	s(EmcDliTrimTxDqs4, 6:0, scratch69, 24:18);
+	s(EmcDliTrimTxDqs5, 6:0, scratch69, 31:25);
+	s(EmcXm2CmdPadCtrl3, 31:14, scratch70, 17:0);
+	s(EmcDliTrimTxDqs6, 6:0, scratch70, 24:18);
+	s(EmcDliTrimTxDqs7, 6:0, scratch70, 31:25);
+	s(EmcXm2CmdPadCtrl5, 2:0, scratch71, 2:0);
+	s(EmcXm2CmdPadCtrl5, 6:4, scratch71, 5:3);
+	s(EmcXm2CmdPadCtrl5, 10:8, scratch71, 8:6);
+	s(EmcXm2CmdPadCtrl5, 14:12, scratch71, 11:9);
+	s(EmcXm2CmdPadCtrl5, 18:16, scratch71, 14:12);
+	s(EmcXm2CmdPadCtrl5, 22:20, scratch71, 17:15);
+	s(EmcDliTrimTxDqs8, 6:0, scratch71, 24:18);
+	s(EmcDliTrimTxDqs9, 6:0, scratch71, 31:25);
+	s(EmcCdbCntl3, 17:0, scratch72, 17:0);
+	s(EmcDliTrimTxDqs10, 6:0, scratch72, 24:18);
+	s(EmcDliTrimTxDqs11, 6:0, scratch72, 31:25);
+	s(EmcSwizzleRank0Byte0, 2:0, scratch73, 2:0);
+	s(EmcSwizzleRank0Byte0, 6:4, scratch73, 5:3);
+	s(EmcSwizzleRank0Byte0, 10:8, scratch73, 8:6);
+	s(EmcSwizzleRank0Byte0, 14:12, scratch73, 11:9);
+	s(EmcSwizzleRank0Byte0, 18:16, scratch73, 14:12);
+	s(EmcSwizzleRank0Byte0, 22:20, scratch73, 17:15);
+	s(EmcDliTrimTxDqs12, 6:0, scratch73, 24:18);
+	s(EmcDliTrimTxDqs13, 6:0, scratch73, 31:25);
+	s(EmcSwizzleRank0Byte1, 2:0, scratch74, 2:0);
+	s(EmcSwizzleRank0Byte1, 6:4, scratch74, 5:3);
+	s(EmcSwizzleRank0Byte1, 10:8, scratch74, 8:6);
+	s(EmcSwizzleRank0Byte1, 14:12, scratch74, 11:9);
+	s(EmcSwizzleRank0Byte1, 18:16, scratch74, 14:12);
+	s(EmcSwizzleRank0Byte1, 22:20, scratch74, 17:15);
+	s(EmcDliTrimTxDqs14, 6:0, scratch74, 24:18);
+	s(EmcDliTrimTxDqs15, 6:0, scratch74, 31:25);
+	s(EmcSwizzleRank0Byte2, 2:0, scratch75, 2:0);
+	s(EmcSwizzleRank0Byte2, 6:4, scratch75, 5:3);
+	s(EmcSwizzleRank0Byte2, 10:8, scratch75, 8:6);
+	s(EmcSwizzleRank0Byte2, 14:12, scratch75, 11:9);
+	s(EmcSwizzleRank0Byte2, 18:16, scratch75, 14:12);
+	s(EmcSwizzleRank0Byte2, 22:20, scratch75, 17:15);
+	s(McEmemArbTimingRp, 6:0, scratch75, 24:18);
+	s(McEmemArbTimingRc, 6:0, scratch75, 31:25);
+	s(EmcSwizzleRank0Byte3, 2:0, scratch76, 2:0);
+	s(EmcSwizzleRank0Byte3, 6:4, scratch76, 5:3);
+	s(EmcSwizzleRank0Byte3, 10:8, scratch76, 8:6);
+	s(EmcSwizzleRank0Byte3, 14:12, scratch76, 11:9);
+	s(EmcSwizzleRank0Byte3, 18:16, scratch76, 14:12);
+	s(EmcSwizzleRank0Byte3, 22:20, scratch76, 17:15);
+	s(McEmemArbTimingFaw, 6:0, scratch76, 24:18);
+	s(McEmemArbTimingWap2Pre, 6:0, scratch76, 31:25);
+	s(EmcSwizzleRank1Byte0, 2:0, scratch77, 2:0);
+	s(EmcSwizzleRank1Byte0, 6:4, scratch77, 5:3);
+	s(EmcSwizzleRank1Byte0, 10:8, scratch77, 8:6);
+	s(EmcSwizzleRank1Byte0, 14:12, scratch77, 11:9);
+	s(EmcSwizzleRank1Byte0, 18:16, scratch77, 14:12);
+	s(EmcSwizzleRank1Byte0, 22:20, scratch77, 17:15);
+	s(EmcRas, 5:0, scratch77, 23:18);
+	s(EmcRp, 5:0, scratch77, 29:24);
+	s(EmcCfg2, 9:8, scratch77, 31:30);
+	s(EmcSwizzleRank1Byte1, 2:0, scratch78, 2:0);
+	s(EmcSwizzleRank1Byte1, 6:4, scratch78, 5:3);
+	s(EmcSwizzleRank1Byte1, 10:8, scratch78, 8:6);
+	s(EmcSwizzleRank1Byte1, 14:12, scratch78, 11:9);
+	s(EmcSwizzleRank1Byte1, 18:16, scratch78, 14:12);
+	s(EmcSwizzleRank1Byte1, 22:20, scratch78, 17:15);
+	s(EmcW2p, 5:0, scratch78, 23:18);
+	s(EmcRdRcd, 5:0, scratch78, 29:24);
+	s(EmcCfg2, 27:26, scratch78, 31:30);
+	s(EmcSwizzleRank1Byte2, 2:0, scratch79, 2:0);
+	s(EmcSwizzleRank1Byte2, 6:4, scratch79, 5:3);
+	s(EmcSwizzleRank1Byte2, 10:8, scratch79, 8:6);
+	s(EmcSwizzleRank1Byte2, 14:12, scratch79, 11:9);
+	s(EmcSwizzleRank1Byte2, 18:16, scratch79, 14:12);
+	s(EmcSwizzleRank1Byte2, 22:20, scratch79, 17:15);
+	s(EmcWrRcd, 5:0, scratch79, 23:18);
+	s(EmcQUse, 5:0, scratch79, 29:24);
+	s(EmcFbioCfg5, 4:4, scratch79, 31:31);
+	s(EmcSwizzleRank1Byte3, 2:0, scratch80, 2:0);
+	s(EmcSwizzleRank1Byte3, 6:4, scratch80, 5:3);
+	s(EmcSwizzleRank1Byte3, 10:8, scratch80, 8:6);
+	s(EmcSwizzleRank1Byte3, 14:12, scratch80, 11:9);
+	s(EmcSwizzleRank1Byte3, 18:16, scratch80, 14:12);
+	s(EmcSwizzleRank1Byte3, 22:20, scratch80, 17:15);
+	s(EmcQRst, 5:0, scratch80, 23:18);
+	s(EmcRdv, 5:0, scratch80, 29:24);
+	s(EmcFbioCfg5, 6:5, scratch80, 31:30);
+	s(EmcDynSelfRefControl, 15:0, scratch81, 15:0);
+	s(EmcDynSelfRefControl, 31:31, scratch81, 16:16);
+	s(EmcPdEx2Wr, 5:0, scratch81, 22:17);
+	s(EmcPdEx2Rd, 5:0, scratch81, 28:23);
+	s(EmcRefresh, 5:0, scratch82, 5:0);
+	s(EmcRefresh, 15:6, scratch82, 15:6);
+	s(EmcCmdQ, 4:0, scratch82, 20:16);
+	s(EmcCmdQ, 10:8, scratch82, 23:21);
+	s(EmcCmdQ, 14:12, scratch82, 26:24);
+	s(EmcCmdQ, 28:24, scratch82, 31:27);
+	s(EmcAcpdControl, 15:0, scratch83, 15:0);
+	s(EmcCfgDigDllPeriod, 15:0, scratch83, 31:16);
+	s(EmcDllXformDqs0, 4:0, scratch84, 4:0);
+	s(EmcDllXformDqs0, 22:12, scratch84, 15:5);
+	s(EmcDllXformDqs1, 4:0, scratch84, 20:16);
+	s(EmcDllXformDqs1, 22:12, scratch84, 31:21);
+	s(EmcDllXformDqs2, 4:0, scratch85, 4:0);
+	s(EmcDllXformDqs2, 22:12, scratch85, 15:5);
+	s(EmcDllXformDqs3, 4:0, scratch85, 20:16);
+	s(EmcDllXformDqs3, 22:12, scratch85, 31:21);
+	s(EmcDllXformDqs4, 4:0, scratch86, 4:0);
+	s(EmcDllXformDqs4, 22:12, scratch86, 15:5);
+	s(EmcDllXformDqs5, 4:0, scratch86, 20:16);
+	s(EmcDllXformDqs5, 22:12, scratch86, 31:21);
+	s(EmcDllXformDqs6, 4:0, scratch87, 4:0);
+	s(EmcDllXformDqs6, 22:12, scratch87, 15:5);
+	s(EmcDllXformDqs7, 4:0, scratch87, 20:16);
+	s(EmcDllXformDqs7, 22:12, scratch87, 31:21);
+	s(EmcDllXformDqs8, 4:0, scratch88, 4:0);
+	s(EmcDllXformDqs8, 22:12, scratch88, 15:5);
+	s(EmcDllXformDqs9, 4:0, scratch88, 20:16);
+	s(EmcDllXformDqs9, 22:12, scratch88, 31:21);
+	s(EmcDllXformDqs10, 4:0, scratch89, 4:0);
+	s(EmcDllXformDqs10, 22:12, scratch89, 15:5);
+	s(EmcDllXformDqs11, 4:0, scratch89, 20:16);
+	s(EmcDllXformDqs11, 22:12, scratch89, 31:21);
+	s(EmcDllXformDqs12, 4:0, scratch90, 4:0);
+	s(EmcDllXformDqs12, 22:12, scratch90, 15:5);
+	s(EmcDllXformDqs13, 4:0, scratch90, 20:16);
+	s(EmcDllXformDqs13, 22:12, scratch90, 31:21);
+	s(EmcDllXformDqs14, 4:0, scratch91, 4:0);
+	s(EmcDllXformDqs14, 22:12, scratch91, 15:5);
+	s(EmcDllXformDqs15, 4:0, scratch91, 20:16);
+	s(EmcDllXformDqs15, 22:12, scratch91, 31:21);
+	s(EmcDllXformQUse0, 4:0, scratch92, 4:0);
+	s(EmcDllXformQUse0, 22:12, scratch92, 15:5);
+	s(EmcDllXformQUse1, 4:0, scratch92, 20:16);
+	s(EmcDllXformQUse1, 22:12, scratch92, 31:21);
+	s(EmcDllXformQUse2, 4:0, scratch93, 4:0);
+	s(EmcDllXformQUse2, 22:12, scratch93, 15:5);
+	s(EmcDllXformQUse3, 4:0, scratch93, 20:16);
+	s(EmcDllXformQUse3, 22:12, scratch93, 31:21);
+	s(EmcDllXformQUse4, 4:0, scratch94, 4:0);
+	s(EmcDllXformQUse4, 22:12, scratch94, 15:5);
+	s(EmcDllXformQUse5, 4:0, scratch94, 20:16);
+	s(EmcDllXformQUse5, 22:12, scratch94, 31:21);
+	s(EmcDllXformQUse6, 4:0, scratch95, 4:0);
+	s(EmcDllXformQUse6, 22:12, scratch95, 15:5);
+	s(EmcDllXformQUse7, 4:0, scratch95, 20:16);
+	s(EmcDllXformQUse7, 22:12, scratch95, 31:21);
+	s(EmcDllXformDq0, 4:0, scratch96, 4:0);
+	s(EmcDllXformDq0, 22:12, scratch96, 15:5);
+	s(EmcDllXformDq1, 4:0, scratch96, 20:16);
+	s(EmcDllXformDq1, 22:12, scratch96, 31:21);
+	s(EmcDllXformDq2, 4:0, scratch97, 4:0);
+	s(EmcDllXformDq2, 22:12, scratch97, 15:5);
+	s(EmcDllXformDq3, 4:0, scratch97, 20:16);
+	s(EmcDllXformDq3, 22:12, scratch97, 31:21);
+	s(EmcPreRefreshReqCnt, 15:0, scratch98, 15:0);
+	s(EmcDllXformAddr0, 4:0, scratch98, 20:16);
+	s(EmcDllXformAddr0, 22:12, scratch98, 31:21);
+	s(EmcDllXformAddr1, 4:0, scratch99, 4:0);
+	s(EmcDllXformAddr1, 22:12, scratch99, 15:5);
+	s(EmcDllXformAddr2, 4:0, scratch99, 20:16);
+	s(EmcDllXformAddr2, 22:12, scratch99, 31:21);
+	s(EmcDllXformAddr3, 4:0, scratch100, 4:0);
+	s(EmcDllXformAddr3, 22:12, scratch100, 15:5);
+	s(EmcDllXformAddr4, 4:0, scratch100, 20:16);
+	s(EmcDllXformAddr4, 22:12, scratch100, 31:21);
+	s(EmcDllXformAddr5, 4:0, scratch101, 4:0);
+	s(EmcDllXformAddr5, 22:12, scratch101, 15:5);
+	s(EmcPChg2Pden, 5:0, scratch102, 5:0);
+	s(EmcAct2Pden, 5:0, scratch102, 11:6);
+	s(EmcRw2Pden, 5:0, scratch102, 17:12);
+	s(EmcTcke, 5:0, scratch102, 23:18);
+	s(EmcTrpab, 5:0, scratch102, 29:24);
+	s(EmcFbioCfg5, 8:7, scratch102, 31:30);
+	s(EmcCtt, 5:0, scratch103, 5:0);
+	s(EmcEInput, 5:0, scratch103, 11:6);
+	s(EmcPutermExtra, 21:16, scratch103, 17:12);
+	s(EmcTckesr, 5:0, scratch103, 23:18);
+	s(EmcTpd, 5:0, scratch103, 29:24);
+	s(EmcFbioCfg5, 10:9, scratch103, 31:30);
+	s(EmcRdvMask, 5:0, scratch104, 5:0);
+	s(EmcXm2CmdPadCtrl4, 0:0, scratch104, 6:6);
+	s(EmcXm2CmdPadCtrl4, 2:2, scratch104, 7:7);
+	s(EmcXm2CmdPadCtrl4, 4:4, scratch104, 8:8);
+	s(EmcXm2CmdPadCtrl4, 6:6, scratch104, 9:9);
+	s(EmcXm2CmdPadCtrl4, 8:8, scratch104, 10:10);
+	s(EmcXm2CmdPadCtrl4, 10:10, scratch104, 11:11);
+	s(EmcQpop, 5:0, scratch104, 17:12);
+	s(McEmemArbTimingRcd, 5:0, scratch104, 23:18);
+	s(McEmemArbTimingRas, 5:0, scratch104, 29:24);
+	s(EmcFbioCfg5, 12:11, scratch104, 31:30);
+	s(McEmemArbTimingRap2Pre, 5:0, scratch105, 5:0);
+	s(McEmemArbTimingR2W, 5:0, scratch105, 11:6);
+	s(McEmemArbTimingW2R, 5:0, scratch105, 17:12);
+	s(EmcIbdly, 4:0, scratch105, 22:18);
+	s(McEmemArbTimingR2R, 4:0, scratch105, 27:23);
+	s(EmcW2w, 3:0, scratch105, 31:28);
+	s(McEmemArbTimingW2W, 4:0, scratch106, 4:0);
+	s(McEmemArbOverride, 27:27, scratch106, 5:5);
+	s(McEmemArbOverride, 26:26, scratch106, 6:6);
+	s(McEmemArbOverride, 16:16, scratch106, 7:7);
+	s(McEmemArbOverride, 10:10, scratch106, 8:8);
+	s(McEmemArbOverride, 4:4, scratch106, 9:9);
+	s(EmcWdvMask, 3:0, scratch106, 13:10);
+	s(EmcCttDuration, 3:0, scratch106, 17:14);
+	s(EmcQuseWidth, 3:0, scratch106, 21:18);
+	s(EmcPutermWidth, 3:0, scratch106, 25:22);
+	s(EmcBgbiasCtl0, 3:0, scratch106, 29:26);
+	s(EmcFbioCfg5, 25:24, scratch106, 31:30);
+	s(McEmemArbTimingRrd, 3:0, scratch107, 3:0);
+	s(EmcFbioCfg5, 23:20, scratch107, 10:7);
+	s(EmcFbioCfg5, 15:13, scratch107, 13:11);
+	s(EmcCfg2, 5:3, scratch107, 16:14);
+	s(EmcFbioCfg5, 26:26, scratch107, 17:17);
+	s(EmcFbioCfg5, 28:28, scratch107, 18:18);
+	s(EmcCfg2, 2:0, scratch107, 21:19);
+	s(EmcCfg2, 7:6, scratch107, 23:22);
+	s(EmcCfg2, 15:10, scratch107, 29:24);
+	s(EmcCfg2, 23:22, scratch107, 31:30);
+	s(EmcCfg2, 25:24, scratch108, 1:0);
+	s(EmcCfg2, 31:28, scratch108, 5:2);
+	s(BootRomPatchData, 31:0, scratch15, 31:0);
+	s(BootRomPatchControl, 31:0, scratch16, 31:0);
+	s(EmcDevSelect, 1:0, scratch17, 31:30);
+	s(EmcZcalWarmColdBootEnables, 1:0, scratch18, 31:30);
+	s(EmcCfgDigDllPeriodWarmBoot, 1:0, scratch19, 31:30);
+	s(EmcWarmBootExtraModeRegWriteEnable, 0:0, scratch46, 30:30);
+	s(McClkenOverrideAllWarmBoot, 0:0, scratch46, 31:31);
+	s(EmcClkenOverrideAllWarmBoot, 0:0, scratch47, 30:30);
+	s(EmcMrsWarmBootEnable, 0:0, scratch47, 31:31);
+	s(EmcTimingControlWait, 7:0, scratch57, 27:20);
+	s(EmcZcalWarmBootWait, 7:0, scratch58, 27:20);
+	s(EmcAutoCalWait, 7:0, scratch59, 27:20);
+	s(WarmBootWait, 7:0, scratch60, 27:20);
+	s(EmcPinProgramWait, 7:0, scratch61, 27:20);
+	s(AhbArbitrationXbarCtrlMemInitDone, 0:0, scratch79, 30:30);
+	s(EmcExtraRefreshNum, 2:0, scratch81, 31:29);
+	s(SwizzleRankByteEncode, 15:0, scratch101, 31:16);
+	s(MemoryType, 2:0, scratch107, 6:4);
+
+	switch (sdram->MemoryType) {
+	case NvBootMemoryType_LpDdr2:
+		s(EmcMrwLpddr2ZcalWarmBoot, 23:16, scratch5, 7:0);
+		s(EmcMrwLpddr2ZcalWarmBoot, 7:0, scratch5, 15:8);
+		s(EmcWarmBootMrwExtra, 23:16, scratch5, 23:16);
+		s(EmcWarmBootMrwExtra, 7:0, scratch5, 31:24);
+		s(EmcMrwLpddr2ZcalWarmBoot, 31:30, scratch6, 1:0);
+		s(EmcWarmBootMrwExtra, 31:30, scratch6, 3:2);
+		s(EmcMrwLpddr2ZcalWarmBoot, 27:26, scratch6, 5:4);
+		s(EmcWarmBootMrwExtra, 27:26, scratch6, 7:6);
+		s(EmcMrw1, 7:0, scratch7, 7:0);
+		s(EmcMrw1, 23:16, scratch7, 15:8);
+		s(EmcMrw1, 27:26, scratch7, 17:16);
+		s(EmcMrw1, 31:30, scratch7, 19:18);
+		s(EmcMrw2, 7:0, scratch8, 7:0);
+		s(EmcMrw2, 23:16, scratch8, 15:8);
+		s(EmcMrw2, 27:26, scratch8, 17:16);
+		s(EmcMrw2, 31:30, scratch8, 19:18);
+		s(EmcMrw3, 7:0, scratch9, 7:0);
+		s(EmcMrw3, 23:16, scratch9, 15:8);
+		s(EmcMrw3, 27:26, scratch9, 17:16);
+		s(EmcMrw3, 31:30, scratch9, 19:18);
+		s(EmcMrw4, 7:0, scratch10, 7:0);
+		s(EmcMrw4, 23:16, scratch10, 15:8);
+		s(EmcMrw4, 27:26, scratch10, 17:16);
+		s(EmcMrw4, 31:30, scratch10, 19:18);
+		break;
+	case NvBootMemoryType_Ddr3:
+		s(EmcMrs, 13:0, scratch5, 13:0);
+		s(EmcEmrs, 13:0, scratch5, 27:14);
+		s(EmcMrs, 21:20, scratch5, 29:28);
+		s(EmcMrs, 31:30, scratch5, 31:30);
+		s(EmcEmrs2, 13:0, scratch7, 13:0);
+		s(EmcEmrs, 21:20, scratch7, 15:14);
+		s(EmcEmrs, 31:30, scratch7, 17:16);
+		s(EmcEmrs2, 21:20, scratch7, 19:18);
+		s(EmcEmrs3, 13:0, scratch8, 13:0);
+		s(EmcEmrs2, 31:30, scratch8, 15:14);
+		s(EmcEmrs3, 21:20, scratch8, 17:16);
+		s(EmcEmrs3, 31:30, scratch8, 19:18);
+		s(EmcWarmBootMrsExtra, 13:0, scratch9, 13:0);
+		s(EmcWarmBootMrsExtra, 31:30, scratch9, 15:14);
+		s(EmcWarmBootMrsExtra, 21:20, scratch9, 17:16);
+		s(EmcZqCalDdr3WarmBoot, 31:30, scratch9, 19:18);
+		s(EmcMrs, 27:26, scratch10, 1:0);
+		s(EmcEmrs, 27:26, scratch10, 3:2);
+		s(EmcEmrs2, 27:26, scratch10, 5:4);
+		s(EmcEmrs3, 27:26, scratch10, 7:6);
+		s(EmcWarmBootMrsExtra, 27:27, scratch10, 8:8);
+		s(EmcWarmBootMrsExtra, 26:26, scratch10, 9:9);
+		s(EmcZqCalDdr3WarmBoot, 0:0, scratch10, 10:10);
+		s(EmcZqCalDdr3WarmBoot, 4:4, scratch10, 11:11);
+		c(0, scratch116, 31:0);
+		c(0, scratch117, 31:0);
+		break;
+	default:
+		printk(BIOS_CRIT, "ERROR: %s() unrecognized MemoryType %d!\n",
+		       __func__, sdram->MemoryType);
+	}
+
+	s(McVideoProtectGpuOverride0, 31:0, secure_scratch8, 31:0);
+	s(McVideoProtectVprOverride, 3:0, secure_scratch9, 3:0);
+	s(McVideoProtectVprOverride, 11:6, secure_scratch9, 9:4);
+	s(McVideoProtectVprOverride, 23:14, secure_scratch9, 19:10);
+	s(McVideoProtectVprOverride, 26:26, secure_scratch9, 20:20);
+	s(McVideoProtectVprOverride, 31:29, secure_scratch9, 23:21);
+	s(EmcFbioCfg5, 19:16, secure_scratch9, 27:24);
+	s(McDisplaySnapRing, 1:0, secure_scratch9, 29:28);
+	s(McDisplaySnapRing, 31:31, secure_scratch9, 30:30);
+	s(EmcAdrCfg, 0:0, secure_scratch9, 31:31);
+	s(McVideoProtectGpuOverride1, 15:0, secure_scratch10, 15:0);
+	s(McEmemAdrCfgBankMask0, 15:0, secure_scratch10, 31:16);
+	s(McEmemAdrCfgBankMask1, 15:0, secure_scratch11, 15:0);
+	s(McEmemAdrCfgBankMask2, 15:0, secure_scratch11, 31:16);
+	s(McEmemCfg, 13:0, secure_scratch12, 13:0);
+	s(McEmemCfg, 31:31, secure_scratch12, 14:14);
+	s(McVideoProtectBom, 31:20, secure_scratch12, 26:15);
+	s(McVideoProtectVprOverride1, 1:0, secure_scratch12, 28:27);
+	s(McVideoProtectVprOverride1, 4:4, secure_scratch12, 29:29);
+	s(McVideoProtectBomAdrHi, 1:0, secure_scratch12, 31:30);
+	s(McVideoProtectSizeMb, 11:0, secure_scratch13, 11:0);
+	s(McSecCarveoutBom, 31:20, secure_scratch13, 23:12);
+	s(McEmemAdrCfgBankSwizzle3, 2:0, secure_scratch13, 26:24);
+	s(McVideoProtectWriteAccess, 1:0, secure_scratch13, 28:27);
+	s(McSecCarveoutAdrHi, 1:0, secure_scratch13, 30:29);
+	s(McEmemAdrCfg, 0:0, secure_scratch13, 31:31);
+	s(McSecCarveoutSizeMb, 11:0, secure_scratch14, 11:0);
+	s(McMtsCarveoutBom, 31:20, secure_scratch14, 23:12);
+	s(McMtsCarveoutAdrHi, 1:0, secure_scratch14, 25:24);
+	s(McSecCarveoutProtectWriteAccess, 0:0, secure_scratch14, 26:26);
+	s(McMtsCarveoutRegCtrl, 0:0, secure_scratch14, 27:27);
+	s(McMtsCarveoutSizeMb, 11:0, secure_scratch15, 11:0);
+	s(McEmemAdrCfgDev0, 2:0, secure_scratch15, 14:12);
+	s(McEmemAdrCfgDev0, 9:8, secure_scratch15, 16:15);
+	s(McEmemAdrCfgDev0, 19:16, secure_scratch15, 20:17);
+	s(McEmemAdrCfgDev1, 2:0, secure_scratch15, 23:21);
+	s(McEmemAdrCfgDev1, 9:8, secure_scratch15, 25:24);
+	s(McEmemAdrCfgDev1, 19:16, secure_scratch15, 29:26);
+
+	c(0x1555555, sec_disable2, 25:0);
+	c(0xff, sec_disable, 19:12);
+
+	c(0, scratch2, 31:0);
+	m(pllm_base, 15:0, scratch2, 15:0);
+	m(pllm_base, 20:20, scratch2, 16:16);
+	m(pllm_misc2, 2:0, scratch2, 19:17);
+	c(0, scratch35, 31:0);
+	m(pllm_misc1, 23:0, scratch35, 23:0);
+	m(pllm_misc1, 30:28, scratch35, 30:28);
+	c(0, scratch3, 31:0);
+	s(PllMInputDivider, 7:0, scratch3, 7:0);
+	c(0x3e, scratch3, 15:8);
+	c(0, scratch3, 19:16);
+	s(PllMKVCO, 0:0, scratch3, 20:20);
+	s(PllMKCP, 1:0, scratch3, 22:21);
+	c(0, scratch36, 31:0);
+	s(PllMSetupControl, 23:0, scratch36, 23:0);
+	c(0, scratch4, 31:0);
+	s(PllMStableTime, 9:0, scratch4, 9:0);
+	s(PllMStableTime, 9:0, scratch4, 19:10);
+
+	s(PllMSelectDiv2, 0:0, pllm_wb0_override2, 27:27);
+	s(PllMKVCO, 0:0, pllm_wb0_override2, 26:26);
+	s(PllMKCP, 1:0, pllm_wb0_override2, 25:24);
+	s(PllMSetupControl, 23:0, pllm_wb0_override2, 23:0);
+	s(PllMFeedbackDivider, 7:0, pllm_wb0_override_freq, 15:8);
+	s(PllMInputDivider, 7:0, pllm_wb0_override_freq, 7:0);
+
+	c(3, pllp_wb0_override, 12:11);
+}
diff --git a/src/soc/nvidia/tegra210/secmon.c b/src/soc/nvidia/tegra210/secmon.c
new file mode 100644
index 0000000..66ebed2
--- /dev/null
+++ b/src/soc/nvidia/tegra210/secmon.c
@@ -0,0 +1,50 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright 2014 Google Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc.
+ */
+
+#include <arch/secmon.h>
+#include <console/console.h>
+#include <soc/addressmap.h>
+#include <soc/mmu_operations.h>
+
+static void soc_get_secure_mem(uint64_t *base, size_t *size)
+{
+	uintptr_t tz_base_mib;
+	size_t tz_size_mib;
+
+	carveout_range(CARVEOUT_TZ, &tz_base_mib, &tz_size_mib);
+
+	tz_base_mib *= MiB;
+	tz_size_mib *= MiB;
+
+	*base = tz_base_mib;
+	*size = tz_size_mib;
+}
+
+void soc_get_secmon_base_size(uint64_t *base, size_t *size)
+{
+	uintptr_t tz_base;
+	size_t ttb_size, tz_size;
+
+	soc_get_secure_mem(&tz_base, &tz_size);
+
+	ttb_size = TTB_SIZE * MiB;
+
+	*base = tz_base + ttb_size;
+	*size = tz_size - ttb_size;
+}
diff --git a/src/soc/nvidia/tegra210/soc.c b/src/soc/nvidia/tegra210/soc.c
new file mode 100644
index 0000000..f3290c3
--- /dev/null
+++ b/src/soc/nvidia/tegra210/soc.c
@@ -0,0 +1,191 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2011 The ChromiumOS Authors.  All rights reserved.
+ * Copyright 2014 Google Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc.
+ */
+
+#include <arch/io.h>
+#include <arch/cache.h>
+#include <arch/spintable.h>
+#include <cpu/cpu.h>
+#include <bootstate.h>
+#include <cbmem.h>
+#include <console/console.h>
+#include <device/device.h>
+#include <soc/nvidia/tegra/dc.h>
+#include <soc/addressmap.h>
+#include <soc/clock.h>
+#include <soc/cpu.h>
+#include <soc/mc.h>
+#include <soc/mtc.h>
+#include <soc/nvidia/tegra/apbmisc.h>
+#include <string.h>
+#include <timer.h>
+#include <vendorcode/google/chromeos/chromeos.h>
+
+#include "chip.h"
+
+static void soc_read_resources(device_t dev)
+{
+	unsigned long index = 0;
+	int i; uintptr_t begin, end;
+	size_t size;
+
+	for (i = 0; i < CARVEOUT_NUM; i++) {
+		carveout_range(i, &begin, &size);
+		if (size == 0)
+			continue;
+		reserved_ram_resource(dev, index++, begin * KiB, size * KiB);
+	}
+
+	memory_in_range_below_4gb(&begin, &end);
+	size = end - begin;
+	ram_resource(dev, index++, begin * KiB, size * KiB);
+
+	memory_in_range_above_4gb(&begin, &end);
+	size = end - begin;
+	ram_resource(dev, index++, begin * KiB, size * KiB);
+}
+
+static size_t cntrl_total_cpus(void)
+{
+	return CONFIG_MAX_CPUS;
+}
+
+static int cntrl_start_cpu(unsigned int id, void (*entry)(void))
+{
+	if (id >= CONFIG_MAX_CPUS)
+		return -1;
+	start_cpu(id, entry);
+	return 0;
+}
+
+static struct cpu_control_ops cntrl_ops = {
+	.total_cpus = cntrl_total_cpus,
+	.start_cpu = cntrl_start_cpu,
+};
+
+
+static void lock_down_vpr(void)
+{
+	struct tegra_mc_regs *regs = (void *)(uintptr_t)TEGRA_MC_BASE;
+
+	write32(&regs->video_protect_bom, 0);
+	write32(&regs->video_protect_size_mb, 0);
+
+	write32(&regs->video_protect_gpu_override_0, 1);
+	/*
+	 * Set both _ACCESS bits so that kernel/secure code
+	 * can reconfig VPR careveout as needed from the TrustZone.
+	 */
+
+	write32(&regs->video_protect_reg_ctrl,
+		(MC_VPR_WR_ACCESS_DISABLE | MC_VPR_ALLOW_TZ_WR_ACCESS_ENABLE));
+}
+
+static void soc_init(device_t dev)
+{
+	struct soc_nvidia_tegra210_config *cfg;
+
+	clock_init_arm_generic_timer();
+
+	cfg = dev->chip_info;
+	spintable_init((void *)cfg->spintable_addr);
+	arch_initialize_cpus(dev, &cntrl_ops);
+
+	/* Lock down VPR */
+	lock_down_vpr();
+
+#if IS_ENABLED(CONFIG_MAINBOARD_DO_NATIVE_VGA_INIT)
+	if (vboot_skip_display_init())
+		printk(BIOS_INFO, "Skipping display init.\n");
+	else
+		display_startup(dev);
+#endif
+}
+
+static void soc_noop(device_t dev)
+{
+}
+
+static struct device_operations soc_ops = {
+	.read_resources   = soc_read_resources,
+	.set_resources    = soc_noop,
+	.enable_resources = soc_noop,
+	.init             = soc_init,
+	.scan_bus         = NULL,
+};
+
+static void enable_tegra210_dev(device_t dev)
+{
+	if (dev->path.type == DEVICE_PATH_CPU_CLUSTER)
+		dev->ops = &soc_ops;
+}
+
+static void tegra210_init(void *chip_info)
+{
+	struct tegra_revision rev;
+
+	tegra_revision_info(&rev);
+
+	printk(BIOS_INFO, "chip %x rev %02x.%x\n",
+		rev.chip_id, rev.major, rev.minor);
+}
+
+struct chip_operations soc_nvidia_tegra210_ops = {
+	CHIP_NAME("SOC Nvidia Tegra210")
+	.init = tegra210_init,
+	.enable_dev = enable_tegra210_dev,
+};
+
+static void tegra210_cpu_init(device_t cpu)
+{
+	if (cpu_is_bsp())
+		if (tegra210_run_mtc() != 0)
+			printk(BIOS_ERR, "MTC: Training failed\n");
+}
+
+static const struct cpu_device_id ids[] = {
+	{ 0x411fd071 },
+	{ CPU_ID_END },
+};
+
+static struct device_operations cpu_dev_ops = {
+	.init = tegra210_cpu_init,
+};
+
+static const struct cpu_driver driver __cpu_driver = {
+	.ops      = &cpu_dev_ops,
+	.id_table = ids,
+};
+
+static void enable_plld(void *unused)
+{
+	/*
+	 * Configure a conservative 300MHz clock for PLLD. The kernel cannot
+	 * handle PLLD not being configured so enable PLLD unconditionally
+	 * with a default clock rate.
+	 */
+	clock_configure_plld(300 * MHz);
+}
+
+/*
+ * The PLLD being enabled is done at BS_DEV_INIT  time because mainboard_init()
+ * is the first thing called. This ensures PLLD is up and functional before
+ * anything that mainboard can do that implicitly relies on PLLD.
+ */
+BOOT_STATE_INIT_ENTRY(BS_DEV_INIT, BS_ON_ENTRY, enable_plld, NULL);
diff --git a/src/soc/nvidia/tegra210/sor.c b/src/soc/nvidia/tegra210/sor.c
new file mode 100644
index 0000000..116656e
--- /dev/null
+++ b/src/soc/nvidia/tegra210/sor.c
@@ -0,0 +1,1100 @@
+/*
+ * drivers/video/tegra/dc/sor.c
+ *
+ * Copyright (c) 2011-2015, NVIDIA Corporation.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <console/console.h>
+#include <arch/io.h>
+#include <stdint.h>
+#include <lib.h>
+#include <stdlib.h>
+#include <delay.h>
+#include <soc/addressmap.h>
+#include <device/device.h>
+#include <stdlib.h>
+#include <string.h>
+#include <cpu/cpu.h>
+#include <boot/tables.h>
+#include <cbmem.h>
+#include <soc/nvidia/tegra/dc.h>
+#include <soc/nvidia/tegra/types.h>
+#include <soc/sor.h>
+#include <soc/nvidia/tegra/displayport.h>
+#include <soc/clk_rst.h>
+#include <soc/clock.h>
+#include "chip.h"
+#include <soc/display.h>
+
+#define DEBUG_SOR 0
+
+#define APBDEV_PMC_DPD_SAMPLE				(0x20)
+#define APBDEV_PMC_DPD_SAMPLE_ON_DISABLE		(0)
+#define APBDEV_PMC_DPD_SAMPLE_ON_ENABLE			(1)
+#define APBDEV_PMC_SEL_DPD_TIM				(0x1c8)
+#define APBDEV_PMC_SEL_DPD_TIM_SEL_DPD_TIM_DEFAULT	(0x7f)
+#define APBDEV_PMC_IO_DPD2_REQ				(0x1c0)
+#define APBDEV_PMC_IO_DPD2_REQ_LVDS_SHIFT		(25)
+#define APBDEV_PMC_IO_DPD2_REQ_LVDS_OFF			(0 << 25)
+#define APBDEV_PMC_IO_DPD2_REQ_LVDS_ON			(1 << 25)
+#define APBDEV_PMC_IO_DPD2_REQ_CODE_SHIFT               (30)
+#define APBDEV_PMC_IO_DPD2_REQ_CODE_DEFAULT_MASK        (0x3 << 30)
+#define APBDEV_PMC_IO_DPD2_REQ_CODE_IDLE                (0 << 30)
+#define APBDEV_PMC_IO_DPD2_REQ_CODE_DPD_OFF             (1 << 30)
+#define APBDEV_PMC_IO_DPD2_REQ_CODE_DPD_ON              (2 << 30)
+#define APBDEV_PMC_IO_DPD2_STATUS			(0x1c4)
+#define APBDEV_PMC_IO_DPD2_STATUS_LVDS_SHIFT		(25)
+#define APBDEV_PMC_IO_DPD2_STATUS_LVDS_OFF		(0 << 25)
+#define APBDEV_PMC_IO_DPD2_STATUS_LVDS_ON		(1 << 25)
+
+#define DC_N_WINDOWS 5
+
+static inline u32 tegra_sor_readl(struct tegra_dc_sor_data *sor, u32 reg)
+{
+	void *addr = sor->base + (u32) (reg << 2);
+	u32 reg_val = READL(addr);
+	return reg_val;
+}
+
+static inline void tegra_sor_writel(struct tegra_dc_sor_data *sor,
+	u32 reg, u32 val)
+{
+	void *addr = sor->base + (u32) (reg << 2);
+	WRITEL(val, addr);
+}
+
+static inline void tegra_sor_write_field(struct tegra_dc_sor_data *sor,
+	u32 reg, u32 mask, u32 val)
+{
+	u32 reg_val = tegra_sor_readl(sor, reg);
+	reg_val &= ~mask;
+	reg_val |= val;
+	tegra_sor_writel(sor, reg, reg_val);
+}
+
+void tegra_dp_disable_tx_pu(struct tegra_dc_sor_data *sor)
+{
+	tegra_sor_write_field(sor,
+			NV_SOR_DP_PADCTL(sor->portnum),
+			NV_SOR_DP_PADCTL_TX_PU_MASK,
+			NV_SOR_DP_PADCTL_TX_PU_DISABLE);
+}
+
+void tegra_dp_set_pe_vs_pc(struct tegra_dc_sor_data *sor, u32 mask,
+			u32 pe_reg, u32 vs_reg, u32 pc_reg, u8 pc_supported)
+{
+	tegra_sor_write_field(sor, NV_SOR_PR(sor->portnum),
+					mask, pe_reg);
+	tegra_sor_write_field(sor, NV_SOR_DC(sor->portnum),
+					mask, vs_reg);
+	if (pc_supported) {
+		tegra_sor_write_field(
+				sor, NV_SOR_POSTCURSOR(sor->portnum),
+				mask, pc_reg);
+	}
+}
+
+static u32 tegra_dc_sor_poll_register(struct tegra_dc_sor_data *sor,
+	u32 reg, u32 mask, u32 exp_val, u32 poll_interval_us, u32 timeout_us)
+{
+	u32 temp = timeout_us;
+	u32 reg_val = 0;
+
+	do {
+		udelay(poll_interval_us);
+		reg_val = tegra_sor_readl(sor, reg);
+		if (timeout_us > poll_interval_us)
+			timeout_us -= poll_interval_us;
+		else
+			break;
+	} while ((reg_val & mask) != exp_val);
+
+	if ((reg_val & mask) == exp_val)
+		return 0;	/* success */
+	printk(BIOS_ERR,
+		"sor_poll_register 0x%x: timeout, "
+		"(reg_val)0x%08x & (mask)0x%08x != (exp_val)0x%08x\n",
+		reg, reg_val, mask, exp_val);
+
+	return temp;
+}
+
+int tegra_dc_sor_set_power_state(struct tegra_dc_sor_data *sor, int pu_pd)
+{
+	u32 reg_val;
+	u32 orig_val;
+
+	orig_val = tegra_sor_readl(sor, NV_SOR_PWR);
+
+	reg_val = pu_pd ? NV_SOR_PWR_NORMAL_STATE_PU :
+		NV_SOR_PWR_NORMAL_STATE_PD; /* normal state only */
+
+	if (reg_val == orig_val)
+		return 0;	/* No update needed */
+
+	reg_val |= NV_SOR_PWR_SETTING_NEW_TRIGGER;
+	tegra_sor_writel(sor, NV_SOR_PWR, reg_val);
+
+	/* Poll to confirm it is done */
+	if (tegra_dc_sor_poll_register(sor, NV_SOR_PWR,
+			NV_SOR_PWR_SETTING_NEW_DEFAULT_MASK,
+			NV_SOR_PWR_SETTING_NEW_DONE,
+			100, TEGRA_SOR_TIMEOUT_MS * 1000)) {
+		printk(BIOS_ERR,
+			"dc timeout waiting for SOR_PWR = NEW_DONE\n");
+		return -EFAULT;
+	}
+	return 0;
+}
+
+void tegra_dc_sor_set_dp_linkctl(struct tegra_dc_sor_data *sor, int ena,
+	u8 training_pattern, const struct tegra_dc_dp_link_config *link_cfg)
+{
+	u32 reg_val;
+
+	reg_val = tegra_sor_readl(sor, NV_SOR_DP_LINKCTL(sor->portnum));
+
+	if (ena)
+		reg_val |= NV_SOR_DP_LINKCTL_ENABLE_YES;
+	else
+		reg_val &= NV_SOR_DP_LINKCTL_ENABLE_NO;
+
+	reg_val &= ~NV_SOR_DP_LINKCTL_TUSIZE_MASK;
+	reg_val |= (link_cfg->tu_size << NV_SOR_DP_LINKCTL_TUSIZE_SHIFT);
+
+	if (link_cfg->enhanced_framing)
+		reg_val |= NV_SOR_DP_LINKCTL_ENHANCEDFRAME_ENABLE;
+
+	tegra_sor_writel(sor, NV_SOR_DP_LINKCTL(sor->portnum), reg_val);
+
+	switch (training_pattern) {
+	case training_pattern_1:
+		tegra_sor_writel(sor, NV_SOR_DP_TPG, 0x41414141);
+		break;
+	case training_pattern_2:
+	case training_pattern_3:
+		reg_val = (link_cfg->link_bw == SOR_LINK_SPEED_G5_4) ?
+			0x43434343 : 0x42424242;
+		tegra_sor_writel(sor, NV_SOR_DP_TPG, reg_val);
+		break;
+	default:
+		tegra_sor_writel(sor, NV_SOR_DP_TPG, 0x50505050);
+		break;
+	}
+}
+
+static int tegra_dc_sor_enable_lane_sequencer(struct tegra_dc_sor_data *sor,
+	int pu, int is_lvds)
+{
+	u32 reg_val;
+
+	/* SOR lane sequencer */
+	if (pu)
+		reg_val = NV_SOR_LANE_SEQ_CTL_SETTING_NEW_TRIGGER |
+			NV_SOR_LANE_SEQ_CTL_SEQUENCE_DOWN |
+			NV_SOR_LANE_SEQ_CTL_NEW_POWER_STATE_PU;
+	else
+		reg_val = NV_SOR_LANE_SEQ_CTL_SETTING_NEW_TRIGGER |
+			NV_SOR_LANE_SEQ_CTL_SEQUENCE_UP |
+			NV_SOR_LANE_SEQ_CTL_NEW_POWER_STATE_PD;
+
+	if (is_lvds)
+		reg_val |= 15 << NV_SOR_LANE_SEQ_CTL_DELAY_SHIFT;
+	else
+		reg_val |= 1 << NV_SOR_LANE_SEQ_CTL_DELAY_SHIFT;
+
+	tegra_sor_writel(sor, NV_SOR_LANE_SEQ_CTL, reg_val);
+
+	if (tegra_dc_sor_poll_register(sor, NV_SOR_LANE_SEQ_CTL,
+			NV_SOR_LANE_SEQ_CTL_SETTING_MASK,
+			NV_SOR_LANE_SEQ_CTL_SETTING_NEW_DONE,
+			100, TEGRA_SOR_TIMEOUT_MS*1000)) {
+		printk(BIOS_ERR,
+			"dp: timeout while waiting for SOR lane sequencer "
+			"to power down langes\n");
+		return -1;
+	}
+	return 0;
+}
+
+static int tegra_dc_sor_power_dplanes(struct tegra_dc_sor_data *sor,
+	u32 lane_count, int pu)
+{
+	u32 reg_val;
+
+	reg_val = tegra_sor_readl(sor, NV_SOR_DP_PADCTL(sor->portnum));
+
+	if (pu) {
+		switch (lane_count) {
+		case 4:
+			reg_val |= (NV_SOR_DP_PADCTL_PD_TXD_3_NO |
+				NV_SOR_DP_PADCTL_PD_TXD_2_NO);
+			/* fall through */
+		case 2:
+			reg_val |= NV_SOR_DP_PADCTL_PD_TXD_1_NO;
+		case 1:
+			reg_val |= NV_SOR_DP_PADCTL_PD_TXD_0_NO;
+			break;
+		default:
+			printk(BIOS_ERR,
+				"dp: invalid lane number %d\n", lane_count);
+			return -1;
+		}
+
+		tegra_sor_writel(sor, NV_SOR_DP_PADCTL(sor->portnum), reg_val);
+		tegra_dc_sor_set_lane_count(sor, lane_count);
+	}
+	return tegra_dc_sor_enable_lane_sequencer(sor, pu, 0);
+}
+
+void tegra_dc_sor_set_panel_power(struct tegra_dc_sor_data *sor,
+	int power_up)
+{
+	u32 reg_val;
+
+	reg_val = tegra_sor_readl(sor, NV_SOR_DP_PADCTL(sor->portnum));
+
+	if (power_up)
+		reg_val &= ~NV_SOR_DP_PADCTL_PAD_CAL_PD_POWERDOWN;
+	else
+		reg_val |= NV_SOR_DP_PADCTL_PAD_CAL_PD_POWERDOWN;
+
+	tegra_sor_writel(sor, NV_SOR_DP_PADCTL(sor->portnum), reg_val);
+}
+
+static void tegra_dc_sor_config_pwm(struct tegra_dc_sor_data *sor, u32 pwm_div,
+	u32 pwm_dutycycle)
+{
+	tegra_sor_writel(sor, NV_SOR_PWM_DIV, pwm_div);
+	tegra_sor_writel(sor, NV_SOR_PWM_CTL,
+		(pwm_dutycycle & NV_SOR_PWM_CTL_DUTY_CYCLE_MASK) |
+		NV_SOR_PWM_CTL_SETTING_NEW_TRIGGER);
+
+	if (tegra_dc_sor_poll_register(sor, NV_SOR_PWM_CTL,
+			NV_SOR_PWM_CTL_SETTING_NEW_SHIFT,
+			NV_SOR_PWM_CTL_SETTING_NEW_DONE,
+			100, TEGRA_SOR_TIMEOUT_MS * 1000)) {
+		printk(BIOS_ERR,
+			"dp: timeout while waiting for SOR PWM setting\n");
+	}
+}
+
+static void tegra_dc_sor_set_dp_mode(struct tegra_dc_sor_data *sor,
+	const struct tegra_dc_dp_link_config *link_cfg)
+{
+	u32 reg_val;
+
+	tegra_dc_sor_set_link_bandwidth(sor, link_cfg->link_bw);
+
+	tegra_dc_sor_set_dp_linkctl(sor, 1, training_pattern_none, link_cfg);
+	reg_val = tegra_sor_readl(sor, NV_SOR_DP_CONFIG(sor->portnum));
+	reg_val &= ~NV_SOR_DP_CONFIG_WATERMARK_MASK;
+	reg_val |= link_cfg->watermark;
+	reg_val &= ~NV_SOR_DP_CONFIG_ACTIVESYM_COUNT_MASK;
+	reg_val |= (link_cfg->active_count <<
+		NV_SOR_DP_CONFIG_ACTIVESYM_COUNT_SHIFT);
+	reg_val &= ~NV_SOR_DP_CONFIG_ACTIVESYM_FRAC_MASK;
+	reg_val |= (link_cfg->active_frac <<
+		NV_SOR_DP_CONFIG_ACTIVESYM_FRAC_SHIFT);
+	if (link_cfg->activepolarity)
+		reg_val |= NV_SOR_DP_CONFIG_ACTIVESYM_POLARITY_POSITIVE;
+	else
+		reg_val &= ~NV_SOR_DP_CONFIG_ACTIVESYM_POLARITY_POSITIVE;
+	reg_val |= (NV_SOR_DP_CONFIG_ACTIVESYM_CNTL_ENABLE |
+		NV_SOR_DP_CONFIG_RD_RESET_VAL_NEGATIVE);
+
+	tegra_sor_writel(sor, NV_SOR_DP_CONFIG(sor->portnum), reg_val);
+
+	/* program h/vblank sym */
+	tegra_sor_write_field(sor, NV_SOR_DP_AUDIO_HBLANK_SYMBOLS,
+		NV_SOR_DP_AUDIO_HBLANK_SYMBOLS_MASK, link_cfg->hblank_sym);
+
+	tegra_sor_write_field(sor, NV_SOR_DP_AUDIO_VBLANK_SYMBOLS,
+		NV_SOR_DP_AUDIO_VBLANK_SYMBOLS_MASK, link_cfg->vblank_sym);
+}
+
+static inline void tegra_dc_sor_super_update(struct tegra_dc_sor_data *sor)
+{
+	tegra_sor_writel(sor, NV_SOR_SUPER_STATE0, 0);
+	tegra_sor_writel(sor, NV_SOR_SUPER_STATE0, 1);
+	tegra_sor_writel(sor, NV_SOR_SUPER_STATE0, 0);
+}
+
+static inline void tegra_dc_sor_update(struct tegra_dc_sor_data *sor)
+{
+	tegra_sor_writel(sor, NV_SOR_STATE0, 0);
+	tegra_sor_writel(sor, NV_SOR_STATE0, 1);
+	tegra_sor_writel(sor, NV_SOR_STATE0, 0);
+}
+
+static void tegra_dc_sor_io_set_dpd(struct tegra_dc_sor_data *sor, int up)
+{
+	u32 reg_val;
+	void *pmc_base = sor->pmc_base;
+
+	if (up) {
+		WRITEL(APBDEV_PMC_DPD_SAMPLE_ON_ENABLE,
+			pmc_base + APBDEV_PMC_DPD_SAMPLE);
+		WRITEL(10, pmc_base + APBDEV_PMC_SEL_DPD_TIM);
+	}
+
+	reg_val = READL(pmc_base + APBDEV_PMC_IO_DPD2_REQ);
+	reg_val &= ~(APBDEV_PMC_IO_DPD2_REQ_LVDS_ON ||
+		APBDEV_PMC_IO_DPD2_REQ_CODE_DEFAULT_MASK);
+
+	reg_val = up ? APBDEV_PMC_IO_DPD2_REQ_LVDS_ON |
+		APBDEV_PMC_IO_DPD2_REQ_CODE_DPD_OFF :
+		APBDEV_PMC_IO_DPD2_REQ_LVDS_OFF |
+		APBDEV_PMC_IO_DPD2_REQ_CODE_DPD_ON;
+
+	WRITEL(reg_val, pmc_base + APBDEV_PMC_IO_DPD2_REQ);
+
+	/* Polling */
+	u32 temp = 10*1000;
+	do {
+		udelay(20);
+		reg_val = READL(pmc_base + APBDEV_PMC_IO_DPD2_STATUS);
+		if (temp > 20)
+			temp -= 20;
+		else
+			break;
+	} while ((reg_val & APBDEV_PMC_IO_DPD2_STATUS_LVDS_ON) != 0);
+
+	if ((reg_val & APBDEV_PMC_IO_DPD2_STATUS_LVDS_ON) != 0)
+		printk(BIOS_ERR,
+			"PMC_IO_DPD2 polling failed (0x%x)\n", reg_val);
+
+	if (up)
+		WRITEL(APBDEV_PMC_DPD_SAMPLE_ON_DISABLE,
+			pmc_base + APBDEV_PMC_DPD_SAMPLE);
+}
+
+void tegra_dc_sor_set_internal_panel(struct tegra_dc_sor_data *sor, int is_int)
+{
+	u32 reg_val;
+
+	reg_val = tegra_sor_readl(sor, NV_SOR_DP_SPARE(sor->portnum));
+	if (is_int)
+		reg_val |= NV_SOR_DP_SPARE_PANEL_INTERNAL;
+	else
+		reg_val &= ~NV_SOR_DP_SPARE_PANEL_INTERNAL;
+
+	reg_val |= NV_SOR_DP_SPARE_SOR_CLK_SEL_MACRO_SORCLK |
+		NV_SOR_DP_SPARE_SEQ_ENABLE_YES;
+	tegra_sor_writel(sor, NV_SOR_DP_SPARE(sor->portnum), reg_val);
+}
+
+void tegra_dc_sor_read_link_config(struct tegra_dc_sor_data *sor, u8 *link_bw,
+				   u8 *lane_count)
+{
+	u32 reg_val;
+
+	reg_val = tegra_sor_readl(sor, NV_SOR_CLK_CNTRL);
+	*link_bw = (reg_val & NV_SOR_CLK_CNTRL_DP_LINK_SPEED_MASK)
+		>> NV_SOR_CLK_CNTRL_DP_LINK_SPEED_SHIFT;
+	reg_val = tegra_sor_readl(sor,
+		NV_SOR_DP_LINKCTL(sor->portnum));
+
+	switch (reg_val & NV_SOR_DP_LINKCTL_LANECOUNT_MASK) {
+	case NV_SOR_DP_LINKCTL_LANECOUNT_ZERO:
+		*lane_count = 0;
+		break;
+	case NV_SOR_DP_LINKCTL_LANECOUNT_ONE:
+		*lane_count = 1;
+		break;
+	case NV_SOR_DP_LINKCTL_LANECOUNT_TWO:
+		*lane_count = 2;
+		break;
+	case NV_SOR_DP_LINKCTL_LANECOUNT_FOUR:
+		*lane_count = 4;
+		break;
+	default:
+		printk(BIOS_ERR, "Unknown lane count\n");
+	}
+}
+
+void tegra_dc_sor_set_link_bandwidth(struct tegra_dc_sor_data *sor, u8 link_bw)
+{
+	tegra_sor_write_field(sor, NV_SOR_CLK_CNTRL,
+		NV_SOR_CLK_CNTRL_DP_LINK_SPEED_MASK,
+		link_bw << NV_SOR_CLK_CNTRL_DP_LINK_SPEED_SHIFT);
+}
+
+void tegra_dc_sor_set_lane_count(struct tegra_dc_sor_data *sor, u8 lane_count)
+{
+	u32 reg_val;
+
+	reg_val = tegra_sor_readl(sor, NV_SOR_DP_LINKCTL(sor->portnum));
+	reg_val &= ~NV_SOR_DP_LINKCTL_LANECOUNT_MASK;
+	switch (lane_count) {
+	case 0:
+		break;
+	case 1:
+		reg_val |= NV_SOR_DP_LINKCTL_LANECOUNT_ONE;
+		break;
+	case 2:
+		reg_val |= NV_SOR_DP_LINKCTL_LANECOUNT_TWO;
+		break;
+	case 4:
+		reg_val |= NV_SOR_DP_LINKCTL_LANECOUNT_FOUR;
+		break;
+	default:
+		/* 0 should be handled earlier. */
+		printk(BIOS_ERR, "dp: Invalid lane count %d\n",
+			lane_count);
+		return;
+	}
+	tegra_sor_writel(sor, NV_SOR_DP_LINKCTL(sor->portnum), reg_val);
+}
+
+static void tegra_sor_enable_edp_clock(struct tegra_dc_sor_data *sor)
+{
+	sor_clock_start();
+}
+
+/* The SOR power sequencer does not work for t1xx so SW has to
+   go through the power sequence manually */
+/* Power up steps from spec: */
+/* STEP	PDPORT	PDPLL	PDBG	PLLVCOD	PLLCAPD	E_DPD	PDCAL */
+/* 1	1	1	1	1	1	1	1 */
+/* 2	1	1	1	1	1	0	1 */
+/* 3	1	1	0	1	1	0	1 */
+/* 4	1	0	0	0	0	0	1 */
+/* 5	0	0	0	0	0	0	1 */
+static void tegra_dc_sor_power_up(struct tegra_dc_sor_data *sor,
+				int is_lvds)
+{
+	if (sor->power_is_up)
+		return;
+
+	/* Set link bw */
+	tegra_dc_sor_set_link_bandwidth(sor,
+		is_lvds ? NV_SOR_CLK_CNTRL_DP_LINK_SPEED_LVDS :
+		NV_SOR_CLK_CNTRL_DP_LINK_SPEED_G1_62);
+
+	/* step 1 */
+	tegra_sor_write_field(sor, NV_SOR_PLL2,
+		NV_SOR_PLL2_AUX7_PORT_POWERDOWN_MASK | /* PDPORT */
+		NV_SOR_PLL2_AUX6_BANDGAP_POWERDOWN_MASK | /* PDBG */
+		NV_SOR_PLL2_AUX8_SEQ_PLLCAPPD_ENFORCE_MASK, /* PLLCAPD */
+		NV_SOR_PLL2_AUX7_PORT_POWERDOWN_ENABLE |
+		NV_SOR_PLL2_AUX6_BANDGAP_POWERDOWN_ENABLE |
+		NV_SOR_PLL2_AUX8_SEQ_PLLCAPPD_ENFORCE_ENABLE);
+	tegra_sor_write_field(sor, NV_SOR_PLL0,
+		NV_SOR_PLL0_PWR_MASK | /* PDPLL */
+		NV_SOR_PLL0_VCOPD_MASK, /* PLLVCOPD */
+		NV_SOR_PLL0_PWR_OFF |
+		NV_SOR_PLL0_VCOPD_ASSERT);
+	tegra_sor_write_field(sor, NV_SOR_DP_PADCTL(sor->portnum),
+		NV_SOR_DP_PADCTL_PAD_CAL_PD_POWERDOWN, /* PDCAL */
+		NV_SOR_DP_PADCTL_PAD_CAL_PD_POWERUP);
+
+	/* step 2 */
+	tegra_dc_sor_io_set_dpd(sor, 1);
+	udelay(15);
+
+	/* step 3 */
+	tegra_sor_write_field(sor, NV_SOR_PLL2,
+		NV_SOR_PLL2_AUX6_BANDGAP_POWERDOWN_MASK,
+		NV_SOR_PLL2_AUX6_BANDGAP_POWERDOWN_DISABLE);
+	udelay(25);
+
+	/* step 4 */
+	tegra_sor_write_field(sor, NV_SOR_PLL0,
+		NV_SOR_PLL0_PWR_MASK | /* PDPLL */
+		NV_SOR_PLL0_VCOPD_MASK, /* PLLVCOPD */
+		NV_SOR_PLL0_PWR_ON | NV_SOR_PLL0_VCOPD_RESCIND);
+	tegra_sor_write_field(sor, NV_SOR_PLL2,
+		NV_SOR_PLL2_AUX8_SEQ_PLLCAPPD_ENFORCE_MASK, /* PLLCAPD */
+		NV_SOR_PLL2_AUX8_SEQ_PLLCAPPD_ENFORCE_DISABLE);
+	udelay(225);
+
+	/* step 5 */
+	tegra_sor_write_field(sor, NV_SOR_PLL2,
+		NV_SOR_PLL2_AUX7_PORT_POWERDOWN_MASK, /* PDPORT */
+		NV_SOR_PLL2_AUX7_PORT_POWERDOWN_DISABLE);
+
+	sor->power_is_up = 1;
+}
+
+#if DEBUG_SOR
+static void dump_sor_reg(struct tegra_dc_sor_data *sor)
+{
+#define DUMP_REG(a) printk(BIOS_INFO, "%-32s  %03x  %08x\n",		\
+		#a, a, tegra_sor_readl(sor, a));
+
+	DUMP_REG(NV_SOR_SUPER_STATE0);
+	DUMP_REG(NV_SOR_SUPER_STATE1);
+	DUMP_REG(NV_SOR_STATE0);
+	DUMP_REG(NV_SOR_STATE1);
+	DUMP_REG(NV_HEAD_STATE0(0));
+	DUMP_REG(NV_HEAD_STATE0(1));
+	DUMP_REG(NV_HEAD_STATE1(0));
+	DUMP_REG(NV_HEAD_STATE1(1));
+	DUMP_REG(NV_HEAD_STATE2(0));
+	DUMP_REG(NV_HEAD_STATE2(1));
+	DUMP_REG(NV_HEAD_STATE3(0));
+	DUMP_REG(NV_HEAD_STATE3(1));
+	DUMP_REG(NV_HEAD_STATE4(0));
+	DUMP_REG(NV_HEAD_STATE4(1));
+	DUMP_REG(NV_HEAD_STATE5(0));
+	DUMP_REG(NV_HEAD_STATE5(1));
+	DUMP_REG(NV_SOR_CRC_CNTRL);
+	DUMP_REG(NV_SOR_CLK_CNTRL);
+	DUMP_REG(NV_SOR_CAP);
+	DUMP_REG(NV_SOR_PWR);
+	DUMP_REG(NV_SOR_TEST);
+	DUMP_REG(NV_SOR_PLL0);
+	DUMP_REG(NV_SOR_PLL1);
+	DUMP_REG(NV_SOR_PLL2);
+	DUMP_REG(NV_SOR_PLL3);
+	DUMP_REG(NV_SOR_CSTM);
+	DUMP_REG(NV_SOR_LVDS);
+	DUMP_REG(NV_SOR_CRCA);
+	DUMP_REG(NV_SOR_CRCB);
+	DUMP_REG(NV_SOR_SEQ_CTL);
+	DUMP_REG(NV_SOR_LANE_SEQ_CTL);
+	DUMP_REG(NV_SOR_SEQ_INST(0));
+	DUMP_REG(NV_SOR_SEQ_INST(1));
+	DUMP_REG(NV_SOR_SEQ_INST(2));
+	DUMP_REG(NV_SOR_SEQ_INST(3));
+	DUMP_REG(NV_SOR_SEQ_INST(4));
+	DUMP_REG(NV_SOR_SEQ_INST(5));
+	DUMP_REG(NV_SOR_SEQ_INST(6));
+	DUMP_REG(NV_SOR_SEQ_INST(7));
+	DUMP_REG(NV_SOR_SEQ_INST(8));
+	DUMP_REG(NV_SOR_PWM_DIV);
+	DUMP_REG(NV_SOR_PWM_CTL);
+	DUMP_REG(NV_SOR_MSCHECK);
+	DUMP_REG(NV_SOR_XBAR_CTRL);
+	DUMP_REG(NV_SOR_DP_LINKCTL(0));
+	DUMP_REG(NV_SOR_DP_LINKCTL(1));
+	DUMP_REG(NV_SOR_DC(0));
+	DUMP_REG(NV_SOR_DC(1));
+	DUMP_REG(NV_SOR_LANE_DRIVE_CURRENT(0));
+	DUMP_REG(NV_SOR_PR(0));
+	DUMP_REG(NV_SOR_LANE4_PREEMPHASIS(0));
+	DUMP_REG(NV_SOR_POSTCURSOR(0));
+	DUMP_REG(NV_SOR_DP_CONFIG(0));
+	DUMP_REG(NV_SOR_DP_CONFIG(1));
+	DUMP_REG(NV_SOR_DP_MN(0));
+	DUMP_REG(NV_SOR_DP_MN(1));
+	DUMP_REG(NV_SOR_DP_PADCTL(0));
+	DUMP_REG(NV_SOR_DP_PADCTL(1));
+	DUMP_REG(NV_SOR_DP_DEBUG(0));
+	DUMP_REG(NV_SOR_DP_DEBUG(1));
+	DUMP_REG(NV_SOR_DP_SPARE(0));
+	DUMP_REG(NV_SOR_DP_SPARE(1));
+	DUMP_REG(NV_SOR_DP_TPG);
+
+	return;
+}
+#endif
+
+static void tegra_dc_sor_config_panel(struct tegra_dc_sor_data *sor,
+	int is_lvds)
+{
+	const struct tegra_dc *dc = sor->dc;
+	const struct tegra_dc_dp_data *dp = dc->out;
+	const struct tegra_dc_dp_link_config *link_cfg = &dp->link_cfg;
+	const struct soc_nvidia_tegra210_config *config = dc->config;
+
+	const int	head_num = 0;
+	u32		reg_val	 = NV_SOR_STATE1_ASY_OWNER_HEAD0 << head_num;
+	u32		vsync_end, hsync_end;
+	u32		vblank_end, hblank_end;
+	u32		vblank_start, hblank_start;
+
+	reg_val |= is_lvds ? NV_SOR_STATE1_ASY_PROTOCOL_LVDS_CUSTOM :
+		NV_SOR_STATE1_ASY_PROTOCOL_DP_A;
+	reg_val |= NV_SOR_STATE1_ASY_SUBOWNER_NONE |
+		NV_SOR_STATE1_ASY_CRCMODE_COMPLETE_RASTER;
+
+	reg_val |= NV_SOR_STATE1_ASY_HSYNCPOL_NEGATIVE_TRUE;
+	reg_val |= NV_SOR_STATE1_ASY_VSYNCPOL_NEGATIVE_TRUE;
+	reg_val |= (link_cfg->bits_per_pixel > 18) ?
+		NV_SOR_STATE1_ASY_PIXELDEPTH_BPP_24_444 :
+		NV_SOR_STATE1_ASY_PIXELDEPTH_BPP_18_444;
+
+	tegra_sor_writel(sor, NV_SOR_STATE1, reg_val);
+
+	/* Skipping programming NV_HEAD_STATE0, assuming:
+	   interlacing: PROGRESSIVE, dynamic range: VESA, colorspace: RGB */
+
+	tegra_sor_writel(sor, NV_HEAD_STATE1(head_num),
+		vtotal(config) << NV_HEAD_STATE1_VTOTAL_SHIFT |
+		htotal(config) << NV_HEAD_STATE1_HTOTAL_SHIFT);
+
+	vsync_end = config->vsync_width - 1;
+	hsync_end = config->hsync_width - 1;
+	tegra_sor_writel(sor, NV_HEAD_STATE2(head_num),
+		vsync_end << NV_HEAD_STATE2_VSYNC_END_SHIFT |
+		hsync_end << NV_HEAD_STATE2_HSYNC_END_SHIFT);
+
+	vblank_end = vsync_end + config->vback_porch;
+	hblank_end = hsync_end + config->hback_porch;
+	tegra_sor_writel(sor, NV_HEAD_STATE3(head_num),
+		vblank_end << NV_HEAD_STATE3_VBLANK_END_SHIFT |
+		hblank_end << NV_HEAD_STATE3_HBLANK_END_SHIFT);
+
+	vblank_start = vblank_end + config->yres;
+	hblank_start = hblank_end + config->xres;
+	tegra_sor_writel(sor, NV_HEAD_STATE4(head_num),
+		vblank_start << NV_HEAD_STATE4_VBLANK_START_SHIFT |
+		hblank_start << NV_HEAD_STATE4_HBLANK_START_SHIFT);
+
+	/* TODO: adding interlace mode support */
+	tegra_sor_writel(sor, NV_HEAD_STATE5(head_num), 0x1);
+
+	tegra_sor_write_field(sor, NV_SOR_CSTM,
+		NV_SOR_CSTM_ROTCLK_DEFAULT_MASK |
+		NV_SOR_CSTM_LVDS_EN_ENABLE,
+		2 << NV_SOR_CSTM_ROTCLK_SHIFT |
+		is_lvds ? NV_SOR_CSTM_LVDS_EN_ENABLE :
+		NV_SOR_CSTM_LVDS_EN_DISABLE);
+
+	 tegra_dc_sor_config_pwm(sor, 1024, 1024);
+}
+
+static void tegra_dc_sor_enable_dc(struct tegra_dc_sor_data *sor)
+{
+	struct tegra_dc		*dc   = sor->dc;
+	struct display_controller *disp_ctrl = (void *)dc->base;
+
+	u32	reg_val = READL(&disp_ctrl->cmd.state_access);
+
+	WRITEL(reg_val | WRITE_MUX_ACTIVE, &disp_ctrl->cmd.state_access);
+	WRITEL(VSYNC_H_POSITION(1), &disp_ctrl->disp.disp_timing_opt);
+
+	/* Enable DC now - otherwise pure text console may not show. */
+	WRITEL(DISP_CTRL_MODE_C_DISPLAY, &disp_ctrl->cmd.disp_cmd);
+	WRITEL(reg_val, &disp_ctrl->cmd.state_access);
+}
+
+void tegra_dc_sor_enable_dp(struct tegra_dc_sor_data *sor)
+{
+	const struct tegra_dc_dp_link_config *link_cfg = sor->link_cfg;
+
+	tegra_sor_write_field(sor, NV_SOR_CLK_CNTRL,
+		NV_SOR_CLK_CNTRL_DP_CLK_SEL_MASK,
+		NV_SOR_CLK_CNTRL_DP_CLK_SEL_SINGLE_DPCLK);
+
+	tegra_sor_write_field(sor, NV_SOR_PLL2,
+		NV_SOR_PLL2_AUX6_BANDGAP_POWERDOWN_MASK,
+		NV_SOR_PLL2_AUX6_BANDGAP_POWERDOWN_DISABLE);
+	udelay(25);
+
+	tegra_sor_write_field(sor, NV_SOR_PLL3,
+		NV_SOR_PLL3_PLLVDD_MODE_MASK,
+		NV_SOR_PLL3_PLLVDD_MODE_V3_3);
+	tegra_sor_writel(sor, NV_SOR_PLL0,
+		0xf << NV_SOR_PLL0_ICHPMP_SHFIT |
+		0x3 << NV_SOR_PLL0_VCOCAP_SHIFT |
+		NV_SOR_PLL0_PLLREG_LEVEL_V45 |
+		NV_SOR_PLL0_RESISTORSEL_EXT |
+		NV_SOR_PLL0_PWR_ON | NV_SOR_PLL0_VCOPD_RESCIND);
+	tegra_sor_write_field(sor, NV_SOR_PLL2,
+		NV_SOR_PLL2_AUX1_SEQ_MASK | NV_SOR_PLL2_AUX9_LVDSEN_OVERRIDE |
+		NV_SOR_PLL2_AUX8_SEQ_PLLCAPPD_ENFORCE_MASK,
+		NV_SOR_PLL2_AUX1_SEQ_PLLCAPPD_OVERRIDE |
+		NV_SOR_PLL2_AUX9_LVDSEN_OVERRIDE |
+		NV_SOR_PLL2_AUX8_SEQ_PLLCAPPD_ENFORCE_DISABLE);
+	tegra_sor_writel(sor, NV_SOR_PLL1,
+		NV_SOR_PLL1_TERM_COMPOUT_HIGH | NV_SOR_PLL1_TMDS_TERM_ENABLE);
+
+	if (tegra_dc_sor_poll_register(sor, NV_SOR_PLL2,
+			NV_SOR_PLL2_AUX8_SEQ_PLLCAPPD_ENFORCE_MASK,
+			NV_SOR_PLL2_AUX8_SEQ_PLLCAPPD_ENFORCE_DISABLE,
+			100, TEGRA_SOR_TIMEOUT_MS * 1000)) {
+		printk(BIOS_ERR, "DP failed to lock PLL\n");
+		return;
+	}
+
+	tegra_sor_write_field(sor, NV_SOR_PLL2,
+		NV_SOR_PLL2_AUX2_MASK | NV_SOR_PLL2_AUX7_PORT_POWERDOWN_MASK,
+		NV_SOR_PLL2_AUX2_OVERRIDE_POWERDOWN |
+		NV_SOR_PLL2_AUX7_PORT_POWERDOWN_DISABLE);
+
+	tegra_dc_sor_power_up(sor, 0);
+
+	/* re-enable SOR clock */
+	tegra_sor_enable_edp_clock(sor); /* select pll_dp as clock source */
+
+	/* Power up lanes */
+	tegra_dc_sor_power_dplanes(sor, link_cfg->lane_count, 1);
+
+	tegra_dc_sor_set_dp_mode(sor, link_cfg);
+
+}
+
+void tegra_dc_sor_attach(struct tegra_dc_sor_data *sor)
+{
+	u32 reg_val;
+	struct display_controller *disp_ctrl = (void *)sor->dc->base;
+
+	tegra_dc_sor_enable_dc(sor);
+	tegra_dc_sor_config_panel(sor, 0);
+
+	WRITEL(0x9f00, &disp_ctrl->cmd.state_ctrl);
+	WRITEL(0x9f, &disp_ctrl->cmd.state_ctrl);
+
+	WRITEL(PW0_ENABLE | PW1_ENABLE | PW2_ENABLE |
+		PW3_ENABLE | PW4_ENABLE | PM0_ENABLE | PM1_ENABLE,
+		&disp_ctrl->cmd.disp_pow_ctrl);
+
+	reg_val = tegra_sor_readl(sor, NV_SOR_TEST);
+	if (reg_val & NV_SOR_TEST_ATTACHED_TRUE)
+		return;
+
+	tegra_sor_writel(sor, NV_SOR_SUPER_STATE1,
+			NV_SOR_SUPER_STATE1_ATTACHED_NO);
+
+	/*
+	 * Enable display2sor clock at least 2 cycles before DC start,
+	 * to clear sor internal valid signal.
+	 */
+
+	/* Stop dc for 3 cycles */
+	WRITEL(0, &disp_ctrl->disp.disp_win_opt);
+	WRITEL(GENERAL_ACT_REQ, &disp_ctrl->cmd.state_ctrl);
+	udelay(FRAME_IN_MS * 1000 * 3);
+
+	/* Attach head */
+	tegra_dc_sor_update(sor);
+	tegra_sor_writel(sor, NV_SOR_SUPER_STATE1,
+			NV_SOR_SUPER_STATE1_ATTACHED_YES);
+	tegra_sor_writel(sor, NV_SOR_SUPER_STATE1,
+		NV_SOR_SUPER_STATE1_ATTACHED_YES |
+		NV_SOR_SUPER_STATE1_ASY_HEAD_OP_AWAKE |
+		NV_SOR_SUPER_STATE1_ASY_ORMODE_NORMAL);
+	tegra_dc_sor_super_update(sor);
+
+	/* wait for another 5 cycles */
+	udelay(FRAME_IN_MS * 1000 * 5);
+
+	/* Re-enable dc */
+	WRITEL(READ_MUX_ACTIVE | WRITE_MUX_ACTIVE,
+		&disp_ctrl->cmd.state_access);
+	WRITEL(SOR_ENABLE, &disp_ctrl->disp.disp_win_opt);
+
+	WRITEL(DISP_CTRL_MODE_C_DISPLAY, &disp_ctrl->cmd.disp_cmd);
+	WRITEL(GENERAL_ACT_REQ, &disp_ctrl->cmd.state_ctrl);
+
+	if (tegra_dc_sor_poll_register(sor, NV_SOR_TEST,
+			NV_SOR_TEST_ACT_HEAD_OPMODE_DEFAULT_MASK,
+			NV_SOR_TEST_ACT_HEAD_OPMODE_AWAKE,
+			100, TEGRA_SOR_ATTACH_TIMEOUT_MS * 1000))
+		printk(BIOS_ERR, "dc timeout waiting for OPMOD = AWAKE\n");
+	else
+		printk(BIOS_INFO, "%s: sor is attached\n", __func__);
+
+#if DEBUG_SOR
+	dump_sor_reg(sor);
+#endif
+}
+
+void tegra_dc_sor_set_lane_parm(struct tegra_dc_sor_data *sor,
+	const struct tegra_dc_dp_link_config *link_cfg)
+{
+	tegra_sor_writel(sor, NV_SOR_LANE_DRIVE_CURRENT(sor->portnum),
+		link_cfg->drive_current);
+	tegra_sor_writel(sor, NV_SOR_PR(sor->portnum),
+		link_cfg->preemphasis);
+	tegra_sor_writel(sor, NV_SOR_POSTCURSOR(sor->portnum),
+		link_cfg->postcursor);
+	tegra_sor_writel(sor, NV_SOR_LVDS, 0);
+
+	tegra_dc_sor_set_link_bandwidth(sor, link_cfg->link_bw);
+	tegra_dc_sor_set_lane_count(sor, link_cfg->lane_count);
+
+	tegra_sor_write_field(sor, NV_SOR_DP_PADCTL(sor->portnum),
+		NV_SOR_DP_PADCTL_TX_PU_ENABLE |
+		NV_SOR_DP_PADCTL_TX_PU_VALUE_DEFAULT_MASK,
+		NV_SOR_DP_PADCTL_TX_PU_ENABLE |
+		2 << NV_SOR_DP_PADCTL_TX_PU_VALUE_SHIFT);
+
+	/* Precharge */
+	tegra_sor_write_field(sor, NV_SOR_DP_PADCTL(sor->portnum),
+				0xf0, 0xf0);
+	udelay(20);
+
+	tegra_sor_write_field(sor, NV_SOR_DP_PADCTL(sor->portnum),
+				0xf0, 0x0);
+}
+
+void tegra_dc_sor_set_voltage_swing(struct tegra_dc_sor_data *sor)
+{
+	u32 drive_current = 0;
+	u32 pre_emphasis = 0;
+
+	/* Set to a known-good pre-calibrated setting */
+	switch (sor->link_cfg->link_bw) {
+	case SOR_LINK_SPEED_G1_62:
+	case SOR_LINK_SPEED_G2_7:
+		drive_current = 0x13131313;
+		pre_emphasis = 0;
+		break;
+	case SOR_LINK_SPEED_G5_4:
+		printk(BIOS_WARNING, "T1xx does not support 5.4G link"
+			" clock.\n");
+	default:
+		printk(BIOS_WARNING, "Invalid sor link bandwidth: %d\n",
+			sor->link_cfg->link_bw);
+		return;
+	}
+
+	tegra_sor_writel(sor, NV_SOR_LANE_DRIVE_CURRENT(sor->portnum),
+				drive_current);
+	tegra_sor_writel(sor, NV_SOR_PR(sor->portnum), pre_emphasis);
+}
+
+void tegra_dc_sor_power_down_unused_lanes(struct tegra_dc_sor_data *sor)
+{
+	u32 pad_ctrl = 0;
+	int err = 0;
+
+	switch (sor->link_cfg->lane_count) {
+	case 4:
+		pad_ctrl = (NV_SOR_DP_PADCTL_PD_TXD_0_NO |
+			NV_SOR_DP_PADCTL_PD_TXD_1_NO |
+			NV_SOR_DP_PADCTL_PD_TXD_2_NO |
+			NV_SOR_DP_PADCTL_PD_TXD_3_NO);
+		break;
+	case 2:
+		pad_ctrl = (NV_SOR_DP_PADCTL_PD_TXD_0_NO |
+			NV_SOR_DP_PADCTL_PD_TXD_1_NO |
+			NV_SOR_DP_PADCTL_PD_TXD_2_YES |
+			NV_SOR_DP_PADCTL_PD_TXD_3_YES);
+		break;
+	case 1:
+		pad_ctrl = (NV_SOR_DP_PADCTL_PD_TXD_0_NO |
+			NV_SOR_DP_PADCTL_PD_TXD_1_YES |
+			NV_SOR_DP_PADCTL_PD_TXD_2_YES |
+			NV_SOR_DP_PADCTL_PD_TXD_3_YES);
+		break;
+	default:
+		printk(BIOS_ERR, "Invalid sor lane count: %u\n",
+			sor->link_cfg->lane_count);
+		return;
+	}
+
+	pad_ctrl |= NV_SOR_DP_PADCTL_PAD_CAL_PD_POWERDOWN;
+	tegra_sor_writel(sor, NV_SOR_DP_PADCTL(sor->portnum), pad_ctrl);
+
+	err = tegra_dc_sor_enable_lane_sequencer(sor, 0, 0);
+	if (err) {
+		printk(BIOS_ERR,
+			"Wait for lane power down failed: %d\n", err);
+		return;
+	}
+}
+
+void tegra_sor_precharge_lanes(struct tegra_dc_sor_data *sor)
+{
+	const struct tegra_dc_dp_link_config *cfg = sor->link_cfg;
+	u32 val = 0;
+
+	switch (cfg->lane_count) {
+	case 4:
+		val |= (NV_SOR_DP_PADCTL_PD_TXD_3_NO |
+			NV_SOR_DP_PADCTL_PD_TXD_2_NO);
+		/* fall through */
+	case 2:
+		val |= NV_SOR_DP_PADCTL_PD_TXD_1_NO;
+		/* fall through */
+	case 1:
+		val |= NV_SOR_DP_PADCTL_PD_TXD_0_NO;
+		break;
+	default:
+		printk(BIOS_ERR,
+			"dp: invalid lane number %d\n", cfg->lane_count);
+		return;
+	}
+
+	tegra_sor_write_field(sor, NV_SOR_DP_PADCTL(sor->portnum),
+		(0xf << NV_SOR_DP_PADCTL_COMODE_TXD_0_DP_TXD_2_SHIFT),
+		(val << NV_SOR_DP_PADCTL_COMODE_TXD_0_DP_TXD_2_SHIFT));
+	udelay(100);
+	tegra_sor_write_field(sor, NV_SOR_DP_PADCTL(sor->portnum),
+		(0xf << NV_SOR_DP_PADCTL_COMODE_TXD_0_DP_TXD_2_SHIFT), 0);
+}
+
+static u32 tegra_dc_poll_register(void *reg,
+	u32 mask, u32 exp_val, u32 poll_interval_us, u32 timeout_us)
+{
+	u32 temp = timeout_us;
+	u32 reg_val = 0;
+
+	do {
+		udelay(poll_interval_us);
+		reg_val = READL(reg);
+		if (timeout_us > poll_interval_us)
+			timeout_us -= poll_interval_us;
+		else
+			break;
+	} while ((reg_val & mask) != exp_val);
+
+	if ((reg_val & mask) == exp_val)
+		return 0;	/* success */
+
+	return temp;
+}
+
+static void tegra_dc_sor_general_act(struct display_controller *disp_ctrl)
+{
+	WRITEL(GENERAL_ACT_REQ, &disp_ctrl->cmd.state_ctrl);
+
+	if (tegra_dc_poll_register(&disp_ctrl->cmd.state_ctrl,
+		GENERAL_ACT_REQ, 0, 100,
+		TEGRA_DC_POLL_TIMEOUT_MS*1000))
+		printk(BIOS_ERR,
+			"dc timeout waiting for DC to stop\n");
+}
+
+static struct tegra_dc_mode min_mode = {
+	.h_ref_to_sync = 0,
+	.v_ref_to_sync = 1,
+	.h_sync_width = 1,
+	.v_sync_width = 1,
+	.h_back_porch = 20,
+	.v_back_porch = 0,
+	.h_active = 16,
+	.v_active = 16,
+	.h_front_porch = 1,
+	.v_front_porch = 2,
+};
+
+/* Disable windows and set minimum raster timings */
+static void
+tegra_dc_sor_disable_win_short_raster(struct display_controller *disp_ctrl,
+					int *dc_reg_ctx)
+{
+	int selected_windows, i;
+
+	selected_windows = READL(&disp_ctrl->cmd.disp_win_header);
+
+	/* Store and clear window options */
+	for (i = 0; i < DC_N_WINDOWS; ++i) {
+		WRITEL(WINDOW_A_SELECT << i, &disp_ctrl->cmd.disp_win_header);
+		dc_reg_ctx[i] = READL(&disp_ctrl->win.win_opt);
+		WRITEL(0, &disp_ctrl->win.win_opt);
+		WRITEL(WIN_A_ACT_REQ << i, &disp_ctrl->cmd.state_ctrl);
+	}
+
+	WRITEL(selected_windows, &disp_ctrl->cmd.disp_win_header);
+
+	/* Store current raster timings and set minimum timings */
+	dc_reg_ctx[i++] = READL(&disp_ctrl->disp.ref_to_sync);
+	WRITEL(min_mode.h_ref_to_sync | (min_mode.v_ref_to_sync << 16),
+		&disp_ctrl->disp.ref_to_sync);
+
+	dc_reg_ctx[i++] = READL(&disp_ctrl->disp.sync_width);
+	WRITEL(min_mode.h_sync_width | (min_mode.v_sync_width << 16),
+		&disp_ctrl->disp.sync_width);
+
+	dc_reg_ctx[i++] = READL(&disp_ctrl->disp.back_porch);
+	WRITEL(min_mode.h_back_porch |
+		min_mode.v_back_porch << 16,
+		&disp_ctrl->disp.back_porch);
+
+	dc_reg_ctx[i++] = READL(&disp_ctrl->disp.front_porch);
+	WRITEL(min_mode.h_front_porch |
+		min_mode.v_front_porch << 16,
+		&disp_ctrl->disp.front_porch);
+
+	dc_reg_ctx[i++] = READL(&disp_ctrl->disp.disp_active);
+	WRITEL(min_mode.h_active | (min_mode.v_active << 16),
+		&disp_ctrl->disp.disp_active);
+
+	WRITEL(GENERAL_ACT_REQ, &disp_ctrl->cmd.state_ctrl);
+}
+
+/* Restore previous windows status and raster timings */
+static void
+tegra_dc_sor_restore_win_and_raster(struct display_controller *disp_ctrl,
+					int *dc_reg_ctx)
+{
+	int selected_windows, i;
+
+	selected_windows = READL(&disp_ctrl->cmd.disp_win_header);
+
+	for (i = 0; i < DC_N_WINDOWS; ++i) {
+		WRITEL(WINDOW_A_SELECT << i, &disp_ctrl->cmd.disp_win_header);
+		WRITEL(dc_reg_ctx[i], &disp_ctrl->win.win_opt);
+		WRITEL(WIN_A_ACT_REQ << i, &disp_ctrl->cmd.state_ctrl);
+	}
+
+	WRITEL(selected_windows, &disp_ctrl->cmd.disp_win_header);
+
+	WRITEL(dc_reg_ctx[i++], &disp_ctrl->disp.ref_to_sync);
+	WRITEL(dc_reg_ctx[i++], &disp_ctrl->disp.sync_width);
+	WRITEL(dc_reg_ctx[i++], &disp_ctrl->disp.back_porch);
+	WRITEL(dc_reg_ctx[i++], &disp_ctrl->disp.front_porch);
+	WRITEL(dc_reg_ctx[i++], &disp_ctrl->disp.disp_active);
+
+	WRITEL(GENERAL_UPDATE, &disp_ctrl->cmd.state_ctrl);
+}
+
+static void tegra_dc_sor_enable_sor(struct tegra_dc_sor_data *sor, int enable)
+{
+	struct display_controller *disp_ctrl = (void *)sor->dc->base;
+	u32 reg_val = READL(&disp_ctrl->disp.disp_win_opt);
+
+	reg_val = enable ? reg_val | SOR_ENABLE : reg_val & ~SOR_ENABLE;
+	WRITEL(reg_val, &disp_ctrl->disp.disp_win_opt);
+}
+
+void tegra_dc_detach(struct tegra_dc_sor_data *sor)
+{
+	struct display_controller *disp_ctrl = (void *)sor->dc->base;
+	int dc_reg_ctx[DC_N_WINDOWS + 5];
+	unsigned long dc_int_mask;
+
+	/* Sleep mode */
+	tegra_sor_writel(sor, NV_SOR_SUPER_STATE1,
+		NV_SOR_SUPER_STATE1_ASY_HEAD_OP_SLEEP |
+		NV_SOR_SUPER_STATE1_ASY_ORMODE_SAFE |
+		NV_SOR_SUPER_STATE1_ATTACHED_YES);
+	tegra_dc_sor_super_update(sor);
+
+	tegra_dc_sor_disable_win_short_raster(disp_ctrl, dc_reg_ctx);
+
+	if (tegra_dc_sor_poll_register(sor, NV_SOR_TEST,
+		NV_SOR_TEST_ACT_HEAD_OPMODE_DEFAULT_MASK,
+		NV_SOR_TEST_ACT_HEAD_OPMODE_SLEEP,
+		100, TEGRA_SOR_ATTACH_TIMEOUT_MS*1000)) {
+		printk(BIOS_ERR,
+			"dc timeout waiting for OPMOD = SLEEP\n");
+	}
+
+	tegra_sor_writel(sor, NV_SOR_SUPER_STATE1,
+		NV_SOR_SUPER_STATE1_ASY_HEAD_OP_SLEEP |
+		NV_SOR_SUPER_STATE1_ASY_ORMODE_SAFE |
+		NV_SOR_SUPER_STATE1_ATTACHED_NO);
+
+	/* Mask DC interrupts during the 2 dummy frames required for detach */
+	dc_int_mask = READL(&disp_ctrl->cmd.int_mask);
+	WRITEL(0, &disp_ctrl->cmd.int_mask);
+
+	/* Stop DC->SOR path */
+	tegra_dc_sor_enable_sor(sor, 0);
+	tegra_dc_sor_general_act(disp_ctrl);
+
+	/* Stop DC */
+	WRITEL(DISP_CTRL_MODE_STOP, &disp_ctrl->cmd.disp_cmd);
+	tegra_dc_sor_general_act(disp_ctrl);
+
+	tegra_dc_sor_restore_win_and_raster(disp_ctrl, dc_reg_ctx);
+
+	WRITEL(dc_int_mask, &disp_ctrl->cmd.int_mask);
+}
diff --git a/src/soc/nvidia/tegra210/spi.c b/src/soc/nvidia/tegra210/spi.c
new file mode 100644
index 0000000..b14231f
--- /dev/null
+++ b/src/soc/nvidia/tegra210/spi.c
@@ -0,0 +1,944 @@
+/*
+ * NVIDIA Tegra SPI controller (T114 and later)
+ *
+ * Copyright (c) 2010-2013 NVIDIA Corporation
+ * Copyright (C) 2013 Google Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc.
+ */
+
+#include <arch/cache.h>
+#include <arch/io.h>
+#include <assert.h>
+#include <boot_device.h>
+#include <cbfs.h>
+#include <console/console.h>
+#include <delay.h>
+#include <inttypes.h>
+#include <spi-generic.h>
+#include <spi_flash.h>
+#include <soc/addressmap.h>
+#include <soc/dma.h>
+#include <soc/spi.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <symbols.h>
+#include <timer.h>
+
+
+#if defined(CONFIG_DEBUG_SPI) && CONFIG_DEBUG_SPI
+# define DEBUG_SPI(x,...)	printk(BIOS_DEBUG, "TEGRA_SPI: " x)
+#else
+# define DEBUG_SPI(x,...)
+#endif
+
+/*
+ * 64 packets in FIFO mode, BLOCK_SIZE packets in DMA mode. Packets can vary
+ * in size from 4 to 32 bits. To keep things simple we'll use 8-bit packets.
+ */
+#define SPI_PACKET_SIZE_BYTES		1
+#define SPI_MAX_TRANSFER_BYTES_FIFO	(64 * SPI_PACKET_SIZE_BYTES)
+#define SPI_MAX_TRANSFER_BYTES_DMA	(65535 * SPI_PACKET_SIZE_BYTES)
+
+/*
+ * This is used to workaround an issue seen where it may take some time for
+ * packets to show up in the FIFO after they have been received and the
+ * BLOCK_COUNT has been incremented.
+ */
+#define SPI_FIFO_XFER_TIMEOUT_US	1000
+
+/* COMMAND1 */
+#define SPI_CMD1_GO			(1 << 31)
+#define SPI_CMD1_M_S			(1 << 30)
+#define SPI_CMD1_MODE_MASK		0x3
+#define SPI_CMD1_MODE_SHIFT		28
+#define SPI_CMD1_CS_SEL_MASK		0x3
+#define SPI_CMD1_CS_SEL_SHIFT		26
+#define SPI_CMD1_CS_POL_INACTIVE3	(1 << 25)
+#define SPI_CMD1_CS_POL_INACTIVE2	(1 << 24)
+#define SPI_CMD1_CS_POL_INACTIVE1	(1 << 23)
+#define SPI_CMD1_CS_POL_INACTIVE0	(1 << 22)
+#define SPI_CMD1_CS_SW_HW		(1 << 21)
+#define SPI_CMD1_CS_SW_VAL		(1 << 20)
+#define SPI_CMD1_IDLE_SDA_MASK		0x3
+#define SPI_CMD1_IDLE_SDA_SHIFT		18
+#define SPI_CMD1_BIDIR			(1 << 17)
+#define SPI_CMD1_LSBI_FE		(1 << 16)
+#define SPI_CMD1_LSBY_FE		(1 << 15)
+#define SPI_CMD1_BOTH_EN_BIT		(1 << 14)
+#define SPI_CMD1_BOTH_EN_BYTE		(1 << 13)
+#define SPI_CMD1_RX_EN			(1 << 12)
+#define SPI_CMD1_TX_EN			(1 << 11)
+#define SPI_CMD1_PACKED			(1 << 5)
+#define SPI_CMD1_BIT_LEN_MASK		0x1f
+#define SPI_CMD1_BIT_LEN_SHIFT		0
+
+/* COMMAND2 */
+#define SPI_CMD2_TX_CLK_TAP_DELAY	(1 << 6)
+#define SPI_CMD2_TX_CLK_TAP_DELAY_MASK	(0x3F << 6)
+#define SPI_CMD2_RX_CLK_TAP_DELAY	(1 << 0)
+#define SPI_CMD2_RX_CLK_TAP_DELAY_MASK	(0x3F << 0)
+
+/* SPI_TRANS_STATUS */
+#define SPI_STATUS_RDY			(1 << 30)
+#define SPI_STATUS_SLV_IDLE_COUNT_MASK	0xff
+#define SPI_STATUS_SLV_IDLE_COUNT_SHIFT	16
+#define SPI_STATUS_BLOCK_COUNT		0xffff
+#define SPI_STATUS_BLOCK_COUNT_SHIFT	0
+
+/* SPI_FIFO_STATUS */
+#define SPI_FIFO_STATUS_CS_INACTIVE			(1 << 31)
+#define SPI_FIFO_STATUS_FRAME_END			(1 << 30)
+#define SPI_FIFO_STATUS_RX_FIFO_FULL_COUNT_MASK		0x7f
+#define SPI_FIFO_STATUS_RX_FIFO_FULL_COUNT_SHIFT	23
+#define SPI_FIFO_STATUS_TX_FIFO_EMPTY_COUNT_MASK	0x7f
+#define SPI_FIFO_STATUS_TX_FIFO_EMPTY_COUNT_SHIFT	16
+#define SPI_FIFO_STATUS_RX_FIFO_FLUSH			(1 << 15)
+#define SPI_FIFO_STATUS_TX_FIFO_FLUSH			(1 << 14)
+#define SPI_FIFO_STATUS_ERR				(1 << 8)
+#define SPI_FIFO_STATUS_TX_FIFO_OVF			(1 << 7)
+#define SPI_FIFO_STATUS_TX_FIFO_UNR			(1 << 6)
+#define SPI_FIFO_STATUS_RX_FIFO_OVF			(1 << 5)
+#define SPI_FIFO_STATUS_RX_FIFO_UNR			(1 << 4)
+#define SPI_FIFO_STATUS_TX_FIFO_FULL			(1 << 3)
+#define SPI_FIFO_STATUS_TX_FIFO_EMPTY			(1 << 2)
+#define SPI_FIFO_STATUS_RX_FIFO_FULL			(1 << 1)
+#define SPI_FIFO_STATUS_RX_FIFO_EMPTY			(1 << 0)
+
+/* SPI_DMA_CTL */
+#define SPI_DMA_CTL_DMA			(1 << 31)
+#define SPI_DMA_CTL_CONT		(1 << 30)
+#define SPI_DMA_CTL_IE_RX		(1 << 29)
+#define SPI_DMA_CTL_IE_TX		(1 << 28)
+#define SPI_DMA_CTL_RX_TRIG_MASK	0x3
+#define SPI_DMA_CTL_RX_TRIG_SHIFT	19
+#define SPI_DMA_CTL_TX_TRIG_MASK	0x3
+#define SPI_DMA_CTL_TX_TRIG_SHIFT	15
+
+/* SPI_DMA_BLK */
+#define SPI_DMA_CTL_BLOCK_SIZE_MASK	0xffff
+#define SPI_DMA_CTL_BLOCK_SIZE_SHIFT	0
+
+static struct tegra_spi_channel tegra_spi_channels[] = {
+	/*
+	 * Note: Tegra pinmux must be setup for corresponding SPI channel in
+	 * order for its registers to be accessible. If pinmux has not been
+	 * set up, access to the channel's registers will simply hang.
+	 *
+	 * TODO(dhendrix): Clarify or remove this comment (is clock setup
+	 * necessary first, or just pinmux, or both?)
+	 */
+	{
+		.slave = { .bus = 1, },
+		.regs = (struct tegra_spi_regs *)TEGRA_SPI1_BASE,
+		.req_sel = APBDMA_SLAVE_SL2B1,
+	},
+	{
+		.slave = { .bus = 2, },
+		.regs = (struct tegra_spi_regs *)TEGRA_SPI2_BASE,
+		.req_sel = APBDMA_SLAVE_SL2B2,
+	},
+	{
+		.slave = { .bus = 3, },
+		.regs = (struct tegra_spi_regs *)TEGRA_SPI3_BASE,
+		.req_sel = APBDMA_SLAVE_SL2B3,
+	},
+	{
+		.slave = { .bus = 4, },
+		.regs = (struct tegra_spi_regs *)TEGRA_SPI4_BASE,
+		.req_sel = APBDMA_SLAVE_SL2B4,
+	},
+	{
+		.slave = { .bus = 5, },
+		.regs = (struct tegra_spi_regs *)TEGRA_SPI5_BASE,
+		.req_sel = APBDMA_SLAVE_SL2B5,
+	},
+	{
+		.slave = { .bus = 6, },
+		.regs = (struct tegra_spi_regs *)TEGRA_SPI6_BASE,
+		.req_sel = APBDMA_SLAVE_SL2B6,
+	},
+	{
+		.slave = { .bus = 7, },
+		.regs = (struct tegra_spi_regs *)TEGRA_QSPI_BASE,
+		.req_sel = APBDMA_SLAVE_QSPI,
+	},
+};
+
+enum spi_direction {
+	SPI_SEND,
+	SPI_RECEIVE,
+};
+
+struct tegra_spi_channel *tegra_spi_init(unsigned int bus)
+{
+	int i;
+	struct tegra_spi_channel *spi = NULL;
+
+	for (i = 0; i < ARRAY_SIZE(tegra_spi_channels); i++) {
+		if (tegra_spi_channels[i].slave.bus == bus) {
+			spi = &tegra_spi_channels[i];
+			break;
+		}
+	}
+	if (!spi)
+		return NULL;
+
+	/* software drives chip-select, set value to high */
+	setbits_le32(&spi->regs->command1,
+			SPI_CMD1_CS_SW_HW | SPI_CMD1_CS_SW_VAL);
+
+	/* 8-bit transfers, unpacked mode, most significant bit first */
+	clrbits_le32(&spi->regs->command1,
+			SPI_CMD1_BIT_LEN_MASK | SPI_CMD1_PACKED);
+	setbits_le32(&spi->regs->command1, 7 << SPI_CMD1_BIT_LEN_SHIFT);
+
+	return spi;
+}
+
+static struct tegra_spi_channel * const to_tegra_spi(int bus) {
+	return &tegra_spi_channels[bus - 1];
+}
+
+static unsigned int tegra_spi_speed(unsigned int bus)
+{
+	/* FIXME: implement this properly, for now use max value (50MHz) */
+	return 50000000;
+}
+
+int spi_claim_bus(struct spi_slave *slave)
+{
+	struct tegra_spi_regs *regs = to_tegra_spi(slave->bus)->regs;
+	u32 val;
+
+	tegra_spi_init(slave->bus);
+
+	val = read32(&regs->command1);
+
+	/* select appropriate chip-select line */
+	val &= ~(SPI_CMD1_CS_SEL_MASK << SPI_CMD1_CS_SEL_SHIFT);
+	val |= (slave->cs << SPI_CMD1_CS_SEL_SHIFT);
+
+	/* drive chip-select with the inverse of the "inactive" value */
+	if (val & (SPI_CMD1_CS_POL_INACTIVE0 << slave->cs))
+		val &= ~SPI_CMD1_CS_SW_VAL;
+	else
+		val |= SPI_CMD1_CS_SW_VAL;
+
+	write32(&regs->command1, val);
+	return 0;
+}
+
+void spi_release_bus(struct spi_slave *slave)
+{
+	struct tegra_spi_regs *regs = to_tegra_spi(slave->bus)->regs;
+	u32 val;
+
+	val = read32(&regs->command1);
+
+	if (val & (SPI_CMD1_CS_POL_INACTIVE0 << slave->cs))
+		val |= SPI_CMD1_CS_SW_VAL;
+	else
+		val &= ~SPI_CMD1_CS_SW_VAL;
+
+	write32(&regs->command1, val);
+}
+
+static void dump_fifo_status(struct tegra_spi_channel *spi)
+{
+	u32 status = read32(&spi->regs->fifo_status);
+
+	printk(BIOS_INFO, "Raw FIFO status: 0x%08x\n", status);
+	if (status & SPI_FIFO_STATUS_TX_FIFO_OVF)
+		printk(BIOS_INFO, "\tTx overflow detected\n");
+	if (status & SPI_FIFO_STATUS_TX_FIFO_UNR)
+		printk(BIOS_INFO, "\tTx underrun detected\n");
+	if (status & SPI_FIFO_STATUS_RX_FIFO_OVF)
+		printk(BIOS_INFO, "\tRx overflow detected\n");
+	if (status & SPI_FIFO_STATUS_RX_FIFO_UNR)
+		printk(BIOS_INFO, "\tRx underrun detected\n");
+
+	printk(BIOS_INFO, "TX_FIFO: 0x%08x, TX_DATA: 0x%08x\n",
+		read32(&spi->regs->tx_fifo), read32(&spi->regs->tx_data));
+	printk(BIOS_INFO, "RX_FIFO: 0x%08x, RX_DATA: 0x%08x\n",
+		read32(&spi->regs->rx_fifo), read32(&spi->regs->rx_data));
+}
+
+static void clear_fifo_status(struct tegra_spi_channel *spi)
+{
+	clrbits_le32(&spi->regs->fifo_status,
+				SPI_FIFO_STATUS_ERR |
+				SPI_FIFO_STATUS_TX_FIFO_OVF |
+				SPI_FIFO_STATUS_TX_FIFO_UNR |
+				SPI_FIFO_STATUS_RX_FIFO_OVF |
+				SPI_FIFO_STATUS_RX_FIFO_UNR);
+}
+
+static void dump_spi_regs(struct tegra_spi_channel *spi)
+{
+	printk(BIOS_INFO, "SPI regs:\n"
+			"\tdma_blk: 0x%08x\n"
+			"\tcommand1: 0x%08x\n"
+			"\tdma_ctl: 0x%08x\n"
+			"\ttrans_status: 0x%08x\n",
+			read32(&spi->regs->dma_blk),
+			read32(&spi->regs->command1),
+			read32(&spi->regs->dma_ctl),
+			read32(&spi->regs->trans_status));
+}
+
+static void dump_dma_regs(struct apb_dma_channel *dma)
+{
+	printk(BIOS_INFO, "DMA regs:\n"
+			"\tahb_ptr: 0x%08x\n"
+			"\tapb_ptr: 0x%08x\n"
+			"\tahb_seq: 0x%08x\n"
+			"\tapb_seq: 0x%08x\n"
+			"\tcsr: 0x%08x\n"
+			"\tcsre: 0x%08x\n"
+			"\twcount: 0x%08x\n"
+			"\tdma_byte_sta: 0x%08x\n"
+			"\tword_transfer: 0x%08x\n",
+			read32(&dma->regs->ahb_ptr),
+			read32(&dma->regs->apb_ptr),
+			read32(&dma->regs->ahb_seq),
+			read32(&dma->regs->apb_seq),
+			read32(&dma->regs->csr),
+			read32(&dma->regs->csre),
+			read32(&dma->regs->wcount),
+			read32(&dma->regs->dma_byte_sta),
+			read32(&dma->regs->word_transfer));
+}
+
+static inline unsigned int spi_byte_count(struct tegra_spi_channel *spi)
+{
+	/* FIXME: Make this take total packet size into account */
+	return read32(&spi->regs->trans_status) &
+		(SPI_STATUS_BLOCK_COUNT << SPI_STATUS_BLOCK_COUNT_SHIFT);
+}
+
+/*
+ * This calls udelay() with a calculated value based on the SPI speed and
+ * number of bytes remaining to be transferred. It assumes that if the
+ * calculated delay period is less than MIN_DELAY_US then it is probably
+ * not worth the overhead of yielding.
+ */
+#define MIN_DELAY_US 250
+static void spi_delay(struct tegra_spi_channel *spi,
+				unsigned int bytes_remaining)
+{
+	unsigned int ns_per_byte, delay_us;
+
+	ns_per_byte = 1000000000 / (tegra_spi_speed(spi->slave.bus) / 8);
+	delay_us = (ns_per_byte * bytes_remaining) / 1000;
+
+	if (delay_us < MIN_DELAY_US)
+		return;
+
+	udelay(delay_us);
+}
+
+static void tegra_spi_wait(struct tegra_spi_channel *spi)
+{
+	unsigned int count, dma_blk;
+
+	dma_blk = 1 + (read32(&spi->regs->dma_blk) &
+		(SPI_DMA_CTL_BLOCK_SIZE_MASK << SPI_DMA_CTL_BLOCK_SIZE_SHIFT));
+
+	while ((count = spi_byte_count(spi)) != dma_blk)
+		spi_delay(spi, dma_blk - count);
+}
+
+
+static int fifo_error(struct tegra_spi_channel *spi)
+{
+	return read32(&spi->regs->fifo_status) & SPI_FIFO_STATUS_ERR ? 1 : 0;
+}
+
+static int tegra_spi_pio_prepare(struct tegra_spi_channel *spi,
+			unsigned int bytes, enum spi_direction dir)
+{
+	u8 *p = spi->out_buf;
+	unsigned int todo = MIN(bytes, SPI_MAX_TRANSFER_BYTES_FIFO);
+	u32 flush_mask, enable_mask;
+
+	if (dir == SPI_SEND) {
+		flush_mask = SPI_FIFO_STATUS_TX_FIFO_FLUSH;
+		enable_mask = SPI_CMD1_TX_EN;
+	} else {
+		flush_mask = SPI_FIFO_STATUS_RX_FIFO_FLUSH;
+		enable_mask = SPI_CMD1_RX_EN;
+	}
+
+	setbits_le32(&spi->regs->fifo_status, flush_mask);
+	while (read32(&spi->regs->fifo_status) & flush_mask)
+		;
+
+	/*
+	 * BLOCK_SIZE in SPI_DMA_BLK register applies to both DMA and
+	 * PIO transfers. And, it should be programmed before RX_EN or
+	 * TX_EN is set.
+	 */
+	write32(&spi->regs->dma_blk, todo - 1);
+
+	setbits_le32(&spi->regs->command1, enable_mask);
+
+	if (dir == SPI_SEND) {
+		unsigned int to_fifo = bytes;
+		while (to_fifo) {
+			write32(&spi->regs->tx_fifo, *p);
+			p++;
+			to_fifo--;
+		}
+	}
+
+	return todo;
+}
+
+static void tegra_spi_pio_start(struct tegra_spi_channel *spi)
+{
+	setbits_le32(&spi->regs->trans_status, SPI_STATUS_RDY);
+	/*
+	 * Need to stabilize other reg bit before GO bit set.
+	 *
+	 * From IAS:
+	 * For successful operation at various freq combinations, min of 4-5
+	 * spi_clk cycle delay might be required before enabling PIO or DMA bit.
+	 * This is needed to overcome the MCP between core and pad_macro.
+	 * The worst case delay calculation can be done considering slowest
+	 * qspi_clk as 1 MHz. based on that 1 us delay should be enough before
+	 * enabling pio or dma.
+	 */
+	udelay(2);
+	setbits_le32(&spi->regs->command1, SPI_CMD1_GO);
+	/* Need to wait a few cycles before command1 register is read */
+	udelay(1);
+	/* Make sure the write to command1 completes. */
+	read32(&spi->regs->command1);
+}
+
+static inline u32 rx_fifo_count(struct tegra_spi_channel *spi)
+{
+	return (read32(&spi->regs->fifo_status) >>
+		SPI_FIFO_STATUS_RX_FIFO_FULL_COUNT_SHIFT) &
+		SPI_FIFO_STATUS_RX_FIFO_FULL_COUNT_MASK;
+}
+
+static int tegra_spi_pio_finish(struct tegra_spi_channel *spi)
+{
+	u8 *p = spi->in_buf;
+	struct stopwatch sw;
+
+	clrbits_le32(&spi->regs->command1, SPI_CMD1_RX_EN | SPI_CMD1_TX_EN);
+
+	/*
+	 * Allow some time in case the Rx FIFO does not yet have
+	 * all packets pushed into it. See chrome-os-partner:24215.
+	 */
+	stopwatch_init_usecs_expire(&sw, SPI_FIFO_XFER_TIMEOUT_US);
+	do {
+		if (rx_fifo_count(spi) == spi_byte_count(spi))
+			break;
+	} while (!stopwatch_expired(&sw));
+
+	while (!(read32(&spi->regs->fifo_status) &
+				SPI_FIFO_STATUS_RX_FIFO_EMPTY)) {
+		*p = read8(&spi->regs->rx_fifo);
+		p++;
+	}
+
+	if (fifo_error(spi)) {
+		printk(BIOS_ERR, "%s: ERROR:\n", __func__);
+		dump_spi_regs(spi);
+		dump_fifo_status(spi);
+		return -1;
+	}
+
+	return 0;
+}
+
+static void setup_dma_params(struct tegra_spi_channel *spi,
+				struct apb_dma_channel *dma)
+{
+	/* APB bus width = 8-bits, address wrap for each word */
+	clrbits_le32(&dma->regs->apb_seq,
+			APB_BUS_WIDTH_MASK << APB_BUS_WIDTH_SHIFT);
+	/* AHB 1 word burst, bus width = 32 bits (fixed in hardware),
+	 * no address wrapping */
+	clrsetbits_le32(&dma->regs->ahb_seq,
+			(AHB_BURST_MASK << AHB_BURST_SHIFT),
+			4 << AHB_BURST_SHIFT);
+
+	/* Set ONCE mode to transfer one "block" at a time (64KB) and enable
+	 * flow control. */
+	clrbits_le32(&dma->regs->csr,
+			APB_CSR_REQ_SEL_MASK << APB_CSR_REQ_SEL_SHIFT);
+	setbits_le32(&dma->regs->csr, APB_CSR_ONCE | APB_CSR_FLOW |
+			(spi->req_sel << APB_CSR_REQ_SEL_SHIFT));
+}
+
+static int tegra_spi_dma_prepare(struct tegra_spi_channel *spi,
+		unsigned int bytes, enum spi_direction dir)
+{
+	unsigned int todo, wcount;
+
+	/*
+	 * For DMA we need to think of things in terms of word count.
+	 * AHB width is fixed at 32-bits. To avoid overrunning
+	 * the in/out buffers we must align down. (Note: lowest 2-bits
+	 * in WCOUNT register are ignored, and WCOUNT seems to count
+	 * words starting at n-1)
+	 *
+	 * Example: If "bytes" is 7 and we are transferring 1-byte at a time,
+	 * WCOUNT should be 4. The remaining 3 bytes must be transferred
+	 * using PIO.
+	 */
+	todo = MIN(bytes, SPI_MAX_TRANSFER_BYTES_DMA - TEGRA_DMA_ALIGN_BYTES);
+	todo = ALIGN_DOWN(todo, TEGRA_DMA_ALIGN_BYTES);
+	wcount = ALIGN_DOWN(todo - TEGRA_DMA_ALIGN_BYTES, TEGRA_DMA_ALIGN_BYTES);
+
+	if (dir == SPI_SEND) {
+		spi->dma_out = dma_claim();
+		if (!spi->dma_out)
+			return -1;
+
+		/* ensure bytes to send will be visible to DMA controller */
+		dcache_clean_by_mva(spi->out_buf, bytes);
+
+		write32(&spi->dma_out->regs->apb_ptr,
+			(uintptr_t) & spi->regs->tx_fifo);
+		write32(&spi->dma_out->regs->ahb_ptr, (uintptr_t)spi->out_buf);
+		setbits_le32(&spi->dma_out->regs->csr, APB_CSR_DIR);
+		setup_dma_params(spi, spi->dma_out);
+		write32(&spi->dma_out->regs->wcount, wcount);
+	} else {
+		spi->dma_in = dma_claim();
+		if (!spi->dma_in)
+			return -1;
+
+		/* avoid data collisions */
+		dcache_clean_invalidate_by_mva(spi->in_buf, bytes);
+
+		write32(&spi->dma_in->regs->apb_ptr,
+			(uintptr_t)&spi->regs->rx_fifo);
+		write32(&spi->dma_in->regs->ahb_ptr, (uintptr_t)spi->in_buf);
+		clrbits_le32(&spi->dma_in->regs->csr, APB_CSR_DIR);
+		setup_dma_params(spi, spi->dma_in);
+		write32(&spi->dma_in->regs->wcount, wcount);
+	}
+
+	/* BLOCK_SIZE starts at n-1 */
+	write32(&spi->regs->dma_blk, todo - 1);
+	return todo;
+}
+
+static void tegra_spi_dma_start(struct tegra_spi_channel *spi)
+{
+	/*
+	 * The RDY bit in SPI_TRANS_STATUS needs to be cleared manually
+	 * (set bit to clear) between each transaction. Otherwise the next
+	 * transaction does not start.
+	 */
+	setbits_le32(&spi->regs->trans_status, SPI_STATUS_RDY);
+
+	/*
+	 * The DMA triggers have units of packets. As each packet is currently
+	 * 1 byte the triggers need to be set to 4 packets (0b01) to match
+	 * the AHB 32-bit (4 byte) tranfser. Otherwise the FIFO errors can
+	 * occur.
+	 */
+	if (spi->dma_out) {
+		clrsetbits_le32(&spi->regs->dma_ctl,
+			SPI_DMA_CTL_TX_TRIG_MASK << SPI_DMA_CTL_TX_TRIG_SHIFT,
+			1 << SPI_DMA_CTL_TX_TRIG_SHIFT);
+		setbits_le32(&spi->regs->command1, SPI_CMD1_TX_EN);
+	}
+	if (spi->dma_in) {
+		clrsetbits_le32(&spi->regs->dma_ctl,
+			SPI_DMA_CTL_RX_TRIG_MASK << SPI_DMA_CTL_RX_TRIG_SHIFT,
+			1 << SPI_DMA_CTL_RX_TRIG_SHIFT);
+		setbits_le32(&spi->regs->command1, SPI_CMD1_RX_EN);
+	}
+
+	/*
+	 * To avoid underrun conditions, enable APB DMA before SPI DMA for
+	 * Tx and enable SPI DMA before APB DMA before Rx.
+	 */
+	if (spi->dma_out)
+		dma_start(spi->dma_out);
+	setbits_le32(&spi->regs->dma_ctl, SPI_DMA_CTL_DMA);
+	if (spi->dma_in)
+		dma_start(spi->dma_in);
+
+
+}
+
+static int tegra_spi_dma_finish(struct tegra_spi_channel *spi)
+{
+	int ret;
+	unsigned int todo;
+
+	todo = read32(&spi->dma_in->regs->wcount);
+
+	if (spi->dma_in) {
+		while ((read32(&spi->dma_in->regs->dma_byte_sta) < todo) ||
+				dma_busy(spi->dma_in))
+			;	/* this shouldn't take long, no udelay */
+		dma_stop(spi->dma_in);
+		clrbits_le32(&spi->regs->command1, SPI_CMD1_RX_EN);
+		dma_release(spi->dma_in);
+	}
+
+	if (spi->dma_out) {
+		while ((read32(&spi->dma_out->regs->dma_byte_sta) < todo) ||
+				dma_busy(spi->dma_out))
+			spi_delay(spi, todo - spi_byte_count(spi));
+		clrbits_le32(&spi->regs->command1, SPI_CMD1_TX_EN);
+		dma_stop(spi->dma_out);
+		dma_release(spi->dma_out);
+	}
+
+	if (fifo_error(spi)) {
+		printk(BIOS_ERR, "%s: ERROR:\n", __func__);
+		dump_dma_regs(spi->dma_out);
+		dump_dma_regs(spi->dma_in);
+		dump_spi_regs(spi);
+		dump_fifo_status(spi);
+		ret = -1;
+		goto done;
+	}
+
+	ret = 0;
+done:
+	spi->dma_in = NULL;
+	spi->dma_out = NULL;
+	return ret;
+}
+
+/*
+ * xfer_setup() prepares a transfer. It does sanity checking, alignment, and
+ * sets transfer mode used by this channel (if not set already).
+ *
+ * A few caveats to watch out for:
+ * - The number of bytes which can be transferred may be smaller than the
+ *   number of bytes the caller specifies. The number of bytes ready for
+ *   a transfer will be returned (unless an error occurs).
+ *
+ * - Only one mode can be used for both RX and TX. The transfer mode of the
+ *   SPI channel (spi->xfer_mode) is checked each time this function is called.
+ *   If conflicting modes are detected, spi->xfer_mode will be set to
+ *   XFER_MODE_NONE and an error will be returned.
+ *
+ * Returns bytes ready for transfer if successful, <0 to indicate error.
+ */
+static int xfer_setup(struct tegra_spi_channel *spi, void *buf,
+		unsigned int bytes, enum spi_direction dir)
+{
+	unsigned int line_size = dcache_line_bytes();
+	unsigned int align;
+	int ret = -1;
+
+	if (!bytes)
+		return 0;
+
+	if (dir == SPI_SEND)
+		spi->out_buf = buf;
+	else if (dir == SPI_RECEIVE)
+		spi->in_buf = buf;
+
+	/*
+	 * Alignment consideratons:
+	 * When we enable caching we'll need to clean/invalidate portions of
+	 * memory. So we need to be careful about memory alignment. Also, DMA
+	 * likes to operate on 4-bytes at a time on the AHB side. So for
+	 * example, if we only want to receive 1 byte, 4 bytes will be be
+	 * written in memory even if those extra 3 bytes are beyond the length
+	 * we want.
+	 *
+	 * For now we'll use PIO to send/receive unaligned bytes. We may
+	 * consider setting aside some space for a kind of bounce buffer to
+	 * stay in DMA mode once we have a chance to benchmark the two
+	 * approaches.
+	 */
+
+	if (bytes < line_size) {
+		if (spi->xfer_mode == XFER_MODE_DMA) {
+			spi->xfer_mode = XFER_MODE_NONE;
+			ret = -1;
+		} else {
+			spi->xfer_mode = XFER_MODE_PIO;
+			ret = tegra_spi_pio_prepare(spi, bytes, dir);
+		}
+		goto done;
+	}
+
+	/* transfer bytes before the aligned boundary */
+	align = line_size - ((uintptr_t)buf % line_size);
+	if ((align != 0) && (align != line_size)) {
+		if (spi->xfer_mode == XFER_MODE_DMA) {
+			spi->xfer_mode = XFER_MODE_NONE;
+			ret = -1;
+		} else {
+			spi->xfer_mode = XFER_MODE_PIO;
+			ret = tegra_spi_pio_prepare(spi, align, dir);
+		}
+		goto done;
+	}
+
+	/* do aligned DMA transfer */
+	align = (((uintptr_t)buf + bytes) % line_size);
+	if (bytes - align > 0) {
+		unsigned int dma_bytes = bytes - align;
+
+		if (spi->xfer_mode == XFER_MODE_PIO) {
+			spi->xfer_mode = XFER_MODE_NONE;
+			ret = -1;
+		} else {
+			spi->xfer_mode = XFER_MODE_DMA;
+			ret = tegra_spi_dma_prepare(spi, dma_bytes, dir);
+		}
+
+		goto done;
+	}
+
+	/* transfer any remaining unaligned bytes */
+	if (align) {
+		if (spi->xfer_mode == XFER_MODE_DMA) {
+			spi->xfer_mode = XFER_MODE_NONE;
+			ret = -1;
+		} else {
+			spi->xfer_mode = XFER_MODE_PIO;
+			ret = tegra_spi_pio_prepare(spi, align, dir);
+		}
+		goto done;
+	}
+
+done:
+	return ret;
+}
+
+static void xfer_start(struct tegra_spi_channel *spi)
+{
+	if (spi->xfer_mode == XFER_MODE_DMA)
+		tegra_spi_dma_start(spi);
+	else
+		tegra_spi_pio_start(spi);
+}
+
+static void xfer_wait(struct tegra_spi_channel *spi)
+{
+	tegra_spi_wait(spi);
+}
+
+static int xfer_finish(struct tegra_spi_channel *spi)
+{
+	int ret;
+
+	if (spi->xfer_mode == XFER_MODE_DMA)
+		ret = tegra_spi_dma_finish(spi);
+	else
+		ret = tegra_spi_pio_finish(spi);
+
+	spi->xfer_mode = XFER_MODE_NONE;
+	return ret;
+}
+
+unsigned int spi_crop_chunk(unsigned int cmd_len, unsigned int buf_len)
+{
+	return buf_len;
+}
+
+int spi_xfer(struct spi_slave *slave, const void *dout,
+		unsigned int out_bytes, void *din, unsigned int in_bytes)
+{
+	struct tegra_spi_channel *spi = to_tegra_spi(slave->bus);
+	u8 *out_buf = (u8 *)dout;
+	u8 *in_buf = (u8 *)din;
+	unsigned int todo;
+	int ret = 0;
+
+	/* tegra bus numbers start at 1 */
+	ASSERT(slave->bus >= 1 && slave->bus <= ARRAY_SIZE(tegra_spi_channels));
+
+	while (out_bytes || in_bytes) {
+		int x = 0;
+
+		if (out_bytes == 0)
+			todo = in_bytes;
+		else if (in_bytes == 0)
+			todo = out_bytes;
+		else
+			todo = MIN(out_bytes, in_bytes);
+
+		if (out_bytes) {
+			x = xfer_setup(spi, out_buf, todo, SPI_SEND);
+			if (x < 0) {
+				if (spi->xfer_mode == XFER_MODE_NONE) {
+					spi->xfer_mode = XFER_MODE_PIO;
+					continue;
+				} else {
+					ret = -1;
+					break;
+				}
+			}
+		}
+		if (in_bytes) {
+			x = xfer_setup(spi, in_buf, todo, SPI_RECEIVE);
+			if (x < 0) {
+				if (spi->xfer_mode == XFER_MODE_NONE) {
+					spi->xfer_mode = XFER_MODE_PIO;
+					continue;
+				} else {
+					ret = -1;
+					break;
+				}
+			}
+		}
+
+		/*
+		 * Note: Some devices (such as Chrome EC) are sensitive to
+		 * delays, so be careful when adding debug prints not to
+		 * cause timeouts between transfers.
+		 */
+		xfer_start(spi);
+		xfer_wait(spi);
+		if (xfer_finish(spi)) {
+			ret = -1;
+			break;
+		}
+
+		/* Post-processing. */
+		if (out_bytes) {
+			out_bytes -= x;
+			out_buf += x;
+		}
+		if (in_bytes) {
+			in_bytes -= x;
+			in_buf += x;
+		}
+	}
+
+	if (ret < 0) {
+		printk(BIOS_ERR, "%s: Error detected\n", __func__);
+		printk(BIOS_ERR, "Transaction size: %u, bytes remaining: "
+				"%u out / %u in\n", todo, out_bytes, in_bytes);
+		clear_fifo_status(spi);
+	}
+	return ret;
+}
+
+#define JEDEC_READ			0x03
+#define JEDEC_READ_OUTSIZE		0x04
+#define JEDEC_FAST_READ_DUAL		0x3b
+#define JEDEC_FAST_READ_DUAL_OUTSIZE	0x05
+
+static struct spi_slave *boot_slave;
+
+static ssize_t tegra_spi_readat(const struct region_device *rdev, void *dest,
+				size_t offset, size_t count)
+{
+	u8 spi_read_cmd[JEDEC_FAST_READ_DUAL_OUTSIZE];
+	unsigned int read_cmd_bytes;
+	int ret = count;
+	struct tegra_spi_channel *channel;
+
+	channel = to_tegra_spi(boot_slave->bus);
+
+	if (channel->dual_mode) {
+		/*
+		 * Command 0x3b will interleave data only, command 0xbb will
+		 * interleave the address as well. It's nice to see the address
+		 * plainly when debugging, and we're mostly concerned with
+		 * large transfers so the optimization of using 0xbb isn't
+		 * really worthwhile.
+		 */
+		spi_read_cmd[0] = JEDEC_FAST_READ_DUAL;
+		spi_read_cmd[4] = 0x00;	/* dummy byte */
+		read_cmd_bytes = JEDEC_FAST_READ_DUAL_OUTSIZE;
+	} else {
+		spi_read_cmd[0] = JEDEC_READ;
+		read_cmd_bytes = JEDEC_READ_OUTSIZE;
+	}
+	spi_read_cmd[1] = (offset >> 16) & 0xff;
+	spi_read_cmd[2] = (offset >> 8) & 0xff;
+	spi_read_cmd[3] = offset & 0xff;
+
+	spi_claim_bus(boot_slave);
+
+	if (spi_xfer(boot_slave, spi_read_cmd,
+			read_cmd_bytes, NULL, 0) < 0) {
+		ret = -1;
+		printk(BIOS_ERR, "%s: Failed to transfer %zu bytes\n",
+				__func__, sizeof(spi_read_cmd));
+		goto tegra_spi_cbfs_read_exit;
+	}
+
+	if (channel->dual_mode) {
+		setbits_le32(&channel->regs->command1, SPI_CMD1_BOTH_EN_BIT);
+	}
+	if (spi_xfer(boot_slave, NULL, 0, dest, count)) {
+		ret = -1;
+		printk(BIOS_ERR, "%s: Failed to transfer %zu bytes\n",
+				__func__, count);
+	}
+	if (channel->dual_mode)
+		clrbits_le32(&channel->regs->command1, SPI_CMD1_BOTH_EN_BIT);
+
+tegra_spi_cbfs_read_exit:
+	/* de-assert /CS */
+	spi_release_bus(boot_slave);
+	return ret;
+}
+
+struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs)
+{
+	struct tegra_spi_channel *channel = to_tegra_spi(bus);
+	if (!channel)
+		return NULL;
+
+	return &channel->slave;
+}
+
+static const struct region_device_ops tegra_spi_ops = {
+	.mmap = mmap_helper_rdev_mmap,
+	.munmap = mmap_helper_rdev_munmap,
+	.readat = tegra_spi_readat,
+};
+
+__attribute__((unused))
+static struct mmap_helper_region_device mdev =
+	MMAP_HELPER_REGION_INIT(&tegra_spi_ops, 0, CONFIG_ROM_SIZE);
+
+#if !IS_ENABLED(CONFIG_COMMON_CBFS_SPI_WRAPPER)
+const struct region_device *boot_device_ro(void)
+{
+	return &mdev.rdev;
+}
+
+void boot_device_init(void)
+{
+	struct tegra_spi_channel *boot_chan;
+
+	boot_chan = &tegra_spi_channels[CONFIG_BOOT_MEDIA_SPI_BUS - 1];
+	boot_chan->slave.cs = CONFIG_BOOT_MEDIA_SPI_CHIP_SELECT;
+
+#if CONFIG_SPI_FLASH_FAST_READ_DUAL_OUTPUT_3B == 1
+	boot_chan->dual_mode = 1;
+#endif
+	boot_slave = &boot_chan->slave;
+
+	mmap_helper_device_init(&mdev, _cbfs_cache, _cbfs_cache_size);
+}
+#endif
diff --git a/src/soc/nvidia/tegra210/stack.S b/src/soc/nvidia/tegra210/stack.S
new file mode 100644
index 0000000..5a48d0e
--- /dev/null
+++ b/src/soc/nvidia/tegra210/stack.S
@@ -0,0 +1,45 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright 2014 Google Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc.
+ */
+
+/* Macro to initialize stack, perform seeding if required and finally call the
+ * function provided
+ * @stack_top    : First address above the stack
+ * @stack_bottom : Lowest address on the stack
+ * @seed         : Stack seeding required (1=yes/otherwise=no)
+ * @func         : Function to call after initializing stack
+ */
+.macro stack_init stack_top, stack_bottom, seed, func
+        /* Check if stack seeding is required */
+	mov	r0, #\seed
+	cmp     r0, #1
+	bne     call_func
+	/* Stack seeding */
+	ldr     r0, =\stack_bottom
+	ldr	r1, =\stack_top
+	ldr	r2, =0xdeadbeef
+init_stack_loop:
+	str	r2, [r0]
+	add	r0, #4
+	cmp	r0, r1
+	bne	init_stack_loop
+
+call_func:
+	ldr	sp, =\stack_top /* Set up stack pointer */
+	bl	\func
+.endm
diff --git a/src/soc/nvidia/tegra210/uart.c b/src/soc/nvidia/tegra210/uart.c
new file mode 100644
index 0000000..773bc89
--- /dev/null
+++ b/src/soc/nvidia/tegra210/uart.c
@@ -0,0 +1,135 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2009 Samsung Electronics
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc.
+ */
+
+#include <arch/io.h>
+#include <boot/coreboot_tables.h>
+#include <console/console.h>	/* for __console definition */
+#include <console/uart.h>
+#include <drivers/uart/uart8250reg.h>
+#include <stdint.h>
+
+struct tegra210_uart {
+	union {
+		uint32_t thr; // Transmit holding register.
+		uint32_t rbr; // Receive buffer register.
+		uint32_t dll; // Divisor latch lsb.
+	};
+	union {
+		uint32_t ier; // Interrupt enable register.
+		uint32_t dlm; // Divisor latch msb.
+	};
+	union {
+		uint32_t iir; // Interrupt identification register.
+		uint32_t fcr; // FIFO control register.
+	};
+	uint32_t lcr; // Line control register.
+	uint32_t mcr; // Modem control register.
+	uint32_t lsr; // Line status register.
+	uint32_t msr; // Modem status register.
+} __attribute__ ((packed));
+
+
+static struct tegra210_uart * const uart_ptr =
+	(void *)CONFIG_CONSOLE_SERIAL_TEGRA210_UART_ADDRESS;
+
+static void tegra210_uart_tx_flush(void);
+static int tegra210_uart_tst_byte(void);
+
+static void tegra210_uart_init(void)
+{
+	// Use a hardcoded divisor for now.
+	const unsigned divisor = 221;
+	const uint8_t line_config = UART8250_LCR_WLS_8; // 8n1
+
+	tegra210_uart_tx_flush();
+
+	// Disable interrupts.
+	write8(&uart_ptr->ier, 0);
+	// Force DTR and RTS to high.
+	write8(&uart_ptr->mcr, UART8250_MCR_DTR | UART8250_MCR_RTS);
+	// Set line configuration, access divisor latches.
+	write8(&uart_ptr->lcr, UART8250_LCR_DLAB | line_config);
+	// Set the divisor.
+	write8(&uart_ptr->dll, divisor & 0xff);
+	write8(&uart_ptr->dlm, (divisor >> 8) & 0xff);
+	// Hide the divisor latches.
+	write8(&uart_ptr->lcr, line_config);
+	// Enable FIFOs, and clear receive and transmit.
+	write8(&uart_ptr->fcr,
+		UART8250_FCR_FIFO_EN |
+		UART8250_FCR_CLEAR_RCVR |
+		UART8250_FCR_CLEAR_XMIT);
+}
+
+static void tegra210_uart_tx_byte(unsigned char data)
+{
+	while (!(read8(&uart_ptr->lsr) & UART8250_LSR_THRE));
+	write8(&uart_ptr->thr, data);
+}
+
+static void tegra210_uart_tx_flush(void)
+{
+	while (!(read8(&uart_ptr->lsr) & UART8250_LSR_TEMT));
+}
+
+static unsigned char tegra210_uart_rx_byte(void)
+{
+	if (!tegra210_uart_tst_byte())
+		return 0;
+	return read8(&uart_ptr->rbr);
+}
+
+static int tegra210_uart_tst_byte(void)
+{
+	return (read8(&uart_ptr->lsr) & UART8250_LSR_DR) == UART8250_LSR_DR;
+}
+
+void uart_init(int idx)
+{
+	tegra210_uart_init();
+}
+
+void uart_tx_byte(int idx, unsigned char data)
+{
+	tegra210_uart_tx_byte(data);
+}
+
+void uart_tx_flush(int idx)
+{
+	tegra210_uart_tx_flush();
+}
+
+unsigned char uart_rx_byte(int idx)
+{
+	return tegra210_uart_rx_byte();
+}
+
+#ifndef __PRE_RAM__
+void uart_fill_lb(void *data)
+{
+	struct lb_serial serial;
+	serial.type = LB_SERIAL_TYPE_MEMORY_MAPPED;
+	serial.baseaddr = CONFIG_CONSOLE_SERIAL_TEGRA210_UART_ADDRESS;
+	serial.baud = default_baudrate();
+	serial.regwidth = 1;
+	lb_add_serial(&serial, data);
+
+	lb_add_console(LB_TAG_CONSOLE_SERIAL8250MEM, data);
+}
+#endif
diff --git a/src/soc/nvidia/tegra210/verstage.c b/src/soc/nvidia/tegra210/verstage.c
new file mode 100644
index 0000000..3df5c71
--- /dev/null
+++ b/src/soc/nvidia/tegra210/verstage.c
@@ -0,0 +1,52 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright 2014 Google Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc.
+ */
+
+#include <arch/cache.h>
+#include <arch/exception.h>
+#include <arch/hlt.h>
+#include <arch/stages.h>
+#include <console/console.h>
+#include <soc/verstage.h>
+#include <timestamp.h>
+#include <vendorcode/google/chromeos/chromeos.h>
+
+void __attribute__((weak)) verstage_mainboard_init(void)
+{
+	/* Default empty implementation. */
+}
+
+static void verstage(void)
+{
+	void *entry;
+
+	console_init();
+	timestamp_add_now(TS_START_VBOOT);
+	exception_init();
+	verstage_mainboard_init();
+
+	entry = vboot2_verify_firmware();
+	if (entry != (void *)-1)
+		stage_exit(entry);
+}
+
+void main(void)
+{
+	verstage();
+	hlt();
+}



More information about the coreboot-gerrit mailing list