[RFC/PATCH] ARM: add Tegra support

Mike Rapoport mike at compulab.co.il
Tue Mar 9 11:38:36 EST 2010


This patch adds basic support for Nvidia Tegra2 platform.

 From 13fac106b9383478a3337e443a946286998536d7 Mon Sep 17 00:00:00 2001
From: Mike Rapoport <mike at compulab.co.il>
Date: Tue, 9 Mar 2010 18:35:45 +0200
Subject: [PATCH] ARM: add Tegra support

Signed-off-by: Mike Rapoport <mike at compulab.co.il>
---
  arch/arm/Kconfig                               |   13 +
  arch/arm/Makefile                              |    1 +
  arch/arm/mach-tegra/Kconfig                    |   27 +
  arch/arm/mach-tegra/Makefile                   |   12 +
  arch/arm/mach-tegra/Makefile.boot              |    1 +
  arch/arm/mach-tegra/board-harmony.c            |   93 +++
  arch/arm/mach-tegra/clock.c                    |  105 +++
  arch/arm/mach-tegra/clock.h                    |   84 +++
  arch/arm/mach-tegra/common.h                   |   26 +
  arch/arm/mach-tegra/gpio.c                     |  335 ++++++++++
  arch/arm/mach-tegra/include/mach/clkdev.h      |   29 +
  arch/arm/mach-tegra/include/mach/debug-macro.S |   29 +
  arch/arm/mach-tegra/include/mach/entry-macro.S |  113 ++++
  arch/arm/mach-tegra/include/mach/gpio.h        |   44 ++
  arch/arm/mach-tegra/include/mach/hardware.h    |   58 ++
  arch/arm/mach-tegra/include/mach/io.h          |   35 +
  arch/arm/mach-tegra/include/mach/irqs.h        |  169 +++++
  arch/arm/mach-tegra/include/mach/memory.h      |   24 +
  arch/arm/mach-tegra/include/mach/system.h      |   34 +
  arch/arm/mach-tegra/include/mach/tegra.h       |  110 ++++
  arch/arm/mach-tegra/include/mach/timex.h       |   22 +
  arch/arm/mach-tegra/include/mach/uncompress.h  |   46 ++
  arch/arm/mach-tegra/include/mach/vmalloc.h     |   22 +
  arch/arm/mach-tegra/io.c                       |   73 +++
  arch/arm/mach-tegra/irq.c                      |   31 +
  arch/arm/mach-tegra/tegra2_clocks.c            |  809 ++++++++++++++++++++++++
  arch/arm/mach-tegra/timer.c                    |  182 ++++++
  27 files changed, 2527 insertions(+), 0 deletions(-)
  create mode 100644 arch/arm/mach-tegra/Kconfig
  create mode 100644 arch/arm/mach-tegra/Makefile
  create mode 100644 arch/arm/mach-tegra/Makefile.boot
  create mode 100644 arch/arm/mach-tegra/board-harmony.c
  create mode 100644 arch/arm/mach-tegra/clock.c
  create mode 100644 arch/arm/mach-tegra/clock.h
  create mode 100644 arch/arm/mach-tegra/common.h
  create mode 100644 arch/arm/mach-tegra/gpio.c
  create mode 100644 arch/arm/mach-tegra/include/mach/clkdev.h
  create mode 100644 arch/arm/mach-tegra/include/mach/debug-macro.S
  create mode 100644 arch/arm/mach-tegra/include/mach/entry-macro.S
  create mode 100644 arch/arm/mach-tegra/include/mach/gpio.h
  create mode 100644 arch/arm/mach-tegra/include/mach/hardware.h
  create mode 100644 arch/arm/mach-tegra/include/mach/io.h
  create mode 100644 arch/arm/mach-tegra/include/mach/irqs.h
  create mode 100644 arch/arm/mach-tegra/include/mach/memory.h
  create mode 100644 arch/arm/mach-tegra/include/mach/system.h
  create mode 100644 arch/arm/mach-tegra/include/mach/tegra.h
  create mode 100644 arch/arm/mach-tegra/include/mach/timex.h
  create mode 100644 arch/arm/mach-tegra/include/mach/uncompress.h
  create mode 100644 arch/arm/mach-tegra/include/mach/vmalloc.h
  create mode 100644 arch/arm/mach-tegra/io.c
  create mode 100644 arch/arm/mach-tegra/irq.c
  create mode 100644 arch/arm/mach-tegra/tegra2_clocks.c
  create mode 100644 arch/arm/mach-tegra/timer.c

diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 3b18128..d479cd8 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -750,6 +750,17 @@ config ARCH_U8500
  	help
  	  Support for ST-Ericsson's Ux500 architecture

+config ARCH_TEGRA
+        bool "NVIDIA Tegra"
+        select GENERIC_TIME
+        select GENERIC_CLOCKEVENTS
+        select GENERIC_GPIO
+        select HAVE_CLK
+        select COMMON_CLKDEV
+        help
+          This enables support for NVIDIA Tegra based systems (Tegra APX,
+          Tegra 6xx and Tegra 2 series).
+
  endchoice

  source "arch/arm/mach-aaec2000/Kconfig"
@@ -852,6 +863,8 @@ if ARCH_S5PC1XX
  source "arch/arm/mach-s5pc100/Kconfig"
  endif

+source "arch/arm/mach-tegra/Kconfig"
+
  source "arch/arm/mach-u300/Kconfig"

  source "arch/arm/mach-ux500/Kconfig"
diff --git a/arch/arm/Makefile b/arch/arm/Makefile
index 81f54ca..9f2a5fe 100644
--- a/arch/arm/Makefile
+++ b/arch/arm/Makefile
@@ -167,6 +167,7 @@ machine-$(CONFIG_ARCH_SA1100)		:= sa1100
  machine-$(CONFIG_ARCH_SHARK)		:= shark
  machine-$(CONFIG_ARCH_STMP378X)		:= stmp378x
  machine-$(CONFIG_ARCH_STMP37XX)		:= stmp37xx
+machine-$(CONFIG_ARCH_TEGRA)		:= tegra
  machine-$(CONFIG_ARCH_U300)		:= u300
  machine-$(CONFIG_ARCH_U8500)		:= ux500
  machine-$(CONFIG_ARCH_VERSATILE)	:= versatile
