diff mbox

[U-Boot,2/9] Tegra: T30: Add AVP (arm720t) files

Message ID 1347487855-27077-3-git-send-email-twarren@nvidia.com
State Changes Requested
Delegated to: Tom Rini
Headers show

Commit Message

Tom Warren Sept. 12, 2012, 10:10 p.m. UTC
Signed-off-by: Tom Warren <twarren@nvidia.com>
---
 arch/arm/cpu/arm720t/tegra30/Makefile  |   48 +++
 arch/arm/cpu/arm720t/tegra30/board.h   |   25 ++
 arch/arm/cpu/arm720t/tegra30/config.mk |   26 ++
 arch/arm/cpu/arm720t/tegra30/cpu.c     |  570 ++++++++++++++++++++++++++++++++
 arch/arm/cpu/arm720t/tegra30/cpu.h     |   65 ++++
 arch/arm/cpu/arm720t/tegra30/spl.c     |  132 ++++++++
 6 files changed, 866 insertions(+), 0 deletions(-)
 create mode 100644 arch/arm/cpu/arm720t/tegra30/Makefile
 create mode 100644 arch/arm/cpu/arm720t/tegra30/board.h
 create mode 100644 arch/arm/cpu/arm720t/tegra30/config.mk
 create mode 100644 arch/arm/cpu/arm720t/tegra30/cpu.c
 create mode 100644 arch/arm/cpu/arm720t/tegra30/cpu.h
 create mode 100644 arch/arm/cpu/arm720t/tegra30/spl.c

Comments

Stephen Warren Sept. 13, 2012, 8:02 p.m. UTC | #1
On 09/12/2012 04:10 PM, Tom Warren wrote:

Patch descriptions would be nice.

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

There's quite a bit of Tegra20-support in this file. Can this file be
shared with Tegra20 rather than forked and enhanced?

> +/* Returns 1 if the current CPU executing is a Cortex-A9, else 0 */
> +int cpu_is_cortexa9(void)
> +{
> +	u32 id = readb(NV_PA_PG_UP_BASE + PG_UP_TAG_0);
> +	return id == (PG_UP_TAG_0_PID_CPU & 0xff);
> +}

Hmm. Given this is support for the AVP/COP running SPL, shouldn't this
always be true? I thought Allen's SPL patches had cleaned this up.

