Patchwork [U-Boot,4/9] Tegra: T30: Add common Tegra30 CPU files

login
register
mail settings
Submitter Tom Warren
Date Sept. 12, 2012, 10:10 p.m.
Message ID <1347487855-27077-5-git-send-email-twarren@nvidia.com>
Download mbox | patch
Permalink /patch/183460/
State Changes Requested
Delegated to: Tom Rini
Headers show

Comments

Tom Warren - Sept. 12, 2012, 10:10 p.m.
Signed-off-by: Tom Warren <twarren@nvidia.com>
---
 arch/arm/cpu/tegra30-common/Makefile        |   51 ++
 arch/arm/cpu/tegra30-common/ap30.c          |   98 +++
 arch/arm/cpu/tegra30-common/board.c         |  141 ++++
 arch/arm/cpu/tegra30-common/clock.c         | 1099 +++++++++++++++++++++++++++
 arch/arm/cpu/tegra30-common/funcmux.c       |   74 ++
 arch/arm/cpu/tegra30-common/lowlevel_init.S |   42 +
 arch/arm/cpu/tegra30-common/pinmux.c        |  507 ++++++++++++
 arch/arm/cpu/tegra30-common/sys_info.c      |   35 +
 arch/arm/cpu/tegra30-common/timer.c         |  111 +++
 9 files changed, 2158 insertions(+), 0 deletions(-)
 create mode 100644 arch/arm/cpu/tegra30-common/Makefile
 create mode 100644 arch/arm/cpu/tegra30-common/ap30.c
 create mode 100644 arch/arm/cpu/tegra30-common/board.c
 create mode 100644 arch/arm/cpu/tegra30-common/clock.c
 create mode 100644 arch/arm/cpu/tegra30-common/funcmux.c
 create mode 100644 arch/arm/cpu/tegra30-common/lowlevel_init.S
 create mode 100644 arch/arm/cpu/tegra30-common/pinmux.c
 create mode 100644 arch/arm/cpu/tegra30-common/sys_info.c
 create mode 100644 arch/arm/cpu/tegra30-common/timer.c
Stephen Warren - Sept. 13, 2012, 10:08 p.m.
On 09/12/2012 04:10 PM, Tom Warren wrote:

> diff --git a/arch/arm/cpu/tegra30-common/board.c b/arch/arm/cpu/tegra30-common/board.c

> +unsigned int query_sdram_size(void)
> +{
> +	struct pmc_ctlr *const pmc = (struct pmc_ctlr *)NV_PA_PMC_BASE;
> +	u32 reg;
> +
> +	reg = readl(&pmc->pmc_scratch20);
> +	debug("pmc->pmc_scratch20 (ODMData) = 0x%08x\n", reg);
> +
> +	/* bits 31:28 in OdmData are used for RAM size  */
> +	switch ((reg) >> 28) {
> +	case 1:
> +		return 0x10000000;	/* 256 MB */
> +	case 2:
> +		return 0x20000000;	/* 512 MB */
> +	case 4:
> +		return 0x40000000;	/* 1GB */
> +	case 8:
> +		return 0x7ff00000;	/* 2GB - 1MB */
> +	default:
> +		return 0x40000000;	/* 1GB */
> +	}
> +}

According to our wiki, there's also a 3=768MB option here, although I
have no idea if that's really true. I guess we can add it if we need it.

> +static int uart_configs[] = {
> +	FUNCMUX_UART1_ULPI_UART2,	/* UARTA */
> +	FUNCMUX_UART2_IRDA,
> +	-1,
> +	FUNCMUX_UART4_GMC,
> +	-1,
> +};

I guess I'm repeating what I wrote for the funcmux.[ch] change, but
those FUNCMUX_* enum names don't make sense on Tegra30.

> diff --git a/arch/arm/cpu/tegra30-common/clock.c b/arch/arm/cpu/tegra30-common/clock.c

