Merge branch 'master' of git://git.denx.de/u-boot-tegra
diff --git a/arch/arm/dts/tegra210-p2371-2180.dts b/arch/arm/dts/tegra210-p2371-2180.dts
index 5d9adcf..bf35497 100644
--- a/arch/arm/dts/tegra210-p2371-2180.dts
+++ b/arch/arm/dts/tegra210-p2371-2180.dts
@@ -21,6 +21,56 @@
 		reg = <0x0 0x80000000 0x0 0xc0000000>;
 	};
 
+	pcie-controller@0,01003000 {
+		status = "okay";
+
+		pci@1,0 {
+			status = "okay";
+		};
+
+		pci@2,0 {
+			status = "okay";
+		};
+	};
+
+	padctl@0,7009f000 {
+		pinctrl-0 = <&padctl_default>;
+		pinctrl-names = "default";
+
+		padctl_default: pinmux {
+			xusb {
+				nvidia,lanes = "otg-1", "otg-2";
+				nvidia,function = "xusb";
+				nvidia,iddq = <0>;
+			};
+
+			usb3 {
+				nvidia,lanes = "pcie-5", "pcie-6";
+				nvidia,function = "usb3";
+				nvidia,iddq = <0>;
+			};
+
+			pcie-x1 {
+				nvidia,lanes = "pcie-0";
+				nvidia,function = "pcie-x1";
+				nvidia,iddq = <0>;
+			};
+
+			pcie-x4 {
+				nvidia,lanes = "pcie-1", "pcie-2",
+					       "pcie-3", "pcie-4";
+				nvidia,function = "pcie-x4";
+				nvidia,iddq = <0>;
+			};
+
+			sata {
+				nvidia,lanes = "sata-0";
+				nvidia,function = "sata";
+				nvidia,iddq = <0>;
+			};
+		};
+	};
+
 	sdhci@0,700b0000 {
 		status = "okay";
 		cd-gpios = <&gpio TEGRA_GPIO(Z, 1) GPIO_ACTIVE_LOW>;
diff --git a/arch/arm/dts/tegra210.dtsi b/arch/arm/dts/tegra210.dtsi
index f3874a1..a8c2f19 100644
--- a/arch/arm/dts/tegra210.dtsi
+++ b/arch/arm/dts/tegra210.dtsi
@@ -12,6 +12,72 @@
 	#address-cells = <2>;
 	#size-cells = <2>;
 
+	pcie-controller@0,01003000 {
+		compatible = "nvidia,tegra210-pcie";
+		device_type = "pci";
+		reg = <0x0 0x01003000 0x0 0x00000800   /* PADS registers */
+		       0x0 0x01003800 0x0 0x00000800   /* AFI registers */
+		       0x0 0x02000000 0x0 0x10000000>; /* configuration space */
+		reg-names = "pads", "afi", "cs";
+		interrupts = <GIC_SPI 98 IRQ_TYPE_LEVEL_HIGH>, /* controller interrupt */
+			     <GIC_SPI 99 IRQ_TYPE_LEVEL_HIGH>; /* MSI interrupt */
+		interrupt-names = "intr", "msi";
+
+		#interrupt-cells = <1>;
+		interrupt-map-mask = <0 0 0 0>;
+		interrupt-map = <0 0 0 0 &gic GIC_SPI 98 IRQ_TYPE_LEVEL_HIGH>;
+
+		bus-range = <0x00 0xff>;
+		#address-cells = <3>;
+		#size-cells = <2>;
+
+		ranges = <0x82000000 0 0x01000000 0x0 0x01000000 0 0x00001000   /* port 0 configuration space */
+			  0x82000000 0 0x01001000 0x0 0x01001000 0 0x00001000   /* port 1 configuration space */
+			  0x81000000 0 0x0        0x0 0x12000000 0 0x00010000   /* downstream I/O (64 KiB) */
+			  0x82000000 0 0x13000000 0x0 0x13000000 0 0x0d000000   /* non-prefetchable memory (208 MiB) */
+			  0xc2000000 0 0x20000000 0x0 0x20000000 0 0x20000000>; /* prefetchable memory (512 MiB) */
+
+		clocks = <&tegra_car TEGRA210_CLK_PCIE>,
+			 <&tegra_car TEGRA210_CLK_AFI>,
+			 <&tegra_car TEGRA210_CLK_PLL_E>,
+			 <&tegra_car TEGRA210_CLK_CML0>;
+		clock-names = "pex", "afi", "pll_e", "cml";
+		resets = <&tegra_car 70>,
+			 <&tegra_car 72>,
+			 <&tegra_car 74>;
+		reset-names = "pex", "afi", "pcie_x";
+		status = "disabled";
+
+		phys = <&padctl TEGRA_XUSB_PADCTL_PCIE>;
+		phy-names = "pcie";
+
+		pci@1,0 {
+			device_type = "pci";
+			assigned-addresses = <0x82000800 0 0x01000000 0 0x1000>;
+			reg = <0x000800 0 0 0 0>;
+			status = "disabled";
+
+			#address-cells = <3>;
+			#size-cells = <2>;
+			ranges;
+
+			nvidia,num-lanes = <4>;
+		};
+
+		pci@2,0 {
+			device_type = "pci";
+			assigned-addresses = <0x82001000 0 0x01001000 0 0x1000>;
+			reg = <0x001000 0 0 0 0>;
+			status = "disabled";
+
+			#address-cells = <3>;
+			#size-cells = <2>;
+			ranges;
+
+			nvidia,num-lanes = <1>;
+		};
+	};
+
 	gic: interrupt-controller@0,50041000 {
 		compatible = "arm,gic-400";
 		#interrupt-cells = <3>;
diff --git a/arch/arm/include/asm/arch-tegra/gpu.h b/arch/arm/include/asm/arch-tegra/gpu.h
index 52280f4..4423386 100644
--- a/arch/arm/include/asm/arch-tegra/gpu.h
+++ b/arch/arm/include/asm/arch-tegra/gpu.h
@@ -10,29 +10,23 @@
 
 #if defined(CONFIG_TEGRA_GPU)
 
-void config_gpu(void);
-bool gpu_configured(void);
+void tegra_gpu_config(void);
 
 #else /* CONFIG_TEGRA_GPU */
 
-static inline void config_gpu(void)
+static inline void tegra_gpu_config(void)
 {
 }
 
-static inline bool gpu_configured(void)
-{
-	return false;
-}
-
 #endif /* CONFIG_TEGRA_GPU */
 
 #if defined(CONFIG_OF_LIBFDT)
 
-int gpu_enable_node(void *blob, const char *gpupath);
+int tegra_gpu_enable_node(void *blob, const char *gpupath);
 
 #else /* CONFIG_OF_LIBFDT */
 
-static inline int gpu_enable_node(void *blob, const char *gpupath)
+static inline int tegra_gpu_enable_node(void *blob, const char *gpupath)
 {
 	return 0;
 }
diff --git a/arch/arm/mach-tegra/Makefile b/arch/arm/mach-tegra/Makefile
index 98431a9..2be6ef4 100644
--- a/arch/arm/mach-tegra/Makefile
+++ b/arch/arm/mach-tegra/Makefile
@@ -23,7 +23,7 @@
 obj-y += lowlevel_init.o
 obj-y += pinmux-common.o
 obj-y += powergate.o
-obj-y += xusb-padctl.o
+obj-y += xusb-padctl-dummy.o
 obj-$(CONFIG_DISPLAY_CPUINFO) += sys_info.o
 obj-$(CONFIG_TEGRA_GPU) += gpu.o
 obj-$(CONFIG_TEGRA_CLOCK_SCALING) += emc.o
diff --git a/arch/arm/mach-tegra/board2.c b/arch/arm/mach-tegra/board2.c
index 8ecc674..8ba143d 100644
--- a/arch/arm/mach-tegra/board2.c
+++ b/arch/arm/mach-tegra/board2.c
@@ -128,7 +128,7 @@
 	clock_init();
 	clock_verify();
 
-	config_gpu();
+	tegra_gpu_config();
 
 #ifdef CONFIG_TEGRA_SPI
 	pin_mux_spi();
@@ -403,3 +403,23 @@
 {
 	return CONFIG_SYS_SDRAM_BASE + usable_ram_size_below_4g();
 }
+
+/*
+ * This function is called right before the kernel is booted. "blob" is the
+ * device tree that will be passed to the kernel.
+ */
+int ft_system_setup(void *blob, bd_t *bd)
+{
+	const char *gpu_path =
+#if defined(CONFIG_TEGRA124) || defined(CONFIG_TEGRA210)
+		"/gpu@0,57000000";
+#else
+		NULL;
+#endif
+
+	/* Enable GPU node if GPU setup has been performed */
+	if (gpu_path != NULL)
+		return tegra_gpu_enable_node(blob, gpu_path);
+
+	return 0;
+}
diff --git a/arch/arm/mach-tegra/gpu.c b/arch/arm/mach-tegra/gpu.c
index 4ea046d..c7d705d 100644
--- a/arch/arm/mach-tegra/gpu.c
+++ b/arch/arm/mach-tegra/gpu.c
@@ -25,7 +25,7 @@
 
 static bool _configured;
 
-void config_gpu(void)
+void tegra_gpu_config(void)
 {
 	struct mc_ctlr *mc = (struct mc_ctlr *)NV_PA_MC_BASE;
 
@@ -41,18 +41,13 @@
 	_configured = true;
 }
 
-bool vpr_configured(void)
-{
-	return _configured;
-}
-
 #if defined(CONFIG_OF_LIBFDT)
 
-int gpu_enable_node(void *blob, const char *gpupath)
+int tegra_gpu_enable_node(void *blob, const char *gpupath)
 {
 	int offset;
 
-	if (vpr_configured()) {
+	if (_configured) {
 		offset = fdt_path_offset(blob, gpupath);
 		if (offset > 0) {
 			fdt_status_okay(blob, offset);
diff --git a/arch/arm/mach-tegra/tegra124/Makefile b/arch/arm/mach-tegra/tegra124/Makefile
index f577f45..c00de61 100644
--- a/arch/arm/mach-tegra/tegra124/Makefile
+++ b/arch/arm/mach-tegra/tegra124/Makefile
@@ -11,6 +11,7 @@
 obj-y	+= funcmux.o
 obj-y	+= pinmux.o
 obj-y	+= xusb-padctl.o
+obj-y	+= ../xusb-padctl-common.o
 
 ifndef CONFIG_SPL_BUILD
 obj-$(CONFIG_ARMV7_NONSEC) += psci.o
diff --git a/arch/arm/mach-tegra/tegra124/xusb-padctl.c b/arch/arm/mach-tegra/tegra124/xusb-padctl.c
index 43af883..76af924 100644
--- a/arch/arm/mach-tegra/tegra124/xusb-padctl.c
+++ b/arch/arm/mach-tegra/tegra124/xusb-padctl.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, NVIDIA CORPORATION.  All rights reserved.
+ * Copyright (c) 2014-2015, NVIDIA CORPORATION.  All rights reserved.
  *
  * SPDX-License-Identifier: GPL-2.0
  */
@@ -8,13 +8,8 @@
 
 #include <common.h>
 #include <errno.h>
-#include <fdtdec.h>
-#include <malloc.h>
 
-#include <asm/io.h>
-
-#include <asm/arch/clock.h>
-#include <asm/arch-tegra/xusb-padctl.h>
+#include "../xusb-padctl-common.h"
 
 #include <dt-bindings/pinctrl/pinctrl-tegra-xusb.h>
 
@@ -83,18 +78,6 @@
 	TEGRA124_FUNC_RSVD,
 };
 
-struct tegra_xusb_padctl_lane {
-	const char *name;
-
-	unsigned int offset;
-	unsigned int shift;
-	unsigned int mask;
-	unsigned int iddq;
-
-	const unsigned int *funcs;
-	unsigned int num_funcs;
-};
-
 #define TEGRA124_LANE(_name, _offset, _shift, _mask, _iddq, _funcs)	\
 	{								\
 		.name = _name,						\
@@ -121,74 +104,6 @@
 	TEGRA124_LANE("sata-0", 0x134, 26, 0x3, 6, pci),
 };
 
-struct tegra_xusb_phy_ops {
-	int (*prepare)(struct tegra_xusb_phy *phy);
-	int (*enable)(struct tegra_xusb_phy *phy);
-	int (*disable)(struct tegra_xusb_phy *phy);
-	int (*unprepare)(struct tegra_xusb_phy *phy);
-};
-
-struct tegra_xusb_phy {
-	const struct tegra_xusb_phy_ops *ops;
-
-	struct tegra_xusb_padctl *padctl;
-};
-
-struct tegra_xusb_padctl_pin {
-	const struct tegra_xusb_padctl_lane *lane;
-
-	unsigned int func;
-	int iddq;
-};
-
-#define MAX_GROUPS 3
-#define MAX_PINS 6
-
-struct tegra_xusb_padctl_group {
-	const char *name;
-
-	const char *pins[MAX_PINS];
-	unsigned int num_pins;
-
-	const char *func;
-	int iddq;
-};
-
-struct tegra_xusb_padctl_config {
-	const char *name;
-
-	struct tegra_xusb_padctl_group groups[MAX_GROUPS];
-	unsigned int num_groups;
-};
-
-struct tegra_xusb_padctl {
-	struct fdt_resource regs;
-
-	unsigned int enable;
-
-	struct tegra_xusb_phy phys[2];
-
-	const struct tegra_xusb_padctl_lane *lanes;
-	unsigned int num_lanes;
-
-	const char *const *functions;
-	unsigned int num_functions;
-
-	struct tegra_xusb_padctl_config config;
-};
-
-static inline u32 padctl_readl(struct tegra_xusb_padctl *padctl,
-			       unsigned long offset)
-{
-	return readl(padctl->regs.start + offset);
-}
-
-static inline void padctl_writel(struct tegra_xusb_padctl *padctl,
-				 u32 value, unsigned long offset)
-{
-	writel(value, padctl->regs.start + offset);
-}
-
 static int tegra_xusb_padctl_enable(struct tegra_xusb_padctl *padctl)
 {
 	u32 value;
@@ -220,7 +135,7 @@
 	u32 value;
 
 	if (padctl->enable == 0) {
-		error("tegra-xusb-padctl: unbalanced enable/disable");
+		error("unbalanced enable/disable");
 		return 0;
 	}
 
@@ -380,329 +295,27 @@
 	.unprepare = phy_unprepare,
 };
 
-static struct tegra_xusb_padctl *padctl = &(struct tegra_xusb_padctl) {
-	.phys = {
-		[0] = {
-			.ops = &pcie_phy_ops,
-		},
-		[1] = {
-			.ops = &sata_phy_ops,
-		},
+static struct tegra_xusb_phy tegra124_phys[] = {
+	{
+		.type = TEGRA_XUSB_PADCTL_PCIE,
+		.ops = &pcie_phy_ops,
+		.padctl = &padctl,
+	},
+	{
+		.type = TEGRA_XUSB_PADCTL_SATA,
+		.ops = &sata_phy_ops,
+		.padctl = &padctl,
 	},
 };
 
-static const struct tegra_xusb_padctl_lane *
-tegra_xusb_padctl_find_lane(struct tegra_xusb_padctl *padctl, const char *name)
-{
-	unsigned int i;
-
-	for (i = 0; i < padctl->num_lanes; i++)
-		if (strcmp(name, padctl->lanes[i].name) == 0)
-			return &padctl->lanes[i];
-
-	return NULL;
-}
-
-static int
-tegra_xusb_padctl_group_parse_dt(struct tegra_xusb_padctl *padctl,
-				 struct tegra_xusb_padctl_group *group,
-				 const void *fdt, int node)
-{
-	unsigned int i;
-	int len, err;
-
-	group->name = fdt_get_name(fdt, node, &len);
-
-	len = fdt_count_strings(fdt, node, "nvidia,lanes");
-	if (len < 0) {
-		error("tegra-xusb-padctl: failed to parse \"nvidia,lanes\" property");
-		return -EINVAL;
-	}
-
-	group->num_pins = len;
-
-	for (i = 0; i < group->num_pins; i++) {
-		err = fdt_get_string_index(fdt, node, "nvidia,lanes", i,
-					   &group->pins[i]);
-		if (err < 0) {
-			error("tegra-xusb-padctl: failed to read string from \"nvidia,lanes\" property");
-			return -EINVAL;
-		}
-	}
-
-	group->num_pins = len;
-
-	err = fdt_get_string(fdt, node, "nvidia,function", &group->func);
-	if (err < 0) {
-		error("tegra-xusb-padctl: failed to parse \"nvidia,func\" property");
-		return -EINVAL;
-	}
-
-	group->iddq = fdtdec_get_int(fdt, node, "nvidia,iddq", -1);
-
-	return 0;
-}
-
-static int tegra_xusb_padctl_find_function(struct tegra_xusb_padctl *padctl,
-					   const char *name)
-{
-	unsigned int i;
-
-	for (i = 0; i < padctl->num_functions; i++)
-		if (strcmp(name, padctl->functions[i]) == 0)
-			return i;
-
-	return -ENOENT;
-}
-
-static int
-tegra_xusb_padctl_lane_find_function(struct tegra_xusb_padctl *padctl,
-				     const struct tegra_xusb_padctl_lane *lane,
-				     const char *name)
-{
-	unsigned int i;
-	int func;
-
-	func = tegra_xusb_padctl_find_function(padctl, name);
-	if (func < 0)
-		return func;
-
-	for (i = 0; i < lane->num_funcs; i++)
-		if (lane->funcs[i] == func)
-			return i;
-
-	return -ENOENT;
-}
-
-static int
-tegra_xusb_padctl_group_apply(struct tegra_xusb_padctl *padctl,
-			      const struct tegra_xusb_padctl_group *group)
-{
-	unsigned int i;
-
-	for (i = 0; i < group->num_pins; i++) {
-		const struct tegra_xusb_padctl_lane *lane;
-		unsigned int func;
-		u32 value;
-
-		lane = tegra_xusb_padctl_find_lane(padctl, group->pins[i]);
-		if (!lane) {
-			error("tegra-xusb-padctl: no lane for pin %s",
-			      group->pins[i]);
-			continue;
-		}
-
-		func = tegra_xusb_padctl_lane_find_function(padctl, lane,
-							    group->func);
-		if (func < 0) {
-			error("tegra-xusb-padctl: function %s invalid for lane %s: %d",
-			      group->func, lane->name, func);
-			continue;
-		}
-
-		value = padctl_readl(padctl, lane->offset);
-
-		/* set pin function */
-		value &= ~(lane->mask << lane->shift);
-		value |= func << lane->shift;
-
-		/*
-		 * Set IDDQ if supported on the lane and specified in the
-		 * configuration.
-		 */
-		if (lane->iddq > 0 && group->iddq >= 0) {
-			if (group->iddq != 0)
-				value &= ~(1 << lane->iddq);
-			else
-				value |= 1 << lane->iddq;
-		}
-
-		padctl_writel(padctl, value, lane->offset);
-	}
-
-	return 0;
-}
-
-static int
-tegra_xusb_padctl_config_apply(struct tegra_xusb_padctl *padctl,
-			       struct tegra_xusb_padctl_config *config)
-{
-	unsigned int i;
-
-	for (i = 0; i < config->num_groups; i++) {
-		const struct tegra_xusb_padctl_group *group;
-		int err;
-
-		group = &config->groups[i];
-
-		err = tegra_xusb_padctl_group_apply(padctl, group);
-		if (err < 0) {
-			error("tegra-xusb-padctl: failed to apply group %s: %d",
-			      group->name, err);
-			continue;
-		}
-	}
-
-	return 0;
-}
-
-static int
-tegra_xusb_padctl_config_parse_dt(struct tegra_xusb_padctl *padctl,
-				  struct tegra_xusb_padctl_config *config,
-				  const void *fdt, int node)
-{
-	int subnode;
-
-	config->name = fdt_get_name(fdt, node, NULL);
-
-	fdt_for_each_subnode(fdt, subnode, node) {
-		struct tegra_xusb_padctl_group *group;
-		int err;
-
-		group = &config->groups[config->num_groups];
-
-		err = tegra_xusb_padctl_group_parse_dt(padctl, group, fdt,
-						       subnode);
-		if (err < 0) {
-			error("tegra-xusb-padctl: failed to parse group %s",
-			      group->name);
-			return err;
-		}
-
-		config->num_groups++;
-	}
-
-	return 0;
-}
-
-static int tegra_xusb_padctl_parse_dt(struct tegra_xusb_padctl *padctl,
-				      const void *fdt, int node)
-{
-	int subnode, err;
-
-	err = fdt_get_resource(fdt, node, "reg", 0, &padctl->regs);
-	if (err < 0) {
-		error("tegra-xusb-padctl: registers not found");
-		return err;
-	}
-
-	fdt_for_each_subnode(fdt, subnode, node) {
-		struct tegra_xusb_padctl_config *config = &padctl->config;
-
-		err = tegra_xusb_padctl_config_parse_dt(padctl, config, fdt,
-							subnode);
-		if (err < 0) {
-			error("tegra-xusb-padctl: failed to parse entry %s: %d",
-			      config->name, err);
-			continue;
-		}
-	}
-
-	return 0;
-}
-
-static int process_nodes(const void *fdt, int nodes[], unsigned int count)
-{
-	unsigned int i;
-
-	for (i = 0; i < count; i++) {
-		enum fdt_compat_id id;
-		int err;
-
-		if (!fdtdec_get_is_enabled(fdt, nodes[i]))
-			continue;
-
-		id = fdtdec_lookup(fdt, nodes[i]);
-		switch (id) {
-		case COMPAT_NVIDIA_TEGRA124_XUSB_PADCTL:
-			break;
-
-		default:
-			error("tegra-xusb-padctl: unsupported compatible: %s",
-			      fdtdec_get_compatible(id));
-			continue;
-		}
-
-		padctl->num_lanes = ARRAY_SIZE(tegra124_lanes);
-		padctl->lanes = tegra124_lanes;
-
-		padctl->num_functions = ARRAY_SIZE(tegra124_functions);
-		padctl->functions = tegra124_functions;
-
-		err = tegra_xusb_padctl_parse_dt(padctl, fdt, nodes[i]);
-		if (err < 0) {
-			error("tegra-xusb-padctl: failed to parse DT: %d",
-			      err);
-			continue;
-		}
-
-		/* deassert XUSB padctl reset */
-		reset_set_enable(PERIPH_ID_XUSB_PADCTL, 0);
-
-		err = tegra_xusb_padctl_config_apply(padctl, &padctl->config);
-		if (err < 0) {
-			error("tegra-xusb-padctl: failed to apply pinmux: %d",
-			      err);
-			continue;
-		}
-
-		/* only a single instance is supported */
-		break;
-	}
-
-	return 0;
-}
-
-struct tegra_xusb_phy *tegra_xusb_phy_get(unsigned int type)
-{
-	struct tegra_xusb_phy *phy = NULL;
-
-	switch (type) {
-	case TEGRA_XUSB_PADCTL_PCIE:
-		phy = &padctl->phys[0];
-		phy->padctl = padctl;
-		break;
-
-	case TEGRA_XUSB_PADCTL_SATA:
-		phy = &padctl->phys[1];
-		phy->padctl = padctl;
-		break;
-	}
-
-	return phy;
-}
-
-int tegra_xusb_phy_prepare(struct tegra_xusb_phy *phy)
-{
-	if (phy && phy->ops && phy->ops->prepare)
-		return phy->ops->prepare(phy);
-
-	return phy ? -ENOSYS : -EINVAL;
-}
-
-int tegra_xusb_phy_enable(struct tegra_xusb_phy *phy)
-{
-	if (phy && phy->ops && phy->ops->enable)
-		return phy->ops->enable(phy);
-
-	return phy ? -ENOSYS : -EINVAL;
-}
-
-int tegra_xusb_phy_disable(struct tegra_xusb_phy *phy)
-{
-	if (phy && phy->ops && phy->ops->disable)
-		return phy->ops->disable(phy);
-
-	return phy ? -ENOSYS : -EINVAL;
-}
-
-int tegra_xusb_phy_unprepare(struct tegra_xusb_phy *phy)
-{
-	if (phy && phy->ops && phy->ops->unprepare)
-		return phy->ops->unprepare(phy);
-
-	return phy ? -ENOSYS : -EINVAL;
-}
+static const struct tegra_xusb_padctl_soc tegra124_socdata = {
+	.lanes = tegra124_lanes,
+	.num_lanes = ARRAY_SIZE(tegra124_lanes),
+	.functions = tegra124_functions,
+	.num_functions = ARRAY_SIZE(tegra124_functions),
+	.phys = tegra124_phys,
+	.num_phys = ARRAY_SIZE(tegra124_phys),
+};
 
 void tegra_xusb_padctl_init(const void *fdt)
 {
@@ -711,6 +324,6 @@
 	count = fdtdec_find_aliases_for_id(fdt, "padctl",
 					   COMPAT_NVIDIA_TEGRA124_XUSB_PADCTL,
 					   nodes, ARRAY_SIZE(nodes));
-	if (process_nodes(fdt, nodes, count))
+	if (tegra_xusb_process_nodes(fdt, nodes, count, &tegra124_socdata))
 		return;
 }
diff --git a/arch/arm/mach-tegra/tegra210/Kconfig b/arch/arm/mach-tegra/tegra210/Kconfig
index b07363a..055fb12 100644
--- a/arch/arm/mach-tegra/tegra210/Kconfig
+++ b/arch/arm/mach-tegra/tegra210/Kconfig
@@ -19,12 +19,12 @@
 	  a GPIO expansion header, and an analog audio jack.
 
 config TARGET_P2371_2180
-	bool "NVIDIA Tegra210 P2371-2180 board"
+	bool "NVIDIA Tegra210 P2371-2180 (Jetson TX1) board"
 	help
-	  P2371-2180 is a P2180 CPU board married to a P2597 I/O board. The
-	  combination contains SoC, DRAM, eMMC, SD card slot, HDMI, USB
-	  micro-B port, Ethernet via USB3, USB3 host port, SATA, PCIe, and
-	  two GPIO expansion headers.
+	  P2371-2180 (Jetson TX1 developer kit) is a P2180 CPU board married
+	  to a P2597 I/O board. The combination contains SoC, DRAM, eMMC, SD
+	  card slot, HDMI, USB micro-B port, Ethernet via USB3, USB3 host
+	  port, SATA, PCIe, and two GPIO expansion headers.
 
 config TARGET_P2571
 	bool "NVIDIA Tegra210 P2571 base board"
diff --git a/arch/arm/mach-tegra/tegra210/Makefile b/arch/arm/mach-tegra/tegra210/Makefile
index 1fb8d1a..b6012fc 100644
--- a/arch/arm/mach-tegra/tegra210/Makefile
+++ b/arch/arm/mach-tegra/tegra210/Makefile
@@ -9,3 +9,4 @@
 obj-y	+= funcmux.o
 obj-y	+= pinmux.o
 obj-y	+= xusb-padctl.o
+obj-y	+= ../xusb-padctl-common.o
diff --git a/arch/arm/mach-tegra/tegra210/clock.c b/arch/arm/mach-tegra/tegra210/clock.c
index 6d75d37..df92bdc 100644
--- a/arch/arm/mach-tegra/tegra210/clock.c
+++ b/arch/arm/mach-tegra/tegra210/clock.c
@@ -8,6 +8,7 @@
 /* Tegra210 Clock control functions */
 
 #include <common.h>
+#include <errno.h>
 #include <asm/io.h>
 #include <asm/arch/clock.h>
 #include <asm/arch/sysctr.h>
@@ -1030,6 +1031,59 @@
 	debug("%s: TSC CNTCR = 0x%08X\n", __func__, val);
 }
 
+#define PLLREFE_MISC			0x4c8
+#define  PLLREFE_MISC_LOCK		BIT(27)
+#define  PLLREFE_MISC_IDDQ		BIT(24)
+
+#define PLLREFE_BASE			0x4c4
+#define  PLLREFE_BASE_BYPASS		BIT(31)
+#define  PLLREFE_BASE_ENABLE		BIT(30)
+#define  PLLREFE_BASE_REF_DIS		BIT(29)
+#define  PLLREFE_BASE_KCP(kcp)		(((kcp) & 0x3) << 27)
+#define  PLLREFE_BASE_KVCO		BIT(26)
+#define  PLLREFE_BASE_DIVP(p)		(((p) & 0x1f) << 16)
+#define  PLLREFE_BASE_DIVN(n)		(((n) & 0xff) << 8)
+#define  PLLREFE_BASE_DIVM(m)		(((m) & 0xff) << 0)
+
+static int tegra_pllref_enable(void)
+{
+	u32 value;
+	unsigned long start;
+
+	/*
+	 * This sequence comes from Tegra X1 TRM section "Cold Boot, with no
+	 * Recovery Mode or Boot from USB", sub-section "PLLREFE".
+	 */
+
+	value = readl(NV_PA_CLK_RST_BASE + PLLREFE_MISC);
+	value &= ~PLLREFE_MISC_IDDQ;
+	writel(value, NV_PA_CLK_RST_BASE + PLLREFE_MISC);
+
+	udelay(5);
+
+	value = PLLREFE_BASE_ENABLE |
+		PLLREFE_BASE_KCP(0) |
+		PLLREFE_BASE_DIVP(0) |
+		PLLREFE_BASE_DIVN(0x41) |
+		PLLREFE_BASE_DIVM(4);
+	writel(value, NV_PA_CLK_RST_BASE + PLLREFE_BASE);
+
+	debug("waiting for pllrefe lock\n");
+	start = get_timer(0);
+	while (get_timer(start) < 250) {
+		value = readl(NV_PA_CLK_RST_BASE + PLLREFE_MISC);
+		if (value & PLLREFE_MISC_LOCK)
+			break;
+	}
+	if (!(value & PLLREFE_MISC_LOCK)) {
+		debug("  timeout\n");
+		return -ETIMEDOUT;
+	}
+	debug("  done\n");
+
+	return 0;
+}
+
 #define PLLE_SS_CNTL 0x68
 #define  PLLE_SS_CNTL_SSCINCINTR(x) (((x) & 0x3f) << 24)
 #define  PLLE_SS_CNTL_SSCINC(x) (((x) & 0xff) << 16)
@@ -1041,100 +1095,131 @@
 #define  PLLE_SS_CNTL_SSCMAX(x) (((x) & 0x1ff) << 0)
 
 #define PLLE_BASE 0x0e8
-#define  PLLE_BASE_ENABLE (1 << 30)
-#define  PLLE_BASE_LOCK_OVERRIDE (1 << 29)
-#define  PLLE_BASE_PLDIV_CML(x) (((x) & 0xf) << 24)
+#define  PLLE_BASE_ENABLE (1 << 31)
+#define  PLLE_BASE_PLDIV_CML(x) (((x) & 0x1f) << 24)
 #define  PLLE_BASE_NDIV(x) (((x) & 0xff) << 8)
 #define  PLLE_BASE_MDIV(x) (((x) & 0xff) << 0)
 
 #define PLLE_MISC 0x0ec
 #define  PLLE_MISC_IDDQ_SWCTL (1 << 14)
-#define  PLLE_MISC_IDDQ_OVERRIDE (1 << 13)
-#define  PLLE_MISC_LOCK_ENABLE (1 << 9)
-#define  PLLE_MISC_PTS (1 << 8)
-#define  PLLE_MISC_VREG_BG_CTRL(x) (((x) & 0x3) << 4)
+#define  PLLE_MISC_IDDQ_OVERRIDE_VALUE (1 << 13)
+#define  PLLE_MISC_LOCK (1 << 11)
+#define  PLLE_MISC_KCP(x) (((x) & 0x3) << 6)
 #define  PLLE_MISC_VREG_CTRL(x) (((x) & 0x3) << 2)
+#define  PLLE_MISC_KVCO (1 << 0)
 
 #define PLLE_AUX 0x48c
+#define  PLLE_AUX_SS_SEQ_INCLUDE (1 << 31)
+#define  PLLE_AUX_REF_SEL_PLLREFE (1 << 28)
 #define  PLLE_AUX_SEQ_ENABLE (1 << 24)
+#define  PLLE_AUX_SS_SWCTL (1 << 6)
 #define  PLLE_AUX_ENABLE_SWCTL (1 << 4)
+#define  PLLE_AUX_USE_LOCKDET (1 << 3)
 
 int tegra_plle_enable(void)
 {
-	unsigned int m = 1, n = 200, cpcon = 13;
 	u32 value;
+	unsigned long start;
 
-	value = readl(NV_PA_CLK_RST_BASE + PLLE_BASE);
-	value &= ~PLLE_BASE_LOCK_OVERRIDE;
-	writel(value, NV_PA_CLK_RST_BASE + PLLE_BASE);
+	/* PLLREF feeds PLLE */
+	tegra_pllref_enable();
+
+	/*
+	 * This sequence comes from Tegra X1 TRM section "Cold Boot, with no
+	 * Recovery Mode or Boot from USB", sub-section "PLLEs".
+	 */
+
+	/* 1. Select XTAL as the source */
 
 	value = readl(NV_PA_CLK_RST_BASE + PLLE_AUX);
-	value |= PLLE_AUX_ENABLE_SWCTL;
-	value &= ~PLLE_AUX_SEQ_ENABLE;
+	value &= ~PLLE_AUX_REF_SEL_PLLREFE;
 	writel(value, NV_PA_CLK_RST_BASE + PLLE_AUX);
 
-	udelay(1);
-
 	value = readl(NV_PA_CLK_RST_BASE + PLLE_MISC);
-	value |= PLLE_MISC_IDDQ_SWCTL;
-	value &= ~PLLE_MISC_IDDQ_OVERRIDE;
-	value |= PLLE_MISC_LOCK_ENABLE;
-	value |= PLLE_MISC_PTS;
-	value |= PLLE_MISC_VREG_BG_CTRL(3);
-	value |= PLLE_MISC_VREG_CTRL(2);
+	value &= ~PLLE_MISC_IDDQ_OVERRIDE_VALUE;
 	writel(value, NV_PA_CLK_RST_BASE + PLLE_MISC);
 
+	/* 2. Wait 5 us */
 	udelay(5);
 
-	value = readl(NV_PA_CLK_RST_BASE + PLLE_SS_CNTL);
-	value |= PLLE_SS_CNTL_SSCBYP | PLLE_SS_CNTL_INTERP_RESET |
-		 PLLE_SS_CNTL_BYPASS_SS;
-	writel(value, NV_PA_CLK_RST_BASE + PLLE_SS_CNTL);
+	/*
+	 * 3. Program the following registers to generate a low jitter 100MHz
+	 * clock.
+	 */
 
 	value = readl(NV_PA_CLK_RST_BASE + PLLE_BASE);
-	value &= ~PLLE_BASE_PLDIV_CML(0xf);
+	value &= ~PLLE_BASE_PLDIV_CML(0x1f);
 	value &= ~PLLE_BASE_NDIV(0xff);
 	value &= ~PLLE_BASE_MDIV(0xff);
-	value |= PLLE_BASE_PLDIV_CML(cpcon);
-	value |= PLLE_BASE_NDIV(n);
-	value |= PLLE_BASE_MDIV(m);
+	value |= PLLE_BASE_PLDIV_CML(0xe);
+	value |= PLLE_BASE_NDIV(0x7d);
+	value |= PLLE_BASE_MDIV(2);
 	writel(value, NV_PA_CLK_RST_BASE + PLLE_BASE);
 
-	udelay(1);
+	value = readl(NV_PA_CLK_RST_BASE + PLLE_MISC);
+	value &= ~PLLE_MISC_KCP(3);
+	value &= ~PLLE_MISC_VREG_CTRL(3);
+	value &= ~PLLE_MISC_KVCO;
+	writel(value, NV_PA_CLK_RST_BASE + PLLE_MISC);
 
 	value = readl(NV_PA_CLK_RST_BASE + PLLE_BASE);
 	value |= PLLE_BASE_ENABLE;
 	writel(value, NV_PA_CLK_RST_BASE + PLLE_BASE);
 
-	/* wait for lock */
-	udelay(300);
+	/* 4. Wait for LOCK */
+
+	debug("waiting for plle lock\n");
+	start = get_timer(0);
+	while (get_timer(start) < 250) {
+		value = readl(NV_PA_CLK_RST_BASE + PLLE_MISC);
+		if (value & PLLE_MISC_LOCK)
+			break;
+	}
+	if (!(value & PLLE_MISC_LOCK)) {
+		debug("  timeout\n");
+		return -ETIMEDOUT;
+	}
+	debug("  done\n");
+
+	/* 5. Enable SSA */
 
 	value = readl(NV_PA_CLK_RST_BASE + PLLE_SS_CNTL);
+	value &= ~PLLE_SS_CNTL_SSCINC(0xff);
+	value |= PLLE_SS_CNTL_SSCINC(1);
+	value &= ~PLLE_SS_CNTL_SSCINCINTR(0x3f);
+	value |= PLLE_SS_CNTL_SSCINCINTR(0x23);
+	value &= ~PLLE_SS_CNTL_SSCMAX(0x1fff);
+	value |= PLLE_SS_CNTL_SSCMAX(0x21);
 	value &= ~PLLE_SS_CNTL_SSCINVERT;
 	value &= ~PLLE_SS_CNTL_SSCCENTER;
-
-	value &= ~PLLE_SS_CNTL_SSCINCINTR(0x3f);
-	value &= ~PLLE_SS_CNTL_SSCINC(0xff);
-	value &= ~PLLE_SS_CNTL_SSCMAX(0x1ff);
-
-	value |= PLLE_SS_CNTL_SSCINCINTR(0x20);
-	value |= PLLE_SS_CNTL_SSCINC(0x01);
-	value |= PLLE_SS_CNTL_SSCMAX(0x25);
-
-	writel(value, NV_PA_CLK_RST_BASE + PLLE_SS_CNTL);
-
-	value = readl(NV_PA_CLK_RST_BASE + PLLE_SS_CNTL);
-	value &= ~PLLE_SS_CNTL_SSCBYP;
 	value &= ~PLLE_SS_CNTL_BYPASS_SS;
+	value &= ~PLLE_SS_CNTL_SSCBYP;
 	writel(value, NV_PA_CLK_RST_BASE + PLLE_SS_CNTL);
 
+	/* 6. Wait 300 ns */
+
 	udelay(1);
-
-	value = readl(NV_PA_CLK_RST_BASE + PLLE_SS_CNTL);
 	value &= ~PLLE_SS_CNTL_INTERP_RESET;
 	writel(value, NV_PA_CLK_RST_BASE + PLLE_SS_CNTL);
 
+	/* 7. Enable HW power sequencer for PLLE */
+
+	value = readl(NV_PA_CLK_RST_BASE + PLLE_MISC);
+	value &= ~PLLE_MISC_IDDQ_SWCTL;
+	writel(value, NV_PA_CLK_RST_BASE + PLLE_MISC);
+
+	value = readl(NV_PA_CLK_RST_BASE + PLLE_AUX);
+	value &= ~PLLE_AUX_SS_SWCTL;
+	value &= ~PLLE_AUX_ENABLE_SWCTL;
+	value |= PLLE_AUX_SS_SEQ_INCLUDE;
+	value |= PLLE_AUX_USE_LOCKDET;
+	writel(value, NV_PA_CLK_RST_BASE + PLLE_AUX);
+
+	/* 8. Wait 1 us */
+
 	udelay(1);
+	value |= PLLE_AUX_SEQ_ENABLE;
+	writel(value, NV_PA_CLK_RST_BASE + PLLE_AUX);
 
 	return 0;
 }
diff --git a/arch/arm/mach-tegra/tegra210/xusb-padctl.c b/arch/arm/mach-tegra/tegra210/xusb-padctl.c
index 3c10a96..9ec93e7 100644
--- a/arch/arm/mach-tegra/tegra210/xusb-padctl.c
+++ b/arch/arm/mach-tegra/tegra210/xusb-padctl.c
@@ -8,51 +8,82 @@
 
 #include <common.h>
 #include <errno.h>
-#include <fdtdec.h>
-#include <malloc.h>
 
-#include <asm/io.h>
+#include "../xusb-padctl-common.h"
 
 #include <asm/arch/clock.h>
-#include <asm/arch-tegra/xusb-padctl.h>
 
 #include <dt-bindings/pinctrl/pinctrl-tegra-xusb.h>
 
-struct tegra_xusb_phy_ops {
-	int (*prepare)(struct tegra_xusb_phy *phy);
-	int (*enable)(struct tegra_xusb_phy *phy);
-	int (*disable)(struct tegra_xusb_phy *phy);
-	int (*unprepare)(struct tegra_xusb_phy *phy);
+enum tegra210_function {
+	TEGRA210_FUNC_SNPS,
+	TEGRA210_FUNC_XUSB,
+	TEGRA210_FUNC_UART,
+	TEGRA210_FUNC_PCIE_X1,
+	TEGRA210_FUNC_PCIE_X4,
+	TEGRA210_FUNC_USB3,
+	TEGRA210_FUNC_SATA,
+	TEGRA210_FUNC_RSVD,
 };
 
-struct tegra_xusb_phy {
-	const struct tegra_xusb_phy_ops *ops;
-
-	struct tegra_xusb_padctl *padctl;
+static const char *const tegra210_functions[] = {
+	"snps",
+	"xusb",
+	"uart",
+	"pcie-x1",
+	"pcie-x4",
+	"usb3",
+	"sata",
+	"rsvd",
 };
 
-struct tegra_xusb_padctl {
-	struct fdt_resource regs;
-
-	unsigned int enable;
-
-	struct tegra_xusb_phy phys[2];
+static const unsigned int tegra210_otg_functions[] = {
+	TEGRA210_FUNC_SNPS,
+	TEGRA210_FUNC_XUSB,
+	TEGRA210_FUNC_UART,
+	TEGRA210_FUNC_RSVD,
 };
 
-static inline u32 padctl_readl(struct tegra_xusb_padctl *padctl,
-			       unsigned long offset)
-{
-	u32 value = readl(padctl->regs.start + offset);
-	debug("padctl: %08lx > %08x\n", offset, value);
-	return value;
-}
+static const unsigned int tegra210_usb_functions[] = {
+	TEGRA210_FUNC_SNPS,
+	TEGRA210_FUNC_XUSB,
+};
 
-static inline void padctl_writel(struct tegra_xusb_padctl *padctl,
-				 u32 value, unsigned long offset)
-{
-	debug("padctl: %08lx < %08x\n", offset, value);
-	writel(value, padctl->regs.start + offset);
-}
+static const unsigned int tegra210_pci_functions[] = {
+	TEGRA210_FUNC_PCIE_X1,
+	TEGRA210_FUNC_USB3,
+	TEGRA210_FUNC_SATA,
+	TEGRA210_FUNC_PCIE_X4,
+};
+
+#define TEGRA210_LANE(_name, _offset, _shift, _mask, _iddq, _funcs)	\
+	{								\
+		.name = _name,						\
+		.offset = _offset,					\
+		.shift = _shift,					\
+		.mask = _mask,						\
+		.iddq = _iddq,						\
+		.num_funcs = ARRAY_SIZE(tegra210_##_funcs##_functions),	\
+		.funcs = tegra210_##_funcs##_functions,			\
+	}
+
+static const struct tegra_xusb_padctl_lane tegra210_lanes[] = {
+	TEGRA210_LANE("otg-0",     0x004,  0, 0x3, 0, otg),
+	TEGRA210_LANE("otg-1",     0x004,  2, 0x3, 0, otg),
+	TEGRA210_LANE("otg-2",     0x004,  4, 0x3, 0, otg),
+	TEGRA210_LANE("otg-3",     0x004,  6, 0x3, 0, otg),
+	TEGRA210_LANE("usb2-bias", 0x004, 18, 0x3, 0, otg),
+	TEGRA210_LANE("hsic-0",    0x004, 14, 0x1, 0, usb),
+	TEGRA210_LANE("hsic-1",    0x004, 15, 0x1, 0, usb),
+	TEGRA210_LANE("pcie-0",    0x028, 12, 0x3, 1, pci),
+	TEGRA210_LANE("pcie-1",    0x028, 14, 0x3, 2, pci),
+	TEGRA210_LANE("pcie-2",    0x028, 16, 0x3, 3, pci),
+	TEGRA210_LANE("pcie-3",    0x028, 18, 0x3, 4, pci),
+	TEGRA210_LANE("pcie-4",    0x028, 20, 0x3, 5, pci),
+	TEGRA210_LANE("pcie-5",    0x028, 22, 0x3, 6, pci),
+	TEGRA210_LANE("pcie-6",    0x028, 24, 0x3, 7, pci),
+	TEGRA210_LANE("sata-0",    0x028, 30, 0x3, 8, pci),
+};
 
 #define XUSB_PADCTL_ELPG_PROGRAM 0x024
 #define  XUSB_PADCTL_ELPG_PROGRAM_AUX_MUX_LP0_VCORE_DOWN (1 << 31)
@@ -248,7 +279,10 @@
 		if (value & XUSB_PADCTL_UPHY_PLL_P0_CTL2_CAL_DONE)
 			break;
 	}
-
+	if (!(value & XUSB_PADCTL_UPHY_PLL_P0_CTL2_CAL_DONE)) {
+		debug("  timeout\n");
+		return -ETIMEDOUT;
+	}
 	debug("  done\n");
 
 	value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_P0_CTL2);
@@ -264,7 +298,10 @@
 		if ((value & XUSB_PADCTL_UPHY_PLL_P0_CTL2_CAL_DONE) == 0)
 			break;
 	}
-
+	if (value & XUSB_PADCTL_UPHY_PLL_P0_CTL2_CAL_DONE) {
+		debug("  timeout\n");
+		return -ETIMEDOUT;
+	}
 	debug("  done\n");
 
 	value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_P0_CTL1);
@@ -279,7 +316,10 @@
 		if (value & XUSB_PADCTL_UPHY_PLL_P0_CTL1_LOCKDET_STATUS)
 			break;
 	}
-
+	if (!(value & XUSB_PADCTL_UPHY_PLL_P0_CTL1_LOCKDET_STATUS)) {
+		debug("  timeout\n");
+		return -ETIMEDOUT;
+	}
 	debug("  done\n");
 
 	value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_P0_CTL8);
@@ -295,7 +335,10 @@
 		if (value & XUSB_PADCTL_UPHY_PLL_P0_CTL8_RCAL_DONE)
 			break;
 	}
-
+	if (!(value & XUSB_PADCTL_UPHY_PLL_P0_CTL8_RCAL_DONE)) {
+		debug("  timeout\n");
+		return -ETIMEDOUT;
+	}
 	debug("  done\n");
 
 	value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_P0_CTL8);
@@ -310,7 +353,10 @@
 		if ((value & XUSB_PADCTL_UPHY_PLL_P0_CTL8_RCAL_DONE) == 0)
 			break;
 	}
-
+	if (value & XUSB_PADCTL_UPHY_PLL_P0_CTL8_RCAL_DONE) {
+		debug("  timeout\n");
+		return -ETIMEDOUT;
+	}
 	debug("  done\n");
 
 	value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_P0_CTL8);
