mips: jz47xx: Add JZ4780 SoC support

Add initial support for the Ingenic JZ47xx MIPS SoC.

Cc: Daniel Schwierzeck <daniel.schwierzeck@gmail.com>
Signed-off-by: Paul Burton <paul.burton@imgtec.com>
Signed-off-by: Marek Vasut <marek.vasut@gmail.com>
Signed-off-by: Ezequiel Garcia <ezequiel@collabora.com>
Reviewed-by: Marek Vasut <marex@denx.de>
diff --git a/MAINTAINERS b/MAINTAINERS
index bb0a107..ae82501 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -525,6 +525,11 @@
 F:	configs/mscc*
 F:	include/configs/vcoreiii.h
 
+MIPS JZ4780
+M:	Ezequiel Garcia <ezequiel@collabora.com>
+S:	Maintained
+F:	arch/mips/mach-jz47xx/
+
 MMC
 M:	Jaehoon Chung <jh80.chung@samsung.com>
 S:	Maintained
diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig
index fe041f0..194f4f3 100644
--- a/arch/mips/Kconfig
+++ b/arch/mips/Kconfig
@@ -93,6 +93,12 @@
 	select SUPPORTS_LITTLE_ENDIAN
 	select SYSRESET
 
+config ARCH_JZ47XX
+	bool "Support Ingenic JZ47xx"
+	select SUPPORT_SPL
+	select OF_CONTROL
+	select DM
+
 config MACH_PIC32
 	bool "Support Microchip PIC32"
 	select DM
@@ -145,6 +151,7 @@
 source "arch/mips/mach-ath79/Kconfig"
 source "arch/mips/mach-mscc/Kconfig"
 source "arch/mips/mach-bmips/Kconfig"
+source "arch/mips/mach-jz47xx/Kconfig"
 source "arch/mips/mach-pic32/Kconfig"
 source "arch/mips/mach-mt7620/Kconfig"
 
diff --git a/arch/mips/Makefile b/arch/mips/Makefile
index 124e93f..029d290 100644
--- a/arch/mips/Makefile
+++ b/arch/mips/Makefile
@@ -13,6 +13,7 @@
 
 machine-$(CONFIG_ARCH_ATH79) += ath79
 machine-$(CONFIG_ARCH_BMIPS) += bmips
+machine-$(CONFIG_ARCH_JZ47XX) += jz47xx
 machine-$(CONFIG_MACH_PIC32) += pic32
 machine-$(CONFIG_ARCH_MT7620) += mt7620
 machine-$(CONFIG_ARCH_MSCC) += mscc
