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

Tom Warren twarren.nvidia at gmail.com
Thu Sep 13 00:10:50 CEST 2012


Signed-off-by: Tom Warren <twarren at 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

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 at 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 at ti.com>
+ * Syed Moahmmed Khasim <khasim at ti.com>
+ *
+ * (C) Copyright 2002
+ * Sysgo Real-Time Solutions, GmbH <www.elinos.com>
+ * Marius Groeger <mgroeger at sysgo.de>
+ * Alex Zuepke <azu at sysgo.de>
+ *
+ * (C) Copyright 2002
+ * Gary Jennejohn, DENX Software Engineering, <garyj at 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);
+}
-- 
1.7.0.4



More information about the U-Boot mailing list