@@ -358,120 +404,22 @@
 	.unprepare = phy_unprepare,
 };
 
-static struct tegra_xusb_padctl *padctl = &(struct tegra_xusb_padctl) {
-	.phys = {
-		[0] = {
-			.ops = &pcie_phy_ops,
-		},
+static struct tegra_xusb_phy tegra210_phys[] = {
+	{
+		.type = TEGRA_XUSB_PADCTL_PCIE,
+		.ops = &pcie_phy_ops,
+		.padctl = &padctl,
 	},
 };
 
-static int tegra_xusb_padctl_parse_dt(struct tegra_xusb_padctl *padctl,
-				      const void *fdt, int node)
-{
-	int err;
-
-	err = fdt_get_resource(fdt, node, "reg", 0, &padctl->regs);
-	if (err < 0) {
-		error("registers not found");
-		return err;
-	}
-
-	debug("regs: %pa-%pa\n", &padctl->regs.start,
-	      &padctl->regs.end);
-
-	return 0;
-}
-
-static int process_nodes(const void *fdt, int nodes[], unsigned int count)
-{
-	unsigned int i;
-	int err;
-
-	debug("> %s(fdt=%p, nodes=%p, count=%u)\n", __func__, fdt, nodes,
-	      count);
-
-	for (i = 0; i < count; i++) {
-		enum fdt_compat_id id;
-
-		if (!fdtdec_get_is_enabled(fdt, nodes[i]))
-			continue;
-
-		id = fdtdec_lookup(fdt, nodes[i]);
-		switch (id) {
-		case COMPAT_NVIDIA_TEGRA124_XUSB_PADCTL:
-		case COMPAT_NVIDIA_TEGRA210_XUSB_PADCTL:
-			break;
-
-		default:
-			error("unsupported compatible: %s",
-			      fdtdec_get_compatible(id));
-			continue;
-		}
-
-		err = tegra_xusb_padctl_parse_dt(padctl, fdt, nodes[i]);
-		if (err < 0) {
-			error("failed to parse DT: %d",
-			      err);
-			continue;
-		}
-
-		/* deassert XUSB padctl reset */
-		reset_set_enable(PERIPH_ID_XUSB_PADCTL, 0);
-
-		/* only a single instance is supported */
-		break;
-	}
-
-	debug("< %s()\n", __func__);
-	return 0;
-}
-
-struct tegra_xusb_phy *tegra_xusb_phy_get(unsigned int type)
-{
-	struct tegra_xusb_phy *phy = NULL;
-
-	switch (type) {
-	case TEGRA_XUSB_PADCTL_PCIE:
-		phy = &padctl->phys[0];
-		phy->padctl = padctl;
-		break;
-	}
-
-	return phy;
-}
-
-int tegra_xusb_phy_prepare(struct tegra_xusb_phy *phy)
-{
-	if (phy && phy->ops && phy->ops->prepare)
-		return phy->ops->prepare(phy);
-
-	return phy ? -ENOSYS : -EINVAL;
-}
-
-int tegra_xusb_phy_enable(struct tegra_xusb_phy *phy)
-{
-	if (phy && phy->ops && phy->ops->enable)
-		return phy->ops->enable(phy);
-
-	return phy ? -ENOSYS : -EINVAL;
-}
-
-int tegra_xusb_phy_disable(struct tegra_xusb_phy *phy)
-{
-	if (phy && phy->ops && phy->ops->disable)
-		return phy->ops->disable(phy);
-
-	return phy ? -ENOSYS : -EINVAL;
-}
-
-int tegra_xusb_phy_unprepare(struct tegra_xusb_phy *phy)
-{
-	if (phy && phy->ops && phy->ops->unprepare)
-		return phy->ops->unprepare(phy);
-
-	return phy ? -ENOSYS : -EINVAL;
-}
+static const struct tegra_xusb_padctl_soc tegra210_socdata = {
+	.lanes = tegra210_lanes,
+	.num_lanes = ARRAY_SIZE(tegra210_lanes),
+	.functions = tegra210_functions,
+	.num_functions = ARRAY_SIZE(tegra210_functions),
+	.phys = tegra210_phys,
+	.num_phys = ARRAY_SIZE(tegra210_phys),
+};
 
 void tegra_xusb_padctl_init(const void *fdt)
 {
@@ -482,13 +430,7 @@
 	count = fdtdec_find_aliases_for_id(fdt, "padctl",
 					   COMPAT_NVIDIA_TEGRA210_XUSB_PADCTL,
 					   nodes, ARRAY_SIZE(nodes));
-	if (process_nodes(fdt, nodes, count))
-		return;
-
-	count = fdtdec_find_aliases_for_id(fdt, "padctl",
-					   COMPAT_NVIDIA_TEGRA124_XUSB_PADCTL,
-					   nodes, ARRAY_SIZE(nodes));
-	if (process_nodes(fdt, nodes, count))
+	if (tegra_xusb_process_nodes(fdt, nodes, count, &tegra210_socdata))
 		return;
 
 	debug("< %s()\n", __func__);
diff --git a/arch/arm/mach-tegra/xusb-padctl-common.c b/arch/arm/mach-tegra/xusb-padctl-common.c
new file mode 100644
index 0000000..18ad7bf
--- /dev/null
+++ b/arch/arm/mach-tegra/xusb-padctl-common.c
@@ -0,0 +1,305 @@
+/*
+ * Copyright (c) 2014-2015, NVIDIA CORPORATION.  All rights reserved.
+ *
+ * SPDX-License-Identifier: GPL-2.0
+ */
+
+#define pr_fmt(fmt) "tegra-xusb-padctl: " fmt
+
+#include <common.h>
+#include <errno.h>
+
+#include "xusb-padctl-common.h"
+
+#include <asm/arch/clock.h>
+
+int tegra_xusb_phy_prepare(struct tegra_xusb_phy *phy)
+{
+	if (phy && phy->ops && phy->ops->prepare)
+		return phy->ops->prepare(phy);
+
+	return phy ? -ENOSYS : -EINVAL;
+}
+
+int tegra_xusb_phy_enable(struct tegra_xusb_phy *phy)
+{
+	if (phy && phy->ops && phy->ops->enable)
+		return phy->ops->enable(phy);
+
+	return phy ? -ENOSYS : -EINVAL;
+}
+
+int tegra_xusb_phy_disable(struct tegra_xusb_phy *phy)
+{
+	if (phy && phy->ops && phy->ops->disable)
+		return phy->ops->disable(phy);
+
+	return phy ? -ENOSYS : -EINVAL;
+}
+
+int tegra_xusb_phy_unprepare(struct tegra_xusb_phy *phy)
+{
+	if (phy && phy->ops && phy->ops->unprepare)
+		return phy->ops->unprepare(phy);
+
+	return phy ? -ENOSYS : -EINVAL;
+}
+
+struct tegra_xusb_phy *tegra_xusb_phy_get(unsigned int type)
+{
+	struct tegra_xusb_phy *phy;
+	int i;
+
+	for (i = 0; i < padctl.socdata->num_phys; i++) {
+		phy = &padctl.socdata->phys[i];
+		if (phy->type != type)
+			continue;
+		return phy;
+	}
+
+	return NULL;
+}
+
+static const struct tegra_xusb_padctl_lane *
+tegra_xusb_padctl_find_lane(struct tegra_xusb_padctl *padctl, const char *name)
+{
+	unsigned int i;
+
+	for (i = 0; i < padctl->socdata->num_lanes; i++)
+		if (strcmp(name, padctl->socdata->lanes[i].name) == 0)
+			return &padctl->socdata->lanes[i];
+
+	return NULL;
+}
+
+static int
+tegra_xusb_padctl_group_parse_dt(struct tegra_xusb_padctl *padctl,
+				 struct tegra_xusb_padctl_group *group,
+				 const void *fdt, int node)
+{
+	unsigned int i;
+	int len, err;
+
+	group->name = fdt_get_name(fdt, node, &len);
+
+	len = fdt_count_strings(fdt, node, "nvidia,lanes");
+	if (len < 0) {
+		error("failed to parse \"nvidia,lanes\" property");
+		return -EINVAL;
+	}
+
+	group->num_pins = len;
+
+	for (i = 0; i < group->num_pins; i++) {
+		err = fdt_get_string_index(fdt, node, "nvidia,lanes", i,
+					   &group->pins[i]);
+		if (err < 0) {
+			error("failed to read string from \"nvidia,lanes\" property");
+			return -EINVAL;
+		}
+	}
+
+	group->num_pins = len;
+
+	err = fdt_get_string(fdt, node, "nvidia,function", &group->func);
+	if (err < 0) {
+		error("failed to parse \"nvidia,func\" property");
+		return -EINVAL;
+	}
+
+	group->iddq = fdtdec_get_int(fdt, node, "nvidia,iddq", -1);
+
+	return 0;
+}
+
+static int tegra_xusb_padctl_find_function(struct tegra_xusb_padctl *padctl,
+					   const char *name)
+{
+	unsigned int i;
+
+	for (i = 0; i < padctl->socdata->num_functions; i++)
+		if (strcmp(name, padctl->socdata->functions[i]) == 0)
+			return i;
+
+	return -ENOENT;
+}
+
+static int
+tegra_xusb_padctl_lane_find_function(struct tegra_xusb_padctl *padctl,
+				     const struct tegra_xusb_padctl_lane *lane,
+				     const char *name)
+{
+	unsigned int i;
+	int func;
+
+	func = tegra_xusb_padctl_find_function(padctl, name);
+	if (func < 0)
+		return func;
+
+	for (i = 0; i < lane->num_funcs; i++)
+		if (lane->funcs[i] == func)
+			return i;
+
+	return -ENOENT;
+}
+
+static int
+tegra_xusb_padctl_group_apply(struct tegra_xusb_padctl *padctl,
+			      const struct tegra_xusb_padctl_group *group)
+{
+	unsigned int i;
+
+	for (i = 0; i < group->num_pins; i++) {
+		const struct tegra_xusb_padctl_lane *lane;
+		unsigned int func;
+		u32 value;
+
+		lane = tegra_xusb_padctl_find_lane(padctl, group->pins[i]);
+		if (!lane) {
+			error("no lane for pin %s", group->pins[i]);
+			continue;
+		}
+
+		func = tegra_xusb_padctl_lane_find_function(padctl, lane,
+							    group->func);
+		if (func < 0) {
+			error("function %s invalid for lane %s: %d",
+			      group->func, lane->name, func);
+			continue;
+		}
+
+		value = padctl_readl(padctl, lane->offset);
+
+		/* set pin function */
+		value &= ~(lane->mask << lane->shift);
+		value |= func << lane->shift;
+
+		/*
+		 * Set IDDQ if supported on the lane and specified in the
+		 * configuration.
+		 */
+		if (lane->iddq > 0 && group->iddq >= 0) {
+			if (group->iddq != 0)
+				value &= ~(1 << lane->iddq);
+			else
+				value |= 1 << lane->iddq;
+		}
+
+		padctl_writel(padctl, value, lane->offset);
+	}
+
+	return 0;
+}
+
+static int
+tegra_xusb_padctl_config_apply(struct tegra_xusb_padctl *padctl,
+			       struct tegra_xusb_padctl_config *config)
+{
+	unsigned int i;
+
+	for (i = 0; i < config->num_groups; i++) {
+		const struct tegra_xusb_padctl_group *group;
+		int err;
+
+		group = &config->groups[i];
+
+		err = tegra_xusb_padctl_group_apply(padctl, group);
+		if (err < 0) {
+			error("failed to apply group %s: %d",
+			      group->name, err);
+			continue;
+		}
+	}
+
+	return 0;
+}
+
+static int
+tegra_xusb_padctl_config_parse_dt(struct tegra_xusb_padctl *padctl,
+				  struct tegra_xusb_padctl_config *config,
+				  const void *fdt, int node)
+{
+	int subnode;
+
+	config->name = fdt_get_name(fdt, node, NULL);
+
+	fdt_for_each_subnode(fdt, subnode, node) {
+		struct tegra_xusb_padctl_group *group;
+		int err;
+
+		group = &config->groups[config->num_groups];
+
+		err = tegra_xusb_padctl_group_parse_dt(padctl, group, fdt,
+						       subnode);
+		if (err < 0) {
+			error("failed to parse group %s", group->name);
+			return err;
+		}
+
+		config->num_groups++;
+	}
+
+	return 0;
+}
+
+static int tegra_xusb_padctl_parse_dt(struct tegra_xusb_padctl *padctl,
+				      const void *fdt, int node)
+{
+	int subnode, err;
+
+	err = fdt_get_resource(fdt, node, "reg", 0, &padctl->regs);
+	if (err < 0) {
+		error("registers not found");
+		return err;
+	}
+
+	fdt_for_each_subnode(fdt, subnode, node) {
+		struct tegra_xusb_padctl_config *config = &padctl->config;
+
+		err = tegra_xusb_padctl_config_parse_dt(padctl, config, fdt,
+							subnode);
+		if (err < 0) {
+			error("failed to parse entry %s: %d",
+			      config->name, err);
+			continue;
+		}
+	}
+
+	return 0;
+}
+
+struct tegra_xusb_padctl padctl;
+
+int tegra_xusb_process_nodes(const void *fdt, int nodes[], unsigned int count,
+	const struct tegra_xusb_padctl_soc *socdata)
+{
+	unsigned int i;
+	int err;
+
+	for (i = 0; i < count; i++) {
+		if (!fdtdec_get_is_enabled(fdt, nodes[i]))
+			continue;
+
+		padctl.socdata = socdata;
+
+		err = tegra_xusb_padctl_parse_dt(&padctl, fdt, nodes[i]);
+		if (err < 0) {
+			error("failed to parse DT: %d", err);
+			continue;
+		}
+
+		/* deassert XUSB padctl reset */
+		reset_set_enable(PERIPH_ID_XUSB_PADCTL, 0);
+
+		err = tegra_xusb_padctl_config_apply(&padctl, &padctl.config);
+		if (err < 0) {
+			error("failed to apply pinmux: %d", err);
+			continue;
+		}
+
+		/* only a single instance is supported */
+		break;
+	}
+
+	return 0;
+}
diff --git a/arch/arm/mach-tegra/xusb-padctl-common.h b/arch/arm/mach-tegra/xusb-padctl-common.h
new file mode 100644
index 0000000..f44790a
--- /dev/null
+++ b/arch/arm/mach-tegra/xusb-padctl-common.h
@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) 2014-2015, NVIDIA CORPORATION.  All rights reserved.
+ *
+ * SPDX-License-Identifier: GPL-2.0
+ */
+
+#ifndef _TEGRA_XUSB_PADCTL_COMMON_H_
+#define _TEGRA_XUSB_PADCTL_COMMON_H_
+
+#include <common.h>
+#include <fdtdec.h>
+
+#include <asm/io.h>
+#include <asm/arch-tegra/xusb-padctl.h>
+
+struct tegra_xusb_padctl_lane {
+	const char *name;
+
+	unsigned int offset;
+	unsigned int shift;
+	unsigned int mask;
+	unsigned int iddq;
+
+	const unsigned int *funcs;
+	unsigned int num_funcs;
+};
+
+struct tegra_xusb_phy_ops {
+	int (*prepare)(struct tegra_xusb_phy *phy);
+	int (*enable)(struct tegra_xusb_phy *phy);
+	int (*disable)(struct tegra_xusb_phy *phy);
+	int (*unprepare)(struct tegra_xusb_phy *phy);
+};
+
+struct tegra_xusb_phy {
+	unsigned int type;
+	const struct tegra_xusb_phy_ops *ops;
+	struct tegra_xusb_padctl *padctl;
+};
+
+struct tegra_xusb_padctl_pin {
+	const struct tegra_xusb_padctl_lane *lane;
+
+	unsigned int func;
+	int iddq;
+};
+
+#define MAX_GROUPS 5
+#define MAX_PINS 7
+
+struct tegra_xusb_padctl_group {
+	const char *name;
+
+	const char *pins[MAX_PINS];
+	unsigned int num_pins;
+
+	const char *func;
+	int iddq;
+};
+
+struct tegra_xusb_padctl_soc {
+	const struct tegra_xusb_padctl_lane *lanes;
+	unsigned int num_lanes;
+	const char *const *functions;
+	unsigned int num_functions;
+	struct tegra_xusb_phy *phys;
+	unsigned int num_phys;
+};
+
+struct tegra_xusb_padctl_config {
+	const char *name;
+
+	struct tegra_xusb_padctl_group groups[MAX_GROUPS];
+	unsigned int num_groups;
+};
+
+struct tegra_xusb_padctl {
+	const struct tegra_xusb_padctl_soc *socdata;
+	struct tegra_xusb_padctl_config config;
+	struct fdt_resource regs;
+	unsigned int enable;
+
+};
+extern struct tegra_xusb_padctl padctl;
+
+static inline u32 padctl_readl(struct tegra_xusb_padctl *padctl,
+			       unsigned long offset)
+{
+	return readl(padctl->regs.start + offset);
+}
+
+static inline void padctl_writel(struct tegra_xusb_padctl *padctl,
+				 u32 value, unsigned long offset)
+{
+	writel(value, padctl->regs.start + offset);
+}
+
+int tegra_xusb_process_nodes(const void *fdt, int nodes[], unsigned int count,
+	const struct tegra_xusb_padctl_soc *socdata);
+
+#endif
diff --git a/arch/arm/mach-tegra/xusb-padctl.c b/arch/arm/mach-tegra/xusb-padctl-dummy.c
similarity index 100%
rename from arch/arm/mach-tegra/xusb-padctl.c
rename to arch/arm/mach-tegra/xusb-padctl-dummy.c
diff --git a/board/nvidia/jetson-tk1/jetson-tk1.c b/board/nvidia/jetson-tk1/jetson-tk1.c
index 3c21767..52425a8 100644
--- a/board/nvidia/jetson-tk1/jetson-tk1.c
+++ b/board/nvidia/jetson-tk1/jetson-tk1.c
@@ -11,7 +11,6 @@
 
 #include <asm/arch/gpio.h>
 #include <asm/arch/pinmux.h>
-#include <asm/arch-tegra/gpu.h>
 
 #include "pinmux-config-jetson-tk1.h"
 
@@ -80,10 +79,3 @@
 	return pci_eth_init(bis);
 }
 #endif /* PCI */
-
-int ft_board_setup(void *blob, bd_t *bd)
-{
-	gpu_enable_node(blob, "/gpu@0,57000000");
-
-	return 0;
-}
diff --git a/board/nvidia/p2371-2180/p2371-2180.c b/board/nvidia/p2371-2180/p2371-2180.c
index cf2dd0b..57f577d8 100644
--- a/board/nvidia/p2371-2180/p2371-2180.c
+++ b/board/nvidia/p2371-2180/p2371-2180.c
@@ -6,6 +6,7 @@
  */
 
 #include <common.h>
+#include <netdev.h>
 #include <i2c.h>
 #include <asm/arch/gpio.h>
 #include <asm/arch/pinmux.h>
@@ -49,3 +50,32 @@
 	pinmux_config_drvgrp_table(p2371_2180_drvgrps,
 				   ARRAY_SIZE(p2371_2180_drvgrps));
 }