diff --git a/arch/mips/dts/jz4780.dtsi b/arch/mips/dts/jz4780.dtsi
new file mode 100644
index 0000000..f62a7a9
--- /dev/null
+++ b/arch/mips/dts/jz4780.dtsi
@@ -0,0 +1,164 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+#include <dt-bindings/clock/jz4780-cgu.h>
+
+/ {
+	#address-cells = <1>;
+	#size-cells = <1>;
+	compatible = "ingenic,jz4780";
+
+	cpuintc: interrupt-controller {
+		#address-cells = <0>;
+		#interrupt-cells = <1>;
+		interrupt-controller;
+		compatible = "mti,cpu-interrupt-controller";
+	};
+
+	intc: interrupt-controller@10001000 {
+		compatible = "ingenic,jz4780-intc";
+		reg = <0x10001000 0x50>;
+
+		interrupt-controller;
+		#interrupt-cells = <1>;
+
+		interrupt-parent = <&cpuintc>;
+		interrupts = <2>;
+	};
+
+	ext: ext {
+		compatible = "fixed-clock";
+		#clock-cells = <0>;
+	};
+
+	rtc: rtc {
+		compatible = "fixed-clock";
+		#clock-cells = <0>;
+		clock-frequency = <32768>;
+	};
+
+	cgu: jz4780-cgu@10000000 {
+		compatible = "ingenic,jz4780-cgu";
+		reg = <0x10000000 0x100>;
+
+		clocks = <&ext>, <&rtc>;
+		clock-names = "ext", "rtc";
+
+		#clock-cells = <1>;
+	};
+
+	mmc0: mmc@13450000 {
+		compatible = "ingenic,jz4780-mmc";
+		reg = <0x13450000 0x1000>;
+
+		status = "disabled";
+
+		clocks = <&cgu JZ4780_CLK_MSC0>;
+		clock-names = "mmc";
+	};
+
+	mmc1: mmc@13460000 {
+		compatible = "ingenic,jz4780-mmc";
+		reg = <0x13460000 0x1000>;
+
+		clocks = <&cgu JZ4780_CLK_MSC1>;
+		clock-names = "mmc";
+
+		status = "disabled";
+	};
+
+	uart0: serial@10030000 {
+		compatible = "ingenic,jz4780-uart";
+		reg = <0x10030000 0x100>;
+		reg-shift = <2>;
+
+		interrupt-parent = <&intc>;
+		interrupts = <51>;
+
+		clocks = <&ext>, <&cgu JZ4780_CLK_UART0>;
+		clock-names = "baud", "module";
+
+		status = "disabled";
+	};
+
+	uart1: serial@10031000 {
+		compatible = "ingenic,jz4780-uart";
+		reg = <0x10031000 0x100>;
+		reg-shift = <2>;
+
+		interrupt-parent = <&intc>;
+		interrupts = <50>;
+
+		clocks = <&ext>, <&cgu JZ4780_CLK_UART1>;
+		clock-names = "baud", "module";
+
+		status = "disabled";
+	};
+
+	uart2: serial@10032000 {
+		compatible = "ingenic,jz4780-uart";
+		reg = <0x10032000 0x100>;
+		reg-shift = <2>;
+
+		interrupt-parent = <&intc>;
+		interrupts = <49>;
+
+		clocks = <&ext>, <&cgu JZ4780_CLK_UART2>;
+		clock-names = "baud", "module";
+
+		status = "disabled";
+	};
+
+	uart3: serial@10033000 {
+		compatible = "ingenic,jz4780-uart";
+		reg = <0x10033000 0x100>;
+		reg-shift = <2>;
+
+		interrupt-parent = <&intc>;
+		interrupts = <48>;
+
+		clocks = <&ext>, <&cgu JZ4780_CLK_UART3>;
+		clock-names = "baud", "module";
+
+		status = "disabled";
+	};
+
+	uart4: serial@10034000 {
+		compatible = "ingenic,jz4780-uart";
+		reg = <0x10034000 0x100>;
+		reg-shift = <2>;
+
+		interrupt-parent = <&intc>;
+		interrupts = <34>;
+
+		clocks = <&ext>, <&cgu JZ4780_CLK_UART4>;
+		clock-names = "baud", "module";
+
+		status = "disabled";
+	};
+
+	nemc: nemc@13410000 {
+		compatible = "ingenic,jz4780-nemc";
+		reg = <0x13410000 0x10000>;
+		#address-cells = <2>;
+		#size-cells = <1>;
+		ranges = <1 0 0x1b000000 0x1000000
+			  2 0 0x1a000000 0x1000000
+			  3 0 0x19000000 0x1000000
+			  4 0 0x18000000 0x1000000
+			  5 0 0x17000000 0x1000000
+			  6 0 0x16000000 0x1000000>;
+
+		clocks = <&cgu JZ4780_CLK_NEMC>;
+
+		status = "disabled";
+	};
+
+	bch: bch@134d0000 {
+		compatible = "ingenic,jz4780-bch";
+		reg = <0x134d0000 0x10000>;
+
+		clocks = <&cgu JZ4780_CLK_BCH>;
+
+		status = "disabled";
+	};
+};
diff --git a/arch/mips/mach-jz47xx/Kconfig b/arch/mips/mach-jz47xx/Kconfig
new file mode 100644
index 0000000..cd6944c
--- /dev/null
+++ b/arch/mips/mach-jz47xx/Kconfig
@@ -0,0 +1,15 @@
+menu "Ingenic JZ47xx platforms"
+	depends on ARCH_JZ47XX
+
+config SYS_SOC
+	default "jz47xx"
+
+config SOC_JZ4780
+	bool
+	select SUPPORTS_LITTLE_ENDIAN
+	select SUPPORTS_CPU_MIPS32_R1
+	select SUPPORTS_CPU_MIPS32_R2
+	help
+	  Support for Ingenic JZ4780 family SoCs.
+
+endmenu
diff --git a/arch/mips/mach-jz47xx/Makefile b/arch/mips/mach-jz47xx/Makefile
new file mode 100644
index 0000000..dbb8229
--- /dev/null
+++ b/arch/mips/mach-jz47xx/Makefile
@@ -0,0 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0+
+
+extra-$(CONFIG_SPL_BUILD)	:= start.o
+
+obj-$(CONFIG_SOC_JZ4780)	+= jz4780/
diff --git a/arch/mips/mach-jz47xx/include/mach/jz4780.h b/arch/mips/mach-jz47xx/include/mach/jz4780.h
new file mode 100644
index 0000000..4422e50
--- /dev/null
+++ b/arch/mips/mach-jz47xx/include/mach/jz4780.h
@@ -0,0 +1,103 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * JZ4780 definitions
+ *
+ * Copyright (c) 2013 Imagination Technologies
+ * Author: Paul Burton <paul.burton@imgtec.com>
+ */
+
+#ifndef __JZ4780_H__
+#define __JZ4780_H__
+
+/* AHB0 BUS Devices */
+#define DDRC_BASE	0xb3010000
+
+/* AHB2 BUS Devices */
+#define NEMC_BASE	0xb3410000
+#define BCH_BASE	0xb34d0000
+
+/* APB BUS Devices */
+#define CPM_BASE	0xb0000000
+#define TCU_BASE	0xb0002000
+#define WDT_BASE	0xb0002000
+#define GPIO_BASE	0xb0010000
+#define UART0_BASE	0xb0030000
+#define UART1_BASE	0xb0031000
+#define UART2_BASE	0xb0032000
+#define UART3_BASE	0xb0033000
+#define MSC0_BASE	0xb3450000
+#define MSC1_BASE	0xb3460000
+#define MSC2_BASE	0xb3470000
+
+/*
+ * GPIO
+ */
+/* n = 0,1,2,3,4,5 */
+#define GPIO_PXPIN(n)	(0x00 + (n) * 0x100)
+#define GPIO_PXINT(n)	(0x10 + (n) * 0x100)
+#define GPIO_PXINTS(n)	(0x14 + (n) * 0x100)
+#define GPIO_PXINTC(n)	(0x18 + (n) * 0x100)
+#define GPIO_PXMASK(n)	(0x20 + (n) * 0x100)
+#define GPIO_PXMASKS(n)	(0x24 + (n) * 0x100)
+#define GPIO_PXMASKC(n)	(0x28 + (n) * 0x100)
+#define GPIO_PXPAT1(n)	(0x30 + (n) * 0x100)
+#define GPIO_PXPAT1S(n)	(0x34 + (n) * 0x100)
+#define GPIO_PXPAT1C(n)	(0x38 + (n) * 0x100)
+#define GPIO_PXPAT0(n)	(0x40 + (n) * 0x100)
+#define GPIO_PXPAT0S(n)	(0x44 + (n) * 0x100)
+#define GPIO_PXPAT0C(n)	(0x48 + (n) * 0x100)
+#define GPIO_PXFLG(n)	(0x50 + (n) * 0x100)
+#define GPIO_PXFLGC(n)	(0x54 + (n) * 0x100)
+#define GPIO_PXOEN(n)	(0x60 + (n) * 0x100)
+#define GPIO_PXOENS(n)	(0x64 + (n) * 0x100)
+#define GPIO_PXOENC(n)	(0x68 + (n) * 0x100)
+#define GPIO_PXPEN(n)	(0x70 + (n) * 0x100)
+#define GPIO_PXPENS(n)	(0x74 + (n) * 0x100)
+#define GPIO_PXPENC(n)	(0x78 + (n) * 0x100)
+#define GPIO_PXDS(n)	(0x80 + (n) * 0x100)
+#define GPIO_PXDSS(n)	(0x84 + (n) * 0x100)
+#define GPIO_PXDSC(n)	(0x88 + (n) * 0x100)
+
+/* PLL setup */
+#define JZ4780_SYS_EXTAL	48000000
+#define JZ4780_SYS_MEM_SPEED	(CONFIG_SYS_MHZ * 1000000)
+#define JZ4780_SYS_MEM_DIV	3
+#define JZ4780_SYS_AUDIO_SPEED	(768 * 1000000)
+
+#define JZ4780_APLL_M	1
+#define JZ4780_APLL_N	1
+#define JZ4780_APLL_OD	1
+
+#define JZ4780_MPLL_M	(JZ4780_SYS_MEM_SPEED / JZ4780_SYS_EXTAL * 2)
+#define JZ4780_MPLL_N	2
+#define JZ4780_MPLL_OD	1
+
+#define JZ4780_EPLL_M	(JZ4780_SYS_AUDIO_SPEED * 2 / JZ4780_SYS_EXTAL)
+#define JZ4780_EPLL_N	1
+#define JZ4780_EPLL_OD	2
+
+#define JZ4780_VPLL_M	((888 * 1000000) * 2 / JZ4780_SYS_EXTAL)
+#define JZ4780_VPLL_N	1
+#define JZ4780_VPLL_OD	2
+
+#ifndef __ASSEMBLY__
+
+u32 sdram_size(int bank);
+
+const u32 jz4780_clk_get_efuse_clk(void);
+void jz4780_clk_ungate_ethernet(void);
+void jz4780_clk_ungate_mmc(void);
+void jz4780_clk_ungate_uart(const unsigned int uart);
+
+void jz4780_efuse_read(size_t addr, size_t count, u8 *buf);
+void jz4780_efuse_init(u32 ahb2_rate);
+
+void jz4780_tcu_wdt_start(void);
+
+#ifdef CONFIG_SPL_BUILD
+int jz_mmc_init(void __iomem *base);
+#endif
+
+#endif /* __ASSEMBLY__ */
+
+#endif	/* __JZ4780_H__ */
diff --git a/arch/mips/mach-jz47xx/include/mach/jz4780_dram.h b/arch/mips/mach-jz47xx/include/mach/jz4780_dram.h
new file mode 100644
index 0000000..92d431b
--- /dev/null
+++ b/arch/mips/mach-jz47xx/include/mach/jz4780_dram.h
@@ -0,0 +1,456 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * JZ4780 DDR initialization - parameters definitions
+ *
+ * Copyright (c) 2015 Imagination Technologies
+ * Author: Matt Redfearn <matt.redfearn.com>
+ */
+
+#ifndef __JZ4780_DRAM_H__
+#define __JZ4780_DRAM_H__
+
+/*
+ * DDR
+ */
+#define DDRC_ST				0x0
+#define DDRC_CFG			0x4
+#define DDRC_CTRL			0x8
+#define DDRC_LMR			0xc
+#define DDRC_REFCNT			0x18
+#define DDRC_DQS			0x1c
+#define DDRC_DQS_ADJ			0x20
+#define DDRC_MMAP0			0x24
+#define DDRC_MMAP1			0x28
+#define DDRC_MDELAY			0x2c
+#define DDRC_CKEL			0x30
+#define DDRC_PMEMCTRL0			0x54
+#define DDRC_PMEMCTRL1			0x50
+#define DDRC_PMEMCTRL2			0x58
+#define DDRC_PMEMCTRL3			0x5c
+
+#define DDRC_TIMING(n)			(0x60 + 4 * (n))
+#define DDRC_REMMAP(n)			(0x9c + 4 * (n))
+
+/*
+ * DDR PHY
+ */
+#define DDR_MEM_PHY_BASE		0x20000000
+#define DDR_PHY_OFFSET			0x1000
+
+#define DDRP_PIR			0x4
+#define DDRP_PGCR			0x8
+#define DDRP_PGSR			0xc
+
+#define DDRP_PTR0			0x18
+#define DDRP_PTR1			0x1c
+#define DDRP_PTR2			0x20
+
+#define DDRP_ACIOCR			0x24
+#define DDRP_DXCCR			0x28
+#define DDRP_DSGCR			0x2c
+#define DDRP_DCR			0x30
+
+#define DDRP_DTPR0			0x34
+#define DDRP_DTPR1			0x38
+#define DDRP_DTPR2			0x3c
+#define DDRP_MR0			0x40
+#define DDRP_MR1			0x44
+#define DDRP_MR2			0x48
+#define DDRP_MR3			0x4c
+
+#define DDRP_ODTCR			0x50
+#define DDRP_DTAR			0x54
+#define DDRP_DTDR0			0x58
+#define DDRP_DTDR1			0x5c
+
+#define DDRP_DCUAR			0xc0
+#define DDRP_DCUDR			0xc4
+#define DDRP_DCURR			0xc8
+#define DDRP_DCULR			0xcc
+#define DDRP_DCUGCR			0xd0
+#define DDRP_DCUTPR			0xd4
+#define DDRP_DCUSR0			0xd8
+#define DDRP_DCUSR1			0xdc
+
+#define DDRP_ZQXCR0(n)			(0x180 + ((n) * 0x10))
+#define DDRP_ZQXCR1(n)			(0x184 + ((n) * 0x10))
+#define DDRP_ZQXSR0(n)			(0x188 + ((n) * 0x10))
+#define DDRP_ZQXSR1(n)			(0x18c + ((n) * 0x10))
+
+#define DDRP_DXGCR(n)			(0x1c0 + ((n) * 0x40))
+#define DDRP_DXGSR0(n)			(0x1c4 + ((n) * 0x40))
+#define DDRP_DXGSR1(n)			(0x1c8 + ((n) * 0x40))
+#define DDRP_DXDQSTR(n)			(0x1d4 + ((n) * 0x40))
+
+/* DDRC Status Register */
+#define DDRC_ST_ENDIAN			BIT(7)
+#define DDRC_ST_DPDN			BIT(5)
+#define DDRC_ST_PDN			BIT(4)
+#define DDRC_ST_AREF			BIT(3)
+#define DDRC_ST_SREF			BIT(2)
+#define DDRC_ST_CKE1			BIT(1)
+#define DDRC_ST_CKE0			BIT(0)
+
+/* DDRC Configure Register */
+#define DDRC_CFG_ROW1_BIT		27
+#define DDRC_CFG_ROW1_MASK		(0x7 << DDRC_CFG_ROW1_BIT)
+#define DDRC_CFG_COL1_BIT		24
+#define DDRC_CFG_COL1_MASK		(0x7 << DDRC_CFG_COL1_BIT)
+#define DDRC_CFG_BA1			BIT(23)
+#define DDRC_CFG_IMBA			BIT(22)
+#define DDRC_CFG_BL_8			BIT(21)
+
+#define DDRC_CFG_TYPE_BIT		17
+#define DDRC_CFG_TYPE_MASK		(0x7 << DDRC_CFG_TYPE_BIT)
+#define DDRC_CFG_TYPE_DDR1		(2 << DDRC_CFG_TYPE_BIT)
+#define DDRC_CFG_TYPE_MDDR		(3 << DDRC_CFG_TYPE_BIT)
+#define DDRC_CFG_TYPE_DDR2		(4 << DDRC_CFG_TYPE_BIT)
+#define DDRC_CFG_TYPE_LPDDR2		(5 << DDRC_CFG_TYPE_BIT)
+#define DDRC_CFG_TYPE_DDR3		(6 << DDRC_CFG_TYPE_BIT)
+
+#define DDRC_CFG_ODT_EN			BIT(16)
+
+#define DDRC_CFG_MPRT			BIT(15)
+
+#define DDRC_CFG_ROW_BIT		11
+#define DDRC_CFG_ROW_MASK		(0x7 << DDRC_CFG_ROW_BIT)
+#define DDRC_CFG_ROW_12			(0 << DDRC_CFG_ROW_BIT)
+#define DDRC_CFG_ROW_13			(1 << DDRC_CFG_ROW_BIT)
+#define DDRC_CFG_ROW_14			(2 << DDRC_CFG_ROW_BIT)
+
+#define DDRC_CFG_COL_BIT		8
+#define DDRC_CFG_COL_MASK		(0x7 << DDRC_CFG_COL_BIT)
+#define DDRC_CFG_COL_8			(0 << DDRC_CFG_COL_BIT)
+#define DDRC_CFG_COL_9			(1 << DDRC_CFG_COL_BIT)
+#define DDRC_CFG_COL_10			(2 << DDRC_CFG_COL_BIT)
+#define DDRC_CFG_COL_11			(3 << DDRC_CFG_COL_BIT)
+
+#define DDRC_CFG_CS1EN			BIT(7)
+#define DDRC_CFG_CS0EN			BIT(6)
+#define DDRC_CFG_CL_BIT			2
+#define DDRC_CFG_CL_MASK		(0xf << DDRC_CFG_CL_BIT)
+#define DDRC_CFG_CL_3			(0 << DDRC_CFG_CL_BIT)
+#define DDRC_CFG_CL_4			(1 << DDRC_CFG_CL_BIT)
+#define DDRC_CFG_CL_5			(2 << DDRC_CFG_CL_BIT)
+#define DDRC_CFG_CL_6			(3 << DDRC_CFG_CL_BIT)
+
+#define DDRC_CFG_BA			BIT(1)
+#define DDRC_CFG_DW			BIT(0)
+
+/* DDRC Control Register */
+#define DDRC_CTRL_DFI_RST		BIT(23)
+#define DDRC_CTRL_DLL_RST		BIT(22)
+#define DDRC_CTRL_CTL_RST		BIT(21)
+#define DDRC_CTRL_CFG_RST		BIT(20)
+#define DDRC_CTRL_ACTPD			BIT(15)
+#define DDRC_CTRL_PDT_BIT		12
+#define DDRC_CTRL_PDT_MASK		(0x7 << DDRC_CTRL_PDT_BIT)
+#define DDRC_CTRL_PDT_DIS		(0 << DDRC_CTRL_PDT_BIT)
+#define DDRC_CTRL_PDT_8			(1 << DDRC_CTRL_PDT_BIT)
+#define DDRC_CTRL_PDT_16		(2 << DDRC_CTRL_PDT_BIT)
+#define DDRC_CTRL_PDT_32		(3 << DDRC_CTRL_PDT_BIT)
+#define DDRC_CTRL_PDT_64		(4 << DDRC_CTRL_PDT_BIT)
+#define DDRC_CTRL_PDT_128		(5 << DDRC_CTRL_PDT_BIT)
+
+#define DDRC_CTRL_PRET_BIT		8
+#define DDRC_CTRL_PRET_MASK		(0x7 << DDRC_CTRL_PRET_BIT)
+#define DDRC_CTRL_PRET_DIS		(0 << DDRC_CTRL_PRET_BIT)
+#define DDRC_CTRL_PRET_8		(1 << DDRC_CTRL_PRET_BIT)
+#define DDRC_CTRL_PRET_16		(2 << DDRC_CTRL_PRET_BIT)
+#define DDRC_CTRL_PRET_32		(3 << DDRC_CTRL_PRET_BIT)
+#define DDRC_CTRL_PRET_64		(4 << DDRC_CTRL_PRET_BIT)
+#define DDRC_CTRL_PRET_128		(5 << DDRC_CTRL_PRET_BIT)
+
+#define DDRC_CTRL_DPD			BIT(6)
+#define DDRC_CTRL_SR			BIT(5)
+#define DDRC_CTRL_UNALIGN		BIT(4)
+#define DDRC_CTRL_ALH			BIT(3)
+#define DDRC_CTRL_RDC			BIT(2)
+#define DDRC_CTRL_CKE			BIT(1)
+#define DDRC_CTRL_RESET			BIT(0)
+
+/* DDRC Load-Mode-Register */
+#define DDRC_LMR_DDR_ADDR_BIT		16
+#define DDRC_LMR_DDR_ADDR_MASK		(0x3fff << DDRC_LMR_DDR_ADDR_BIT)
+
+#define DDRC_LMR_BA_BIT			8
+#define DDRC_LMR_BA_MASK		(0x7 << DDRC_LMR_BA_BIT)
+/* For DDR2 */
+#define DDRC_LMR_BA_MRS			(0 << DDRC_LMR_BA_BIT)
+#define DDRC_LMR_BA_EMRS1		(1 << DDRC_LMR_BA_BIT)
+#define DDRC_LMR_BA_EMRS2		(2 << DDRC_LMR_BA_BIT)
+#define DDRC_LMR_BA_EMRS3		(3 << DDRC_LMR_BA_BIT)
+/* For mobile DDR */
+#define DDRC_LMR_BA_M_MRS		(0 << DDRC_LMR_BA_BIT)
+#define DDRC_LMR_BA_M_EMRS		(2 << DDRC_LMR_BA_BIT)
+#define DDRC_LMR_BA_M_SR		(1 << DDRC_LMR_BA_BIT)
+/* For Normal DDR1 */
+#define DDRC_LMR_BA_N_MRS		(0 << DDRC_LMR_BA_BIT)
+#define DDRC_LMR_BA_N_EMRS		(1 << DDRC_LMR_BA_BIT)
+
+#define DDRC_LMR_CMD_BIT		4
+#define DDRC_LMR_CMD_MASK		(0x3 << DDRC_LMR_CMD_BIT)
+#define DDRC_LMR_CMD_PREC		(0 << DDRC_LMR_CMD_BIT)
+#define DDRC_LMR_CMD_AUREF		(1 << DDRC_LMR_CMD_BIT)
+#define DDRC_LMR_CMD_LMR		(2 << DDRC_LMR_CMD_BIT)
+
+#define DDRC_LMR_START			BIT(0)
+
+/* DDRC Timing Config Register 1 */
+#define DDRC_TIMING1_TRTP_BIT		24
+#define DDRC_TIMING1_TRTP_MASK		(0x3f << DDRC_TIMING1_TRTP_BIT)
+#define DDRC_TIMING1_TWTR_BIT		16
+#define DDRC_TIMING1_TWTR_MASK		(0x3f << DDRC_TIMING1_TWTR_BIT)
+#define DDRC_TIMING1_TWTR_1		(0 << DDRC_TIMING1_TWTR_BIT)
+#define DDRC_TIMING1_TWTR_2		(1 << DDRC_TIMING1_TWTR_BIT)
+#define DDRC_TIMING1_TWTR_3		(2 << DDRC_TIMING1_TWTR_BIT)
+#define DDRC_TIMING1_TWTR_4		(3 << DDRC_TIMING1_TWTR_BIT)
+#define DDRC_TIMING1_TWR_BIT		8
+#define DDRC_TIMING1_TWR_MASK		(0x3f << DDRC_TIMING1_TWR_BIT)
+#define DDRC_TIMING1_TWR_1		(0 << DDRC_TIMING1_TWR_BIT)
+#define DDRC_TIMING1_TWR_2		(1 << DDRC_TIMING1_TWR_BIT)
+#define DDRC_TIMING1_TWR_3		(2 << DDRC_TIMING1_TWR_BIT)
+#define DDRC_TIMING1_TWR_4		(3 << DDRC_TIMING1_TWR_BIT)
+#define DDRC_TIMING1_TWR_5		(4 << DDRC_TIMING1_TWR_BIT)
+#define DDRC_TIMING1_TWR_6		(5 << DDRC_TIMING1_TWR_BIT)
+#define DDRC_TIMING1_TWL_BIT		0
+#define DDRC_TIMING1_TWL_MASK		(0x3f << DDRC_TIMING1_TWL_BIT)
+
+/* DDRC Timing Config Register 2 */
+#define DDRC_TIMING2_TCCD_BIT		24
+#define DDRC_TIMING2_TCCD_MASK		(0x3f << DDRC_TIMING2_TCCD_BIT)
+#define DDRC_TIMING2_TRAS_BIT		16
+#define DDRC_TIMING2_TRAS_MASK		(0x3f << DDRC_TIMING2_TRAS_BIT)
+#define DDRC_TIMING2_TRCD_BIT		8
+#define DDRC_TIMING2_TRCD_MASK		(0x3f << DDRC_TIMING2_TRCD_BIT)
+#define DDRC_TIMING2_TRL_BIT		0
+#define DDRC_TIMING2_TRL_MASK		(0x3f << DDRC_TIMING2_TRL_BIT)
+
+/* DDRC Timing Config Register 3 */
+#define DDRC_TIMING3_ONUM		27
+#define DDRC_TIMING3_TCKSRE_BIT		24
+#define DDRC_TIMING3_TCKSRE_MASK	(0x3f << DDRC_TIMING3_TCKSRE_BIT)
+#define DDRC_TIMING3_TRP_BIT		16
+#define DDRC_TIMING3_TRP_MASK		(0x3f << DDRC_TIMING3_TRP_BIT)
+#define DDRC_TIMING3_TRRD_BIT		8
+#define DDRC_TIMING3_TRRD_MASK		(0x3f << DDRC_TIMING3_TRRD_BIT)
+#define DDRC_TIMING3_TRRD_DISABLE	(0 << DDRC_TIMING3_TRRD_BIT)
+#define DDRC_TIMING3_TRRD_2		(1 << DDRC_TIMING3_TRRD_BIT)
+#define DDRC_TIMING3_TRRD_3		(2 << DDRC_TIMING3_TRRD_BIT)
+#define DDRC_TIMING3_TRRD_4		(3 << DDRC_TIMING3_TRRD_BIT)
+#define DDRC_TIMING3_TRC_BIT		0
+#define DDRC_TIMING3_TRC_MASK		(0x3f << DDRC_TIMING3_TRC_BIT)
+
+/* DDRC Timing Config Register 4 */
+#define DDRC_TIMING4_TRFC_BIT		24
+#define DDRC_TIMING4_TRFC_MASK		(0x3f << DDRC_TIMING4_TRFC_BIT)
+#define DDRC_TIMING4_TEXTRW_BIT		21
+#define DDRC_TIMING4_TEXTRW_MASK	(0x7 << DDRC_TIMING4_TEXTRW_BIT)
+#define DDRC_TIMING4_TRWCOV_BIT		19
+#define DDRC_TIMING4_TRWCOV_MASK	(0x3 << DDRC_TIMING4_TRWCOV_BIT)
+#define DDRC_TIMING4_TCKE_BIT		16
+#define DDRC_TIMING4_TCKE_MASK		(0x7 << DDRC_TIMING4_TCKE_BIT)
+#define DDRC_TIMING4_TMINSR_BIT		8
+#define DDRC_TIMING4_TMINSR_MASK	(0xf << DDRC_TIMING4_TMINSR_BIT)
+#define DDRC_TIMING4_TXP_BIT		4
+#define DDRC_TIMING4_TXP_MASK		(0x7 << DDRC_TIMING4_TXP_BIT)
+#define DDRC_TIMING4_TMRD_BIT		0
+#define DDRC_TIMING4_TMRD_MASK		(0x3 << DDRC_TIMING4_TMRD_BIT)
+
+/* DDRC Timing Config Register 5 */
+#define DDRC_TIMING5_TCTLUPD_BIT	24
+#define DDRC_TIMING4_TCTLUPD_MASK	(0x3f << DDRC_TIMING5_TCTLUDP_BIT)
+#define DDRC_TIMING5_TRTW_BIT		16
+#define DDRC_TIMING5_TRTW_MASK		(0x3f << DDRC_TIMING5_TRTW_BIT)
+#define DDRC_TIMING5_TRDLAT_BIT		8
+#define DDRC_TIMING5_TRDLAT_MASK	(0x3f << DDRC_TIMING5_TRDLAT_BIT)
+#define DDRC_TIMING5_TWDLAT_BIT		0
+#define DDRC_TIMING5_TWDLAT_MASK	(0x3f << DDRC_TIMING5_TWDLAT_BIT)
+
+/* DDRC Timing Config Register 6 */
+#define DDRC_TIMING6_TXSRD_BIT		24
+#define DDRC_TIMING6_TXSRD_MASK		(0x3f << DDRC_TIMING6_TXSRD_BIT)
+#define DDRC_TIMING6_TFAW_BIT		16
+#define DDRC_TIMING6_TFAW_MASK		(0x3f << DDRC_TIMING6_TFAW_BIT)
+#define DDRC_TIMING6_TCFGW_BIT		8
+#define DDRC_TIMING6_TCFGW_MASK		(0x3f << DDRC_TIMING6_TCFGW_BIT)
+#define DDRC_TIMING6_TCFGR_BIT		0
+#define DDRC_TIMING6_TCFGR_MASK		(0x3f << DDRC_TIMING6_TCFGR_BIT)
+
+/* DDRC  Auto-Refresh Counter */
+#define DDRC_REFCNT_CON_BIT		16
+#define DDRC_REFCNT_CON_MASK		(0xff << DDRC_REFCNT_CON_BIT)
+#define DDRC_REFCNT_CNT_BIT		8
+#define DDRC_REFCNT_CNT_MASK		(0xff << DDRC_REFCNT_CNT_BIT)
+#define DDRC_REFCNT_CLKDIV_BIT		1
+#define DDRC_REFCNT_CLKDIV_MASK		(0x7 << DDRC_REFCNT_CLKDIV_BIT)
+#define DDRC_REFCNT_REF_EN		BIT(0)
+
+/* DDRC DQS Delay Control Register */
+#define DDRC_DQS_ERROR			BIT(29)
+#define DDRC_DQS_READY			BIT(28)
+#define DDRC_DQS_AUTO			BIT(23)
+#define DDRC_DQS_DET			BIT(24)
+#define DDRC_DQS_SRDET			BIT(25)
+#define DDRC_DQS_CLKD_BIT		16
+#define DDRC_DQS_CLKD_MASK		(0x3f << DDRC_DQS_CLKD_BIT)
+#define DDRC_DQS_WDQS_BIT		8
+#define DDRC_DQS_WDQS_MASK		(0x3f << DDRC_DQS_WDQS_BIT)
+#define DDRC_DQS_RDQS_BIT		0
+#define DDRC_DQS_RDQS_MASK		(0x3f << DDRC_DQS_RDQS_BIT)
+
+/* DDRC DQS Delay Adjust Register */
+#define DDRC_DQS_ADJWDQS_BIT		8
+#define DDRC_DQS_ADJWDQS_MASK		(0x1f << DDRC_DQS_ADJWDQS_BIT)
+#define DDRC_DQS_ADJRDQS_BIT		0
+#define DDRC_DQS_ADJRDQS_MASK		(0x1f << DDRC_DQS_ADJRDQS_BIT)
+
+/* DDRC Memory Map Config Register */
+#define DDRC_MMAP_BASE_BIT		8
+#define DDRC_MMAP_BASE_MASK		(0xff << DDRC_MMAP_BASE_BIT)
+#define DDRC_MMAP_MASK_BIT		0
+#define DDRC_MMAP_MASK_MASK		(0xff << DDRC_MMAP_MASK_BIT)
+
+#define DDRC_MMAP0_BASE			(0x20 << DDRC_MMAP_BASE_BIT)
+#define DDRC_MMAP1_BASE_64M		(0x24 << DDRC_MMAP_BASE_BIT)
+#define DDRC_MMAP1_BASE_128M		(0x28 << DDRC_MMAP_BASE_BIT)
+#define DDRC_MMAP1_BASE_256M		(0x30 << DDRC_MMAP_BASE_BIT)
+
+#define DDRC_MMAP_MASK_64_64		(0xfc << DDRC_MMAP_MASK_BIT)
+#define DDRC_MMAP_MASK_128_128		(0xf8 << DDRC_MMAP_MASK_BIT)
+#define DDRC_MMAP_MASK_256_256		(0xf0 << DDRC_MMAP_MASK_BIT)
+
+/* DDRP PHY Initialization Register */
+#define DDRP_PIR_INIT			BIT(0)
+#define DDRP_PIR_DLLSRST		BIT(1)
+#define DDRP_PIR_DLLLOCK		BIT(2)
+#define DDRP_PIR_ZCAL			BIT(3)
+#define DDRP_PIR_ITMSRST		BIT(4)
+#define DDRP_PIR_DRAMRST		BIT(5)
+#define DDRP_PIR_DRAMINT		BIT(6)
+#define DDRP_PIR_QSTRN			BIT(7)
+#define DDRP_PIR_EYETRN			BIT(8)
+#define DDRP_PIR_DLLBYP			BIT(17)
+/* DDRP PHY General Configurate Register */
+#define DDRP_PGCR_ITMDMD		BIT(0)
+#define DDRP_PGCR_DQSCFG		BIT(1)
+#define DDRP_PGCR_DFTCMP		BIT(2)
+#define DDRP_PGCR_DFTLMT_BIT		3
+#define DDRP_PGCR_DTOSEL_BIT		5
+#define DDRP_PGCR_CKEN_BIT		9
+#define DDRP_PGCR_CKDV_BIT		12
+#define DDRP_PGCR_CKINV			BIT(14)
+#define DDRP_PGCR_RANKEN_BIT		18
+#define DDRP_PGCR_ZCKSEL_32		(2 << 22)
+#define DDRP_PGCR_PDDISDX		BIT(24)
+/* DDRP PHY General Status Register */
+#define DDRP_PGSR_IDONE			BIT(0)
+#define DDRP_PGSR_DLDONE		BIT(1)
+#define DDRP_PGSR_ZCDONE		BIT(2)
+#define DDRP_PGSR_DIDONE		BIT(3)
+#define DDRP_PGSR_DTDONE		BIT(4)
+#define DDRP_PGSR_DTERR			BIT(5)
+#define DDRP_PGSR_DTIERR		BIT(6)
+#define DDRP_PGSR_DFTEERR		BIT(7)
+/* DDRP DRAM Configuration Register */
+#define DDRP_DCR_TYPE_BIT		0
+#define DDRP_DCR_TYPE_MASK		(0x7 << DDRP_DCR_TYPE_BIT)
+#define DDRP_DCR_TYPE_MDDR		(0 << DDRP_DCR_TYPE_BIT)
+#define DDRP_DCR_TYPE_DDR		(1 << DDRP_DCR_TYPE_BIT)
+#define DDRP_DCR_TYPE_DDR2		(2 << DDRP_DCR_TYPE_BIT)
+#define DDRP_DCR_TYPE_DDR3		(3 << DDRP_DCR_TYPE_BIT)
+#define DDRP_DCR_TYPE_LPDDR2		(4 << DDRP_DCR_TYPE_BIT)
+#define DDRP_DCR_DDR8BNK_BIT		3
+#define DDRP_DCR_DDR8BNK_MASK		(1 << DDRP_DCR_DDR8BNK_BIT)
+#define DDRP_DCR_DDR8BNK		(1 << DDRP_DCR_DDR8BNK_BIT)
+#define DDRP_DCR_DDR8BNK_DIS		(0 << DDRP_DCR_DDR8BNK_BIT)
+
+#define DRP_DTRP1_RTODT			BIT(11)
+
+#define DDRP_DXGCR_DXEN			BIT(0)
+
+#define DDRP_ZQXCR_ZDEN_BIT		28
+#define DDRP_ZQXCR_ZDEN			(1 << DDRP_ZQXCR_ZDEN_BIT)
+#define DDRP_ZQXCR_PULLUP_IMPE_BIT	5
+#define DDRP_ZQXCR_PULLDOWN_IMPE_BIT	0
+
+/* DDR3 Mode Register Set */
+#define DDR3_MR0_BL_BIT			0
+#define DDR3_MR0_BL_MASK		(3 << DDR3_MR0_BL_BIT)
+#define DDR3_MR0_BL_8			(0 << DDR3_MR0_BL_BIT)
+#define DDR3_MR0_BL_fly			(1 << DDR3_MR0_BL_BIT)
+#define DDR3_MR0_BL_4			(2 << DDR3_MR0_BL_BIT)
+#define DDR3_MR0_BT_BIT			3
+#define DDR3_MR0_BT_MASK		(1 << DDR3_MR0_BT_BIT)
+#define DDR3_MR0_BT_SEQ			(0 << DDR3_MR0_BT_BIT)
+#define DDR3_MR0_BT_INTER		(1 << DDR3_MR0_BT_BIT)
+#define DDR3_MR0_WR_BIT			9
+
+#define DDR3_MR1_DLL_DISABLE		1
+#define DDR3_MR1_DIC_6			(0 << 5 | 0 << 1)
+#define DDR3_MR1_DIC_7			(0 << 5 | BIT(1))
+#define DDR3_MR1_RTT_DIS		(0 << 9 | 0 << 6 | 0 << 2)
+#define DDR3_MR1_RTT_4			(0 << 9 | 0 << 6 | BIT(2))
+#define DDR3_MR1_RTT_2			(0 << 9 | BIT(6) | 0 << 2)
+#define DDR3_MR1_RTT_6			(0 << 9 | BIT(6) | BIT(2))
+#define DDR3_MR1_RTT_12			(BIT(9) | 0 << 6 | 0 << 2)
+#define DDR3_MR1_RTT_8			(BIT(9) | 0 << 6 | BIT(2))
+
+#define DDR3_MR2_CWL_BIT		3
+
+/* Parameters common to all RAM devices used */
+
+/* Chip Select */
+/* CSEN : whether a ddr chip exists 0 - un-used, 1 - used */
+#define DDR_CS0EN	1
+/* CSEN : whether a ddr chip exists 0 - un-used, 1 - used */
+#define DDR_CS1EN	0
+
+/* ROW : 12 to 18 row address, 1G only 512MB */
+#define DDR_ROW		15
+/* COL :  8 to 14 column address */
+#define DDR_COL		10
+/* Banks each chip: 0-4bank, 1-8bank */
+#define DDR_BANK8	1
+/* 0 - 16-bit data width, 1 - 32-bit data width */
+#define DDR_DW32	1
+
+/* Refresh period: 64ms / 32768 = 1.95 us , 2 ^ 15 = 32768 */
+#define DDR_tREFI	7800
+/* Clock Divider */
+#define DDR_CLK_DIV	1
+
+/* DDR3 Burst length: 0 - 8 burst, 2 - 4 burst , 1 - 4 or 8 (on the fly) */
+#define DDR_BL		8
+
+/* CAS latency: 5 to 14, tCK */
+#define DDR_CL		6
+/* DDR3 only: CAS Write Latency, 5 to 8 */
+#define DDR_tCWL	(DDR_CL - 1)
+
+/* Structure representing per-RAM type configuration */
+
+struct jz4780_ddr_config {
+	u32	timing[6];	/* Timing1..6 register value */
+
+	/* DDR PHY control */
+	u16	mr0;	/* Mode Register 0 */
+	u16	mr1;	/* Mode Register 1 */
+
+	u32	ptr0;	/* PHY Timing Register 0 */
+	u32	ptr1;	/* PHY Timing Register 1 */
+	u32	ptr2;	/* PHY Timing Register 1 */
+
+	u32	dtpr0;	/* DRAM Timing Parameters Register 0 */
+	u32	dtpr1;	/* DRAM Timing Parameters Register 1 */
+	u32	dtpr2;	/* DRAM Timing Parameters Register 2 */
+
+	u8	pullup;	/* PHY pullup impedance */
+	u8	pulldn;	/* PHY pulldown impedance */
+};
+
+void pll_init(void);
+void sdram_init(void);
+
+#endif	/* __JZ4780_DRAM_H__ */
+
diff --git a/arch/mips/mach-jz47xx/include/mach/jz4780_gpio.h b/arch/mips/mach-jz47xx/include/mach/jz4780_gpio.h
new file mode 100644
index 0000000..37f0892
--- /dev/null
+++ b/arch/mips/mach-jz47xx/include/mach/jz4780_gpio.h
@@ -0,0 +1,12 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+
+#ifndef __JZ4780_GPIO_H__
+#define __JZ4780_GPIO_H__
+
+#define JZ_GPIO(bank, pin) ((32 * (bank)) + (pin))
+
+int jz47xx_gpio_get_value(unsigned int gpio);
+void jz47xx_gpio_direction_input(unsigned int gpio);
+void jz47xx_gpio_direction_output(unsigned int gpio, int value);
+
+#endif
diff --git a/arch/mips/mach-jz47xx/jz4780/Makefile b/arch/mips/mach-jz47xx/jz4780/Makefile
new file mode 100644
index 0000000..5b3c354
--- /dev/null
+++ b/arch/mips/mach-jz47xx/jz4780/Makefile
@@ -0,0 +1,3 @@
+# SPDX-License-Identifier: GPL-2.0+
+
+obj-y := gpio.o jz4780.o pll.o reset.o sdram.o timer.o
diff --git a/arch/mips/mach-jz47xx/jz4780/TODO b/arch/mips/mach-jz47xx/jz4780/TODO
new file mode 100644
index 0000000..99ad622
--- /dev/null
+++ b/arch/mips/mach-jz47xx/jz4780/TODO
@@ -0,0 +1,4 @@
+- dm gpio driver
+- ethernet driver for the dm9000
+- reduce the hundreds of definitions of register addresses to the ones really needed in assembly or SPL.
+- define the remaining register base addresses as physical addresses and establish a mapping with ioremap_nocache()
diff --git a/arch/mips/mach-jz47xx/jz4780/gpio.c b/arch/mips/mach-jz47xx/jz4780/gpio.c
new file mode 100644
index 0000000..cee2328
--- /dev/null
+++ b/arch/mips/mach-jz47xx/jz4780/gpio.c
@@ -0,0 +1,39 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+#include <config.h>
+#include <common.h>
+#include <asm/io.h>
+#include <mach/jz4780.h>
+
+int jz47xx_gpio_get_value(unsigned int gpio)
+{
+	void __iomem *gpio_regs = (void __iomem *)GPIO_BASE;
+	int port = gpio / 32;
+	int pin = gpio % 32;
+
+	return readl(gpio_regs + GPIO_PXPIN(port)) & BIT(pin);
+}
+
+void jz47xx_gpio_direction_input(unsigned int gpio)
+{
+	void __iomem *gpio_regs = (void __iomem *)GPIO_BASE;
+	int port = gpio / 32;
+	int pin = gpio % 32;
+
+	writel(BIT(pin), gpio_regs + GPIO_PXINTC(port));
+	writel(BIT(pin), gpio_regs + GPIO_PXMASKS(port));
+	writel(BIT(pin), gpio_regs + GPIO_PXPAT1S(port));
+}
+
+void jz47xx_gpio_direction_output(unsigned int gpio, int value)
+{
+	void __iomem *gpio_regs = (void __iomem *)GPIO_BASE;
+	int port = gpio / 32;
+	int pin = gpio % 32;
+
+	writel(BIT(pin), gpio_regs + GPIO_PXINTC(port));
+	writel(BIT(pin), gpio_regs + GPIO_PXMASKS(port));
+	writel(BIT(pin), gpio_regs + GPIO_PXPAT1C(port));
+	writel(BIT(pin), gpio_regs +
+			 (value ? GPIO_PXPAT0S(port) : GPIO_PXPAT0C(port)));
+}
diff --git a/arch/mips/mach-jz47xx/jz4780/jz4780.c b/arch/mips/mach-jz47xx/jz4780/jz4780.c
new file mode 100644
index 0000000..dbd328c
--- /dev/null
+++ b/arch/mips/mach-jz47xx/jz4780/jz4780.c
@@ -0,0 +1,83 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * JZ4780 common routines
+ *
+ * Copyright (c) 2013 Imagination Technologies
+ * Author: Paul Burton <paul.burton@imgtec.com>
+ */
+
+#include <config.h>
+#include <common.h>
+#include <asm/io.h>
+#include <asm/sections.h>
+#include <mach/jz4780.h>
+#include <mach/jz4780_dram.h>
+#include <mmc.h>
+#include <spl.h>
+
+#ifdef CONFIG_SPL_BUILD
+/* Pointer to the global data structure for SPL */
+DECLARE_GLOBAL_DATA_PTR;
+gd_t gdata __attribute__ ((section(".bss")));
+
+void board_init_f(ulong dummy)
+{
+	typedef void __noreturn (*image_entry_noargs_t)(void);
+	struct mmc *mmc;
+	unsigned long count;
+	struct image_header *header;
+	int ret;
+
+	/* Set global data pointer */
+	gd = &gdata;
+
+	timer_init();
+	pll_init();
+	sdram_init();
+	enable_caches();
+
+	/* Clear the BSS */
+	memset(__bss_start, 0, (char *)&__bss_end - __bss_start);
+
+	gd->flags |= GD_FLG_SPL_INIT;
+
+	ret = mmc_initialize(NULL);
+	if (ret)
+		hang();
+
+	mmc = find_mmc_device(BOOT_DEVICE_MMC1);
+	if (ret)
+		hang();
+
+	ret = mmc_init(mmc);
+	if (ret)
+		hang();
+
+	header = (struct image_header *)(CONFIG_SYS_TEXT_BASE -
+					 sizeof(struct image_header));
+
+	count = blk_dread(mmc_get_blk_desc(mmc),
+			  CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR,
+		0x800, header);
+	if (count == 0)
+		hang();
+
+	image_entry_noargs_t image_entry =
+		(image_entry_noargs_t)CONFIG_SYS_TEXT_BASE;
+
+	image_entry();
+
+	hang();
+}
+#endif /* CONFIG_SPL_BUILD */
+
+ulong board_get_usable_ram_top(ulong total_size)
+{
+	return CONFIG_SYS_SDRAM_BASE + (256 * 1024 * 1024);
+}
+
+int print_cpuinfo(void)
+{
+	printf("CPU:   Ingenic JZ4780\n");
+	return 0;
+}
diff --git a/arch/mips/mach-jz47xx/jz4780/pll.c b/arch/mips/mach-jz47xx/jz4780/pll.c
new file mode 100644
index 0000000..9a46198
--- /dev/null
+++ b/arch/mips/mach-jz47xx/jz4780/pll.c
@@ -0,0 +1,530 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * JZ4780 PLL setup
+ *
+ * Copyright (c) 2013 Imagination Technologies
+ * Author: Paul Burton <paul.burton@imgtec.com>
+ */
+
+#include <config.h>
+#include <common.h>
+#include <asm/io.h>
+#include <mach/jz4780.h>
+
+#define CPM_CPCCR		0x00
+#define CPM_LCR			0x04
+#define CPM_RSR			0x08
+#define CPM_CPPCR		0x0c
+#define CPM_CPAPCR		0x10
+#define CPM_CPMPCR		0x14
+#define CPM_CPEPCR		0x18
+#define CPM_CPVPCR		0x1c
+#define CPM_CLKGR0		0x20
+#define CPM_OPCR		0x24
+#define CPM_CLKGR1		0x28
+#define CPM_DDCDR		0x2c
+#define CPM_VPUCDR		0x30
+#define CPM_CPSPR		0x34
+#define CPM_CPSPPR		0x38
+#define CPM_USBPCR		0x3c
+#define CPM_USBRDT		0x40
+#define CPM_USBVBFIL		0x44
+#define CPM_USBPCR1		0x48
+#define CPM_USBCDR		0x50
+#define CPM_LPCDR		0x54
+#define CPM_I2SCDR		0x60
+#define CPM_LPCDR1		0x64
+#define CPM_MSCCDR		0x68
+#define CPM_UHCCDR		0x6c
+#define CPM_SSICDR		0x74
+#define CPM_CIMCDR		0x7c
+#define CPM_PCMCDR		0x84
+#define CPM_GPUCDR		0x88
+#define CPM_HDMICDR		0x8c
+#define CPM_I2S1CDR		0xa0
+#define CPM_MSCCDR1		0xa4
+#define CPM_MSCCDR2		0xa8
+#define CPM_BCHCDR		0xac
+#define CPM_SPCR0		0xb8
+#define CPM_SPCR1		0xbc
+#define CPM_CPCSR		0xd4
+#define CPM_PSWCST(n)		((0x4 * (n)) + 0x90)
+
+/* Clock control register */
+#define CPM_CPCCR_SEL_SRC_BIT		30
+#define CPM_CPCCR_SEL_SRC_MASK		(0x3 << CPM_CPCCR_SEL_SRC_BIT)
+#define CPM_SRC_SEL_STOP		0
+#define CPM_SRC_SEL_APLL		1
+#define CPM_SRC_SEL_EXCLK		2
+#define CPM_SRC_SEL_RTCLK		3
+#define CPM_CPCCR_SEL_CPLL_BIT		28
+#define CPM_CPCCR_SEL_CPLL_MASK		(0x3 << CPM_CPCCR_SEL_CPLL_BIT)
+#define CPM_CPCCR_SEL_H0PLL_BIT		26
+#define CPM_CPCCR_SEL_H0PLL_MASK	(0x3 << CPM_CPCCR_SEL_H0PLL_BIT)
+#define CPM_CPCCR_SEL_H2PLL_BIT		24
+#define CPM_CPCCR_SEL_H2PLL_MASK	(0x3 << CPM_CPCCR_SEL_H2PLL_BIT)
+#define CPM_PLL_SEL_STOP		0
+#define CPM_PLL_SEL_SRC			1
+#define CPM_PLL_SEL_MPLL		2
+#define CPM_PLL_SEL_EPLL		3
+#define CPM_CPCCR_CE_CPU		(0x1 << 22)
+#define CPM_CPCCR_CE_AHB0		(0x1 << 21)
+#define CPM_CPCCR_CE_AHB2		(0x1 << 20)
+#define CPM_CPCCR_PDIV_BIT		16
+#define CPM_CPCCR_PDIV_MASK		(0xf << CPM_CPCCR_PDIV_BIT)
+#define CPM_CPCCR_H2DIV_BIT		12
+#define CPM_CPCCR_H2DIV_MASK		(0xf << CPM_CPCCR_H2DIV_BIT)
+#define CPM_CPCCR_H0DIV_BIT		8
+#define CPM_CPCCR_H0DIV_MASK		(0x0f << CPM_CPCCR_H0DIV_BIT)
+#define CPM_CPCCR_L2DIV_BIT		4
+#define CPM_CPCCR_L2DIV_MASK		(0x0f << CPM_CPCCR_L2DIV_BIT)
+#define CPM_CPCCR_CDIV_BIT		0
+#define CPM_CPCCR_CDIV_MASK		(0x0f << CPM_CPCCR_CDIV_BIT)
+
+/* Clock Status register */
+#define CPM_CPCSR_H2DIV_BUSY		BIT(2)
+#define CPM_CPCSR_H0DIV_BUSY		BIT(1)
+#define CPM_CPCSR_CDIV_BUSY		BIT(0)
+
+/* PLL control register */
+#define CPM_CPPCR_PLLST_BIT		0
+#define CPM_CPPCR_PLLST_MASK		(0xff << CPM_CPPCR_PLLST_BIT)
+
+/* XPLL control register */
+#define CPM_CPXPCR_XPLLM_BIT		19
+#define CPM_CPXPCR_XPLLM_MASK		(0x1fff << CPM_CPXPCR_XPLLM_BIT)
+#define CPM_CPXPCR_XPLLN_BIT		13
+#define CPM_CPXPCR_XPLLN_MASK		(0x3f << CPM_CPXPCR_XPLLN_BIT)
+#define CPM_CPXPCR_XPLLOD_BIT		9
+#define CPM_CPXPCR_XPLLOD_MASK		(0xf << CPM_CPXPCR_XPLLOD_BIT)
+#define CPM_CPXPCR_XLOCK		BIT(6)
+#define CPM_CPXPCR_XPLL_ON		BIT(4)
+#define CPM_CPXPCR_XF_MODE		BIT(3)
+#define CPM_CPXPCR_XPLLBP		BIT(1)
+#define CPM_CPXPCR_XPLLEN		BIT(0)
+
+/* CPM scratch protected register */
+#define CPM_CPSPPR_BIT			0
+#define CPM_CPSPPR_MASK			(0xffff << CPM_CPSPPR_BIT)
+
+/* USB parameter control register */
+#define CPM_USBPCR_USB_MODE		BIT(31)  /* 1: OTG, 0: UDC*/
+#define CPM_USBPCR_AVLD_REG		BIT(30)
+#define CPM_USBPCR_IDPULLUP_MASK_BIT	28
+#define CPM_USBPCR_IDPULLUP_MASK_MASK	(0x02 << IDPULLUP_MASK_BIT)
+#define CPM_USBPCR_INCR_MASK		BIT(27)
+#define CPM_USBPCR_CLK12_EN		BIT(26)
+#define CPM_USBPCR_COMMONONN		BIT(25)
+#define CPM_USBPCR_VBUSVLDEXT		BIT(24)
+#define CPM_USBPCR_VBUSVLDEXTSEL	BIT(23)
+#define CPM_USBPCR_POR			BIT(22)
+#define CPM_USBPCR_SIDDQ		BIT(21)
+#define CPM_USBPCR_OTG_DISABLE		BIT(20)
+#define CPM_USBPCR_COMPDISTUNE_BIT	17
+#define CPM_USBPCR_COMPDISTUNE_MASK	(0x07 << COMPDISTUNE_BIT)
+#define CPM_USBPCR_OTGTUNE_BIT		14
+#define CPM_USBPCR_OTGTUNE_MASK		(0x07 << OTGTUNE_BIT)
+#define CPM_USBPCR_SQRXTUNE_BIT		11
+#define CPM_USBPCR_SQRXTUNE_MASK	(0x7x << SQRXTUNE_BIT)
+#define CPM_USBPCR_TXFSLSTUNE_BIT	7
+#define CPM_USBPCR_TXFSLSTUNE_MASK	(0x0f << TXFSLSTUNE_BIT)
+#define CPM_USBPCR_TXPREEMPHTUNE	BIT(6)
+#define CPM_USBPCR_TXRISETUNE_BIT	4
+#define CPM_USBPCR_TXRISETUNE_MASK	(0x03 << TXRISETUNE_BIT)
+#define CPM_USBPCR_TXVREFTUNE_BIT	0
+#define CPM_USBPCR_TXVREFTUNE_MASK	(0x0f << TXVREFTUNE_BIT)
+
+/* DDR memory clock divider register */
+#define CPM_DDRCDR_DCS_BIT		30
+#define CPM_DDRCDR_DCS_MASK		(0x3 << CPM_DDRCDR_DCS_BIT)
+#define CPM_DDRCDR_DCS_STOP		(0x0 << CPM_DDRCDR_DCS_BIT)
+#define CPM_DDRCDR_DCS_SRC		(0x1 << CPM_DDRCDR_DCS_BIT)
+#define CPM_DDRCDR_DCS_MPLL		(0x2 << CPM_DDRCDR_DCS_BIT)
+#define CPM_DDRCDR_CE_DDR		BIT(29)
+#define CPM_DDRCDR_DDR_BUSY		BIT(28)
+#define CPM_DDRCDR_DDR_STOP		BIT(27)
+#define CPM_DDRCDR_DDRDIV_BIT		0
+#define CPM_DDRCDR_DDRDIV_MASK		(0xf << CPM_DDRCDR_DDRDIV_BIT)
+
+/* USB reset detect timer register */
+#define CPM_USBRDT_VBFIL_LD_EN		BIT(25)
+#define CPM_USBRDT_IDDIG_EN		BIT(24)
+#define CPM_USBRDT_IDDIG_REG		BIT(23)
+#define CPM_USBRDT_USBRDT_BIT		0
+#define CPM_USBRDT_USBRDT_MASK		(0x7fffff << CPM_USBRDT_USBRDT_BIT)
+
+/* USB OTG PHY clock divider register */
+#define CPM_USBCDR_UCS			BIT(31)
+#define CPM_USBCDR_UPCS			BIT(30)
+#define CPM_USBCDR_CEUSB		BIT(29)
+#define CPM_USBCDR_USB_BUSY		BIT(28)
+#define CPM_USBCDR_OTGDIV_BIT		0
+#define CPM_USBCDR_OTGDIV_MASK		(0xff << CPM_USBCDR_OTGDIV_BIT)
+
+/* I2S device clock divider register */
+#define CPM_I2SCDR_I2CS			BIT(31)
+#define CPM_I2SCDR_I2PCS		BIT(30)
+#define CPM_I2SCDR_I2SDIV_BIT		0
+#define CPM_I2SCDR_I2SDIV_MASK		(0x1ff << CPM_I2SCDR_I2SDIV_BIT)
+
+/* LCD0 pix clock divider register */
+#define CPM_LPCDR_LPCS_BIT		30
+#define CPM_LPCDR_LPCS_MASK		(0x3 << CPM_LPCDR_LPCS_BIT)
+#define CPM_LPCDR_CELCD			BIT(28)
+#define CPM_LPCDR_LCD_BUSY		BIT(27)
+#define CPM_LPCDR_LCD_STOP		BIT(26)
+#define CPM_LPCDR_PIXDIV_BIT		0
+#define CPM_LPCDR_PIXDIV_MASK		(0xff << CPM_LPCDR_PIXDIV_BIT)
+
+/* MSC clock divider register */
+#define CPM_MSCCDR_MPCS_BIT		30
+#define CPM_MSCCDR_MPCS_MASK		(3 << CPM_MSCCDR_MPCS_BIT)
+#define CPM_MSCCDR_MPCS_STOP		(0x0 << CPM_MSCCDR_MPCS_BIT)
+#define CPM_MSCCDR_MPCS_SRC		(0x1 << CPM_MSCCDR_MPCS_BIT)
+#define CPM_MSCCDR_MPCS_MPLL		(0x2 << CPM_MSCCDR_MPCS_BIT)
+#define CPM_MSCCDR_CE			BIT(29)
+#define CPM_MSCCDR_MSC_BUSY		BIT(28)
+#define CPM_MSCCDR_MSC_STOP		BIT(27)
+#define CPM_MSCCDR_MSC_CLK0_SEL		BIT(15)
+#define CPM_MSCCDR_MSCDIV_BIT		0
+#define CPM_MSCCDR_MSCDIV_MASK		(0xff << CPM_MSCCDR_MSCDIV_BIT)
+
+/* UHC 48M clock divider register */
+#define CPM_UHCCDR_UHCS_BIT		30
+#define CPM_UHCCDR_UHCS_MASK		(0x3 << CPM_UHCCDR_UHCS_BIT)
+#define CPM_UHCCDR_UHCS_SRC		(0x0 << CPM_UHCCDR_UHCS_BIT)
+#define CPM_UHCCDR_UHCS_MPLL		(0x1 << CPM_UHCCDR_UHCS_BIT)
+#define CPM_UHCCDR_UHCS_EPLL		(0x2 << CPM_UHCCDR_UHCS_BIT)
+#define CPM_UHCCDR_UHCS_OTG		(0x3 << CPM_UHCCDR_UHCS_BIT)
+#define CPM_UHCCDR_CE_UHC		BIT(29)
+#define CPM_UHCCDR_UHC_BUSY		BIT(28)
+#define CPM_UHCCDR_UHC_STOP		BIT(27)
+#define CPM_UHCCDR_UHCDIV_BIT		0
+#define CPM_UHCCDR_UHCDIV_MASK		(0xff << CPM_UHCCDR_UHCDIV_BIT)
+
+/* SSI clock divider register */
+#define CPM_SSICDR_SCS			BIT(31)
+#define CPM_SSICDR_SSIDIV_BIT		0
+#define CPM_SSICDR_SSIDIV_MASK		(0x3f << CPM_SSICDR_SSIDIV_BIT)
+
+/* CIM MCLK clock divider register */
+#define CPM_CIMCDR_CIMDIV_BIT		0
+#define CPM_CIMCDR_CIMDIV_MASK		(0xff << CPM_CIMCDR_CIMDIV_BIT)
+
+/* GPS clock divider register */
+#define CPM_GPSCDR_GPCS			BIT(31)
+#define CPM_GPSCDR_GPSDIV_BIT		0
+#define CPM_GSPCDR_GPSDIV_MASK		(0xf << CPM_GPSCDR_GPSDIV_BIT)
+
+/* PCM device clock divider register */
+#define CPM_PCMCDR_PCMS			BIT(31)
+#define CPM_PCMCDR_PCMPCS		BIT(30)
+#define CPM_PCMCDR_PCMDIV_BIT		0
+#define CPM_PCMCDR_PCMDIV_MASK		(0x1ff << CPM_PCMCDR_PCMDIV_BIT)
+
+/* GPU clock divider register */
+#define CPM_GPUCDR_GPCS			BIT(31)
+#define CPM_GPUCDR_GPUDIV_BIT		0
+#define CPM_GPUCDR_GPUDIV_MASK		(0x7 << CPM_GPUCDR_GPUDIV_BIT)
+
+/* HDMI clock divider register */
+#define CPM_HDMICDR_HPCS_BIT		30
+#define CPM_HDMICDR_HPCS_MASK		(0x3 << CPM_HDMICDR_HPCS_BIT)
+#define CPM_HDMICDR_CEHDMI		BIT(29)
+#define CPM_HDMICDR_HDMI_BUSY		BIT(28)
+#define CPM_HDMICDR_HDMI_STOP		BIT(26)
+#define CPM_HDMICDR_HDMIDIV_BIT		0
+#define CPM_HDMICDR_HDMIDIV_MASK	(0xff << CPM_HDMICDR_HDMIDIV_BIT)
+
+/* Low Power Control Register */
+#define CPM_LCR_PD_SCPU			BIT(31)
+#define CPM_LCR_PD_VPU			BIT(30)
+#define CPM_LCR_PD_GPU			BIT(29)
+#define CPM_LCR_PD_GPS			BIT(28)
+#define CPM_LCR_SCPUS			BIT(27)
+#define CPM_LCR_VPUS			BIT(26)
+#define CPM_LCR_GPUS			BIT(25)
+#define CPM_LCR_GPSS			BIT(24)
+#define CPM_LCR_GPU_IDLE		BIT(20)
+#define CPM_LCR_PST_BIT			8
+#define CPM_LCR_PST_MASK		(0xfff << CPM_LCR_PST_BIT)
+#define CPM_LCR_DOZE_DUTY_BIT		3
+#define CPM_LCR_DOZE_DUTY_MASK		(0x1f << CPM_LCR_DOZE_DUTY_BIT)
+#define CPM_LCR_DOZE_ON			BIT(2)
+#define CPM_LCR_LPM_BIT			0
+#define CPM_LCR_LPM_MASK		(0x3 << CPM_LCR_LPM_BIT)
+#define CPM_LCR_LPM_IDLE		(0x0 << CPM_LCR_LPM_BIT)
+#define CPM_LCR_LPM_SLEEP		(0x1 << CPM_LCR_LPM_BIT)
+
+/* Clock Gate Register0 */
+#define CPM_CLKGR0_DDR1			BIT(31)
+#define CPM_CLKGR0_DDR0			BIT(30)
+#define CPM_CLKGR0_IPU			BIT(29)
+#define CPM_CLKGR0_LCD1			BIT(28)
+#define CPM_CLKGR0_LCD			BIT(27)
+#define CPM_CLKGR0_CIM			BIT(26)
+#define CPM_CLKGR0_I2C2			BIT(25)
+#define CPM_CLKGR0_UHC			BIT(24)
+#define CPM_CLKGR0_MAC			BIT(23)
+#define CPM_CLKGR0_GPS			BIT(22)
+#define CPM_CLKGR0_PDMAC		BIT(21)
+#define CPM_CLKGR0_SSI2			BIT(20)
+#define CPM_CLKGR0_SSI1			BIT(19)
+#define CPM_CLKGR0_UART3		BIT(18)
+#define CPM_CLKGR0_UART2		BIT(17)
+#define CPM_CLKGR0_UART1		BIT(16)
+#define CPM_CLKGR0_UART0		BIT(15)
+#define CPM_CLKGR0_SADC			BIT(14)
+#define CPM_CLKGR0_KBC			BIT(13)
+#define CPM_CLKGR0_MSC2			BIT(12)
+#define CPM_CLKGR0_MSC1			BIT(11)
+#define CPM_CLKGR0_OWI			BIT(10)
+#define CPM_CLKGR0_TSSI			BIT(9)
+#define CPM_CLKGR0_AIC			BIT(8)
+#define CPM_CLKGR0_SCC			BIT(7)
+#define CPM_CLKGR0_I2C1			BIT(6)
+#define CPM_CLKGR0_I2C0			BIT(5)
+#define CPM_CLKGR0_SSI0			BIT(4)
+#define CPM_CLKGR0_MSC0			BIT(3)
+#define CPM_CLKGR0_OTG			BIT(2)
+#define CPM_CLKGR0_BCH			BIT(1)
+#define CPM_CLKGR0_NEMC			BIT(0)
+
+/* Clock Gate Register1 */
+#define CPM_CLKGR1_P1			BIT(15)
+#define CPM_CLKGR1_X2D			BIT(14)
+#define CPM_CLKGR1_DES			BIT(13)
+#define CPM_CLKGR1_I2C4			BIT(12)
+#define CPM_CLKGR1_AHB			BIT(11)
+#define CPM_CLKGR1_UART4		BIT(10)
+#define CPM_CLKGR1_HDMI			BIT(9)
+#define CPM_CLKGR1_OTG1			BIT(8)
+#define CPM_CLKGR1_GPVLC		BIT(7)
+#define CPM_CLKGR1_AIC1			BIT(6)
+#define CPM_CLKGR1_COMPRES		BIT(5)
+#define CPM_CLKGR1_GPU			BIT(4)
+#define CPM_CLKGR1_PCM			BIT(3)
+#define CPM_CLKGR1_VPU			BIT(2)
+#define CPM_CLKGR1_TSSI1		BIT(1)
+#define CPM_CLKGR1_I2C3			BIT(0)
+
+/* Oscillator and Power Control Register */
+#define CPM_OPCR_O1ST_BIT		8
+#define CPM_OPCR_O1ST_MASK		(0xff << CPM_OPCR_O1ST_BIT)
+#define CPM_OPCR_SPENDN			BIT(7)
+#define CPM_OPCR_GPSEN			BIT(6)
+#define CPM_OPCR_SPENDH			BIT(5)
+#define CPM_OPCR_O1SE			BIT(4)
+#define CPM_OPCR_ERCS			BIT(2) /* 0: select EXCLK/512 clock, 1: RTCLK clock */
+#define CPM_OPCR_USBM			BIT(0) /* 0: select EXCLK/512 clock, 1: RTCLK clock */
+
+/* Reset Status Register */
+#define CPM_RSR_P0R			BIT(2)
+#define CPM_RSR_WR			BIT(1)
+#define CPM_RSR_PR			BIT(0)
+
+/* BCH clock divider register */
+#define CPM_BCHCDR_BPCS_BIT		30
+#define CPM_BCHCDR_BPCS_MASK		(0x3 << CPM_BCHCDR_BPCS_BIT)
+#define CPM_BCHCDR_BPCS_STOP		(0X0 << CPM_BCHCDR_BPCS_BIT)
+#define CPM_BCHCDR_BPCS_SRC_CLK		(0x1 << CPM_BCHCDR_BPCS_BIT)
+#define CPM_BCHCDR_BPCS_MPLL		(0x2 << CPM_BCHCDR_BPCS_BIT)
+#define CPM_BCHCDR_BPCS_EPLL		(0x3 << CPM_BCHCDR_BPCS_BIT)
+#define CPM_BCHCDR_CE_BCH		BIT(29)
+#define CPM_BCHCDR_BCH_BUSY		BIT(28)
+#define CPM_BCHCDR_BCH_STOP		BIT(27)
+#define CPM_BCHCDR_BCHCDR_BIT		0
+#define CPM_BCHCDR_BCHCDR_MASK		(0x7 << CPM_BCHCDR_BCHCDR_BIT)
+
+/* CPM scratch pad protected register(CPSPPR) */
+#define CPSPPR_CPSPR_WRITABLE		0x00005a5a
+#define RECOVERY_SIGNATURE		0x1a1a	/* means "RECY" */
+#define RECOVERY_SIGNATURE_SEC		0x800	/* means "RECY" */
+
+#define REBOOT_SIGNATURE		0x3535	/* means reboot */
+
+/* XPLL control register */
+#define XLOCK		(1 << 6)
+#define XPLL_ON		(1 << 4)
+#define XF_MODE		(1 << 3)
+#define XPLLBP		(1 << 1)
+#define XPLLEN		(1 << 0)
+
+enum PLLS {
+	EXTCLK = 0,
+	APLL,
+	MPLL,
+	EPLL,
+	VPLL,
+};
+
+#define M_N_OD(m, n, od)		\
+		((((m) - 1) << 19) | (((n) - 1) << 13) | (((od) - 1) << 9))
+
+struct cgu_pll_select {
+	u8	reg;
+	u8	pll;
+	u8	pll_shift;
+};
+
+static void pll_init_one(int pll, int m, int n, int od)
+{
+	void __iomem *cpm_regs = (void __iomem *)CPM_BASE;
+	void __iomem *pll_reg = cpm_regs + CPM_CPAPCR + ((pll - 1) * 4);
+
+	setbits_le32(pll_reg, M_N_OD(m, n, od) | XPLLEN);
+
+	/* FIXME */
+	while (!(readl(pll_reg) & XPLL_ON))
+		;
+}
+
+static void cpu_mux_select(int pll)
+{
+	void __iomem *cpm_regs = (void __iomem *)CPM_BASE;
+	u32 clk_ctrl;
+	unsigned int selectplls[] = {
+		CPM_PLL_SEL_STOP,
+		CPM_PLL_SEL_SRC,
+		CPM_PLL_SEL_MPLL,
+		CPM_PLL_SEL_EPLL
+	};
+
+	/* Init CPU, L2CACHE, AHB0, AHB2, APB clock */
+	clk_ctrl = CPM_CPCCR_CE_CPU | CPM_CPCCR_CE_AHB0 | CPM_CPCCR_CE_AHB2 |
+			((6 - 1) << CPM_CPCCR_H2DIV_BIT) |
+			((3 - 1) << CPM_CPCCR_H0DIV_BIT) |
+			((2 - 1) << CPM_CPCCR_L2DIV_BIT) |
+			((1 - 1) << CPM_CPCCR_CDIV_BIT);
+
+	if (CONFIG_SYS_MHZ >= 1000)
+		clk_ctrl |= (12 - 1) << CPM_CPCCR_PDIV_BIT;
+	else
+		clk_ctrl |= (6 - 1) << CPM_CPCCR_PDIV_BIT;
+
+	clrsetbits_le32(cpm_regs + CPM_CPCCR, 0x00ffffff, clk_ctrl);
+
+	while (readl(cpm_regs + CPM_CPCSR) & (CPM_CPCSR_CDIV_BUSY |
+	       CPM_CPCSR_H0DIV_BUSY | CPM_CPCSR_H2DIV_BUSY))
+		;
+
+	clk_ctrl = (selectplls[pll] << CPM_CPCCR_SEL_CPLL_BIT) |
+		   (selectplls[MPLL] << CPM_CPCCR_SEL_H0PLL_BIT) |
+		   (selectplls[MPLL] << CPM_CPCCR_SEL_H2PLL_BIT);
+	if (pll == APLL)
+		clk_ctrl |= CPM_PLL_SEL_SRC << CPM_CPCCR_SEL_SRC_BIT;
+	else
+		clk_ctrl |= CPM_SRC_SEL_EXCLK << CPM_CPCCR_SEL_SRC_BIT;
+
+	clrsetbits_le32(cpm_regs + CPM_CPCCR, 0xff << 24, clk_ctrl);
+}
+
+static void ddr_mux_select(int pll)
+{
+	void __iomem *cpm_regs = (void __iomem *)CPM_BASE;
+	int selectplls[] = { CPM_DDRCDR_DCS_STOP,
+			     CPM_DDRCDR_DCS_SRC,
+			     CPM_DDRCDR_DCS_MPLL};
+
+	writel(selectplls[pll] | CPM_DDRCDR_CE_DDR | (JZ4780_SYS_MEM_DIV - 1),
+	       cpm_regs + CPM_DDCDR);
+
+	while (readl(cpm_regs + CPM_DDCDR) & CPM_DDRCDR_DDR_BUSY)
+		;
+
+	clrbits_le32(cpm_regs + CPM_CLKGR0, CPM_CLKGR0_DDR0);
+
+	mdelay(200);
+}
+
+static void cgu_mux_init(struct cgu_pll_select *cgu, unsigned int num)
+{
+	void __iomem *cpm_regs = (void __iomem *)CPM_BASE;
+	unsigned int selectplls[] = {0, 1, 2, 3, 2, 6};
+	int i;
+
+	for (i = 0; i < num; i++)
+		writel(selectplls[cgu[i].pll] << cgu[i].pll_shift,
+		       cpm_regs + cgu[i].reg);
+}
+
+void pll_init(void)
+{
+	void __iomem *cpm_regs = (void __iomem *)CPM_BASE;
+	struct cgu_pll_select cgu_mux[] = {
+		{ CPM_MSCCDR,  MPLL, 30 },
+		{ CPM_LPCDR,   VPLL, 30 },
+		{ CPM_LPCDR1,  VPLL, 30 },
+		{ CPM_GPUCDR,  MPLL, 30 },
+		{ CPM_HDMICDR, VPLL, 30 },
+		{ CPM_I2SCDR,  EPLL, 30 },
+		{ CPM_BCHCDR,  MPLL, 30 },
+		{ CPM_VPUCDR,  0x1,  30 },
+		{ CPM_UHCCDR,  0x3,  30 },
+		{ CPM_CIMCDR,  0x1,  31 },
+		{ CPM_PCMCDR,  0x5,  29 },
+		{ CPM_SSICDR,  0x3,  30 },
+	};
+
+	/* PLL stable time set to default -- 1ms */
+	clrsetbits_le32(cpm_regs + CPM_CPPCR, 0xfffff, (16 << 8) | 0x20);
+
+	pll_init_one(APLL, JZ4780_APLL_M, JZ4780_APLL_N, JZ4780_APLL_OD);
+	pll_init_one(MPLL, JZ4780_MPLL_M, JZ4780_MPLL_N, JZ4780_MPLL_OD);
+	pll_init_one(VPLL, JZ4780_VPLL_M, JZ4780_VPLL_N, JZ4780_VPLL_OD);
+	pll_init_one(EPLL, JZ4780_EPLL_M, JZ4780_EPLL_N, JZ4780_EPLL_OD);
+
+	cpu_mux_select(MPLL);
+	ddr_mux_select(MPLL);
+	cgu_mux_init(cgu_mux, ARRAY_SIZE(cgu_mux));
+}
+
+const u32 jz4780_clk_get_efuse_clk(void)
+{
+	void __iomem *cpm_regs = (void __iomem *)CPM_BASE;
+	u32 cpccr = readl(cpm_regs + CPM_CPCCR);
+	u32 ahb2_div = ((cpccr & CPM_CPCCR_H2DIV_MASK) >>
+			CPM_CPCCR_H2DIV_BIT) + 1;
+	return JZ4780_SYS_MEM_SPEED / ahb2_div;
+}
+
+void jz4780_clk_ungate_ethernet(void)
+{
+	void __iomem *cpm_regs = (void __iomem *)CPM_BASE;
+
+	clrbits_le32(cpm_regs + CPM_CLKGR0, CPM_CLKGR0_MAC);
+	clrbits_le32(cpm_regs + CPM_CLKGR0, CPM_CLKGR0_NEMC);
+}
+
+void jz4780_clk_ungate_mmc(void)
+{
+	void __iomem *cpm_regs = (void __iomem *)CPM_BASE;
+	u32 msc_cdr = JZ4780_SYS_MEM_SPEED / 24000000 / 2 - 1;
+
+	msc_cdr |= CPM_MSCCDR_MPCS_MPLL | CPM_MSCCDR_CE;
+	writel(msc_cdr, cpm_regs + CPM_MSCCDR);
+	writel(msc_cdr, cpm_regs + CPM_MSCCDR1);
+	writel(msc_cdr, cpm_regs + CPM_MSCCDR2);
+
+	/* The wait_for_bit() won't fit, thus unbounded loop here. */
+	while (readl(cpm_regs + CPM_MSCCDR1) & CPM_MSCCDR_MSC_BUSY)
+		;
+}
+
+void jz4780_clk_ungate_uart(const unsigned int uart)
+{
+	void __iomem *cpm_regs = (void __iomem *)CPM_BASE;
+
+	if (uart == 0)
+		clrbits_le32(cpm_regs + CPM_CLKGR0, CPM_CLKGR0_UART0);
+	else if (uart == 1)
+		clrbits_le32(cpm_regs + CPM_CLKGR0, CPM_CLKGR0_UART1);
+	else if (uart == 2)
+		clrbits_le32(cpm_regs + CPM_CLKGR0, CPM_CLKGR0_UART2);
+	else if (uart == 3)
+		clrbits_le32(cpm_regs + CPM_CLKGR0, CPM_CLKGR0_UART3);
+	else if (uart == 4)
+		clrbits_le32(cpm_regs + CPM_CLKGR1, CPM_CLKGR1_UART4);
+	else
+		printf("%s[%i]: Invalid UART %d\n", __func__, __LINE__, uart);
+}
diff --git a/arch/mips/mach-jz47xx/jz4780/reset.c b/arch/mips/mach-jz47xx/jz4780/reset.c
new file mode 100644
index 0000000..73af347
--- /dev/null
+++ b/arch/mips/mach-jz47xx/jz4780/reset.c
@@ -0,0 +1,53 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * JZ4780 common routines
+ *
+ * Copyright (c) 2013 Imagination Technologies
+ * Author: Paul Burton <paul.burton@imgtec.com>
+ */
+
+#include <config.h>
+#include <common.h>
+#include <asm/io.h>
+#include <mach/jz4780.h>
+
+/* WDT */
+#define WDT_TDR		0x00
+#define WDT_TCER	0x04
+#define WDT_TCNT	0x08
+#define WDT_TCSR	0x0C
+
+/* Register definition */
+#define WDT_TCSR_PRESCALE_BIT	3
+#define WDT_TCSR_PRESCALE_MASK	(0x7 << WDT_TCSR_PRESCALE_BIT)
+  #define WDT_TCSR_PRESCALE1	(0x0 << WDT_TCSR_PRESCALE_BIT)
+  #define WDT_TCSR_PRESCALE4	(0x1 << WDT_TCSR_PRESCALE_BIT)
+  #define WDT_TCSR_PRESCALE16	(0x2 << WDT_TCSR_PRESCALE_BIT)
+  #define WDT_TCSR_PRESCALE64	(0x3 << WDT_TCSR_PRESCALE_BIT)
+  #define WDT_TCSR_PRESCALE256	(0x4 << WDT_TCSR_PRESCALE_BIT)
+  #define WDT_TCSR_PRESCALE1024	(0x5 << WDT_TCSR_PRESCALE_BIT)
+#define WDT_TCSR_EXT_EN		BIT(2)
+#define WDT_TCSR_RTC_EN		BIT(1)
+#define WDT_TCSR_PCK_EN		BIT(0)
+
+#define WDT_TCER_TCEN		BIT(0)
+
+void _machine_restart(void)
+{
+	void __iomem *wdt_regs = (void __iomem *)WDT_BASE;
+
+	/* EXTAL as the timer clock input. */
+	writew(WDT_TCSR_PRESCALE1 | WDT_TCSR_EXT_EN, wdt_regs + WDT_TCSR);
+
+	/* Reset the WDT counter and timeout. */
+	writew(0, wdt_regs + WDT_TCNT);
+	writew(0, wdt_regs + WDT_TDR);
+
+	jz4780_tcu_wdt_start();
+
+	/* WDT start */
+	writeb(WDT_TCER_TCEN, wdt_regs + WDT_TCER);
+
+	for (;;)
+		;
+}
diff --git a/arch/mips/mach-jz47xx/jz4780/sdram.c b/arch/mips/mach-jz47xx/jz4780/sdram.c
new file mode 100644
index 0000000..5b25c8d
--- /dev/null
+++ b/arch/mips/mach-jz47xx/jz4780/sdram.c
@@ -0,0 +1,270 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * JZ4780 DDR initialization
+ *
+ * Copyright (c) 2013 Imagination Technologies
+ * Author: Paul Burton <paul.burton@imgtec.com>
+ *
+ * Based on spl/common/{jz4780_ddr,jz_ddr3_init}.c from X-Boot
+ * Copyright (c) 2006-2013 Ingenic Semiconductor
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <mach/jz4780.h>
+#include <mach/jz4780_dram.h>
+
+static const u32 get_mem_clk(void)
+{
+	const u32 mpll_out = ((u64)JZ4780_SYS_EXTAL * JZ4780_MPLL_M) /
+			     (JZ4780_MPLL_N * JZ4780_MPLL_OD);
+	return mpll_out / JZ4780_SYS_MEM_DIV;
+}
+
+u32 sdram_size(int cs)
+{
+	u32 dw = DDR_DW32 ? 4 : 2;
+	u32 banks = DDR_BANK8 ? 8 : 4;
+	u32 size = 0;
+
+	if ((cs == 0) && DDR_CS0EN) {
+		size = (1 << (DDR_ROW + DDR_COL)) * dw * banks;
+		if (DDR_CS1EN && (size > 0x20000000))
+			size = 0x20000000;
+	} else if ((cs == 1) && DDR_CS1EN) {
+		size = (1 << (DDR_ROW + DDR_COL)) * dw * banks;
+	}
+
+	return size;
+}
+
+static void ddr_cfg_init(void)
+{
+	void __iomem *ddr_ctl_regs = (void __iomem *)DDRC_BASE;
+	u32 ddrc_cfg, tmp;
+
+	tmp = DDR_CL;
+	if (tmp)
+		tmp--;
+	if (tmp > 4)
+		tmp = 4;
+
+	ddrc_cfg = DDRC_CFG_TYPE_DDR3 | DDRC_CFG_IMBA |
+		   DDR_DW32 | DDRC_CFG_MPRT | ((tmp | 0x8) << 2) |
+		   ((DDR_ROW - 12) << 11) | ((DDR_COL - 8) << 8) |
+		   (DDR_CS0EN << 6) | (DDR_BANK8 << 1) |
+		   ((DDR_ROW - 12) << 27) | ((DDR_COL - 8) << 24) |
+		   (DDR_CS1EN << 7) | (DDR_BANK8 << 23);
+
+	if (DDR_BL > 4)
+		ddrc_cfg |= BIT(21);
+
+	writel(ddrc_cfg, ddr_ctl_regs + DDRC_CFG);
+}
+
+static void ddr_phy_init(const struct jz4780_ddr_config *ddr_config)
+{
+	void __iomem *ddr_ctl_regs = (void __iomem *)DDRC_BASE;
+	void __iomem *ddr_phy_regs = ddr_ctl_regs + DDR_PHY_OFFSET;
+	unsigned int count = 0, i;
+	u32 reg, mask;
+
+	writel(DDRP_DCR_TYPE_DDR3 | (DDR_BANK8 << 3), ddr_phy_regs + DDRP_DCR);
+
+	writel(ddr_config->mr0, ddr_phy_regs + DDRP_MR0);
+	writel(ddr_config->mr1, ddr_phy_regs + DDRP_MR1);
+	writel(0, ddr_phy_regs + DDRP_ODTCR);
+	writel(0, ddr_phy_regs + DDRP_MR2);
+
+	writel(ddr_config->ptr0, ddr_phy_regs + DDRP_PTR0);
+	writel(ddr_config->ptr1, ddr_phy_regs + DDRP_PTR1);
+	writel(ddr_config->ptr2, ddr_phy_regs + DDRP_PTR2);
+
+	writel(ddr_config->dtpr0, ddr_phy_regs + DDRP_DTPR0);
+	writel(ddr_config->dtpr1, ddr_phy_regs + DDRP_DTPR1);
+	writel(ddr_config->dtpr2, ddr_phy_regs + DDRP_DTPR2);
+
+	writel(DDRP_PGCR_DQSCFG | (7 << DDRP_PGCR_CKEN_BIT) |
+	       (2 << DDRP_PGCR_CKDV_BIT) |
+	       (DDR_CS0EN | (DDR_CS1EN << 1)) << DDRP_PGCR_RANKEN_BIT |
+	       DDRP_PGCR_ZCKSEL_32 | DDRP_PGCR_PDDISDX,
+	       ddr_phy_regs + DDRP_PGCR);
+
+	for (i = 0; i < 8; i++)
+		clrbits_le32(ddr_phy_regs + DDRP_DXGCR(i), 0x3 << 9);
+
+	count = 0;
+	mask = DDRP_PGSR_IDONE | DDRP_PGSR_DLDONE | DDRP_PGSR_ZCDONE;
+	for (;;) {
+		reg = readl(ddr_phy_regs + DDRP_PGSR);
+		if ((reg == mask) || (reg == 0x1f))
+			break;
+		if (count++ == 10000)
+			hang();
+	}
+
+	/* DQS extension and early set to 1 */
+	clrsetbits_le32(ddr_phy_regs + DDRP_DSGCR, 0x7E << 4, 0x12 << 4);
+
+	/* 500 pull up and 500 pull down */
+	clrsetbits_le32(ddr_phy_regs + DDRP_DXCCR, 0xFF << 4, 0xC4 << 4);
+
+	/* Initialise phy */
+	writel(DDRP_PIR_INIT | DDRP_PIR_DRAMINT | DDRP_PIR_DRAMRST,
+	       ddr_phy_regs + DDRP_PIR);
+
+	count = 0;
+	mask |= DDRP_PGSR_DIDONE;
+	for (;;) {
+		reg = readl(ddr_phy_regs + DDRP_PGSR);
+		if ((reg == mask) || (reg == 0x1f))
+			break;
+		if (count++ == 20000)
+			hang();
+	}
+
+	writel(DDRP_PIR_INIT | DDRP_PIR_QSTRN, ddr_phy_regs + DDRP_PIR);
+
+	count = 0;
+	mask |= DDRP_PGSR_DTDONE;
+	for (;;) {
+		reg = readl(ddr_phy_regs + DDRP_PGSR);
+		if (reg == mask)
+			break;
+		if (count++ != 50000)
+			continue;
+		reg &= DDRP_PGSR_DTDONE | DDRP_PGSR_DTERR | DDRP_PGSR_DTIERR;
+		if (reg)
+			hang();
+		count = 0;
+	}
+
+	/* Override impedance */
+	clrsetbits_le32(ddr_phy_regs + DDRP_ZQXCR0(0), 0x3ff,
+		((ddr_config->pullup & 0x1f) << DDRP_ZQXCR_PULLUP_IMPE_BIT) |
+		((ddr_config->pulldn & 0x1f) << DDRP_ZQXCR_PULLDOWN_IMPE_BIT) |
+		DDRP_ZQXCR_ZDEN);
+}
+
+#define JZBIT(bit) ((bit % 4) * 8)
+#define JZMASK(bit) (0x1f << JZBIT(bit))
+
+static void remap_swap(int a, int b)
+{
+	void __iomem *ddr_ctl_regs = (void __iomem *)DDRC_BASE;
+	u32 remmap[2], tmp[2];
+
+	remmap[0] = readl(ddr_ctl_regs + DDRC_REMMAP(a / 4));
+	remmap[1] = readl(ddr_ctl_regs + DDRC_REMMAP(b / 4));
+
+	tmp[0] = (remmap[0] & JZMASK(a)) >> JZBIT(a);
+	tmp[1] = (remmap[1] & JZMASK(b)) >> JZBIT(b);
+
+	remmap[0] &= ~JZMASK(a);
+	remmap[1] &= ~JZMASK(b);
+
+	writel(remmap[0] | (tmp[1] << JZBIT(a)),
+	       ddr_ctl_regs + DDRC_REMMAP(a / 4));
+	writel(remmap[1] | (tmp[0] << JZBIT(b)),
+	       ddr_ctl_regs + DDRC_REMMAP(b / 4));
+}
+
+static void mem_remap(void)
+{
+	u32 start = (DDR_ROW + DDR_COL + (DDR_DW32 ? 4 : 2) / 2) - 12;
+	u32 num = DDR_BANK8 ? 3 : 2;
+
+	if (DDR_CS0EN && DDR_CS1EN)
+		num++;
+
+	for (; num > 0; num--)
+		remap_swap(0 + num - 1, start + num - 1);
+}
+
+/* Fetch DRAM config from board file */
+__weak const struct jz4780_ddr_config *jz4780_get_ddr_config(void)
+{
+	return NULL;
+}
+
+void sdram_init(void)
+{
+	const struct jz4780_ddr_config *ddr_config = jz4780_get_ddr_config();
+	void __iomem *ddr_ctl_regs = (void __iomem *)DDRC_BASE;
+	void __iomem *ddr_phy_regs = ddr_ctl_regs + DDR_PHY_OFFSET;
+	void __iomem *cpm_regs = (void __iomem *)CPM_BASE;
+	u32 mem_clk, tmp, i;
+	u32 mem_base0, mem_base1;
+	u32 mem_mask0, mem_mask1;
+	u32 mem_size0, mem_size1;
+
+	if (!ddr_config)
+		hang();
+
+	/* Reset DLL in DDR PHY */
+	writel(0x3, cpm_regs + 0xd0);
+	mdelay(400);
+	writel(0x1, cpm_regs + 0xd0);
+	mdelay(400);
+
+	/* Enter reset */
+	writel(0xf << 20, ddr_ctl_regs + DDRC_CTRL);
+
+	mem_clk = get_mem_clk();
+
+	tmp = 1000000000 / mem_clk;
+	if (1000000000 % mem_clk)
+		tmp++;
+	tmp = DDR_tREFI / tmp;
+	tmp = tmp / (16 * (1 << DDR_CLK_DIV)) - 1;
+	if (tmp > 0xff)
+		tmp = 0xff;
+	if (tmp < 1)
+		tmp = 1;
+
+	writel(0x0, ddr_ctl_regs + DDRC_CTRL);
+
+	writel(0x150000, ddr_phy_regs + DDRP_DTAR);
+	ddr_phy_init(ddr_config);
+
+	writel(DDRC_CTRL_CKE | DDRC_CTRL_ALH, ddr_ctl_regs + DDRC_CTRL);
+	writel(0x0, ddr_ctl_regs + DDRC_CTRL);
+
+	ddr_cfg_init();
+
+	for (i = 0; i < 6; i++)
+		writel(ddr_config->timing[i], ddr_ctl_regs + DDRC_TIMING(i));
+
+	mem_size0 = sdram_size(0);
+	mem_size1 = sdram_size(1);
+
+	if (!mem_size1 && mem_size0 > 0x20000000) {
+		mem_base0 = 0x0;
+		mem_mask0 = ~(((mem_size0 * 2) >> 24) - 1) & DDRC_MMAP_MASK_MASK;
+	} else {
+		mem_base0 = (DDR_MEM_PHY_BASE >> 24) & 0xff;
+		mem_mask0 = ~((mem_size0 >> 24) - 1) & DDRC_MMAP_MASK_MASK;
+	}
+
+	if (mem_size1) {
+		mem_mask1 = ~((mem_size1 >> 24) - 1) & DDRC_MMAP_MASK_MASK;
+		mem_base1 = ((DDR_MEM_PHY_BASE + mem_size0) >> 24) & 0xff;
+	} else {
+		mem_mask1 = 0;
+		mem_base1 = 0xff;
+	}
+
+	writel(mem_base0 << DDRC_MMAP_BASE_BIT | mem_mask0,
+	       ddr_ctl_regs + DDRC_MMAP0);
+	writel(mem_base1 << DDRC_MMAP_BASE_BIT | mem_mask1,
+	       ddr_ctl_regs + DDRC_MMAP1);
+	writel(DDRC_CTRL_CKE | DDRC_CTRL_ALH, ddr_ctl_regs + DDRC_CTRL);
+	writel((DDR_CLK_DIV << 1) | DDRC_REFCNT_REF_EN |
+	       (tmp << DDRC_REFCNT_CON_BIT),
+	       ddr_ctl_regs + DDRC_REFCNT);
+	writel((1 << 15) | (4 << 12) | (1 << 11) | (1 << 8) | (0 << 6) |
+	       (1 << 4) | (1 << 3) | (1 << 2) | (1 << 1),
+	       ddr_ctl_regs + DDRC_CTRL);
+	mem_remap();
+	clrbits_le32(ddr_ctl_regs + DDRC_ST, 0x40);
+}
diff --git a/arch/mips/mach-jz47xx/jz4780/timer.c b/arch/mips/mach-jz47xx/jz4780/timer.c
new file mode 100644
index 0000000..a689b9d
--- /dev/null
+++ b/arch/mips/mach-jz47xx/jz4780/timer.c
@@ -0,0 +1,239 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * JZ4780 timer
+ *
+ * Copyright (c) 2013 Imagination Technologies
+ * Author: Paul Burton <paul.burton@imgtec.com>
+ */
+
+#include <config.h>
+#include <common.h>
+#include <div64.h>
+#include <asm/io.h>
+#include <asm/mipsregs.h>
+#include <mach/jz4780.h>
+
+#define TCU_TSR		0x1C	/* Timer Stop Register */
+#define TCU_TSSR	0x2C	/* Timer Stop Set Register */
+#define TCU_TSCR	0x3C	/* Timer Stop Clear Register */
+#define TCU_TER		0x10	/* Timer Counter Enable Register */
+#define TCU_TESR	0x14	/* Timer Counter Enable Set Register */
+#define TCU_TECR	0x18	/* Timer Counter Enable Clear Register */
+#define TCU_TFR		0x20	/* Timer Flag Register */
+#define TCU_TFSR	0x24	/* Timer Flag Set Register */
+#define TCU_TFCR	0x28	/* Timer Flag Clear Register */
+#define TCU_TMR		0x30	/* Timer Mask Register */
+#define TCU_TMSR	0x34	/* Timer Mask Set Register */
+#define TCU_TMCR	0x38	/* Timer Mask Clear Register */
+/* n = 0,1,2,3,4,5 */
+#define TCU_TDFR(n)	(0x40 + (n) * 0x10)	/* Timer Data Full Reg */
+#define TCU_TDHR(n)	(0x44 + (n) * 0x10)	/* Timer Data Half Reg */
+#define TCU_TCNT(n)	(0x48 + (n) * 0x10)	/* Timer Counter Reg */
+#define TCU_TCSR(n)	(0x4C + (n) * 0x10)	/* Timer Control Reg */
+
+#define TCU_OSTCNTL	0xe4
+#define TCU_OSTCNTH	0xe8
+#define TCU_OSTCSR	0xec
+#define TCU_OSTCNTHBUF	0xfc
+
+/* Register definitions */
+#define TCU_TCSR_PWM_SD		BIT(9)
+#define TCU_TCSR_PWM_INITL_HIGH	BIT(8)
+#define TCU_TCSR_PWM_EN		BIT(7)
+#define TCU_TCSR_PRESCALE_BIT	3
+#define TCU_TCSR_PRESCALE_MASK	(0x7 << TCU_TCSR_PRESCALE_BIT)
+#define TCU_TCSR_PRESCALE1	(0x0 << TCU_TCSR_PRESCALE_BIT)
+#define TCU_TCSR_PRESCALE4	(0x1 << TCU_TCSR_PRESCALE_BIT)
+#define TCU_TCSR_PRESCALE16	(0x2 << TCU_TCSR_PRESCALE_BIT)
+#define TCU_TCSR_PRESCALE64	(0x3 << TCU_TCSR_PRESCALE_BIT)
+#define TCU_TCSR_PRESCALE256	(0x4 << TCU_TCSR_PRESCALE_BIT)
+#define TCU_TCSR_PRESCALE1024	(0x5 << TCU_TCSR_PRESCALE_BIT)
+#define TCU_TCSR_EXT_EN		BIT(2)
+#define TCU_TCSR_RTC_EN		BIT(1)
+#define TCU_TCSR_PCK_EN		BIT(0)
+
+#define TCU_TER_TCEN5		BIT(5)
+#define TCU_TER_TCEN4		BIT(4)
+#define TCU_TER_TCEN3		BIT(3)
+#define TCU_TER_TCEN2		BIT(2)
+#define TCU_TER_TCEN1		BIT(1)
+#define TCU_TER_TCEN0		BIT(0)
+
+#define TCU_TESR_TCST5		BIT(5)
+#define TCU_TESR_TCST4		BIT(4)
+#define TCU_TESR_TCST3		BIT(3)
+#define TCU_TESR_TCST2		BIT(2)
+#define TCU_TESR_TCST1		BIT(1)
+#define TCU_TESR_TCST0		BIT(0)
+
+#define TCU_TECR_TCCL5		BIT(5)
+#define TCU_TECR_TCCL4		BIT(4)
+#define TCU_TECR_TCCL3		BIT(3)
+#define TCU_TECR_TCCL2		BIT(2)
+#define TCU_TECR_TCCL1		BIT(1)
+#define TCU_TECR_TCCL0		BIT(0)
+
+#define TCU_TFR_HFLAG5		BIT(21)
+#define TCU_TFR_HFLAG4		BIT(20)
+#define TCU_TFR_HFLAG3		BIT(19)
+#define TCU_TFR_HFLAG2		BIT(18)
+#define TCU_TFR_HFLAG1		BIT(17)
+#define TCU_TFR_HFLAG0		BIT(16)
+#define TCU_TFR_FFLAG5		BIT(5)
+#define TCU_TFR_FFLAG4		BIT(4)
+#define TCU_TFR_FFLAG3		BIT(3)
+#define TCU_TFR_FFLAG2		BIT(2)
+#define TCU_TFR_FFLAG1		BIT(1)
+#define TCU_TFR_FFLAG0		BIT(0)
+
+#define TCU_TFSR_HFLAG5		BIT(21)
+#define TCU_TFSR_HFLAG4		BIT(20)
+#define TCU_TFSR_HFLAG3		BIT(19)
+#define TCU_TFSR_HFLAG2		BIT(18)
+#define TCU_TFSR_HFLAG1		BIT(17)
+#define TCU_TFSR_HFLAG0		BIT(16)
+#define TCU_TFSR_FFLAG5		BIT(5)
+#define TCU_TFSR_FFLAG4		BIT(4)
+#define TCU_TFSR_FFLAG3		BIT(3)
+#define TCU_TFSR_FFLAG2		BIT(2)
+#define TCU_TFSR_FFLAG1		BIT(1)
+#define TCU_TFSR_FFLAG0		BIT(0)
+
+#define TCU_TFCR_HFLAG5		BIT(21)
+#define TCU_TFCR_HFLAG4		BIT(20)
+#define TCU_TFCR_HFLAG3		BIT(19)
+#define TCU_TFCR_HFLAG2		BIT(18)
+#define TCU_TFCR_HFLAG1		BIT(17)
+#define TCU_TFCR_HFLAG0		BIT(16)
+#define TCU_TFCR_FFLAG5		BIT(5)
+#define TCU_TFCR_FFLAG4		BIT(4)
+#define TCU_TFCR_FFLAG3		BIT(3)
+#define TCU_TFCR_FFLAG2		BIT(2)
+#define TCU_TFCR_FFLAG1		BIT(1)
+#define TCU_TFCR_FFLAG0		BIT(0)
+
+#define TCU_TMR_HMASK5		BIT(21)
+#define TCU_TMR_HMASK4		BIT(20)
+#define TCU_TMR_HMASK3		BIT(19)
+#define TCU_TMR_HMASK2		BIT(18)
+#define TCU_TMR_HMASK1		BIT(17)
+#define TCU_TMR_HMASK0		BIT(16)
+#define TCU_TMR_FMASK5		BIT(5)
+#define TCU_TMR_FMASK4		BIT(4)
+#define TCU_TMR_FMASK3		BIT(3)
+#define TCU_TMR_FMASK2		BIT(2)
+#define TCU_TMR_FMASK1		BIT(1)
+#define TCU_TMR_FMASK0		BIT(0)
+
+#define TCU_TMSR_HMST5		BIT(21)
+#define TCU_TMSR_HMST4		BIT(20)
+#define TCU_TMSR_HMST3		BIT(19)
+#define TCU_TMSR_HMST2		BIT(18)
+#define TCU_TMSR_HMST1		BIT(17)
+#define TCU_TMSR_HMST0		BIT(16)
+#define TCU_TMSR_FMST5		BIT(5)
+#define TCU_TMSR_FMST4		BIT(4)
+#define TCU_TMSR_FMST3		BIT(3)
+#define TCU_TMSR_FMST2		BIT(2)
+#define TCU_TMSR_FMST1		BIT(1)
+#define TCU_TMSR_FMST0		BIT(0)
+
+#define TCU_TMCR_HMCL5		BIT(21)
+#define TCU_TMCR_HMCL4		BIT(20)
+#define TCU_TMCR_HMCL3		BIT(19)
+#define TCU_TMCR_HMCL2		BIT(18)
+#define TCU_TMCR_HMCL1		BIT(17)
+#define TCU_TMCR_HMCL0		BIT(16)
+#define TCU_TMCR_FMCL5		BIT(5)
+#define TCU_TMCR_FMCL4		BIT(4)
+#define TCU_TMCR_FMCL3		BIT(3)
+#define TCU_TMCR_FMCL2		BIT(2)
+#define TCU_TMCR_FMCL1		BIT(1)
+#define TCU_TMCR_FMCL0		BIT(0)
+
+#define TCU_TSR_WDTS		BIT(16)
+#define TCU_TSR_STOP5		BIT(5)
+#define TCU_TSR_STOP4		BIT(4)
+#define TCU_TSR_STOP3		BIT(3)
+#define TCU_TSR_STOP2		BIT(2)
+#define TCU_TSR_STOP1		BIT(1)
+#define TCU_TSR_STOP0		BIT(0)
+
+#define TCU_TSSR_WDTSS		BIT(16)
+#define TCU_TSSR_STPS5		BIT(5)
+#define TCU_TSSR_STPS4		BIT(4)
+#define TCU_TSSR_STPS3		BIT(3)
+#define TCU_TSSR_STPS2		BIT(2)
+#define TCU_TSSR_STPS1		BIT(1)
+#define TCU_TSSR_STPS0		BIT(0)
+
+#define TCU_TSSR_WDTSC		BIT(16)
+#define TCU_TSSR_STPC5		BIT(5)
+#define TCU_TSSR_STPC4		BIT(4)
+#define TCU_TSSR_STPC3		BIT(3)
+#define TCU_TSSR_STPC2		BIT(2)
+#define TCU_TSSR_STPC1		BIT(1)
+#define TCU_TSSR_STPC0		BIT(0)
+
+#define TER_OSTEN		BIT(15)
+
+#define OSTCSR_CNT_MD		BIT(15)
+#define OSTCSR_SD		BIT(9)
+#define OSTCSR_PRESCALE_16	(0x2 << 3)
+#define OSTCSR_EXT_EN		BIT(2)
+
+int timer_init(void)
+{
+	void __iomem *regs = (void __iomem *)TCU_BASE;
+
+	writel(OSTCSR_SD, regs + TCU_OSTCSR);
+	reset_timer();
+	writel(OSTCSR_CNT_MD | OSTCSR_EXT_EN | OSTCSR_PRESCALE_16,
+	       regs + TCU_OSTCSR);
+	writew(TER_OSTEN, regs + TCU_TESR);
+	return 0;
+}
+
+void reset_timer(void)
+{
+	void __iomem *regs = (void __iomem *)TCU_BASE;
+
+	writel(0, regs + TCU_OSTCNTH);
+	writel(0, regs + TCU_OSTCNTL);
+}
+
+static u64 get_timer64(void)
+{
+	void __iomem *regs = (void __iomem *)TCU_BASE;
+	u32 low = readl(regs + TCU_OSTCNTL);
+	u32 high = readl(regs + TCU_OSTCNTHBUF);
+
+	return ((u64)high << 32) | low;
+}
+
+ulong get_timer(ulong base)
+{
+	return lldiv(get_timer64(), 3000) - base;
+}
+
+void __udelay(unsigned long usec)
+{
+	/* OST count increments at 3MHz */
+	u64 end = get_timer64() + ((u64)usec * 3);
+
+	while (get_timer64() < end)
+		;
+}
+
+unsigned long long get_ticks(void)
+{
+	return get_timer64();
+}
+
+void jz4780_tcu_wdt_start(void)
+{
+	void __iomem *tcu_regs = (void __iomem *)TCU_BASE;
+
+	/* Enable WDT clock */
+	writel(TCU_TSSR_WDTSC, tcu_regs + TCU_TSCR);
+}
diff --git a/arch/mips/mach-jz47xx/jz4780/u-boot-spl.lds b/arch/mips/mach-jz47xx/jz4780/u-boot-spl.lds
new file mode 100644
index 0000000..347cabc
--- /dev/null
+++ b/arch/mips/mach-jz47xx/jz4780/u-boot-spl.lds
@@ -0,0 +1,50 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+
+MEMORY { .sram : ORIGIN = CONFIG_SPL_TEXT_BASE,\
+		LENGTH = CONFIG_SPL_MAX_SIZE }
+MEMORY { .sdram : ORIGIN = CONFIG_SPL_BSS_START_ADDR, \
+		LENGTH = CONFIG_SPL_BSS_MAX_SIZE }
+
+OUTPUT_ARCH(mips)
+ENTRY(_start)
+SECTIONS
+{
+	.text :
+	{
+		__image_copy_start = .;
+		arch/mips/mach-jz47xx/start.o	(.text*)
+		*(.text*)
+	} >.sram
+
+	. = ALIGN(4);
+	.rodata : { *(SORT_BY_ALIGNMENT(.rodata*)) } >.sram
+
+	. = ALIGN(4);
+	.data : { *(SORT_BY_ALIGNMENT(.data*)) } >.sram
+
+	. = ALIGN(4);
+	__image_copy_end = .;
+
+	.bss : {
+		. = ALIGN(4);
+		__bss_start = .;
+		*(.sbss.*)
+		*(.bss.*)
+		*(COMMON)
+		. = ALIGN(4);
+		__bss_end = .;
+	} >.sdram
+
+	/DISCARD/ : {
+		*(.dynbss)
+		*(.dynstr)
+		*(.dynamic)
+		*(.interp)
+		*(.hash)
+		*(.gnu.*)
+		*(.plt)
+		*(.got.plt)
+		*(.rel.plt)
+		*(.rel.dyn)
+	}
+}
diff --git a/arch/mips/mach-jz47xx/start.S b/arch/mips/mach-jz47xx/start.S
new file mode 100644
index 0000000..760d021
--- /dev/null
+++ b/arch/mips/mach-jz47xx/start.S
@@ -0,0 +1,98 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ *  Startup Code for MIPS32 XBURST CPU-core
+ *
+ *  Copyright (c) 2010 Xiangfu Liu <xiangfu@sharism.cc>
+ */
+
+#include <config.h>
+#include <asm/regdef.h>
+#include <asm/mipsregs.h>
+#include <asm/addrspace.h>
+#include <asm/cacheops.h>
+#include <asm/cache.h>
+#include <mach/jz4780.h>
+
+	.set noreorder
+
+	.globl _start
+	.text
+_start:
+#ifdef CONFIG_SPL_BUILD
+
+	/* magic value ("MSPL") */
+	.word 0x4d53504c
+
+	/* Invalidate BTB */
+	mfc0	t0, CP0_CONFIG, 7
+	nop
+	ori	t0, 2
+	mtc0	t0, CP0_CONFIG, 7
+	nop
+
+	/*
+	 * CU0=UM=EXL=IE=0, BEV=ERL=1, IP2~7=1
+	 */
+	li	t0, 0x0040FC04
+	mtc0	t0, CP0_STATUS
+
+	/* CAUSE register */
+	/* IV=1, use the specical interrupt vector (0x200) */
+	li	t1, 0x00800000
+	mtc0	t1, CP0_CAUSE
+
+#ifdef CONFIG_SOC_JZ4780
+	/* enable bridge radical mode */
+	la	t0, CPM_BASE
+	lw	t1, 0x24(t0)
+	ori	t1, t1, 0x22
+	sw	t1, 0x24(t0)
+#endif
+
+	/* Set up stack */
+	li	sp, CONFIG_SPL_STACK
+
+	b		board_init_f
+	 nop
+
+#ifdef CONFIG_SOC_JZ4780
+
+	.globl enable_caches
+	.ent enable_caches
+enable_caches:
+	mtc0	zero, CP0_TAGLO
+	mtc0	zero, CP0_TAGHI
+
+	li	t0, KSEG0
+	addu	t1, t0, CONFIG_SYS_DCACHE_SIZE
+1:
+	cache	INDEX_STORE_TAG_D, 0(t0)
+	bne	t0, t1, 1b
+	addiu	t0, t0, CONFIG_SYS_CACHELINE_SIZE
+
+	li	t0, KSEG0
+	addu	t1, t0, CONFIG_SYS_ICACHE_SIZE
+2:
+	cache	INDEX_STORE_TAG_I, 0(t0)
+	bne	t0, t1, 2b
+	addiu	t0, t0, CONFIG_SYS_CACHELINE_SIZE
+
+	/* Invalidate BTB */
+	mfc0	t0, CP0_CONFIG, 7
+	nop
+	ori	t0, 2
+	mtc0	t0, CP0_CONFIG, 7
+	nop
+
+	/* Enable caches */
+	li	t0, CONF_CM_CACHABLE_NONCOHERENT
+	mtc0	t0, CP0_CONFIG
+	nop
+
+	jr	ra
+	 nop
+
+	.end enable_caches
+
+#endif /* CONFIG_SOC_JZ4780 */
+#endif /* !CONFIG_SPL_BUILD */
diff --git a/include/dt-bindings/clock/jz4780-cgu.h b/include/dt-bindings/clock/jz4780-cgu.h
new file mode 100644
index 0000000..73214c5
--- /dev/null
+++ b/include/dt-bindings/clock/jz4780-cgu.h
@@ -0,0 +1,89 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * This header provides clock numbers for the ingenic,jz4780-cgu DT binding.
+ *
+ * They are roughly ordered as:
+ *   - external clocks
+ *   - PLLs
+ *   - muxes/dividers in the order they appear in the jz4780 programmers manual
+ *   - gates in order of their bit in the CLKGR* registers
+ */
+
+#ifndef __DT_BINDINGS_CLOCK_JZ4780_CGU_H__
+#define __DT_BINDINGS_CLOCK_JZ4780_CGU_H__
+
+#define JZ4780_CLK_EXCLK	0
+#define JZ4780_CLK_RTCLK	1
+#define JZ4780_CLK_APLL		2
+#define JZ4780_CLK_MPLL		3
+#define JZ4780_CLK_EPLL		4
+#define JZ4780_CLK_VPLL		5
+#define JZ4780_CLK_OTGPHY	6
+#define JZ4780_CLK_SCLKA	7
+#define JZ4780_CLK_CPUMUX	8
+#define JZ4780_CLK_CPU		9
+#define JZ4780_CLK_L2CACHE	10
+#define JZ4780_CLK_AHB0		11
+#define JZ4780_CLK_AHB2PMUX	12
+#define JZ4780_CLK_AHB2		13
+#define JZ4780_CLK_PCLK		14
+#define JZ4780_CLK_DDR		15
+#define JZ4780_CLK_VPU		16
+#define JZ4780_CLK_I2SPLL	17
+#define JZ4780_CLK_I2S		18
+#define JZ4780_CLK_LCD0PIXCLK	19
+#define JZ4780_CLK_LCD1PIXCLK	20
+#define JZ4780_CLK_MSCMUX	21
+#define JZ4780_CLK_MSC0		22
+#define JZ4780_CLK_MSC1		23
+#define JZ4780_CLK_MSC2		24
+#define JZ4780_CLK_UHC		25
+#define JZ4780_CLK_SSIPLL	26
+#define JZ4780_CLK_SSI		27
+#define JZ4780_CLK_CIMMCLK	28
+#define JZ4780_CLK_PCMPLL	29
+#define JZ4780_CLK_PCM		30
+#define JZ4780_CLK_GPU		31
+#define JZ4780_CLK_HDMI		32
+#define JZ4780_CLK_BCH		33
+#define JZ4780_CLK_NEMC		34
+#define JZ4780_CLK_OTG0		35
+#define JZ4780_CLK_SSI0		36
+#define JZ4780_CLK_SMB0		37
+#define JZ4780_CLK_SMB1		38
+#define JZ4780_CLK_SCC		39
+#define JZ4780_CLK_AIC		40
+#define JZ4780_CLK_TSSI0	41
+#define JZ4780_CLK_OWI		42
+#define JZ4780_CLK_KBC		43
+#define JZ4780_CLK_SADC		44
+#define JZ4780_CLK_UART0	45
+#define JZ4780_CLK_UART1	46
+#define JZ4780_CLK_UART2	47
+#define JZ4780_CLK_UART3	48
+#define JZ4780_CLK_SSI1		49
+#define JZ4780_CLK_SSI2		50
+#define JZ4780_CLK_PDMA		51
+#define JZ4780_CLK_GPS		52
+#define JZ4780_CLK_MAC		53
+#define JZ4780_CLK_SMB2		54
+#define JZ4780_CLK_CIM		55
+#define JZ4780_CLK_LCD		56
+#define JZ4780_CLK_TVE		57
+#define JZ4780_CLK_IPU		58
+#define JZ4780_CLK_DDR0		59
+#define JZ4780_CLK_DDR1		60
+#define JZ4780_CLK_SMB3		61
+#define JZ4780_CLK_TSSI1	62
+#define JZ4780_CLK_COMPRESS	63
+#define JZ4780_CLK_AIC1		64
+#define JZ4780_CLK_GPVLC	65
+#define JZ4780_CLK_OTG1		66
+#define JZ4780_CLK_UART4	67
+#define JZ4780_CLK_AHBMON	68
+#define JZ4780_CLK_SMB4		69
+#define JZ4780_CLK_DES		70
+#define JZ4780_CLK_X2D		71
+#define JZ4780_CLK_CORE1	72
+
+#endif /* __DT_BINDINGS_CLOCK_JZ4780_CGU_H__ */