diff --git a/arch/arm/mach-tegra/Kconfig b/arch/arm/mach-tegra/Kconfig
new file mode 100644
index 0000000..731405f
--- /dev/null
+++ b/arch/arm/mach-tegra/Kconfig
@@ -0,0 +1,27 @@
+if ARCH_TEGRA
+
+comment "NVIDIA Tegra options"
+
+choice
+	prompt "Tegra processor family"
+
+config ARCH_TEGRA_2x_SOC
+	bool "Tegra 2 family"
+	select CPU_V7
+	select ARM_GIC
+	select ARCH_REQUIRE_GPIOLIB
+	help
+	  Support for NVIDIA Tegra AP20 and T20 processors, based on the
+	  ARM CortexA9MP CPU and the ARM PL310 L2 cache controller
+
+endchoice
+
+
+comment "Tegra-based boards"
+
+config MACH_HARMONY
+       bool "Harmony board"
+       help
+         Support for nVidia Harmony development platform
+
+endif
diff --git a/arch/arm/mach-tegra/Makefile b/arch/arm/mach-tegra/Makefile
new file mode 100644
index 0000000..ed4fb3b
--- /dev/null
+++ b/arch/arm/mach-tegra/Makefile
@@ -0,0 +1,12 @@
+#
+# Makefile for the linux kernel.
+#
+
+# Common support
+obj-y += irq.o io.o
+
+# SoC-specific support
+obj-$(CONFIG_ARCH_TEGRA_2x_SOC)	+= clock.o tegra2_clocks.o timer.o gpio.o
+
+# Board-specific support
+obj-$(CONFIG_MACH_HARMONY) += board-harmony.o
diff --git a/arch/arm/mach-tegra/Makefile.boot b/arch/arm/mach-tegra/Makefile.boot
new file mode 100644
index 0000000..dae9661
--- /dev/null
+++ b/arch/arm/mach-tegra/Makefile.boot
@@ -0,0 +1 @@
+zreladdr-y	:= 0x00008000
diff --git a/arch/arm/mach-tegra/board-harmony.c b/arch/arm/mach-tegra/board-harmony.c
new file mode 100644
index 0000000..f713393
--- /dev/null
+++ b/arch/arm/mach-tegra/board-harmony.c
@@ -0,0 +1,93 @@
+/*
+ * arch/arm/mach-tegra/board-harmony.c
+ *
+ * Copyright (C) 2010 Google, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/platform_device.h>
+#include <linux/serial_8250.h>
+#include <linux/clk.h>
+
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/time.h>
+#include <asm/setup.h>
+
+#include <mach/hardware.h>
+
+#include "common.h"
+
+static struct plat_serial8250_port debug_uart_platform_data[] = {
+	{
+		.membase	= IO_ADDRESS(TEGRA_UARTD_BASE),
+		.mapbase	= TEGRA_UARTD_BASE,
+		.irq		= INT_UARTD,
+		.flags		= UPF_BOOT_AUTOCONF,
+		.iotype		= UPIO_MEM,
+		.regshift	= 2,
+		.uartclk	= 216000000/16 * 16,
+	}, {
+		.flags		= 0
+	}
+};
+
+static struct platform_device debug_uart = {
+	.name = "serial8250",
+	.id = 0,
+	.dev = {
+		.platform_data = debug_uart_platform_data,
+	},
+};
+
+static struct platform_device *harmony_devices[] __initdata = {
+	&debug_uart,
+};
+
+static void __init tegra_harmony_fixup(struct machine_desc *desc,
+				       struct tag *tags,
+				       char **cmdline, struct meminfo *mi)
+{
+	mi->nr_banks = 2;
+	mi->bank[0].start = PHYS_OFFSET;
+	mi->bank[0].node = PHYS_TO_NID(PHYS_OFFSET);
+	mi->bank[0].size = (448*1024*1024);
+	mi->bank[1].start = 512*1024*1024;
+	mi->bank[1].node = PHYS_TO_NID(512*1024*1024);
+	mi->bank[1].size = (512*1024*1024);
+}
+
+static void __init tegra_harmony_init(void)
+{
+	struct clk *clk;
+
+	clk = clk_get_sys(NULL, "pll_p");
+	clk_enable(clk);
+	clk_set_rate(clk, 216000000);
+
+	clk = clk_get_sys("uart.3", NULL);
+	clk_set_rate(clk, 216000000);
+	clk_enable(clk);
+
+	platform_add_devices(harmony_devices, ARRAY_SIZE(harmony_devices));
+}
+
+MACHINE_START(HARMONY, "harmony")
+	.boot_params  = 0x00000100,
+	.phys_io        = IO_APB_PHYS,
+	.io_pg_offst    = ((IO_APB_VIRT) >> 18) & 0xfffc,
+	.timer          = &tegra_timer,
+	.init_irq       = tegra_init_irq,
+	.map_io         = tegra_map_common_io,
+	.init_machine   = tegra_harmony_init,
+	.fixup		= tegra_harmony_fixup,
+MACHINE_END
diff --git a/arch/arm/mach-tegra/clock.c b/arch/arm/mach-tegra/clock.c
new file mode 100644
index 0000000..729ddb5
--- /dev/null
+++ b/arch/arm/mach-tegra/clock.c
@@ -0,0 +1,105 @@
+/*
+ * arch/arm/mach-tegra/clock.c
+ *
+ * Copyright (C) 2010 Google, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/clk.h>
+#include <linux/list.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <asm/clkdev.h>
+
+#include "clock.h"
+
+static DEFINE_SPINLOCK(clk_spinlock);
+
+int clk_enable(struct clk *c)
+{
+	int ret = 0;
+	unsigned long flags;
+	if (c->refcnt == 0) {
+		if (c->parent) {
+			ret = clk_enable(c->parent);
+			if (ret)
+				goto err;
+		}
+
+		if (c->ops && c->ops->enable) {
+			spin_lock_irqsave(&clk_spinlock, flags);
+			ret = c->ops->enable(c);
+			spin_unlock_irqrestore(&clk_spinlock, flags);
+			if (ret) {
+				if (c->parent)
+					clk_disable(c->parent);
+				goto err;
+			}
+		}
+	}
+	c->refcnt++;
+err:
+	return ret;
+}
+EXPORT_SYMBOL(clk_enable);
+
+void clk_disable(struct clk *c)
+{
+	unsigned long flags;
+	if (c->refcnt == 0) {
+		WARN(1, "Trying to disable clock %s with refcnt 0", c->name);
+		return;
+	}
+
+	if (c->refcnt == 1) {
+		if (c->parent)
+			clk_disable(c->parent);
+
+		if (c->ops && c->ops->disable) {
+			spin_lock_irqsave(&clk_spinlock, flags);
+			c->ops->disable(c);
+			spin_unlock_irqrestore(&clk_spinlock, flags);
+		}
+	}
+	c->refcnt--;
+}
+EXPORT_SYMBOL(clk_disable);
+
+int clk_set_parent(struct clk *c, struct clk *parent)
+{
+	if (c->ops && c->ops->set_parent)
+		return c->ops->set_parent(c, parent);
+	else
+		BUG();
+}
+EXPORT_SYMBOL(clk_set_parent);
+
+int clk_set_rate(struct clk *c, unsigned long rate)
+{
+	if (c->ops && c->ops->set_rate)
+		return c->ops->set_rate(c, rate);
+	else
+		BUG();
+}
+EXPORT_SYMBOL(clk_set_rate);
+
+unsigned long clk_get_rate(struct clk *c)
+{
+	if (c->ops && c->ops->get_rate)
+		return c->ops->get_rate(c);
+	else if (c->parent)
+		return clk_get_rate(c->parent);
+	else
+		BUG();
+}
+EXPORT_SYMBOL(clk_get_rate);
diff --git a/arch/arm/mach-tegra/clock.h b/arch/arm/mach-tegra/clock.h
new file mode 100644
index 0000000..a6c77bb
--- /dev/null
+++ b/arch/arm/mach-tegra/clock.h
@@ -0,0 +1,84 @@
+/*
+ * arch/arm/mach-tegra/include/mach/clock.h
+ *
+ * Copyright (C) 2010 Google, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#define ENABLE_ON_INIT	0x00000001
+#define DIV_U71 	0x00000002
+#define DIV_U71_FIXED	0x00000004
+#define DIV_2		0x00000008
+#define PLL_FIXED 	0x00000010
+#define PLL_HAS_CPCON 	0x00000020
+#define MUX		0x00000040
+
+struct clk;
+
+struct clk_mux_sel {
+	struct clk	*input;
+	u32		value;
+};
+
+struct clk_pll_table {
+	unsigned long   input_rate;
+	unsigned long   output_rate;
+	u16             n;
+	u16             m;
+	u8              p;
+	u8              cpcon;
+};
+
+struct clk_ops {
+	void		(*init)(struct clk *);
+	int		(*enable)(struct clk *);
+	void		(*disable)(struct clk *);
+	void		(*recalc)(struct clk *);
+	int		(*set_parent)(struct clk *, struct clk *);
+	int		(*set_rate)(struct clk *, unsigned long);
+	unsigned long   (*get_rate)(struct clk *);
+	long		(*round_rate)(struct clk *, unsigned long);
+};
+
+struct clk {
+	const char			*name;
+	struct clk_ops			*ops;
+	struct clk			*parent;
+	unsigned long			rate;
+	u32				flags;
+	u32				refcnt;
+	u32				reg;
+	u32				reg_shift;
+	unsigned int                    clk_num;
+
+	/* PLL */
+	unsigned long			input_min;
+	unsigned long			input_max;
+	unsigned long			cf_min;
+	unsigned long			cf_max;
+	unsigned long			vco_min;
+	unsigned long			vco_max;
+	u32				m;
+	u32				n;
+	u32				p;
+	u32                             cpcon;
+	const struct clk_pll_table      *pll_table;
+
+	/* DIV */
+
+	/* MUX */
+	const struct clk_mux_sel 	*inputs;
+	u32                     	sel;
+	u32                     	reg_mask;
+};
+
+extern void tegra2_arch_clk_init(void);
diff --git a/arch/arm/mach-tegra/common.h b/arch/arm/mach-tegra/common.h
new file mode 100644
index 0000000..4430e36
--- /dev/null
+++ b/arch/arm/mach-tegra/common.h
@@ -0,0 +1,26 @@
+/*
+ * arch/arm/mach-tegra/include/mach/board.h
+ *
+ * Copyright (C) 2010 Google, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef __MACH_TEGRA_BOARD_H
+#define __MACH_TEGRA_BOARD_H
+
+extern struct sys_timer tegra_timer;
+
+void __init tegra_map_common_io(void);
+void __init tegra_init_irq(void);
+void __init tegra_init_clock(void);
+
+#endif
diff --git a/arch/arm/mach-tegra/gpio.c b/arch/arm/mach-tegra/gpio.c
new file mode 100644
index 0000000..9625bd2
--- /dev/null
+++ b/arch/arm/mach-tegra/gpio.c
@@ -0,0 +1,335 @@
+/*
+ * arch/arm/mach-tegra/gpio.c
+ *
+ * Copyright (c) 2010 Google, Inc
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; 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.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+#include <linux/init.h>
+#include <linux/irq.h>
+
+#include <asm/io.h>
+#include <asm/gpio.h>
+
+#include <mach/hardware.h>
+
+#define GPIO_BANK(x)		((x) >> 5)
+#define GPIO_PORT(x)		(((x) >> 3) & 0x3)
+#define GPIO_BIT(x)		((x) & 0x7)
+
+#define GPIO_REG(x)		(IO_TO_VIRT(TEGRA_GPIO_BASE) +	\
+				 GPIO_BANK(x) * 0x80 +		\
+				 GPIO_PORT(x) * 4)
+
+#define GPIO_CNF(x)		(GPIO_REG(x) + 0x00)
+#define GPIO_OE(x)		(GPIO_REG(x) + 0x10)
+#define GPIO_OUT(x)		(GPIO_REG(x) + 0X20)
+#define GPIO_IN(x)		(GPIO_REG(x) + 0x30)
+#define GPIO_INT_STA(x)		(GPIO_REG(x) + 0x40)
+#define GPIO_INT_ENB(x)		(GPIO_REG(x) + 0x50)
+#define GPIO_INT_LVL(x)		(GPIO_REG(x) + 0x60)
+#define GPIO_INT_CLR(x)		(GPIO_REG(x) + 0x70)
+
+#define GPIO_MSK_CNF(x)		(GPIO_REG(x) + 0x800)
+#define GPIO_MSK_OE(x)		(GPIO_REG(x) + 0x810)
+#define GPIO_MSK_OUT(x)		(GPIO_REG(x) + 0X820)
+#define GPIO_MSK_INT_STA(x)	(GPIO_REG(x) + 0x840)
+#define GPIO_MSK_INT_ENB(x)	(GPIO_REG(x) + 0x850)
+#define GPIO_MSK_INT_LVL(x)	(GPIO_REG(x) + 0x860)
+
+#define GPIO_INT_LVL_MASK		0x010101
+#define GPIO_INT_LVL_EDGE_RISING	0x000101
+#define GPIO_INT_LVL_EDGE_FALLING	0x000100
+#define GPIO_INT_LVL_EDGE_BOTH		0x010100
+#define GPIO_INT_LVL_LEVEL_HIGH		0x000001
+#define GPIO_INT_LVL_LEVEL_LOW		0x000000
+
+struct tegra_gpio_bank {
+	int bank;
+	int irq;
+	spinlock_t lvl_lock[4];
+};
+
+static struct tegra_gpio_bank tegra_gpio_banks[] = {
+	{.bank = 0, .irq = INT_GPIO1},
+	{.bank = 1, .irq = INT_GPIO2},
+	{.bank = 2, .irq = INT_GPIO3},
+	{.bank = 3, .irq = INT_GPIO4},
+	{.bank = 4, .irq = INT_GPIO5},
+	{.bank = 5, .irq = INT_GPIO6},
+	{.bank = 6, .irq = INT_GPIO7},
+};
+
+static int tegra_gpio_compose(int bank, int port, int bit)
+{
+	return (bank << 5) | ((port & 0x3) << 3) | (bit & 0x7);
+}
+
+static void tegra_gpio_mask_write(u32 reg, int gpio, int value)
+{
+	u32 val;
+
+	val = 0x100 << GPIO_BIT(gpio);
+	if (value)
+		val |= 1 << GPIO_BIT(gpio);
+	__raw_writel(val, reg);
+}
+
+static void tegra_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
+{
+	tegra_gpio_mask_write(GPIO_MSK_OUT(offset), offset, value);
+}
+
+static int tegra_gpio_get(struct gpio_chip *chip, unsigned offset)
+{
+	return (__raw_readl(GPIO_IN(offset)) >> GPIO_BIT(offset)) & 0x1;
+}
+
+static int tegra_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
+{
+	tegra_gpio_mask_write(GPIO_MSK_OE(offset), offset, 0);
+	return 0;
+}
+
+static int tegra_gpio_direction_output(struct gpio_chip *chip, unsigned offset,
+					int value)
+{
+	tegra_gpio_mask_write(GPIO_MSK_OE(offset), offset, 1);
+	return 0;
+}
+
+static struct gpio_chip tegra_gpio_chip = {
+	.label			= "tegra-gpio",
+	.direction_input	= tegra_gpio_direction_input,
+	.get			= tegra_gpio_get,
+	.direction_output	= tegra_gpio_direction_output,
+	.set			= tegra_gpio_set,
+	.base			= 0,
+	.ngpio			= ARCH_NR_GPIOS,
+};
+
+static void tegra_gpio_irq_ack(unsigned int irq)
+{
+	int gpio = irq - INT_GPIO_BASE;
+
+	__raw_writel(1 << GPIO_BIT(gpio), GPIO_INT_CLR(gpio));
+}
+
+static void tegra_gpio_irq_mask(unsigned int irq)
+{
+	int gpio = irq - INT_GPIO_BASE;
+
+	tegra_gpio_mask_write(GPIO_MSK_INT_ENB(gpio), gpio, 0);
+}
+
+static void tegra_gpio_irq_unmask(unsigned int irq)
+{
+	int gpio = irq - INT_GPIO_BASE;
+
+	tegra_gpio_mask_write(GPIO_MSK_INT_ENB(gpio), gpio, 1);
+}
+
+static int tegra_gpio_irq_set_type(unsigned int irq, unsigned int type)
+{
+	int gpio = irq - INT_GPIO_BASE;
+	struct tegra_gpio_bank *bank = get_irq_data(irq);
+	int port = GPIO_PORT(gpio);
+	int lvl_type;
+	int val;
+	unsigned long flags;
+
+	switch (type) {
+	case IRQ_TYPE_EDGE_RISING:
+		lvl_type = GPIO_INT_LVL_EDGE_RISING;
+		break;
+
+	case IRQ_TYPE_EDGE_FALLING:
+		lvl_type = GPIO_INT_LVL_EDGE_FALLING;
+		break;
+
+	case IRQ_TYPE_EDGE_BOTH:
+		lvl_type = GPIO_INT_LVL_EDGE_BOTH;
+		break;
+
+	case IRQ_TYPE_LEVEL_HIGH:
+		lvl_type = GPIO_INT_LVL_LEVEL_HIGH;
+		break;
+
+	case IRQ_TYPE_LEVEL_LOW:
+		lvl_type = GPIO_INT_LVL_LEVEL_LOW;
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	spin_lock_irqsave(&bank->lvl_lock[port], flags);
+
+	val = __raw_readl(GPIO_INT_LVL(gpio));
+	val &= ~(GPIO_INT_LVL_MASK << GPIO_BIT(gpio));
+	val |= lvl_type << GPIO_BIT(gpio);
+	__raw_writel(val, GPIO_INT_LVL(gpio));
+
+	spin_unlock_irqrestore(&bank->lvl_lock[port], flags);
+
+	if (type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH))
+		__set_irq_handler_unlocked(irq, handle_level_irq);
+	else if (type & (IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING))
+		__set_irq_handler_unlocked(irq, handle_edge_irq);
+
+	return 0;
+}
+
+static void tegra_gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
+{
+	struct tegra_gpio_bank *bank;
+	int port;
+	int pin;
+	int unmasked = 0;
+
+	desc->chip->ack(irq);
+
+	bank = get_irq_data(irq);
+
+	for (port = 0; port < 4; port++) {
+		int gpio = tegra_gpio_compose(bank->bank, port, 0);
+		unsigned long sta = __raw_readl(GPIO_INT_STA(gpio)) &
+			__raw_readl(GPIO_INT_ENB(gpio));
+		u32 lvl = __raw_readl(GPIO_INT_LVL(gpio));
+
+		for_each_bit(pin, &sta, 8) {
+			__raw_writel(1 << pin, GPIO_INT_CLR(gpio));
+
+			/* if gpio is edge triggered, clear condition
+			 * before executing the hander so that we don't
+			 * miss edges
+			 */
+			if (lvl & (0x100 << pin)) {
+				unmasked = 1;
+				desc->chip->unmask(irq);
+			}
+
+			generic_handle_irq(gpio_to_irq(gpio + pin));
+		}
+	}
+
+	if (!unmasked)
+		desc->chip->unmask(irq);
+
+}
+
+
+static struct irq_chip tegra_gpio_irq_chip = {
+	.name		= "GPIO",
+	.ack		= tegra_gpio_irq_ack,
+	.mask		= tegra_gpio_irq_mask,
+	.unmask		= tegra_gpio_irq_unmask,
+	.set_type	= tegra_gpio_irq_set_type,
+};
+
+
+/* This lock class tells lockdep that GPIO irqs are in a different
+ * category than their parents, so it won't report false recursion.
+ */
+static struct lock_class_key gpio_lock_class;
+
+static int __init tegra_gpio_init(void)
+{
+	struct tegra_gpio_bank *bank;
+	int i;
+	int j;
+
+	for (i = 0; i < 7; i++) {
+		for (j = 0; j < 4; j++) {
+			int gpio = tegra_gpio_compose(i, j, 0);
+			__raw_writel(0x00, GPIO_INT_ENB(gpio));
+		}
+	}
+
+	gpiochip_add(&tegra_gpio_chip);
+
+	for (i = INT_GPIO_BASE; i < (INT_GPIO_BASE + ARCH_NR_GPIOS); i++) {
+		bank = &tegra_gpio_banks[GPIO_BANK(i)];
+
+		lockdep_set_class(&irq_desc[i].lock, &gpio_lock_class);
+		set_irq_chip_data(i, bank);
+		set_irq_chip(i, &tegra_gpio_irq_chip);
+		set_irq_handler(i, handle_simple_irq);
+		set_irq_flags(i, IRQF_VALID);
+	}
+
+	for (i = 0; i < ARRAY_SIZE(tegra_gpio_banks); i++) {
+		bank = &tegra_gpio_banks[i];
+
+		set_irq_chained_handler(bank->irq, tegra_gpio_irq_handler);
+		set_irq_data(bank->irq, bank);
+
+		for (j = 0; j < 4; j++)
+			spin_lock_init(&bank->lvl_lock[j]);
+	}
+
+	return 0;
+}
+
+postcore_initcall(tegra_gpio_init);
+
+#ifdef	CONFIG_DEBUG_FS
+
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
+
+static int dbg_gpio_show(struct seq_file *s, void *unused)
+{
+	int i;
+	int j;
+
+	for (i = 0; i < 7; i++) {
+		for (j = 0; j < 4; j++) {
+			int gpio = tegra_gpio_compose(i, j, 0);
+			seq_printf(s, "%d:%d %02x %02x %02x %02x %02x %02x %06x\n",
+			       i, j,
+			       __raw_readl(GPIO_CNF(gpio)),
+			       __raw_readl(GPIO_OE(gpio)),
+			       __raw_readl(GPIO_OUT(gpio)),
+			       __raw_readl(GPIO_IN(gpio)),
+			       __raw_readl(GPIO_INT_STA(gpio)),
+			       __raw_readl(GPIO_INT_ENB(gpio)),
+			       __raw_readl(GPIO_INT_LVL(gpio)));
+		}
+	}
+	return 0;
+}
+
+static int dbg_gpio_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, dbg_gpio_show, &inode->i_private);
+}
+
+static const struct file_operations debug_fops = {
+	.open		= dbg_gpio_open,
+	.read		= seq_read,
+	.llseek		= seq_lseek,
+	.release	= single_release,
+};
+
+static int __init tegra_gpio_debuginit(void)
+{
+	(void) debugfs_create_file("tegra_gpio", S_IRUGO,
+					NULL, NULL, &debug_fops);
+	return 0;
+}
+late_initcall(tegra_gpio_debuginit);
+#endif
diff --git a/arch/arm/mach-tegra/include/mach/clkdev.h b/arch/arm/mach-tegra/include/mach/clkdev.h
new file mode 100644
index 0000000..f3dd0d3
--- /dev/null
+++ b/arch/arm/mach-tegra/include/mach/clkdev.h
@@ -0,0 +1,29 @@
+/*
+ * arch/arm/mach-tegra/include/mach/clkdev.h
+ *
+ * Copyright (C) 2010 Google, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef __MACH_CLKDEV_H
+#define __MACH_CLKDEV_H
+
+static inline int __clk_get(struct clk *clk)
+{
+	return 1;
+}
+
+static inline void __clk_put(struct clk *clk)
+{
+}
+
+#endif
diff --git a/arch/arm/mach-tegra/include/mach/debug-macro.S b/arch/arm/mach-tegra/include/mach/debug-macro.S
new file mode 100644
index 0000000..0c119f3
--- /dev/null
+++ b/arch/arm/mach-tegra/include/mach/debug-macro.S
@@ -0,0 +1,29 @@
+/*
+ * arch/arm/mach-tegra/include/mach/debug-macro.S
+ *
+ * Copyright (C) 2010 Google, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <mach/hardware.h>
+
+	.macro  addruart, rx, tmp
+        mrc     p15, 0, \rx, c1, c0
+        tst     \rx, #1                 @ MMU enabled?
+        ldreq   \rx, =IO_APB_PHYS       @ physical
+        ldrne   \rx, =IO_APB_VIRT       @ virtual
+        orr     \rx, \rx, #0x6300	@ UART D
+	.endm
+
+#define UART_SHIFT	2
+#include <asm/hardware/debug-8250.S>
+
diff --git a/arch/arm/mach-tegra/include/mach/entry-macro.S b/arch/arm/mach-tegra/include/mach/entry-macro.S
new file mode 100644
index 0000000..05a618c
--- /dev/null
+++ b/arch/arm/mach-tegra/include/mach/entry-macro.S
@@ -0,0 +1,113 @@
+/*
+ * arch/arm/mach-tegra/include/mach/entry-macro.S
+ *
+ * Copyright (C) 2009 Palm, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+#include <mach/hardware.h>
+
+#if defined(CONFIG_ARM_GIC)
+
+#include <asm/hardware/gic.h>
+
+	/* Uses the GIC interrupt controller built into the cpu */
+#define ICTRL_BASE (IO_CPU_VIRT + 0x100)
+
+	.macro	disable_fiq
+	.endm
+
+	.macro	get_irqnr_preamble, base, tmp
+	movw \base, #(ICTRL_BASE & 0x0000ffff)
+	movt \base, #((ICTRL_BASE & 0xffff0000) >> 16)
+	.endm
+
+	.macro  arch_ret_to_user, tmp1, tmp2
+	.endm
+
+	/*
+	 * The interrupt numbering scheme is defined in the
+	 * interrupt controller spec.  To wit:
+	 *
+	 * Interrupts 0-15 are IPI
+	 * 16-28 are reserved
+	 * 29-31 are local.  We allow 30 to be used for the watchdog.
+	 * 32-1020 are global
+	 * 1021-1022 are reserved
+	 * 1023 is "spurious" (no interrupt)
+	 *
+	 * For now, we ignore all local interrupts so only return an
+	 * interrupt if it's between 30 and 1020.  The test_for_ipi
+	 * routine below will pick up on IPIs.
+	 *
+	 * A simple read from the controller will tell us the number
+	 * of the highest priority enabled interrupt.  We then just
+	 * need to check whether it is in the valid range for an IRQ
+	 * (30-1020 inclusive).
+	 */
+
+	.macro  get_irqnr_and_base, irqnr, irqstat, base, tmp
+	/* bits 12-10 = src CPU, 9-0 = int # */
+	ldr     \irqstat, [\base, #GIC_CPU_INTACK]
+	ldr	\tmp, =1021
+	bic     \irqnr, \irqstat, #0x1c00
+	cmp     \irqnr, #29
+	cmpcc	\irqnr, \irqnr
+	cmpne	\irqnr, \tmp
+	cmpcs	\irqnr, \irqnr
+	.endm
+
+	/*
+	 * We assume that irqstat (the raw value of the IRQ acknowledge
+	 * register) is preserved from the macro above.
+	 * If there is an IPI, we immediately signal end of interrupt on the
+	 * controller, since this requires the original irqstat value which
+	 * we won't easily be able to recreate later.
+	 */
+	.macro test_for_ipi, irqnr, irqstat, base, tmp
+	bic	\irqnr, \irqstat, #0x1c00
+	cmp	\irqnr, #16
+	strcc	\irqstat, [\base, #GIC_CPU_EOI]
+	cmpcs	\irqnr, \irqnr
+	.endm
+
+	/* As above, this assumes that irqstat and base are preserved.. */
+	.macro test_for_ltirq, irqnr, irqstat, base, tmp
+	bic	\irqnr, \irqstat, #0x1c00
+	mov 	\tmp, #0
+	cmp	\irqnr, #29
+	moveq	\tmp, #1
+	streq	\irqstat, [\base, #GIC_CPU_EOI]
+	cmp	\tmp, #0
+	.endm
+
+#else
+	/* legacy interrupt controller for AP16 */
+	.macro	disable_fiq
+	.endm
+
+	.macro	get_irqnr_preamble, base, tmp
+	@ enable imprecise aborts
+	cpsie	a
+	@ EVP base at 0xf010f000
+	mov \base, #0xf0000000
+	orr \base, #0x00100000
+	orr \base, #0x0000f000
+	.endm
+
+	.macro	arch_ret_to_user, tmp1, tmp2
+	.endm
+
+	.macro	get_irqnr_and_base, irqnr, irqstat, base, tmp
+	ldr \irqnr, [\base, #0x20]	@ EVT_IRQ_STS
+	cmp \irqnr, #0x80
+	.endm
+#endif
diff --git a/arch/arm/mach-tegra/include/mach/gpio.h b/arch/arm/mach-tegra/include/mach/gpio.h
new file mode 100644
index 0000000..612f49e
--- /dev/null
+++ b/arch/arm/mach-tegra/include/mach/gpio.h
@@ -0,0 +1,44 @@
+/*
+ * arch/arm/mach-tegra/include/mach/gpio.h
+ *
+ * Copyright (C) 2010 Google, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef __MACH_TEGRA_GPIO_H
+#define __MACH_TEGRA_GPIO_H
+
+#include <mach/irqs.h>
+
+#define ARCH_NR_GPIOS		INT_GPIO_NR
+
+#include <asm-generic/gpio.h>
+
+#define gpio_get_value		__gpio_get_value
+#define gpio_set_value		__gpio_set_value
+#define gpio_cansleep		__gpio_cansleep
+
+static inline int gpio_to_irq(unsigned int gpio)
+{
+	if (gpio < ARCH_NR_GPIOS)
+		return INT_GPIO_BASE + gpio;
+	return -EINVAL;
+}
+
+static inline int irq_to_gpio(unsigned int irq)
+{
+	if ((irq >= INT_GPIO_BASE) && (irq < INT_GPIO_BASE + INT_GPIO_NR))
+		return irq - INT_GPIO_BASE;
+	return -EINVAL;
+}
+
+#endif
diff --git a/arch/arm/mach-tegra/include/mach/hardware.h b/arch/arm/mach-tegra/include/mach/hardware.h
new file mode 100644
index 0000000..381adb1
--- /dev/null
+++ b/arch/arm/mach-tegra/include/mach/hardware.h
@@ -0,0 +1,58 @@
+/*
+ * arch/arm/mach-tegra/include/mach/hardware.h
+ *
+ * Copyright (C) 2010 Google, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef __MACH_TEGRA_HARDWARE_H
+#define __MACH_TEGRA_HARDWARE_H
+
+#include "tegra.h"
+
+/* On TEGRA, many peripherals are very closely packed in
+ * two 256MB io windows (that actually only use about 64KB
+ * at the start of each).
+ *
+ * We will just map the first 1MB of each window (to minimize
+ * pt entries needed) and provide a macro to transform physical
+ * io addresses to an appropriate void __iomem *.
+ *
+ */
+
+#define IO_CPU_PHYS     0x50040000
+#define IO_CPU_VIRT     0xFE000000
+#define IO_CPU_SIZE	SZ_16K
+
+#define IO_PPSB_PHYS	0x60000000
+#define IO_PPSB_VIRT	0xFE200000
+#define IO_PPSB_SIZE	SZ_1M
+
+#define IO_APB_PHYS	0x70000000
+#define IO_APB_VIRT	0xFE300000
+#define IO_APB_SIZE	SZ_1M
+
+#define IO_TO_VIRT_BETWEEN(p, st, sz)	((p) >= (st) && (p) < ((st) + (sz)))
+#define IO_TO_VIRT_XLATE(p, pst, vst)	(((p) - (pst) + (vst)))
+
+#define IO_TO_VIRT(n) ( \
+	IO_TO_VIRT_BETWEEN((n), IO_PPSB_PHYS, IO_PPSB_SIZE) ?		\
+		IO_TO_VIRT_XLATE((n), IO_PPSB_PHYS, IO_PPSB_VIRT) :	\
+	IO_TO_VIRT_BETWEEN((n), IO_APB_PHYS, IO_APB_SIZE) ?		\
+		IO_TO_VIRT_XLATE((n), IO_APB_PHYS, IO_APB_VIRT) :	\
+	IO_TO_VIRT_BETWEEN((n), IO_CPU_PHYS, IO_CPU_SIZE) ?		\
+		IO_TO_VIRT_XLATE((n), IO_CPU_PHYS, IO_CPU_VIRT) :	\
+	0)
+
+#define IO_ADDRESS(n) ((void __iomem *) IO_TO_VIRT(n))
+
+#endif
diff --git a/arch/arm/mach-tegra/include/mach/io.h b/arch/arm/mach-tegra/include/mach/io.h
new file mode 100644
index 0000000..7198934
--- /dev/null
+++ b/arch/arm/mach-tegra/include/mach/io.h
@@ -0,0 +1,35 @@
+/*
+ * arch/arm/mach-tegra/include/mach/io.h
+ *
+ * Copyright (C) 2010 Google, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef __MACH_TEGRA_IO_H
+#define __MACH_TEGRA_IO_H
+
+#define IO_SPACE_LIMIT 0xffffffff
+
+#define __io(a)         __typesafe_io(a)
+#define __mem_pci(a)    (a)
+
+#ifndef __ASSEMBLER__
+
+#define __arch_ioremap(p, s, t)	tegra_ioremap(p, s, t)
+#define __arch_iounmap(v)	tegra_iounmap(v)
+
+void __iomem *tegra_ioremap(unsigned long phys, size_t size, unsigned int type);
+void tegra_iounmap(volatile void __iomem *addr);
+
+#endif
+
+#endif
diff --git a/arch/arm/mach-tegra/include/mach/irqs.h b/arch/arm/mach-tegra/include/mach/irqs.h
new file mode 100644
index 0000000..230fae3
--- /dev/null
+++ b/arch/arm/mach-tegra/include/mach/irqs.h
@@ -0,0 +1,169 @@
+/*
+ * arch/arm/mach-tegra/include/mach/irqs.h
+ *
+ * Copyright (C) 2010 Google, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef __MACH_TEGRA_IRQS_H
+#define __MACH_TEGRA_IRQS_H
+
+#define INT_GIC_BASE			0
+
+#define IRQ_LOCALTIMER                  29
+
+/* Primary Interrupt Controller */
+#define INT_PRI_BASE			(INT_GIC_BASE + 32)
+#define INT_TMR1			(INT_PRI_BASE + 0)
+#define INT_TMR2			(INT_PRI_BASE + 1)
+#define INT_RTC				(INT_PRI_BASE + 2)
+#define INT_I2S2			(INT_PRI_BASE + 3)
+#define INT_SHR_SEM_INBOX_IBF		(INT_PRI_BASE + 4)
+#define INT_SHR_SEM_INBOX_IBE		(INT_PRI_BASE + 5)
+#define INT_SHR_SEM_OUTBOX_IBF		(INT_PRI_BASE + 6)
+#define INT_SHR_SEM_OUTBOX_IBE		(INT_PRI_BASE + 7)
+#define INT_VDE_UCQ_ERROR		(INT_PRI_BASE + 8)
+#define INT_VDE_SYNC_TOKEN		(INT_PRI_BASE + 9)
+#define INT_VDE_BSE_V			(INT_PRI_BASE + 10)
+#define INT_VDE_BSE_A			(INT_PRI_BASE + 11)
+#define INT_VDE_SXE			(INT_PRI_BASE + 12)
+#define INT_I2S1			(INT_PRI_BASE + 13)
+#define INT_SDMMC1			(INT_PRI_BASE + 14)
+#define INT_SDMMC2			(INT_PRI_BASE + 15)
+#define INT_XIO				(INT_PRI_BASE + 16)
+#define INT_VDE				(INT_PRI_BASE + 17)
+#define INT_AVP_UCQ			(INT_PRI_BASE + 18)
+#define INT_SDMMC3			(INT_PRI_BASE + 19)
+#define INT_USB				(INT_PRI_BASE + 20)
+#define INT_USB2			(INT_PRI_BASE + 21)
+#define INT_PRI_RES_22			(INT_PRI_BASE + 22)
+#define INT_EIDE			(INT_PRI_BASE + 23)
+#define INT_NANDFLASH			(INT_PRI_BASE + 24)
+#define INT_VCP				(INT_PRI_BASE + 25)
+#define INT_APB_DMA			(INT_PRI_BASE + 26)
+#define INT_AHB_DMA			(INT_PRI_BASE + 27)
+#define INT_GNT_0			(INT_PRI_BASE + 28)
+#define INT_GNT_1			(INT_PRI_BASE + 29)
+#define INT_OWR				(INT_PRI_BASE + 30)
+#define INT_SDMMC4			(INT_PRI_BASE + 31)
+
+/* Secondary Interrupt Controller */
+#define INT_SEC_BASE			(INT_PRI_BASE + 32)
+#define INT_GPIO1			(INT_SEC_BASE + 0)
+#define INT_GPIO2			(INT_SEC_BASE + 1)
+#define INT_GPIO3			(INT_SEC_BASE + 2)
+#define INT_GPIO4			(INT_SEC_BASE + 3)
+#define INT_UARTA			(INT_SEC_BASE + 4)
+#define INT_UARTB			(INT_SEC_BASE + 5)
+#define INT_I2C				(INT_SEC_BASE + 6)
+#define INT_SPI				(INT_SEC_BASE + 7)
+#define INT_TWC				(INT_SEC_BASE + 8)
+#define INT_TMR3			(INT_SEC_BASE + 9)
+#define INT_TMR4			(INT_SEC_BASE + 10)
+#define INT_FLOW_RSM0			(INT_SEC_BASE + 11)
+#define INT_FLOW_RSM1			(INT_SEC_BASE + 12)
+#define INT_SPDIF			(INT_SEC_BASE + 13)
+#define INT_UARTC			(INT_SEC_BASE + 14)
+#define INT_MIPI			(INT_SEC_BASE + 15)
+#define INT_EVENTA			(INT_SEC_BASE + 16)
+#define INT_EVENTB			(INT_SEC_BASE + 17)
+#define INT_EVENTC			(INT_SEC_BASE + 18)
+#define INT_EVENTD			(INT_SEC_BASE + 19)
+#define INT_VFIR			(INT_SEC_BASE + 20)
+#define INT_DVC				(INT_SEC_BASE + 21)
+#define INT_SYS_STATS_MON		(INT_SEC_BASE + 22)
+#define INT_GPIO5			(INT_SEC_BASE + 23)
+#define INT_CPU0_PMU_INTR		(INT_SEC_BASE + 24)
+#define INT_CPU2_PMU_INTR		(INT_SEC_BASE + 25)
+#define INT_SEC_RES_26			(INT_SEC_BASE + 26)
+#define INT_S_LINK1			(INT_SEC_BASE + 27)
+#define INT_APB_DMA_COP			(INT_SEC_BASE + 28)
+#define INT_AHB_DMA_COP			(INT_SEC_BASE + 29)
+#define INT_DMA_TX			(INT_SEC_BASE + 30)
+#define INT_DMA_RX			(INT_SEC_BASE + 31)
+
+/* Tertiary Interrupt Controller */
+#define INT_TRI_BASE			(INT_SEC_BASE + 32)
+#define INT_HOST1X_COP_SYNCPT		(INT_TRI_BASE + 0)
+#define INT_HOST1X_MPCORE_SYNCPT	(INT_TRI_BASE + 1)
+#define INT_HOST1X_COP_GENERAL		(INT_TRI_BASE + 2)
+#define INT_HOST1X_MPCORE_GENERAL	(INT_TRI_BASE + 3)
+#define INT_MPE_GENERAL			(INT_TRI_BASE + 4)
+#define INT_VI_GENERAL			(INT_TRI_BASE + 5)
+#define INT_EPP_GENERAL			(INT_TRI_BASE + 6)
+#define INT_ISP_GENERAL			(INT_TRI_BASE + 7)
+#define INT_2D_GENERAL			(INT_TRI_BASE + 8)
+#define INT_DISPLAY_GENERAL		(INT_TRI_BASE + 9)
+#define INT_DISPLAY_B_GENERAL		(INT_TRI_BASE + 10)
+#define INT_HDMI			(INT_TRI_BASE + 11)
+#define INT_TVO_GENERAL			(INT_TRI_BASE + 12)
+#define INT_MC_GENERAL			(INT_TRI_BASE + 13)
+#define INT_EMC_GENERAL			(INT_TRI_BASE + 14)
+#define INT_TRI_RES_15			(INT_TRI_BASE + 15)
+#define INT_TRI_RES_16			(INT_TRI_BASE + 16)
+#define INT_AC97			(INT_TRI_BASE + 17)
+#define INT_SPI_2			(INT_TRI_BASE + 18)
+#define INT_SPI_3			(INT_TRI_BASE + 19)
+#define INT_I2C2			(INT_TRI_BASE + 20)
+#define INT_KBC				(INT_TRI_BASE + 21)
+#define INT_EXTERNAL_PMU		(INT_TRI_BASE + 22)
+#define INT_GPIO6			(INT_TRI_BASE + 23)
+#define INT_TVDAC			(INT_TRI_BASE + 24)
+#define INT_GPIO7			(INT_TRI_BASE + 25)
+#define INT_UARTD			(INT_TRI_BASE + 26)
+#define INT_UARTE			(INT_TRI_BASE + 27)
+#define INT_I2C3			(INT_TRI_BASE + 28)
+#define INT_SPI4			(INT_TRI_BASE + 29)
+#define INT_TRI_RES_30			(INT_TRI_BASE + 30)
+#define INT_SW_RESERVED			(INT_TRI_BASE + 31)
+
+/* Quaternary Interrupt Controller */
+#define INT_QUAD_BASE			(INT_TRI_BASE + 32)
+#define INT_SNOR			(INT_QUAD_BASE + 0)
+#define INT_USB3			(INT_QUAD_BASE + 1)
+#define INT_PCIE_INTR			(INT_QUAD_BASE + 2)
+#define INT_PCIE_MSI			(INT_QUAD_BASE + 3)
+#define INT_QUAD_RES_4			(INT_QUAD_BASE + 4)
+#define INT_QUAD_RES_5			(INT_QUAD_BASE + 5)
+#define INT_QUAD_RES_6			(INT_QUAD_BASE + 6)
+#define INT_QUAD_RES_7			(INT_QUAD_BASE + 7)
+#define INT_APB_DMA_CH0			(INT_QUAD_BASE + 8)
+#define INT_APB_DMA_CH1			(INT_QUAD_BASE + 9)
+#define INT_APB_DMA_CH2			(INT_QUAD_BASE + 10)
+#define INT_APB_DMA_CH3			(INT_QUAD_BASE + 11)
+#define INT_APB_DMA_CH4			(INT_QUAD_BASE + 12)
+#define INT_APB_DMA_CH5			(INT_QUAD_BASE + 13)
+#define INT_APB_DMA_CH6			(INT_QUAD_BASE + 14)
+#define INT_APB_DMA_CH7			(INT_QUAD_BASE + 15)
+#define INT_APB_DMA_CH8			(INT_QUAD_BASE + 16)
+#define INT_APB_DMA_CH9			(INT_QUAD_BASE + 17)
+#define INT_APB_DMA_CH10		(INT_QUAD_BASE + 18)
+#define INT_APB_DMA_CH11		(INT_QUAD_BASE + 19)
+#define INT_APB_DMA_CH12		(INT_QUAD_BASE + 20)
+#define INT_APB_DMA_CH13		(INT_QUAD_BASE + 21)
+#define INT_APB_DMA_CH14		(INT_QUAD_BASE + 22)
+#define INT_APB_DMA_CH15		(INT_QUAD_BASE + 23)
+#define INT_QUAD_RES_24			(INT_QUAD_BASE + 24)
+#define INT_QUAD_RES_25			(INT_QUAD_BASE + 25)
+#define INT_QUAD_RES_26			(INT_QUAD_BASE + 26)
+#define INT_QUAD_RES_27			(INT_QUAD_BASE + 27)
+#define INT_QUAD_RES_28			(INT_QUAD_BASE + 28)
+#define INT_QUAD_RES_29			(INT_QUAD_BASE + 29)
+#define INT_QUAD_RES_30			(INT_QUAD_BASE + 30)
+#define INT_QUAD_RES_31			(INT_QUAD_BASE + 31)
+
+#define INT_GPIO_BASE			(INT_QUAD_BASE + 32)
+#define INT_GPIO_NR			(28 * 8)
+
+#define NR_IRQS				(INT_GPIO_BASE + INT_GPIO_NR)
+
+#endif
diff --git a/arch/arm/mach-tegra/include/mach/memory.h b/arch/arm/mach-tegra/include/mach/memory.h
new file mode 100644
index 0000000..9507b08
--- /dev/null
+++ b/arch/arm/mach-tegra/include/mach/memory.h
@@ -0,0 +1,24 @@
+/*
+ * arch/arm/mach-tegra/include/mach/memory.h
+ *
+ * Copyright (C) 2010 Google, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef __MACH_TEGRA_MEMORY_H
+#define __MACH_TEGRA_MEMORY_H
+
+/* physical offset of RAM */
+#define PHYS_OFFSET		UL(0)
+
+#endif
+
diff --git a/arch/arm/mach-tegra/include/mach/system.h b/arch/arm/mach-tegra/include/mach/system.h
new file mode 100644
index 0000000..0aef65a
--- /dev/null
+++ b/arch/arm/mach-tegra/include/mach/system.h
@@ -0,0 +1,34 @@
+/*
+ * arch/arm/mach-tegra/include/mach/system.h
+ *
+ * Copyright (C) 2010 Google, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef __MACH_TEGRA_SYSTEM_H
+#define __MACH_TEGRA_SYSTEM_H
+
+#include <mach/hardware.h>
+
+static inline void arch_idle(void)
+{
+}
+
+static inline void arch_reset(char mode, const char *cmd)
+{
+	void __iomem *reset = IO_ADDRESS(TEGRA_CLK_RESET_BASE + 0x04);
+	u32 reg = readl(reset);
+	reg |= 0x04;
+	writel(reg, reset);
+}
+
+#endif
diff --git a/arch/arm/mach-tegra/include/mach/tegra.h b/arch/arm/mach-tegra/include/mach/tegra.h
new file mode 100644
index 0000000..9ef99ee
--- /dev/null
+++ b/arch/arm/mach-tegra/include/mach/tegra.h
@@ -0,0 +1,110 @@
+/*
+ * arch/arm/mach-tegra/include/mach/iomap.h
+ *
+ * Copyright (C) 2010 Google, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef __MACH_TEGRA_IOMAP_H
+#define __MACH_TEGRA_IOMAP_H
+
+#include <asm/sizes.h>
+
+#define TEGRA_ARM_PERIF_BASE    	0x50040000
+#define TEGRA_ARM_PERIF_SIZE    	SZ_8K
+
+#define TEGRA_ARM_INT_DIST_BASE      	0x50041000
+#define TEGRA_ARM_INT_DIST_SIZE      	SZ_4K
+
+#define TEGRA_DISPLAY_BASE		0x54200000
+#define TEGRA_DISPLAY_SIZE		SZ_256K
+
+#define TEGRA_DISPLAY2_BASE		0x54240000
+#define TEGRA_DISPLAY2_SIZE		SZ_256K
+
+#define TEGRA_PRIMARY_ICTLR_BASE     	0x60004000
+#define TEGRA_PRIMARY_ICTLR_SIZE     	SZ_64
+
+#define TEGRA_SECONDARY_ICTLR_BASE   	0x60004100
+#define TEGRA_SECONDARY_ICTLR_SIZE   	SZ_64
+
+#define TEGRA_TERTIARY_ICTLR_BASE   	0x60004200
+#define TEGRA_TERTIARY_ICTLR_SIZE   	SZ_64
+
+#define TEGRA_QUATERNARY_ICTLR_BASE	0x60004300
+#define TEGRA_QUATERNARY_ICTLR_SIZE	SZ_64
+
+#define TEGRA_TMR1_BASE			0x60005000
+#define TEGRA_TMR1_SIZE			SZ_8
+
+#define TEGRA_TMR2_BASE			0x60005008
+#define TEGRA_TMR2_SIZE			SZ_8
+
+#define TEGRA_TMRUS_BASE		0x60005010
+#define TEGRA_TMRUS_SIZE		SZ_64
+
+#define TEGRA_TMR3_BASE			0x60005050
+#define TEGRA_TMR3_SIZE			SZ_8
+
+#define TEGRA_TMR4_BASE			0x60005058
+#define TEGRA_TMR4_SIZE			SZ_8
+
+#define TEGRA_CLK_RESET_BASE		0x60006000
+#define TEGRA_CLK_RESET_SIZE		SZ_4K
+
+#define TEGRA_FLOW_CTRL_BASE		0x60007000
+#define TEGRA_FLOW_CTRL_SIZE		20
+
+#define TEGRA_GPIO_BASE			0x6000D000
+#define TEGRA_GPIO_SIZE			SZ_1K
+
+#define TEGRA_EXCEPTION_VECTORS_BASE    0x6000F000
+#define TEGRA_EXCEPTION_VECTORS_SIZE    SZ_4K
+
+#define TEGRA_APB_MISC_BASE		0x70000000
+#define TEGRA_APB_MISC_SIZE		SZ_4K
+
+#define TEGRA_UARTA_BASE		0x70006000
+#define TEGRA_UARTA_SIZE		SZ_64
+
+#define TEGRA_UARTB_BASE		0x70006040
+#define TEGRA_UARTB_SIZE		SZ_64
+
+#define TEGRA_UARTC_BASE		0x70006200
+#define TEGRA_UARTC_SIZE		SZ_256
+
+#define TEGRA_UARTD_BASE		0x70006300
+#define TEGRA_UARTD_SIZE		SZ_256
+
+#define TEGRA_UARTE_BASE		0x70006400
+#define TEGRA_UARTE_SIZE		SZ_256
+
+#define TEGRA_NAND_BASE			0x70008000
+#define TEGRA_NAND_SIZE			SZ_256
+
+#define TEGRA_RTC_BASE			0x7000E000
+#define TEGRA_RTC_SIZE			SZ_256
+
+#define TEGRA_PMC_BASE  		0x7000E400
+#define TEGRA_PMC_SIZE  		SZ_256
+
+#define TEGRA_USB_BASE			0xC5000000
+#define TEGRA_USB_SIZE			SZ_16K
+
+#define TEGRA_USB1_BASE			0xC5004000
+#define TEGRA_USB1_SIZE			SZ_16K
+
+#define TEGRA_USB2_BASE			0xC5008000
+#define TEGRA_USB2_SIZE			SZ_16K
+
+
+#endif
diff --git a/arch/arm/mach-tegra/include/mach/timex.h b/arch/arm/mach-tegra/include/mach/timex.h
new file mode 100644
index 0000000..8e1a3c4
--- /dev/null
+++ b/arch/arm/mach-tegra/include/mach/timex.h
@@ -0,0 +1,22 @@
+/*
+ * arch/arm/mach-tegra/include/mach/timex.h
+ *
+ * Copyright (C) 2010 Google, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef __MACH_TEGRA_TIMEX_H
+#define __MACH_TEGRA_TIMEX_H
+
+#define CLOCK_TICK_RATE		1000000
+
+#endif
diff --git a/arch/arm/mach-tegra/include/mach/uncompress.h b/arch/arm/mach-tegra/include/mach/uncompress.h
new file mode 100644
index 0000000..1400798
--- /dev/null
+++ b/arch/arm/mach-tegra/include/mach/uncompress.h
@@ -0,0 +1,46 @@
+/*
+ * arch/arm/mach-tegra/include/mach/uncompress.h
+ *
+ * Copyright (C) 2010 Google, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef __MACH_TEGRA_UNCOMPRESS_H
+#define __MACH_TEGRA_UNCOMPRESS_H
+
+#include <linux/serial_reg.h>
+
+#include "tegra.h"
+
+static void putc(int c)
+{
+	volatile u8 *uart = (volatile u8 *)(TEGRA_UARTD_BASE);
+	int shift = 2;
+
+	while (!(uart[UART_LSR << shift] & UART_LSR_THRE))
+		barrier();
+	uart[UART_TX << shift] = c;
+}
+
+static inline void flush(void)
+{
+}
+
+static inline void arch_decomp_setup(void)
+{
+}
+
+static inline void arch_decomp_wdog(void)
+{
+}
+
+#endif
diff --git a/arch/arm/mach-tegra/include/mach/vmalloc.h b/arch/arm/mach-tegra/include/mach/vmalloc.h
new file mode 100644
index 0000000..33444b1
--- /dev/null
+++ b/arch/arm/mach-tegra/include/mach/vmalloc.h
@@ -0,0 +1,22 @@
+/*
+ * arch/arm/mach-tegra/include/mach/vmalloc.h
+ *
+ * Copyright (C) 2010 Google, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef __MACH_TEGRA_VMALLOC_H
+#define __MACH_TEGRA_VMALLOC_H
+
+#define VMALLOC_END        ((PAGE_OFFSET) + 0x38000000)
+
+#endif
diff --git a/arch/arm/mach-tegra/io.c b/arch/arm/mach-tegra/io.c
new file mode 100644
index 0000000..f856269
--- /dev/null
+++ b/arch/arm/mach-tegra/io.c
@@ -0,0 +1,73 @@
+/*
+ * arch/arm/mach-tegra/io.c
+ *
+ * Copyright (C) 2010 Google, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/mm.h>
+
+#include <asm/io.h>
+#include <asm/page.h>
+#include <asm/mach/map.h>
+
+#include <mach/hardware.h>
+
+static struct map_desc tegra_io_desc[] __initdata = {
+	{
+		.virtual = IO_PPSB_VIRT,
+		.pfn = __phys_to_pfn(IO_PPSB_PHYS),
+		.length = IO_PPSB_SIZE,
+		.type = MT_DEVICE,
+	},
+	{
+		.virtual = IO_APB_VIRT,
+		.pfn = __phys_to_pfn(IO_APB_PHYS),
+		.length = IO_APB_SIZE,
+		.type = MT_DEVICE,
+	},
+	{
+		.virtual = IO_CPU_VIRT,
+		.pfn = __phys_to_pfn(IO_CPU_PHYS),
+		.length = IO_CPU_SIZE,
+		.type = MT_DEVICE,
+	},
+};
+
+void __init tegra_map_common_io(void)
+{
+	iotable_init(tegra_io_desc, ARRAY_SIZE(tegra_io_desc));
+}
+
+/*
+ * Intercept ioremap() requests for addresses in our fixed mapping regions.
+ */
+void __iomem *tegra_ioremap(unsigned long p, size_t size, unsigned int type)
+{
+	void __iomem *v = IO_ADDRESS(p);
+	if (v == NULL)
+		v = __arm_ioremap(p, size, type);
+	return v;
+}
+EXPORT_SYMBOL(tegra_ioremap);
+
+void tegra_iounmap(volatile void __iomem *addr)
+{
+	unsigned long virt = (unsigned long)addr;
+
+	if (virt >= VMALLOC_START && virt < VMALLOC_END)
+		__iounmap(addr);
+}
+EXPORT_SYMBOL(tegra_iounmap);
diff --git a/arch/arm/mach-tegra/irq.c b/arch/arm/mach-tegra/irq.c
new file mode 100644
index 0000000..9690a1b
--- /dev/null
+++ b/arch/arm/mach-tegra/irq.c
@@ -0,0 +1,31 @@
+/*
+ * arch/arm/mach-tegra/irq.c
+ *
+ * Copyright (C) 2010 Google, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/irq.h>
+
+#include <asm/hardware/gic.h>
+
+#include <mach/hardware.h>
+
+#include "common.h"
+
+void __init tegra_init_irq(void)
+{
+	gic_dist_init(0, IO_ADDRESS(TEGRA_ARM_INT_DIST_BASE), 29);
+	gic_cpu_init(0, IO_ADDRESS(TEGRA_ARM_PERIF_BASE + 0x100));
+	tegra_init_clock();
+}
diff --git a/arch/arm/mach-tegra/tegra2_clocks.c b/arch/arm/mach-tegra/tegra2_clocks.c
new file mode 100644
index 0000000..e480625
--- /dev/null
+++ b/arch/arm/mach-tegra/tegra2_clocks.c
@@ -0,0 +1,809 @@
+/*
+ * arch/arm/mach-tegra/tegra2_clocks.c
+ *
+ * Copyright (C) 2010 Google, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/clk.h>
+#include <linux/list.h>
+#include <linux/spinlock.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+
+#include <asm/clkdev.h>
+
+#include <mach/hardware.h>
+
+#include "clock.h"
+
+#define CLK_RST_CONTROLLER_RST_DEVICES         0x004
+#define CLK_RST_CONTROLLER_RST_DEVICES_SET_CLR 0x300
+#define CLK_RST_CONTROLLER_CLK_OUT_ENB         0x010
+#define CLK_RST_CONTROLLER_CLK_OUT_ENB_SET_CLR 0x320
+#define CLK_RST_CONTROLLER_CLK_SOURCE          0x100
+
+static void __iomem *reg_clk_base;
+
+#define clk_writel(value, reg) \
+	__raw_writel(value, (u32)reg_clk_base + (reg))
+#define clk_readl(reg) \
+	__raw_readl((u32)reg_clk_base + (reg))
+
+static int clk_div71_possible_rate(struct clk *c, unsigned long rate)
+{
+	unsigned long input_rate = clk_get_rate(c);
+	int divider_u71;
+
+	divider_u71 = (input_rate*2)/rate;
+	if (rate * divider_u71 == input_rate*2)
+		return divider_u71 - 2;
+	else
+		return -1;
+}
+
+/* Default clk ops */
+static int tegra2_clk_enable(struct clk *c)
+{
+	return 0;
+}
+
+static void tegra2_clk_disable(struct clk *c)
+{
+}
+
+static unsigned long tegra2_clk_get_rate(struct clk *c)
+{
+	return c->rate;
+}
+
+/* clk_m functions */
+static unsigned long tegra2_clk_m_autodetect_rate(struct clk *c)
+{
+	u32 clk_autodetect;
+	u32 auto_clk_ctl = clk_readl(0x50) & ~(3<<30);
+
+	clk_writel(0x80000001, 0x58);
+
+	while ((clk_autodetect = clk_readl(0x5c)) & 0x80000000)
+		;
+
+	switch (clk_autodetect) {
+	case 732:
+	case 733:
+		c->rate = 12000000;
+		auto_clk_ctl |= 2<<30;
+		break;
+	case 794:
+		c->rate = 13000000;
+		auto_clk_ctl |= 0<<30;
+		break;
+	case 1172:
+		c->rate = 19200000;
+		auto_clk_ctl |= 1<<30;
+		break;
+	case 1587:
+		c->rate = 26000000;
+		auto_clk_ctl |= 3<<30;
+		break;
+	default:
+		WARN(1, "Unexpected clock autodetect value %d", clk_autodetect);
+	}
+
+	clk_writel(auto_clk_ctl, 0x50);
+
+	return c->rate;
+}
+
+static void tegra2_clk_m_init(struct clk *c)
+{
+	tegra2_clk_m_autodetect_rate(c);
+}
+
+static int tegra2_clk_m_enable(struct clk *c)
+{
+	return 0;
+}
+
+static void tegra2_clk_m_disable(struct clk *c)
+{
+	BUG();
+}
+
+static struct clk_ops tegra_clk_m_ops = {
+	.init     = tegra2_clk_m_init,
+	.enable   = tegra2_clk_m_enable,
+	.disable  = tegra2_clk_m_disable,
+	.get_rate = tegra2_clk_get_rate,
+};
+
+/* PLL Functions */
+static int tegra2_pll_clk_set_rate(struct clk *c, unsigned long rate)
+{
+	u32 reg;
+	unsigned long input_rate;
+	const struct clk_pll_table *sel;
+
+	input_rate = clk_get_rate(c->parent);
+	for (sel = c->pll_table; sel->input_rate != 0; sel++) {
+		if (sel->input_rate == input_rate && sel->output_rate == rate) {
+			c->n = sel->n;
+			c->m = sel->m;
+			c->p = sel->p;
+			c->cpcon = sel->cpcon;
+			reg = clk_readl(c->reg);
+			if (c->flags & PLL_FIXED)
+				reg |= 1<<28;
+			reg &= ~0x7FFF;
+			reg |= (c->m << 0) | (c->n << 8);
+			BUG_ON(c->p > 2);
+			if (c->p == 2)
+				reg |= 1<<20;
+			clk_writel(reg, c->reg);
+			c->rate = rate;
+
+			if (c->flags & PLL_HAS_CPCON) {
+				reg = c->cpcon << 8;
+				clk_writel(reg, c->reg+0xC);
+			}
+			return 0;
+		}
+	}
+	return 1;
+}
+
+static int tegra2_pll_clk_enable(struct clk *c)
+{
+	int ret = 0;
+	u32 reg;
+
+	reg = clk_readl(c->reg);
+	reg &= ~(1 << 31);
+	reg |= 1 << 30;
+	clk_writel(reg, c->reg);
+	return ret;
+}
+
+static void tegra2_pll_clk_disable(struct clk *c)
+{
+	u32 reg;
+
+	reg = clk_readl(c->reg);
+	reg &= ~(1 << 31);
+	reg &= ~(1 << 30);
+	clk_writel(reg, c->reg);
+}
+
+static struct clk_ops tegra_pll_ops = {
+	.enable   = tegra2_pll_clk_enable,
+	.disable  = tegra2_pll_clk_disable,
+	.set_rate = tegra2_pll_clk_set_rate,
+	.get_rate = tegra2_clk_get_rate,
+};
+
+/* Clock divider ops */
+static int tegra2_div_clk_set_rate(struct clk *c, unsigned long rate)
+{
+	int ret = 0;
+	u32 reg;
+	u32 new_reg;
+	int divider_u71;
+
+	if (c->flags & DIV_U71) {
+		divider_u71 = clk_div71_possible_rate(c->parent, rate);
+		if (divider_u71 >= 0) {
+			reg = clk_readl(c->reg);
+			new_reg = reg >> c->reg_shift;
+			new_reg &= 0xFFFF;
+
+			if (c->flags & DIV_U71_FIXED)
+				new_reg &= ~(1<<2);
+			new_reg &= ~(0xFF);
+			new_reg |= divider_u71;
+
+			reg &= ~(0xFFFF << c->reg_shift);
+			reg |= new_reg << c->reg_shift;
+			clk_writel(reg, c->reg);
+			return 1;
+		}
+	} else if (c->flags & DIV_2) {
+		if (clk_get_rate(c->parent) == rate * 2)
+			return 1;
+	}
+	BUG();
+	return ret;
+}
+
+
+static struct clk_ops tegra_div_ops = {
+	.enable   = tegra2_clk_enable,
+	.disable  = tegra2_clk_disable,
+	.set_rate = tegra2_div_clk_set_rate,
+	.get_rate = tegra2_clk_get_rate,
+};
+
+/* Periph clk ops */
+static void tegra2_periph_clk_init(struct clk *c)
+{
+	clk_set_parent(c, c->inputs[0].input);
+}
+
+static int tegra2_periph_clk_enable(struct clk *c)
+{
+	u32 reg, bit;
+
+	reg = (1 << (c->clk_num % 32));
+	bit = (c->clk_num / 32) << 3;
+
+	clk_writel(reg, CLK_RST_CONTROLLER_CLK_OUT_ENB_SET_CLR | bit);
+	clk_writel(reg, CLK_RST_CONTROLLER_RST_DEVICES_SET_CLR | bit | 4);
+	return 0;
+}
+
+static void tegra2_periph_clk_disable(struct clk *c)
+{
+	u32 reg, bit;
+
+	reg = (1 << (c->clk_num % 32));
+	bit = (c->clk_num / 32) << 3;
+
+	clk_writel(reg, CLK_RST_CONTROLLER_CLK_OUT_ENB_SET_CLR | bit | 4);
+	clk_writel(reg, CLK_RST_CONTROLLER_RST_DEVICES_SET_CLR | bit);
+}
+
+static int tegra2_periph_clk_set_parent(struct clk *c, struct clk *p)
+{
+	int ret = 0;
+	u32 reg;
+	const struct clk_mux_sel *sel;
+	for (sel = c->inputs; sel->input != NULL; sel++) {
+		if (sel->input == p) {
+			c->parent = p;
+			reg = clk_readl(c->reg);
+			reg &= ~(0x3<<30);
+			reg |= (sel->value)<<30;
+			clk_writel(reg, c->reg);
+		}
+	}
+
+	return ret;
+}
+
+static int tegra2_periph_clk_set_rate(struct clk *c, unsigned long rate)
+{
+	int ret = 0;
+	u32 reg;
+	int divider_u71;
+	const struct clk_mux_sel *sel;
+
+	for (sel = c->inputs; sel->input != NULL; sel++) {
+		if (c->flags & DIV_U71) {
+			divider_u71 = clk_div71_possible_rate(sel->input, rate);
+			if (divider_u71 >= 0) {
+				/* FIXME: ensure we don't have too high rate */
+				clk_set_parent(c, sel->input);
+				udelay(1);
+				reg = clk_readl(c->reg);
+				reg &= ~(0xFF);
+				reg |= divider_u71;
+				clk_writel(reg, c->reg);
+				return 1;
+			}
+		} else {
+			if (clk_get_rate(sel->input) == rate) {
+				clk_set_parent(c, sel->input);
+				return 1;
+			}
+		}
+	}
+	BUG();
+	return ret;
+}
+
+static struct clk_ops tegra_periph_clk_ops = {
+	.init       = &tegra2_periph_clk_init,
+	.enable     = &tegra2_periph_clk_enable,
+	.disable    = &tegra2_periph_clk_disable,
+	.set_parent = &tegra2_periph_clk_set_parent,
+	.set_rate   = &tegra2_periph_clk_set_rate,
+};
+
+static struct clk tegra_clk_32k = {
+	.name = "tegra_clk_32k",
+	.rate = 32678,
+	.ops  = NULL,
+};
+
+static struct clk tegra_clk_input = {
+	.name = "tegra_clk_input",
+	.flags = ENABLE_ON_INIT,
+	.rate = 12000000,
+	.ops = NULL,
+};
+
+static struct clk_pll_table tegra_pll_s_table[] = {
+	{32768, 12000000, 366, 1, 1, 0},
+	{32768, 13000000, 397, 1, 1, 0},
+	{32768, 19200000, 586, 1, 1, 0},
+	{32768, 26000000, 793, 1, 1, 0},
+	{0, 0, 0, 0, 0, 0},
+};
+
+static struct clk tegra_pll_s = {
+	.name = "tegra_pll_s",
+	.ops = &tegra_pll_ops,
+	.reg       = 0xf0,
+	.input_min = 32768,
+	.input_max = 32768,
+	.parent     = &tegra_clk_32k,
+	.cf_min    = 0, /* FIXME */
+	.cf_max    = 0, /* FIXME */
+	.vco_min   = 12000000,
+	.vco_max   = 26000000,
+	.pll_table = tegra_pll_s_table,
+};
+
+static struct clk_mux_sel tegra_clk_m_sel[] = {
+	{ .input = &tegra_clk_32k, .value = 0},
+	{ .input = &tegra_pll_s,  .value = 1},
+	{ 0, 0},
+};
+
+static struct clk tegra_clk_m = {
+	.name      = "tegra_clk_m",
+	.flags     = ENABLE_ON_INIT,
+	.ops       = &tegra_clk_m_ops,
+	.inputs    = tegra_clk_m_sel,
+	.reg       = 0x1fc,
+	.reg_mask  = (1<<28),
+	.reg_shift = 28,
+};
+
+static struct clk_pll_table tegra_pll_c_table[] = {
+	{ 0, 0, 0, 0, 0, 0 },
+};
+
+static struct clk tegra_pll_c = {
+	.name      = "tegra_pll_c",
+	.flags	   = PLL_HAS_CPCON,
+	.ops       = &tegra_pll_ops,
+	.reg       = 0x80,
+	.input_min = 2000000,
+	.input_max = 31000000,
+	.parent    = &tegra_clk_m,
+	.cf_min    = 1000000,
+	.cf_max    = 6000000,
+	.vco_min   = 20000000,
+	.vco_max   = 1400000000,
+	.pll_table = tegra_pll_c_table,
+};
+
+static struct clk tegra_pll_c_out1 = {
+	.name      = "tegra_pll_c_out1",
+	.ops       = &tegra_div_ops,
+	.flags     = DIV_U71,
+	.parent    = &tegra_pll_c,
+	.reg       = 0x84,
+	.reg_shift = 0,
+};
+
+static struct clk_pll_table tegra_pll_m_table[] = {
+	{ 0, 0, 0, 0, 0, 0 },
+};
+
+static struct clk tegra_pll_m = {
+	.name      = "tegra_pll_m",
+	.flags     = PLL_HAS_CPCON,
+	.ops       = &tegra_pll_ops,
+	.reg       = 0x90,
+	.input_min = 2000000,
+	.input_max = 31000000,
+	.parent    = &tegra_clk_m,
+	.cf_min    = 1000000,
+	.cf_max    = 6000000,
+	.vco_min   = 20000000,
+	.vco_max   = 1200000000,
+	.pll_table = tegra_pll_m_table,
+};
+
+static struct clk tegra_pll_m_out1 = {
+	.name      = "tegra_pll_m_out1",
+	.ops       = &tegra_div_ops,
+	.flags     = DIV_U71,
+	.parent    = &tegra_pll_m,
+	.reg       = 0x94,
+	.reg_shift = 0,
+};
+
+static struct clk_pll_table tegra_pll_p_table[] = {
+	{ 12000000, 216000000, 432, 12, 2, 8},
+	{ 13000000, 216000000, 432, 13, 2, 8},
+	{ 19200000, 216000000, 90,   4, 2, 1},
+	{ 26000000, 216000000, 432, 26, 2, 8},
+	{ 12000000, 432000000, 432, 12, 1, 8},
+	{ 13000000, 432000000, 432, 13, 1, 8},
+	{ 19200000, 432000000, 90,   4, 1, 1},
+	{ 26000000, 432000000, 432, 26, 1, 8},
+	{ 0, 0, 0, 0, 0, 0 },
+};
+
+static struct clk tegra_pll_p = {
+	.name      = "tegra_pll_p",
+	.flags     = ENABLE_ON_INIT | PLL_FIXED | PLL_HAS_CPCON,
+	.ops       = &tegra_pll_ops,
+	.reg       = 0xa0,
+	.input_min = 2000000,
+	.input_max = 31000000,
+	.parent    = &tegra_clk_m,
+	.cf_min    = 1000000,
+	.cf_max    = 6000000,
+	.vco_min   = 20000000,
+	.vco_max   = 1400000000,
+	.pll_table = tegra_pll_p_table,
+};
+
+static struct clk tegra_pll_p_out1 = {
+	.name      = "tegra_pll_p_out1",
+	.ops       = &tegra_div_ops,
+	.flags     = ENABLE_ON_INIT | DIV_U71 | DIV_U71_FIXED,
+	.parent    = &tegra_pll_p,
+	.reg       = 0xa4,
+	.reg_shift = 0,
+};
+
+static struct clk tegra_pll_p_out2 = {
+	.name      = "tegra_pll_p_out2",
+	.ops       = &tegra_div_ops,
+	.flags     = ENABLE_ON_INIT | DIV_U71 | DIV_U71_FIXED,
+	.parent    = &tegra_pll_p,
+	.reg       = 0xa4,
+	.reg_shift = 16,
+};
+
+static struct clk tegra_pll_p_out3 = {
+	.name      = "tegra_pll_p_out3",
+	.ops       = &tegra_div_ops,
+	.flags     = ENABLE_ON_INIT | DIV_U71 | DIV_U71_FIXED,
+	.parent    = &tegra_pll_p,
+	.reg       = 0xa8,
+	.reg_shift = 0,
+};
+
+static struct clk tegra_pll_p_out4 = {
+	.name      = "tegra_pll_p_out4",
+	.ops       = &tegra_div_ops,
+	.flags     = ENABLE_ON_INIT | DIV_U71 | DIV_U71_FIXED,
+	.parent    = &tegra_pll_p,
+	.reg       = 0xa8,
+	.reg_shift = 16,
+};
+
+static struct clk_pll_table tegra_pll_a_table[] = {
+	{ 28800000, 56448000, 49, 25, 1, 1},
+	{ 28800000, 73728000, 64, 25, 1, 1},
+	{ 28800000, 11289600, 49, 25, 1, 1},
+	{ 28800000, 12288000, 64, 25, 1, 1},
+	{ 0, 0, 0, 0, 0, 0 },
+};
+
+static struct clk tegra_pll_a = {
+	.name      = "tegra_pll_a",
+	.flags     = PLL_HAS_CPCON,
+	.ops       = &tegra_pll_ops,
+	.reg       = 0xb0,
+	.input_min = 2000000,
+	.input_max = 31000000,
+	.parent    = &tegra_pll_p_out1,
+	.cf_min    = 1000000,
+	.cf_max    = 6000000,
+	.vco_min   = 20000000,
+	.vco_max   = 1400000000,
+	.pll_table = tegra_pll_a_table,
+};
+
+static struct clk tegra_pll_a_out0 = {
+	.name      = "tegra_pll_a_out0",
+	.ops       = &tegra_div_ops,
+	.flags     = DIV_U71,
+	.parent    = &tegra_pll_a,
+	.reg       = 0xb4,
+	.reg_shift = 0,
+};
+
+static struct clk_pll_table tegra_pll_d_table[] = {
+	{ 12000000, 1000000000, 1000, 12, 1, 12},
+	{ 13000000, 1000000000, 1000, 13, 1, 12},
+	{ 19200000, 1000000000, 625,  12, 1, 8},
+	{ 26000000, 1000000000, 1000, 26, 1, 12},
+	{ 0, 0, 0, 0, 0, 0 },
+};
+
+static struct clk tegra_pll_d = {
+	.name      = "tegra_pll_d",
+	.flags     = PLL_HAS_CPCON,
+	.ops       = &tegra_pll_ops,
+	.reg       = 0xd0,
+	.input_min = 2000000,
+	.input_max = 40000000,
+	.parent    = &tegra_clk_m,
+	.cf_min    = 1000000,
+	.cf_max    = 6000000,
+	.vco_min   = 40000000,
+	.vco_max   = 1000000000,
+	.pll_table = tegra_pll_d_table,
+};
+
+static struct clk tegra_pll_d_out0 = {
+	.name      = "tegra_pll_d_out0",
+	.ops       = &tegra_div_ops,
+	.flags     = DIV_2,
+	.parent    = &tegra_pll_d,
+};
+
+static struct clk_pll_table tegra_pll_u_table[] = {
+	{ 12000000, 480000000, 960, 12, 1, 0},
+	{ 13000000, 480000000, 960, 13, 1, 0},
+	{ 19200000, 480000000, 200, 4,  1, 0},
+	{ 26000000, 480000000, 960, 26, 1, 0},
+	{ 0, 0, 0, 0, 0, 0 },
+};
+
+static struct clk tegra_pll_u = {
+	.name      = "tegra_pll_u",
+	.flags     = 0,
+	.ops       = &tegra_pll_ops,
+	.reg       = 0xc0,
+	.input_min = 2000000,
+	.input_max = 40000000,
+	.parent    = &tegra_clk_m,
+	.cf_min    = 1000000,
+	.cf_max    = 6000000,
+	.vco_min   = 480000000,
+	.vco_max   = 960000000,
+	.pll_table = tegra_pll_u_table,
+};
+
+static struct clk_mux_sel mux_pllm_pllc_pllp_plla[] = {
+	{ .input = &tegra_pll_m, .value = 0},
+	{ .input = &tegra_pll_c, .value = 1},
+	{ .input = &tegra_pll_p, .value = 2},
+	{ .input = &tegra_pll_a_out0, .value = 3},
+	{ 0, 0},
+};
+
+static struct clk_mux_sel mux_pllp_pllc_pllm_clkm[] = {
+	{ .input = &tegra_pll_p, .value = 0},
+	{ .input = &tegra_pll_c, .value = 1},
+	{ .input = &tegra_pll_m, .value = 2},
+	{ .input = &tegra_clk_m, .value = 3},
+	{ 0, 0},
+};
+
+static struct clk_mux_sel mux_plla_audio_pllp_clkm[] = {
+	{.input = &tegra_pll_a, .value = 0},
+	/* FIXME: no mux defined for tegra_audio
+	{.input = &tegra_audio, .value = 1},*/
+	{.input = &tegra_pll_p, .value = 2},
+	{.input = &tegra_clk_m, .value = 3},
+	{ 0, 0},
+};
+
+static struct clk_mux_sel mux_pllp_plld_pllc_clkm[] = {
+	{.input = &tegra_pll_p, .value = 0},
+	{.input = &tegra_pll_d_out0, .value = 1},
+	{.input = &tegra_pll_c, .value = 2},
+	{.input = &tegra_clk_m, .value = 3},
+	{ 0, 0},
+};
+
+static struct clk_mux_sel mux_pllp_pllc_audio_clkm_clk32[] = {
+	{.input = &tegra_pll_p,     .value = 0},
+	{.input = &tegra_pll_c,     .value = 1},
+	/* FIXME: no mux defined for tegra_audio
+	{.input = &tegra_audio,     .value = 2},*/
+	{.input = &tegra_clk_m,     .value = 3},
+	{.input = &tegra_clk_32k,   .value = 4},
+	{ 0, 0},
+};
+
+static struct clk_mux_sel mux_pllp_pllc_pllm[] = {
+	{.input = &tegra_pll_p,     .value = 0},
+	{.input = &tegra_pll_c,     .value = 1},
+	{.input = &tegra_pll_m,     .value = 2},
+	{ 0, 0},
+};
+
+static struct clk_mux_sel mux_clk_m[] = {
+	{ .input = &tegra_clk_m, .value = 0},
+	{ 0, 0},
+};
+
+static struct clk_mux_sel mux_clk_32k[] = {
+	{ .input = &tegra_clk_32k, .value = 0},
+	{ 0, 0},
+};
+
+#define PERIPH_CLK(_name, _clk_num, _reg, _inputs, _flags) \
+	struct clk clk_##_name = {		   \
+		.name      = __stringify(_name),	   \
+		.ops       = &tegra_periph_clk_ops,	   \
+		.clk_num   = _clk_num,			   \
+		.reg       = _reg,			   \
+		.inputs    = _inputs,			   \
+		.flags     = _flags,			   \
+	}
+
+#define PERIPH_CLK_U71(_name, _clk_num, _reg, _inputs) \
+	PERIPH_CLK(_name, _clk_num, _reg, _inputs, MUX | DIV_U71)
+
+static PERIPH_CLK(rtc, 4, 0, mux_clk_32k, 0);
+static PERIPH_CLK(usbd, 22, 0, mux_clk_m, 0);
+static PERIPH_CLK(usb2, 58, 0, mux_clk_m, 0);
+static PERIPH_CLK(usb3, 59, 0, mux_clk_m, 0);
+static PERIPH_CLK(timer, 5, 0, mux_clk_m, 0);
+
+static PERIPH_CLK_U71(i2s1, 11, 0x100, mux_plla_audio_pllp_clkm);
+static PERIPH_CLK_U71(i2s2, 18, 0x104, mux_plla_audio_pllp_clkm);
+static PERIPH_CLK_U71(spdif_in, 10, 0x10c, mux_pllp_pllc_pllm);
+static PERIPH_CLK_U71(spdif_out, 10, 0x108, mux_plla_audio_pllp_clkm);
+static PERIPH_CLK_U71(pwm, 17, 0x110, mux_pllp_pllc_audio_clkm_clk32);
+static PERIPH_CLK_U71(spi, 43, 0x114, mux_pllp_pllc_pllm_clkm);
+static PERIPH_CLK_U71(xio, 45, 0x120, mux_pllp_pllc_pllm_clkm);
+static PERIPH_CLK_U71(twc, 16, 0x12c, mux_pllp_pllc_pllm_clkm);
+static PERIPH_CLK_U71(sbc1, 41, 0x134, mux_pllp_pllc_pllm_clkm);
+static PERIPH_CLK_U71(sbc2, 44, 0x118, mux_pllp_pllc_pllm_clkm);
+static PERIPH_CLK_U71(sbc3, 46, 0x11c, mux_pllp_pllc_pllm_clkm);
+static PERIPH_CLK_U71(sbc4, 68, 0x1b4, mux_pllp_pllc_pllm_clkm);
+static PERIPH_CLK_U71(ide, 25, 0x144, mux_pllp_pllc_pllm_clkm);
+static PERIPH_CLK_U71(ndflash, 13, 0x160, mux_pllp_pllc_pllm_clkm);
+static PERIPH_CLK_U71(vfir, 7, 0x168, mux_pllp_pllc_pllm_clkm);
+static PERIPH_CLK_U71(sdmmc1, 14, 0x150, mux_pllp_pllc_pllm_clkm);
+static PERIPH_CLK_U71(sdmmc2, 9, 0x154, mux_pllp_pllc_pllm_clkm);
+static PERIPH_CLK_U71(sdmmc3, 69, 0x1bc, mux_pllp_pllc_pllm_clkm);
+static PERIPH_CLK_U71(sdmmc4, 15, 0x160, mux_pllp_pllc_pllm_clkm);
+static PERIPH_CLK_U71(vde, 61, 0x1c8, mux_pllp_pllc_pllm_clkm);
+static PERIPH_CLK_U71(csite, 73, 0x1d4, mux_pllp_pllc_pllm_clkm);
+static PERIPH_CLK_U71(la, 76, 0x1f8, mux_pllp_pllc_pllm_clkm);
+static PERIPH_CLK_U71(owr, 71, 0x1cc, mux_pllp_pllc_pllm_clkm);
+static PERIPH_CLK_U71(nor, 42, 0x1d0, mux_pllp_pllc_pllm_clkm);
+static PERIPH_CLK_U71(mipi, 50, 0x174, mux_pllp_pllc_pllm_clkm);
+static PERIPH_CLK_U71(i2c1, 12, 0x124, mux_pllp_pllc_pllm_clkm);
+static PERIPH_CLK_U71(i2c2, 54, 0x198, mux_pllp_pllc_pllm_clkm);
+static PERIPH_CLK_U71(i2c3, 67, 0x1b8, mux_pllp_pllc_pllm_clkm);
+static PERIPH_CLK_U71(dvc, 47, 0x128, mux_pllp_pllc_pllm_clkm);
+static PERIPH_CLK_U71(uarta, 6, 0x178, mux_pllp_pllc_pllm_clkm);
+static PERIPH_CLK_U71(uartb, 7, 0x17c, mux_pllp_pllc_pllm_clkm);
+static PERIPH_CLK_U71(uartc, 55, 0x1a0, mux_pllp_pllc_pllm_clkm);
+static PERIPH_CLK_U71(uartd, 65, 0x1c0, mux_pllp_pllc_pllm_clkm);
+static PERIPH_CLK_U71(uarte, 66, 0x1c4, mux_pllp_pllc_pllm_clkm);
+static PERIPH_CLK_U71(3d, 24, 0x158, mux_pllm_pllc_pllp_plla);
+static PERIPH_CLK_U71(2d, 21, 0x15c, mux_pllm_pllc_pllp_plla);
+static PERIPH_CLK_U71(vi, 20, 0x148, mux_pllm_pllc_pllp_plla);
+static PERIPH_CLK_U71(vi_sensor, 20, 0x1a8, mux_pllm_pllc_pllp_plla);
+static PERIPH_CLK_U71(epp, 19, 0x16c, mux_pllm_pllc_pllp_plla);
+static PERIPH_CLK_U71(mpe, 60, 0x170, mux_pllm_pllc_pllp_plla);
+static PERIPH_CLK_U71(host1x, 28, 0x180, mux_pllm_pllc_pllp_plla);
+static PERIPH_CLK_U71(cve, 49, 0x140, mux_pllp_plld_pllc_clkm);
+static PERIPH_CLK_U71(tvo, 49, 0x188, mux_pllp_plld_pllc_clkm);
+static PERIPH_CLK_U71(hdmi, 51, 0x18c, mux_pllp_plld_pllc_clkm);
+static PERIPH_CLK_U71(tvdac, 53, 0x194, mux_pllp_plld_pllc_clkm);
+static PERIPH_CLK_U71(disp1, 27, 0x138, mux_pllp_plld_pllc_clkm);
+static PERIPH_CLK_U71(disp2, 26, 0x13c, mux_pllp_plld_pllc_clkm);
+
+#define CLK(dev, con, ck)     \
+	{       \
+		.dev_id = dev,  \
+		.con_id = con,  \
+		.clk = ck,  \
+	}
+
+struct clk_lookup tegra_clk_lookups[] = {
+	/* external root sources */
+	CLK(NULL, "input_clk",	&tegra_clk_input),
+	CLK(NULL, "32k_clk",	&tegra_clk_32k),
+	CLK(NULL, "clk_m",	&tegra_clk_m),
+
+	/* PLLs */
+	CLK(NULL, "pll_a",	&tegra_pll_a),
+	CLK(NULL, "pll_c",	&tegra_pll_c),
+	CLK(NULL, "pll_d",      &tegra_pll_d),
+	CLK(NULL, "pll_m",	&tegra_pll_m),
+	CLK(NULL, "pll_p",	&tegra_pll_p),
+	CLK(NULL, "pll_s",	&tegra_pll_s),
+	CLK(NULL, "pll_u",      &tegra_pll_u),
+
+	/* PLL outputs */
+	CLK(NULL, "pll_a_out0", &tegra_pll_a_out0),
+	CLK(NULL, "pll_c_out1", &tegra_pll_c_out1),
+	CLK(NULL, "pll_d_out0", &tegra_pll_d_out0),
+	CLK(NULL, "pll_m_out1", &tegra_pll_m_out1),
+	CLK(NULL, "pll_p_out1", &tegra_pll_p_out1),
+	CLK(NULL, "pll_p_out2", &tegra_pll_p_out2),
+	CLK(NULL, "pll_p_out3", &tegra_pll_p_out3),
+	CLK(NULL, "pll_p_out4", &tegra_pll_p_out4),
+
+	/* peripheral clocks */
+	CLK("rtc-tegra",	NULL,	&clk_rtc),
+	CLK("timer",		NULL,	&clk_timer),
+	CLK("i2s.0",		NULL,	&clk_i2s1),
+	CLK("i2s.1",		NULL,	&clk_i2s2),
+	CLK("spdif_out",	NULL,	&clk_spdif_out),
+	CLK("spdif_in",		NULL,	&clk_spdif_in),
+	CLK("pwm",		NULL,	&clk_pwm),
+	CLK("spi",		NULL,	&clk_spi),
+	CLK("xio",		NULL,	&clk_xio),
+	CLK("twc",		NULL,	&clk_twc),
+	CLK("sbc.0",		NULL,	&clk_sbc1),
+	CLK("sbc.1",		NULL,	&clk_sbc2),
+	CLK("sbc.2",		NULL,	&clk_sbc3),
+	CLK("sbc.3",		NULL,	&clk_sbc4),
+	CLK("ide",		NULL,	&clk_ide),
+	CLK("tegra_nand",	NULL,	&clk_ndflash),
+	CLK("vfir",		NULL,	&clk_vfir),
+	CLK("sdmmc.0",		NULL,	&clk_sdmmc1),
+	CLK("sdmmc.1",		NULL,	&clk_sdmmc2),
+	CLK("sdmmc.2",		NULL,	&clk_sdmmc3),
+	CLK("sdmmc.3",		NULL,	&clk_sdmmc4),
+	CLK("vde",		NULL,	&clk_vde),
+	CLK("csite",		NULL,	&clk_csite),
+	CLK("la",		NULL,	&clk_la),
+	CLK("owr",		NULL,	&clk_owr),
+	CLK("nor",		NULL,	&clk_nor),
+	CLK("mipi",		NULL,	&clk_mipi),
+	CLK("i2c.0",		NULL,	&clk_i2c1),
+	CLK("i2c.1",		NULL,	&clk_i2c2),
+	CLK("i2c.2",		NULL,	&clk_i2c3),
+	CLK("dvc",		NULL,	&clk_dvc),
+	CLK("uart.0",		NULL,	&clk_uarta),
+	CLK("uart.1",		NULL,	&clk_uartb),
+	CLK("uart.2",		NULL,	&clk_uartc),
+	CLK("uart.3",		NULL,	&clk_uartd),
+	CLK("uart.4",		NULL,	&clk_uarte),
+	CLK("3d",		NULL,	&clk_3d),
+	CLK("2d",		NULL,	&clk_2d),
+	CLK("vi",		NULL,	&clk_vi),
+	CLK("vi_sensor",	NULL,	&clk_vi_sensor),
+	CLK("epp",		NULL,	&clk_epp),
+	CLK("mpe",		NULL,	&clk_mpe),
+	CLK("host1x",		NULL,	&clk_host1x),
+	CLK("cve",		NULL,	&clk_cve),
+	CLK("tvo",		NULL,	&clk_tvo),
+	CLK("hdmi",		NULL,	&clk_hdmi),
+	CLK("tvdac",		NULL,	&clk_tvdac),
+	CLK("tegrafb.0",	NULL,	&clk_disp1),
+	CLK("tegrafb.1",	NULL,	&clk_disp2),
+	CLK("usb.0",		NULL,	&clk_usbd),
+	CLK("usb.1",		NULL,	&clk_usb2),
+	CLK("usb.2",		NULL,	&clk_usb3),
+};
+
+int __init tegra_init_clock(void)
+{
+	int i;
+	struct clk_lookup *cl;
+
+	reg_clk_base = IO_ADDRESS(TEGRA_CLK_RESET_BASE);
+
+	for (i = 0; i < ARRAY_SIZE(tegra_clk_lookups); i++) {
+		cl = &tegra_clk_lookups[i];
+		if (cl->clk->ops && cl->clk->ops->init)
+			cl->clk->ops->init(cl->clk);
+		clkdev_add(cl);
+
+		if (cl->clk->flags & ENABLE_ON_INIT)
+			clk_enable(cl->clk);
+	}
+
+	return 0;
+}
diff --git a/arch/arm/mach-tegra/timer.c b/arch/arm/mach-tegra/timer.c
new file mode 100644
index 0000000..a82f808
--- /dev/null
+++ b/arch/arm/mach-tegra/timer.c
@@ -0,0 +1,182 @@
+/*
+ *
+ * Copyright (C) 2010 Google, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/time.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/clockchips.h>
+#include <linux/clocksource.h>
+#include <linux/clk.h>
+#include <asm/mach/time.h>
+#include <asm/io.h>
+#include <asm/mach/time.h>
+#include <asm/localtimer.h>
+
+#include <mach/hardware.h>
+
+#define TIMERUS_CNTR_1US 0x10
+#define TIMERUS_USEC_CFG 0x14
+#define TIMERUS_CNTR_FREEZE 0x4c
+
+#define TIMER1_BASE 0x0
+#define TIMER2_BASE 0x8
+#define TIMER3_BASE 0x50
+#define TIMER4_BASE 0x58
+
+#define TIMER_PTV 0x0
+#define TIMER_PCR 0x4
+
+#define TIMER1_IRQ 32
+#define TIMER2_IRQ 33
+#define TIMER3_IRQ 41
+#define TIMER4_IRQ 42
+
+struct tegra_timer;
+
+static void __iomem *timer_reg_base = IO_ADDRESS(TEGRA_TMR1_BASE);
+
+#define timer_writel(value, reg) \
+	__raw_writel(value, (u32)timer_reg_base + (reg))
+#define timer_readl(reg) \
+	__raw_readl((u32)timer_reg_base + (reg))
+
+static int tegra_timer_set_next_event(unsigned long cycles,
+					 struct clock_event_device *evt)
+{
+	u32 reg;
+
+	reg = 0x80000000 | ((1000000/HZ)*(cycles+1)-1);
+	timer_writel(reg, TIMER1_BASE + TIMER_PTV);
+
+	return 0;
+}
+
+static void tegra_timer_set_mode(enum clock_event_mode mode,
+				    struct clock_event_device *evt)
+{
+	u32 reg;
+
+	timer_writel(0, TIMER1_BASE + TIMER_PTV);
+
+	switch (mode) {
+	case CLOCK_EVT_MODE_PERIODIC:
+		reg = 0xC0000000 | ((1000000/HZ)-1);
+		timer_writel(reg, TIMER1_BASE + TIMER_PTV);
+		break;
+	case CLOCK_EVT_MODE_ONESHOT:
+		break;
+	case CLOCK_EVT_MODE_UNUSED:
+	case CLOCK_EVT_MODE_SHUTDOWN:
+	case CLOCK_EVT_MODE_RESUME:
+		break;
+	}
+}
+
+static cycle_t tegra_clocksource_read(struct clocksource *cs)
+{
+	return timer_readl(TIMERUS_CNTR_1US);
+}
+
+static struct clock_event_device tegra_clockevent = {
+	.name		= "timer0",
+	.rating         = 300,
+	.features       = CLOCK_EVT_FEAT_ONESHOT, CLOCK_EVT_FEAT_PERIODIC,
+	.mult           = 16777,
+	.shift		= 24,
+	.set_next_event	= tegra_timer_set_next_event,
+	.set_mode	= tegra_timer_set_mode,
+};
+
+static struct clocksource tegra_clocksource = {
+	.name	= "timer_us",
+	.rating	= 300,
+	.read	= tegra_clocksource_read,
+	.mask	= 0xFFFFFFFFUL,
+	.mult	= 1000,
+	.shift	= 0,
+	.flags	= CLOCK_SOURCE_IS_CONTINUOUS,
+};
+
+static irqreturn_t tegra_timer_interrupt(int irq, void *dev_id)
+{
+	struct clock_event_device *evt = (struct clock_event_device *)dev_id;
+	timer_writel(1<<30, TIMER1_BASE + TIMER_PCR);
+	evt->event_handler(evt);
+	return IRQ_HANDLED;
+}
+
+static struct irqaction tegra_timer_irq = {
+	.name		= "timer0",
+	.flags		= IRQF_DISABLED | IRQF_TIMER | IRQF_TRIGGER_HIGH,
+	.handler	= tegra_timer_interrupt,
+	.dev_id		= &tegra_clockevent,
+	.irq            = TIMER1_IRQ,
+};
+
+static void __init tegra_init_timer(void)
+{
+	struct clk *c;
+	int ret;
+
+#ifdef CONFIG_HAVE_ARM_TWD
+	twd_base = IO_ADDRESS(TEGRA_ARM_PERIF_BASE + 0x600);
+#endif
+
+	c = clk_get_sys("timer", NULL);
+	pr_info("Timer clock rate %lu\n", clk_get_rate(c));
+
+	switch (clk_get_rate(c)) {
+	case 12000000:
+		timer_writel(0x000b, TIMERUS_USEC_CFG);
+		break;
+	case 13000000:
+		timer_writel(0x000c, TIMERUS_USEC_CFG);
+		break;
+	case 19200000:
+		timer_writel(0x045f, TIMERUS_USEC_CFG);
+		break;
+	case 26000000:
+		timer_writel(0x0019, TIMERUS_USEC_CFG);
+		break;
+	default:
+		WARN(1, "Unknown clock rate");
+	}
+
+	if (clocksource_register(&tegra_clocksource)) {
+		printk(KERN_ERR "Failed to register clocksource\n");
+		BUG();
+	}
+
+	ret = setup_irq(tegra_timer_irq.irq, &tegra_timer_irq);
+	if (ret) {
+		printk(KERN_ERR "Failed to register timer IRQ: %d\n", ret);
+		BUG();
+	}
+
+	tegra_clockevent.max_delta_ns =
+		clockevent_delta2ns(0x1fffffff, &tegra_clockevent);
+	tegra_clockevent.max_delta_ns =
+		clockevent_delta2ns(0x1, &tegra_clockevent);
+	tegra_clockevent.cpumask = cpu_all_mask;
+	tegra_clockevent.irq = TIMER1_IRQ;
+	clockevents_register_device(&tegra_clockevent);
+
+	return;
+}
+
+struct sys_timer tegra_timer = {
+	.init = tegra_init_timer,
+};
-- 
1.6.4.4




-- 
Sincerely yours,
Mike.




More information about the linux-arm-kernel mailing list