+
+#ifdef CONFIG_PCI_TEGRA
+int tegra_pcie_board_init(void)
+{
+	struct udevice *dev;
+	uchar val;
+	int ret;
+
+	/* Turn on MAX77620 LDO1 to 1.05V for PEX power */
+	debug("%s: Set LDO1 for PEX power to 1.05V\n", __func__);
+	ret = i2c_get_chip_for_busnum(0, MAX77620_I2C_ADDR_7BIT, 1, &dev);
+	if (ret) {
+		printf("%s: Cannot find MAX77620 I2C chip\n", __func__);
+		return -1;
+	}
+	/* 0xCA for 1.05v, enabled: bit7:6 = 11 = enable, bit5:0 = voltage */
+	val = 0xCA;
+	ret = dm_i2c_write(dev, MAX77620_CNFG1_L1_REG, &val, 1);
+	if (ret)
+		printf("i2c_write 0 0x3c 0x25 failed: %d\n", ret);
+
+	return 0;
+}
+
+int board_eth_init(bd_t *bis)
+{
+	return pci_eth_init(bis);
+}
+#endif /* PCI */
diff --git a/board/nvidia/p2571/p2571.c b/board/nvidia/p2571/p2571.c
index d33e4d1..d80a7d0 100644
--- a/board/nvidia/p2571/p2571.c
+++ b/board/nvidia/p2571/p2571.c
@@ -11,7 +11,6 @@
 #include <asm/arch/pinmux.h>
 #include <asm/gpio.h>
 #include "max77620_init.h"