> +static void enable_cpu_power_rail(void)
> +{
> +	struct pmc_ctlr *pmc = (struct pmc_ctlr *)NV_PA_PMC_BASE;
> +	u32 reg;
> +
> +	debug("enable_cpu_power_rail entry\n");
> +	reg = readl(&pmc->pmc_cntrl);
> +	reg |= CPUPWRREQ_OE;
> +	writel(reg, &pmc->pmc_cntrl);
> +
> +	/*
> +	 * Pulse PWRREQ via I2C.  We need to find out what this is
> +	 * doing, tidy up the code and maybe find a better place for it.
> +	 */
> +	tegra_i2c_ll_write_addr(0x005a, 0x0002);
> +	tegra_i2c_ll_write_data(0x2328, 0x0a02);
> +	udelay(1000);
> +	tegra_i2c_ll_write_data(0x0127, 0x0a02);
> +	udelay(10 * 1000);

Those functions access the DVC I2C controller's register space, so
presumably they're doing I2C accesses. Not all boards use the same PMIC,
so it seems like we really do need to factor this out.

> +	/*
> +	 * The TI PMU65861C needs a 3.75ms delay between enabling
> +	 * the power rail and enabling the CPU clock.  This delay
> +	 * between SM1EN and SM1 is for switching time + the ramp
> +	 * up of the voltage to the CPU (VDD_CPU from PMU). We use 0xf00 as
> +	 * is is ARM-friendly (can fit in a single ARMv4T mov immmediate
> +	 * instruction).
> +	 */
> +	udelay(3840);

The Cardhu board at least does not use the TPS65861. At the very least
the comment isn't quite right. Is this code needed?

> diff --git a/arch/arm/cpu/arm720t/tegra30/spl.c b/arch/arm/cpu/arm720t/tegra30/spl.c

> +void board_init_f(ulong dummy)
> +{
> +	board_init_uart_f();
> +
> +	/* Initialize periph GPIOs */
> +#ifdef CONFIG_SPI_UART_SWITCH
> +	gpio_early_init_uart();
> +#else
> +	gpio_config_uart();
> +#endif

Didn't we have patches to get rid of that mess and just use the same
function consistently across all boards, or was that only discussed and
never actually implemented?
Tom Warren Sept. 13, 2012, 9 p.m. UTC | #2
Stephen,

On Thu, Sep 13, 2012 at 1:02 PM, Stephen Warren <swarren@wwwdotorg.org> wrote:
> On 09/12/2012 04:10 PM, Tom Warren wrote:
>
> Patch descriptions would be nice.

Sure, sorry. Not sure how much more info I can add beyond what's in
the commit msg, though, at least for this patch.

>
>> diff --git a/arch/arm/cpu/arm720t/tegra30/cpu.c b/arch/arm/cpu/arm720t/tegra30/cpu.c
>
> There's quite a bit of Tegra20-support in this file. Can this file be
> shared with Tegra20 rather than forked and enhanced?
>
>> +/* Returns 1 if the current CPU executing is a Cortex-A9, else 0 */
>> +int cpu_is_cortexa9(void)
>> +{
>> +     u32 id = readb(NV_PA_PG_UP_BASE + PG_UP_TAG_0);
>> +     return id == (PG_UP_TAG_0_PID_CPU & 0xff);
>> +}
>
> Hmm. Given this is support for the AVP/COP running SPL, shouldn't this
> always be true? I thought Allen's SPL patches had cleaned this up.

Copied from tegra20/cpu.c - didn't notice it never gets called (same
for Tegra20). So it's vestigial and can be removed.

>
>> +static void enable_cpu_power_rail(void)
>> +{
>> +     struct pmc_ctlr *pmc = (struct pmc_ctlr *)NV_PA_PMC_BASE;
>> +     u32 reg;
>> +
>> +     debug("enable_cpu_power_rail entry\n");
>> +     reg = readl(&pmc->pmc_cntrl);
>> +     reg |= CPUPWRREQ_OE;
>> +     writel(reg, &pmc->pmc_cntrl);
>> +
>> +     /*
>> +      * Pulse PWRREQ via I2C.  We need to find out what this is
>> +      * doing, tidy up the code and maybe find a better place for it.
>> +      */
>> +     tegra_i2c_ll_write_addr(0x005a, 0x0002);
>> +     tegra_i2c_ll_write_data(0x2328, 0x0a02);
>> +     udelay(1000);
>> +     tegra_i2c_ll_write_data(0x0127, 0x0a02);
>> +     udelay(10 * 1000);
>
> Those functions access the DVC I2C controller's register space, so
> presumably they're doing I2C accesses. Not all boards use the same PMIC,
> so it seems like we really do need to factor this out.

It's in the original internal T30 repo for Cardhu, with a comment from
Simon Glass that I edited somewhat. I haven't tried removing it to see
if the board still boots.

>
>> +     /*
>> +      * The TI PMU65861C needs a 3.75ms delay between enabling
>> +      * the power rail and enabling the CPU clock.  This delay
>> +      * between SM1EN and SM1 is for switching time + the ramp
>> +      * up of the voltage to the CPU (VDD_CPU from PMU). We use 0xf00 as
>> +      * is is ARM-friendly (can fit in a single ARMv4T mov immmediate
>> +      * instruction).
>> +      */
>> +     udelay(3840);
>
> The Cardhu board at least does not use the TPS65861. At the very least
> the comment isn't quite right. Is this code needed?
>

No idea - it's in our internal T30 bringup repo, as well as Simon's. I
can try removing it and see if we power up consistently.

>> diff --git a/arch/arm/cpu/arm720t/tegra30/spl.c b/arch/arm/cpu/arm720t/tegra30/spl.c
>
>> +void board_init_f(ulong dummy)
>> +{
>> +     board_init_uart_f();
>> +
>> +     /* Initialize periph GPIOs */
>> +#ifdef CONFIG_SPI_UART_SWITCH
>> +     gpio_early_init_uart();
>> +#else
>> +     gpio_config_uart();
>> +#endif
>
> Didn't we have patches to get rid of that mess and just use the same
> function consistently across all boards, or was that only discussed and
> never actually implemented?

Someone on the list talked about a cleanup (Lucas? Thierry?), but,
AFAIK, that never happened, or I would have put it in tegra/next. At
the very least, it's not needed in Tegra30/spl.c, so I'll remove
it/clean it up.

Thanks,

Tom
Lucas Stach Sept. 13, 2012, 9:47 p.m. UTC | #3
Hi Tom,

Am Donnerstag, den 13.09.2012, 14:00 -0700 schrieb Tom Warren:
[...]
> 
> >> diff --git a/arch/arm/cpu/arm720t/tegra30/spl.c b/arch/arm/cpu/arm720t/tegra30/spl.c
> >
> >> +void board_init_f(ulong dummy)
> >> +{
> >> +     board_init_uart_f();
> >> +
> >> +     /* Initialize periph GPIOs */
> >> +#ifdef CONFIG_SPI_UART_SWITCH
> >> +     gpio_early_init_uart();
> >> +#else
> >> +     gpio_config_uart();
> >> +#endif
> >
> > Didn't we have patches to get rid of that mess and just use the same
> > function consistently across all boards, or was that only discussed and
> > never actually implemented?
> 
> Someone on the list talked about a cleanup (Lucas? Thierry?), but,
> AFAIK, that never happened, or I would have put it in tegra/next. At
> the very least, it's not needed in Tegra30/spl.c, so I'll remove
> it/clean it up.

I did the cleanup and you in fact missed it in the last round of tegra/next.
Patch is called "tegra20: rework UART GPIO handling" and is already
acked-by Simon Glass.

Thanks,
Lucas
Tom Warren Sept. 13, 2012, 10:06 p.m. UTC | #4
Lucas,

On Thu, Sep 13, 2012 at 2:47 PM, Lucas Stach <dev@lynxeye.de> wrote:
> Hi Tom,
>
> Am Donnerstag, den 13.09.2012, 14:00 -0700 schrieb Tom Warren:
> [...]
>>
>> >> diff --git a/arch/arm/cpu/arm720t/tegra30/spl.c b/arch/arm/cpu/arm720t/tegra30/spl.c
>> >
>> >> +void board_init_f(ulong dummy)
>> >> +{
>> >> +     board_init_uart_f();
>> >> +
>> >> +     /* Initialize periph GPIOs */
>> >> +#ifdef CONFIG_SPI_UART_SWITCH
>> >> +     gpio_early_init_uart();
>> >> +#else
>> >> +     gpio_config_uart();
>> >> +#endif
>> >
>> > Didn't we have patches to get rid of that mess and just use the same
>> > function consistently across all boards, or was that only discussed and
>> > never actually implemented?
>>
>> Someone on the list talked about a cleanup (Lucas? Thierry?), but,
>> AFAIK, that never happened, or I would have put it in tegra/next. At
>> the very least, it's not needed in Tegra30/spl.c, so I'll remove
>> it/clean it up.
>
> I did the cleanup and you in fact missed it in the last round of tegra/next.
> Patch is called "tegra20: rework UART GPIO handling" and is already
> acked-by Simon Glass.

Thanks, I see it. Now that I've re-read it, I'm remembering that I was
waiting on Allen Martin to answer Stephen's question:

" .. it looks like both SPL and non-SPL end up calling
gpio_early_init_uart(); is that duplication correct or problematic?"

I'll apply it to /next regardless, since Simon seems to think it's OK.

BTW, I'm not sure how patchwork is supposed to operate, but it appears
that the originator of the patch needs to assign it to me, mark it as
under review, etc. I don't seem to have that power for patches I
haven't written.  Is that how it works for other custodians?  It would
really help me keep track of Tegra patches if they could be
marked/assigned to me so I can sort on 'em.  Right now, I just use a
filter with 'tegra' in it, which doesn't always find all the patches I
need to know about.

Thanks,

Tom
>
> Thanks,
> Lucas
>
>
Simon Glass Sept. 18, 2012, 7:37 p.m. UTC | #5
Hi Tom,

On Wed, Sep 12, 2012 at 3:10 PM, Tom Warren <twarren.nvidia@gmail.com> wrote:
> Signed-off-by: Tom Warren <twarren@nvidia.com>
> ---
>  arch/arm/cpu/arm720t/tegra30/Makefile  |   48 +++
>  arch/arm/cpu/arm720t/tegra30/board.h   |   25 ++
>  arch/arm/cpu/arm720t/tegra30/config.mk |   26 ++
>  arch/arm/cpu/arm720t/tegra30/cpu.c     |  570 ++++++++++++++++++++++++++++++++
>  arch/arm/cpu/arm720t/tegra30/cpu.h     |   65 ++++
>  arch/arm/cpu/arm720t/tegra30/spl.c     |  132 ++++++++

It certainly has complicated your work, with the AVP arm720t refactor
going in before these patches.

I feel that quite a bit of the code here should perhaps go to
arch/arm/cpu/arm720t/tegra-common or similar, so that you can share it
with tegra30.

Regards,
Simon
Tom Warren Sept. 18, 2012, 9:19 p.m. UTC | #6
Simon,

On Tue, Sep 18, 2012 at 12:37 PM, Simon Glass <sjg@chromium.org> wrote:
> Hi Tom,
>
> On Wed, Sep 12, 2012 at 3:10 PM, Tom Warren <twarren.nvidia@gmail.com> wrote:
>> Signed-off-by: Tom Warren <twarren@nvidia.com>
>> ---
>>  arch/arm/cpu/arm720t/tegra30/Makefile  |   48 +++
>>  arch/arm/cpu/arm720t/tegra30/board.h   |   25 ++
>>  arch/arm/cpu/arm720t/tegra30/config.mk |   26 ++
>>  arch/arm/cpu/arm720t/tegra30/cpu.c     |  570 ++++++++++++++++++++++++++++++++
>>  arch/arm/cpu/arm720t/tegra30/cpu.h     |   65 ++++
>>  arch/arm/cpu/arm720t/tegra30/spl.c     |  132 ++++++++
>
> It certainly has complicated your work, with the AVP arm720t refactor
> going in before these patches.

In some ways, yes. In others, it made it easy to first get a SPL (AVP)
U-Boot up and printing its sign-on, and then having a base to work
from/debug A9 code for the second, CPU-init half.
>
> I feel that quite a bit of the code here should perhaps go to
> arch/arm/cpu/arm720t/tegra-common or similar, so that you can share it
> with tegra30.

WIP.  There'll be an arch/arm/cpu/arm720t/tegra-common, an
arch/arm/cpu/armv7/tegra-common, and even an
arch/arm/cpu/tegra-common, plus an arch/arm/include/asm/arch-tegra to
hold common code & include files.

How those changes will be captured in a patchset (or 2) that show the
movement of the original Tegra20 files, then the copy/edit for Tegra30
is still to be seen.

Thanks,

Tom
>
> Regards,
> Simon
diff mbox

Patch

diff --git a/arch/arm/cpu/arm720t/tegra30/Makefile b/arch/arm/cpu/arm720t/tegra30/Makefile
new file mode 100644
index 0000000..96e722c
--- /dev/null
+++ b/arch/arm/cpu/arm720t/tegra30/Makefile
@@ -0,0 +1,48 @@ 
+#
+# (C) Copyright 2010-2012 Nvidia Corporation.
+#
+# (C) Copyright 2000-2008
+# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+#
+# See file CREDITS for list of people who contributed to this
+# project.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; either version 2 of
+# the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+# MA 02111-1307 USA
+#
+
+include $(TOPDIR)/config.mk
+
+LIB	= $(obj)lib$(SOC).o
+
+COBJS-y	+= cpu.o
+COBJS-$(CONFIG_SPL_BUILD) += spl.o
+
+SRCS	:= $(COBJS-y:.o=.c)
+OBJS	:= $(addprefix $(obj),$(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/arm720t/tegra30/board.h b/arch/arm/cpu/arm720t/tegra30/board.h
new file mode 100644
index 0000000..fc11a7b
--- /dev/null
+++ b/arch/arm/cpu/arm720t/tegra30/board.h
@@ -0,0 +1,25 @@ 
+/*
+ * (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
+ */
+
+void board_init_uart_f(void);
+void gpio_config_uart(void);
diff --git a/arch/arm/cpu/arm720t/tegra30/config.mk b/arch/arm/cpu/arm720t/tegra30/config.mk
new file mode 100644
index 0000000..ca9c6ea
--- /dev/null
+++ b/arch/arm/cpu/arm720t/tegra30/config.mk
@@ -0,0 +1,26 @@ 
+#
+# (C) Copyright 2010-2012
+# NVIDIA Corporation <www.nvidia.com>
+#
+# (C) Copyright 2002
+# Gary Jennejohn, DENX Software Engineering, <garyj@denx.de>
+#
+# See file CREDITS for list of people who contributed to this
+# project.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; either version 2 of
+# the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+# MA 02111-1307 USA
+#
+USE_PRIVATE_LIBGCC = yes
diff --git a/arch/arm/cpu/arm720t/tegra30/cpu.c b/arch/arm/cpu/arm720t/tegra30/cpu.c
new file mode 100644
index 0000000..f7d9b87
--- /dev/null
+++ b/arch/arm/cpu/arm720t/tegra30/cpu.c
@@ -0,0 +1,570 @@ 
+/*
+ * (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/tegra30.h>
+#include <asm/arch/clk_rst.h>
+#include <asm/arch/clock.h>
+#include <asm/arch/flow.h>
+#include <asm/arch/fuse.h>
+#include <asm/arch/tegra_i2c.h>
+#include <asm/arch/pinmux.h>
+#include <asm/arch/pmc.h>
+#include <asm/arch/scu.h>
+#include "cpu.h"
+
+struct clk_pll_table {
+	u16		n;
+	u16		m;
+	u8		p;
+	u8		cpcon;
+};
+
+/* ~0=uninitialized/unknown, 0=false, 1=true */
+uint32_t is_tegra_processor_reset = 0xffffffff;
+
+/*
+ * Timing tables for each SOC for all four oscillator options.
+ */
+static struct clk_pll_table tegra_pll_x_table[TEGRA_SOC_COUNT]
+						[CLOCK_OSC_FREQ_COUNT] = {
+	/* T20: 1 GHz */
+	{{ 1000, 13, 0, 12},	/* OSC 13M */
+	 { 625,  12, 0, 8},	/* OSC 19.2M */
+	 { 1000, 12, 0, 12},	/* OSC 12M */
+	 { 1000, 26, 0, 12},	/* OSC 26M */
+	},
+
+	/* T25: 1.2 GHz */
+	{{ 923, 10, 0, 12},
+	 { 750, 12, 0, 8},
+	 { 600,  6, 0, 12},
+	 { 600, 13, 0, 12},
+	},
+
+	/* T30(slow): 1.0 GHz */
+	{{ 1000,  13, 0, 8},
+	 { 625,  12, 0, 4},
+	 { 1000, 12, 0, 8},
+	 { 1000,  26, 0, 8},
+	},
+
+	/* T30(high): 1.4 GHz */
+	{{ 862, 8, 0, 8},
+	 { 583, 8, 0, 4},
+	 { 700, 6, 0, 8},
+	 { 700, 13, 0, 8},
+	},
+
+	/* TEGRA_SOC2_SLOW: 312 MHz */
+	{{ 312, 13, 0, 12},	/* OSC 13M */
+	 { 260, 16, 0, 8},	/* OSC 19.2M */
+	 { 312, 12, 0, 12},	/* OSC 12M */
+	 { 312, 26, 0, 12},	/* OSC 26M */
+	},
+};
+
+enum tegra_family_t {
+	TEGRA_FAMILY_T2x,
+	TEGRA_FAMILY_T3x,
+};
+
+int tegra_get_chip_type(void)
+{
+	struct fuse_regs *fuse = (struct fuse_regs *)NV_PA_FUSE_BASE;
+	uint tegra_sku_id;
+
+	debug("tegra_get_chip_type entry\n");
+	tegra_sku_id = readl(&fuse->sku_info) & 0xff;
+	debug("  tegra_get_chip_type: sku_id = %d\n", tegra_sku_id);
+
+	switch (tegra_sku_id) {
+	case SKU_ID_T20:
+		return TEGRA_SOC_T20;
+	case SKU_ID_T25SE:
+	case SKU_ID_AP25:
+	case SKU_ID_T25:
+	case SKU_ID_AP25E:
+	case SKU_ID_T25E:
+		return TEGRA_SOC_T25;
+	case SKU_ID_T30:
+		/*
+		 * T30 has two options. We will return TEGRA_SOC_T30 until
+		 * we have the fdt set up when it may change to
+		 * TEGRA_SOC_T30_408MHZ depending on what we set PLLP to.
+		 */
+		if (clock_get_rate(CLOCK_ID_PERIPH) == 408000000)
+			return TEGRA_SOC_T30_408MHZ;
+		else
+			return TEGRA_SOC_T30;
+
+	default:
+		/* unknown sku id */
+		return TEGRA_SOC_UNKNOWN;
+	}
+}
+
+static enum tegra_family_t get_family(void)
+{
+	u32 reg, chip_id;
+
+	debug("tegra_get_family entry\n");
+	reg = readl(NV_PA_APB_MISC_BASE + GP_HIDREV);
+
+	chip_id = reg >> 8;
+	chip_id &= 0xff;
+	debug("  tegra_get_family: chip_id = %x\n", chip_id);
+	if (chip_id == 0x30)
+		return TEGRA_FAMILY_T3x;
+	else
+		return TEGRA_FAMILY_T2x;
+}
+
+int get_num_cpus(void)
+{
+	return get_family() == TEGRA_FAMILY_T3x ? 4 : 2;
+}
+
+/* Returns 1 if the current CPU executing is a Cortex-A9, else 0 */
+int cpu_is_cortexa9(void)
+{
+	u32 id = readb(NV_PA_PG_UP_BASE + PG_UP_TAG_0);
+	return id == (PG_UP_TAG_0_PID_CPU & 0xff);
+}
+
+static void adjust_pllp_out_freqs(void)
+{
+	struct clk_rst_ctlr *clkrst = (struct clk_rst_ctlr *)NV_PA_CLK_RST_BASE;
+	struct clk_pll *pll = &clkrst->crc_pll[CLOCK_ID_PERIPH];
+	u32 reg;
+
+	/* Set T30 PLLP_OUT1, 2, 3 & 4 freqs to 9.6, 48, 102 & 204MHz */
+	reg = readl(&pll->pll_out);     /* OUTA, contains OUT2 / OUT1 */
+	reg |= (IN_408_OUT_48_DIVISOR << PLLP_OUT2_RATIO) | PLLP_OUT2_OVR
+		| (IN_408_OUT_9_6_DIVISOR << PLLP_OUT1_RATIO) | PLLP_OUT1_OVR;
+	writel(reg, &pll->pll_out);
+
+	reg = readl(&pll->pll_out_b);   /* OUTB, contains OUT4 / OUT3 */
+	reg |= (IN_408_OUT_204_DIVISOR << PLLP_OUT4_RATIO) | PLLP_OUT4_OVR
+		| (IN_408_OUT_102_DIVISOR << PLLP_OUT3_RATIO) | PLLP_OUT3_OVR;
+	writel(reg, &pll->pll_out_b);
+}
+
+static int pllx_set_rate(struct clk_pll_simple *pll , u32 divn, u32 divm,
+		u32 divp, u32 cpcon)
+{
+	u32 reg;
+
+	/* If PLLX is already enabled, just return */
+	if (readl(&pll->pll_base) & PLL_ENABLE_MASK) {
+		debug("pllx_set_rate: PLLX already enabled, returning\n");
+		return 0;
+	}
+
+	debug(" pllx_set_rate entry\n");
+
+	/* Set BYPASS, m, n and p to PLLX_BASE */
+	reg = PLL_BYPASS_MASK | (divm << PLL_DIVM_SHIFT);
+	reg |= ((divn << PLL_DIVN_SHIFT) | (divp << PLL_DIVP_SHIFT));
+	writel(reg, &pll->pll_base);
+
+	/* Set cpcon to PLLX_MISC */
+	reg = (cpcon << PLL_CPCON_SHIFT);
+
+	/* Set dccon to PLLX_MISC if freq > 600MHz */
+	if (divn > 600)
+		reg |= (1 << PLL_DCCON_SHIFT);
+	writel(reg, &pll->pll_misc);
+
+	/* Enable PLLX */
+	reg = readl(&pll->pll_base);
+	reg |= PLL_ENABLE_MASK;
+
+	/* Disable BYPASS */
+	reg &= ~PLL_BYPASS_MASK;
+	writel(reg, &pll->pll_base);
+
+	/* Set lock_enable to PLLX_MISC */
+	reg = readl(&pll->pll_misc);
+	reg |= PLL_LOCK_ENABLE_MASK;
+	writel(reg, &pll->pll_misc);
+
+	return 0;
+}
+
+void init_pllx(int slow)
+{
+	struct clk_rst_ctlr *clkrst = (struct clk_rst_ctlr *)NV_PA_CLK_RST_BASE;
+	struct clk_pll_simple *pll = &clkrst->crc_pll_simple[SIMPLE_PLLX];
+	int chip_type;
+	enum clock_osc_freq osc;
+	struct clk_pll_table *sel;
+
+	debug("init_pllx entry\n");
+
+	/* get chip type. If unknown, assign to T30 */
+	chip_type = tegra_get_chip_type();
+	if (chip_type == TEGRA_SOC_UNKNOWN)
+		chip_type = TEGRA_SOC_T30;
+	debug(" init_pllx: chip_type = %d\n", chip_type);
+
+	/* get osc freq */
+	osc = clock_get_osc_freq();
+	debug("  init_pllx: osc = %d\n", osc);
+
+	/* set pllx */
+	sel = &tegra_pll_x_table[chip_type][osc];
+	pllx_set_rate(pll, sel->n, sel->m, sel->p, sel->cpcon);
+
+	/* once we are out of slow mode, set up the T30 PLLs also */
+	if (!slow && chip_type == TEGRA_SOC_T30_408MHZ) {
+		debug("  init_pllx: adjusting PLLP out freqs\n");
+		adjust_pllp_out_freqs();
+	}
+}
+
+static void enable_cpu_clock(int enable)
+{
+	struct clk_rst_ctlr *clkrst = (struct clk_rst_ctlr *)NV_PA_CLK_RST_BASE;
+	u32 clk;
+
+	debug("enable_cpu_clock entry, enable = %d\n", enable);
+	/*
+	 * NOTE:
+	 * Regardless of whether the request is to enable or disable the CPU
+	 * clock, every processor in the CPU complex except the master (CPU 0)
+	 * will have it's clock stopped because the AVP only talks to the
+	 * master. The AVP does not know (nor does it need to know) that there
+	 * are multiple processors in the CPU complex.
+	 */
+
+	if (enable) {
+		/* Initialize PLLX in 'slow' mode */
+		init_pllx(1);
+
+		/* Wait until all clocks are stable */
+		udelay(PLL_STABILIZATION_DELAY);
+
+		writel(CCLK_BURST_POLICY, &clkrst->crc_cclk_brst_pol);
+		writel(SUPER_CCLK_DIVIDER, &clkrst->crc_super_cclk_div);
+	}
+
+	/*
+	 * Read the register containing the individual CPU clock enables and
+	 * always stop the clock to CPUs 1, 2 & 3.
+	 */
+	clk = readl(&clkrst->crc_clk_cpu_cmplx);
+	clk |= 1 << CPU1_CLK_STP_SHIFT;
+	clk |= 1 << CPU2_CLK_STP_SHIFT;
+	clk |= 1 << CPU3_CLK_STP_SHIFT;
+
+	/* Stop/Unstop the CPU clock */
+	clk &= ~CPU0_CLK_STP_MASK;
+	clk |= !enable << CPU0_CLK_STP_SHIFT;
+	writel(clk, &clkrst->crc_clk_cpu_cmplx);
+
+	clock_enable(PERIPH_ID_CPU);
+	debug("enable_cpu_clock entry, enabled CPU clock\n");
+}
+
+static int is_cpu_powered(void)
+{
+	struct pmc_ctlr *pmc = (struct pmc_ctlr *)NV_PA_PMC_BASE;
+
+	debug("is_cpu_powered entry\n");
+	return (readl(&pmc->pmc_pwrgate_status) & CPU_PWRED) ? 1 : 0;
+}
+
+static void remove_cpu_io_clamps(void)
+{
+	struct pmc_ctlr *pmc = (struct pmc_ctlr *)NV_PA_PMC_BASE;
+	u32 reg;
+
+	debug("remove_cpu_io_clamps entry\n");
+	/* Remove the clamps on the CPU I/O signals */
+	reg = readl(&pmc->pmc_remove_clamping);
+	reg |= CPU_CLMP;
+	writel(reg, &pmc->pmc_remove_clamping);
+
+	/* Give I/O signals time to stabilize */
+	udelay(IO_STABILIZATION_DELAY);
+}
+
+static void powerup_cpu(void)
+{
+	struct pmc_ctlr *pmc = (struct pmc_ctlr *)NV_PA_PMC_BASE;
+	u32 reg;
+	int timeout = IO_STABILIZATION_DELAY;
+
+	debug("powerup_cpu entry\n");
+	if (!is_cpu_powered()) {
+		/* Toggle the CPU power state (OFF -> ON) */
+		reg = readl(&pmc->pmc_pwrgate_toggle);
+		reg &= PARTID_CP;
+		reg |= START_CP;
+		writel(reg, &pmc->pmc_pwrgate_toggle);
+
+		/* Wait for the power to come up */
+		while (!is_cpu_powered()) {
+			if (timeout-- == 0)
+				printf("CPU failed to power up!\n");
+			else
+				udelay(10);
+		}
+
+		/*
+		 * Remove the I/O clamps from CPU power partition.
+		 * Recommended only on a Warm boot, if the CPU partition gets
+		 * power gated. Shouldn't cause any harm when called after a
+		 * cold boot according to HW, probably just redundant.
+		 */
+		remove_cpu_io_clamps();
+	}
+}
+
+void tegra_i2c_ll_write_addr(uint addr, uint config)
+{
+	struct i2c_ctlr *reg = (struct i2c_ctlr *)TEGRA_DVC_BASE;
+
+	writel(addr, &reg->cmd_addr0);
+	writel(config, &reg->cnfg);
+}
+
+void tegra_i2c_ll_write_data(uint data, uint config)
+{
+	struct i2c_ctlr *reg = (struct i2c_ctlr *)TEGRA_DVC_BASE;
+
+	writel(data, &reg->cmd_data1);
+	writel(config, &reg->cnfg);
+}
+
+static void enable_cpu_power_rail(void)
+{
+	struct pmc_ctlr *pmc = (struct pmc_ctlr *)NV_PA_PMC_BASE;
+	u32 reg;
+
+	debug("enable_cpu_power_rail entry\n");
+	reg = readl(&pmc->pmc_cntrl);
+	reg |= CPUPWRREQ_OE;
+	writel(reg, &pmc->pmc_cntrl);
+
+	/*
+	 * Pulse PWRREQ via I2C.  We need to find out what this is
+	 * doing, tidy up the code and maybe find a better place for it.
+	 */
+	tegra_i2c_ll_write_addr(0x005a, 0x0002);
+	tegra_i2c_ll_write_data(0x2328, 0x0a02);
+	udelay(1000);
+	tegra_i2c_ll_write_data(0x0127, 0x0a02);
+	udelay(10 * 1000);
+
+	/*
+	 * The TI PMU65861C needs a 3.75ms delay between enabling
+	 * the power rail and enabling the CPU clock.  This delay
+	 * between SM1EN and SM1 is for switching time + the ramp
+	 * up of the voltage to the CPU (VDD_CPU from PMU). We use 0xf00 as
+	 * is is ARM-friendly (can fit in a single ARMv4T mov immmediate
+	 * instruction).
+	 */
+	udelay(3840);
+}
+
+static void reset_A9_cpu(int reset)
+{
+	/*
+	* NOTE:  Regardless of whether the request is to hold the CPU in reset
+	*        or take it out of reset, every processor in the CPU complex
+	*        except the master (CPU 0) will be held in reset because the
+	*        AVP only talks to the master. The AVP does not know that there
+	*        are multiple processors in the CPU complex.
+	*/
+	int mask = crc_rst_cpu | crc_rst_de | crc_rst_debug;
+	int num_cpus = get_num_cpus();
+	int cpu;
+
+	debug("reset_a9_cpu entry\n");
+	/* Hold CPUs 1 onwards in reset, and CPU 0 if asked */
+	for (cpu = 1; cpu < num_cpus; cpu++)
+		reset_cmplx_set_enable(cpu, mask, 1);
+	reset_cmplx_set_enable(0, mask, reset);
+
+	/* Enable/Disable master CPU reset */
+	reset_set_enable(PERIPH_ID_CPU, reset);
+}
+
+/**
+ * The T30 requires some special clock initialization, including setting up
+ * the dvc i2c, turning on mselect and selecting the G CPU cluster
+ */
+void t30_init_clocks(void)
+{
+	/*
+	* Sadly our clock functions don't support the V and W clocks of T30
+	* yet, as well as a few other functions, so use low-level register
+	* access for now. This eventual removal of low-level code from
+	* ap20.c is the same process we went through for T20.
+	*/
+	struct clk_rst_ctlr *clkrst =
+			(struct clk_rst_ctlr *)NV_PA_CLK_RST_BASE;
+	struct flow_ctlr *flow = (struct flow_ctlr *)NV_PA_FLOW_BASE;
+	u32 val;
+
+	debug("t30_init_clocks entry\n");
+	/* Set active CPU cluster to G */
+	clrbits_le32(flow->cluster_control, 1 << 0);
+
+	/*
+	 * Switch system clock to PLLP_OUT4 (108 MHz), AVP will now run
+	 * at 108 MHz. This is glitch free as only the source is changed, no
+	 * special precaution needed.
+	 */
+	val = (SCLK_SOURCE_PLLP_OUT4 << SCLK_SWAKEUP_FIQ_SOURCE_SHIFT) |
+		(SCLK_SOURCE_PLLP_OUT4 << SCLK_SWAKEUP_IRQ_SOURCE_SHIFT) |
+		(SCLK_SOURCE_PLLP_OUT4 << SCLK_SWAKEUP_RUN_SOURCE_SHIFT) |
+		(SCLK_SOURCE_PLLP_OUT4 << SCLK_SWAKEUP_IDLE_SOURCE_SHIFT) |
+		(SCLK_SYS_STATE_RUN << SCLK_SYS_STATE_SHIFT);
+	writel(val, &clkrst->crc_sclk_brst_pol);
+
+	writel(SUPER_SCLK_ENB_MASK, &clkrst->crc_super_sclk_div);
+
+	val = (0 << CLK_SYS_RATE_HCLK_DISABLE_SHIFT) |
+		(1 << CLK_SYS_RATE_AHB_RATE_SHIFT) |
+		(0 << CLK_SYS_RATE_PCLK_DISABLE_SHIFT) |
+		(0 << CLK_SYS_RATE_APB_RATE_SHIFT);
+	writel(val, &clkrst->crc_clk_sys_rate);
+
+	/* Put i2c, mselect in reset and enable clocks */
+	reset_set_enable(PERIPH_ID_DVC_I2C, 1);
+	clock_set_enable(PERIPH_ID_DVC_I2C, 1);
+	reset_set_enable(PERIPH_ID_MSELECT, 1);
+	clock_set_enable(PERIPH_ID_MSELECT, 1);
+
+	/* Switch MSELECT clock to PLLP (00) */
+	clock_ll_set_source(PERIPH_ID_MSELECT, 0);
+
+	/*
+	 * Our high-level clock routines are not available prior to
+	 * relocation. We use the low-level functions which require a
+	 * hard-coded divisor. Use CLK_M with divide by (n + 1 = 17)
+	 */
+	clock_ll_set_source_divisor(PERIPH_ID_DVC_I2C, 3, 16);
+
+	/*
+	 * Give clocks time to stabilize, then take i2c and mselect out of
+	 * reset
+	 */
+	udelay(1000);
+	reset_set_enable(PERIPH_ID_DVC_I2C, 0);
+	reset_set_enable(PERIPH_ID_MSELECT, 0);
+}
+
+static void clock_enable_coresight(int enable)
+{
+	u32 rst, src;
+
+	debug("clock_enable_coresight entry\n");
+	clock_set_enable(PERIPH_ID_CORESIGHT, enable);
+	reset_set_enable(PERIPH_ID_CORESIGHT, !enable);
+
+	if (enable) {
+		/*
+		 * Put CoreSight on PLLP_OUT0 (216 MHz) and divide it down by
+		 *  1.5, giving an effective frequency of 144MHz.
+		 * Set PLLP_OUT0 [bits31:30 = 00], and use a 7.1 divisor
+		 *  (bits 7:0), so 00000001b == 1.5 (n+1 + .5)
+		 *
+		 * Clock divider request for 204MHz would setup CSITE clock as
+		 * 144MHz for PLLP base 216MHz and 204MHz for PLLP base 408MHz
+		 */
+		if (tegra_get_chip_type() == TEGRA_SOC_T30_408MHZ)
+			src = CLK_DIVIDER(NVBL_PLLP_KHZ, 204000);
+		else
+			src = CLK_DIVIDER(NVBL_PLLP_KHZ, 144000);
+		clock_ll_set_source_divisor(PERIPH_ID_CSI, 0, src);
+
+		/* Unlock the CPU CoreSight interfaces */
+		rst = CORESIGHT_UNLOCK;
+		writel(rst, CSITE_CPU_DBG0_LAR);
+		writel(rst, CSITE_CPU_DBG1_LAR);
+		writel(rst, CSITE_CPU_DBG2_LAR);
+		writel(rst, CSITE_CPU_DBG3_LAR);
+	}
+}
+
+static void set_cpu_running(int run)
+{
+	struct flow_ctlr *flow = (struct flow_ctlr *)NV_PA_FLOW_BASE;
+
+	debug("set_cpu_running entry, run = %d\n", run);
+	writel(run ? FLOW_MODE_NONE : FLOW_MODE_STOP, &flow->halt_cpu_events);
+}
+
+void start_cpu(u32 reset_vector)
+{
+	debug("start_cpu entry, reset_vector = %x\n", reset_vector);
+	t30_init_clocks();
+
+	/* Enable VDD_CPU */
+	enable_cpu_power_rail();
+
+	set_cpu_running(0);
+
+	/* Hold the CPUs in reset */
+	reset_A9_cpu(1);
+
+	/* Disable the CPU clock */
+	enable_cpu_clock(0);
+
+	/* Enable CoreSight */
+	clock_enable_coresight(1);
+
+	/*
+	 * Set the entry point for CPU execution from reset,
+	 *  if it's a non-zero value.
+	 */
+	if (reset_vector)
+		writel(reset_vector, EXCEP_VECTOR_CPU_RESET_VECTOR);
+
+	/* Enable the CPU clock */
+	enable_cpu_clock(1);
+
+	/* If the CPU doesn't already have power, power it up */
+	powerup_cpu();
+
+	/* Take the CPU out of reset */
+	reset_A9_cpu(0);
+
+	set_cpu_running(1);
+}
+
+
+void halt_avp(void)
+{
+	debug("halt_avp entry\n");
+	for (;;) {
+		writel((HALT_COP_EVENT_JTAG | HALT_COP_EVENT_IRQ_1 \
+			| HALT_COP_EVENT_FIQ_1 | (FLOW_MODE_STOP<<29)),
+			FLOW_CTLR_HALT_COP_EVENTS);
+	}
+}
diff --git a/arch/arm/cpu/arm720t/tegra30/cpu.h b/arch/arm/cpu/arm720t/tegra30/cpu.h
new file mode 100644
index 0000000..a5c0474
--- /dev/null
+++ b/arch/arm/cpu/arm720t/tegra30/cpu.h
@@ -0,0 +1,65 @@ 
+/*
+ * (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/types.h>
+
+/* Stabilization delays, in usec */
+#define PLL_STABILIZATION_DELAY (300)
+#define IO_STABILIZATION_DELAY	(1000)
+
+#define NVBL_PLLP_KHZ	(216000)
+
+#define PLLX_ENABLED		(1 << 30)
+#define CCLK_BURST_POLICY	0x20008888
+#define SUPER_CCLK_DIVIDER	0x80000000
+
+/* Calculate clock fractional divider value from ref and target frequencies */
+#define CLK_DIVIDER(REF, FREQ)  ((((REF) * 2) / FREQ) - 2)
+
+/* Calculate clock frequency value from reference and clock divider value */
+#define CLK_FREQUENCY(REF, REG)  (((REF) * 2) / (REG + 2))
+
+/* AVP/CPU ID */
+#define PG_UP_TAG_0_PID_CPU	0x55555555	/* CPU aka "a9" aka "mpcore" */
+#define PG_UP_TAG_0             0x0
+
+#define CORESIGHT_UNLOCK	0xC5ACCE55;
+
+#define EXCEP_VECTOR_CPU_RESET_VECTOR	(NV_PA_EVP_BASE + 0x100)
+#define CSITE_CPU_DBG0_LAR		(NV_PA_CSITE_BASE + 0x10FB0)
+#define CSITE_CPU_DBG1_LAR		(NV_PA_CSITE_BASE + 0x12FB0)
+#define CSITE_CPU_DBG2_LAR		(NV_PA_CSITE_BASE + 0x14FB0)
+#define CSITE_CPU_DBG3_LAR		(NV_PA_CSITE_BASE + 0x16FB0)
+
+#define FLOW_CTLR_HALT_COP_EVENTS	(NV_PA_FLOW_BASE + 4)
+#define FLOW_MODE_STOP			2
+#define HALT_COP_EVENT_JTAG		(1 << 28)
+#define HALT_COP_EVENT_IRQ_1		(1 << 11)
+#define HALT_COP_EVENT_FIQ_1		(1 << 9)
+
+#define GP_HIDREV		0x804
+#define FLOW_MODE_NONE		0
+
+#define SIMPLE_PLLX     (CLOCK_ID_XCPU - CLOCK_ID_FIRST_SIMPLE)
+
+void start_cpu(u32 reset_vector);
+void halt_avp(void)  __attribute__ ((noreturn));
diff --git a/arch/arm/cpu/arm720t/tegra30/spl.c b/arch/arm/cpu/arm720t/tegra30/spl.c
new file mode 100644
index 0000000..c391746
--- /dev/null
+++ b/arch/arm/cpu/arm720t/tegra30/spl.c
@@ -0,0 +1,132 @@ 
+/*
+ * (C) Copyright 2012
+ * NVIDIA Inc, <www.nvidia.com>
+ *
+ * Allen Martin <amartin@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/u-boot.h>
+#include <asm/utils.h>
+#include <asm/arch/sys_proto.h>
+#include <asm/arch/clock.h>
+#include <nand.h>
+#include <mmc.h>
+#include <fat.h>
+#include <version.h>
+#include <i2c.h>
+#include <image.h>
+#include <malloc.h>
+#include <linux/compiler.h>
+#include "board.h"
+#include "cpu.h"
+
+#include <asm/io.h>
+#include <asm/arch/tegra30.h>
+#include <asm/arch/clk_rst.h>
+#include <asm/arch/clock.h>
+#include <asm/arch/pmc.h>
+#include <asm/arch/pinmux.h>
+#include <asm/arch/scu.h>
+#include <common.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/* Define global data structure pointer to it*/
+static gd_t gdata __attribute__ ((section(".data")));
+static bd_t bdata __attribute__ ((section(".data")));
+
+inline void hang(void)
+{
+	puts("### ERROR ### Please RESET the board ###\n");
+	for (;;)
+		;
+}
+
+void board_init_f(ulong dummy)
+{
+	board_init_uart_f();
+
+	/* Initialize periph GPIOs */
+#ifdef CONFIG_SPI_UART_SWITCH
+	gpio_early_init_uart();
+#else
+	gpio_config_uart();
+#endif
+
+	/*
+	 * We call relocate_code() with relocation target same as the
+	 * CONFIG_SYS_SPL_TEXT_BASE. This will result in relocation getting
+	 * skipped. Instead, only .bss initialization will happen. That's
+	 * all we need
+	 */
+	debug(">>board_init_f()\n");
+	relocate_code(CONFIG_SPL_STACK, &gdata, CONFIG_SPL_TEXT_BASE);
+}
+
+/* This requires UART clocks to be enabled */
+static void preloader_console_init(void)
+{
+	const char *u_boot_rev = U_BOOT_VERSION;
+
+	gd = &gdata;
+	gd->bd = &bdata;
+	gd->flags |= GD_FLG_RELOC;
+	gd->baudrate = CONFIG_BAUDRATE;
+
+	serial_init();		/* serial communications setup */
+
+	gd->have_console = 1;
+
+	/* Avoid a second "U-Boot" coming from this string */
+	u_boot_rev = &u_boot_rev[7];
+
+	printf("\nU-Boot SPL %s (%s - %s)\n", u_boot_rev, U_BOOT_DATE,
+		U_BOOT_TIME);
+}
+
+void board_init_r(gd_t *id, ulong dummy)
+{
+	struct pmux_tri_ctlr *pmt = (struct pmux_tri_ctlr *)NV_PA_APB_MISC_BASE;
+
+	/* enable JTAG */
+	writel(0xC0, &pmt->pmt_cfg_ctl);
+
+	debug(">>spl:board_init_r()\n");
+
+	mem_malloc_init(CONFIG_SYS_SPL_MALLOC_START,
+			CONFIG_SYS_SPL_MALLOC_SIZE);
+
+#ifdef CONFIG_SPL_BOARD_INIT
+	spl_board_init();
+#endif
+
+	clock_early_init();
+	preloader_console_init();
+
+	start_cpu((u32)CONFIG_SYS_TEXT_BASE);
+	halt_avp();
+	/* not reached */
+}
+
+int board_usb_init(const void *blob)
+{
+	return 0;
+}