> +/*
> + * This array translates a periph_id to a periphc_internal_id
> + *
> + * Not present/matched up:
> + *	uint vi_sensor;	 _VI_SENSOR_0,		0x1A8
> + *	SPDIF - which is both 0x08 and 0x0c
> + *
> + */
> +#define NONE(name) (-1)
> +#define OFFSET(name, value) PERIPHC_ ## name
> +static s8 periph_id_to_internal_id[PERIPH_ID_COUNT] = {
> +	/* Low word: 31:0 */
> +	NONE(CPU),
> +	NONE(COP),
> +	NONE(TRIGSYS),
> +	NONE(RESERVED3),
> +	NONE(RESERVED4),
> +	NONE(TMR),
> +	PERIPHC_UART1,
> +	PERIPHC_UART2,	/* and vfir 0x68 */

Oh, there's a mapping table anyway. In that case, I would definitely
recommend aligning the enum order with the kernel to allow easier DT
handling in the future.

Still, as you mentioned in another email, this is something we can do
later since it doesn't change any interface to anything outside U-Boot.

> +#ifdef CONFIG_OF_CONTROL
> +/*
> + * Convert a device tree clock ID to our peripheral ID. They are mostly
> + * the same but we are very cautious so we check that a valid clock ID is
> + * provided.
> + *
> + * @param clk_id	Clock ID according to tegra20 device tree binding
> + * @return peripheral ID, or PERIPH_ID_NONE if the clock ID is invalid
> + */
> +static enum periph_id clk_id_to_periph_id(int clk_id)
> +{
> +	if (clk_id > 95)
> +		return PERIPH_ID_NONE;
> +
> +	switch (clk_id) {
> +	case 1:
> +	case 2:
> +	case 7:
> +	case 10:
> +	case 20:
> +	case 30:
> +	case 35:
> +	case 49:
> +	case 56:
> +	case 74:
> +	case 76:
> +	case 77:
> +	case 78:
> +	case 79:
> +	case 80:
> +	case 81:
> +	case 82:
> +	case 83:
> +	case 91:
> +	case 95:
> +		return PERIPH_ID_NONE;
> +	default:
> +		return clk_id;
> +	}
> +}

This is something that would need to be validated against the Tegra30
device tree bindings for the clock module. I guess since
CONFIG_OF_CONTROL isn't enabled now, it's somewhat OK to defer this
until later, but a comment here indicating that fact would be useful.

> diff --git a/arch/arm/cpu/tegra30-common/funcmux.c b/arch/arm/cpu/tegra30-common/funcmux.c

> +int funcmux_select(enum periph_id id, int config)
> +{
> +	int bad_config = config != FUNCMUX_DEFAULT;
> +
> +	switch (id) {
> +	case PERIPH_ID_UART1:
> +		switch (config) {
> +		case FUNCMUX_UART1_ULPI_UART2:
> +			pinmux_set_func(PINGRP_ULPI_DATA0, PMUX_FUNC_UARTA); txd
> +			pinmux_set_func(PINGRP_ULPI_DATA1, PMUX_FUNC_UARTA); rxd
> +			pinmux_set_func(PINGRP_ULPI_DATA2, PMUX_FUNC_UARTA); cts
> +			pinmux_set_func(PINGRP_ULPI_DATA3, PMUX_FUNC_UARTA); rts
> +			pinmux_set_func(PINGRP_ULPI_DATA4, PMUX_FUNC_UARTA); ri
> +			pinmux_set_func(PINGRP_ULPI_DATA5, PMUX_FUNC_UARTA); dcd
> +			pinmux_set_func(PINGRP_ULPI_DATA6, PMUX_FUNC_UARTA); dsr
> +			pinmux_set_func(PINGRP_UART2_RTS_N, PMUX_FUNC_UARTA); txd
> +			pinmux_set_func(PINGRP_UART2_CTS_N, PMUX_FUNC_UARTA); rxd

I've augmented the lines above with comments re: what signals are
selected onto each line when those functions are selected.

Note that RXD/TXD are duplicated. I suspect you're just getting lucky
that when rxd is selected on both ULPI_DATA1 and UART2_CTS_N, that it
happens to take the input from the correct one of those two pins.

Looking at the schematic for Cardhu A02, you only want to configure
ULPI_DATA[3:0] for UARTA. All those other pins are used for purposes
other than UART.

And somewhat as an aside, this is why I wonder if a funcmux-style API is
still a good idea; you could easily have the following sets of UARTA
signals in use:

RXD+TXD
RXD+TXD+RTS+CTS
RXD+TXD+RTS+CTS+RI+DCD+DSR+DTR (or perhaps subsets of those last 3?)

... and for each of those 3 sets of signals, any of the individual
signals can actually be muxed onto one of n different pins, where n is
at least 2, and up to 4 in many cases. That's perhaps thousands of
combinations just for UARTA!

Calling pinmux.c APIs directly from the board file seems much simpler,
and avoids a level of abstraction that doesn't really exist in HW.
Simon Glass - Sept. 18, 2012, 7:40 p.m.
Hi Tom,

On Wed, Sep 12, 2012 at 3:10 PM, Tom Warren <twarren.nvidia@gmail.com> wrote:
> Signed-off-by: Tom Warren <twarren@nvidia.com>
> ---
>  arch/arm/cpu/tegra30-common/Makefile        |   51 ++
>  arch/arm/cpu/tegra30-common/ap30.c          |   98 +++
>  arch/arm/cpu/tegra30-common/board.c         |  141 ++++
>  arch/arm/cpu/tegra30-common/clock.c         | 1099 +++++++++++++++++++++++++++

Again I feel that a lot of the code here is common. We actually got
away with identical code for T30 (even the tables!). Agreed that won't
really work, but it should hows much can be common.

Regards,
Simon

Patch

diff --git a/arch/arm/cpu/tegra30-common/Makefile b/arch/arm/cpu/tegra30-common/Makefile
new file mode 100644
index 0000000..6efc554
--- /dev/null
+++ b/arch/arm/cpu/tegra30-common/Makefile
@@ -0,0 +1,51 @@ 
+#
+# (C) Copyright 2010-2012 Nvidia Corporation.
+#
+# (C) Copyright 2000-2008
+# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+#
+# See file CREDITS for list of people who contributed to this
+# project.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; either version 2 of
+# the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+# MA 02111-1307 USA
+#
+
+include $(TOPDIR)/config.mk
+
+# The AVP is ARMv4T architecture so we must use special compiler
+# flags for any startup files it might use.
+
+LIB	= $(obj)lib$(SOC)-common.o
+
+SOBJS += lowlevel_init.o
+COBJS-y	+= ap30.o board.o clock.o funcmux.o pinmux.o sys_info.o timer.o
+
+SRCS	:= $(SOBJS:.o=.S) $(COBJS-y:.o=.c)
+OBJS	:= $(addprefix $(obj),$(SOBJS) $(COBJS-y))
+
+all:	$(obj).depend $(LIB)
+
+$(LIB):	$(OBJS)
+	$(call cmd_link_o_target, $(OBJS))
+
+#########################################################################
+
+# defines $(obj).depend target
+include $(SRCTREE)/rules.mk
+
+sinclude $(obj).depend
+
+#########################################################################
diff --git a/arch/arm/cpu/tegra30-common/ap30.c b/arch/arm/cpu/tegra30-common/ap30.c
new file mode 100644
index 0000000..4f07c4e
--- /dev/null
+++ b/arch/arm/cpu/tegra30-common/ap30.c
@@ -0,0 +1,98 @@ 
+/*
+* (C) Copyright 2010-2012
+* NVIDIA Corporation <www.nvidia.com>
+*
+* See file CREDITS for list of people who contributed to this
+* project.
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License as
+* published by the Free Software Foundation; either version 2 of
+* the License, or (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software
+* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+* MA 02111-1307 USA
+*/
+
+#include <asm/io.h>
+#include <asm/arch/ap30.h>
+#include <asm/arch/fuse.h>
+#include <asm/arch/gp_padctrl.h>
+#include <asm/arch/pmc.h>
+#include <asm/arch/scu.h>
+#include <asm/arch/warmboot.h>
+#include <common.h>
+
+static void enable_scu(void)
+{
+	struct scu_ctlr *scu = (struct scu_ctlr *)NV_PA_ARM_PERIPHBASE;
+	u32 reg;
+
+	/* If SCU already setup/enabled, return */
+	if (readl(&scu->scu_ctrl) & SCU_CTRL_ENABLE)
+		return;
+
+	/* Invalidate all ways for all processors */
+	writel(0xFFFF, &scu->scu_inv_all);
+
+	/* Enable SCU - bit 0 */
+	reg = readl(&scu->scu_ctrl);
+	reg |= SCU_CTRL_ENABLE;
+	writel(reg, &scu->scu_ctrl);
+}
+
+static u32 get_odmdata(void)
+{
+	/*
+	 * ODMDATA is stored in the BCT in IRAM by the BootROM.
+	 * The BCT start and size are stored in the BIT in IRAM.
+	 * Read the data @ bct_start + (bct_size - 12). This works
+	 * on T20 and T30 BCTs, which are locked down. If this changes
+	 * in new chips (T114, etc.), we can revisit this algorithm.
+	 */
+
+	u32 bct_start, odmdata;
+
+	bct_start = readl(T30_BASE_PA_SRAM + NVBOOTINFOTABLE_BCTPTR);
+	odmdata = readl(bct_start + BCT_ODMDATA_OFFSET);
+
+	return odmdata;
+}
+
+static void init_pmc_scratch(void)
+{
+	struct pmc_ctlr *const pmc = (struct pmc_ctlr *)NV_PA_PMC_BASE;
+	u32 odmdata;
+	int i;
+
+	/* SCRATCH0 is initialized by the boot ROM and shouldn't be cleared */
+	for (i = 0; i < 23; i++)
+		writel(0, &pmc->pmc_scratch1+i);
+
+	/* ODMDATA is for kernel use to determine RAM size, LP config, etc. */
+	odmdata = get_odmdata();
+	writel(odmdata, &pmc->pmc_scratch20);
+}
+
+void s_init(void)
+{
+	/* Init PMC scratch memory */
+	init_pmc_scratch();
+
+	enable_scu();
+
+	/* enable SMP mode and FW for CPU0, by writing to Auxiliary Ctl reg */
+	asm volatile(
+		"mrc	p15, 0, r0, c1, c0, 1\n"
+		"orr	r0, r0, #0x41\n"
+		"mcr	p15, 0, r0, c1, c0, 1\n");
+
+	/* FIXME: should have ap30's L2 disabled too? */
+}
diff --git a/arch/arm/cpu/tegra30-common/board.c b/arch/arm/cpu/tegra30-common/board.c
new file mode 100644
index 0000000..6fe017d
--- /dev/null
+++ b/arch/arm/cpu/tegra30-common/board.c
@@ -0,0 +1,141 @@ 
+/*
+ *  (C) Copyright 2010-2012
+ *  NVIDIA Corporation <www.nvidia.com>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <asm/arch/clock.h>
+#include <asm/arch/funcmux.h>
+#include <asm/arch/pmc.h>
+#include <asm/arch/sys_proto.h>
+#include <asm/arch/tegra30.h>
+#include <asm/arch/warmboot.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+enum {
+	/* UARTs which we can enable */
+	UARTA	= 1 << 0,
+	UARTB	= 1 << 1,
+	UARTD	= 1 << 3,
+	UART_COUNT = 4,
+};
+
+/*
+ * Boot ROM initializes the odmdata in APBDEV_PMC_SCRATCH20_0,
+ * so we are using this value to identify memory size.
+ */
+
+unsigned int query_sdram_size(void)
+{
+	struct pmc_ctlr *const pmc = (struct pmc_ctlr *)NV_PA_PMC_BASE;
+	u32 reg;
+
+	reg = readl(&pmc->pmc_scratch20);
+	debug("pmc->pmc_scratch20 (ODMData) = 0x%08x\n", reg);
+
+	/* bits 31:28 in OdmData are used for RAM size  */
+	switch ((reg) >> 28) {
+	case 1:
+		return 0x10000000;	/* 256 MB */
+	case 2:
+		return 0x20000000;	/* 512 MB */
+	case 4:
+		return 0x40000000;	/* 1GB */
+	case 8:
+		return 0x7ff00000;	/* 2GB - 1MB */
+	default:
+		return 0x40000000;	/* 1GB */
+	}
+}
+
+int dram_init(void)
+{
+	/* We do not initialise DRAM here. We just query the size */
+	gd->ram_size = query_sdram_size();
+	return 0;
+}
+
+#ifdef CONFIG_DISPLAY_BOARDINFO
+int checkboard(void)
+{
+	printf("Board: %s\n", sysinfo.board_string);
+	return 0;
+}
+#endif	/* CONFIG_DISPLAY_BOARDINFO */
+
+static int uart_configs[] = {
+	FUNCMUX_UART1_ULPI_UART2,	/* UARTA */
+	FUNCMUX_UART2_IRDA,
+	-1,
+	FUNCMUX_UART4_GMC,
+	-1,
+};
+
+/**
+ * Set up the specified uarts
+ *
+ * @param uarts_ids	Mask containing UARTs to init (UARTx)
+ */
+static void setup_uarts(int uart_ids)
+{
+	static enum periph_id id_for_uart[] = {
+		PERIPH_ID_UART1,
+		PERIPH_ID_UART2,
+		PERIPH_ID_UART3,
+		PERIPH_ID_UART4,
+	};
+	size_t i;
+
+	for (i = 0; i < UART_COUNT; i++) {
+		if (uart_ids & (1 << i)) {
+			enum periph_id id = id_for_uart[i];
+
+			funcmux_select(id, uart_configs[i]);
+			clock_ll_start_uart(id);
+		}
+	}
+}
+
+void board_init_uart_f(void)
+{
+	int uart_ids = 0;	/* bit mask of which UART ids to enable */
+
+#ifdef CONFIG_TEGRA_ENABLE_UARTA
+	uart_ids |= UARTA;
+#endif
+#ifdef CONFIG_TEGRA_ENABLE_UARTB
+	uart_ids |= UARTB;
+#endif
+#ifdef CONFIG_TEGRA_ENABLE_UARTD
+	uart_ids |= UARTD;
+#endif
+	setup_uarts(uart_ids);
+}
+
+#ifndef CONFIG_SYS_DCACHE_OFF
+void enable_caches(void)
+{
+	/* Enable D-cache. I-cache is already enabled in start.S */
+	dcache_enable();
+}
+#endif
diff --git a/arch/arm/cpu/tegra30-common/clock.c b/arch/arm/cpu/tegra30-common/clock.c
new file mode 100644
index 0000000..dd5450f
--- /dev/null
+++ b/arch/arm/cpu/tegra30-common/clock.c
@@ -0,0 +1,1099 @@ 
+/*
+ * Copyright (c) 2011 The Chromium OS Authors.
+ * Copyright (C) 2010-2012 NVIDIA Corporation <www.nvidia.com>
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/* Tegra30 Clock control functions */
+#include <asm/io.h>
+#include <asm/arch/clk_rst.h>
+#include <asm/arch/clock.h>
+#include <asm/arch/timer.h>
+#include <asm/arch/tegra30.h>
+#include <common.h>
+#include <div64.h>
+#include <fdtdec.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/*
+ * This is our record of the current clock rate of each clock. We don't
+ * fill all of these in since we are only really interested in clocks which
+ * we use as parents.
+ */
+static unsigned pll_rate[CLOCK_ID_COUNT];
+
+/*
+ * The oscillator frequency is fixed to one of four set values. Based on this
+ * the other clocks are set up appropriately.
+ */
+static unsigned osc_freq[CLOCK_OSC_FREQ_COUNT] = {
+	13000000,
+	19200000,
+	12000000,
+	26000000,
+};
+
+/*
+ * Clock types that we can use as a source. The Tegra3 has muxes for the
+ * peripheral clocks, and in most cases there are four options for the clock
+ * source. This gives us a clock 'type' and exploits what commonality exists
+ * in the device.
+ *
+ * Letters are obvious, except for T which means CLK_M, and S which means the
+ * clock derived from 32KHz. Beware that CLK_M (also called OSC in the
+ * datasheet) and PLL_M are different things. The former is the basic
+ * clock supplied to the SOC from an external oscillator. The latter is the
+ * memory clock PLL.
+ *
+ * See definitions in clock_id in the header file.
+ */
+enum clock_type_id {
+	CLOCK_TYPE_AXPT,	/* PLL_A, PLL_X, PLL_P, CLK_M */
+	CLOCK_TYPE_MCPA,	/* and so on */
+	CLOCK_TYPE_MCPT,
+	CLOCK_TYPE_PCM,
+	CLOCK_TYPE_PCMT,
+	CLOCK_TYPE_PDCT,
+	CLOCK_TYPE_ACPT,
+	CLOCK_TYPE_ASPTE,
+	CLOCK_TYPE_PMDACD2T,
+	CLOCK_TYPE_PCST,
+
+	CLOCK_TYPE_COUNT,
+	CLOCK_TYPE_NONE = -1,	/* invalid clock type */
+};
+
+/* return 1 if a peripheral ID is in range */
+#define clock_type_id_isvalid(id) ((id) >= 0 && \
+		(id) < CLOCK_TYPE_COUNT)
+
+char pllp_valid = 1;	/* PLLP is set up correctly */
+
+enum {
+	CLOCK_MAX_MUX	= 8	/* number of source options for each clock */
+};
+
+enum {
+	MASK_BITS_31_30	= 2,	/* num of bits used to specify clock source */
+	MASK_BITS_31_29,
+	MASK_BITS_29_28,
+};
+
+/*
+ * Clock source mux for each clock type. This just converts our enum into
+ * a list of mux sources for use by the code.
+ *
+ * Note:
+ *  The extra column in each clock source array is used to store the mask
+ *  bits in its register for the source.
+ */
+#define CLK(x) CLOCK_ID_ ## x
+static enum clock_id clock_source[CLOCK_TYPE_COUNT][CLOCK_MAX_MUX+1] = {
+	{ CLK(AUDIO),	CLK(XCPU),	CLK(PERIPH),	CLK(OSC),
+		CLK(NONE),	CLK(NONE),	CLK(NONE),	CLK(NONE),
+		MASK_BITS_31_30},
+	{ CLK(MEMORY),	CLK(CGENERAL),	CLK(PERIPH),	CLK(AUDIO),
+		CLK(NONE),	CLK(NONE),	CLK(NONE),	CLK(NONE),
+		MASK_BITS_31_30},
+	{ CLK(MEMORY),	CLK(CGENERAL),	CLK(PERIPH),	CLK(OSC),
+		CLK(NONE),	CLK(NONE),	CLK(NONE),	CLK(NONE),
+		MASK_BITS_31_30},
+	{ CLK(PERIPH),	CLK(CGENERAL),	CLK(MEMORY),	CLK(NONE),
+		CLK(NONE),	CLK(NONE),	CLK(NONE),	CLK(NONE),
+		MASK_BITS_31_30},
+	{ CLK(PERIPH),	CLK(CGENERAL),	CLK(MEMORY),	CLK(OSC),
+		CLK(NONE),	CLK(NONE),	CLK(NONE),	CLK(NONE),
+		MASK_BITS_31_30},
+	{ CLK(PERIPH),	CLK(DISPLAY),	CLK(CGENERAL),	CLK(OSC),
+		CLK(NONE),	CLK(NONE),	CLK(NONE),	CLK(NONE),
+		MASK_BITS_31_30},
+	{ CLK(AUDIO),	CLK(CGENERAL),	CLK(PERIPH),	CLK(OSC),
+		CLK(NONE),	CLK(NONE),	CLK(NONE),	CLK(NONE),
+		MASK_BITS_31_30},
+	{ CLK(AUDIO),	CLK(SFROM32KHZ),	CLK(PERIPH),	CLK(OSC),
+		CLK(EPCI),	CLK(NONE),	CLK(NONE),	CLK(NONE),
+		MASK_BITS_31_29},
+	{ CLK(PERIPH),	CLK(MEMORY),	CLK(DISPLAY),	CLK(AUDIO),
+		CLK(CGENERAL),	CLK(DISPLAY2),	CLK(OSC),	CLK(NONE),
+		MASK_BITS_31_29},
+	{ CLK(PERIPH),	CLK(CGENERAL),	CLK(SFROM32KHZ),	CLK(OSC),
+		CLK(NONE),	CLK(NONE),	CLK(NONE),	CLK(NONE),
+		MASK_BITS_29_28}
+};
+
+/* return 1 if a periphc_internal_id is in range */
+#define periphc_internal_id_isvalid(id) ((id) >= 0 && \
+		(id) < PERIPHC_COUNT)
+
+/*
+ * Clock type for each peripheral clock source. We put the name in each
+ * record just so it is easy to match things up
+ */
+#define TYPE(name, type) type
+static enum clock_type_id clock_periph_type[PERIPHC_COUNT] = {
+	/* 0x00 */
+	TYPE(PERIPHC_I2S1,	CLOCK_TYPE_AXPT),
+	TYPE(PERIPHC_I2S2,	CLOCK_TYPE_AXPT),
+	TYPE(PERIPHC_SPDIF_OUT,	CLOCK_TYPE_AXPT),
+	TYPE(PERIPHC_SPDIF_IN,	CLOCK_TYPE_PCM),
+	TYPE(PERIPHC_PWM,	CLOCK_TYPE_PCST),
+	TYPE(PERIPHC_NONE,	CLOCK_TYPE_NONE),
+	TYPE(PERIPHC_SBC2,	CLOCK_TYPE_PCMT),
+	TYPE(PERIPHC_SBC3,	CLOCK_TYPE_PCMT),
+
+	/* 0x08 */
+	TYPE(PERIPHC_NONE,	CLOCK_TYPE_NONE),
+	TYPE(PERIPHC_I2C1,	CLOCK_TYPE_PCMT),
+	TYPE(PERIPHC_DVC_I2C,	CLOCK_TYPE_PCMT),
+	TYPE(PERIPHC_NONE,	CLOCK_TYPE_NONE),
+	TYPE(PERIPHC_NONE,	CLOCK_TYPE_NONE),
+	TYPE(PERIPHC_SBC1,	CLOCK_TYPE_PCMT),
+	TYPE(PERIPHC_DISP1,	CLOCK_TYPE_PMDACD2T),
+	TYPE(PERIPHC_DISP2,	CLOCK_TYPE_PMDACD2T),
+
+	/* 0x10 */
+	TYPE(PERIPHC_CVE,	CLOCK_TYPE_PDCT),
+	TYPE(PERIPHC_NONE,	CLOCK_TYPE_NONE),
+	TYPE(PERIPHC_VI,	CLOCK_TYPE_MCPA),
+	TYPE(PERIPHC_NONE,	CLOCK_TYPE_NONE),
+	TYPE(PERIPHC_SDMMC1,	CLOCK_TYPE_PCMT),
+	TYPE(PERIPHC_SDMMC2,	CLOCK_TYPE_PCMT),
+	TYPE(PERIPHC_G3D,	CLOCK_TYPE_MCPA),
+	TYPE(PERIPHC_G2D,	CLOCK_TYPE_MCPA),
+
+	/* 0x18 */
+	TYPE(PERIPHC_NDFLASH,	CLOCK_TYPE_PCMT),
+	TYPE(PERIPHC_SDMMC4,	CLOCK_TYPE_PCMT),
+	TYPE(PERIPHC_VFIR,	CLOCK_TYPE_PCMT),
+	TYPE(PERIPHC_EPP,	CLOCK_TYPE_MCPA),
+	TYPE(PERIPHC_MPE,	CLOCK_TYPE_MCPA),
+	TYPE(PERIPHC_MIPI,	CLOCK_TYPE_PCMT),
+	TYPE(PERIPHC_UART1,	CLOCK_TYPE_PCMT),
+	TYPE(PERIPHC_UART2,	CLOCK_TYPE_PCMT),
+
+	/* 0x20 */
+	TYPE(PERIPHC_HOST1X,	CLOCK_TYPE_MCPA),
+	TYPE(PERIPHC_NONE,	CLOCK_TYPE_NONE),
+	TYPE(PERIPHC_TVO,	CLOCK_TYPE_PDCT),
+	TYPE(PERIPHC_HDMI,	CLOCK_TYPE_PMDACD2T),
+	TYPE(PERIPHC_NONE,	CLOCK_TYPE_NONE),
+	TYPE(PERIPHC_TVDAC,	CLOCK_TYPE_PDCT),
+	TYPE(PERIPHC_I2C2,	CLOCK_TYPE_PCMT),
+	TYPE(PERIPHC_EMC,	CLOCK_TYPE_MCPT),
+
+	/* 0x28 */
+	TYPE(PERIPHC_UART3,	CLOCK_TYPE_PCMT),
+	TYPE(PERIPHC_NONE,	CLOCK_TYPE_NONE),
+	TYPE(PERIPHC_VI,	CLOCK_TYPE_MCPA),
+	TYPE(PERIPHC_NONE,	CLOCK_TYPE_NONE),
+	TYPE(PERIPHC_NONE,	CLOCK_TYPE_NONE),
+	TYPE(PERIPHC_SBC4,	CLOCK_TYPE_PCMT),
+	TYPE(PERIPHC_I2C3,	CLOCK_TYPE_PCMT),
+	TYPE(PERIPHC_SDMMC3,	CLOCK_TYPE_PCMT),
+
+	/* 0x30 */
+	TYPE(PERIPHC_UART4,	CLOCK_TYPE_PCMT),
+	TYPE(PERIPHC_UART5,	CLOCK_TYPE_PCMT),
+	TYPE(PERIPHC_VDE,	CLOCK_TYPE_PCMT),
+	TYPE(PERIPHC_OWR,	CLOCK_TYPE_PCMT),
+	TYPE(PERIPHC_NOR,	CLOCK_TYPE_PCMT),
+	TYPE(PERIPHC_CSITE,	CLOCK_TYPE_PCMT),
+	TYPE(PERIPHC_I2S0,	CLOCK_TYPE_AXPT),
+	TYPE(PERIPHC_NONE,	CLOCK_TYPE_NONE),
+
+	/* 0x38h */
+	TYPE(PERIPHC_G3D2,	CLOCK_TYPE_MCPA),
+	TYPE(PERIPHC_MSELECT,	CLOCK_TYPE_PCMT),
+	TYPE(PERIPHC_TSENSOR,	CLOCK_TYPE_PCM),
+	TYPE(PERIPHC_I2S3,	CLOCK_TYPE_AXPT),
+	TYPE(PERIPHC_I2S4,	CLOCK_TYPE_AXPT),
+	TYPE(PERIPHC_I2C4,	CLOCK_TYPE_PCMT),
+	TYPE(PERIPHC_SBC5,	CLOCK_TYPE_PCMT),
+	TYPE(PERIPHC_SBC6,	CLOCK_TYPE_PCMT),
+
+	/* 0x40 */
+	TYPE(PERIPHC_AUDIO,	CLOCK_TYPE_ACPT),
+	TYPE(PERIPHC_NONE,	CLOCK_TYPE_NONE),
+	TYPE(PERIPHC_DAM0,	CLOCK_TYPE_ACPT),
+	TYPE(PERIPHC_DAM1,	CLOCK_TYPE_ACPT),
+	TYPE(PERIPHC_DAM2,	CLOCK_TYPE_ACPT),
+	TYPE(PERIPHC_HDA2CODEC2X, CLOCK_TYPE_PCMT),
+	TYPE(PERIPHC_ACTMON,	CLOCK_TYPE_PCM),
+	TYPE(PERIPHC_EXTPERIPH1, CLOCK_TYPE_ASPTE),
+
+	/* 0x48 */
+	TYPE(PERIPHC_EXTPERIPH2, CLOCK_TYPE_ASPTE),
+	TYPE(PERIPHC_EXTPERIPH3, CLOCK_TYPE_ASPTE),
+	TYPE(PERIPHC_NANDSPEED,	CLOCK_TYPE_PCMT),
+	TYPE(PERIPHC_I2CSLOW,	CLOCK_TYPE_PCMT),
+	TYPE(PERIPHC_SYS,	CLOCK_TYPE_NONE),
+	TYPE(PERIPHC_SPEEDO,	CLOCK_TYPE_PCMT),
+	TYPE(PERIPHC_NONE,	CLOCK_TYPE_NONE),
+	TYPE(PERIPHC_NONE,	CLOCK_TYPE_NONE),
+
+	/* 0x50 */
+	TYPE(PERIPHC_SATAOOB,	CLOCK_TYPE_PCMT),
+	TYPE(PERIPHC_SATA,	CLOCK_TYPE_PCMT),
+	TYPE(PERIPHC_HDA,	CLOCK_TYPE_PCMT),
+};
+
+/*
+ * This array translates a periph_id to a periphc_internal_id
+ *
+ * Not present/matched up:
+ *	uint vi_sensor;	 _VI_SENSOR_0,		0x1A8
+ *	SPDIF - which is both 0x08 and 0x0c
+ *
+ */
+#define NONE(name) (-1)
+#define OFFSET(name, value) PERIPHC_ ## name
+static s8 periph_id_to_internal_id[PERIPH_ID_COUNT] = {
+	/* Low word: 31:0 */
+	NONE(CPU),
+	NONE(COP),
+	NONE(TRIGSYS),
+	NONE(RESERVED3),
+	NONE(RESERVED4),
+	NONE(TMR),
+	PERIPHC_UART1,
+	PERIPHC_UART2,	/* and vfir 0x68 */
+
+	/* 8 */
+	NONE(GPIO),
+	PERIPHC_SDMMC2,
+	NONE(SPDIF),		/* 0x08 and 0x0c, unclear which to use */
+	PERIPHC_I2S1,
+	PERIPHC_I2C1,
+	PERIPHC_NDFLASH,
+	PERIPHC_SDMMC1,
+	PERIPHC_SDMMC4,
+
+	/* 16 */
+	NONE(RESERVED16),
+	PERIPHC_PWM,
+	PERIPHC_I2S2,
+	PERIPHC_EPP,
+	PERIPHC_VI,
+	PERIPHC_G2D,
+	NONE(USBD),
+	NONE(ISP),
+
+	/* 24 */
+	PERIPHC_G3D,
+	NONE(RESERVED25),
+	PERIPHC_DISP2,
+	PERIPHC_DISP1,
+	PERIPHC_HOST1X,
+	NONE(VCP),
+	PERIPHC_I2S0,
+	NONE(CACHE2),
+
+	/* Middle word: 63:32 */
+	NONE(MEM),
+	NONE(AHBDMA),
+	NONE(APBDMA),
+	NONE(RESERVED35),
+	NONE(RESERVED36),
+	NONE(STAT_MON),
+	NONE(RESERVED38),
+	NONE(RESERVED39),
+
+	/* 40 */
+	NONE(KFUSE),
+	NONE(SBC1),	/* SBC1, 0x34, is this SPI1? */
+	PERIPHC_NOR,
+	NONE(RESERVED43),
+	PERIPHC_SBC2,
+	NONE(RESERVED45),
+	PERIPHC_SBC3,
+	PERIPHC_DVC_I2C,
+
+	/* 48 */
+	NONE(DSI),
+	PERIPHC_TVO,	/* also CVE 0x40 */
+	PERIPHC_MIPI,
+	PERIPHC_HDMI,
+	NONE(CSI),
+	PERIPHC_TVDAC,
+	PERIPHC_I2C2,
+	PERIPHC_UART3,
+
+	/* 56 */
+	NONE(RESERVED56),
+	PERIPHC_EMC,
+	NONE(USB2),
+	NONE(USB3),
+	PERIPHC_MPE,
+	PERIPHC_VDE,
+	NONE(BSEA),
+	NONE(BSEV),
+
+	/* Upper word 95:64 */
+	PERIPHC_SPEEDO,
+	PERIPHC_UART4,
+	PERIPHC_UART5,
+	PERIPHC_I2C3,
+	PERIPHC_SBC4,
+	PERIPHC_SDMMC3,
+	NONE(PCIE),
+	PERIPHC_OWR,
+
+	/* 72 */
+	NONE(AFI),
+	PERIPHC_CSITE,
+	NONE(PCIEXCLK),
+	NONE(AVPUCQ),
+	NONE(RESERVED76),
+	NONE(RESERVED77),
+	NONE(RESERVED78),
+	NONE(DTV),
+
+	/* 80 */
+	PERIPHC_NANDSPEED,
+	PERIPHC_I2CSLOW,
+	NONE(DSIB),
+	NONE(RESERVED83),
+	NONE(IRAMA),
+	NONE(IRAMB),
+	NONE(IRAMC),
+	NONE(IRAMD),
+
+	/* 88 */
+	NONE(CRAM2),
+	NONE(RESERVED89),
+	NONE(MDOUBLER),
+	NONE(RESERVED91),
+	NONE(SUSOUT),
+	NONE(RESERVED93),
+	NONE(RESERVED94),
+	NONE(RESERVED95),
+
+	/* V word: 31:0 */
+	NONE(CPUG),
+	NONE(CPULP),
+	PERIPHC_G3D2,
+	PERIPHC_MSELECT,
+	PERIPHC_TSENSOR,
+	PERIPHC_I2S3,
+	PERIPHC_I2S4,
+	PERIPHC_I2C4,
+
+	/* 08 */
+	PERIPHC_SBC5,
+	PERIPHC_SBC6,
+	PERIPHC_AUDIO,
+	NONE(APBIF),
+	PERIPHC_DAM0,
+	PERIPHC_DAM1,
+	PERIPHC_DAM2,
+	PERIPHC_HDA2CODEC2X,
+
+	/* 16 */
+	NONE(ATOMICS),
+	NONE(RESERVED17),
+	NONE(RESERVED18),
+	NONE(RESERVED19),
+	NONE(RESERVED20),
+	NONE(RESERVED21),
+	NONE(RESERVED22),
+	PERIPHC_ACTMON,
+
+	/* 24 */
+	NONE(RESERVED24),
+	NONE(RESERVED25),
+	NONE(RESERVED26),
+	NONE(RESERVED27),
+	PERIPHC_SATA,
+	PERIPHC_HDA,
+	NONE(RESERVED30),
+	NONE(RESERVED31),
+
+	/* W word: 31:0 */
+	NONE(HDA2HDMICODEC),
+	NONE(SATACOLD),
+	NONE(RESERVED0_PCIERX0),
+	NONE(RESERVED1_PCIERX1),
+	NONE(RESERVED2_PCIERX2),
+	NONE(RESERVED3_PCIERX3),
+	NONE(RESERVED4_PCIERX4),
+	NONE(RESERVED5_PCIERX5),
+
+	/* 40 */
+	NONE(CEC),
+	NONE(RESERVED6_PCIE2),
+	NONE(RESERVED7_EMC),
+	NONE(RESERVED8_HDMI),
+	NONE(RESERVED9_SATA),
+	NONE(RESERVED10_MIPI),
+	NONE(EX_RESERVED46),
+	NONE(EX_RESERVED47),
+};
+
+/*
+ * Get the oscillator frequency, from the corresponding hardware configuration
+ * field.
+ */
+enum clock_osc_freq clock_get_osc_freq(void)
+{
+	struct clk_rst_ctlr *clkrst =
+			(struct clk_rst_ctlr *)NV_PA_CLK_RST_BASE;
+	u32 reg;
+
+	reg = readl(&clkrst->crc_osc_ctrl);
+	return (reg & OSC_FREQ_MASK) >> OSC_FREQ_SHIFT;
+}
+
+int clock_get_osc_bypass(void)
+{
+	struct clk_rst_ctlr *clkrst =
+			(struct clk_rst_ctlr *)NV_PA_CLK_RST_BASE;
+	u32 reg;
+
+	reg = readl(&clkrst->crc_osc_ctrl);
+	return (reg & OSC_XOBP_MASK) >> OSC_XOBP_SHIFT;
+}
+
+/* Returns a pointer to the registers of the given pll */
+static struct clk_pll *get_pll(enum clock_id clkid)
+{
+	struct clk_rst_ctlr *clkrst =
+			(struct clk_rst_ctlr *)NV_PA_CLK_RST_BASE;
+
+	assert(clock_id_is_pll(clkid));
+	return &clkrst->crc_pll[clkid];
+}
+
+int clock_ll_read_pll(enum clock_id clkid, u32 *divm, u32 *divn,
+		u32 *divp, u32 *cpcon, u32 *lfcon)
+{
+	struct clk_pll *pll = get_pll(clkid);
+	u32 data;
+
+	assert(clkid != CLOCK_ID_USB);
+
+	/* Safety check, adds to code size but is small */
+	if (!clock_id_is_pll(clkid) || clkid == CLOCK_ID_USB)
+		return -1;
+	data = readl(&pll->pll_base);
+	*divm = (data & PLL_DIVM_MASK) >> PLL_DIVM_SHIFT;
+	*divn = (data & PLL_DIVN_MASK) >> PLL_DIVN_SHIFT;
+	*divp = (data & PLL_DIVP_MASK) >> PLL_DIVP_SHIFT;
+	data = readl(&pll->pll_misc);
+	*cpcon = (data & PLL_CPCON_MASK) >> PLL_CPCON_SHIFT;
+	*lfcon = (data & PLL_LFCON_MASK) >> PLL_LFCON_SHIFT;
+	return 0;
+}
+
+unsigned long clock_start_pll(enum clock_id clkid, u32 divm, u32 divn,
+		u32 divp, u32 cpcon, u32 lfcon)
+{
+	struct clk_pll *pll = get_pll(clkid);
+	u32 data;
+
+	/*
+	 * We cheat by treating all PLL (except PLLU) in the same fashion.
+	 * This works only because:
+	 * - same fields are always mapped at same offsets, except DCCON
+	 * - DCCON is always 0, doesn't conflict
+	 * - M,N, P of PLLP values are ignored for PLLP
+	 */
+	data = (cpcon << PLL_CPCON_SHIFT) | (lfcon << PLL_LFCON_SHIFT);
+	writel(data, &pll->pll_misc);
+
+	data = (divm << PLL_DIVM_SHIFT) | (divn << PLL_DIVN_SHIFT) |
+			(0 << PLL_BYPASS_SHIFT) | (1 << PLL_ENABLE_SHIFT);
+
+	if (clkid == CLOCK_ID_USB)
+		data |= divp << PLLU_VCO_FREQ_SHIFT;
+	else
+		data |= divp << PLL_DIVP_SHIFT;
+	writel(data, &pll->pll_base);
+
+	/* calculate the stable time */
+	return timer_get_us() + CLOCK_PLL_STABLE_DELAY_US;
+}
+
+/* Returns a pointer to the clock source register for a peripheral */
+static u32 *get_periph_source_reg(enum periph_id periph_id)
+{
+	struct clk_rst_ctlr *clkrst =
+			(struct clk_rst_ctlr *)NV_PA_CLK_RST_BASE;
+	enum periphc_internal_id internal_id;
+
+	/* Coresight is a special case */
+	if (periph_id == PERIPH_ID_CSI)
+		return &clkrst->crc_clk_src[PERIPH_ID_CSI+1];
+
+	assert(periph_id >= PERIPH_ID_FIRST && periph_id < PERIPH_ID_COUNT);
+	internal_id = periph_id_to_internal_id[periph_id];
+	assert(internal_id != -1);
+	if (internal_id >= PERIPHC_VW_FIRST) {
+		internal_id -= PERIPHC_VW_FIRST;
+		return &clkrst->crc_clk_src_vw[internal_id];
+	} else
+		return &clkrst->crc_clk_src[internal_id];
+}
+
+void clock_ll_set_source_divisor(enum periph_id periph_id, unsigned source,
+			      unsigned divisor)
+{
+	u32 *reg = get_periph_source_reg(periph_id);
+	u32 value;
+
+	value = readl(reg);
+
+	value &= ~OUT_CLK_SOURCE_MASK;
+	value |= source << OUT_CLK_SOURCE_SHIFT;
+
+	value &= ~OUT_CLK_DIVISOR_MASK;
+	value |= divisor << OUT_CLK_DIVISOR_SHIFT;
+
+	writel(value, reg);
+}
+
+void clock_ll_set_source(enum periph_id periph_id, unsigned source)
+{
+	u32 *reg = get_periph_source_reg(periph_id);
+
+	clrsetbits_le32(reg, OUT_CLK_SOURCE_MASK,
+			source << OUT_CLK_SOURCE_SHIFT);
+}
+
+/**
+ * Given the parent's rate and the required rate for the children, this works
+ * out the peripheral clock divider to use, in 7.1 binary format.
+ *
+ * @param divider_bits	number of divider bits (8 or 16)
+ * @param parent_rate	clock rate of parent clock in Hz
+ * @param rate		required clock rate for this clock
+ * @return divider which should be used
+ */
+static int clk_get_divider(unsigned divider_bits, unsigned long parent_rate,
+			   unsigned long rate)
+{
+	u64 divider = parent_rate * 2;
+	unsigned max_divider = 1 << divider_bits;
+
+	divider += rate - 1;
+	do_div(divider, rate);
+
+	if ((s64)divider - 2 < 0)
+		return 0;
+
+	if ((s64)divider - 2 >= max_divider)
+		return -1;
+
+	return divider - 2;
+}
+
+/**
+ * Given the parent's rate and the divider in 7.1 format, this works out the
+ * resulting peripheral clock rate.
+ *
+ * @param parent_rate	clock rate of parent clock in Hz
+ * @param divider which should be used in 7.1 format
+ * @return effective clock rate of peripheral
+ */
+static unsigned long get_rate_from_divider(unsigned long parent_rate,
+					   int divider)
+{
+	u64 rate;
+
+	rate = (u64)parent_rate * 2;
+	do_div(rate, divider + 2);
+	return rate;
+}
+
+unsigned long clock_get_periph_rate(enum periph_id periph_id,
+		enum clock_id parent)
+{
+	u32 *reg = get_periph_source_reg(periph_id);
+
+	return get_rate_from_divider(pll_rate[parent],
+		(readl(reg) & OUT_CLK_DIVISOR_MASK) >> OUT_CLK_DIVISOR_SHIFT);
+}
+
+/**
+ * Find the best available 7.1 format divisor given a parent clock rate and
+ * required child clock rate. This function assumes that a second-stage
+ * divisor is available which can divide by powers of 2 from 1 to 256.
+ *
+ * @param divider_bits	number of divider bits (8 or 16)
+ * @param parent_rate	clock rate of parent clock in Hz
+ * @param rate		required clock rate for this clock
+ * @param extra_div	value for the second-stage divisor (not set if this
+ *			function returns -1.
+ * @return divider which should be used, or -1 if nothing is valid
+ *
+ */
+static int find_best_divider(unsigned divider_bits, unsigned long parent_rate,
+			     unsigned long rate, int *extra_div)
+{
+	int shift;
+	int best_divider = -1;
+	int best_error = rate;
+
+	/* try dividers from 1 to 256 and find closest match */
+	for (shift = 0; shift <= 8 && best_error > 0; shift++) {
+		unsigned divided_parent = parent_rate >> shift;
+		int divider = clk_get_divider(divider_bits, divided_parent,
+					      rate);
+		unsigned effective_rate = get_rate_from_divider(divided_parent,
+						       divider);
+		int error = rate - effective_rate;
+
+		/* Given a valid divider, look for the lowest error */
+		if (divider != -1 && error < best_error) {
+			best_error = error;
+			*extra_div = 1 << shift;
+			best_divider = divider;
+		}
+	}
+
+	/* return what we found - *extra_div will already be set */
+	return best_divider;
+}
+
+/**
+ * Given a peripheral ID and the required source clock, this returns which
+ * value should be programmed into the source mux for that peripheral.
+ *
+ * There is special code here to handle the one source type with 5 sources.
+ *
+ * @param periph_id	peripheral to start
+ * @param source	PLL id of required parent clock
+ * @param mux_bits	Set to number of bits in mux register: 2 or 4
+ * @param divider_bits	Set to number of divider bits (8 or 16)
+ * @return mux value (0-4, or -1 if not found)
+ */
+static int get_periph_clock_source(enum periph_id periph_id,
+		enum clock_id parent, int *mux_bits, int *divider_bits)
+{
+	enum clock_type_id type;
+	enum periphc_internal_id internal_id;
+	int mux;
+
+	assert(clock_periph_id_isvalid(periph_id));
+
+	internal_id = periph_id_to_internal_id[periph_id];
+	assert(periphc_internal_id_isvalid(internal_id));
+
+	type = clock_periph_type[internal_id];
+	assert(clock_type_id_isvalid(type));
+
+	*mux_bits = clock_source[type][CLOCK_MAX_MUX];
+
+	for (mux = 0; mux < CLOCK_MAX_MUX; mux++)
+		if (clock_source[type][mux] == parent)
+			return mux;
+
+	/* if we get here, either us or the caller has made a mistake */
+	printf("Caller requested bad clock: periph=%d, parent=%d\n", periph_id,
+		parent);
+	return -1;
+}
+
+/**
+ * Adjust peripheral PLL to use the given divider and source.
+ *
+ * @param periph_id	peripheral to adjust
+ * @param source	Source number (0-3 or 0-7)
+ * @param mux_bits	Number of mux bits (2 or 4)
+ * @param divider	Required divider in 7.1 or 15.1 format
+ * @return 0 if ok, -1 on error (requesting a parent clock which is not valid
+ *		for this peripheral)
+ */
+static int adjust_periph_pll(enum periph_id periph_id, int source,
+			     int mux_bits, unsigned divider)
+{
+	u32 *reg = get_periph_source_reg(periph_id);
+
+	clrsetbits_le32(reg, OUT_CLK_DIVISOR_MASK,
+			divider << OUT_CLK_DIVISOR_SHIFT);
+	udelay(1);
+
+	/* work out the source clock and set it */
+	if (source < 0)
+		return -1;
+	if (mux_bits == 4) {
+		clrsetbits_le32(reg, OUT_CLK_SOURCE4_MASK,
+			source << OUT_CLK_SOURCE4_SHIFT);
+	} else {
+		clrsetbits_le32(reg, OUT_CLK_SOURCE_MASK,
+			source << OUT_CLK_SOURCE_SHIFT);
+	}
+	udelay(2);
+	return 0;
+}
+
+unsigned clock_adjust_periph_pll_div(enum periph_id periph_id,
+		enum clock_id parent, unsigned rate, int *extra_div)
+{
+	unsigned effective_rate;
+	int mux_bits, source;
+	int divider, divider_bits = 0;
+
+	/* work out the source clock and set it */
+	source = get_periph_clock_source(periph_id, parent, &mux_bits,
+					 &divider_bits);
+
+	if (extra_div)
+		divider = find_best_divider(divider_bits, pll_rate[parent],
+					    rate, extra_div);
+	else
+		divider = clk_get_divider(divider_bits, pll_rate[parent],
+					  rate);
+	assert(divider >= 0);
+	if (adjust_periph_pll(periph_id, source, mux_bits, divider))
+		return -1U;
+	debug("periph %d, rate=%d, reg=%p = %x\n", periph_id, rate,
+		get_periph_source_reg(periph_id),
+		readl(get_periph_source_reg(periph_id)));
+
+	/* Check what we ended up with. This shouldn't matter though */
+	effective_rate = clock_get_periph_rate(periph_id, parent);
+	if (extra_div)
+		effective_rate /= *extra_div;
+	if (rate != effective_rate)
+		debug("Requested clock rate %u not honored (got %u)\n",
+		       rate, effective_rate);
+	return effective_rate;
+}
+
+unsigned clock_start_periph_pll(enum periph_id periph_id,
+		enum clock_id parent, unsigned rate)
+{
+	unsigned effective_rate;
+
+	reset_set_enable(periph_id, 1);
+	clock_enable(periph_id);
+
+	effective_rate = clock_adjust_periph_pll_div(periph_id, parent, rate,
+						 NULL);
+
+	reset_set_enable(periph_id, 0);
+	return effective_rate;
+}
+
+void clock_set_enable(enum periph_id periph_id, int enable)
+{
+	struct clk_rst_ctlr *clkrst =
+			(struct clk_rst_ctlr *)NV_PA_CLK_RST_BASE;
+	u32 *clk;
+	u32 reg;
+
+	/* Enable/disable the clock to this peripheral */
+	assert(clock_periph_id_isvalid(periph_id));
+	if ((int)periph_id < (int)PERIPH_ID_VW_FIRST)
+		clk = &clkrst->crc_clk_out_enb[PERIPH_REG(periph_id)];
+	else
+		clk = &clkrst->crc_clk_out_enb_vw[PERIPH_REG(periph_id)];
+	reg = readl(clk);
+	if (enable)
+		reg |= PERIPH_MASK(periph_id);
+	else
+		reg &= ~PERIPH_MASK(periph_id);
+	writel(reg, clk);
+}
+
+void clock_enable(enum periph_id clkid)
+{
+	clock_set_enable(clkid, 1);
+}
+
+void clock_disable(enum periph_id clkid)
+{
+	clock_set_enable(clkid, 0);
+}
+
+void reset_set_enable(enum periph_id periph_id, int enable)
+{
+	struct clk_rst_ctlr *clkrst =
+			(struct clk_rst_ctlr *)NV_PA_CLK_RST_BASE;
+	u32 *reset;
+	u32 reg;
+
+	/* Enable/disable reset to the peripheral */
+	assert(clock_periph_id_isvalid(periph_id));
+	if (periph_id < PERIPH_ID_VW_FIRST)
+		reset = &clkrst->crc_rst_dev[PERIPH_REG(periph_id)];
+	else
+		reset = &clkrst->crc_rst_dev_vw[PERIPH_REG(periph_id)];
+	reg = readl(reset);
+	if (enable)
+		reg |= PERIPH_MASK(periph_id);
+	else
+		reg &= ~PERIPH_MASK(periph_id);
+	writel(reg, reset);
+}
+
+void reset_periph(enum periph_id periph_id, int us_delay)
+{
+	/* Put peripheral into reset */
+	reset_set_enable(periph_id, 1);
+	udelay(us_delay);
+
+	/* Remove reset */
+	reset_set_enable(periph_id, 0);
+
+	udelay(us_delay);
+}
+
+void reset_cmplx_set_enable(int cpu, int which, int reset)
+{
+	struct clk_rst_ctlr *clkrst =
+			(struct clk_rst_ctlr *)NV_PA_CLK_RST_BASE;
+	u32 mask;
+
+	/* Form the mask, which depends on the cpu chosen. Tegra3 has 4 */
+	assert(cpu >= 0 && cpu < 4);
+	mask = which << cpu;
+
+	/* either enable or disable those reset for that CPU */
+	if (reset)
+		writel(mask, &clkrst->crc_cpu_cmplx_set);
+	else
+		writel(mask, &clkrst->crc_cpu_cmplx_clr);
+}
+
+unsigned clock_get_rate(enum clock_id clkid)
+{
+	struct clk_pll *pll;
+	u32 base;
+	u32 divm;
+	u64 parent_rate;
+	u64 rate;
+
+	parent_rate = osc_freq[clock_get_osc_freq()];
+	if (clkid == CLOCK_ID_OSC)
+		return parent_rate;
+
+	pll = get_pll(clkid);
+	base = readl(&pll->pll_base);
+
+	/* Oh for bf_unpack()... */
+	rate = parent_rate * ((base & PLL_DIVN_MASK) >> PLL_DIVN_SHIFT);
+	divm = (base & PLL_DIVM_MASK) >> PLL_DIVM_SHIFT;
+	if (clkid == CLOCK_ID_USB)
+		divm <<= (base & PLLU_VCO_FREQ_MASK) >> PLLU_VCO_FREQ_SHIFT;
+	else
+		divm <<= (base & PLL_DIVP_MASK) >> PLL_DIVP_SHIFT;
+	do_div(rate, divm);
+	return rate;
+}
+
+/**
+ * Set the output frequency you want for each PLL clock.
+ * PLL output frequencies are programmed by setting their N, M and P values.
+ * The governing equations are:
+ *     VCO = (Fi / m) * n, Fo = VCO / (2^p)
+ *     where Fo is the output frequency from the PLL.
+ * Example: Set the output frequency to 216Mhz(Fo) with 12Mhz OSC(Fi)
+ *     216Mhz = ((12Mhz / m) * n) / (2^p) so n=432,m=12,p=1
+ * Please see Tegra TRM section 5.3 to get the detail for PLL Programming
+ *
+ * @param n PLL feedback divider(DIVN)
+ * @param m PLL input divider(DIVN)
+ * @param p post divider(DIVP)
+ * @param cpcon base PLL charge pump(CPCON)
+ * @return 0 if ok, -1 on error (the requested PLL is incorrect and cannot
+ *		be overriden), 1 if PLL is already correct
+ */
+static int clock_set_rate(enum clock_id clkid, u32 n, u32 m, u32 p, u32 cpcon)
+{
+	u32 base_reg;
+	u32 misc_reg;
+	struct clk_pll *pll;
+
+	pll = get_pll(clkid);
+
+	base_reg = readl(&pll->pll_base);
+
+	/* Set BYPASS, m, n and p to PLL_BASE */
+	base_reg &= ~PLL_DIVM_MASK;
+	base_reg |= m << PLL_DIVM_SHIFT;
+
+	base_reg &= ~PLL_DIVN_MASK;
+	base_reg |= n << PLL_DIVN_SHIFT;
+
+	base_reg &= ~PLL_DIVP_MASK;
+	base_reg |= p << PLL_DIVP_SHIFT;
+
+	if (clkid == CLOCK_ID_PERIPH) {
+		/*
+		 * If the PLL is already set up, check that it is correct
+		 * and record this info for clock_verify() to check.
+		 */
+		if (base_reg & PLL_BASE_OVRRIDE_MASK) {
+			base_reg |= PLL_ENABLE_MASK;
+			if (base_reg != readl(&pll->pll_base))
+				pllp_valid = 0;
+			return pllp_valid ? 1 : -1;
+		}
+		base_reg |= PLL_BASE_OVRRIDE_MASK;
+	}
+
+	base_reg |= PLL_BYPASS_MASK;
+	writel(base_reg, &pll->pll_base);
+
+	/* Set cpcon to PLL_MISC */
+	misc_reg = readl(&pll->pll_misc);
+	misc_reg &= ~PLL_CPCON_MASK;
+	misc_reg |= cpcon << PLL_CPCON_SHIFT;
+	writel(misc_reg, &pll->pll_misc);
+
+	/* Enable PLL */
+	base_reg |= PLL_ENABLE_MASK;
+	writel(base_reg, &pll->pll_base);
+
+	/* Disable BYPASS */
+	base_reg &= ~PLL_BYPASS_MASK;
+	writel(base_reg, &pll->pll_base);
+
+	return 0;
+}
+
+void clock_ll_start_uart(enum periph_id periph_id)
+{
+	/* Assert UART reset and enable clock */
+	reset_set_enable(periph_id, 1);
+	clock_enable(periph_id);
+	clock_ll_set_source(periph_id, 0); /* UARTx_CLK_SRC = 00, PLLP_OUT0 */
+
+	/* wait for 2us */
+	udelay(2);
+
+	/* De-assert reset to UART */
+	reset_set_enable(periph_id, 0);
+}
+
+#ifdef CONFIG_OF_CONTROL
+/*
+ * Convert a device tree clock ID to our peripheral ID. They are mostly
+ * the same but we are very cautious so we check that a valid clock ID is
+ * provided.
+ *
+ * @param clk_id	Clock ID according to tegra20 device tree binding
+ * @return peripheral ID, or PERIPH_ID_NONE if the clock ID is invalid
+ */
+static enum periph_id clk_id_to_periph_id(int clk_id)
+{
+	if (clk_id > 95)
+		return PERIPH_ID_NONE;
+
+	switch (clk_id) {
+	case 1:
+	case 2:
+	case 7:
+	case 10:
+	case 20:
+	case 30:
+	case 35:
+	case 49:
+	case 56:
+	case 74:
+	case 76:
+	case 77:
+	case 78:
+	case 79:
+	case 80:
+	case 81:
+	case 82:
+	case 83:
+	case 91:
+	case 95:
+		return PERIPH_ID_NONE;
+	default:
+		return clk_id;
+	}
+}
+
+int clock_decode_periph_id(const void *blob, int node)
+{
+	enum periph_id id;
+	u32 cell[2];
+	int err;
+
+	err = fdtdec_get_int_array(blob, node, "clocks", cell,
+				   ARRAY_SIZE(cell));
+	if (err)
+		return -1;
+	id = clk_id_to_periph_id(cell[1]);
+	assert(clock_periph_id_isvalid(id));
+	return id;
+}
+#endif /* CONFIG_OF_CONTROL */
+
+int clock_verify(void)
+{
+	struct clk_pll *pll = get_pll(CLOCK_ID_PERIPH);
+	u32 reg = readl(&pll->pll_base);
+
+	if (!pllp_valid) {
+		printf("Warning: PLLP %x is not correct\n", reg);
+		return -1;
+	}
+	debug("PLLX %x is correct\n", reg);
+	return 0;
+}
+
+void clock_early_init(void)
+{
+	/*
+	 * PLLP output frequency set to 216Mh
+	 * PLLC output frequency set to 228Mhz
+	 */
+	switch (clock_get_osc_freq()) {
+	case CLOCK_OSC_FREQ_12_0: /* OSC is 12Mhz */
+		clock_set_rate(CLOCK_ID_PERIPH, 432, 12, 1, 8);
+		clock_set_rate(CLOCK_ID_CGENERAL, 456, 12, 1, 8);
+		break;
+
+	case CLOCK_OSC_FREQ_26_0: /* OSC is 26Mhz */
+		clock_set_rate(CLOCK_ID_PERIPH, 432, 26, 1, 8);
+		clock_set_rate(CLOCK_ID_CGENERAL, 600, 26, 0, 8);
+		break;
+
+	case CLOCK_OSC_FREQ_13_0: /* OSC is 13Mhz */
+		clock_set_rate(CLOCK_ID_PERIPH, 432, 13, 1, 8);
+		clock_set_rate(CLOCK_ID_CGENERAL, 600, 13, 0, 8);
+		break;
+	case CLOCK_OSC_FREQ_19_2:
+	default:
+		/*
+		 * These are not supported. It is too early to print a
+		 * message and the UART likely won't work anyway due to the
+		 * oscillator being wrong.
+		 */
+		break;
+	}
+}
+
+void clock_init(void)
+{
+	pll_rate[CLOCK_ID_MEMORY] = clock_get_rate(CLOCK_ID_MEMORY);
+	pll_rate[CLOCK_ID_PERIPH] = clock_get_rate(CLOCK_ID_PERIPH);
+	pll_rate[CLOCK_ID_CGENERAL] = clock_get_rate(CLOCK_ID_CGENERAL);
+	pll_rate[CLOCK_ID_OSC] = clock_get_rate(CLOCK_ID_OSC);
+	pll_rate[CLOCK_ID_SFROM32KHZ] = 32768;
+	debug("Osc = %d\n", pll_rate[CLOCK_ID_OSC]);
+	debug("PLLM = %d\n", pll_rate[CLOCK_ID_MEMORY]);
+	debug("PLLP = %d\n", pll_rate[CLOCK_ID_PERIPH]);
+}
diff --git a/arch/arm/cpu/tegra30-common/funcmux.c b/arch/arm/cpu/tegra30-common/funcmux.c
new file mode 100644
index 0000000..6e28ac9
--- /dev/null
+++ b/arch/arm/cpu/tegra30-common/funcmux.c
@@ -0,0 +1,74 @@ 
+/*
+ * Copyright (c) 2011 The Chromium OS Authors.
+ * Copyright (C) 2010-2012 NVIDIA Corporation <www.nvidia.com>
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/* Tegra30 high-level function multiplexing */
+
+#include <common.h>
+#include <asm/arch/clock.h>
+#include <asm/arch/funcmux.h>
+#include <asm/arch/pinmux.h>
+
+int funcmux_select(enum periph_id id, int config)
+{
+	int bad_config = config != FUNCMUX_DEFAULT;
+
+	switch (id) {
+	case PERIPH_ID_UART1:
+		switch (config) {
+		case FUNCMUX_UART1_ULPI_UART2:
+			pinmux_set_func(PINGRP_ULPI_DATA0, PMUX_FUNC_UARTA);
+			pinmux_set_func(PINGRP_ULPI_DATA1, PMUX_FUNC_UARTA);
+			pinmux_set_func(PINGRP_ULPI_DATA2, PMUX_FUNC_UARTA);
+			pinmux_set_func(PINGRP_ULPI_DATA3, PMUX_FUNC_UARTA);
+			pinmux_set_func(PINGRP_ULPI_DATA4, PMUX_FUNC_UARTA);
+			pinmux_set_func(PINGRP_ULPI_DATA5, PMUX_FUNC_UARTA);
+			pinmux_set_func(PINGRP_ULPI_DATA6, PMUX_FUNC_UARTA);
+			pinmux_set_func(PINGRP_UART2_RTS_N, PMUX_FUNC_UARTA);
+			pinmux_set_func(PINGRP_UART2_CTS_N, PMUX_FUNC_UARTA);
+			pinmux_tristate_disable(PINGRP_ULPI_DATA0);
+			pinmux_tristate_disable(PINGRP_ULPI_DATA1);
+			pinmux_tristate_disable(PINGRP_ULPI_DATA2);
+			pinmux_tristate_disable(PINGRP_ULPI_DATA3);
+			pinmux_tristate_disable(PINGRP_ULPI_DATA4);
+			pinmux_tristate_disable(PINGRP_ULPI_DATA5);
+			pinmux_tristate_disable(PINGRP_ULPI_DATA6);
+			pinmux_tristate_disable(PINGRP_ULPI_DATA7);
+			pinmux_tristate_disable(PINGRP_UART2_RTS_N);
+			pinmux_tristate_disable(PINGRP_UART2_CTS_N);
+			break;
+		}
+		break;
+
+	/* Add other periph IDs here as needed */
+
+	default:
+		debug("%s: invalid periph_id %d", __func__, id);
+		return -1;
+	}
+
+	if (bad_config) {
+		debug("%s: invalid config %d for periph_id %d", __func__,
+		      config, id);
+		return -1;
+	}
+	return 0;
+}
diff --git a/arch/arm/cpu/tegra30-common/lowlevel_init.S b/arch/arm/cpu/tegra30-common/lowlevel_init.S
new file mode 100644
index 0000000..91ff3b9
--- /dev/null
+++ b/arch/arm/cpu/tegra30-common/lowlevel_init.S
@@ -0,0 +1,42 @@ 
+/*
+ * SoC-specific setup info
+ *
+ * (C) Copyright 2010-2012
+ * NVIDIA Corporation <www.nvidia.com>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <config.h>
+#include <version.h>
+#include <linux/linkage.h>
+
+	.align	5
+ENTRY(reset_cpu)
+	ldr	r1, rstctl			@ get addr for global reset
+						@ reg
+	ldr	r3, [r1]
+	orr	r3, r3, #0x10
+	str	r3, [r1]			@ force reset
+	mov	r0, r0
+_loop_forever:
+	b	_loop_forever
+rstctl:
+	.word	PRM_RSTCTRL
+ENDPROC(reset_cpu)
diff --git a/arch/arm/cpu/tegra30-common/pinmux.c b/arch/arm/cpu/tegra30-common/pinmux.c
new file mode 100644
index 0000000..387110e
--- /dev/null
+++ b/arch/arm/cpu/tegra30-common/pinmux.c
@@ -0,0 +1,507 @@ 
+/*
+ * Copyright (c) 2011 The Chromium OS Authors.
+ * Copyright (C) 2010-2012 NVIDIA Corporation <www.nvidia.com>
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/* Tegra30 pin multiplexing functions */
+
+#include <asm/io.h>
+#include <asm/arch/tegra30.h>
+#include <asm/arch/pinmux.h>
+#include <common.h>
+
+struct tegra_pingroup_desc {
+	const char *name;
+	enum pmux_func funcs[4];
+	enum pmux_func func_safe;
+	enum pmux_vddio vddio;
+	enum pmux_pin_io io;
+};
+
+#define PMUX_MUXCTL_SHIFT	0
+#define PMUX_PULL_SHIFT		2
+#define PMUX_TRISTATE_SHIFT	4
+#define PMUX_TRISTATE_MASK	(1 << PMUX_TRISTATE_SHIFT)
+#define PMUX_IO_SHIFT		5
+#define PMUX_OD_SHIFT		6
+#define PMUX_LOCK_SHIFT		7
+#define PMUX_IO_RESET_SHIFT	8
+
+/* Convenient macro for defining pin group properties */
+#define PIN(pg_name, vdd, f0, f1, f2, f3, iod)	\
+	{						\
+		.vddio = PMUX_VDDIO_ ## vdd,		\
+		.funcs = {				\
+			PMUX_FUNC_ ## f0,		\
+			PMUX_FUNC_ ## f1,		\
+			PMUX_FUNC_ ## f2,		\
+			PMUX_FUNC_ ## f3,		\
+		},					\
+		.func_safe = PMUX_FUNC_RSVD,		\
+		.io = PMUX_PIN_ ## iod,			\
+	}
+
+/* Input and output pins */
+#define PINI(pg_name, vdd, f0, f1, f2, f3) \
+	PIN(pg_name, vdd, f0, f1, f2, f3, INPUT)
+#define PINO(pg_name, vdd, f0, f1, f2, f3) \
+	PIN(pg_name, vdd, f0, f1, f2, f3, OUTPUT)
+
+const struct tegra_pingroup_desc tegra_soc_pingroups[PINGRP_COUNT] = {
+	/*  NAME	VDD	f0	f1	f2	f3	fSafe	io */
+	PINI(ULPI_DATA0,  BB,	   SPI3,	HSI,	   UARTA,   ULPI),
+	PINI(ULPI_DATA1,  BB,	   SPI3,	HSI,	   UARTA,   ULPI),
+	PINI(ULPI_DATA2,  BB,	   SPI3,	HSI,	   UARTA,   ULPI),
+	PINI(ULPI_DATA3,  BB,	   SPI3,	HSI,	   UARTA,   ULPI),
+	PINI(ULPI_DATA4,  BB,	   SPI2,	HSI,	   UARTA,   ULPI),
+	PINI(ULPI_DATA5,  BB,	   SPI2,	HSI,	   UARTA,   ULPI),
+	PINI(ULPI_DATA6,  BB,	   SPI2,	HSI,	   UARTA,   ULPI),
+	PINI(ULPI_DATA7,  BB,	   SPI2,	HSI,	   UARTA,   ULPI),
+	PINI(ULPI_CLK,	  BB,	   SPI1,	RSVD,	   UARTD,   ULPI),
+	PINI(ULPI_DIR,	  BB,	   SPI1,	RSVD,	   UARTD,   ULPI),
+	PINI(ULPI_NXT,	  BB,	   SPI1,	RSVD,	   UARTD,   ULPI),
+	PINI(ULPI_STP,	  BB,	   SPI1,	RSVD,	   UARTD,   ULPI),
+	PINI(DAP3_FS,	  BB,	   I2S2,	RSVD1,	   DISPA,   DISPB),
+	PINI(DAP3_DIN,	  BB,	   I2S2,	RSVD1,	   DISPA,   DISPB),
+	PINI(DAP3_DOUT,	  BB,	   I2S2,	RSVD1,	   DISPA,   DISPB),
+	PINI(DAP3_SCLK,	  BB,	   I2S2,	RSVD1,	   DISPA,   DISPB),
+	PINI(GPIO_PV0,	  BB,	   RSVD,	RSVD,	   RSVD,    RSVD),
+	PINI(GPIO_PV1,	  BB,	   RSVD,	RSVD,	   RSVD,    RSVD),
+	PINI(SDMMC1_CLK,  SDMMC1,  SDMMC1,	RSVD1,	   RSVD2,   BAD),
+	PINI(SDMMC1_CMD,  SDMMC1,  SDMMC1,	RSVD1,	   RSVD2,   BAD),
+	PINI(SDMMC1_DAT3, SDMMC1,  SDMMC1,	RSVD1,	   UARTE,   BAD),
+	PINI(SDMMC1_DAT2, SDMMC1,  SDMMC1,	RSVD1,	   UARTE,   BAD),
+	PINI(SDMMC1_DAT1, SDMMC1,  SDMMC1,	RSVD1,	   UARTE,   BAD),
+	PINI(SDMMC1_DAT0, SDMMC1,  SDMMC1,	RSVD1,	   UARTE,   BAD),
+	PINI(GPIO_PV2,	  SDMMC1,  OWR,		RSVD1,	   RSVD2,   RSVD3),
+	PINI(GPIO_PV3,	  SDMMC1,  BAD,		RSVD1,	   RSVD2,   RSVD3),
+	PINI(CLK2_OUT,	  SDMMC1,  EXTPERIPH2,	RSVD1,	   RSVD2,   RSVD3),
+	PINI(CLK2_REQ,	  SDMMC1,  DAP,		RSVD1,	  RSVD2,    RSVD3),
+	PINO(LCD_PWR1,	  LCD,	   DISPA,	DISPB,	  RSVD1,    RSVD2),
+	PINO(LCD_PWR2,	  LCD,	   DISPA,	DISPB,	  SPI5,     BAD),
+	PINO(LCD_SDIN,	  LCD,	   DISPA,	DISPB,	  SPI5,     RSVD),
+	PINO(LCD_SDOUT,	  LCD,	   DISPA,	DISPB,	  SPI5,     BAD),
+	PINO(LCD_WR_N,	  LCD,	   DISPA,	DISPB,	  SPI5,     BAD),
+	PINO(LCD_CS0_N,	  LCD,	   DISPA,	DISPB,	  SPI5,     RSVD),
+	PINO(LCD_DC0,	  LCD,	   DISPA,	DISPB,	  RSVD1,    RSVD2),
+	PINO(LCD_SCK,	  LCD,	   DISPA,	DISPB,	  SPI5,     BAD),
+	PINO(LCD_PWR0,	  LCD,	   DISPA,	DISPB,	  SPI5,     BAD),
+	PINO(LCD_PCLK,	  LCD,	   DISPA,	DISPB,	  RSVD1,    RSVD2),
+	PINO(LCD_DE,	  LCD,	   DISPA,	DISPB,	  RSVD1,    RSVD2),
+	PINO(LCD_HSYNC,	  LCD,	   DISPA,	DISPB,	  RSVD1,    RSVD2),
+	PINO(LCD_VSYNC,	  LCD,	   DISPA,	DISPB,	  RSVD1,    RSVD2),
+	PINO(LCD_D0,	  LCD,	   DISPA,	DISPB,	  RSVD1,    RSVD2),
+	PINO(LCD_D1,	  LCD,	   DISPA,	DISPB,	  RSVD1,    RSVD2),
+	PINO(LCD_D2,	  LCD,	   DISPA,	DISPB,	  RSVD1,    RSVD2),
+	PINO(LCD_D3,	  LCD,	   DISPA,	DISPB,	  RSVD1,    RSVD2),
+	PINO(LCD_D4,	  LCD,	   DISPA,	DISPB,	  RSVD1,    RSVD2),
+	PINO(LCD_D5,	  LCD,	   DISPA,	DISPB,	  RSVD1,    RSVD2),
+	PINO(LCD_D6,	  LCD,	   DISPA,	DISPB,	  RSVD1,    RSVD2),
+	PINO(LCD_D7,	  LCD,	   DISPA,	DISPB,	  RSVD1,    RSVD2),
+	PINO(LCD_D8,	  LCD,	   DISPA,	DISPB,	  RSVD1,    RSVD2),
+	PINO(LCD_D9,	  LCD,	   DISPA,	DISPB,	  RSVD1,    RSVD2),
+	PINO(LCD_D10,	  LCD,	   DISPA,	DISPB,	  RSVD1,    RSVD2),
+	PINO(LCD_D11,	  LCD,	   DISPA,	DISPB,	  RSVD1,    RSVD2),
+	PINO(LCD_D12,	  LCD,	   DISPA,	DISPB,	  RSVD1,    RSVD2),
+	PINO(LCD_D13,	  LCD,	   DISPA,	DISPB,	  RSVD1,    RSVD2),
+	PINO(LCD_D14,	  LCD,	   DISPA,	DISPB,	  RSVD1,    RSVD2),
+	PINO(LCD_D15,	  LCD,	   DISPA,	DISPB,	  RSVD1,    RSVD2),
+	PINO(LCD_D16,	  LCD,	   DISPA,	DISPB,	  RSVD1,    RSVD2),
+	PINO(LCD_D17,	  LCD,	   DISPA,	DISPB,	  RSVD1,    RSVD2),
+	PINO(LCD_D18,	  LCD,	   DISPA,	DISPB,	  RSVD1,    RSVD2),
+	PINO(LCD_D19,	  LCD,	   DISPA,	DISPB,	  RSVD1,    RSVD2),
+	PINO(LCD_D20,	  LCD,	   DISPA,	DISPB,	  RSVD1,    RSVD2),
+	PINO(LCD_D21,	  LCD,	   DISPA,	DISPB,	  RSVD1,    RSVD2),
+	PINO(LCD_D22,	  LCD,	   DISPA,	DISPB,	  RSVD1,    RSVD2),
+	PINO(LCD_D23,	  LCD,	   DISPA,	DISPB,	  RSVD1,    RSVD2),
+	PINO(LCD_CS1_N,	  LCD,	   DISPA,	DISPB,	  SPI5,     RSVD2),
+	PINO(LCD_M1,	  LCD,	   DISPA,	DISPB,	  RSVD1,    RSVD2),
+	PINO(LCD_DC1,	  LCD,	   DISPA,	DISPB,	  RSVD1,    RSVD2),
+	PINI(HDMI_INT,	  LCD,	   RSVD,	RSVD,	   RSVD,    RSVD),
+	PINI(DDC_SCL,	  LCD,	   I2C4,	RSVD1,	   RSVD2,   RSVD3),
+	PINI(DDC_SDA,	  LCD,	   I2C4,	RSVD1,	   RSVD2,   RSVD3),
+	PINI(CRT_HSYNC,	  LCD,	   CRT,		RSVD1,	   RSVD2,   RSVD3),
+	PINI(CRT_VSYNC,	  LCD,	   CRT,		RSVD1,	   RSVD2,   RSVD3),
+	PINI(VI_D0,	  VI,	   BAD,		RSVD1,	   VI,      RSVD2),
+	PINI(VI_D1,	  VI,	   BAD,		SDMMC2,	   VI,      RSVD1),
+	PINI(VI_D2,	  VI,	   BAD,		SDMMC2,	   VI,      RSVD1),
+	PINI(VI_D3,	  VI,	   BAD,		SDMMC2,	   VI,      RSVD1),
+	PINI(VI_D4,	  VI,	   BAD,		SDMMC2,	   VI,      RSVD1),
+	PINI(VI_D5,	  VI,	   BAD,		SDMMC2,	   VI,      RSVD1),
+	PINI(VI_D6,	  VI,	   BAD,		SDMMC2,	   VI,      RSVD1),
+	PINI(VI_D7,	  VI,	   BAD,		SDMMC2,	   VI,      RSVD1),
+	PINI(VI_D8,	  VI,	   BAD,		SDMMC2,	   VI,      RSVD1),
+	PINI(VI_D9,	  VI,	   BAD,		SDMMC2,	   VI,      RSVD1),
+	PINI(VI_D10,	  VI,	   BAD,		RSVD1,	   VI,      RSVD2),
+	PINI(VI_D11,	  VI,	   BAD,		RSVD1,	   VI,      RSVD2),
+	PINI(VI_PCLK,	  VI,	   RSVD1,	SDMMC2,	   VI,      RSVD2),
+	PINI(VI_MCLK,	  VI,	   VI,		BAD,	   BAD,     BAD),
+	PINI(VI_VSYNC,	  VI,	   BAD,		RSVD1,	   VI,      RSVD2),
+	PINI(VI_HSYNC,	  VI,	   BAD,		RSVD1,	   VI,      RSVD2),
+	PINI(UART2_RXD,	  UART,	   IRDA,	SPDIF,	   UARTA,   SPI4),
+	PINI(UART2_TXD,	  UART,	   IRDA,	SPDIF,	   UARTA,   SPI4),
+	PINI(UART2_RTS_N, UART,	   UARTA,	UARTB,	   GMI,     SPI4),
+	PINI(UART2_CTS_N, UART,	   UARTA,	UARTB,	   GMI,     SPI4),
+	PINI(UART3_TXD,	  UART,	   UARTC,	RSVD1,	   GMI,     RSVD2),
+	PINI(UART3_RXD,	  UART,	   UARTC,	RSVD1,	   GMI,     RSVD2),
+	PINI(UART3_CTS_N, UART,	   UARTC,	RSVD1,	   GMI,     RSVD2),
+	PINI(UART3_RTS_N, UART,	   UARTC,	PWM0,	   GMI,     RSVD2),
+	PINI(GPIO_PU0,	  UART,	   OWR,		UARTA,	   GMI,     RSVD1),
+	PINI(GPIO_PU1,	  UART,	   RSVD1,	UARTA,	   GMI,     RSVD2),
+	PINI(GPIO_PU2,	  UART,	   RSVD1,	UARTA,	   GMI,     RSVD2),
+	PINI(GPIO_PU3,	  UART,	   PWM0,	UARTA,	   GMI,     RSVD1),
+	PINI(GPIO_PU4,	  UART,	   PWM1,	UARTA,	   GMI,     RSVD1),
+	PINI(GPIO_PU5,	  UART,	   PWM2,	UARTA,	   GMI,     RSVD1),
+	PINI(GPIO_PU6,	  UART,	   PWM3,	UARTA,	   GMI,     RSVD1),
+	PINI(GEN1_I2C_SDA, UART,   I2C1,	RSVD1,	   RSVD2,   RSVD3),
+	PINI(GEN1_I2C_SCL, UART,   I2C1,	RSVD1,	   RSVD2,   RSVD3),
+	PINI(DAP4_FS,	  UART,	   I2S3,	RSVD1,	   GMI,     RSVD2),
+	PINI(DAP4_DIN,	  UART,	   I2S3,	RSVD1,	   GMI,     RSVD2),
+	PINI(DAP4_DOUT,	  UART,	   I2S3,	RSVD1,	   GMI,     RSVD2),
+	PINI(DAP4_SCLK,	  UART,	   I2S3,	RSVD1,	   GMI,     RSVD2),
+	PINI(CLK3_OUT,	  UART,	   EXTPERIPH3,	RSVD1,	   RSVD2,   RSVD3),
+	PINI(CLK3_REQ,	  UART,	   DEV3,	RSVD1,	   RSVD2,   RSVD3),
+	PINI(GMI_WP_N,	  GMI,	   RSVD1,	NAND,	   GMI,     GMI_ALT),
+	PINI(GMI_IORDY,	  GMI,	   RSVD1,	NAND,	   GMI,     RSVD2),
+	PINI(GMI_WAIT,	  GMI,	   RSVD1,	NAND,	   GMI,     RSVD2),
+	PINI(GMI_ADV_N,	  GMI,	   RSVD1,	NAND,	   GMI,     RSVD2),
+	PINI(GMI_CLK,	  GMI,	   RSVD1,	NAND,	   GMI,     RSVD2),
+	PINI(GMI_CS0_N,	  GMI,	   RSVD1,	NAND,	   GMI,     BAD),
+	PINI(GMI_CS1_N,	  GMI,	   RSVD1,	NAND,	   GMI,     DTV),
+	PINI(GMI_CS2_N,	  GMI,	   RSVD1,	NAND,	   GMI,     RSVD2),
+	PINI(GMI_CS3_N,	  GMI,	   RSVD1,	NAND,	   GMI,     GMI_ALT),
+	PINI(GMI_CS4_N,	  GMI,	   RSVD1,	NAND,	   GMI,     RSVD2),
+	PINI(GMI_CS6_N,	  GMI,	   NAND,	NAND_ALT,  GMI,     SATA),
+	PINI(GMI_CS7_N,	  GMI,	   NAND,	NAND_ALT,  GMI,     GMI_ALT),
+	PINI(GMI_AD0,	  GMI,	   RSVD1,	NAND,	   GMI,     RSVD2),
+	PINI(GMI_AD1,	  GMI,	   RSVD1,	NAND,	   GMI,     RSVD2),
+	PINI(GMI_AD2,	  GMI,	   RSVD1,	NAND,	   GMI,     RSVD2),
+	PINI(GMI_AD3,	  GMI,	   RSVD1,	NAND,	   GMI,     RSVD2),
+	PINI(GMI_AD4,	  GMI,	   RSVD1,	NAND,	   GMI,     RSVD2),
+	PINI(GMI_AD5,	  GMI,	   RSVD1,	NAND,	   GMI,     RSVD2),
+	PINI(GMI_AD6,	  GMI,	   RSVD1,	NAND,	   GMI,     RSVD2),
+	PINI(GMI_AD7,	  GMI,	   RSVD1,	NAND,	   GMI,     RSVD2),
+	PINI(GMI_AD8,	  GMI,	   PWM0,	NAND,	   GMI,     RSVD2),
+	PINI(GMI_AD9,	  GMI,	   PWM1,	NAND,	   GMI,     RSVD2),
+	PINI(GMI_AD10,	  GMI,	   PWM2,	NAND,	   GMI,     RSVD2),
+	PINI(GMI_AD11,	  GMI,	   PWM3,	NAND,	   GMI,     RSVD2),
+	PINI(GMI_AD12,	  GMI,	   RSVD1,	NAND,	   GMI,     RSVD2),
+	PINI(GMI_AD13,	  GMI,	   RSVD1,	NAND,	   GMI,     RSVD2),
+	PINI(GMI_AD14,	  GMI,	   RSVD1,	NAND,	   GMI,     RSVD2),
+	PINI(GMI_AD15,	  GMI,	   RSVD1,	NAND,	   GMI,     RSVD2),
+	PINI(GMI_A16,	  GMI,	   UARTD,	SPI4,	   GMI,     GMI_ALT),
+	PINI(GMI_A17,	  GMI,	   UARTD,	SPI4,	   GMI,     BAD),
+	PINI(GMI_A18,	  GMI,	   UARTD,	SPI4,	   GMI,     BAD),
+	PINI(GMI_A19,	  GMI,	   UARTD,	SPI4,	   GMI,     RSVD3),
+	PINI(GMI_WR_N,	  GMI,	   RSVD1,	NAND,	   GMI,     RSVD3),
+	PINI(GMI_OE_N,	  GMI,	   RSVD1,	NAND,	   GMI,     RSVD3),
+	PINI(GMI_DQS,	  GMI,	   RSVD1,	NAND,	   GMI,     RSVD3),
+	PINI(GMI_RST_N,	  GMI,	   NAND,	NAND_ALT,  GMI,     RSVD3),
+	PINI(GEN2_I2C_SCL, GMI,	   I2C2,	BAD,	   GMI,     RSVD3),
+	PINI(GEN2_I2C_SDA, GMI,	   I2C2,	BAD,	   GMI,     RSVD3),
+	PINI(SDMMC4_CLK,  SDMMC4,  BAD,		NAND,	   GMI,     SDMMC4),
+	PINI(SDMMC4_CMD,  SDMMC4,  I2C3,	NAND,	   GMI,     SDMMC4),
+	PINI(SDMMC4_DAT0, SDMMC4,  UARTE,	SPI3,	   GMI,     SDMMC4),
+	PINI(SDMMC4_DAT1, SDMMC4,  UARTE,	SPI3,	   GMI,     SDMMC4),
+	PINI(SDMMC4_DAT2, SDMMC4,  UARTE,	SPI3,	   GMI,     SDMMC4),
+	PINI(SDMMC4_DAT3, SDMMC4,  UARTE,	SPI3,	   GMI,     SDMMC4),
+	PINI(SDMMC4_DAT4, SDMMC4,  I2C3,	I2S4,	   GMI,     SDMMC4),
+	PINI(SDMMC4_DAT5, SDMMC4,  VGP3,	I2S4,	   GMI,     SDMMC4),
+	PINI(SDMMC4_DAT6, SDMMC4,  VGP4,	I2S4,	   GMI,     SDMMC4),
+	PINI(SDMMC4_DAT7, SDMMC4,  VGP5,	I2S4,	   GMI,     SDMMC4),
+	PINI(SDMMC4_RST_N, SDMMC4, VGP6,	RSVD1,	   RSVD2,   POPSDMMC4),
+	PINI(CAM_MCLK,	  CAM,	   VI,		BAD,	   VI_ALT2, POPSDMMC4),
+	PINI(GPIO_PCC1,	  CAM,	   I2S4,	RSVD1,	   RSVD2,   POPSDMMC4),
+	PINI(GPIO_PBB0,	  CAM,	   I2S4,	RSVD1,	   RSVD2,   POPSDMMC4),
+	PINI(CAM_I2C_SCL, CAM,	   BAD,		I2C3,	   RSVD2,   POPSDMMC4),
+	PINI(CAM_I2C_SDA, CAM,	   BAD,		I2C3,	   RSVD2,   POPSDMMC4),
+	PINI(GPIO_PBB3,	  CAM,	   VGP3,	DISPA,	   DISPB,   POPSDMMC4),
+	PINI(GPIO_PBB4,	  CAM,	   VGP4,	DISPA,	   DISPB,   POPSDMMC4),
+	PINI(GPIO_PBB5,	  CAM,	   VGP5,	DISPA,	   DISPB,   POPSDMMC4),
+	PINI(GPIO_PBB6,	  CAM,	   VGP6,	DISPA,	   DISPB,   POPSDMMC4),
+	PINI(GPIO_PBB7,	  CAM,	   I2S4,	RSVD1,	   RSVD2,   POPSDMMC4),
+	PINI(GPIO_PCC2,	  CAM,	   I2S4,	RSVD1,	   RSVD2,   RSVD3),
+	PINI(JTAG_RTCK,	  SYS,	   RTCK,	RSVD1,	   RSVD2,   RSVD3),
+	PINI(PWR_I2C_SCL, SYS,	   I2CPWR,	RSVD1,	   RSVD2,   RSVD3),
+	PINI(PWR_I2C_SDA, SYS,	   I2CPWR,	RSVD1,	   RSVD2,   RSVD3),
+	PINI(KB_ROW0,	  SYS,	   KBC,		BAD,	   RSVD2,   RSVD3),
+	PINI(KB_ROW1,	  SYS,	   KBC,		BAD,	   RSVD2,   RSVD3),
+	PINI(KB_ROW2,	  SYS,	   KBC,		BAD,	   RSVD2,   RSVD3),
+	PINI(KB_ROW3,	  SYS,	   KBC,		BAD,	   RSVD2,   BAD),
+	PINI(KB_ROW4,	  SYS,	   KBC,		BAD,	   TRACE,   RSVD3),
+	PINI(KB_ROW5,	  SYS,	   KBC,		BAD,	   TRACE,   OWR),
+	PINI(KB_ROW6,	  SYS,	   KBC,		BAD,	   SDMMC2,  BAD),
+	PINI(KB_ROW7,	  SYS,	   KBC,		BAD,	   SDMMC2,  BAD),
+	PINI(KB_ROW8,	  SYS,	   KBC,		BAD,	   SDMMC2,  BAD),
+	PINI(KB_ROW9,	  SYS,	   KBC,		BAD,	   SDMMC2,  BAD),
+	PINI(KB_ROW10,	  SYS,	   KBC,		BAD,	   SDMMC2,  BAD),
+	PINI(KB_ROW11,	  SYS,	   KBC,		BAD,	   SDMMC2,  BAD),
+	PINI(KB_ROW12,	  SYS,	   KBC,		BAD,	   SDMMC2,  BAD),
+	PINI(KB_ROW13,	  SYS,	   KBC,		BAD,	   SDMMC2,  BAD),
+	PINI(KB_ROW14,	  SYS,	   KBC,		BAD,	   SDMMC2,  BAD),
+	PINI(KB_ROW15,	  SYS,	   KBC,		BAD,	   SDMMC2,  BAD),
+	PINI(KB_COL0,	  SYS,	   KBC,		BAD,	   TRACE,   BAD),
+	PINI(KB_COL1,	  SYS,	   KBC,		BAD,	   TRACE,   BAD),
+	PINI(KB_COL2,	  SYS,	   KBC,		BAD,	   TRACE,   RSVD),
+	PINI(KB_COL3,	  SYS,	   KBC,		BAD,	   TRACE,   RSVD),
+	PINI(KB_COL4,	  SYS,	   KBC,		BAD,	   TRACE,   RSVD),
+	PINI(KB_COL5,	  SYS,	   KBC,		BAD,	   TRACE,   RSVD),
+	PINI(KB_COL6,	  SYS,	   KBC,		BAD,	   TRACE,   BAD),
+	PINI(KB_COL7,	  SYS,	   KBC,		BAD,	   TRACE,   BAD),
+	PINI(CLK_32K_OUT, SYS,	   BLINK,	RSVD1,	   RSVD2,   RSVD3),
+	PINI(SYS_CLK_REQ, SYS,	   SYSCLK,	RSVD1,	   RSVD2,   RSVD3),
+	PINI(CORE_PWR_REQ, SYS,	   RSVD,	RSVD,	   RSVD,    RSVD),
+	PINI(CPU_PWR_REQ, SYS,	   RSVD,	RSVD,	   RSVD,    RSVD),
+	PINI(PWR_INT_N,	  SYS,	   RSVD,	RSVD,	   RSVD,    RSVD),
+	PINI(CLK_32K_IN,  SYS,	   RSVD,	RSVD,	   RSVD,    RSVD),
+	PINI(OWR,	  SYS,	   OWR,		RSVD,	   RSVD,    RSVD),
+	PINI(DAP1_FS,	  AUDIO,   I2S0,	HDA,	   GMI,     SDMMC2),
+	PINI(DAP1_DIN,	  AUDIO,   I2S0,	HDA,	   GMI,     SDMMC2),
+	PINI(DAP1_DOUT,	  AUDIO,   I2S0,	HDA,	   GMI,     SDMMC2),
+	PINI(DAP1_SCLK,	  AUDIO,   I2S0,	HDA,	   GMI,     SDMMC2),
+	PINI(CLK1_REQ,	  AUDIO,   DAP,		HDA,	   RSVD2,   RSVD3),
+	PINI(CLK1_OUT,	  AUDIO,   EXTPERIPH1,	RSVD1,	   RSVD2,   RSVD3),
+	PINI(SPDIF_IN,	  AUDIO,   SPDIF,	HDA,	   BAD,     DAPSDMMC2),
+	PINI(SPDIF_OUT,	  AUDIO,   SPDIF,	RSVD1,	   BAD,     DAPSDMMC2),
+	PINI(DAP2_FS,	  AUDIO,   I2S1,	HDA,	   RSVD2,   GMI),
+	PINI(DAP2_DIN,	  AUDIO,   I2S1,	HDA,	   RSVD2,   GMI),
+	PINI(DAP2_DOUT,	  AUDIO,   I2S1,	HDA,	   RSVD2,   GMI),
+	PINI(DAP2_SCLK,	  AUDIO,   I2S1,	HDA,	   RSVD2,   GMI),
+	PINI(SPI2_MOSI,	  AUDIO,   SPI6,	SPI2,	   BAD,     GMI),
+	PINI(SPI2_MISO,	  AUDIO,   SPI6,	SPI2,	   BAD,     GMI),
+	PINI(SPI2_CS0_N,  AUDIO,   SPI6,	SPI2,	   BAD,     GMI),
+	PINI(SPI2_SCK,	  AUDIO,   SPI6,	SPI2,	   BAD,     GMI),
+	PINI(SPI1_MOSI,	  AUDIO,   SPI2,	SPI1,	   BAD,     GMI),
+	PINI(SPI1_SCK,	  AUDIO,   SPI2,	SPI1,	   BAD,     GMI),
+	PINI(SPI1_CS0_N,  AUDIO,   SPI2,	SPI1,	   BAD,     GMI),
+	PINI(SPI1_MISO,	  AUDIO,   BAD,		SPI1,	   BAD,     RSVD3),
+	PINI(SPI2_CS1_N,  AUDIO,   BAD,		SPI2,	   BAD,     BAD),
+	PINI(SPI2_CS2_N,  AUDIO,   BAD,		SPI2,	   BAD,     BAD),
+	PINI(SDMMC3_CLK,  SDMMC3,  UARTA,	PWM2,	   SDMMC3,  BAD),
+	PINI(SDMMC3_CMD,  SDMMC3,  UARTA,	PWM3,	   SDMMC3,  BAD),
+	PINI(SDMMC3_DAT0, SDMMC3,  RSVD0,	RSVD1,	   SDMMC3,  BAD),
+	PINI(SDMMC3_DAT1, SDMMC3,  RSVD0,	RSVD1,	   SDMMC3,  BAD),
+	PINI(SDMMC3_DAT2, SDMMC3,  RSVD0,	PWM1,	   SDMMC3,  BAD),
+	PINI(SDMMC3_DAT3, SDMMC3,  RSVD0,	PWM0,	   SDMMC3,  BAD),
+	PINI(SDMMC3_DAT4, SDMMC3,  PWM1,	BAD,	   SDMMC3,  BAD),
+	PINI(SDMMC3_DAT5, SDMMC3,  PWM0,	BAD,	   SDMMC3,  BAD),
+	PINI(SDMMC3_DAT6, SDMMC3,  SPDIF,	BAD,	   SDMMC3,  BAD),
+	PINI(SDMMC3_DAT7, SDMMC3,  SPDIF,	BAD,	   SDMMC3,  BAD),
+	PINI(PEX_L0_PRSNT_N,	PEXCTL,   PCIE,	HDA,	   RSVD2,   RSVD3),
+	PINI(PEX_L0_RST_N,	PEXCTL,   PCIE,	HDA,	   RSVD2,   RSVD3),
+	PINI(PEX_L0_CLKREQ_N,	PEXCTL,   PCIE,	HDA,	   RSVD2,   RSVD3),
+	PINI(PEX_WAKE_N,	PEXCTL,   PCIE,	HDA,	   RSVD2,   RSVD3),
+	PINI(PEX_L1_PRSNT_N,	PEXCTL,   PCIE,	HDA,	   RSVD2,   RSVD3),
+	PINI(PEX_L1_RST_N,	PEXCTL,   PCIE,	HDA,	   RSVD2,   RSVD3),
+	PINI(PEX_L1_CLKREQ_N,	PEXCTL,   PCIE,	HDA,	   RSVD2,   RSVD3),
+	PINI(PEX_L2_PRSNT_N,	PEXCTL,   PCIE,	HDA,	   RSVD2,   RSVD3),
+	PINI(PEX_L2_RST_N,	PEXCTL,   PCIE,	HDA,	   RSVD2,   RSVD3),
+	PINI(PEX_L2_CLKREQ_N,	PEXCTL,   PCIE,	HDA,	   RSVD2,   RSVD3),
+	PINI(HDMI_CEC,		SYS,      CEC,	RSVD1,	   RSVD2,   RSVD3),
+};
+
+void pinmux_set_tristate(enum pmux_pingrp pin, int enable)
+{
+	struct pmux_tri_ctlr *pmt =
+			(struct pmux_tri_ctlr *)NV_PA_APB_MISC_BASE;
+	u32 *tri = &pmt->pmt_ctl[pin];
+	u32 reg;
+
+	/* Error check on pin */
+	assert(pmux_pingrp_isvalid(pin));
+
+	reg = readl(tri);
+	if (enable)
+		reg |= PMUX_TRISTATE_MASK;
+	else
+		reg &= ~PMUX_TRISTATE_MASK;
+	writel(reg, tri);
+}
+
+void pinmux_tristate_enable(enum pmux_pingrp pin)
+{
+	pinmux_set_tristate(pin, 1);
+}
+
+void pinmux_tristate_disable(enum pmux_pingrp pin)
+{
+	pinmux_set_tristate(pin, 0);
+}
+
+void pinmux_set_pullupdown(enum pmux_pingrp pin, enum pmux_pull pupd)
+{
+	struct pmux_tri_ctlr *pmt =
+			(struct pmux_tri_ctlr *)NV_PA_APB_MISC_BASE;
+	u32 *pull = &pmt->pmt_ctl[pin];
+	u32 reg;
+
+	/* Error check on pin and pupd */
+	assert(pmux_pingrp_isvalid(pin));
+	assert(pmux_pin_pupd_isvalid(pupd));
+
+	reg = readl(pull);
+	reg &= ~(0x3 << PMUX_PULL_SHIFT);
+	reg |= (pupd << PMUX_PULL_SHIFT);
+	writel(reg, pull);
+}
+
+void pinmux_set_func(enum pmux_pingrp pin, enum pmux_func func)
+{
+	struct pmux_tri_ctlr *pmt =
+			(struct pmux_tri_ctlr *)NV_PA_APB_MISC_BASE;
+	u32 *muxctl = &pmt->pmt_ctl[pin];
+	int i, mux = -1;
+	u32 reg;
+
+	/* Error check on pin and func */
+	assert(pmux_pingrp_isvalid(pin));
+	assert(pmux_func_isvalid(func));
+
+	/* Handle special values */
+	if (func == PMUX_FUNC_SAFE)
+		func = tegra_soc_pingroups[pin].func_safe;
+
+	if (func & PMUX_FUNC_RSVD) {
+		mux = func & 0x3;
+	} else {
+		/* Search for the appropriate function */
+		for (i = 0; i < 4; i++) {
+			if (tegra_soc_pingroups[pin].funcs[i] == func) {
+				mux = i;
+				break;
+			}
+		}
+	}
+	assert(mux != -1);
+
+	reg = readl(muxctl);
+	reg &= ~(0x3 << PMUX_MUXCTL_SHIFT);
+	reg |= (mux << PMUX_MUXCTL_SHIFT);
+	writel(reg, muxctl);
+
+}
+
+void pinmux_set_io(enum pmux_pingrp pin, enum pmux_pin_io io)
+{
+	struct pmux_tri_ctlr *pmt =
+			(struct pmux_tri_ctlr *)NV_PA_APB_MISC_BASE;
+	u32 *pin_io = &pmt->pmt_ctl[pin];
+	u32 reg;
+
+	/* Error check on pin and io */
+	assert(pmux_pingrp_isvalid(pin));
+	assert(pmux_pin_io_isvalid(io));
+
+	reg = readl(pin_io);
+	reg &= ~(0x1 << PMUX_IO_SHIFT);
+	reg |= (io & 0x1) << PMUX_IO_SHIFT;
+	writel(reg, pin_io);
+}
+
+static int pinmux_set_lock(enum pmux_pingrp pin, enum pmux_pin_lock lock)
+{
+	struct pmux_tri_ctlr *pmt =
+			(struct pmux_tri_ctlr *)NV_PA_APB_MISC_BASE;
+	u32 *pin_lock = &pmt->pmt_ctl[pin];
+	u32 reg;
+
+	/* Error check on pin and lock */
+	assert(pmux_pingrp_isvalid(pin));
+	assert(pmux_pin_lock_isvalid(lock));
+
+	if (lock == PMUX_PIN_LOCK_DEFAULT)
+		return 0;
+
+	reg = readl(pin_lock);
+	reg &= ~(0x1 << PMUX_LOCK_SHIFT);
+	if (lock == PMUX_PIN_LOCK_ENABLE)
+		reg |= (0x1 << PMUX_LOCK_SHIFT);
+	writel(reg, pin_lock);
+
+	return 0;
+}
+
+static int pinmux_set_od(enum pmux_pingrp pin, enum pmux_pin_od od)
+{
+	struct pmux_tri_ctlr *pmt =
+			(struct pmux_tri_ctlr *)NV_PA_APB_MISC_BASE;
+	u32 *pin_od = &pmt->pmt_ctl[pin];
+	u32 reg;
+
+	/* Error check on pin and od */
+	assert(pmux_pingrp_isvalid(pin));
+	assert(pmux_pin_od_isvalid(od));
+
+	if (od == PMUX_PIN_OD_DEFAULT)
+		return 0;
+
+	reg = readl(pin_od);
+	reg &= ~(0x1 << PMUX_OD_SHIFT);
+	if (od == PMUX_PIN_OD_ENABLE)
+		reg |= (0x1 << PMUX_OD_SHIFT);
+	writel(reg, pin_od);
+
+	return 0;
+}
+
+static int pinmux_set_ioreset(enum pmux_pingrp pin,
+				enum pmux_pin_ioreset ioreset)
+{
+	struct pmux_tri_ctlr *pmt =
+			(struct pmux_tri_ctlr *)NV_PA_APB_MISC_BASE;
+	u32 *pin_ioreset = &pmt->pmt_ctl[pin];
+	u32 reg;
+
+	/* Error check on pin and ioreset */
+	assert(pmux_pingrp_isvalid(pin));
+	assert(pmux_pin_ioreset_isvalid(ioreset));
+
+	if (ioreset == PMUX_PIN_IO_RESET_DEFAULT)
+		return 0;
+
+	reg = readl(pin_ioreset);
+	reg &= ~(0x1 << PMUX_IO_RESET_SHIFT);
+	if (ioreset == PMUX_PIN_IO_RESET_ENABLE)
+		reg |= (0x1 << PMUX_IO_RESET_SHIFT);
+	writel(reg, pin_ioreset);
+
+	return 0;
+}
+
+void pinmux_config_pingroup(struct pingroup_config *config)
+{
+	enum pmux_pingrp pin = config->pingroup;
+
+	pinmux_set_func(pin, config->func);
+	pinmux_set_pullupdown(pin, config->pull);
+	pinmux_set_tristate(pin, config->tristate);
+	pinmux_set_io(pin, config->io);
+	pinmux_set_lock(pin, config->lock);
+	pinmux_set_od(pin, config->od);
+	pinmux_set_ioreset(pin, config->ioreset);
+}
+
+void pinmux_config_table(struct pingroup_config *config, int len)
+{
+	int i;
+
+	for (i = 0; i < len; i++)
+		pinmux_config_pingroup(&config[i]);
+}
diff --git a/arch/arm/cpu/tegra30-common/sys_info.c b/arch/arm/cpu/tegra30-common/sys_info.c
new file mode 100644
index 0000000..eb638da
--- /dev/null
+++ b/arch/arm/cpu/tegra30-common/sys_info.c
@@ -0,0 +1,35 @@ 
+/*
+ * (C) Copyright 2010-2012
+ * NVIDIA Corporation <www.nvidia.com>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+
+#ifdef CONFIG_DISPLAY_CPUINFO
+/* Print CPU information */
+int print_cpuinfo(void)
+{
+	puts("TEGRA30\n");
+
+	/* TBD: Add printf of major/minor rev info, stepping, etc. */
+	return 0;
+}
+#endif	/* CONFIG_DISPLAY_CPUINFO */
diff --git a/arch/arm/cpu/tegra30-common/timer.c b/arch/arm/cpu/tegra30-common/timer.c
new file mode 100644
index 0000000..c532580
--- /dev/null
+++ b/arch/arm/cpu/tegra30-common/timer.c
@@ -0,0 +1,111 @@ 
+/*
+ * (C) Copyright 2010-2012
+ * NVIDIA Corporation <www.nvidia.com>
+ *
+ * (C) Copyright 2008
+ * Texas Instruments
+ *
+ * Richard Woodruff <r-woodruff2@ti.com>
+ * Syed Moahmmed Khasim <khasim@ti.com>
+ *
+ * (C) Copyright 2002
+ * Sysgo Real-Time Solutions, GmbH <www.elinos.com>
+ * Marius Groeger <mgroeger@sysgo.de>
+ * Alex Zuepke <azu@sysgo.de>
+ *
+ * (C) Copyright 2002
+ * Gary Jennejohn, DENX Software Engineering, <garyj@denx.de>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <asm/arch/tegra30.h>
+#include <asm/arch/timer.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/* counter runs at 1MHz */
+#define TIMER_CLK	1000000
+#define TIMER_LOAD_VAL	0xffffffff
+
+/* timer without interrupts */
+ulong get_timer(ulong base)
+{
+	return get_timer_masked() - base;
+}
+
+/* delay x useconds */
+void __udelay(unsigned long usec)
+{
+	long tmo = usec * (TIMER_CLK / 1000) / 1000;
+	unsigned long now, last = timer_get_us();
+
+	while (tmo > 0) {
+		now = timer_get_us();
+		if (last > now) /* count up timer overflow */
+			tmo -= TIMER_LOAD_VAL - last + now;
+		else
+			tmo -= now - last;
+		last = now;
+	}
+}
+
+ulong get_timer_masked(void)
+{
+	ulong now;
+
+	/* current tick value */
+	now = timer_get_us() / (TIMER_CLK / CONFIG_SYS_HZ);
+
+	if (now >= gd->lastinc)	/* normal mode (non roll) */
+		/* move stamp forward with absolute diff ticks */
+		gd->tbl += (now - gd->lastinc);
+	else	/* we have rollover of incrementer */
+		gd->tbl += ((TIMER_LOAD_VAL / (TIMER_CLK / CONFIG_SYS_HZ))
+				- gd->lastinc) + now;
+	gd->lastinc = now;
+	return gd->tbl;
+}
+
+/*
+ * This function is derived from PowerPC code (read timebase as long long).
+ * On ARM it just returns the timer value.
+ */
+unsigned long long get_ticks(void)
+{
+	return get_timer(0);
+}
+
+/*
+ * This function is derived from PowerPC code (timebase clock frequency).
+ * On ARM it returns the number of timer ticks per second.
+ */
+ulong get_tbclk(void)
+{
+	return CONFIG_SYS_HZ;
+}
+
+unsigned long timer_get_us(void)
+{
+	struct timerus *timer_base = (struct timerus *)NV_PA_TMRUS_BASE;
+
+	return readl(&timer_base->cntr_1us);
+}