-#include <asm/arch-tegra/gpu.h>
 #include "pinmux-config-p2571.h"
 
 void pin_mux_mmc(void)
@@ -62,9 +61,3 @@
 	gpio_request(GPIO_PE4, "FAN_VDD");
 	gpio_direction_output(GPIO_PE4, 1);
 }
-
-int ft_board_setup(void *blob, bd_t *bd)
-{
-	gpu_enable_node(blob, "/gpu@0,57000000");
-	return 0;
-}
diff --git a/board/nvidia/venice2/venice2.c b/board/nvidia/venice2/venice2.c
index 3e2b9a7..c56ef12 100644
--- a/board/nvidia/venice2/venice2.c
+++ b/board/nvidia/venice2/venice2.c
@@ -8,7 +8,6 @@
 #include <common.h>
 #include <asm/arch/gpio.h>
 #include <asm/arch/pinmux.h>
-#include <asm/arch-tegra/gpu.h>
 #include "pinmux-config-venice2.h"
 
 /*
@@ -28,10 +27,3 @@
 	pinmux_config_drvgrp_table(venice2_drvgrps,
 				   ARRAY_SIZE(venice2_drvgrps));
 }
-
-int ft_board_setup(void *blob, bd_t *bd)
-{
-	gpu_enable_node(blob, "/gpu@0,57000000");
-
-	return 0;
-}
diff --git a/drivers/pci/pci_tegra.c b/drivers/pci/pci_tegra.c
index ebb959f..690896f 100644
--- a/drivers/pci/pci_tegra.c
+++ b/drivers/pci/pci_tegra.c
@@ -166,6 +166,9 @@
 #define RP_VEND_XP	0x00000F00
 #define  RP_VEND_XP_DL_UP	(1 << 30)
 
+#define RP_VEND_CTL2				0x00000FA8
+#define  RP_VEND_CTL2_PCA_ENABLE		(1 << 7)
+
 #define RP_PRIV_MISC	0x00000FE0
 #define  RP_PRIV_MISC_PRSNT_MAP_EP_PRSNT (0xE << 0)
 #define  RP_PRIV_MISC_PRSNT_MAP_EP_ABSNT (0xF << 0)
@@ -194,6 +197,7 @@
 	bool has_pex_bias_ctrl;
 	bool has_cml_clk;
 	bool has_gen2;
+	bool force_pca_enable;
 };
 
 struct tegra_pcie {
@@ -383,6 +387,7 @@
 		break;
 
 	case COMPAT_NVIDIA_TEGRA124_PCIE:
+	case COMPAT_NVIDIA_TEGRA210_PCIE:
 		switch (lanes) {
 		case 0x0000104:
 			debug("4x1, 1x1 configuration\n");
@@ -406,9 +411,34 @@
 static int tegra_pcie_parse_dt_ranges(const void *fdt, int node,
 				      struct tegra_pcie *pcie)
 {
+	int parent, na_parent, na_pcie, ns_pcie;
 	const u32 *ptr, *end;
 	int len;
 
+	parent = fdt_parent_offset(fdt, node);
+	if (parent < 0) {
+		error("Can't find PCI parent node\n");
+		return -FDT_ERR_NOTFOUND;
+	}
+
+	na_parent = fdt_address_cells(fdt, parent);
+	if (na_parent < 1) {
+		error("bad #address-cells for PCIE parent\n");
+		return -FDT_ERR_NOTFOUND;
+	}
+
+	na_pcie = fdt_address_cells(fdt, node);
+	if (na_pcie < 1) {
+		error("bad #address-cells for PCIE\n");
+		return -FDT_ERR_NOTFOUND;
+	}
+
+	ns_pcie = fdt_size_cells(fdt, node);
+	if (ns_pcie < 1) {
+		error("bad #size-cells for PCIE\n");
+		return -FDT_ERR_NOTFOUND;
+	}
+
 	ptr = fdt_getprop(fdt, node, "ranges", &len);
 	if (!ptr) {
 		error("missing \"ranges\" property");
@@ -437,11 +467,13 @@
 		}
 
 		if (res) {
-			res->start = fdt32_to_cpu(ptr[3]);
-			res->end = res->start + fdt32_to_cpu(ptr[5]);
+			int start_low = na_pcie + (na_parent - 1);
+			int size_low = na_pcie + na_parent + (ns_pcie - 1);
+			res->start = fdt32_to_cpu(ptr[start_low]);
+			res->end = res->start + fdt32_to_cpu(ptr[size_low]);
 		}
 
-		ptr += 3 + 1 + 2;
+		ptr += na_pcie + na_parent + ns_pcie;
 	}
 
 	debug("PCI regions:\n");
@@ -587,8 +619,6 @@
 		return err;
 	}
 
-	tegra_pcie_board_init();
-
 	err = tegra_powergate_sequence_power_up(TEGRA_POWERGATE_PCIE,
 						PERIPH_ID_PCIE);
 	if (err < 0) {
@@ -860,6 +890,7 @@
 
 static void tegra_pcie_port_enable(struct tegra_pcie_port *port)
 {
+	const struct tegra_pcie_soc *soc = port->pcie->soc;
 	unsigned long ctrl = tegra_pcie_port_get_pex_ctrl(port);
 	unsigned long value;
 
@@ -875,6 +906,12 @@
 	afi_writel(port->pcie, value, ctrl);
 
 	tegra_pcie_port_reset(port);
+
+	if (soc->force_pca_enable) {
+		value = rp_readl(port, RP_VEND_CTL2);
+		value |= RP_VEND_CTL2_PCA_ENABLE;
+		rp_writel(port, value, RP_VEND_CTL2);
+	}
 }
 
 static bool tegra_pcie_port_check_link(struct tegra_pcie_port *port)
@@ -972,6 +1009,7 @@
 	.has_pex_bias_ctrl = false,
 	.has_cml_clk = false,
 	.has_gen2 = false,
+	.force_pca_enable = false,
 };
 
 static const struct tegra_pcie_soc tegra30_pcie_soc = {
@@ -982,6 +1020,7 @@
 	.has_pex_bias_ctrl = true,
 	.has_cml_clk = true,
 	.has_gen2 = false,
+	.force_pca_enable = false,
 };
 
 static const struct tegra_pcie_soc tegra124_pcie_soc = {
@@ -992,11 +1031,31 @@
 	.has_pex_bias_ctrl = true,
 	.has_cml_clk = true,
 	.has_gen2 = true,
+	.force_pca_enable = false,
+};
+
+static const struct tegra_pcie_soc tegra210_pcie_soc = {
+	.num_ports = 2,
+	.pads_pll_ctl = PADS_PLL_CTL_TEGRA30,
+	.tx_ref_sel = PADS_PLL_CTL_TXCLKREF_BUF_EN,
+	.has_pex_clkreq_en = true,
+	.has_pex_bias_ctrl = true,
+	.has_cml_clk = true,
+	.has_gen2 = true,
+	.force_pca_enable = true,
 };
 
 static int process_nodes(const void *fdt, int nodes[], unsigned int count)
 {
 	unsigned int i;
+	uint64_t dram_end;
+	uint32_t pci_dram_size;
+
+	/* Clip PCI-accessible DRAM to 32-bits */
+	dram_end = ((uint64_t)NV_PA_SDRAM_BASE) + gd->ram_size;
+	if (dram_end > 0x100000000)
+		dram_end = 0x100000000;
+	pci_dram_size = dram_end - NV_PA_SDRAM_BASE;
 
 	for (i = 0; i < count; i++) {
 		const struct tegra_pcie_soc *soc;
@@ -1021,6 +1080,10 @@
 			soc = &tegra124_pcie_soc;
 			break;
 
+		case COMPAT_NVIDIA_TEGRA210_PCIE:
+			soc = &tegra210_pcie_soc;
+			break;
+
 		default:
 			error("unsupported compatible: %s",
 			      fdtdec_get_compatible(id));
@@ -1069,7 +1132,7 @@
 		pcie->hose.last_busno = 0;
 
 		pci_set_region(&pcie->hose.regions[0], NV_PA_SDRAM_BASE,
-			       NV_PA_SDRAM_BASE, gd->ram_size,
+			       NV_PA_SDRAM_BASE, pci_dram_size,
 			       PCI_REGION_MEM | PCI_REGION_SYS_MEMORY);
 
 		pci_set_region(&pcie->hose.regions[1], pcie->io.start,
@@ -1115,6 +1178,14 @@
 	const void *fdt = gd->fdt_blob;
 	int count, nodes[1];
 
+	tegra_pcie_board_init();
+
+	count = fdtdec_find_aliases_for_id(fdt, "pcie-controller",
+					   COMPAT_NVIDIA_TEGRA210_PCIE,
+					   nodes, ARRAY_SIZE(nodes));
+	if (process_nodes(fdt, nodes, count))
+		return;
+
 	count = fdtdec_find_aliases_for_id(fdt, "pcie-controller",
 					   COMPAT_NVIDIA_TEGRA124_PCIE,
 					   nodes, ARRAY_SIZE(nodes));
diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
index 7d7a9d0..a0dbd8b 100644
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -123,6 +123,13 @@
 	  be used to access the SPI NOR flash on platforms embedding this
 	  nVidia Tegra20/Tegra30 IP cores.
 
+config TEGRA210_QSPI
+	bool "nVidia Tegra210 QSPI driver"
+	help
+	  Enable the Tegra Quad-SPI (QSPI) driver for T210. This driver
+	  be used to access SPI chips on platforms embedding this
+	  NVIDIA Tegra210 IP core.
+
 config XILINX_SPI
 	bool "Xilinx SPI driver"
 	help
diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
index 637fea8..3eca745 100644
--- a/drivers/spi/Makefile
+++ b/drivers/spi/Makefile
@@ -46,6 +46,7 @@
 obj-$(CONFIG_TEGRA114_SPI) += tegra114_spi.o
 obj-$(CONFIG_TEGRA20_SFLASH) += tegra20_sflash.o
 obj-$(CONFIG_TEGRA20_SLINK) += tegra20_slink.o
+obj-$(CONFIG_TEGRA210_QSPI) += tegra210_qspi.o
 obj-$(CONFIG_TI_QSPI) += ti_qspi.o
 obj-$(CONFIG_XILINX_SPI) += xilinx_spi.o
 obj-$(CONFIG_ZYNQ_SPI) += zynq_spi.o
diff --git a/drivers/spi/tegra210_qspi.c b/drivers/spi/tegra210_qspi.c
new file mode 100644
index 0000000..6bbbe93
--- /dev/null
+++ b/drivers/spi/tegra210_qspi.c
@@ -0,0 +1,417 @@
+/*
+ * NVIDIA Tegra210 QSPI controller driver
+ *
+ * (C) Copyright 2015 NVIDIA Corporation <www.nvidia.com>
+ *
+ * SPDX-License-Identifier:     GPL-2.0+
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <asm/io.h>
+#include <asm/arch/clock.h>
+#include <asm/arch-tegra/clk_rst.h>
+#include <spi.h>
+#include <fdtdec.h>
+#include "tegra_spi.h"
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/* COMMAND1 */
+#define QSPI_CMD1_GO			BIT(31)
+#define QSPI_CMD1_M_S			BIT(30)
+#define QSPI_CMD1_MODE_MASK		GENMASK(1,0)
+#define QSPI_CMD1_MODE_SHIFT		28
+#define QSPI_CMD1_CS_SEL_MASK		GENMASK(1,0)
+#define QSPI_CMD1_CS_SEL_SHIFT		26
+#define QSPI_CMD1_CS_POL_INACTIVE0	BIT(22)
+#define QSPI_CMD1_CS_SW_HW		BIT(21)
+#define QSPI_CMD1_CS_SW_VAL		BIT(20)
+#define QSPI_CMD1_IDLE_SDA_MASK		GENMASK(1,0)
+#define QSPI_CMD1_IDLE_SDA_SHIFT	18
+#define QSPI_CMD1_BIDIR			BIT(17)
+#define QSPI_CMD1_LSBI_FE		BIT(16)
+#define QSPI_CMD1_LSBY_FE		BIT(15)
+#define QSPI_CMD1_BOTH_EN_BIT		BIT(14)
+#define QSPI_CMD1_BOTH_EN_BYTE		BIT(13)
+#define QSPI_CMD1_RX_EN			BIT(12)
+#define QSPI_CMD1_TX_EN			BIT(11)
+#define QSPI_CMD1_PACKED		BIT(5)
+#define QSPI_CMD1_BITLEN_MASK		GENMASK(4,0)
+#define QSPI_CMD1_BITLEN_SHIFT		0
+
+/* COMMAND2 */
+#define QSPI_CMD2_TX_CLK_TAP_DELAY	BIT(6)
+#define QSPI_CMD2_TX_CLK_TAP_DELAY_MASK	GENMASK(11,6)
+#define QSPI_CMD2_RX_CLK_TAP_DELAY	BIT(0)
+#define QSPI_CMD2_RX_CLK_TAP_DELAY_MASK	GENMASK(5,0)
+
+/* TRANSFER STATUS */
+#define QSPI_XFER_STS_RDY		BIT(30)
+
+/* FIFO STATUS */
+#define QSPI_FIFO_STS_CS_INACTIVE	BIT(31)
+#define QSPI_FIFO_STS_FRAME_END		BIT(30)
+#define QSPI_FIFO_STS_RX_FIFO_FLUSH	BIT(15)
+#define QSPI_FIFO_STS_TX_FIFO_FLUSH	BIT(14)
+#define QSPI_FIFO_STS_ERR		BIT(8)
+#define QSPI_FIFO_STS_TX_FIFO_OVF	BIT(7)
+#define QSPI_FIFO_STS_TX_FIFO_UNR	BIT(6)
+#define QSPI_FIFO_STS_RX_FIFO_OVF	BIT(5)
+#define QSPI_FIFO_STS_RX_FIFO_UNR	BIT(4)
+#define QSPI_FIFO_STS_TX_FIFO_FULL	BIT(3)
+#define QSPI_FIFO_STS_TX_FIFO_EMPTY	BIT(2)
+#define QSPI_FIFO_STS_RX_FIFO_FULL	BIT(1)
+#define QSPI_FIFO_STS_RX_FIFO_EMPTY	BIT(0)
+
+#define QSPI_TIMEOUT		1000
+
+struct qspi_regs {
+	u32 command1;	/* 000:QSPI_COMMAND1 register */
+	u32 command2;	/* 004:QSPI_COMMAND2 register */
+	u32 timing1;	/* 008:QSPI_CS_TIM1 register */
+	u32 timing2;	/* 00c:QSPI_CS_TIM2 register */
+	u32 xfer_status;/* 010:QSPI_TRANS_STATUS register */
+	u32 fifo_status;/* 014:QSPI_FIFO_STATUS register */
+	u32 tx_data;	/* 018:QSPI_TX_DATA register */
+	u32 rx_data;	/* 01c:QSPI_RX_DATA register */
+	u32 dma_ctl;	/* 020:QSPI_DMA_CTL register */
+	u32 dma_blk;	/* 024:QSPI_DMA_BLK register */
+	u32 rsvd[56];	/* 028-107 reserved */
+	u32 tx_fifo;	/* 108:QSPI_FIFO1 register */
+	u32 rsvd2[31];	/* 10c-187 reserved */
+	u32 rx_fifo;	/* 188:QSPI_FIFO2 register */
+	u32 spare_ctl;	/* 18c:QSPI_SPARE_CTRL register */
+};
+
+struct tegra210_qspi_priv {
+	struct qspi_regs *regs;
+	unsigned int freq;
+	unsigned int mode;
+	int periph_id;
+	int valid;
+	int last_transaction_us;
+};
+
+static int tegra210_qspi_ofdata_to_platdata(struct udevice *bus)
+{
+	struct tegra_spi_platdata *plat = bus->platdata;
+	const void *blob = gd->fdt_blob;
+	int node = bus->of_offset;
+
+	plat->base = dev_get_addr(bus);
+	plat->periph_id = clock_decode_periph_id(blob, node);
+
+	if (plat->periph_id == PERIPH_ID_NONE) {
+		debug("%s: could not decode periph id %d\n", __func__,
+		      plat->periph_id);
+		return -FDT_ERR_NOTFOUND;
+	}
+
+	/* Use 500KHz as a suitable default */
+	plat->frequency = fdtdec_get_int(blob, node, "spi-max-frequency",
+					500000);
+	plat->deactivate_delay_us = fdtdec_get_int(blob, node,
+					"spi-deactivate-delay", 0);
+	debug("%s: base=%#08lx, periph_id=%d, max-frequency=%d, deactivate_delay=%d\n",
+	      __func__, plat->base, plat->periph_id, plat->frequency,
+	      plat->deactivate_delay_us);
+
+	return 0;
+}
+
+static int tegra210_qspi_probe(struct udevice *bus)
+{
+	struct tegra_spi_platdata *plat = dev_get_platdata(bus);
+	struct tegra210_qspi_priv *priv = dev_get_priv(bus);
+
+	priv->regs = (struct qspi_regs *)plat->base;
+
+	priv->last_transaction_us = timer_get_us();
+	priv->freq = plat->frequency;
+	priv->periph_id = plat->periph_id;
+
+	return 0;
+}
+
+static int tegra210_qspi_claim_bus(struct udevice *bus)
+{
+	struct tegra210_qspi_priv *priv = dev_get_priv(bus);
+	struct qspi_regs *regs = priv->regs;
+
+	/* Change SPI clock to correct frequency, PLLP_OUT0 source */
+	clock_start_periph_pll(priv->periph_id, CLOCK_ID_PERIPH, priv->freq);
+
+	debug("%s: FIFO STATUS = %08x\n", __func__, readl(&regs->fifo_status));
+
+	/* Set master mode and sw controlled CS */
+	setbits_le32(&regs->command1, QSPI_CMD1_M_S | QSPI_CMD1_CS_SW_HW |
+		     (priv->mode << QSPI_CMD1_MODE_SHIFT));
+	debug("%s: COMMAND1 = %08x\n", __func__, readl(&regs->command1));
+
+	return 0;
+}
+
+/**
+ * Activate the CS by driving it LOW
+ *
+ * @param slave	Pointer to spi_slave to which controller has to
+ *		communicate with
+ */
+static void spi_cs_activate(struct udevice *dev)
+{
+	struct udevice *bus = dev->parent;
+	struct tegra_spi_platdata *pdata = dev_get_platdata(bus);
+	struct tegra210_qspi_priv *priv = dev_get_priv(bus);
+
+	/* If it's too soon to do another transaction, wait */
+	if (pdata->deactivate_delay_us &&
+	    priv->last_transaction_us) {
+		ulong delay_us;		/* The delay completed so far */
+		delay_us = timer_get_us() - priv->last_transaction_us;
+		if (delay_us < pdata->deactivate_delay_us)
+			udelay(pdata->deactivate_delay_us - delay_us);
+	}
+
+	clrbits_le32(&priv->regs->command1, QSPI_CMD1_CS_SW_VAL);
+}
+
+/**
+ * Deactivate the CS by driving it HIGH
+ *
+ * @param slave	Pointer to spi_slave to which controller has to
+ *		communicate with
+ */
+static void spi_cs_deactivate(struct udevice *dev)
+{
+	struct udevice *bus = dev->parent;
+	struct tegra_spi_platdata *pdata = dev_get_platdata(bus);
+	struct tegra210_qspi_priv *priv = dev_get_priv(bus);
+
+	setbits_le32(&priv->regs->command1, QSPI_CMD1_CS_SW_VAL);
+
+	/* Remember time of this transaction so we can honour the bus delay */
+	if (pdata->deactivate_delay_us)
+		priv->last_transaction_us = timer_get_us();
+
+	debug("Deactivate CS, bus '%s'\n", bus->name);
+}
+
+static int tegra210_qspi_xfer(struct udevice *dev, unsigned int bitlen,
+			     const void *data_out, void *data_in,
+			     unsigned long flags)
+{
+	struct udevice *bus = dev->parent;
+	struct tegra210_qspi_priv *priv = dev_get_priv(bus);
+	struct qspi_regs *regs = priv->regs;
+	u32 reg, tmpdout, tmpdin = 0;
+	const u8 *dout = data_out;
+	u8 *din = data_in;
+	int num_bytes, tm, ret;
+
+	debug("%s: slave %u:%u dout %p din %p bitlen %u\n",
+	      __func__, bus->seq, spi_chip_select(dev), dout, din, bitlen);
+	if (bitlen % 8)
+		return -1;
+	num_bytes = bitlen / 8;
+
+	ret = 0;
+
+	/* clear all error status bits */
+	reg = readl(&regs->fifo_status);
+	writel(reg, &regs->fifo_status);
+
+	/* flush RX/TX FIFOs */
+	setbits_le32(&regs->fifo_status,
+		     (QSPI_FIFO_STS_RX_FIFO_FLUSH |
+		      QSPI_FIFO_STS_TX_FIFO_FLUSH));
+
+	tm = QSPI_TIMEOUT;
+	while ((tm && readl(&regs->fifo_status) &
+		      (QSPI_FIFO_STS_RX_FIFO_FLUSH |
+		       QSPI_FIFO_STS_TX_FIFO_FLUSH))) {
+		tm--;
+		udelay(1);
+	}
+
+	if (!tm) {
+		printf("%s: timeout during QSPI FIFO flush!\n",
+		       __func__);
+		return -1;
+	}
+
+	/*
+	 * Notes:
+	 *   1. don't set LSBY_FE, so no need to swap bytes from/to TX/RX FIFOs;
+	 *   2. don't set RX_EN and TX_EN yet.
+	 *      (SW needs to make sure that while programming the blk_size,
+	 *       tx_en and rx_en bits must be zero)
+	 *      [TODO] I (Yen Lin) have problems when both RX/TX EN bits are set
+	 *	       i.e., both dout and din are not NULL.
+	 */
+	clrsetbits_le32(&regs->command1,
+			(QSPI_CMD1_LSBI_FE | QSPI_CMD1_LSBY_FE |
+			 QSPI_CMD1_RX_EN | QSPI_CMD1_TX_EN),
+			(spi_chip_select(dev) << QSPI_CMD1_CS_SEL_SHIFT));
+
+	/* set xfer size to 1 block (32 bits) */
+	writel(0, &regs->dma_blk);
+
+	if (flags & SPI_XFER_BEGIN)
+		spi_cs_activate(dev);
+
+	/* handle data in 32-bit chunks */
+	while (num_bytes > 0) {
+		int bytes;
+
+		tmpdout = 0;
+		bytes = (num_bytes > 4) ?  4 : num_bytes;
+
+		if (dout != NULL) {
+			memcpy((void *)&tmpdout, (void *)dout, bytes);
+			dout += bytes;
+			num_bytes -= bytes;
+			writel(tmpdout, &regs->tx_fifo);
+			setbits_le32(&regs->command1, QSPI_CMD1_TX_EN);
+		}
+
+		if (din != NULL)
+			setbits_le32(&regs->command1, QSPI_CMD1_RX_EN);
+
+		/* clear ready bit */
+		setbits_le32(&regs->xfer_status, QSPI_XFER_STS_RDY);
+
+		clrsetbits_le32(&regs->command1,
+				QSPI_CMD1_BITLEN_MASK << QSPI_CMD1_BITLEN_SHIFT,
+				(bytes * 8 - 1) << QSPI_CMD1_BITLEN_SHIFT);
+
+		/* Need to stabilize other reg bits before GO bit set.
+		 * As per the TRM:
+		 * "For successful operation at various freq combinations,
+		 * a minimum of 4-5 spi_clk cycle delay might be required
+		 * before enabling the PIO or DMA bits. The worst case delay
+		 * calculation can be done considering slowest qspi_clk as
+		 * 1MHz. Based on that 1us delay should be enough before
+		 * enabling PIO or DMA." Padded another 1us for safety.
+		 */
+		udelay(2);
+		setbits_le32(&regs->command1, QSPI_CMD1_GO);
+		udelay(1);
+
+		/*
+		 * Wait for SPI transmit FIFO to empty, or to time out.
+		 * The RX FIFO status will be read and cleared last
+		 */
+		for (tm = 0; tm < QSPI_TIMEOUT; ++tm) {
+			u32 fifo_status, xfer_status;
+
+			xfer_status = readl(&regs->xfer_status);
+			if (!(xfer_status & QSPI_XFER_STS_RDY))
+				continue;
+
+			fifo_status = readl(&regs->fifo_status);
+			if (fifo_status & QSPI_FIFO_STS_ERR) {
+				debug("%s: got a fifo error: ", __func__);
+				if (fifo_status & QSPI_FIFO_STS_TX_FIFO_OVF)
+					debug("tx FIFO overflow ");
+				if (fifo_status & QSPI_FIFO_STS_TX_FIFO_UNR)
+					debug("tx FIFO underrun ");
+				if (fifo_status & QSPI_FIFO_STS_RX_FIFO_OVF)
+					debug("rx FIFO overflow ");
+				if (fifo_status & QSPI_FIFO_STS_RX_FIFO_UNR)
+					debug("rx FIFO underrun ");
+				if (fifo_status & QSPI_FIFO_STS_TX_FIFO_FULL)
+					debug("tx FIFO full ");
+				if (fifo_status & QSPI_FIFO_STS_TX_FIFO_EMPTY)
+					debug("tx FIFO empty ");
+				if (fifo_status & QSPI_FIFO_STS_RX_FIFO_FULL)
+					debug("rx FIFO full ");
+				if (fifo_status & QSPI_FIFO_STS_RX_FIFO_EMPTY)
+					debug("rx FIFO empty ");
+				debug("\n");
+				break;
+			}
+
+			if (!(fifo_status & QSPI_FIFO_STS_RX_FIFO_EMPTY)) {
+				tmpdin = readl(&regs->rx_fifo);
+				if (din != NULL) {
+					memcpy(din, &tmpdin, bytes);
+					din += bytes;
+					num_bytes -= bytes;
+				}
+			}
+			break;
+		}
+
+		if (tm >= QSPI_TIMEOUT)
+			ret = tm;
+
+		/* clear ACK RDY, etc. bits */
+		writel(readl(&regs->fifo_status), &regs->fifo_status);
+	}
+
+	if (flags & SPI_XFER_END)
+		spi_cs_deactivate(dev);
+
+	debug("%s: transfer ended. Value=%08x, fifo_status = %08x\n",
+	      __func__, tmpdin, readl(&regs->fifo_status));
+
+	if (ret) {
+		printf("%s: timeout during SPI transfer, tm %d\n",
+		       __func__, ret);
+		return -1;
+	}
+
+	return ret;
+}
+
+static int tegra210_qspi_set_speed(struct udevice *bus, uint speed)
+{
+	struct tegra_spi_platdata *plat = bus->platdata;
+	struct tegra210_qspi_priv *priv = dev_get_priv(bus);
+
+	if (speed > plat->frequency)
+		speed = plat->frequency;
+	priv->freq = speed;
+	debug("%s: regs=%p, speed=%d\n", __func__, priv->regs, priv->freq);
+
+	return 0;
+}
+
+static int tegra210_qspi_set_mode(struct udevice *bus, uint mode)
+{
+	struct tegra210_qspi_priv *priv = dev_get_priv(bus);
+
+	priv->mode = mode;
+	debug("%s: regs=%p, mode=%d\n", __func__, priv->regs, priv->mode);
+
+	return 0;
+}
+
+static const struct dm_spi_ops tegra210_qspi_ops = {
+	.claim_bus	= tegra210_qspi_claim_bus,
+	.xfer		= tegra210_qspi_xfer,
+	.set_speed	= tegra210_qspi_set_speed,
+	.set_mode	= tegra210_qspi_set_mode,
+	/*
+	 * cs_info is not needed, since we require all chip selects to be
+	 * in the device tree explicitly
+	 */
+};
+
+static const struct udevice_id tegra210_qspi_ids[] = {
+	{ .compatible = "nvidia,tegra210-qspi" },
+	{ }
+};
+
+U_BOOT_DRIVER(tegra210_qspi) = {
+	.name = "tegra210-qspi",
+	.id = UCLASS_SPI,
+	.of_match = tegra210_qspi_ids,
+	.ops = &tegra210_qspi_ops,
+	.ofdata_to_platdata = tegra210_qspi_ofdata_to_platdata,
+	.platdata_auto_alloc_size = sizeof(struct tegra_spi_platdata),
+	.priv_auto_alloc_size = sizeof(struct tegra210_qspi_priv),
+	.per_child_auto_alloc_size = sizeof(struct spi_slave),
+	.probe = tegra210_qspi_probe,
+};
diff --git a/include/configs/jetson-tk1.h b/include/configs/jetson-tk1.h
index e87a010..f63957a 100644
--- a/include/configs/jetson-tk1.h
+++ b/include/configs/jetson-tk1.h
@@ -78,6 +78,4 @@
 #define CONFIG_ARMV7_SECURE_BASE		0xfff00000
 #define CONFIG_ARMV7_SECURE_RESERVE_SIZE	0x00100000
 
-#define CONFIG_OF_BOARD_SETUP
-
 #endif /* __CONFIG_H */
diff --git a/include/configs/p2371-2180.h b/include/configs/p2371-2180.h
index 3bdf196..94f8085 100644
--- a/include/configs/p2371-2180.h
+++ b/include/configs/p2371-2180.h
@@ -53,6 +53,16 @@
 #define CONFIG_USB_HOST_ETHER
 #define CONFIG_USB_ETHER_ASIX
 
+/* PCI host support */
+#define CONFIG_PCI
+#define CONFIG_PCI_TEGRA
+#define CONFIG_PCI_PNP
+#define CONFIG_CMD_PCI
+#define CONFIG_CMD_PCI_ENUM
+
+/* PCI networking support */
+#define CONFIG_RTL8169
+
 /* General networking support */
 #define CONFIG_CMD_DHCP
 
diff --git a/include/configs/p2571.h b/include/configs/p2571.h
index c65d3e5..a5de411 100644
--- a/include/configs/p2571.h
+++ b/include/configs/p2571.h
@@ -60,6 +60,4 @@
 #include "tegra-common-usb-gadget.h"
 #include "tegra-common-post.h"
 
-#define CONFIG_OF_BOARD_SETUP
-
 #endif /* _P2571_H */
diff --git a/include/configs/tegra-common.h b/include/configs/tegra-common.h
index a005e6a..32cc39b 100644
--- a/include/configs/tegra-common.h
+++ b/include/configs/tegra-common.h
@@ -143,4 +143,6 @@
 #define CONFIG_FAT_WRITE
 #endif
 
+#define CONFIG_OF_SYSTEM_SETUP
+
 #endif /* _TEGRA_COMMON_H_ */
diff --git a/include/configs/venice2.h b/include/configs/venice2.h
index 0fc8cf7..a374cd9 100644
--- a/include/configs/venice2.h
+++ b/include/configs/venice2.h
@@ -60,6 +60,4 @@
 #include "tegra-common-usb-gadget.h"
 #include "tegra-common-post.h"
 
-#define CONFIG_OF_BOARD_SETUP
-
 #endif /* __CONFIG_H */
diff --git a/include/fdtdec.h b/include/fdtdec.h
index 0e36664..3a6ff1f 100644
--- a/include/fdtdec.h
+++ b/include/fdtdec.h
@@ -130,6 +130,7 @@
 	COMPAT_NVIDIA_TEGRA30_SDMMC,	/* Tegra30 SDMMC controller */
 	COMPAT_NVIDIA_TEGRA20_SDMMC,	/* Tegra20 SDMMC controller */
 	COMPAT_NVIDIA_TEGRA124_PCIE,	/* Tegra 124 PCIe controller */
+	COMPAT_NVIDIA_TEGRA210_PCIE,	/* Tegra 210 PCIe controller */
 	COMPAT_NVIDIA_TEGRA30_PCIE,	/* Tegra 30 PCIe controller */
 	COMPAT_NVIDIA_TEGRA20_PCIE,	/* Tegra 20 PCIe controller */
 	COMPAT_NVIDIA_TEGRA124_XUSB_PADCTL,
diff --git a/lib/fdtdec.c b/lib/fdtdec.c
index c1b5177..f1849bc 100644
--- a/lib/fdtdec.c
+++ b/lib/fdtdec.c
@@ -36,6 +36,7 @@
 	COMPAT(NVIDIA_TEGRA30_SDMMC, "nvidia,tegra30-sdhci"),
 	COMPAT(NVIDIA_TEGRA20_SDMMC, "nvidia,tegra20-sdhci"),
 	COMPAT(NVIDIA_TEGRA124_PCIE, "nvidia,tegra124-pcie"),
+	COMPAT(NVIDIA_TEGRA210_PCIE, "nvidia,tegra210-pcie"),
 	COMPAT(NVIDIA_TEGRA30_PCIE, "nvidia,tegra30-pcie"),
 	COMPAT(NVIDIA_TEGRA20_PCIE, "nvidia,tegra20-pcie"),
 	COMPAT(NVIDIA_TEGRA124_XUSB_PADCTL, "nvidia,tegra124-xusb-padctl"),