ARM1176: TI: TNETV107X soc initial support

TNETV107X is a Texas Instruments SoC based on an ARM1176 core, and with a
bunch on on-chip integrated peripherals.  This is an initial commit with
basic functionality, more commits with drivers, etc. to follow.

Signed-off-by: Cyril Chemparathy <cyril@ti.com>
Signed-off-by: Sandeep Paulraj <s-paulraj@ti.com>
diff --git a/arch/arm/cpu/arm1176/tnetv107x/Makefile b/arch/arm/cpu/arm1176/tnetv107x/Makefile
new file mode 100644
index 0000000..fe9d8a0
--- /dev/null
+++ b/arch/arm/cpu/arm1176/tnetv107x/Makefile
@@ -0,0 +1,44 @@
+#
+# 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+
+include $(TOPDIR)/config.mk
+
+LIB	= $(obj)lib$(SOC).a
+
+COBJS	+= aemif.o clock.o init.o mux.o timer.o wdt.o
+SOBJS	+= lowlevel_init.o
+
+SRCS	:= $(START:.o=.S) $(SOBJS:.o=.S) $(COBJS:.o=.c)
+
+OBJS	:= $(addprefix $(obj),$(COBJS) $(SOBJS))
+START	:= $(addprefix $(obj),$(START))
+
+all:	$(obj).depend $(LIB)
+
+$(LIB):	$(OBJS)
+	$(AR) $(ARFLAGS) $@ $(OBJS)
+
+#########################################################################
+
+# defines $(obj).depend target
+include $(SRCTREE)/rules.mk
+
+sinclude $(obj).depend
+
+#########################################################################
diff --git a/arch/arm/cpu/arm1176/tnetv107x/aemif.c b/arch/arm/cpu/arm1176/tnetv107x/aemif.c
new file mode 100644
index 0000000..172f583
--- /dev/null
+++ b/arch/arm/cpu/arm1176/tnetv107x/aemif.c
@@ -0,0 +1,93 @@
+/*
+ * TNETV107X: Asynchronous EMIF Configuration
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <asm/arch/clock.h>
+#include <asm/arch/mux.h>
+
+#define ASYNC_EMIF_BASE			TNETV107X_ASYNC_EMIF_CNTRL_BASE
+#define ASYNC_EMIF_CONFIG(cs)		(ASYNC_EMIF_BASE+0x10+(cs)*4)
+#define ASYNC_EMIF_ONENAND_CONTROL	(ASYNC_EMIF_BASE+0x5c)
+#define ASYNC_EMIF_NAND_CONTROL		(ASYNC_EMIF_BASE+0x60)
+#define ASYNC_EMIF_WAITCYCLE_CONFIG	(ASYNC_EMIF_BASE+0x4)
+
+#define CONFIG_SELECT_STROBE(v)		((v) ? 1 << 31 : 0)
+#define CONFIG_EXTEND_WAIT(v)		((v) ? 1 << 30 : 0)
+#define CONFIG_WR_SETUP(v)		(((v) & 0x0f) << 26)
+#define CONFIG_WR_STROBE(v)		(((v) & 0x3f) << 20)
+#define CONFIG_WR_HOLD(v)		(((v) & 0x07) << 17)
+#define CONFIG_RD_SETUP(v)		(((v) & 0x0f) << 13)
+#define CONFIG_RD_STROBE(v)		(((v) & 0x3f) << 7)
+#define CONFIG_RD_HOLD(v)		(((v) & 0x07) << 4)
+#define CONFIG_TURN_AROUND(v)		(((v) & 0x03) << 2)
+#define CONFIG_WIDTH(v)			(((v) & 0x03) << 0)
+
+#define NUM_CS				4
+
+#define set_config_field(reg, field, val)			\
+	do {							\
+		if (val != -1) {				\
+			reg &= ~CONFIG_##field(0xffffffff);	\
+			reg |=	CONFIG_##field(val);		\
+		}						\
+	} while (0)
+
+void configure_async_emif(int cs, struct async_emif_config *cfg)
+{
+	unsigned long tmp;
+
+	if (cfg->mode == ASYNC_EMIF_MODE_NAND) {
+		tmp = __raw_readl(ASYNC_EMIF_NAND_CONTROL);
+		tmp |= (1 << cs);
+		__raw_writel(tmp, ASYNC_EMIF_NAND_CONTROL);
+
+	} else if (cfg->mode == ASYNC_EMIF_MODE_ONENAND) {
+		tmp = __raw_readl(ASYNC_EMIF_ONENAND_CONTROL);
+		tmp |= (1 << cs);
+		__raw_writel(tmp, ASYNC_EMIF_ONENAND_CONTROL);
+	}
+
+	tmp = __raw_readl(ASYNC_EMIF_CONFIG(cs));
+
+	set_config_field(tmp, SELECT_STROBE,	cfg->select_strobe);
+	set_config_field(tmp, EXTEND_WAIT,	cfg->extend_wait);
+	set_config_field(tmp, WR_SETUP,		cfg->wr_setup);
+	set_config_field(tmp, WR_STROBE,	cfg->wr_strobe);
+	set_config_field(tmp, WR_HOLD,		cfg->wr_hold);
+	set_config_field(tmp, RD_SETUP,		cfg->rd_setup);
+	set_config_field(tmp, RD_STROBE,	cfg->rd_strobe);
+	set_config_field(tmp, RD_HOLD,		cfg->rd_hold);
+	set_config_field(tmp, TURN_AROUND,	cfg->turn_around);
+	set_config_field(tmp, WIDTH,		cfg->width);
+
+	__raw_writel(tmp, ASYNC_EMIF_CONFIG(cs));
+}
+
+void init_async_emif(int num_cs, struct async_emif_config *config)
+{
+	int cs;
+
+	clk_enable(TNETV107X_LPSC_AEMIF);
+
+	for (cs = 0; cs < num_cs; cs++)
+		configure_async_emif(cs, config + cs);
+}
diff --git a/arch/arm/cpu/arm1176/tnetv107x/clock.c b/arch/arm/cpu/arm1176/tnetv107x/clock.c
new file mode 100644
index 0000000..e26fec1
--- /dev/null
+++ b/arch/arm/cpu/arm1176/tnetv107x/clock.c
@@ -0,0 +1,451 @@
+/*
+ * TNETV107X: Clock management APIs
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <common.h>
+#include <asm-generic/errno.h>
+#include <asm/io.h>
+#include <asm/processor.h>
+#include <asm/arch/clock.h>
+
+#define CLOCK_BASE		TNETV107X_CLOCK_CONTROL_BASE
+#define PSC_BASE		TNETV107X_PSC_BASE
+
+#define BIT(x)			(1 << (x))
+
+#define MAX_PREDIV		64
+#define MAX_POSTDIV		8
+#define MAX_MULT		512
+#define MAX_DIV			(MAX_PREDIV * MAX_POSTDIV)
+
+/* LPSC registers */
+#define PSC_PTCMD		0x120
+#define PSC_PTSTAT		0x128
+#define PSC_MDSTAT(n)		(0x800 + (n) * 4)
+#define PSC_MDCTL(n)		(0xA00 + (n) * 4)
+
+#define PSC_MDCTL_LRSTZ		BIT(8)
+
+#define psc_reg_read(reg)	__raw_readl((u32 *)(PSC_BASE + (reg)))
+#define psc_reg_write(reg, val)	__raw_writel(val, (u32 *)(PSC_BASE + (reg)))
+
+/* SSPLL registers */
+struct sspll_regs {
+	u32	modes;
+	u32	postdiv;
+	u32	prediv;
+	u32	mult_factor;
+	u32	divider_range;
+	u32	bw_divider;
+	u32	spr_amount;
+	u32	spr_rate_div;
+	u32	diag;
+};
+
+/* SSPLL base addresses */
+static struct sspll_regs *sspll_regs[] = {
+	(struct sspll_regs *)(CLOCK_BASE + 0x040),
+	(struct sspll_regs *)(CLOCK_BASE + 0x080),
+	(struct sspll_regs *)(CLOCK_BASE + 0x0c0),
+};
+
+#define sspll_reg(pll, reg)		(&(sspll_regs[pll]->reg))
+#define sspll_reg_read(pll, reg)	__raw_readl(sspll_reg(pll, reg))
+#define sspll_reg_write(pll, reg, val)	__raw_writel(val, sspll_reg(pll, reg))
+
+
+/* PLL Control Registers */
+struct pllctl_regs {
+	u32	ctl;		/* 00 */
+	u32	ocsel;		/* 04 */
+	u32	secctl;		/* 08 */
+	u32	__pad0;
+	u32	mult;		/* 10 */
+	u32	prediv;		/* 14 */
+	u32	div1;		/* 18 */
+	u32	div2;		/* 1c */
+	u32	div3;		/* 20 */
+	u32	oscdiv1;	/* 24 */
+	u32	postdiv;	/* 28 */
+	u32	bpdiv;		/* 2c */
+	u32	wakeup;		/* 30 */
+	u32	__pad1;
+	u32	cmd;		/* 38 */
+	u32	stat;		/* 3c */
+	u32	alnctl;		/* 40 */
+	u32	dchange;	/* 44 */
+	u32	cken;		/* 48 */
+	u32	ckstat;		/* 4c */
+	u32	systat;		/* 50 */
+	u32	ckctl;		/* 54 */
+	u32	__pad2[2];
+	u32	div4;		/* 60 */
+	u32	div5;		/* 64 */
+	u32	div6;		/* 68 */
+	u32	div7;		/* 6c */
+	u32	div8;		/* 70 */
+};
+
+struct lpsc_map {
+	int	pll, div;
+};
+
+static struct pllctl_regs *pllctl_regs[] = {
+	(struct pllctl_regs *)(CLOCK_BASE + 0x700),
+	(struct pllctl_regs *)(CLOCK_BASE + 0x300),
+	(struct pllctl_regs *)(CLOCK_BASE + 0x500),
+};
+
+#define pllctl_reg(pll, reg)		(&(pllctl_regs[pll]->reg))
+#define pllctl_reg_read(pll, reg)	__raw_readl(pllctl_reg(pll, reg))
+#define pllctl_reg_write(pll, reg, val)	__raw_writel(val, pllctl_reg(pll, reg))
+
+#define pllctl_reg_rmw(pll, reg, mask, val)			\
+	pllctl_reg_write(pll, reg,				\
+		(pllctl_reg_read(pll, reg) & ~(mask)) | val)
+
+#define pllctl_reg_setbits(pll, reg, mask)			\
+	pllctl_reg_rmw(pll, reg, 0, mask)
+
+#define pllctl_reg_clrbits(pll, reg, mask)			\
+	pllctl_reg_rmw(pll, reg, mask, 0)
+
+/* PLLCTL Bits */
+#define PLLCTL_CLKMODE		BIT(8)
+#define PLLCTL_PLLSELB		BIT(7)
+#define PLLCTL_PLLENSRC		BIT(5)
+#define PLLCTL_PLLDIS		BIT(4)
+#define PLLCTL_PLLRST		BIT(3)
+#define PLLCTL_PLLPWRDN		BIT(1)
+#define PLLCTL_PLLEN		BIT(0)
+
+#define PLLDIV_ENABLE		BIT(15)
+
+static int pll_div_offset[] = {
+#define div_offset(reg)	offsetof(struct pllctl_regs, reg)
+	div_offset(div1), div_offset(div2), div_offset(div3),
+	div_offset(div4), div_offset(div5), div_offset(div6),
+	div_offset(div7), div_offset(div8),
+};
+
+static unsigned long pll_bypass_mask[] = { 1, 4, 2 };
+static unsigned long pll_div_mask[] = { 0x01ff, 0x00ff, 0x00ff };
+
+/* Mappings from PLL+DIV to subsystem clocks */
+#define sys_arm1176_clk		{SYS_PLL, 0}
+#define sys_dsp_clk		{SYS_PLL, 1}
+#define sys_ddr_clk		{SYS_PLL, 2}
+#define sys_full_clk		{SYS_PLL, 3}
+#define sys_lcd_clk		{SYS_PLL, 4}
+#define sys_vlynq_ref_clk	{SYS_PLL, 5}
+#define sys_tsc_clk		{SYS_PLL, 6}
+#define sys_half_clk		{SYS_PLL, 7}
+
+#define eth_clk_5		{ETH_PLL, 0}
+#define eth_clk_50		{ETH_PLL, 1}
+#define eth_clk_125		{ETH_PLL, 2}
+#define eth_clk_250		{ETH_PLL, 3}
+#define eth_clk_25		{ETH_PLL, 4}
+
+#define tdm_clk			{TDM_PLL, 0}
+#define tdm_extra_clk		{TDM_PLL, 1}
+#define tdm1_clk		{TDM_PLL, 2}
+
+/* Optimization barrier */
+#define barrier()	\
+	__asm__ __volatile__("mov r0, r0\n" : : : "memory");
+
+static const struct lpsc_map lpsc_clk_map[] = {
+	[TNETV107X_LPSC_ARM]			= sys_arm1176_clk,
+	[TNETV107X_LPSC_GEM]			= sys_dsp_clk,
+	[TNETV107X_LPSC_DDR2_PHY]		= sys_ddr_clk,
+	[TNETV107X_LPSC_TPCC]			= sys_full_clk,
+	[TNETV107X_LPSC_TPTC0]			= sys_full_clk,
+	[TNETV107X_LPSC_TPTC1]			= sys_full_clk,
+	[TNETV107X_LPSC_RAM]			= sys_full_clk,
+	[TNETV107X_LPSC_MBX_LITE]		= sys_arm1176_clk,
+	[TNETV107X_LPSC_LCD]			= sys_lcd_clk,
+	[TNETV107X_LPSC_ETHSS]			= eth_clk_125,
+	[TNETV107X_LPSC_AEMIF]			= sys_full_clk,
+	[TNETV107X_LPSC_CHIP_CFG]		= sys_half_clk,
+	[TNETV107X_LPSC_TSC]			= sys_tsc_clk,
+	[TNETV107X_LPSC_ROM]			= sys_half_clk,
+	[TNETV107X_LPSC_UART2]			= sys_half_clk,
+	[TNETV107X_LPSC_PKTSEC]			= sys_half_clk,
+	[TNETV107X_LPSC_SECCTL]			= sys_half_clk,
+	[TNETV107X_LPSC_KEYMGR]			= sys_half_clk,
+	[TNETV107X_LPSC_KEYPAD]			= sys_half_clk,
+	[TNETV107X_LPSC_GPIO]			= sys_half_clk,
+	[TNETV107X_LPSC_MDIO]			= sys_half_clk,
+	[TNETV107X_LPSC_SDIO0]			= sys_half_clk,
+	[TNETV107X_LPSC_UART0]			= sys_half_clk,
+	[TNETV107X_LPSC_UART1]			= sys_half_clk,
+	[TNETV107X_LPSC_TIMER0]			= sys_half_clk,
+	[TNETV107X_LPSC_TIMER1]			= sys_half_clk,
+	[TNETV107X_LPSC_WDT_ARM]		= sys_half_clk,
+	[TNETV107X_LPSC_WDT_DSP]		= sys_half_clk,
+	[TNETV107X_LPSC_SSP]			= sys_half_clk,
+	[TNETV107X_LPSC_TDM0]			= tdm_clk,
+	[TNETV107X_LPSC_VLYNQ]			= sys_vlynq_ref_clk,
+	[TNETV107X_LPSC_MCDMA]			= sys_half_clk,
+	[TNETV107X_LPSC_USB0]			= sys_half_clk,
+	[TNETV107X_LPSC_TDM1]			= tdm1_clk,
+	[TNETV107X_LPSC_DEBUGSS]		= sys_half_clk,
+	[TNETV107X_LPSC_ETHSS_RGMII]		= eth_clk_250,
+	[TNETV107X_LPSC_SYSTEM]			= sys_half_clk,
+	[TNETV107X_LPSC_IMCOP]			= sys_dsp_clk,
+	[TNETV107X_LPSC_SPARE]			= sys_half_clk,
+	[TNETV107X_LPSC_SDIO1]			= sys_half_clk,
+	[TNETV107X_LPSC_USB1]			= sys_half_clk,
+	[TNETV107X_LPSC_USBSS]			= sys_half_clk,
+	[TNETV107X_LPSC_DDR2_EMIF1_VRST]	= sys_ddr_clk,
+	[TNETV107X_LPSC_DDR2_EMIF2_VCTL_RST]	= sys_ddr_clk,
+};
+
+static const unsigned long pll_ext_freq[] = {
+	[SYS_PLL] = CONFIG_PLL_SYS_EXT_FREQ,
+	[ETH_PLL] = CONFIG_PLL_ETH_EXT_FREQ,
+	[TDM_PLL] = CONFIG_PLL_TDM_EXT_FREQ,
+};
+
+static unsigned long pll_freq_get(int pll)
+{
+	unsigned long mult = 1, prediv = 1, postdiv = 1;
+	unsigned long ref = CONFIG_SYS_INT_OSC_FREQ;
+	unsigned long ret;
+	u32 bypass;
+
+	bypass = __raw_readl((u32 *)(CLOCK_BASE));
+	if (!(bypass & pll_bypass_mask[pll])) {
+		mult	= sspll_reg_read(pll, mult_factor);
+		prediv	= sspll_reg_read(pll, prediv) + 1;
+		postdiv	= sspll_reg_read(pll, postdiv) + 1;
+	}
+
+	if (pllctl_reg_read(pll, ctl) & PLLCTL_CLKMODE)
+		ref = pll_ext_freq[pll];
+
+	if (!(pllctl_reg_read(pll, ctl) & PLLCTL_PLLEN))
+		return ref;
+
+	ret = (unsigned long)(ref + ((unsigned long long)ref * mult) / 256);
+	ret /= (prediv * postdiv);
+
+	return ret;
+}
+
+static unsigned long __pll_div_freq_get(int pll, unsigned int fpll,
+					int div)
+{
+	int divider = 1;
+	unsigned long divreg;
+
+	divreg = __raw_readl((void *)pllctl_regs[pll] + pll_div_offset[div]);
+
+	if (divreg & PLLDIV_ENABLE)
+		divider = (divreg & pll_div_mask[pll]) + 1;
+
+	return fpll / divider;
+}
+
+static unsigned long pll_div_freq_get(int pll, int div)
+{
+	unsigned int fpll = pll_freq_get(pll);
+
+	return __pll_div_freq_get(pll, fpll, div);
+}
+
+static void __pll_div_freq_set(int pll, unsigned int fpll, int div,
+			       unsigned long hz)
+{
+	int divider = (fpll / hz - 1);
+
+	divider &= pll_div_mask[pll];
+	divider |= PLLDIV_ENABLE;
+
+	__raw_writel(divider, (void *)pllctl_regs[pll] + pll_div_offset[div]);
+	pllctl_reg_setbits(pll, alnctl, (1 << div));
+	pllctl_reg_setbits(pll, dchange, (1 << div));
+}
+
+static unsigned long pll_div_freq_set(int pll, int div, unsigned long hz)
+{
+	unsigned int fpll = pll_freq_get(pll);
+
+	__pll_div_freq_set(pll, fpll, div, hz);
+
+	pllctl_reg_write(pll, cmd, 1);
+
+	/* Wait until new divider takes effect */
+	while (pllctl_reg_read(pll, stat) & 0x01);
+
+	return __pll_div_freq_get(pll, fpll, div);
+}
+
+unsigned long clk_get_rate(unsigned int clk)
+{
+	return pll_div_freq_get(lpsc_clk_map[clk].pll, lpsc_clk_map[clk].div);
+}
+
+unsigned long clk_round_rate(unsigned int clk, unsigned long hz)
+{
+	unsigned long fpll, divider, pll;
+
+	pll = lpsc_clk_map[clk].pll;
+	fpll = pll_freq_get(pll);
+	divider = (fpll / hz - 1);
+	divider &= pll_div_mask[pll];
+
+	return fpll / (divider + 1);
+}
+
+int clk_set_rate(unsigned int clk, unsigned long _hz)
+{
+	unsigned long hz;
+
+	hz = clk_round_rate(clk, _hz);
+	if (hz != _hz)
+		return -EINVAL;	/* Cannot set to target freq */
+
+	pll_div_freq_set(lpsc_clk_map[clk].pll, lpsc_clk_map[clk].div, hz);
+	return 0;
+}
+
+void lpsc_control(int mod, unsigned long state, int lrstz)
+{
+	u32 mdctl;
+
+	mdctl = psc_reg_read(PSC_MDCTL(mod));
+	mdctl &= ~0x1f;
+	mdctl |= state;
+
+	if (lrstz == 0)
+		mdctl &= ~PSC_MDCTL_LRSTZ;
+	else if (lrstz == 1)
+		mdctl |= PSC_MDCTL_LRSTZ;
+
+	psc_reg_write(PSC_MDCTL(mod), mdctl);
+
+	psc_reg_write(PSC_PTCMD, 1);
+
+	/* wait for power domain transition to end */
+	while (psc_reg_read(PSC_PTSTAT) & 1);
+
+	/* Wait for module state change */
+	while ((psc_reg_read(PSC_MDSTAT(mod)) & 0x1f) != state);
+}
+
+int lpsc_status(unsigned int id)
+{
+	return psc_reg_read(PSC_MDSTAT(id)) & 0x1f;
+}
+
+static void init_pll(const struct pll_init_data *data)
+{
+	unsigned long fpll;
+	unsigned long best_pre = 0, best_post = 0, best_mult = 0;
+	unsigned long div, prediv, postdiv, mult;
+	unsigned long delta, actual;
+	long best_delta = -1;
+	int i;
+	u32 tmp;
+
+	if (data->pll == SYS_PLL)
+		return; /* cannot reconfigure system pll on the fly */
+
+	tmp = pllctl_reg_read(data->pll, ctl);
+	if (data->internal_osc) {
+		tmp &= ~PLLCTL_CLKMODE;
+		fpll = CONFIG_SYS_INT_OSC_FREQ;
+	} else {
+		tmp |= PLLCTL_CLKMODE;
+		fpll = pll_ext_freq[data->pll];
+	}
+	pllctl_reg_write(data->pll, ctl, tmp);
+
+	mult = data->pll_freq / fpll;
+	for (mult = MAX(mult, 1); mult <= MAX_MULT; mult++) {
+		div = (fpll * mult) / data->pll_freq;
+		if (div < 1 || div > MAX_DIV)
+			continue;
+
+		for (postdiv = 1; postdiv <= min(div, MAX_POSTDIV); postdiv++) {
+			prediv = div / postdiv;
+			if (prediv < 1 || prediv > MAX_PREDIV)
+				continue;
+
+			actual = (fpll / prediv) * (mult / postdiv);
+			delta = (actual - data->pll_freq);
+			if (delta < 0)
+				delta = -delta;
+			if ((delta < best_delta) || (best_delta == -1)) {
+				best_delta = delta;
+				best_mult = mult;
+				best_pre = prediv;
+				best_post = postdiv;
+				if (delta == 0)
+					goto done;
+			}
+		}
+	}
+done:
+
+	if (best_delta == -1) {
+		printf("pll cannot derive %lu from %lu\n",
+				data->pll_freq, fpll);
+		return;
+	}
+
+	fpll = fpll * best_mult;
+	fpll /= best_pre * best_post;
+
+	pllctl_reg_clrbits(data->pll, ctl, PLLCTL_PLLENSRC);
+	pllctl_reg_clrbits(data->pll, ctl, PLLCTL_PLLEN);
+
+	pllctl_reg_setbits(data->pll, ctl, PLLCTL_PLLRST);
+
+	pllctl_reg_clrbits(data->pll, ctl, PLLCTL_PLLPWRDN);
+	pllctl_reg_clrbits(data->pll, ctl, PLLCTL_PLLDIS);
+
+	sspll_reg_write(data->pll, mult_factor,	(best_mult - 1) << 8);
+	sspll_reg_write(data->pll, prediv,	best_pre - 1);
+	sspll_reg_write(data->pll, postdiv,	best_post - 1);
+
+	for (i = 0; i < 10; i++)
+		if (data->div_freq[i])
+			__pll_div_freq_set(data->pll, fpll, i,
+					   data->div_freq[i]);
+
+	pllctl_reg_write(data->pll, cmd, 1);
+
+	/* Wait until pll "go" operation completes */
+	while (pllctl_reg_read(data->pll, stat) & 0x01);
+
+	pllctl_reg_clrbits(data->pll, ctl, PLLCTL_PLLRST);
+	pllctl_reg_setbits(data->pll, ctl, PLLCTL_PLLEN);
+}
+
+void init_plls(int num_pll, struct pll_init_data *config)
+{
+	int i;
+
+	for (i = 0; i < num_pll; i++)
+		init_pll(&config[i]);
+}
diff --git a/arch/arm/cpu/arm1176/tnetv107x/init.c b/arch/arm/cpu/arm1176/tnetv107x/init.c
new file mode 100644
index 0000000..ce3a025
--- /dev/null
+++ b/arch/arm/cpu/arm1176/tnetv107x/init.c
@@ -0,0 +1,37 @@
+/*
+ * TNETV107X: Architecture initialization
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <common.h>
+#include <asm/io.h>
+
+void chip_configuration_unlock(void)
+{
+       __raw_writel(TNETV107X_KICK0_MAGIC, TNETV107X_KICK0);
+       __raw_writel(TNETV107X_KICK1_MAGIC, TNETV107X_KICK1);
+}
+
+int arch_cpu_init(void)
+{
+       icache_enable();
+       chip_configuration_unlock();
+
+       return 0;
+}
diff --git a/arch/arm/cpu/arm1176/tnetv107x/lowlevel_init.S b/arch/arm/cpu/arm1176/tnetv107x/lowlevel_init.S
new file mode 100644
index 0000000..3ee32ef
--- /dev/null
+++ b/arch/arm/cpu/arm1176/tnetv107x/lowlevel_init.S
@@ -0,0 +1,25 @@
+/*
+ * TNETV107X: Low-level pre-relocation initialization
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+.globl lowlevel_init
+lowlevel_init:
+	/* nothing for now, maybe needed for more exotic boot modes */
+	mov	pc, lr
diff --git a/arch/arm/cpu/arm1176/tnetv107x/mux.c b/arch/arm/cpu/arm1176/tnetv107x/mux.c
new file mode 100644
index 0000000..ccc5314
--- /dev/null
+++ b/arch/arm/cpu/arm1176/tnetv107x/mux.c
@@ -0,0 +1,334 @@
+/*
+ * TNETV107X: Pinmux configuration
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <asm/arch/clock.h>
+#include <asm/arch/mux.h>
+
+#define MUX_MODE_1		0x00
+#define MUX_MODE_2		0x04
+#define MUX_MODE_3		0x0c
+#define MUX_MODE_4		0x1c
+
+#define MUX_DEBUG		0
+
+static const struct pin_config pin_table[] = {
+	/*		  reg	shift	mode	*/
+	TNETV107X_MUX_CFG(0,	0,	MUX_MODE_1),
+	TNETV107X_MUX_CFG(0,	0,	MUX_MODE_2),
+	TNETV107X_MUX_CFG(0,	5,	MUX_MODE_1),
+	TNETV107X_MUX_CFG(0,	5,	MUX_MODE_2),
+	TNETV107X_MUX_CFG(0,	10,	MUX_MODE_1),
+	TNETV107X_MUX_CFG(0,	10,	MUX_MODE_2),
+	TNETV107X_MUX_CFG(0,	15,	MUX_MODE_1),
+	TNETV107X_MUX_CFG(0,	15,	MUX_MODE_2),
+	TNETV107X_MUX_CFG(0,	20,	MUX_MODE_1),
+	TNETV107X_MUX_CFG(0,	20,	MUX_MODE_2),
+	TNETV107X_MUX_CFG(0,	25,	MUX_MODE_1),
+	TNETV107X_MUX_CFG(0,	25,	MUX_MODE_2),
+	TNETV107X_MUX_CFG(1,	0,	MUX_MODE_1),
+	TNETV107X_MUX_CFG(1,	0,	MUX_MODE_2),
+	TNETV107X_MUX_CFG(1,	5,	MUX_MODE_1),
+	TNETV107X_MUX_CFG(1,	5,	MUX_MODE_2),
+	TNETV107X_MUX_CFG(1,	10,	MUX_MODE_1),
+	TNETV107X_MUX_CFG(1,	10,	MUX_MODE_2),
+	TNETV107X_MUX_CFG(1,	15,	MUX_MODE_1),
+	TNETV107X_MUX_CFG(1,	15,	MUX_MODE_2),
+	TNETV107X_MUX_CFG(1,	20,	MUX_MODE_1),
+	TNETV107X_MUX_CFG(1,	20,	MUX_MODE_2),
+	TNETV107X_MUX_CFG(1,	25,	MUX_MODE_1),
+	TNETV107X_MUX_CFG(1,	25,	MUX_MODE_2),
+	TNETV107X_MUX_CFG(2,	0,	MUX_MODE_1),
+	TNETV107X_MUX_CFG(2,	0,	MUX_MODE_2),
+	TNETV107X_MUX_CFG(2,	5,	MUX_MODE_1),
+	TNETV107X_MUX_CFG(2,	5,	MUX_MODE_2),
+	TNETV107X_MUX_CFG(2,	10,	MUX_MODE_1),
+	TNETV107X_MUX_CFG(2,	10,	MUX_MODE_2),
+	TNETV107X_MUX_CFG(2,	15,	MUX_MODE_1),
+	TNETV107X_MUX_CFG(2,	15,	MUX_MODE_2),
+	TNETV107X_MUX_CFG(2,	20,	MUX_MODE_1),
+	TNETV107X_MUX_CFG(2,	20,	MUX_MODE_2),
+	TNETV107X_MUX_CFG(2,	25,	MUX_MODE_1),
+	TNETV107X_MUX_CFG(2,	25,	MUX_MODE_2),
+	TNETV107X_MUX_CFG(3,	0,	MUX_MODE_1),
+	TNETV107X_MUX_CFG(3,	0,	MUX_MODE_2),
+	TNETV107X_MUX_CFG(3,	0,	MUX_MODE_4),
+	TNETV107X_MUX_CFG(3,	5,	MUX_MODE_1),
+	TNETV107X_MUX_CFG(3,	5,	MUX_MODE_2),
+	TNETV107X_MUX_CFG(3,	5,	MUX_MODE_4),
+	TNETV107X_MUX_CFG(3,	10,	MUX_MODE_1),
+	TNETV107X_MUX_CFG(3,	10,	MUX_MODE_2),
+	TNETV107X_MUX_CFG(3,	10,	MUX_MODE_4),
+	TNETV107X_MUX_CFG(3,	15,	MUX_MODE_1),
+	TNETV107X_MUX_CFG(3,	15,	MUX_MODE_2),
+	TNETV107X_MUX_CFG(3,	15,	MUX_MODE_4),
+	TNETV107X_MUX_CFG(3,	20,	MUX_MODE_1),
+	TNETV107X_MUX_CFG(3,	20,	MUX_MODE_2),
+	TNETV107X_MUX_CFG(3,	20,	MUX_MODE_4),
+	TNETV107X_MUX_CFG(3,	25,	MUX_MODE_1),
+	TNETV107X_MUX_CFG(3,	25,	MUX_MODE_2),
+	TNETV107X_MUX_CFG(3,	25,	MUX_MODE_4),
+	TNETV107X_MUX_CFG(4,	0,	MUX_MODE_1),
+	TNETV107X_MUX_CFG(4,	0,	MUX_MODE_2),
+	TNETV107X_MUX_CFG(4,	0,	MUX_MODE_4),
+	TNETV107X_MUX_CFG(4,	5,	MUX_MODE_1),
+	TNETV107X_MUX_CFG(4,	10,	MUX_MODE_1),
+	TNETV107X_MUX_CFG(4,	15,	MUX_MODE_1),
+	TNETV107X_MUX_CFG(4,	15,	MUX_MODE_4),
+	TNETV107X_MUX_CFG(4,	20,	MUX_MODE_1),
+	TNETV107X_MUX_CFG(4,	20,	MUX_MODE_3),
+	TNETV107X_MUX_CFG(4,	25,	MUX_MODE_1),
+	TNETV107X_MUX_CFG(4,	25,	MUX_MODE_4),
+	TNETV107X_MUX_CFG(5,	0,	MUX_MODE_1),
+	TNETV107X_MUX_CFG(5,	0,	MUX_MODE_4),
+	TNETV107X_MUX_CFG(5,	5,	MUX_MODE_1),
+	TNETV107X_MUX_CFG(5,	5,	MUX_MODE_4),
+	TNETV107X_MUX_CFG(5,	10,	MUX_MODE_1),
+	TNETV107X_MUX_CFG(5,	10,	MUX_MODE_4),
+	TNETV107X_MUX_CFG(5,	15,	MUX_MODE_1),
+	TNETV107X_MUX_CFG(5,	15,	MUX_MODE_4),
+	TNETV107X_MUX_CFG(5,	20,	MUX_MODE_1),
+	TNETV107X_MUX_CFG(5,	20,	MUX_MODE_4),
+	TNETV107X_MUX_CFG(5,	25,	MUX_MODE_1),
+	TNETV107X_MUX_CFG(5,	25,	MUX_MODE_4),
+	TNETV107X_MUX_CFG(6,	0,	MUX_MODE_1),
+	TNETV107X_MUX_CFG(6,	0,	MUX_MODE_4),
+	TNETV107X_MUX_CFG(6,	5,	MUX_MODE_1),
+	TNETV107X_MUX_CFG(6,	5,	MUX_MODE_4),
+	TNETV107X_MUX_CFG(6,	10,	MUX_MODE_1),
+	TNETV107X_MUX_CFG(6,	10,	MUX_MODE_4),
+	TNETV107X_MUX_CFG(6,	15,	MUX_MODE_1),
+	TNETV107X_MUX_CFG(6,	15,	MUX_MODE_4),
+	TNETV107X_MUX_CFG(6,	20,	MUX_MODE_1),
+	TNETV107X_MUX_CFG(6,	20,	MUX_MODE_4),
+	TNETV107X_MUX_CFG(6,	25,	MUX_MODE_1),
+	TNETV107X_MUX_CFG(6,	25,	MUX_MODE_4),
+	TNETV107X_MUX_CFG(7,	0,	MUX_MODE_1),
+	TNETV107X_MUX_CFG(7,	0,	MUX_MODE_4),
+	TNETV107X_MUX_CFG(7,	5,	MUX_MODE_1),
+	TNETV107X_MUX_CFG(7,	5,	MUX_MODE_4),
+	TNETV107X_MUX_CFG(7,	10,	MUX_MODE_1),
+	TNETV107X_MUX_CFG(7,	10,	MUX_MODE_4),
+	TNETV107X_MUX_CFG(7,	15,	MUX_MODE_1),
+	TNETV107X_MUX_CFG(7,	15,	MUX_MODE_2),
+	TNETV107X_MUX_CFG(7,	20,	MUX_MODE_1),
+	TNETV107X_MUX_CFG(7,	20,	MUX_MODE_2),
+	TNETV107X_MUX_CFG(7,	25,	MUX_MODE_1),
+	TNETV107X_MUX_CFG(7,	25,	MUX_MODE_2),
+	TNETV107X_MUX_CFG(8,	0,	MUX_MODE_1),
+	TNETV107X_MUX_CFG(8,	0,	MUX_MODE_2),
+	TNETV107X_MUX_CFG(8,	5,	MUX_MODE_1),
+	TNETV107X_MUX_CFG(8,	5,	MUX_MODE_2),
+	TNETV107X_MUX_CFG(8,	5,	MUX_MODE_4),
+	TNETV107X_MUX_CFG(8,	10,	MUX_MODE_1),
+	TNETV107X_MUX_CFG(8,	10,	MUX_MODE_2),
+	TNETV107X_MUX_CFG(9,	0,	MUX_MODE_1),
+	TNETV107X_MUX_CFG(9,	0,	MUX_MODE_2),
+	TNETV107X_MUX_CFG(9,	0,	MUX_MODE_4),
+	TNETV107X_MUX_CFG(9,	5,	MUX_MODE_1),
+	TNETV107X_MUX_CFG(9,	5,	MUX_MODE_2),
+	TNETV107X_MUX_CFG(9,	5,	MUX_MODE_4),
+	TNETV107X_MUX_CFG(9,	10,	MUX_MODE_1),
+	TNETV107X_MUX_CFG(9,	10,	MUX_MODE_2),
+	TNETV107X_MUX_CFG(9,	10,	MUX_MODE_4),
+	TNETV107X_MUX_CFG(9,	15,	MUX_MODE_1),
+	TNETV107X_MUX_CFG(9,	15,	MUX_MODE_2),
+	TNETV107X_MUX_CFG(9,	15,	MUX_MODE_4),
+	TNETV107X_MUX_CFG(9,	20,	MUX_MODE_1),
+	TNETV107X_MUX_CFG(9,	20,	MUX_MODE_2),
+	TNETV107X_MUX_CFG(9,	20,	MUX_MODE_4),
+	TNETV107X_MUX_CFG(10,	0,	MUX_MODE_1),
+	TNETV107X_MUX_CFG(10,	0,	MUX_MODE_2),
+	TNETV107X_MUX_CFG(10,	5,	MUX_MODE_1),
+	TNETV107X_MUX_CFG(10,	5,	MUX_MODE_2),
+	TNETV107X_MUX_CFG(10,	10,	MUX_MODE_1),
+	TNETV107X_MUX_CFG(10,	10,	MUX_MODE_2),
+	TNETV107X_MUX_CFG(10,	15,	MUX_MODE_1),
+	TNETV107X_MUX_CFG(10,	15,	MUX_MODE_2),
+	TNETV107X_MUX_CFG(10,	20,	MUX_MODE_1),
+	TNETV107X_MUX_CFG(10,	20,	MUX_MODE_2),
+	TNETV107X_MUX_CFG(10,	25,	MUX_MODE_1),
+	TNETV107X_MUX_CFG(10,	25,	MUX_MODE_2),
+	TNETV107X_MUX_CFG(11,	0,	MUX_MODE_1),
+	TNETV107X_MUX_CFG(11,	5,	MUX_MODE_1),
+	TNETV107X_MUX_CFG(12,	0,	MUX_MODE_1),
+	TNETV107X_MUX_CFG(12,	5,	MUX_MODE_1),
+	TNETV107X_MUX_CFG(12,	10,	MUX_MODE_1),
+	TNETV107X_MUX_CFG(12,	15,	MUX_MODE_1),
+	TNETV107X_MUX_CFG(12,	20,	MUX_MODE_1),
+	TNETV107X_MUX_CFG(12,	25,	MUX_MODE_1),
+	TNETV107X_MUX_CFG(13,	0,	MUX_MODE_1),
+	TNETV107X_MUX_CFG(13,	5,	MUX_MODE_1),
+	TNETV107X_MUX_CFG(13,	10,	MUX_MODE_1),
+	TNETV107X_MUX_CFG(13,	15,	MUX_MODE_1),
+	TNETV107X_MUX_CFG(14,	0,	MUX_MODE_1),
+	TNETV107X_MUX_CFG(14,	5,	MUX_MODE_1),
+	TNETV107X_MUX_CFG(14,	10,	MUX_MODE_1),
+	TNETV107X_MUX_CFG(14,	15,	MUX_MODE_1),
+	TNETV107X_MUX_CFG(14,	20,	MUX_MODE_1),
+	TNETV107X_MUX_CFG(14,	25,	MUX_MODE_1),
+	TNETV107X_MUX_CFG(15,	0,	MUX_MODE_1),
+	TNETV107X_MUX_CFG(15,	0,	MUX_MODE_2),
+	TNETV107X_MUX_CFG(15,	5,	MUX_MODE_1),
+	TNETV107X_MUX_CFG(15,	5,	MUX_MODE_2),
+	TNETV107X_MUX_CFG(15,	10,	MUX_MODE_1),
+	TNETV107X_MUX_CFG(15,	15,	MUX_MODE_1),
+	TNETV107X_MUX_CFG(15,	20,	MUX_MODE_1),
+	TNETV107X_MUX_CFG(15,	25,	MUX_MODE_1),
+	TNETV107X_MUX_CFG(16,	0,	MUX_MODE_1),
+	TNETV107X_MUX_CFG(16,	5,	MUX_MODE_1),
+	TNETV107X_MUX_CFG(16,	10,	MUX_MODE_1),
+	TNETV107X_MUX_CFG(16,	10,	MUX_MODE_2),
+	TNETV107X_MUX_CFG(16,	10,	MUX_MODE_3),
+	TNETV107X_MUX_CFG(16,	15,	MUX_MODE_1),
+	TNETV107X_MUX_CFG(16,	15,	MUX_MODE_2),
+	TNETV107X_MUX_CFG(17,	0,	MUX_MODE_1),
+	TNETV107X_MUX_CFG(17,	0,	MUX_MODE_2),
+	TNETV107X_MUX_CFG(17,	0,	MUX_MODE_3),
+	TNETV107X_MUX_CFG(17,	5,	MUX_MODE_1),
+	TNETV107X_MUX_CFG(17,	5,	MUX_MODE_2),
+	TNETV107X_MUX_CFG(17,	5,	MUX_MODE_3),
+	TNETV107X_MUX_CFG(17,	10,	MUX_MODE_1),
+	TNETV107X_MUX_CFG(17,	10,	MUX_MODE_2),
+	TNETV107X_MUX_CFG(17,	10,	MUX_MODE_3),
+	TNETV107X_MUX_CFG(17,	15,	MUX_MODE_1),
+	TNETV107X_MUX_CFG(17,	15,	MUX_MODE_2),
+	TNETV107X_MUX_CFG(17,	15,	MUX_MODE_3),
+	TNETV107X_MUX_CFG(18,	0,	MUX_MODE_1),
+	TNETV107X_MUX_CFG(18,	0,	MUX_MODE_2),
+	TNETV107X_MUX_CFG(18,	0,	MUX_MODE_3),
+	TNETV107X_MUX_CFG(18,	5,	MUX_MODE_1),
+	TNETV107X_MUX_CFG(18,	5,	MUX_MODE_2),
+	TNETV107X_MUX_CFG(18,	5,	MUX_MODE_3),
+	TNETV107X_MUX_CFG(18,	10,	MUX_MODE_1),
+	TNETV107X_MUX_CFG(18,	10,	MUX_MODE_2),
+	TNETV107X_MUX_CFG(18,	10,	MUX_MODE_3),
+	TNETV107X_MUX_CFG(18,	15,	MUX_MODE_1),
+	TNETV107X_MUX_CFG(18,	15,	MUX_MODE_2),
+	TNETV107X_MUX_CFG(18,	15,	MUX_MODE_3),
+	TNETV107X_MUX_CFG(19,	0,	MUX_MODE_1),
+	TNETV107X_MUX_CFG(19,	5,	MUX_MODE_1),
+	TNETV107X_MUX_CFG(19,	10,	MUX_MODE_1),
+	TNETV107X_MUX_CFG(19,	15,	MUX_MODE_1),
+	TNETV107X_MUX_CFG(19,	20,	MUX_MODE_1),
+	TNETV107X_MUX_CFG(19,	25,	MUX_MODE_1),
+	TNETV107X_MUX_CFG(20,	0,	MUX_MODE_1),
+	TNETV107X_MUX_CFG(20,	5,	MUX_MODE_1),
+	TNETV107X_MUX_CFG(20,	10,	MUX_MODE_1),
+	TNETV107X_MUX_CFG(20,	15,	MUX_MODE_1),
+	TNETV107X_MUX_CFG(20,	15,	MUX_MODE_3),
+	TNETV107X_MUX_CFG(20,	20,	MUX_MODE_1),
+	TNETV107X_MUX_CFG(20,	25,	MUX_MODE_1),
+	TNETV107X_MUX_CFG(21,	0,	MUX_MODE_1),
+	TNETV107X_MUX_CFG(21,	5,	MUX_MODE_1),
+	TNETV107X_MUX_CFG(21,	10,	MUX_MODE_1),
+	TNETV107X_MUX_CFG(21,	15,	MUX_MODE_1),
+	TNETV107X_MUX_CFG(21,	20,	MUX_MODE_1),
+	TNETV107X_MUX_CFG(21,	25,	MUX_MODE_1),
+	TNETV107X_MUX_CFG(22,	0,	MUX_MODE_1),
+	TNETV107X_MUX_CFG(22,	5,	MUX_MODE_1),
+	TNETV107X_MUX_CFG(22,	5,	MUX_MODE_3),
+	TNETV107X_MUX_CFG(22,	10,	MUX_MODE_1),
+	TNETV107X_MUX_CFG(22,	10,	MUX_MODE_3),
+	TNETV107X_MUX_CFG(22,	15,	MUX_MODE_1),
+	TNETV107X_MUX_CFG(22,	15,	MUX_MODE_2),
+	TNETV107X_MUX_CFG(22,	15,	MUX_MODE_3),
+	TNETV107X_MUX_CFG(22,	20,	MUX_MODE_1),
+	TNETV107X_MUX_CFG(22,	20,	MUX_MODE_3),
+	TNETV107X_MUX_CFG(22,	25,	MUX_MODE_1),
+	TNETV107X_MUX_CFG(22,	25,	MUX_MODE_3),
+	TNETV107X_MUX_CFG(23,	0,	MUX_MODE_1),
+	TNETV107X_MUX_CFG(23,	0,	MUX_MODE_3),
+	TNETV107X_MUX_CFG(23,	5,	MUX_MODE_1),
+	TNETV107X_MUX_CFG(23,	5,	MUX_MODE_3),
+	TNETV107X_MUX_CFG(23,	10,	MUX_MODE_1),
+	TNETV107X_MUX_CFG(23,	10,	MUX_MODE_3),
+	TNETV107X_MUX_CFG(24,	0,	MUX_MODE_1),
+	TNETV107X_MUX_CFG(24,	0,	MUX_MODE_2),
+	TNETV107X_MUX_CFG(24,	5,	MUX_MODE_1),
+	TNETV107X_MUX_CFG(24,	5,	MUX_MODE_2),
+	TNETV107X_MUX_CFG(24,	10,	MUX_MODE_1),
+	TNETV107X_MUX_CFG(24,	10,	MUX_MODE_2),
+	TNETV107X_MUX_CFG(24,	10,	MUX_MODE_3),
+	TNETV107X_MUX_CFG(24,	15,	MUX_MODE_1),
+	TNETV107X_MUX_CFG(24,	15,	MUX_MODE_2),
+	TNETV107X_MUX_CFG(24,	15,	MUX_MODE_3),
+	TNETV107X_MUX_CFG(24,	20,	MUX_MODE_1),
+	TNETV107X_MUX_CFG(24,	20,	MUX_MODE_2),
+	TNETV107X_MUX_CFG(24,	25,	MUX_MODE_1),
+	TNETV107X_MUX_CFG(24,	25,	MUX_MODE_2),
+	TNETV107X_MUX_CFG(25,	0,	MUX_MODE_1),
+	TNETV107X_MUX_CFG(25,	0,	MUX_MODE_2),
+	TNETV107X_MUX_CFG(25,	0,	MUX_MODE_3),
+	TNETV107X_MUX_CFG(25,	5,	MUX_MODE_1),
+	TNETV107X_MUX_CFG(25,	5,	MUX_MODE_2),
+	TNETV107X_MUX_CFG(25,	5,	MUX_MODE_3),
+	TNETV107X_MUX_CFG(25,	10,	MUX_MODE_1),
+	TNETV107X_MUX_CFG(25,	10,	MUX_MODE_2),
+	TNETV107X_MUX_CFG(25,	10,	MUX_MODE_3),
+	TNETV107X_MUX_CFG(25,	15,	MUX_MODE_1),
+	TNETV107X_MUX_CFG(25,	15,	MUX_MODE_2),
+	TNETV107X_MUX_CFG(25,	15,	MUX_MODE_3),
+	TNETV107X_MUX_CFG(25,	15,	MUX_MODE_4),
+	TNETV107X_MUX_CFG(26,	0,	MUX_MODE_1),
+	TNETV107X_MUX_CFG(26,	5,	MUX_MODE_1),
+	TNETV107X_MUX_CFG(26,	10,	MUX_MODE_1),
+	TNETV107X_MUX_CFG(26,	10,	MUX_MODE_2),
+	TNETV107X_MUX_CFG(26,	15,	MUX_MODE_1),
+	TNETV107X_MUX_CFG(26,	15,	MUX_MODE_2),
+	TNETV107X_MUX_CFG(26,	20,	MUX_MODE_1),
+	TNETV107X_MUX_CFG(26,	20,	MUX_MODE_2),
+	TNETV107X_MUX_CFG(26,	25,	MUX_MODE_1),
+	TNETV107X_MUX_CFG(26,	25,	MUX_MODE_2),
+};
+
+const int pin_table_size = sizeof(pin_table) / sizeof(pin_table[0]);
+
+int mux_select_pin(short index)
+{
+	const struct pin_config *cfg;
+	unsigned long mask, mode, reg;
+
+	if (index >= pin_table_size)
+		return 0;
+
+	cfg = &pin_table[index];
+
+	mask = 0x1f << cfg->mask_offset;
+	mode = cfg->mode << cfg->mask_offset;
+
+	reg = __raw_readl(TNETV107X_PINMUX(cfg->reg_index));
+	reg = (reg & ~mask) | mode;
+	__raw_writel(reg, TNETV107X_PINMUX(cfg->reg_index));
+
+	return 1;
+}
+
+int mux_select_pins(const short *pins)
+{
+	int i, ret = 1;
+
+	for (i = 0; pins[i] >= 0; i++)
+		ret &= mux_select_pin(pins[i]);
+
+	return ret;
+}
diff --git a/arch/arm/cpu/arm1176/tnetv107x/timer.c b/arch/arm/cpu/arm1176/tnetv107x/timer.c
new file mode 100644
index 0000000..a7a400d
--- /dev/null
+++ b/arch/arm/cpu/arm1176/tnetv107x/timer.c
@@ -0,0 +1,122 @@
+/*
+ * TNETV107X: Timer implementation
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <asm/arch/clock.h>
+
+struct timer_regs {
+	u_int32_t pid12;
+	u_int32_t pad[3];
+	u_int32_t tim12;
+	u_int32_t tim34;
+	u_int32_t prd12;
+	u_int32_t prd34;
+	u_int32_t tcr;
+	u_int32_t tgcr;
+	u_int32_t wdtcr;
+};
+
+#define regs ((struct timer_regs *)CONFIG_SYS_TIMERBASE)
+
+#define TIMER_LOAD_VAL	(CONFIG_SYS_HZ_CLOCK / CONFIG_SYS_HZ)
+#define TIM_CLK_DIV	16
+
+static ulong timestamp;
+static ulong lastinc;
+
+int timer_init(void)
+{
+	clk_enable(TNETV107X_LPSC_TIMER0);
+
+	lastinc = timestamp = 0;
+
+	/* We are using timer34 in unchained 32-bit mode, full speed */
+	__raw_writel(0x0, &regs->tcr);
+	__raw_writel(0x0, &regs->tgcr);
+	__raw_writel(0x06 | ((TIM_CLK_DIV - 1) << 8), &regs->tgcr);
+	__raw_writel(0x0, &regs->tim34);
+	__raw_writel(TIMER_LOAD_VAL, &regs->prd34);
+	__raw_writel(2 << 22, &regs->tcr);
+
+	return 0;
+}
+
+void reset_timer(void)
+{
+	lastinc = timestamp = 0;
+
+	__raw_writel(0,		&regs->tcr);
+	__raw_writel(0,		&regs->tim34);
+	__raw_writel(2 << 22,	&regs->tcr);
+}
+
+static ulong get_timer_raw(void)
+{
+	ulong now = __raw_readl(&regs->tim34);
+
+	if (now >= lastinc)
+		timestamp += now - lastinc;
+	else
+		timestamp += now + TIMER_LOAD_VAL - lastinc;
+
+	lastinc = now;
+
+	return timestamp;
+}
+
+ulong get_timer(ulong base)
+{
+	return (get_timer_raw() / (TIMER_LOAD_VAL / TIM_CLK_DIV)) - base;
+}
+
+void set_timer(ulong t)
+{
+	timestamp = t;
+}
+
+unsigned long long get_ticks(void)
+{
+	return get_timer(0);
+}
+
+void __udelay(unsigned long usec)
+{
+	ulong tmo;
+	ulong endtime;
+	signed long diff;
+
+	tmo = CONFIG_SYS_HZ_CLOCK / 1000;
+	tmo *= usec;
+	tmo /= (1000 * TIM_CLK_DIV);
+
+	endtime = get_timer_raw() + tmo;
+
+	do {
+		ulong now = get_timer_raw();
+		diff = endtime - now;
+	} while (diff >= 0);
+}
+
+ulong get_tbclk(void)
+{
+	return CONFIG_SYS_HZ;
+}
diff --git a/arch/arm/cpu/arm1176/tnetv107x/wdt.c b/arch/arm/cpu/arm1176/tnetv107x/wdt.c
new file mode 100644
index 0000000..18aadb0
--- /dev/null
+++ b/arch/arm/cpu/arm1176/tnetv107x/wdt.c
@@ -0,0 +1,180 @@
+/*
+ * TNETV107X: Watchdog timer implementation (for reset)
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <asm/arch/clock.h>
+
+#define MAX_DIV		0xFFFE0001
+
+struct wdt_regs {
+	u32 kick_lock;
+#define KICK_LOCK_1	0x5555
+#define KICK_LOCK_2	0xaaaa
+	u32 kick;
+
+	u32 change_lock;
+#define CHANGE_LOCK_1	0x6666
+#define CHANGE_LOCK_2	0xbbbb
+	u32 change;
+
+	u32 disable_lock;
+#define DISABLE_LOCK_1	0x7777
+#define DISABLE_LOCK_2	0xcccc
+#define DISABLE_LOCK_3	0xdddd
+	u32 disable;
+
+	u32 prescale_lock;
+#define PRESCALE_LOCK_1	0x5a5a
+#define PRESCALE_LOCK_2	0xa5a5
+	u32 prescale;
+};
+
+static struct wdt_regs* regs = (struct wdt_regs *)TNETV107X_WDT0_ARM_BASE;
+
+#define wdt_reg_read(reg)	__raw_readl(&regs->reg)
+#define wdt_reg_write(reg, val)	__raw_writel((val), &regs->reg)
+
+static int write_prescale_reg(unsigned long prescale_value)
+{
+	wdt_reg_write(prescale_lock, PRESCALE_LOCK_1);
+	if ((wdt_reg_read(prescale_lock) & 0x3) != 0x1)
+		return -1;
+
+	wdt_reg_write(prescale_lock, PRESCALE_LOCK_2);
+	if ((wdt_reg_read(prescale_lock) & 0x3) != 0x3)
+		return -1;
+
+	wdt_reg_write(prescale, prescale_value);
+
+	return 0;
+}
+
+static int write_change_reg(unsigned long initial_timer_value)
+{
+	wdt_reg_write(change_lock, CHANGE_LOCK_1);
+	if ((wdt_reg_read(change_lock) & 0x3) != 0x1)
+		return -1;
+
+	wdt_reg_write(change_lock, CHANGE_LOCK_2);
+	if ((wdt_reg_read(change_lock) & 0x3) != 0x3)
+		return -1;
+
+	wdt_reg_write(change, initial_timer_value);
+
+	return 0;
+}
+
+static int wdt_control(unsigned long disable_value)
+{
+	wdt_reg_write(disable_lock, DISABLE_LOCK_1);
+	if ((wdt_reg_read(disable_lock) & 0x3) != 0x1)
+		return -1;
+
+	wdt_reg_write(disable_lock, DISABLE_LOCK_2);
+	if ((wdt_reg_read(disable_lock) & 0x3) != 0x2)
+		return -1;
+
+	wdt_reg_write(disable_lock, DISABLE_LOCK_3);
+	if ((wdt_reg_read(disable_lock) & 0x3) != 0x3)
+		return -1;
+
+	wdt_reg_write(disable, disable_value);
+	return 0;
+}
+
+static int wdt_set_period(unsigned long msec)
+{
+	unsigned long change_value, count_value;
+	unsigned long prescale_value = 1;
+	unsigned long refclk_khz, maxdiv;
+	int ret;
+
+	refclk_khz = clk_get_rate(TNETV107X_LPSC_WDT_ARM);
+	maxdiv = (MAX_DIV / refclk_khz);
+
+	if ((!msec) || (msec > maxdiv))
+		return -1;
+
+	count_value = refclk_khz * msec;
+	if (count_value > 0xffff) {
+		change_value = count_value / 0xffff + 1;
+		prescale_value = count_value / change_value;
+	} else {
+		change_value = count_value;
+	}
+
+	ret = write_prescale_reg(prescale_value - 1);
+	if (ret)
+		return ret;
+
+	ret = write_change_reg(change_value);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+unsigned long last_wdt = -1;
+
+int wdt_start(unsigned long msecs)
+{
+	int ret;
+	ret = wdt_control(0);
+	if (ret)
+		return ret;
+	ret = wdt_set_period(msecs);
+	if (ret)
+		return ret;
+	ret = wdt_control(1);
+	if (ret)
+		return ret;
+	ret = wdt_kick();
+	last_wdt = msecs;
+	return ret;
+}
+
+int wdt_stop(void)
+{
+	last_wdt = -1;
+	return wdt_control(0);
+}
+
+int wdt_kick(void)
+{
+	wdt_reg_write(kick_lock, KICK_LOCK_1);
+	if ((wdt_reg_read(kick_lock) & 0x3) != 0x1)
+		return -1;
+
+	wdt_reg_write(kick_lock, KICK_LOCK_2);
+	if ((wdt_reg_read(kick_lock) & 0x3) != 0x3)
+		return -1;
+
+	wdt_reg_write(kick, 1);
+	return 0;
+}
+
+void reset_cpu(ulong addr)
+{
+	clk_enable(TNETV107X_LPSC_WDT_ARM);
+	wdt_start(1);
+	wdt_kick();
+}