diff --git a/api/api.c b/api/api.c
index 457dc36f6fc4e76a9ff5356414e9c0ba67fe7466..8a1433af78a98357f8e7ac58773c2b32a49aebad 100644
--- a/api/api.c
+++ b/api/api.c
@@ -52,7 +52,7 @@ static int API_getc(va_list ap)
 {
 	int *c;
 
-	if ((c = (int *)va_arg(ap, u_int32_t)) == NULL)
+	if ((c = (int *)va_arg(ap, uintptr_t)) == NULL)
 		return API_EINVAL;
 
 	*c = getc();
@@ -68,7 +68,7 @@ static int API_tstc(va_list ap)
 {
 	int *t;
 
-	if ((t = (int *)va_arg(ap, u_int32_t)) == NULL)
+	if ((t = (int *)va_arg(ap, uintptr_t)) == NULL)
 		return API_EINVAL;
 
 	*t = tstc();
@@ -84,7 +84,7 @@ static int API_putc(va_list ap)
 {
 	char *c;
 
-	if ((c = (char *)va_arg(ap, u_int32_t)) == NULL)
+	if ((c = (char *)va_arg(ap, uintptr_t)) == NULL)
 		return API_EINVAL;
 
 	putc(*c);
@@ -100,7 +100,7 @@ static int API_puts(va_list ap)
 {
 	char *s;
 
-	if ((s = (char *)va_arg(ap, u_int32_t)) == NULL)
+	if ((s = (char *)va_arg(ap, uintptr_t)) == NULL)
 		return API_EINVAL;
 
 	puts(s);
@@ -132,7 +132,7 @@ static int API_get_sys_info(va_list ap)
 {
 	struct sys_info *si;
 
-	si = (struct sys_info *)va_arg(ap, u_int32_t);
+	si = (struct sys_info *)va_arg(ap, uintptr_t);
 	if (si == NULL)
 		return API_ENOMEM;
 
@@ -148,7 +148,7 @@ static int API_udelay(va_list ap)
 {
 	unsigned long *d;
 
-	if ((d = (unsigned long *)va_arg(ap, u_int32_t)) == NULL)
+	if ((d = (unsigned long *)va_arg(ap, unsigned long)) == NULL)
 		return API_EINVAL;
 
 	udelay(*d);
@@ -164,11 +164,11 @@ static int API_get_timer(va_list ap)
 {
 	unsigned long *base, *cur;
 
-	cur = (unsigned long *)va_arg(ap, u_int32_t);
+	cur = (unsigned long *)va_arg(ap, unsigned long);
 	if (cur == NULL)
 		return API_EINVAL;
 
-	base = (unsigned long *)va_arg(ap, u_int32_t);
+	base = (unsigned long *)va_arg(ap, unsigned long);
 	if (base == NULL)
 		return API_EINVAL;
 
@@ -199,7 +199,7 @@ static int API_dev_enum(va_list ap)
 	struct device_info *di;
 
 	/* arg is ptr to the device_info struct we are going to fill out */
-	di = (struct device_info *)va_arg(ap, u_int32_t);
+	di = (struct device_info *)va_arg(ap, uintptr_t);
 	if (di == NULL)
 		return API_EINVAL;
 
@@ -233,7 +233,7 @@ static int API_dev_open(va_list ap)
 	int err = 0;
 
 	/* arg is ptr to the device_info struct */
-	di = (struct device_info *)va_arg(ap, u_int32_t);
+	di = (struct device_info *)va_arg(ap, uintptr_t);
 	if (di == NULL)
 		return API_EINVAL;
 
@@ -265,7 +265,7 @@ static int API_dev_close(va_list ap)
 	int err = 0;
 
 	/* arg is ptr to the device_info struct */
-	di = (struct device_info *)va_arg(ap, u_int32_t);
+	di = (struct device_info *)va_arg(ap, uintptr_t);
 	if (di == NULL)
 		return API_EINVAL;
 
@@ -319,7 +319,7 @@ static int API_dev_write(va_list ap)
 	int err = 0;
 
 	/* 1. arg is ptr to the device_info struct */
-	di = (struct device_info *)va_arg(ap, u_int32_t);
+	di = (struct device_info *)va_arg(ap, uintptr_t);
 	if (di == NULL)
 		return API_EINVAL;
 
@@ -329,12 +329,12 @@ static int API_dev_write(va_list ap)
 		return API_ENODEV;
 
 	/* 2. arg is ptr to buffer from where to get data to write */
-	buf = (void *)va_arg(ap, u_int32_t);
+	buf = (void *)va_arg(ap, uintptr_t);
 	if (buf == NULL)
 		return API_EINVAL;
 
 	/* 3. arg is length of buffer */
-	len = (int *)va_arg(ap, u_int32_t);
+	len = (int *)va_arg(ap, uintptr_t);
 	if (len == NULL)
 		return API_EINVAL;
 	if (*len <= 0)
@@ -387,7 +387,7 @@ static int API_dev_read(va_list ap)
 	int *len_net, *act_len_net;
 
 	/* 1. arg is ptr to the device_info struct */
-	di = (struct device_info *)va_arg(ap, u_int32_t);
+	di = (struct device_info *)va_arg(ap, uintptr_t);
 	if (di == NULL)
 		return API_EINVAL;
 
@@ -397,23 +397,23 @@ static int API_dev_read(va_list ap)
 		return API_ENODEV;
 
 	/* 2. arg is ptr to buffer from where to put the read data */
-	buf = (void *)va_arg(ap, u_int32_t);
+	buf = (void *)va_arg(ap, uintptr_t);
 	if (buf == NULL)
 		return API_EINVAL;
 
 	if (di->type & DEV_TYP_STOR) {
 		/* 3. arg - ptr to var with # of blocks to read */
-		len_stor = (lbasize_t *)va_arg(ap, u_int32_t);
+		len_stor = (lbasize_t *)va_arg(ap, uintptr_t);
 		if (!len_stor)
 			return API_EINVAL;
 		if (*len_stor <= 0)
 			return API_EINVAL;
 
 		/* 4. arg - ptr to var with start block */
-		start = (lbastart_t *)va_arg(ap, u_int32_t);
+		start = (lbastart_t *)va_arg(ap, uintptr_t);
 
 		/* 5. arg - ptr to var where to put the len actually read */
-		act_len_stor = (lbasize_t *)va_arg(ap, u_int32_t);
+		act_len_stor = (lbasize_t *)va_arg(ap, uintptr_t);
 		if (!act_len_stor)
 			return API_EINVAL;
 
@@ -422,14 +422,14 @@ static int API_dev_read(va_list ap)
 	} else if (di->type & DEV_TYP_NET) {
 
 		/* 3. arg points to the var with length of packet to read */
-		len_net = (int *)va_arg(ap, u_int32_t);
+		len_net = (int *)va_arg(ap, uintptr_t);
 		if (!len_net)
 			return API_EINVAL;
 		if (*len_net <= 0)
 			return API_EINVAL;
 
 		/* 4. - ptr to var where to put the len actually read */
-		act_len_net = (int *)va_arg(ap, u_int32_t);
+		act_len_net = (int *)va_arg(ap, uintptr_t);
 		if (!act_len_net)
 			return API_EINVAL;
 
@@ -453,9 +453,9 @@ static int API_env_get(va_list ap)
 {
 	char *name, **value;
 
-	if ((name = (char *)va_arg(ap, u_int32_t)) == NULL)
+	if ((name = (char *)va_arg(ap, uintptr_t)) == NULL)
 		return API_EINVAL;
-	if ((value = (char **)va_arg(ap, u_int32_t)) == NULL)
+	if ((value = (char **)va_arg(ap, uintptr_t)) == NULL)
 		return API_EINVAL;
 
 	*value = getenv(name);
@@ -476,9 +476,9 @@ static int API_env_set(va_list ap)
 {
 	char *name, *value;
 
-	if ((name = (char *)va_arg(ap, u_int32_t)) == NULL)
+	if ((name = (char *)va_arg(ap, uintptr_t)) == NULL)
 		return API_EINVAL;
-	if ((value = (char *)va_arg(ap, u_int32_t)) == NULL)
+	if ((value = (char *)va_arg(ap, uintptr_t)) == NULL)
 		return API_EINVAL;
 
 	setenv(name, value);
@@ -498,9 +498,9 @@ static int API_env_enum(va_list ap)
 	int i, n;
 	char *last, **next;
 
-	last = (char *)va_arg(ap, u_int32_t);
+	last = (char *)va_arg(ap, unsigned long);
 
-	if ((next = (char **)va_arg(ap, u_int32_t)) == NULL)
+	if ((next = (char **)va_arg(ap, uintptr_t)) == NULL)
 		return API_EINVAL;
 
 	if (last == NULL)
@@ -662,14 +662,14 @@ void api_init(void)
 	}
 
 	setenv_hex("api_address", (unsigned long)sig);
-	debugf("API sig @ 0x%08x\n", sig);
+	debugf("API sig @ 0x%lX\n", (unsigned long)sig);
 	memcpy(sig->magic, API_SIG_MAGIC, 8);
 	sig->version = API_SIG_VERSION;
 	sig->syscall = &syscall;
 	sig->checksum = 0;
 	sig->checksum = crc32(0, (unsigned char *)sig,
 			      sizeof(struct api_signature));
-	debugf("syscall entry: 0x%08x\n", sig->syscall);
+	debugf("syscall entry: 0x%lX\n", (unsigned long)sig->syscall);
 }
 
 void platform_set_mr(struct sys_info *si, unsigned long start, unsigned long size,
diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig
index fe37d1fa2d7f14dc7cd20fe42c840fd16c577cef..dc34c18258cbf9aad441fd1b8145ecfd88f13a76 100644
--- a/arch/mips/Kconfig
+++ b/arch/mips/Kconfig
@@ -5,8 +5,8 @@ config SYS_ARCH
 	default "mips"
 
 config SYS_CPU
-	default "mips32" if CPU_MIPS32_R1 || CPU_MIPS32_R2
-	default "mips64" if CPU_MIPS64_R1 || CPU_MIPS64_R2
+	default "mips32" if CPU_MIPS32
+	default "mips64" if CPU_MIPS64
 
 choice
 	prompt "Target select"
@@ -28,6 +28,7 @@ config TARGET_MALTA
 	select SUPPORTS_LITTLE_ENDIAN
 	select SUPPORTS_CPU_MIPS32_R1
 	select SUPPORTS_CPU_MIPS32_R2
+	select SUPPORTS_CPU_MIPS32_R6
 	select SWAP_IO_SPACE
 	select MIPS_L1_CACHE_SHIFT_6
 
@@ -55,6 +56,11 @@ config TARGET_PB1X00
 	select SYS_MIPS_CACHE_INIT_RAM_LOAD
 	select MIPS_TUNE_4KC
 
+config ARCH_ATH79
+	bool "Support QCA/Atheros ath79"
+	select OF_CONTROL
+	select DM
+
 config MACH_PIC32
 	bool "Support Microchip PIC32"
 	select OF_CONTROL
@@ -67,6 +73,7 @@ source "board/imgtec/malta/Kconfig"
 source "board/micronas/vct/Kconfig"
 source "board/pb1x00/Kconfig"
 source "board/qemu-mips/Kconfig"
+source "arch/mips/mach-ath79/Kconfig"
 source "arch/mips/mach-pic32/Kconfig"
 
 if MIPS
@@ -98,7 +105,7 @@ config CPU_MIPS32_R1
 	depends on SUPPORTS_CPU_MIPS32_R1
 	select 32BIT
 	help
-	  Choose this option to build an U-Boot for release 1 or later of the
+	  Choose this option to build an U-Boot for release 1 through 5 of the
 	  MIPS32 architecture.
 
 config CPU_MIPS32_R2
@@ -106,7 +113,15 @@ config CPU_MIPS32_R2
 	depends on SUPPORTS_CPU_MIPS32_R2
 	select 32BIT
 	help
-	  Choose this option to build an U-Boot for release 2 or later of the
+	  Choose this option to build an U-Boot for release 2 through 5 of the
+	  MIPS32 architecture.
+
+config CPU_MIPS32_R6
+	bool "MIPS32 Release 6"
+	depends on SUPPORTS_CPU_MIPS32_R6
+	select 32BIT
+	help
+	  Choose this option to build an U-Boot for release 6 or later of the
 	  MIPS32 architecture.
 
 config CPU_MIPS64_R1
@@ -114,7 +129,7 @@ config CPU_MIPS64_R1
 	depends on SUPPORTS_CPU_MIPS64_R1
 	select 64BIT
 	help
-	  Choose this option to build a kernel for release 1 or later of the
+	  Choose this option to build a kernel for release 1 through 5 of the
 	  MIPS64 architecture.
 
 config CPU_MIPS64_R2
@@ -122,7 +137,15 @@ config CPU_MIPS64_R2
 	depends on SUPPORTS_CPU_MIPS64_R2
 	select 64BIT
 	help
-	  Choose this option to build a kernel for release 2 or later of the
+	  Choose this option to build a kernel for release 2 through 5 of the
+	  MIPS64 architecture.
+
+config CPU_MIPS64_R6
+	bool "MIPS64 Release 6"
+	depends on SUPPORTS_CPU_MIPS64_R6
+	select 64BIT
+	help
+	  Choose this option to build a kernel for release 6 or later of the
 	  MIPS64 architecture.
 
 endchoice
@@ -169,19 +192,25 @@ config SUPPORTS_CPU_MIPS32_R1
 config SUPPORTS_CPU_MIPS32_R2
 	bool
 
+config SUPPORTS_CPU_MIPS32_R6
+	bool
+
 config SUPPORTS_CPU_MIPS64_R1
 	bool
 
 config SUPPORTS_CPU_MIPS64_R2
 	bool
 
+config SUPPORTS_CPU_MIPS64_R6
+	bool
+
 config CPU_MIPS32
 	bool
-	default y if CPU_MIPS32_R1 || CPU_MIPS32_R2
+	default y if CPU_MIPS32_R1 || CPU_MIPS32_R2 || CPU_MIPS32_R6
 
 config CPU_MIPS64
 	bool
-	default y if CPU_MIPS64_R1 || CPU_MIPS64_R2
+	default y if CPU_MIPS64_R1 || CPU_MIPS64_R2 || CPU_MIPS64_R6
 
 config MIPS_TUNE_4KC
 	bool
@@ -192,6 +221,9 @@ config MIPS_TUNE_14KC
 config MIPS_TUNE_24KC
 	bool
 
+config MIPS_TUNE_74KC
+	bool
+
 config 32BIT
 	bool
 
diff --git a/arch/mips/Makefile b/arch/mips/Makefile
index aec5a1517a7b1ef20d4e47ecd7e53783c079bbe7..655a49338201396559df33a13b9208271b105e01 100644
--- a/arch/mips/Makefile
+++ b/arch/mips/Makefile
@@ -8,6 +8,7 @@ libs-y += arch/mips/cpu/
 libs-y += arch/mips/lib/
 
 machine-$(CONFIG_SOC_AU1X00) += au1x00
+machine-$(CONFIG_ARCH_ATH79) += ath79
 machine-$(CONFIG_MACH_PIC32) += pic32
 
 machdirs := $(patsubst %,arch/mips/mach-%/,$(machine-y))
@@ -18,13 +19,16 @@ PLATFORM_CPPFLAGS += $(patsubst %,-I$(srctree)/%include,$(machdirs))
 # Optimize for MIPS architectures
 arch-$(CONFIG_CPU_MIPS32_R1) += -march=mips32 -Wa,-mips32
 arch-$(CONFIG_CPU_MIPS32_R2) += -march=mips32r2 -Wa,-mips32r2
+arch-$(CONFIG_CPU_MIPS32_R6) += -march=mips32r6 -Wa,-mips32r6
 arch-$(CONFIG_CPU_MIPS64_R1) += -march=mips64 -Wa,-mips64
 arch-$(CONFIG_CPU_MIPS64_R2) += -march=mips64r2 -Wa,-mips64r2
+arch-$(CONFIG_CPU_MIPS64_R6) += -march=mips64r6 -Wa,-mips64r6
 
 # Allow extra optimization for specific CPUs/SoCs
 tune-$(CONFIG_MIPS_TUNE_4KC) += -mtune=4kc
 tune-$(CONFIG_MIPS_TUNE_14KC) += -mtune=14kc
 tune-$(CONFIG_MIPS_TUNE_24KC) += -mtune=24kc
+tune-$(CONFIG_MIPS_TUNE_74KC) += -mtune=74kc
 
 # Include default header files
 cflags-y += -I$(srctree)/arch/mips/include/asm/mach-generic
diff --git a/arch/mips/cpu/cpu.c b/arch/mips/cpu/cpu.c
index 8d3b2f5c2b4e535ce12142f97b64874cc9f65430..391feb3250e42f665627c11cc7d07f182ffc2b4f 100644
--- a/arch/mips/cpu/cpu.c
+++ b/arch/mips/cpu/cpu.c
@@ -7,7 +7,6 @@
 
 #include <common.h>
 #include <command.h>
-#include <netdev.h>
 #include <linux/compiler.h>
 #include <asm/mipsregs.h>
 #include <asm/reboot.h>
diff --git a/arch/mips/cpu/start.S b/arch/mips/cpu/start.S
index 1b56ca350a1cf0cb7bd3a1743ca6fb7125e0d76b..fc6dd66aa655b9e1c7a8b25c5311e96e0ff6f4cb 100644
--- a/arch/mips/cpu/start.S
+++ b/arch/mips/cpu/start.S
@@ -164,12 +164,14 @@ reset:
 	li	t0, -16
 	PTR_LI	t1, CONFIG_SYS_INIT_SP_ADDR
 	and	sp, t1, t0		# force 16 byte alignment
-	PTR_SUB	sp, sp, GD_SIZE		# reserve space for gd
+	PTR_SUBU \
+		sp, sp, GD_SIZE		# reserve space for gd
 	and	sp, sp, t0		# force 16 byte alignment
 	move	k0, sp			# save gd pointer
 #ifdef CONFIG_SYS_MALLOC_F_LEN
 	li	t2, CONFIG_SYS_MALLOC_F_LEN
-	PTR_SUB	sp, sp, t2		# reserve space for early malloc
+	PTR_SUBU \
+		sp, sp, t2		# reserve space for early malloc
 	and	sp, sp, t0		# force 16 byte alignment
 #endif
 	move	fp, sp
@@ -179,7 +181,7 @@ reset:
 1:
 	PTR_S	zero, 0(t0)
 	blt	t0, t1, 1b
-	 PTR_ADDI t0, PTRSIZE
+	 PTR_ADDIU t0, PTRSIZE
 
 #ifdef CONFIG_SYS_MALLOC_F_LEN
 	PTR_S	sp, GD_MALLOC_BASE(k0)	# gd->malloc_base offset
@@ -237,7 +239,7 @@ ENTRY(relocate_code)
 	 move	a0, s2			# a0 <-- destination address
 
 	/* Jump to where we've relocated ourselves */
-	PTR_ADDI t0, s2, in_ram - _start
+	PTR_ADDIU t0, s2, in_ram - _start
 	jr	t0
 	 nop
 
@@ -257,7 +259,7 @@ in_ram:
 	PTR_L	t3, -(1 * PTRSIZE)(t0)	# t3 <-- num_got_entries
 	PTR_L	t8, -(2 * PTRSIZE)(t0)	# t8 <-- _GLOBAL_OFFSET_TABLE_
 	PTR_ADD	t8, s1			# t8 now holds relocated _G_O_T_
-	PTR_ADDI t8, t8, 2 * PTRSIZE	# skipping first two entries
+	PTR_ADDIU t8, t8, 2 * PTRSIZE	# skipping first two entries
 	PTR_LI	t2, 2
 1:
 	PTR_L	t1, 0(t8)
@@ -265,16 +267,16 @@ in_ram:
 	 PTR_ADD t1, s1
 	PTR_S	t1, 0(t8)
 2:
-	PTR_ADDI t2, 1
+	PTR_ADDIU t2, 1
 	blt	t2, t3, 1b
-	 PTR_ADDI t8, PTRSIZE
+	 PTR_ADDIU t8, PTRSIZE
 
 	/* Update dynamic relocations */
 	PTR_L	t1, -(4 * PTRSIZE)(t0)	# t1 <-- __rel_dyn_start
 	PTR_L	t2, -(5 * PTRSIZE)(t0)	# t2 <-- __rel_dyn_end
 
 	b	2f			# skip first reserved entry
-	 PTR_ADDI t1, 2 * PTRSIZE
+	 PTR_ADDIU t1, 2 * PTRSIZE
 
 1:
 	lw	t8, -4(t1)		# t8 <-- relocation info
@@ -293,7 +295,7 @@ in_ram:
 
 2:
 	blt	t1, t2, 1b
-	 PTR_ADDI t1, 2 * PTRSIZE	# each rel.dyn entry is 2*PTRSIZE bytes
+	 PTR_ADDIU t1, 2 * PTRSIZE	# each rel.dyn entry is 2*PTRSIZE bytes
 
 	/*
 	 * Clear BSS
@@ -307,7 +309,7 @@ in_ram:
 1:
 	PTR_S	zero, 0(t1)
 	blt	t1, t2, 1b
-	 PTR_ADDI t1, PTRSIZE
+	 PTR_ADDIU t1, PTRSIZE
 
 	move	a0, s0			# a0 <-- gd
 	move	a1, s2
diff --git a/arch/mips/dts/Makefile b/arch/mips/dts/Makefile
index b5139187c2068bb9905d68a8be07da24a4fddfb2..a94b74555073d5c0c59bfdaae1f07e1a0e13f542 100644
--- a/arch/mips/dts/Makefile
+++ b/arch/mips/dts/Makefile
@@ -2,7 +2,10 @@
 # SPDX-License-Identifier:	GPL-2.0+
 #
 
+dtb-$(CONFIG_TARGET_AP121) += ap121.dtb
+dtb-$(CONFIG_TARGET_AP143) += ap143.dtb
 dtb-$(CONFIG_TARGET_PIC32MZDASK) += pic32mzda_sk.dtb
+dtb-$(CONFIG_BOARD_TPLINK_WDR4300) += tplink_wdr4300.dtb
 
 targets += $(dtb-y)
 
diff --git a/arch/mips/dts/ap121.dts b/arch/mips/dts/ap121.dts
new file mode 100644
index 0000000000000000000000000000000000000000..e31f601d039403c771b56e1b4f0280cea93d6d3e
--- /dev/null
+++ b/arch/mips/dts/ap121.dts
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2015-2016 Wills Wang <wills.wang@live.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+/dts-v1/;
+#include "ar933x.dtsi"
+
+/ {
+	model = "AP121 Reference Board";
+	compatible = "qca,ap121", "qca,ar933x";
+
+	aliases {
+		spi0 = &spi0;
+		serial0 = &uart0;
+	};
+
+	chosen {
+		stdout-path = "serial0:115200n8";
+	};
+};
+
+&xtal {
+	clock-frequency = <25000000>;
+};
+
+&uart0 {
+	status = "okay";
+};
+
+&spi0 {
+	spi-max-frequency = <25000000>;
+	status = "okay";
+	spi-flash@0 {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		compatible = "spi-flash";
+		memory-map = <0x9f000000 0x00800000>;
+		spi-max-frequency = <25000000>;
+		reg = <0>;
+	};
+};
diff --git a/arch/mips/dts/ap143.dts b/arch/mips/dts/ap143.dts
new file mode 100644
index 0000000000000000000000000000000000000000..f53207e771028ca5cc67f33f159f504687e449fd
--- /dev/null
+++ b/arch/mips/dts/ap143.dts
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2015-2016 Wills Wang <wills.wang@live.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+/dts-v1/;
+#include "qca953x.dtsi"
+
+/ {
+	model = "AP143 Reference Board";
+	compatible = "qca,ap143", "qca,qca953x";
+
+	aliases {
+		spi0 = &spi0;
+		serial0 = &uart0;
+	};
+
+	chosen {
+		stdout-path = "serial0:115200n8";
+	};
+};
+
+&xtal {
+	clock-frequency = <25000000>;
+};
+
+&uart0 {
+	status = "okay";
+};
+
+&spi0 {
+	spi-max-frequency = <25000000>;
+	status = "okay";
+	spi-flash@0 {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		compatible = "spi-flash";
+		memory-map = <0x9f000000 0x00800000>;
+		spi-max-frequency = <25000000>;
+		reg = <0>;
+	};
+};
diff --git a/arch/mips/dts/ar933x.dtsi b/arch/mips/dts/ar933x.dtsi
new file mode 100644
index 0000000000000000000000000000000000000000..00896b2be477e483f254decbf070f39d8c58c914
--- /dev/null
+++ b/arch/mips/dts/ar933x.dtsi
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2015-2016 Wills Wang <wills.wang@live.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <dt-bindings/interrupt-controller/irq.h>
+#include "skeleton.dtsi"
+
+/ {
+	compatible = "qca,ar933x";
+
+	#address-cells = <1>;
+	#size-cells = <1>;
+
+	cpus {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		cpu@0 {
+			device_type = "cpu";
+			compatible = "mips,mips24Kc";
+			reg = <0>;
+		};
+	};
+
+	clocks {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		ranges;
+
+		xtal: xtal {
+			#clock-cells = <0>;
+			compatible = "fixed-clock";
+			clock-output-names = "xtal";
+		};
+	};
+
+	pinctrl {
+		u-boot,dm-pre-reloc;
+		compatible = "qca,ar933x-pinctrl";
+		ranges;
+		#address-cells = <1>;
+		#size-cells = <1>;
+		reg = <0x18040000 0x100>;
+	};
+
+	ahb {
+		compatible = "simple-bus";
+		ranges;
+
+		#address-cells = <1>;
+		#size-cells = <1>;
+
+		apb {
+			compatible = "simple-bus";
+			ranges;
+
+			#address-cells = <1>;
+			#size-cells = <1>;
+
+			ehci0: ehci@1b000100 {
+				compatible = "generic-ehci";
+				reg = <0x1b000100 0x100>;
+
+				status = "disabled";
+			};
+
+			uart0: uart@18020000 {
+				compatible = "qca,ar9330-uart";
+				reg = <0x18020000 0x20>;
+				interrupts = <128 IRQ_TYPE_LEVEL_HIGH>;
+
+				status = "disabled";
+			};
+
+			gmac0: eth@0x19000000 {
+				compatible = "qca,ag7240-mac";
+				reg = <0x19000000 0x200>;
+				phy = <&phy0>;
+				phy-mode = "rmii";
+
+				status = "disabled";
+
+				mdio {
+					#address-cells = <1>;
+					#size-cells = <0>;
+					phy0: ethernet-phy@0 {
+						reg = <0>;
+					};
+				};
+			};
+
+			gmac1: eth@0x1a000000 {
+				compatible = "qca,ag7240-mac";
+				reg = <0x1a000000 0x200>;
+				phy = <&phy0>;
+				phy-mode = "rgmii";
+
+				status = "disabled";
+			};
+		};
+
+		spi0: spi@1f000000 {
+			compatible = "qca,ar7100-spi";
+			reg = <0x1f000000 0x10>;
+			interrupts = <129 IRQ_TYPE_LEVEL_HIGH>;
+
+			status = "disabled";
+
+			#address-cells = <1>;
+			#size-cells = <0>;
+		};
+	};
+};
diff --git a/arch/mips/dts/ar934x.dtsi b/arch/mips/dts/ar934x.dtsi
new file mode 100644
index 0000000000000000000000000000000000000000..7a036a8f9483ac0fe1a61922717f6e4bd05822b2
--- /dev/null
+++ b/arch/mips/dts/ar934x.dtsi
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2016 Marek Vasut <marex@denx.de>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include "skeleton.dtsi"
+
+/ {
+	compatible = "qca,ar934x";
+
+	#address-cells = <1>;
+	#size-cells = <1>;
+
+	cpus {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		cpu@0 {
+			device_type = "cpu";
+			compatible = "mips,mips74Kc";
+			reg = <0>;
+		};
+	};
+
+	clocks {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		ranges;
+
+		xtal: xtal {
+			#clock-cells = <0>;
+			compatible = "fixed-clock";
+			clock-output-names = "xtal";
+		};
+	};
+
+	ahb {
+		compatible = "simple-bus";
+		ranges;
+
+		#address-cells = <1>;
+		#size-cells = <1>;
+
+		apb {
+			compatible = "simple-bus";
+			ranges;
+
+			#address-cells = <1>;
+			#size-cells = <1>;
+
+			ehci0: ehci@1b000100 {
+				compatible = "generic-ehci";
+				reg = <0x1b000100 0x100>;
+
+				status = "disabled";
+			};
+
+			uart0: uart@18020000 {
+				compatible = "ns16550";
+				reg = <0x18020000 0x20>;
+				reg-shift = <2>;
+
+				status = "disabled";
+			};
+
+			gmac0: eth@0x19000000 {
+				compatible = "qca,ag934x-mac";
+				reg = <0x19000000 0x200>;
+				phy = <&phy0>;
+				phy-mode = "rgmii";
+
+				status = "disabled";
+
+				mdio {
+					#address-cells = <1>;
+					#size-cells = <0>;
+					phy0: ethernet-phy@0 {
+						reg = <0>;
+					};
+				};
+			};
+
+			gmac1: eth@0x1a000000 {
+				compatible = "qca,ag934x-mac";
+				reg = <0x1a000000 0x200>;
+				phy = <&phy1>;
+				phy-mode = "rgmii";
+
+				status = "disabled";
+
+				mdio {
+					#address-cells = <1>;
+					#size-cells = <0>;
+					phy1: ethernet-phy@0 {
+						reg = <0>;
+					};
+				};
+			};
+		};
+
+		spi0: spi@1f000000 {
+			compatible = "qca,ar7100-spi";
+			reg = <0x1f000000 0x10>;
+
+			status = "disabled";
+
+			#address-cells = <1>;
+			#size-cells = <0>;
+		};
+	};
+};
diff --git a/arch/mips/dts/qca953x.dtsi b/arch/mips/dts/qca953x.dtsi
new file mode 100644
index 0000000000000000000000000000000000000000..870010f0e40dc81893cb6e752827c76cea537b9e
--- /dev/null
+++ b/arch/mips/dts/qca953x.dtsi
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2015-2016 Wills Wang <wills.wang@live.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <dt-bindings/interrupt-controller/irq.h>
+#include "skeleton.dtsi"
+
+/ {
+	compatible = "qca,qca953x";
+
+	#address-cells = <1>;
+	#size-cells = <1>;
+
+	cpus {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		cpu@0 {
+			device_type = "cpu";
+			compatible = "mips,mips24Kc";
+			reg = <0>;
+		};
+	};
+
+	clocks {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		ranges;
+
+		xtal: xtal {
+			#clock-cells = <0>;
+			compatible = "fixed-clock";
+			clock-output-names = "xtal";
+		};
+	};
+
+	pinctrl {
+		u-boot,dm-pre-reloc;
+		compatible = "qca,qca953x-pinctrl";
+		ranges;
+		#address-cells = <1>;
+		#size-cells = <1>;
+		reg = <0x18040000 0x100>;
+	};
+
+	ahb {
+		compatible = "simple-bus";
+		ranges;
+
+		#address-cells = <1>;
+		#size-cells = <1>;
+
+		apb {
+			compatible = "simple-bus";
+			ranges;
+
+			#address-cells = <1>;
+			#size-cells = <1>;
+
+			uart0: uart@18020000 {
+				compatible = "ns16550";
+				reg = <0x18020000 0x20>;
+				reg-shift = <2>;
+				clock-frequency = <25000000>;
+				interrupts = <128 IRQ_TYPE_LEVEL_HIGH>;
+
+				status = "disabled";
+			};
+		};
+
+		spi0: spi@1f000000 {
+			compatible = "qca,ar7100-spi";
+			reg = <0x1f000000 0x10>;
+			interrupts = <129 IRQ_TYPE_LEVEL_HIGH>;
+
+			status = "disabled";
+
+			#address-cells = <1>;
+			#size-cells = <0>;
+		};
+	};
+};
diff --git a/arch/mips/dts/tplink_wdr4300.dts b/arch/mips/dts/tplink_wdr4300.dts
new file mode 100644
index 0000000000000000000000000000000000000000..cfda4df72b722e47ea48ddfb3d4002d321d61c03
--- /dev/null
+++ b/arch/mips/dts/tplink_wdr4300.dts
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2016 Marek Vasut <marex@denx.de>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+/dts-v1/;
+#include "ar934x.dtsi"
+
+/ {
+	model = "TP-Link WDR4300 Board";
+	compatible = "tplink,wdr4300", "qca,ar934x";
+
+	aliases {
+		serial0 = &uart0;
+		spi0 = &spi0;
+	};
+
+	chosen {
+		stdout-path = "serial0:115200n8";
+	};
+};
+
+&ehci0 {
+	status = "okay";
+};
+
+&gmac0 {
+	phy-mode = "rgmii";
+	status = "okay";
+};
+
+&spi0 {
+	spi-max-frequency = <25000000>;
+	status = "okay";
+	spi-flash@0 {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		compatible = "spi-flash";
+		memory-map = <0x1e000000 0x00800000>;
+		spi-max-frequency = <25000000>;
+		reg = <0>;
+	};
+};
+
+&uart0 {
+	clock-frequency = <40000000>;
+	status = "okay";
+};
+
+&xtal {
+	clock-frequency = <40000000>;
+};
diff --git a/arch/mips/include/asm/global_data.h b/arch/mips/include/asm/global_data.h
index a1ca257db593a94f4cc7afedf2eaa1282315ca58..3f230b08f6042a0fc465bf341e4ea0863396683c 100644
--- a/arch/mips/include/asm/global_data.h
+++ b/arch/mips/include/asm/global_data.h
@@ -23,6 +23,12 @@ struct arch_global_data {
 	unsigned long tbl;
 	unsigned long lastinc;
 #endif
+#ifdef CONFIG_ARCH_ATH79
+	unsigned long id;
+	unsigned long soc;
+	unsigned long rev;
+	unsigned long ver;
+#endif
 };
 
 #include <asm-generic/global_data.h>
diff --git a/arch/mips/lib/cache_init.S b/arch/mips/lib/cache_init.S
index 14cc2c49fda23c30e7d9fdb2d2f2bf4ad88941ef..08b7c3af5254b80b08e2ecd04a815795e9ca458a 100644
--- a/arch/mips/lib/cache_init.S
+++ b/arch/mips/lib/cache_init.S
@@ -64,7 +64,7 @@
 	/* detect associativity */
 	srl	\sz, $1, \off + MIPS_CONF1_DA_SHF - MIPS_CONF1_DA_SHF
 	andi	\sz, \sz, (MIPS_CONF1_DA >> MIPS_CONF1_DA_SHF)
-	addi	\sz, \sz, 1
+	addiu	\sz, \sz, 1
 
 	/* sz *= line_sz */
 	mul	\sz, \sz, \line_sz
diff --git a/arch/mips/mach-ath79/Kconfig b/arch/mips/mach-ath79/Kconfig
new file mode 100644
index 0000000000000000000000000000000000000000..7d483aa8dce398754df81efdba157d69e179cb75
--- /dev/null
+++ b/arch/mips/mach-ath79/Kconfig
@@ -0,0 +1,55 @@
+menu "QCA/Atheros 7xxx/9xxx platforms"
+	depends on ARCH_ATH79
+
+config SYS_SOC
+	default "ath79"
+
+config SOC_AR933X
+	bool
+	select SUPPORTS_BIG_ENDIAN
+	select SUPPORTS_CPU_MIPS32_R1
+	select SUPPORTS_CPU_MIPS32_R2
+	select MIPS_TUNE_24KC
+	help
+	  This supports QCA/Atheros ar933x family SOCs.
+
+config SOC_AR934X
+	bool
+	select SUPPORTS_BIG_ENDIAN
+	select SUPPORTS_CPU_MIPS32_R1
+	select SUPPORTS_CPU_MIPS32_R2
+	select MIPS_TUNE_74KC
+	help
+	  This supports QCA/Atheros ar934x family SOCs.
+
+config SOC_QCA953X
+	bool
+	select SUPPORTS_BIG_ENDIAN
+	select SUPPORTS_CPU_MIPS32_R1
+	select SUPPORTS_CPU_MIPS32_R2
+	select MIPS_TUNE_24KC
+	help
+	  This supports QCA/Atheros qca953x family SOCs.
+
+choice
+	prompt "Board select"
+
+config TARGET_AP121
+	bool "AP121 Reference Board"
+	select SOC_AR933X
+
+config TARGET_AP143
+	bool "AP143 Reference Board"
+	select SOC_QCA953X
+
+config BOARD_TPLINK_WDR4300
+	bool "TP-Link WDR4300 Board"
+	select SOC_AR934X
+
+endchoice
+
+source "board/qca/ap121/Kconfig"
+source "board/qca/ap143/Kconfig"
+source "board/tplink/wdr4300/Kconfig"
+
+endmenu
diff --git a/arch/mips/mach-ath79/Makefile b/arch/mips/mach-ath79/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..d7e2666a7c92c7357c72ce88bb7bdd700ab3152d
--- /dev/null
+++ b/arch/mips/mach-ath79/Makefile
@@ -0,0 +1,11 @@
+#
+# SPDX-License-Identifier:	GPL-2.0+
+#
+
+obj-y += reset.o
+obj-y += cpu.o
+obj-y += dram.o
+
+obj-$(CONFIG_SOC_AR933X)	+= ar933x/
+obj-$(CONFIG_SOC_AR934X)	+= ar934x/
+obj-$(CONFIG_SOC_QCA953X)	+= qca953x/
diff --git a/arch/mips/mach-ath79/ar933x/Makefile b/arch/mips/mach-ath79/ar933x/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..fd74f0c2ae511afcb29b4cf558bb98336cfc9e56
--- /dev/null
+++ b/arch/mips/mach-ath79/ar933x/Makefile
@@ -0,0 +1,7 @@
+#
+# SPDX-License-Identifier:	GPL-2.0+
+#
+
+obj-y += clk.o
+obj-y += ddr.o
+obj-y += lowlevel_init.o
diff --git a/arch/mips/mach-ath79/ar933x/clk.c b/arch/mips/mach-ath79/ar933x/clk.c
new file mode 100644
index 0000000000000000000000000000000000000000..9fcd4961f542607aa32ef71492d620fbe51d9f2f
--- /dev/null
+++ b/arch/mips/mach-ath79/ar933x/clk.c
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2015-2016 Wills Wang <wills.wang@live.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <asm/addrspace.h>
+#include <asm/types.h>
+#include <mach/ar71xx_regs.h>
+#include <mach/reset.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+static u32 ar933x_get_xtal(void)
+{
+	u32 val;
+
+	val = get_bootstrap();
+	if (val & AR933X_BOOTSTRAP_REF_CLK_40)
+		return 40000000;
+	else
+		return 25000000;
+}
+
+int get_serial_clock(void)
+{
+	return ar933x_get_xtal();
+}
+
+int get_clocks(void)
+{
+	void __iomem *regs;
+	u32 val, xtal, pll, div;
+
+	regs = map_physmem(AR71XX_PLL_BASE, AR71XX_PLL_SIZE,
+			   MAP_NOCACHE);
+	xtal = ar933x_get_xtal();
+	val = readl(regs + AR933X_PLL_CPU_CONFIG_REG);
+
+	/* VCOOUT = XTAL * DIV_INT */
+	div = (val >> AR933X_PLL_CPU_CONFIG_REFDIV_SHIFT)
+			& AR933X_PLL_CPU_CONFIG_REFDIV_MASK;
+	pll = xtal / div;
+
+	/* PLLOUT = VCOOUT * (1/2^OUTDIV) */
+	div = (val >> AR933X_PLL_CPU_CONFIG_NINT_SHIFT)
+			& AR933X_PLL_CPU_CONFIG_NINT_MASK;
+	pll *= div;
+	div = (val >> AR933X_PLL_CPU_CONFIG_OUTDIV_SHIFT)
+			& AR933X_PLL_CPU_CONFIG_OUTDIV_MASK;
+	if (!div)
+		div = 1;
+	pll >>= div;
+
+	val = readl(regs + AR933X_PLL_CLK_CTRL_REG);
+
+	/* CPU_CLK = PLLOUT / CPU_POST_DIV */
+	div = ((val >> AR933X_PLL_CLK_CTRL_CPU_POST_DIV_SHIFT)
+			& AR933X_PLL_CLK_CTRL_CPU_POST_DIV_MASK) + 1;
+	gd->cpu_clk = pll / div;
+
+	/* DDR_CLK = PLLOUT / DDR_POST_DIV */
+	div = ((val >> AR933X_PLL_CLK_CTRL_DDR_POST_DIV_SHIFT)
+			& AR933X_PLL_CLK_CTRL_DDR_POST_DIV_MASK) + 1;
+	gd->mem_clk = pll / div;
+
+	/* AHB_CLK = PLLOUT / AHB_POST_DIV */
+	div = ((val >> AR933X_PLL_CLK_CTRL_AHB_POST_DIV_SHIFT)
+			& AR933X_PLL_CLK_CTRL_AHB_POST_DIV_MASK) + 1;
+	gd->bus_clk = pll / div;
+
+	return 0;
+}
+
+ulong get_bus_freq(ulong dummy)
+{
+	if (!gd->bus_clk)
+		get_clocks();
+	return gd->bus_clk;
+}
+
+ulong get_ddr_freq(ulong dummy)
+{
+	if (!gd->mem_clk)
+		get_clocks();
+	return gd->mem_clk;
+}
diff --git a/arch/mips/mach-ath79/ar933x/ddr.c b/arch/mips/mach-ath79/ar933x/ddr.c
new file mode 100644
index 0000000000000000000000000000000000000000..91452bcc5345db4af581bd7da540ee3c91c1aa25
--- /dev/null
+++ b/arch/mips/mach-ath79/ar933x/ddr.c
@@ -0,0 +1,333 @@
+/*
+ * Copyright (C) 2015-2016 Wills Wang <wills.wang@live.com>
+ * Based on Atheros LSDK/QSDK
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <asm/addrspace.h>
+#include <asm/types.h>
+#include <mach/ar71xx_regs.h>
+#include <mach/reset.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#define DDR_CTRL_UPD_EMR3S      BIT(5)
+#define DDR_CTRL_UPD_EMR2S      BIT(4)
+#define DDR_CTRL_PRECHARGE      BIT(3)
+#define DDR_CTRL_AUTO_REFRESH   BIT(2)
+#define DDR_CTRL_UPD_EMRS       BIT(1)
+#define DDR_CTRL_UPD_MRS        BIT(0)
+
+#define DDR_REFRESH_EN          BIT(14)
+#define DDR_REFRESH_M           0x3ff
+#define DDR_REFRESH(x)          ((x) & 0x3ff)
+#define DDR_REFRESH_VAL_25M     (DDR_REFRESH_EN | DDR_REFRESH(390))
+#define DDR_REFRESH_VAL_40M     (DDR_REFRESH_EN | DDR_REFRESH(624))
+
+#define DDR_TRAS_S              0
+#define DDR_TRAS_M              0x1f
+#define DDR_TRAS(x)             ((x) << DDR_TRAS_S)
+#define DDR_TRCD_M              0xf
+#define DDR_TRCD_S              5
+#define DDR_TRCD(x)             ((x) << DDR_TRCD_S)
+#define DDR_TRP_M               0xf
+#define DDR_TRP_S               9
+#define DDR_TRP(x)              ((x) << DDR_TRP_S)
+#define DDR_TRRD_M              0xf
+#define DDR_TRRD_S              13
+#define DDR_TRRD(x)             ((x) << DDR_TRRD_S)
+#define DDR_TRFC_M              0x7f
+#define DDR_TRFC_S              17
+#define DDR_TRFC(x)             ((x) << DDR_TRFC_S)
+#define DDR_TMRD_M              0xf
+#define DDR_TMRD_S              23
+#define DDR_TMRD(x)             ((x) << DDR_TMRD_S)
+#define DDR_CAS_L_M             0x17
+#define DDR_CAS_L_S             27
+#define DDR_CAS_L(x)            (((x) & DDR_CAS_L_M) << DDR_CAS_L_S)
+#define DDR_OPEN                BIT(30)
+#define DDR_CONF_REG_VAL        (DDR_TRAS(16) | DDR_TRCD(6) | \
+				 DDR_TRP(6) | DDR_TRRD(4) | \
+				 DDR_TRFC(30) | DDR_TMRD(15) | \
+				 DDR_CAS_L(7) | DDR_OPEN)
+
+#define DDR_BURST_LEN_S         0
+#define DDR_BURST_LEN_M         0xf
+#define DDR_BURST_LEN(x)        ((x) << DDR_BURST_LEN_S)
+#define DDR_BURST_TYPE          BIT(4)
+#define DDR_CNTL_OE_EN          BIT(5)
+#define DDR_PHASE_SEL           BIT(6)
+#define DDR_CKE                 BIT(7)
+#define DDR_TWR_S               8
+#define DDR_TWR_M               0xf
+#define DDR_TWR(x)              ((x) << DDR_TWR_S)
+#define DDR_TRTW_S              12
+#define DDR_TRTW_M              0x1f
+#define DDR_TRTW(x)             ((x) << DDR_TRTW_S)
+#define DDR_TRTP_S              17
+#define DDR_TRTP_M              0xf
+#define DDR_TRTP(x)             ((x) << DDR_TRTP_S)
+#define DDR_TWTR_S              21
+#define DDR_TWTR_M              0x1f
+#define DDR_TWTR(x)             ((x) << DDR_TWTR_S)
+#define DDR_G_OPEN_L_S          26
+#define DDR_G_OPEN_L_M          0xf
+#define DDR_G_OPEN_L(x)         ((x) << DDR_G_OPEN_L_S)
+#define DDR_HALF_WIDTH_LOW      BIT(31)
+#define DDR_CONF2_REG_VAL       (DDR_BURST_LEN(8) | DDR_CNTL_OE_EN | \
+				 DDR_CKE | DDR_TWR(6) | DDR_TRTW(14) | \
+				 DDR_TRTP(8) | DDR_TWTR(14) | \
+				 DDR_G_OPEN_L(7) | DDR_HALF_WIDTH_LOW)
+
+#define DDR2_CONF_TWL_S         10
+#define DDR2_CONF_TWL_M         0xf
+#define DDR2_CONF_TWL(x)        (((x) & DDR2_CONF_TWL_M) << DDR2_CONF_TWL_S)
+#define DDR2_CONF_ODT           BIT(9)
+#define DDR2_CONF_TFAW_S        2
+#define DDR2_CONF_TFAW_M        0x3f
+#define DDR2_CONF_TFAW(x)       (((x) & DDR2_CONF_TFAW_M) << DDR2_CONF_TFAW_S)
+#define DDR2_CONF_EN            BIT(0)
+#define DDR2_CONF_VAL           (DDR2_CONF_TWL(2) | DDR2_CONF_ODT | \
+				 DDR2_CONF_TFAW(22) | DDR2_CONF_EN)
+
+#define DDR1_EXT_MODE_VAL       0x02
+#define DDR2_EXT_MODE_VAL       0x402
+#define DDR2_EXT_MODE_OCD_VAL   0x382
+#define DDR1_MODE_DLL_VAL       0x133
+#define DDR2_MODE_DLL_VAL       0x100
+#define DDR1_MODE_VAL           0x33
+#define DDR2_MODE_VAL           0xa33
+#define DDR_TAP_VAL0            0x08
+#define DDR_TAP_VAL1            0x09
+
+void ddr_init(void)
+{
+	void __iomem *regs;
+	u32 val;
+
+	regs = map_physmem(AR71XX_DDR_CTRL_BASE, AR71XX_DDR_CTRL_SIZE,
+			   MAP_NOCACHE);
+
+	writel(DDR_CONF_REG_VAL, regs + AR71XX_DDR_REG_CONFIG);
+	writel(DDR_CONF2_REG_VAL, regs + AR71XX_DDR_REG_CONFIG2);
+
+	val = get_bootstrap();
+	if (val & AR933X_BOOTSTRAP_DDR2) {
+		/* AHB maximum timeout */
+		writel(0xfffff, regs + AR933X_DDR_REG_TIMEOUT_MAX);
+
+		/* Enable DDR2 */
+		writel(DDR2_CONF_VAL, regs + AR933X_DDR_REG_DDR2_CONFIG);
+
+		/* Precharge All */
+		writel(DDR_CTRL_PRECHARGE, regs + AR71XX_DDR_REG_CONTROL);
+
+		/* Disable High Temperature Self-Refresh, Full Array */
+		writel(0x00, regs + AR933X_DDR_REG_EMR2);
+
+		/* Extended Mode Register 2 Set (EMR2S) */
+		writel(DDR_CTRL_UPD_EMR2S, regs + AR71XX_DDR_REG_CONTROL);
+
+		writel(0x00, regs + AR933X_DDR_REG_EMR3);
+
+		/* Extended Mode Register 3 Set (EMR3S) */
+		writel(DDR_CTRL_UPD_EMR3S, regs + AR71XX_DDR_REG_CONTROL);
+
+		/* Enable DLL,  Full strength, ODT Disabled */
+		writel(0x00, regs + AR71XX_DDR_REG_EMR);
+
+		/* Extended Mode Register Set (EMRS) */
+		writel(DDR_CTRL_UPD_EMRS, regs + AR71XX_DDR_REG_CONTROL);
+
+		/* Reset DLL */
+		writel(DDR2_MODE_DLL_VAL, regs + AR71XX_DDR_REG_MODE);
+
+		/* Mode Register Set (MRS) */
+		writel(DDR_CTRL_UPD_MRS, regs + AR71XX_DDR_REG_CONTROL);
+
+		/* Precharge All */
+		writel(DDR_CTRL_PRECHARGE, regs + AR71XX_DDR_REG_CONTROL);
+
+		/* Auto Refresh */
+		writel(DDR_CTRL_AUTO_REFRESH, regs + AR71XX_DDR_REG_CONTROL);
+		writel(DDR_CTRL_AUTO_REFRESH, regs + AR71XX_DDR_REG_CONTROL);
+
+		/* Write recovery (WR) 6 clock, CAS Latency 3, Burst Length 8 */
+		writel(DDR2_MODE_VAL, regs + AR71XX_DDR_REG_MODE);
+		/* Mode Register Set (MRS) */
+		writel(DDR_CTRL_UPD_MRS, regs + AR71XX_DDR_REG_CONTROL);
+
+		/* Enable OCD defaults, Enable DLL, Reduced Drive Strength */
+		writel(DDR2_EXT_MODE_OCD_VAL, regs + AR71XX_DDR_REG_EMR);
+
+		/* Extended Mode Register Set (EMRS) */
+		writel(DDR_CTRL_UPD_EMRS, regs + AR71XX_DDR_REG_CONTROL);
+
+		/* OCD exit, Enable DLL, Enable /DQS, Reduced Drive Strength */
+		writel(DDR2_EXT_MODE_VAL, regs + AR71XX_DDR_REG_EMR);
+		/* Extended Mode Register Set (EMRS) */
+		writel(DDR_CTRL_UPD_EMRS, regs + AR71XX_DDR_REG_CONTROL);
+
+		/* Refresh time control */
+		if (val & AR933X_BOOTSTRAP_REF_CLK_40)
+			writel(DDR_REFRESH_VAL_40M, regs +
+			       AR71XX_DDR_REG_REFRESH);
+		else
+			writel(DDR_REFRESH_VAL_25M, regs +
+			       AR71XX_DDR_REG_REFRESH);
+
+		/* DQS 0 Tap Control */
+		writel(DDR_TAP_VAL0, regs + AR71XX_DDR_REG_TAP_CTRL0);
+
+		/* DQS 1 Tap Control */
+		writel(DDR_TAP_VAL1, regs + AR71XX_DDR_REG_TAP_CTRL1);
+
+		/* For 16-bit DDR */
+		writel(0xff, regs + AR71XX_DDR_REG_RD_CYCLE);
+	} else {
+		/* AHB maximum timeout */
+		writel(0xfffff, regs + AR933X_DDR_REG_TIMEOUT_MAX);
+
+		/* Precharge All */
+		writel(DDR_CTRL_PRECHARGE, regs + AR71XX_DDR_REG_CONTROL);
+
+		/* Reset DLL, Burst Length 8, CAS Latency 3 */
+		writel(DDR1_MODE_DLL_VAL, regs + AR71XX_DDR_REG_MODE);
+
+		/* Forces an MRS update cycle in DDR */
+		writel(DDR_CTRL_UPD_MRS, regs + AR71XX_DDR_REG_CONTROL);
+
+		/* Enable DLL, Full strength */
+		writel(DDR1_EXT_MODE_VAL, regs + AR71XX_DDR_REG_EMR);
+
+		/* Extended Mode Register Set (EMRS) */
+		writel(DDR_CTRL_UPD_EMRS, regs + AR71XX_DDR_REG_CONTROL);
+
+		/* Precharge All */
+		writel(DDR_CTRL_PRECHARGE, regs + AR71XX_DDR_REG_CONTROL);
+
+		/* Normal DLL, Burst Length 8, CAS Latency 3 */
+		writel(DDR1_MODE_VAL, regs + AR71XX_DDR_REG_MODE);
+
+		/* Mode Register Set (MRS) */
+		writel(DDR_CTRL_UPD_MRS, regs + AR71XX_DDR_REG_CONTROL);
+
+		/* Refresh time control */
+		if (val & AR933X_BOOTSTRAP_REF_CLK_40)
+			writel(DDR_REFRESH_VAL_40M, regs +
+			       AR71XX_DDR_REG_REFRESH);
+		else
+			writel(DDR_REFRESH_VAL_25M, regs +
+			       AR71XX_DDR_REG_REFRESH);
+
+		/* DQS 0 Tap Control */
+		writel(DDR_TAP_VAL0, regs + AR71XX_DDR_REG_TAP_CTRL0);
+
+		/* DQS 1 Tap Control */
+		writel(DDR_TAP_VAL1, regs + AR71XX_DDR_REG_TAP_CTRL1);
+
+		/* For 16-bit DDR */
+		writel(0xff, regs + AR71XX_DDR_REG_RD_CYCLE);
+	}
+}
+
+void ddr_tap_tuning(void)
+{
+	void __iomem *regs;
+	u32 *addr_k0, *addr_k1, *addr;
+	u32 val, tap, upper, lower;
+	int i, j, dir, err, done;
+
+	regs = map_physmem(AR71XX_DDR_CTRL_BASE, AR71XX_DDR_CTRL_SIZE,
+			   MAP_NOCACHE);
+
+	/* Init memory pattern */
+	addr = (void *)CKSEG0ADDR(0x2000);
+	for (i = 0; i < 256; i++) {
+		val = 0;
+		for (j = 0; j < 8; j++) {
+			if (i & (1 << j)) {
+				if (j % 2)
+					val |= 0xffff0000;
+				else
+					val |= 0x0000ffff;
+			}
+
+			if (j % 2) {
+				*addr++ = val;
+				val = 0;
+			}
+		}
+	}
+
+	err = 0;
+	done = 0;
+	dir = 1;
+	tap = readl(regs + AR71XX_DDR_REG_TAP_CTRL0);
+	val = tap;
+	while (!done) {
+		err = 0;
+
+		/* Update new DDR tap value */
+		writel(val, regs + AR71XX_DDR_REG_TAP_CTRL0);
+		writel(val, regs + AR71XX_DDR_REG_TAP_CTRL1);
+
+		/* Compare DDR with cache */
+		for (i = 0; i < 2; i++) {
+			addr_k1 = (void *)CKSEG1ADDR(0x2000);
+			addr_k0 = (void *)CKSEG0ADDR(0x2000);
+			addr = (void *)CKSEG0ADDR(0x3000);
+
+			while (addr_k0 < addr) {
+				if (*addr_k1++ != *addr_k0++) {
+					err = 1;
+					break;
+				}
+			}
+
+			if (err)
+				break;
+		}
+
+		if (err) {
+			/* Save upper/lower threshold if error  */
+			if (dir) {
+				dir = 0;
+				val--;
+				upper = val;
+				val = tap;
+			} else {
+				val++;
+				lower = val;
+				done = 1;
+			}
+		} else {
+			/* Try the next value until limitation */
+			if (dir) {
+				if (val < 0x20) {
+					val++;
+				} else {
+					dir = 0;
+					upper = val;
+					val = tap;
+				}
+			} else {
+				if (!val) {
+					lower = val;
+					done = 1;
+				} else {
+					val--;
+				}
+			}
+		}
+	}
+
+	/* compute an intermediate value and write back */
+	val = (upper + lower) / 2;
+	writel(val, regs + AR71XX_DDR_REG_TAP_CTRL0);
+	val++;
+	writel(val, regs + AR71XX_DDR_REG_TAP_CTRL1);
+}
diff --git a/arch/mips/mach-ath79/ar933x/lowlevel_init.S b/arch/mips/mach-ath79/ar933x/lowlevel_init.S
new file mode 100644
index 0000000000000000000000000000000000000000..1b847f5eae3ec08dc8d54a86aed084dea478952e
--- /dev/null
+++ b/arch/mips/mach-ath79/ar933x/lowlevel_init.S
@@ -0,0 +1,280 @@
+/*
+ * Copyright (C) 2015-2016 Wills Wang <wills.wang@live.com>
+ * Based on Atheros LSDK/QSDK and u-boot_mod project
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <config.h>
+#include <asm/asm.h>
+#include <asm/regdef.h>
+#include <asm/mipsregs.h>
+#include <asm/addrspace.h>
+#include <mach/ar71xx_regs.h>
+
+#define SET_BIT(val, bit)   ((val) | (1 << (bit)))
+#define SET_PLL_PD(val)     SET_BIT(val, 30)
+#define AHB_DIV_TO_4(val)   SET_BIT(SET_BIT(val, 15), 16)
+#define PLL_BYPASS(val)     SET_BIT(val, 2)
+
+#define MK_PLL_CONF(divint, refdiv, range, outdiv) \
+     (((0x3F & divint) << 10) | \
+     ((0x1F & refdiv) << 16) | \
+     ((0x1 & range)   << 21) | \
+     ((0x7 & outdiv)  << 23) )
+
+#define MK_CLK_CNTL(cpudiv, ddrdiv, ahbdiv) \
+    (((0x3 & (cpudiv - 1)) << 5)  | \
+    ((0x3 & (ddrdiv - 1)) << 10) | \
+    ((0x3 & (ahbdiv - 1)) << 15) )
+
+/*
+ * PLL_CPU_CONFIG_VAL
+ *
+ * Bit30 is set (CPU_PLLPWD = 1 -> power down control for CPU PLL)
+ * After PLL configuration we need to clear this bit
+ *
+ * Values written into CPU PLL Configuration (CPU_PLL_CONFIG)
+ *
+ * bits 10..15  (6bit)  DIV_INT (Integer part of the DIV to CPU PLL)
+ *                      =>  32  (0x20)  VCOOUT = XTAL * DIV_INT
+ * bits 16..20  (5bit)  REFDIV  (Reference clock divider)
+ *                      =>  1   (0x1)   [Must start at values 1]
+ * bits 21      (1bit)  RANGE   (VCO frequency range of the CPU PLL)
+ *                      =>  0   (0x0)   [Doesn't impact clock values]
+ * bits 23..25  (3bit)  OUTDIV  (Ratio between VCO and PLL output)
+ *                      =>  1   (0x1)   [0 is illegal!]
+ *                              PLLOUT = VCOOUT * (1/2^OUTDIV)
+ */
+/* DIV_INT=32 (25MHz*32/2=400MHz), REFDIV=1, RANGE=0, OUTDIV=1 */
+#define PLL_CPU_CONFIG_VAL_40M  MK_PLL_CONF(20, 1, 0, 1)
+/* DIV_INT=20 (40MHz*20/2=400MHz), REFDIV=1, RANGE=0, OUTDIV=1 */
+#define PLL_CPU_CONFIG_VAL_25M  MK_PLL_CONF(32, 1, 0, 1)
+
+/*
+ * PLL_CLK_CONTROL_VAL
+ *
+ * In PLL_CLK_CONTROL_VAL bit 2 is set (BYPASS = 1 -> bypass PLL)
+ * After PLL configuration we need to clear this bit
+ *
+ * Values written into CPU Clock Control Register CLOCK_CONTROL
+ *
+ * bits 2       (1bit)  BYPASS (Bypass PLL. This defaults to 1 for test.
+ *                      Software must enable the CPU PLL for normal and
+ *                      then set this bit to 0)
+ * bits 5..6    (2bit)  CPU_POST_DIV    =>  0   (DEFAULT, Ratio = 1)
+ *                      CPU_CLK = PLLOUT / CPU_POST_DIV
+ * bits 10..11  (2bit)  DDR_POST_DIV    =>  0   (DEFAULT, Ratio = 1)
+ *                      DDR_CLK = PLLOUT / DDR_POST_DIV
+ * bits 15..16  (2bit)  AHB_POST_DIV    =>  1   (DEFAULT, Ratio = 2)
+ *                      AHB_CLK = PLLOUT / AHB_POST_DIV
+ *
+ */
+#define PLL_CLK_CONTROL_VAL MK_CLK_CNTL(1, 1, 2)
+
+    .text
+    .set noreorder
+
+LEAF(lowlevel_init)
+	/* These three WLAN_RESET will avoid original issue */
+	li      t3, 0x03
+1:
+	li      t0, CKSEG1ADDR(AR71XX_RESET_BASE)
+	lw      t1, AR933X_RESET_REG_RESET_MODULE(t0)
+	ori     t1, t1, 0x0800
+	sw      t1, AR933X_RESET_REG_RESET_MODULE(t0)
+	nop
+	lw      t1, AR933X_RESET_REG_RESET_MODULE(t0)
+	li      t2, 0xfffff7ff
+	and     t1, t1, t2
+	sw      t1, AR933X_RESET_REG_RESET_MODULE(t0)
+	nop
+	addi    t3, t3, -1
+	bnez    t3, 1b
+	nop
+
+	li      t2, 0x20
+2:
+	beqz    t2, 1b
+	nop
+	addi    t2, t2, -1
+	lw      t5, AR933X_RESET_REG_BOOTSTRAP(t0)
+	andi    t1, t5, 0x10
+	bnez    t1, 2b
+	nop
+
+	li      t1, 0x02110E
+	sw      t1, AR933X_RESET_REG_BOOTSTRAP(t0)
+	nop
+
+	/* RTC Force Wake */
+	li      t0, CKSEG1ADDR(AR933X_RTC_BASE)
+	li      t1, 0x03
+	sw      t1, AR933X_RTC_REG_FORCE_WAKE(t0)
+	nop
+	nop
+
+	/* RTC Reset */
+	li      t1, 0x00
+	sw      t1, AR933X_RTC_REG_RESET(t0)
+	nop
+	nop
+
+	li      t1, 0x01
+	sw      t1, AR933X_RTC_REG_RESET(t0)
+	nop
+	nop
+
+	/* Wait for RTC in on state */
+1:
+	lw      t1, AR933X_RTC_REG_STATUS(t0)
+	andi    t1, t1, 0x02
+	beqz    t1, 1b
+	nop
+
+	/* Program ki/kd */
+	li      t0, CKSEG1ADDR(AR933X_SRIF_BASE)
+	andi    t1, t5, 0x01            # t5 BOOT_STRAP
+	bnez    t1, 1f
+	nop
+	li      t1, 0x19e82f01
+	b       2f
+	nop
+1:
+	li      t1, 0x18e82f01
+2:
+	sw      t1, AR933X_SRIF_DDR_DPLL2_REG(t0)
+
+	/* Program phase shift */
+	lw      t1, AR933X_SRIF_DDR_DPLL3_REG(t0)
+	li      t2, 0xc07fffff
+	and     t1, t1, t2
+	li      t2, 0x800000
+	or      t1, t1, t2
+	sw      t1, AR933X_SRIF_DDR_DPLL3_REG(t0)
+	nop
+
+	/* in some cases, the SoC doesn't start with higher clock on AHB */
+	li      t0, CKSEG1ADDR(AR71XX_PLL_BASE)
+	li      t1, AHB_DIV_TO_4(PLL_BYPASS(PLL_CLK_CONTROL_VAL))
+	sw      t1, AR933X_PLL_CLK_CTRL_REG(t0)
+	nop
+
+	/* Set SETTLE_TIME in CPU PLL */
+	andi    t1, t5, 0x01            # t5 BOOT_STRAP
+	bnez    t1, 1f
+	nop
+	li      t1, 0x0352
+	b       2f
+	nop
+1:
+	li      t1, 0x0550
+2:
+	sw      t1, AR71XX_PLL_REG_SEC_CONFIG(t0)
+	nop
+
+	/* Set nint, frac, refdiv, outdiv, range according to xtal */
+0:
+	andi    t1, t5, 0x01            # t5 BOOT_STRAP
+	bnez    t1, 1f
+	nop
+	li      t1, SET_PLL_PD(PLL_CPU_CONFIG_VAL_25M)
+	b       2f
+	nop
+1:
+	li      t1, SET_PLL_PD(PLL_CPU_CONFIG_VAL_40M)
+2:
+	sw      t1, AR933X_PLL_CPU_CONFIG_REG(t0)
+	nop
+1:
+	lw      t1, AR933X_PLL_CPU_CONFIG_REG(t0)
+	li      t2, 0x80000000
+	and     t1, t1, t2
+	bnez    t1, 1b
+	nop
+
+	/* Put frac bit19:10 configuration */
+	li      t1, 0x1003E8
+	sw      t1, AR933X_PLL_DITHER_FRAC_REG(t0)
+	nop
+
+	/* Clear PLL power down bit in CPU PLL configuration */
+	andi    t1, t5, 0x01            # t5 BOOT_STRAP
+	bnez    t1, 1f
+	nop
+	li      t1, PLL_CPU_CONFIG_VAL_25M
+	b       2f
+	nop
+1:
+	li      t1, PLL_CPU_CONFIG_VAL_40M
+2:
+	sw      t1, AR933X_PLL_CPU_CONFIG_REG(t0)
+	nop
+
+	/* Wait for PLL update -> bit 31 in CPU_PLL_CONFIG should be 0 */
+1:
+	lw      t1, AR933X_PLL_CPU_CONFIG_REG(t0)
+	li      t2, 0x80000000
+	and     t1, t1, t2
+	bnez    t1, 1b
+	nop
+
+	/* Confirm DDR PLL lock */
+	li      t3, 100
+	li      t4, 0
+
+2:
+	addi    t4, t4, 1
+	bgt     t4, t3, 0b
+	nop
+
+	li      t3, 5
+3:
+	/* Clear do_meas */
+	li      t0, CKSEG1ADDR(AR933X_SRIF_BASE)
+	lw      t1, AR933X_SRIF_DDR_DPLL3_REG(t0)
+	li      t2, 0xBFFFFFFF
+	and     t1, t1, t2
+	sw      t1, AR933X_SRIF_DDR_DPLL3_REG(t0)
+	nop
+
+	li      t2, 10
+1:
+	subu    t2, t2, 1
+	bnez    t2, 1b
+	nop
+
+	/* Set do_meas */
+	li      t2, 0x40000000
+	or      t1, t1, t2
+	sw      t1, AR933X_SRIF_DDR_DPLL3_REG(t0)
+	nop
+
+	/* Check meas_done */
+1:
+	lw      t1, AR933X_SRIF_DDR_DPLL4_REG(t0)
+	andi    t1, t1, 0x8
+	beqz    t1, 1b
+	nop
+
+	lw      t1, AR933X_SRIF_DDR_DPLL3_REG(t0)
+	li      t2, 0x007FFFF8
+	and     t1, t1, t2
+	srl     t1, t1, 3
+	li      t2, 0x4000
+	bgt     t1, t2, 2b
+	nop
+	addi    t3, t3, -1
+	bnez    t3, 3b
+	nop
+
+	/* clear PLL bypass (bit 2) in CPU CLOCK CONTROL register */
+	li      t0, CKSEG1ADDR(AR71XX_PLL_BASE)
+	li      t1, PLL_CLK_CONTROL_VAL
+	sw      t1, AR933X_PLL_CLK_CTRL_REG(t0)
+	nop
+
+	nop
+	jr ra
+	nop
+    END(lowlevel_init)
diff --git a/arch/mips/mach-ath79/ar934x/Makefile b/arch/mips/mach-ath79/ar934x/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..348c65b2533299e0535ebfcc70c95daed4761d34
--- /dev/null
+++ b/arch/mips/mach-ath79/ar934x/Makefile
@@ -0,0 +1,7 @@
+#
+# SPDX-License-Identifier:	GPL-2.0+
+#
+
+obj-y += cpu.o
+obj-y += clk.o
+obj-y += ddr.o
diff --git a/arch/mips/mach-ath79/ar934x/clk.c b/arch/mips/mach-ath79/ar934x/clk.c
new file mode 100644
index 0000000000000000000000000000000000000000..9c65184e7a63483e759abde56b1510d454b2ff17
--- /dev/null
+++ b/arch/mips/mach-ath79/ar934x/clk.c
@@ -0,0 +1,334 @@
+/*
+ * Copyright (C) 2016 Marek Vasut <marex@denx.de>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <asm/addrspace.h>
+#include <asm/types.h>
+#include <mach/ar71xx_regs.h>
+#include <mach/reset.h>
+#include <wait_bit.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/*
+ * The math for calculating PLL:
+ *                                       NFRAC * 2^8
+ *                               NINT + -------------
+ *                XTAL [MHz]              2^(18 - 1)
+ *   PLL [MHz] = ------------ * ----------------------
+ *                  REFDIV              2^OUTDIV
+ *
+ * Unfortunatelly, there is no way to reliably compute the variables.
+ * The vendor U-Boot port contains macros for various combinations of
+ * CPU PLL / DDR PLL / AHB bus speed and there is no obvious pattern
+ * in those numbers.
+ */
+struct ar934x_pll_config {
+	u8	range;
+	u8	refdiv;
+	u8	outdiv;
+	/* Index 0 is for XTAL=25MHz , Index 1 is for XTAL=40MHz */
+	u8	nint[2];
+};
+
+struct ar934x_clock_config {
+	u16				cpu_freq;
+	u16				ddr_freq;
+	u16				ahb_freq;
+
+	struct ar934x_pll_config	cpu_pll;
+	struct ar934x_pll_config	ddr_pll;
+};
+
+static const struct ar934x_clock_config ar934x_clock_config[] = {
+	{ 300, 300, 150, { 1, 1, 1, { 24, 15 } }, { 1, 1, 1, { 24, 15 } } },
+	{ 400, 200, 200, { 1, 1, 1, { 32, 20 } }, { 1, 1, 2, { 32, 20 } } },
+	{ 400, 400, 200, { 0, 1, 1, { 32, 20 } }, { 0, 1, 1, { 32, 20 } } },
+	{ 500, 400, 200, { 1, 1, 0, { 20, 12 } }, { 0, 1, 1, { 32, 20 } } },
+	{ 533, 400, 200, { 1, 1, 0, { 21, 13 } }, { 0, 1, 1, { 32, 20 } } },
+	{ 533, 500, 250, { 1, 1, 0, { 21, 13 } }, { 0, 1, 0, { 20, 12 } } },
+	{ 560, 480, 240, { 1, 1, 0, { 22, 14 } }, { 1, 1, 0, { 19, 12 } } },
+	{ 566, 400, 200, { 1, 1, 0, { 22, 14 } }, { 1, 1, 0, { 16, 10 } } },
+	{ 566, 450, 225, { 1, 1, 0, { 22, 14 } }, { 0, 1, 1, { 36, 22 } } },
+	{ 566, 475, 237, { 1, 1, 0, { 22, 14 } }, { 1, 1, 0, { 19, 11 } } },
+	{ 566, 500, 250, { 1, 1, 0, { 22, 14 } }, { 1, 1, 0, { 20, 12 } } },
+	{ 566, 525, 262, { 1, 1, 0, { 22, 14 } }, { 1, 1, 0, { 21, 13 } } },
+	{ 566, 550, 275, { 1, 1, 0, { 22, 14 } }, { 1, 1, 0, { 22, 13 } } },
+	{ 600, 266, 133, { 0, 1, 0, { 24, 15 } }, { 1, 1, 1, { 21, 16 } } },
+	{ 600, 266, 200, { 0, 1, 0, { 24, 15 } }, { 1, 1, 1, { 21, 16 } } },
+	{ 600, 300, 150, { 0, 1, 0, { 24, 15 } }, { 0, 1, 1, { 24, 15 } } },
+	{ 600, 332, 166, { 0, 1, 0, { 24, 15 } }, { 1, 1, 1, { 26, 16 } } },
+	{ 600, 332, 200, { 0, 1, 0, { 24, 15 } }, { 1, 1, 1, { 26, 16 } } },
+	{ 600, 400, 200, { 0, 1, 0, { 24, 15 } }, { 0, 1, 1, { 32, 20 } } },
+	{ 600, 450, 200, { 0, 1, 0, { 24, 15 } }, { 0, 1, 0, { 18, 20 } } },
+	{ 600, 500, 250, { 0, 1, 0, { 24, 15 } }, { 1, 1, 0, { 20, 12 } } },
+	{ 600, 525, 262, { 0, 1, 0, { 24, 15 } }, { 0, 1, 0, { 21, 20 } } },
+	{ 600, 550, 275, { 0, 1, 0, { 24, 15 } }, { 0, 1, 0, { 22, 20 } } },
+	{ 600, 575, 287, { 0, 1, 0, { 24, 15 } }, { 0, 1, 0, { 23, 14 } } },
+	{ 600, 600, 300, { 0, 1, 0, { 24, 15 } }, { 0, 1, 0, { 24, 20 } } },
+	{ 600, 650, 325, { 0, 1, 0, { 24, 15 } }, { 0, 1, 0, { 26, 20 } } },
+	{ 650, 600, 300, { 0, 1, 0, { 26, 15 } }, { 0, 1, 0, { 24, 20 } } },
+	{ 700, 400, 200, { 3, 1, 0, { 28, 17 } }, { 0, 1, 1, { 32, 20 } } },
+};
+
+static void ar934x_srif_pll_cfg(void __iomem *pll_reg_base, const u32 srif_val)
+{
+	u32 reg;
+	do {
+		writel(0x10810f00, pll_reg_base + 0x4);
+		writel(srif_val, pll_reg_base + 0x0);
+		writel(0xd0810f00, pll_reg_base + 0x4);
+		writel(0x03000000, pll_reg_base + 0x8);
+		writel(0xd0800f00, pll_reg_base + 0x4);
+
+		clrbits_be32(pll_reg_base + 0x8, BIT(30));
+		udelay(5);
+		setbits_be32(pll_reg_base + 0x8, BIT(30));
+		udelay(5);
+
+		wait_for_bit("clk", pll_reg_base + 0xc, BIT(3), 1, 10, 0);
+
+		clrbits_be32(pll_reg_base + 0x8, BIT(30));
+		udelay(5);
+
+		/* Check if CPU SRIF PLL locked. */
+		reg = readl(pll_reg_base + 0x8);
+		reg = (reg & 0x7ffff8) >> 3;
+	} while (reg >= 0x40000);
+}
+
+void ar934x_pll_init(const u16 cpu_mhz, const u16 ddr_mhz, const u16 ahb_mhz)
+{
+	void __iomem *srif_regs = map_physmem(AR934X_SRIF_BASE,
+					      AR934X_SRIF_SIZE, MAP_NOCACHE);
+	void __iomem *pll_regs = map_physmem(AR71XX_PLL_BASE,
+					     AR71XX_PLL_SIZE, MAP_NOCACHE);
+	const struct ar934x_pll_config *pll_cfg;
+	int i, pll_nint, pll_refdiv, xtal_40 = 0;
+	u32 reg, cpu_pll, cpu_srif, ddr_pll, ddr_srif;
+
+	/* Configure SRIF PLL with initial values. */
+	writel(0x13210f00, srif_regs + AR934X_SRIF_CPU_DPLL2_REG);
+	writel(0x03000000, srif_regs + AR934X_SRIF_CPU_DPLL3_REG);
+	writel(0x13210f00, srif_regs + AR934X_SRIF_DDR_DPLL2_REG);
+	writel(0x03000000, srif_regs + AR934X_SRIF_DDR_DPLL3_REG);
+	writel(0x03000000, srif_regs + 0x188); /* Undocumented reg :-) */
+
+	/* Test for 40MHz XTAL */
+	reg = get_bootstrap();
+	if (reg & AR934X_BOOTSTRAP_REF_CLK_40) {
+		xtal_40 = 1;
+		cpu_srif = 0x41c00000;
+		ddr_srif = 0x41680000;
+	} else {
+		xtal_40 = 0;
+		cpu_srif = 0x29c00000;
+		ddr_srif = 0x29680000;
+	}
+
+	/* Locate CPU/DDR PLL configuration */
+	for (i = 0; i < ARRAY_SIZE(ar934x_clock_config); i++) {
+		if (cpu_mhz != ar934x_clock_config[i].cpu_freq)
+			continue;
+		if (ddr_mhz != ar934x_clock_config[i].ddr_freq)
+			continue;
+		if (ahb_mhz != ar934x_clock_config[i].ahb_freq)
+			continue;
+
+		/* Entry found */
+		pll_cfg = &ar934x_clock_config[i].cpu_pll;
+		pll_nint = pll_cfg->nint[xtal_40];
+		pll_refdiv = pll_cfg->refdiv;
+		cpu_pll =
+			(pll_nint << AR934X_PLL_CPU_CONFIG_NINT_SHIFT) |
+			(pll_refdiv << AR934X_PLL_CPU_CONFIG_REFDIV_SHIFT) |
+			(pll_cfg->range << AR934X_PLL_CPU_CONFIG_RANGE_SHIFT) |
+			(pll_cfg->outdiv << AR934X_PLL_CPU_CONFIG_OUTDIV_SHIFT);
+
+		pll_cfg = &ar934x_clock_config[i].ddr_pll;
+		pll_nint = pll_cfg->nint[xtal_40];
+		pll_refdiv = pll_cfg->refdiv;
+		ddr_pll =
+			(pll_nint << AR934X_PLL_DDR_CONFIG_NINT_SHIFT) |
+			(pll_refdiv << AR934X_PLL_DDR_CONFIG_REFDIV_SHIFT) |
+			(pll_cfg->range << AR934X_PLL_DDR_CONFIG_RANGE_SHIFT) |
+			(pll_cfg->outdiv << AR934X_PLL_DDR_CONFIG_OUTDIV_SHIFT);
+		break;
+	}
+
+	/* PLL configuration not found, hang. */
+	if (i == ARRAY_SIZE(ar934x_clock_config))
+		hang();
+
+	/* Set PLL Bypass */
+	setbits_be32(pll_regs + AR934X_PLL_CPU_DDR_CLK_CTRL_REG,
+		     AR934X_PLL_CLK_CTRL_CPU_PLL_BYPASS);
+	setbits_be32(pll_regs + AR934X_PLL_CPU_DDR_CLK_CTRL_REG,
+		     AR934X_PLL_CLK_CTRL_DDR_PLL_BYPASS);
+	setbits_be32(pll_regs + AR934X_PLL_CPU_DDR_CLK_CTRL_REG,
+		     AR934X_PLL_CLK_CTRL_AHB_PLL_BYPASS);
+
+	/* Configure CPU PLL */
+	writel(cpu_pll | AR934X_PLL_CPU_CONFIG_PLLPWD,
+	       pll_regs + AR934X_PLL_CPU_CONFIG_REG);
+	/* Configure DDR PLL */
+	writel(ddr_pll | AR934X_PLL_DDR_CONFIG_PLLPWD,
+	       pll_regs + AR934X_PLL_DDR_CONFIG_REG);
+	/* Configure PLL routing */
+	writel(AR934X_PLL_CLK_CTRL_CPU_PLL_BYPASS |
+	       AR934X_PLL_CLK_CTRL_DDR_PLL_BYPASS |
+	       AR934X_PLL_CLK_CTRL_AHB_PLL_BYPASS |
+	       (0 << AR934X_PLL_CLK_CTRL_CPU_POST_DIV_SHIFT) |
+	       (0 << AR934X_PLL_CLK_CTRL_DDR_POST_DIV_SHIFT) |
+	       (1 << AR934X_PLL_CLK_CTRL_AHB_POST_DIV_SHIFT) |
+	       AR934X_PLL_CLK_CTRL_CPUCLK_FROM_CPUPLL |
+	       AR934X_PLL_CLK_CTRL_DDRCLK_FROM_DDRPLL |
+	       AR934X_PLL_CLK_CTRL_AHBCLK_FROM_DDRPLL,
+	       pll_regs + AR934X_PLL_CPU_DDR_CLK_CTRL_REG);
+
+	/* Configure SRIF PLLs, which is completely undocumented :-) */
+	ar934x_srif_pll_cfg(srif_regs + AR934X_SRIF_CPU_DPLL1_REG, cpu_srif);
+	ar934x_srif_pll_cfg(srif_regs + AR934X_SRIF_DDR_DPLL1_REG, ddr_srif);
+
+	/* Unset PLL Bypass */
+	clrbits_be32(pll_regs + AR934X_PLL_CPU_DDR_CLK_CTRL_REG,
+		     AR934X_PLL_CLK_CTRL_CPU_PLL_BYPASS);
+	clrbits_be32(pll_regs + AR934X_PLL_CPU_DDR_CLK_CTRL_REG,
+		     AR934X_PLL_CLK_CTRL_DDR_PLL_BYPASS);
+	clrbits_be32(pll_regs + AR934X_PLL_CPU_DDR_CLK_CTRL_REG,
+		     AR934X_PLL_CLK_CTRL_AHB_PLL_BYPASS);
+
+	/* Enable PLL dithering */
+	writel((1 << AR934X_PLL_DDR_DIT_FRAC_STEP_SHIFT) |
+	       (0xf << AR934X_PLL_DDR_DIT_UPD_CNT_SHIFT),
+	       pll_regs + AR934X_PLL_DDR_DIT_FRAC_REG);
+	writel(48 << AR934X_PLL_CPU_DIT_UPD_CNT_SHIFT,
+	       pll_regs + AR934X_PLL_CPU_DIT_FRAC_REG);
+}
+
+static u32 ar934x_get_xtal(void)
+{
+	u32 val;
+
+	val = get_bootstrap();
+	if (val & AR934X_BOOTSTRAP_REF_CLK_40)
+		return 40000000;
+	else
+		return 25000000;
+}
+
+int get_serial_clock(void)
+{
+	return ar934x_get_xtal();
+}
+
+static u32 ar934x_cpupll_to_hz(const u32 regval)
+{
+	const u32 outdiv = (regval >> AR934X_PLL_CPU_CONFIG_OUTDIV_SHIFT) &
+			   AR934X_PLL_CPU_CONFIG_OUTDIV_MASK;
+	const u32 refdiv = (regval >> AR934X_PLL_CPU_CONFIG_REFDIV_SHIFT) &
+			   AR934X_PLL_CPU_CONFIG_REFDIV_MASK;
+	const u32 nint = (regval >> AR934X_PLL_CPU_CONFIG_NINT_SHIFT) &
+			   AR934X_PLL_CPU_CONFIG_NINT_MASK;
+	const u32 nfrac = (regval >> AR934X_PLL_CPU_CONFIG_NFRAC_SHIFT) &
+			   AR934X_PLL_CPU_CONFIG_NFRAC_MASK;
+	const u32 xtal = ar934x_get_xtal();
+
+	return (xtal * (nint + (nfrac >> 9))) / (refdiv * (1 << outdiv));
+}
+
+static u32 ar934x_ddrpll_to_hz(const u32 regval)
+{
+	const u32 outdiv = (regval >> AR934X_PLL_DDR_CONFIG_OUTDIV_SHIFT) &
+			   AR934X_PLL_DDR_CONFIG_OUTDIV_MASK;
+	const u32 refdiv = (regval >> AR934X_PLL_DDR_CONFIG_REFDIV_SHIFT) &
+			   AR934X_PLL_DDR_CONFIG_REFDIV_MASK;
+	const u32 nint = (regval >> AR934X_PLL_DDR_CONFIG_NINT_SHIFT) &
+			   AR934X_PLL_DDR_CONFIG_NINT_MASK;
+	const u32 nfrac = (regval >> AR934X_PLL_DDR_CONFIG_NFRAC_SHIFT) &
+			   AR934X_PLL_DDR_CONFIG_NFRAC_MASK;
+	const u32 xtal = ar934x_get_xtal();
+
+	return (xtal * (nint + (nfrac >> 9))) / (refdiv * (1 << outdiv));
+}
+
+static void ar934x_update_clock(void)
+{
+	void __iomem *regs;
+	u32 ctrl, cpu, cpupll, ddr, ddrpll;
+	u32 cpudiv, ddrdiv, busdiv;
+	u32 cpuclk, ddrclk, busclk;
+
+	regs = map_physmem(AR71XX_PLL_BASE, AR71XX_PLL_SIZE,
+			   MAP_NOCACHE);
+
+	cpu = readl(regs + AR934X_PLL_CPU_CONFIG_REG);
+	ddr = readl(regs + AR934X_PLL_DDR_CONFIG_REG);
+	ctrl = readl(regs + AR934X_PLL_CPU_DDR_CLK_CTRL_REG);
+
+	cpupll = ar934x_cpupll_to_hz(cpu);
+	ddrpll = ar934x_ddrpll_to_hz(ddr);
+
+	if (ctrl & AR934X_PLL_CLK_CTRL_CPU_PLL_BYPASS)
+		cpuclk = ar934x_get_xtal();
+	else if (ctrl & AR934X_PLL_CLK_CTRL_CPUCLK_FROM_CPUPLL)
+		cpuclk = cpupll;
+	else
+		cpuclk = ddrpll;
+
+	if (ctrl & AR934X_PLL_CLK_CTRL_DDR_PLL_BYPASS)
+		ddrclk = ar934x_get_xtal();
+	else if (ctrl & AR934X_PLL_CLK_CTRL_DDRCLK_FROM_DDRPLL)
+		ddrclk = ddrpll;
+	else
+		ddrclk = cpupll;
+
+	if (ctrl & AR934X_PLL_CLK_CTRL_AHB_PLL_BYPASS)
+		busclk = ar934x_get_xtal();
+	else if (ctrl & AR934X_PLL_CLK_CTRL_AHBCLK_FROM_DDRPLL)
+		busclk = ddrpll;
+	else
+		busclk = cpupll;
+
+	cpudiv = (ctrl >> AR934X_PLL_CLK_CTRL_CPU_POST_DIV_SHIFT) &
+		 AR934X_PLL_CLK_CTRL_CPU_POST_DIV_MASK;
+	ddrdiv = (ctrl >> AR934X_PLL_CLK_CTRL_DDR_POST_DIV_SHIFT) &
+		 AR934X_PLL_CLK_CTRL_DDR_POST_DIV_MASK;
+	busdiv = (ctrl >> AR934X_PLL_CLK_CTRL_AHB_POST_DIV_SHIFT) &
+		 AR934X_PLL_CLK_CTRL_AHB_POST_DIV_MASK;
+
+	gd->cpu_clk = cpuclk / (cpudiv + 1);
+	gd->mem_clk = ddrclk / (ddrdiv + 1);
+	gd->bus_clk = busclk / (busdiv + 1);
+}
+
+ulong get_bus_freq(ulong dummy)
+{
+	ar934x_update_clock();
+	return gd->bus_clk;
+}
+
+ulong get_ddr_freq(ulong dummy)
+{
+	ar934x_update_clock();
+	return gd->mem_clk;
+}
+
+int do_ar934x_showclk(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+	ar934x_update_clock();
+	printf("CPU:       %8ld MHz\n", gd->cpu_clk / 1000000);
+	printf("Memory:    %8ld MHz\n", gd->mem_clk / 1000000);
+	printf("AHB:       %8ld MHz\n", gd->bus_clk / 1000000);
+	return 0;
+}
+
+U_BOOT_CMD(
+	clocks,	CONFIG_SYS_MAXARGS, 1, do_ar934x_showclk,
+	"display clocks",
+	""
+);
diff --git a/arch/mips/mach-ath79/ar934x/cpu.c b/arch/mips/mach-ath79/ar934x/cpu.c
new file mode 100644
index 0000000000000000000000000000000000000000..8fcdf657d1e7334ab219e1d0a33fb53e673c466b
--- /dev/null
+++ b/arch/mips/mach-ath79/ar934x/cpu.c
@@ -0,0 +1,10 @@
+/*
+ * Copyright (C) 2016 Marek Vasut <marex@denx.de>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+
+/* The lowlevel_init() is not needed on AR934x */
+void lowlevel_init(void) {}
diff --git a/arch/mips/mach-ath79/ar934x/ddr.c b/arch/mips/mach-ath79/ar934x/ddr.c
new file mode 100644
index 0000000000000000000000000000000000000000..4621d5845cd5b8be815024ac8aa10444c8c84714
--- /dev/null
+++ b/arch/mips/mach-ath79/ar934x/ddr.c
@@ -0,0 +1,163 @@
+/*
+ * Copyright (C) 2016 Marek Vasut <marex@denx.de>
+ *
+ * Based on RAM init sequence by Piotr Dymacz <pepe2k@gmail.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <asm/addrspace.h>
+#include <asm/types.h>
+#include <mach/ar71xx_regs.h>
+#include <mach/reset.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+enum {
+	AR934X_SDRAM = 0,
+	AR934X_DDR1,
+	AR934X_DDR2,
+};
+
+struct ar934x_mem_config {
+	u32	config1;
+	u32	config2;
+	u32	mode;
+	u32	extmode;
+	u32	tap;
+};
+
+static const struct ar934x_mem_config ar934x_mem_config[] = {
+	[AR934X_SDRAM] = { 0x7fbe8cd0, 0x959f66a8, 0x33, 0, 0x1f1f },
+	[AR934X_DDR1]  = { 0x7fd48cd0, 0x99d0e6a8, 0x33, 0, 0x14 },
+	[AR934X_DDR2]  = { 0xc7d48cd0, 0x9dd0e6a8, 0x33, 0, 0x10012 },
+};
+
+void ar934x_ddr_init(const u16 cpu_mhz, const u16 ddr_mhz, const u16 ahb_mhz)
+{
+	void __iomem *ddr_regs;
+	const struct ar934x_mem_config *memcfg;
+	int memtype;
+	u32 reg, cycle, ctl;
+
+	ddr_regs = map_physmem(AR71XX_DDR_CTRL_BASE, AR71XX_DDR_CTRL_SIZE,
+			       MAP_NOCACHE);
+
+	reg = get_bootstrap();
+	if (reg & AR934X_BOOTSTRAP_SDRAM_DISABLED) {	/* DDR */
+		if (reg & AR934X_BOOTSTRAP_DDR1) {	/* DDR 1 */
+			memtype = AR934X_DDR1;
+			cycle = 0xffff;
+		} else {				/* DDR 2 */
+			memtype = AR934X_DDR2;
+			if (gd->arch.rev) {
+				ctl = BIT(6);	/* Undocumented bit :-( */
+				if (reg & BIT(3))
+					cycle = 0xff;
+				else
+					cycle = 0xffff;
+			} else {
+				/* Force DDR2/x16 configuratio on old chips. */
+				ctl = 0;
+				cycle = 0xffff;		/* DDR2 16bit */
+			}
+
+			writel(0xe59, ddr_regs + AR934X_DDR_REG_DDR2_CONFIG);
+			udelay(100);
+
+			writel(0x10, ddr_regs + AR71XX_DDR_REG_CONTROL);
+			udelay(10);
+
+			writel(0x20, ddr_regs + AR71XX_DDR_REG_CONTROL);
+			udelay(10);
+
+			writel(ctl, ddr_regs + AR934X_DDR_REG_CTL_CONF);
+			udelay(10);
+		}
+	} else {					/* SDRAM */
+		memtype = AR934X_SDRAM;
+		cycle = 0xffffffff;
+
+		writel(0x13b, ddr_regs + AR934X_DDR_REG_CTL_CONF);
+		udelay(100);
+
+		/* Undocumented register */
+		writel(0x13b, ddr_regs + 0x118);
+		udelay(100);
+	}
+
+	memcfg = &ar934x_mem_config[memtype];
+
+	writel(memcfg->config1, ddr_regs + AR71XX_DDR_REG_CONFIG);
+	udelay(100);
+
+	writel(memcfg->config2, ddr_regs + AR71XX_DDR_REG_CONFIG2);
+	udelay(100);
+
+	writel(0x8, ddr_regs + AR71XX_DDR_REG_CONTROL);
+	udelay(10);
+
+	writel(memcfg->mode | 0x100, ddr_regs + AR71XX_DDR_REG_MODE);
+	mdelay(1);
+
+	writel(0x1, ddr_regs + AR71XX_DDR_REG_CONTROL);
+	udelay(10);
+
+	if (memtype == AR934X_DDR2) {
+		writel(memcfg->mode | 0x100, ddr_regs + AR71XX_DDR_REG_EMR);
+		udelay(100);
+
+		writel(0x2, ddr_regs + AR71XX_DDR_REG_CONTROL);
+		udelay(10);
+	}
+
+	if (memtype != AR934X_SDRAM)
+		writel(0x402, ddr_regs + AR71XX_DDR_REG_EMR);
+
+	udelay(100);
+
+	writel(0x2, ddr_regs + AR71XX_DDR_REG_CONTROL);
+	udelay(10);
+
+	writel(0x8, ddr_regs + AR71XX_DDR_REG_CONTROL);
+	udelay(10);
+
+	writel(memcfg->mode, ddr_regs + AR71XX_DDR_REG_MODE);
+	udelay(100);
+
+	writel(0x1, ddr_regs + AR71XX_DDR_REG_CONTROL);
+	udelay(10);
+
+	writel(0x412c /* FIXME */, ddr_regs + AR71XX_DDR_REG_REFRESH);
+	udelay(100);
+
+	writel(memcfg->tap, ddr_regs + AR71XX_DDR_REG_TAP_CTRL0);
+	writel(memcfg->tap, ddr_regs + AR71XX_DDR_REG_TAP_CTRL1);
+
+	if (memtype != AR934X_SDRAM) {
+		if ((gd->arch.rev && (reg & BIT(3))) || !gd->arch.rev) {
+			writel(memcfg->tap,
+			       ddr_regs + AR934X_DDR_REG_TAP_CTRL2);
+			writel(memcfg->tap,
+			       ddr_regs + AR934X_DDR_REG_TAP_CTRL3);
+		}
+	}
+
+	writel(cycle, ddr_regs + AR71XX_DDR_REG_RD_CYCLE);
+	udelay(100);
+
+	writel(0x74444444, ddr_regs + AR934X_DDR_REG_BURST);
+	udelay(100);
+
+	writel(0x222, ddr_regs + AR934X_DDR_REG_BURST2);
+	udelay(100);
+
+	writel(0xfffff, ddr_regs + AR934X_DDR_REG_TIMEOUT_MAX);
+	udelay(100);
+}
+
+void ddr_tap_tuning(void)
+{
+}
diff --git a/arch/mips/mach-ath79/cpu.c b/arch/mips/mach-ath79/cpu.c
new file mode 100644
index 0000000000000000000000000000000000000000..5756a06d5082de35c4faa6f47c1fa15539b1f5f3
--- /dev/null
+++ b/arch/mips/mach-ath79/cpu.c
@@ -0,0 +1,142 @@
+/*
+ * Copyright (C) 2015-2016 Wills Wang <wills.wang@live.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <asm/addrspace.h>
+#include <asm/types.h>
+#include <mach/ath79.h>
+#include <mach/ar71xx_regs.h>
+
+struct ath79_soc_desc {
+	const enum ath79_soc_type soc;
+	const char *chip;
+	const int major;
+	const int minor;
+};
+
+static const struct ath79_soc_desc desc[] = {
+	{ATH79_SOC_AR7130,      "7130",
+	 REV_ID_MAJOR_AR71XX,   AR71XX_REV_ID_MINOR_AR7130},
+	{ATH79_SOC_AR7141,      "7141",
+	 REV_ID_MAJOR_AR71XX,   AR71XX_REV_ID_MINOR_AR7141},
+	{ATH79_SOC_AR7161,      "7161",
+	 REV_ID_MAJOR_AR71XX,   AR71XX_REV_ID_MINOR_AR7161},
+	{ATH79_SOC_AR7240,      "7240", REV_ID_MAJOR_AR7240,    0},
+	{ATH79_SOC_AR7241,      "7241", REV_ID_MAJOR_AR7241,    0},
+	{ATH79_SOC_AR7242,      "7242", REV_ID_MAJOR_AR7242,    0},
+	{ATH79_SOC_AR9130,      "9130",
+	 REV_ID_MAJOR_AR913X,   AR913X_REV_ID_MINOR_AR9130},
+	{ATH79_SOC_AR9132,      "9132",
+	 REV_ID_MAJOR_AR913X,   AR913X_REV_ID_MINOR_AR9132},
+	{ATH79_SOC_AR9330,      "9330", REV_ID_MAJOR_AR9330,    0},
+	{ATH79_SOC_AR9331,      "9331", REV_ID_MAJOR_AR9331,    0},
+	{ATH79_SOC_AR9341,      "9341", REV_ID_MAJOR_AR9341,    0},
+	{ATH79_SOC_AR9342,      "9342", REV_ID_MAJOR_AR9342,    0},
+	{ATH79_SOC_AR9344,      "9344", REV_ID_MAJOR_AR9344,    0},
+	{ATH79_SOC_QCA9533,     "9533", REV_ID_MAJOR_QCA9533,   0},
+	{ATH79_SOC_QCA9533,     "9533",
+	 REV_ID_MAJOR_QCA9533_V2,       0},
+	{ATH79_SOC_QCA9556,     "9556", REV_ID_MAJOR_QCA9556,   0},
+	{ATH79_SOC_QCA9558,     "9558", REV_ID_MAJOR_QCA9558,   0},
+	{ATH79_SOC_TP9343,      "9343", REV_ID_MAJOR_TP9343,    0},
+	{ATH79_SOC_QCA9561,     "9561", REV_ID_MAJOR_QCA9561,   0},
+};
+
+int arch_cpu_init(void)
+{
+	void __iomem *base;
+	enum ath79_soc_type soc = ATH79_SOC_UNKNOWN;
+	u32 id, major, minor = 0;
+	u32 rev = 0, ver = 1;
+	int i;
+
+	base = map_physmem(AR71XX_RESET_BASE, AR71XX_RESET_SIZE,
+			   MAP_NOCACHE);
+
+	id = readl(base + AR71XX_RESET_REG_REV_ID);
+	major = id & REV_ID_MAJOR_MASK;
+	switch (major) {
+	case REV_ID_MAJOR_AR71XX:
+	case REV_ID_MAJOR_AR913X:
+		minor = id & AR71XX_REV_ID_MINOR_MASK;
+		rev = id >> AR71XX_REV_ID_REVISION_SHIFT;
+		rev &= AR71XX_REV_ID_REVISION_MASK;
+		break;
+
+	case REV_ID_MAJOR_QCA9533_V2:
+		ver = 2;
+		/* drop through */
+
+	case REV_ID_MAJOR_AR9341:
+	case REV_ID_MAJOR_AR9342:
+	case REV_ID_MAJOR_AR9344:
+	case REV_ID_MAJOR_QCA9533:
+	case REV_ID_MAJOR_QCA9556:
+	case REV_ID_MAJOR_QCA9558:
+	case REV_ID_MAJOR_TP9343:
+	case REV_ID_MAJOR_QCA9561:
+		rev = id & AR71XX_REV_ID_REVISION2_MASK;
+		break;
+	default:
+		rev = id & AR71XX_REV_ID_REVISION_MASK;
+		break;
+	}
+
+	for (i = 0; i < ARRAY_SIZE(desc); i++) {
+		if ((desc[i].major == major) &&
+		    (desc[i].minor == minor)) {
+			soc = desc[i].soc;
+			break;
+		}
+	}
+
+	gd->arch.id = id;
+	gd->arch.soc = soc;
+	gd->arch.rev = rev;
+	gd->arch.ver = ver;
+	return 0;
+}
+
+int print_cpuinfo(void)
+{
+	enum ath79_soc_type soc = ATH79_SOC_UNKNOWN;
+	const char *chip = "????";
+	u32 id, rev, ver;
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(desc); i++) {
+		if (desc[i].soc == gd->arch.soc) {
+			chip = desc[i].chip;
+			soc = desc[i].soc;
+			break;
+		}
+	}
+
+	id = gd->arch.id;
+	rev = gd->arch.rev;
+	ver = gd->arch.ver;
+
+	switch (soc) {
+	case ATH79_SOC_QCA9533:
+	case ATH79_SOC_QCA9556:
+	case ATH79_SOC_QCA9558:
+	case ATH79_SOC_QCA9561:
+		printf("Qualcomm Atheros QCA%s ver %u rev %u\n", chip,
+		       ver, rev);
+		break;
+	case ATH79_SOC_TP9343:
+		printf("Qualcomm Atheros TP%s rev %u\n", chip, rev);
+		break;
+	case ATH79_SOC_UNKNOWN:
+		printf("ATH79: unknown SoC, id:0x%08x", id);
+		break;
+	default:
+		printf("Atheros AR%s rev %u\n", chip, rev);
+	}
+
+	return 0;
+}
diff --git a/arch/mips/mach-ath79/dram.c b/arch/mips/mach-ath79/dram.c
new file mode 100644
index 0000000000000000000000000000000000000000..c29e98c2f4c2e0009fd843c214490d6d3c1b519e
--- /dev/null
+++ b/arch/mips/mach-ath79/dram.c
@@ -0,0 +1,16 @@
+/*
+ * Copyright (C) 2015-2016 Wills Wang <wills.wang@live.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <linux/sizes.h>
+#include <asm/addrspace.h>
+#include <mach/ddr.h>
+
+phys_size_t initdram(int board_type)
+{
+	ddr_tap_tuning();
+	return get_ram_size((void *)KSEG1, SZ_256M);
+}
diff --git a/arch/mips/mach-ath79/include/mach/ar71xx_regs.h b/arch/mips/mach-ath79/include/mach/ar71xx_regs.h
new file mode 100644
index 0000000000000000000000000000000000000000..a8e51cb4cf4ce24ddb04fcd21c47984db2d50bfa
--- /dev/null
+++ b/arch/mips/mach-ath79/include/mach/ar71xx_regs.h
@@ -0,0 +1,1263 @@
+/*
+ * Atheros AR71XX/AR724X/AR913X SoC register definitions
+ *
+ * Copyright (C) 2015-2016 Wills Wang <wills.wang@live.com>
+ * Copyright (C) 2010-2011 Jaiganesh Narayanan <jnarayanan@atheros.com>
+ * Copyright (C) 2008-2010 Gabor Juhos <juhosg@openwrt.org>
+ * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
+ *
+ * SPDX-License-Identifier:     GPL-2.0+
+ */
+
+#ifndef __ASM_MACH_AR71XX_REGS_H
+#define __ASM_MACH_AR71XX_REGS_H
+
+#ifndef __ASSEMBLY__
+#include <linux/bitops.h>
+#else
+#ifndef BIT
+#define BIT(nr)		(1 << (nr))
+#endif
+#endif
+
+#define AR71XX_APB_BASE					0x18000000
+#define AR71XX_GE0_BASE					0x19000000
+#define AR71XX_GE0_SIZE					0x10000
+#define AR71XX_GE1_BASE					0x1a000000
+#define AR71XX_GE1_SIZE					0x10000
+#define AR71XX_EHCI_BASE				0x1b000000
+#define AR71XX_EHCI_SIZE				0x1000
+#define AR71XX_OHCI_BASE				0x1c000000
+#define AR71XX_OHCI_SIZE				0x1000
+#define AR71XX_SPI_BASE					0x1f000000
+#define AR71XX_SPI_SIZE					0x01000000
+
+#define AR71XX_DDR_CTRL_BASE \
+	(AR71XX_APB_BASE + 0x00000000)
+#define AR71XX_DDR_CTRL_SIZE				0x100
+#define AR71XX_UART_BASE \
+	(AR71XX_APB_BASE + 0x00020000)
+#define AR71XX_UART_SIZE				0x100
+#define AR71XX_USB_CTRL_BASE \
+	(AR71XX_APB_BASE + 0x00030000)
+#define AR71XX_USB_CTRL_SIZE				0x100
+#define AR71XX_GPIO_BASE \
+	(AR71XX_APB_BASE + 0x00040000)
+#define AR71XX_GPIO_SIZE				0x100
+#define AR71XX_PLL_BASE \
+	(AR71XX_APB_BASE + 0x00050000)
+#define AR71XX_PLL_SIZE					0x100
+#define AR71XX_RESET_BASE \
+	(AR71XX_APB_BASE + 0x00060000)
+#define AR71XX_RESET_SIZE				0x100
+#define AR71XX_MII_BASE \
+	(AR71XX_APB_BASE + 0x00070000)
+#define AR71XX_MII_SIZE					0x100
+
+#define AR71XX_PCI_MEM_BASE				0x10000000
+#define AR71XX_PCI_MEM_SIZE				0x07000000
+
+#define AR71XX_PCI_WIN0_OFFS				0x10000000
+#define AR71XX_PCI_WIN1_OFFS				0x11000000
+#define AR71XX_PCI_WIN2_OFFS				0x12000000
+#define AR71XX_PCI_WIN3_OFFS				0x13000000
+#define AR71XX_PCI_WIN4_OFFS				0x14000000
+#define AR71XX_PCI_WIN5_OFFS				0x15000000
+#define AR71XX_PCI_WIN6_OFFS				0x16000000
+#define AR71XX_PCI_WIN7_OFFS				0x07000000
+
+#define AR71XX_PCI_CFG_BASE \
+	(AR71XX_PCI_MEM_BASE + AR71XX_PCI_WIN7_OFFS + 0x10000)
+#define AR71XX_PCI_CFG_SIZE				0x100
+
+#define AR7240_USB_CTRL_BASE \
+	(AR71XX_APB_BASE + 0x00030000)
+#define AR7240_USB_CTRL_SIZE				0x100
+#define AR7240_OHCI_BASE				0x1b000000
+#define AR7240_OHCI_SIZE				0x1000
+
+#define AR724X_PCI_MEM_BASE				0x10000000
+#define AR724X_PCI_MEM_SIZE				0x04000000
+
+#define AR724X_PCI_CFG_BASE				0x14000000
+#define AR724X_PCI_CFG_SIZE				0x1000
+#define AR724X_PCI_CRP_BASE \
+	(AR71XX_APB_BASE + 0x000c0000)
+#define AR724X_PCI_CRP_SIZE				0x1000
+#define AR724X_PCI_CTRL_BASE \
+	(AR71XX_APB_BASE + 0x000f0000)
+#define AR724X_PCI_CTRL_SIZE				0x100
+
+#define AR724X_EHCI_BASE				0x1b000000
+#define AR724X_EHCI_SIZE				0x1000
+
+#define AR913X_EHCI_BASE				0x1b000000
+#define AR913X_EHCI_SIZE				0x1000
+#define AR913X_WMAC_BASE \
+	(AR71XX_APB_BASE + 0x000C0000)
+#define AR913X_WMAC_SIZE				0x30000
+
+#define AR933X_UART_BASE \
+	(AR71XX_APB_BASE + 0x00020000)
+#define AR933X_UART_SIZE				0x14
+#define AR933X_GMAC_BASE \
+	(AR71XX_APB_BASE + 0x00070000)
+#define AR933X_GMAC_SIZE				0x04
+#define AR933X_WMAC_BASE \
+	(AR71XX_APB_BASE + 0x00100000)
+#define AR933X_WMAC_SIZE				0x20000
+#define AR933X_RTC_BASE \
+	(AR71XX_APB_BASE + 0x00107000)
+#define AR933X_RTC_SIZE					0x1000
+#define AR933X_EHCI_BASE				0x1b000000
+#define AR933X_EHCI_SIZE				0x1000
+#define AR933X_SRIF_BASE \
+	(AR71XX_APB_BASE + 0x00116000)
+#define AR933X_SRIF_SIZE				0x1000
+
+#define AR934X_GMAC_BASE \
+	(AR71XX_APB_BASE + 0x00070000)
+#define AR934X_GMAC_SIZE				0x14
+#define AR934X_WMAC_BASE \
+	(AR71XX_APB_BASE + 0x00100000)
+#define AR934X_WMAC_SIZE				0x20000
+#define AR934X_EHCI_BASE				0x1b000000
+#define AR934X_EHCI_SIZE				0x200
+#define AR934X_NFC_BASE					0x1b000200
+#define AR934X_NFC_SIZE					0xb8
+#define AR934X_SRIF_BASE \
+	(AR71XX_APB_BASE + 0x00116000)
+#define AR934X_SRIF_SIZE				0x1000
+
+#define QCA953X_GMAC_BASE \
+	(AR71XX_APB_BASE + 0x00070000)
+#define QCA953X_GMAC_SIZE				0x14
+#define QCA953X_WMAC_BASE \
+	(AR71XX_APB_BASE + 0x00100000)
+#define QCA953X_WMAC_SIZE				0x20000
+#define QCA953X_RTC_BASE \
+	(AR71XX_APB_BASE + 0x00107000)
+#define QCA953X_RTC_SIZE				0x1000
+#define QCA953X_EHCI_BASE				0x1b000000
+#define QCA953X_EHCI_SIZE				0x200
+#define QCA953X_SRIF_BASE \
+	(AR71XX_APB_BASE + 0x00116000)
+#define QCA953X_SRIF_SIZE				0x1000
+
+#define QCA953X_PCI_CFG_BASE0				0x14000000
+#define QCA953X_PCI_CTRL_BASE0 \
+	(AR71XX_APB_BASE + 0x000f0000)
+#define QCA953X_PCI_CRP_BASE0 \
+	(AR71XX_APB_BASE + 0x000c0000)
+#define QCA953X_PCI_MEM_BASE0				0x10000000
+#define QCA953X_PCI_MEM_SIZE				0x02000000
+
+#define QCA955X_PCI_MEM_BASE0				0x10000000
+#define QCA955X_PCI_MEM_BASE1				0x12000000
+#define QCA955X_PCI_MEM_SIZE				0x02000000
+#define QCA955X_PCI_CFG_BASE0				0x14000000
+#define QCA955X_PCI_CFG_BASE1				0x16000000
+#define QCA955X_PCI_CFG_SIZE				0x1000
+#define QCA955X_PCI_CRP_BASE0 \
+	(AR71XX_APB_BASE + 0x000c0000)
+#define QCA955X_PCI_CRP_BASE1 \
+	(AR71XX_APB_BASE + 0x00250000)
+#define QCA955X_PCI_CRP_SIZE				0x1000
+#define QCA955X_PCI_CTRL_BASE0 \
+	(AR71XX_APB_BASE + 0x000f0000)
+#define QCA955X_PCI_CTRL_BASE1 \
+	(AR71XX_APB_BASE + 0x00280000)
+#define QCA955X_PCI_CTRL_SIZE				0x100
+
+#define QCA955X_GMAC_BASE \
+	(AR71XX_APB_BASE + 0x00070000)
+#define QCA955X_GMAC_SIZE				0x40
+#define QCA955X_WMAC_BASE \
+	(AR71XX_APB_BASE + 0x00100000)
+#define QCA955X_WMAC_SIZE				0x20000
+#define QCA955X_EHCI0_BASE				0x1b000000
+#define QCA955X_EHCI1_BASE				0x1b400000
+#define QCA955X_EHCI_SIZE				0x1000
+#define QCA955X_NFC_BASE				0x1b800200
+#define QCA955X_NFC_SIZE				0xb8
+
+#define QCA956X_PCI_MEM_BASE1				0x12000000
+#define QCA956X_PCI_MEM_SIZE				0x02000000
+#define QCA956X_PCI_CFG_BASE1				0x16000000
+#define QCA956X_PCI_CFG_SIZE				0x1000
+#define QCA956X_PCI_CRP_BASE1 \
+	(AR71XX_APB_BASE + 0x00250000)
+#define QCA956X_PCI_CRP_SIZE				0x1000
+#define QCA956X_PCI_CTRL_BASE1 \
+	(AR71XX_APB_BASE + 0x00280000)
+#define QCA956X_PCI_CTRL_SIZE				0x100
+
+#define QCA956X_WMAC_BASE \
+	(AR71XX_APB_BASE + 0x00100000)
+#define QCA956X_WMAC_SIZE				0x20000
+#define QCA956X_EHCI0_BASE				0x1b000000
+#define QCA956X_EHCI1_BASE				0x1b400000
+#define QCA956X_EHCI_SIZE				0x200
+#define QCA956X_GMAC_BASE \
+	(AR71XX_APB_BASE + 0x00070000)
+#define QCA956X_GMAC_SIZE				0x64
+
+/*
+ * DDR_CTRL block
+ */
+#define AR71XX_DDR_REG_CONFIG				0x00
+#define AR71XX_DDR_REG_CONFIG2				0x04
+#define AR71XX_DDR_REG_MODE				0x08
+#define AR71XX_DDR_REG_EMR				0x0c
+#define AR71XX_DDR_REG_CONTROL				0x10
+#define AR71XX_DDR_REG_REFRESH				0x14
+#define AR71XX_DDR_REG_RD_CYCLE				0x18
+#define AR71XX_DDR_REG_TAP_CTRL0			0x1c
+#define AR71XX_DDR_REG_TAP_CTRL1			0x20
+
+#define AR71XX_DDR_REG_PCI_WIN0				0x7c
+#define AR71XX_DDR_REG_PCI_WIN1				0x80
+#define AR71XX_DDR_REG_PCI_WIN2				0x84
+#define AR71XX_DDR_REG_PCI_WIN3				0x88
+#define AR71XX_DDR_REG_PCI_WIN4				0x8c
+#define AR71XX_DDR_REG_PCI_WIN5				0x90
+#define AR71XX_DDR_REG_PCI_WIN6				0x94
+#define AR71XX_DDR_REG_PCI_WIN7				0x98
+#define AR71XX_DDR_REG_FLUSH_GE0			0x9c
+#define AR71XX_DDR_REG_FLUSH_GE1			0xa0
+#define AR71XX_DDR_REG_FLUSH_USB			0xa4
+#define AR71XX_DDR_REG_FLUSH_PCI			0xa8
+
+#define AR724X_DDR_REG_FLUSH_GE0			0x7c
+#define AR724X_DDR_REG_FLUSH_GE1			0x80
+#define AR724X_DDR_REG_FLUSH_USB			0x84
+#define AR724X_DDR_REG_FLUSH_PCIE			0x88
+
+#define AR913X_DDR_REG_FLUSH_GE0			0x7c
+#define AR913X_DDR_REG_FLUSH_GE1			0x80
+#define AR913X_DDR_REG_FLUSH_USB			0x84
+#define AR913X_DDR_REG_FLUSH_WMAC			0x88
+
+#define AR933X_DDR_REG_FLUSH_GE0			0x7c
+#define AR933X_DDR_REG_FLUSH_GE1			0x80
+#define AR933X_DDR_REG_FLUSH_USB			0x84
+#define AR933X_DDR_REG_FLUSH_WMAC			0x88
+#define AR933X_DDR_REG_DDR2_CONFIG			0x8c
+#define AR933X_DDR_REG_EMR2				0x90
+#define AR933X_DDR_REG_EMR3				0x94
+#define AR933X_DDR_REG_BURST				0x98
+#define AR933X_DDR_REG_TIMEOUT_MAX			0x9c
+#define AR933X_DDR_REG_TIMEOUT_CNT			0x9c
+#define AR933X_DDR_REG_TIMEOUT_ADDR			0x9c
+
+#define AR934X_DDR_REG_TAP_CTRL2			0x24
+#define AR934X_DDR_REG_TAP_CTRL3			0x28
+#define AR934X_DDR_REG_FLUSH_GE0			0x9c
+#define AR934X_DDR_REG_FLUSH_GE1			0xa0
+#define AR934X_DDR_REG_FLUSH_USB			0xa4
+#define AR934X_DDR_REG_FLUSH_PCIE			0xa8
+#define AR934X_DDR_REG_FLUSH_WMAC			0xac
+#define AR934X_DDR_REG_FLUSH_SRC1			0xb0
+#define AR934X_DDR_REG_FLUSH_SRC2			0xb4
+#define AR934X_DDR_REG_DDR2_CONFIG			0xb8
+#define AR934X_DDR_REG_EMR2				0xbc
+#define AR934X_DDR_REG_EMR3				0xc0
+#define AR934X_DDR_REG_BURST				0xc4
+#define AR934X_DDR_REG_BURST2				0xc8
+#define AR934X_DDR_REG_TIMEOUT_MAX			0xcc
+#define AR934X_DDR_REG_CTL_CONF				0x108
+
+#define QCA953X_DDR_REG_FLUSH_GE0			0x9c
+#define QCA953X_DDR_REG_FLUSH_GE1			0xa0
+#define QCA953X_DDR_REG_FLUSH_USB			0xa4
+#define QCA953X_DDR_REG_FLUSH_PCIE			0xa8
+#define QCA953X_DDR_REG_FLUSH_WMAC			0xac
+#define QCA953X_DDR_REG_DDR2_CONFIG			0xb8
+#define QCA953X_DDR_REG_BURST				0xc4
+#define QCA953X_DDR_REG_BURST2				0xc8
+#define QCA953X_DDR_REG_TIMEOUT_MAX			0xcc
+#define QCA953X_DDR_REG_CTL_CONF			0x108
+#define QCA953X_DDR_REG_CONFIG3				0x15c
+
+/*
+ * PLL block
+ */
+#define AR71XX_PLL_REG_CPU_CONFIG			0x00
+#define AR71XX_PLL_REG_SEC_CONFIG			0x04
+#define AR71XX_PLL_REG_ETH0_INT_CLOCK			0x10
+#define AR71XX_PLL_REG_ETH1_INT_CLOCK			0x14
+
+#define AR71XX_PLL_DIV_SHIFT				3
+#define AR71XX_PLL_DIV_MASK				0x1f
+#define AR71XX_CPU_DIV_SHIFT				16
+#define AR71XX_CPU_DIV_MASK				0x3
+#define AR71XX_DDR_DIV_SHIFT				18
+#define AR71XX_DDR_DIV_MASK				0x3
+#define AR71XX_AHB_DIV_SHIFT				20
+#define AR71XX_AHB_DIV_MASK				0x7
+
+#define AR71XX_ETH0_PLL_SHIFT				17
+#define AR71XX_ETH1_PLL_SHIFT				19
+
+#define AR724X_PLL_REG_CPU_CONFIG			0x00
+#define AR724X_PLL_REG_PCIE_CONFIG			0x18
+
+#define AR724X_PLL_DIV_SHIFT				0
+#define AR724X_PLL_DIV_MASK				0x3ff
+#define AR724X_PLL_REF_DIV_SHIFT			10
+#define AR724X_PLL_REF_DIV_MASK				0xf
+#define AR724X_AHB_DIV_SHIFT				19
+#define AR724X_AHB_DIV_MASK				0x1
+#define AR724X_DDR_DIV_SHIFT				22
+#define AR724X_DDR_DIV_MASK				0x3
+
+#define AR7242_PLL_REG_ETH0_INT_CLOCK			0x2c
+
+#define AR913X_PLL_REG_CPU_CONFIG			0x00
+#define AR913X_PLL_REG_ETH_CONFIG			0x04
+#define AR913X_PLL_REG_ETH0_INT_CLOCK			0x14
+#define AR913X_PLL_REG_ETH1_INT_CLOCK			0x18
+
+#define AR913X_PLL_DIV_SHIFT				0
+#define AR913X_PLL_DIV_MASK				0x3ff
+#define AR913X_DDR_DIV_SHIFT				22
+#define AR913X_DDR_DIV_MASK				0x3
+#define AR913X_AHB_DIV_SHIFT				19
+#define AR913X_AHB_DIV_MASK				0x1
+
+#define AR913X_ETH0_PLL_SHIFT				20
+#define AR913X_ETH1_PLL_SHIFT				22
+
+#define AR933X_PLL_CPU_CONFIG_REG			0x00
+#define AR933X_PLL_CLK_CTRL_REG				0x08
+#define AR933X_PLL_DITHER_FRAC_REG			0x10
+
+#define AR933X_PLL_CPU_CONFIG_NINT_SHIFT		10
+#define AR933X_PLL_CPU_CONFIG_NINT_MASK			0x3f
+#define AR933X_PLL_CPU_CONFIG_REFDIV_SHIFT		16
+#define AR933X_PLL_CPU_CONFIG_REFDIV_MASK		0x1f
+#define AR933X_PLL_CPU_CONFIG_OUTDIV_SHIFT		23
+#define AR933X_PLL_CPU_CONFIG_OUTDIV_MASK		0x7
+
+#define AR933X_PLL_CLK_CTRL_BYPASS			BIT(2)
+#define AR933X_PLL_CLK_CTRL_CPU_POST_DIV_SHIFT		5
+#define AR933X_PLL_CLK_CTRL_CPU_POST_DIV_MASK		0x3
+#define AR933X_PLL_CLK_CTRL_DDR_POST_DIV_SHIFT		10
+#define AR933X_PLL_CLK_CTRL_DDR_POST_DIV_MASK		0x3
+#define AR933X_PLL_CLK_CTRL_AHB_POST_DIV_SHIFT		15
+#define AR933X_PLL_CLK_CTRL_AHB_POST_DIV_MASK		0x7
+
+#define AR934X_PLL_CPU_CONFIG_REG			0x00
+#define AR934X_PLL_DDR_CONFIG_REG			0x04
+#define AR934X_PLL_CPU_DDR_CLK_CTRL_REG			0x08
+#define AR934X_PLL_SWITCH_CLOCK_CONTROL_REG		0x24
+#define AR934X_PLL_ETH_XMII_CONTROL_REG			0x2c
+#define AR934X_PLL_DDR_DIT_FRAC_REG			0x44
+#define AR934X_PLL_CPU_DIT_FRAC_REG			0x48
+
+#define AR934X_PLL_CPU_CONFIG_NFRAC_SHIFT		0
+#define AR934X_PLL_CPU_CONFIG_NFRAC_MASK		0x3f
+#define AR934X_PLL_CPU_CONFIG_NINT_SHIFT		6
+#define AR934X_PLL_CPU_CONFIG_NINT_MASK			0x3f
+#define AR934X_PLL_CPU_CONFIG_REFDIV_SHIFT		12
+#define AR934X_PLL_CPU_CONFIG_REFDIV_MASK		0x1f
+#define AR934X_PLL_CPU_CONFIG_RANGE_SHIFT		17
+#define AR934X_PLL_CPU_CONFIG_RANGE_MASK		0x3
+#define AR934X_PLL_CPU_CONFIG_OUTDIV_SHIFT		19
+#define AR934X_PLL_CPU_CONFIG_OUTDIV_MASK		0x3
+#define AR934X_PLL_CPU_CONFIG_PLLPWD			BIT(30)
+#define AR934X_PLL_CPU_CONFIG_UPDATING			BIT(31)
+
+#define AR934X_PLL_DDR_CONFIG_NFRAC_SHIFT		0
+#define AR934X_PLL_DDR_CONFIG_NFRAC_MASK		0x3ff
+#define AR934X_PLL_DDR_CONFIG_NINT_SHIFT		10
+#define AR934X_PLL_DDR_CONFIG_NINT_MASK			0x3f
+#define AR934X_PLL_DDR_CONFIG_REFDIV_SHIFT		16
+#define AR934X_PLL_DDR_CONFIG_REFDIV_MASK		0x1f
+#define AR934X_PLL_DDR_CONFIG_RANGE_SHIFT		21
+#define AR934X_PLL_DDR_CONFIG_RANGE_MASK		0x3
+#define AR934X_PLL_DDR_CONFIG_OUTDIV_SHIFT		23
+#define AR934X_PLL_DDR_CONFIG_OUTDIV_MASK		0x7
+#define AR934X_PLL_DDR_CONFIG_PLLPWD			BIT(30)
+#define AR934X_PLL_DDR_CONFIG_UPDATING			BIT(31)
+
+#define AR934X_PLL_CLK_CTRL_CPU_PLL_BYPASS		BIT(2)
+#define AR934X_PLL_CLK_CTRL_DDR_PLL_BYPASS		BIT(3)
+#define AR934X_PLL_CLK_CTRL_AHB_PLL_BYPASS		BIT(4)
+#define AR934X_PLL_CLK_CTRL_CPU_POST_DIV_SHIFT		5
+#define AR934X_PLL_CLK_CTRL_CPU_POST_DIV_MASK		0x1f
+#define AR934X_PLL_CLK_CTRL_DDR_POST_DIV_SHIFT		10
+#define AR934X_PLL_CLK_CTRL_DDR_POST_DIV_MASK		0x1f
+#define AR934X_PLL_CLK_CTRL_AHB_POST_DIV_SHIFT		15
+#define AR934X_PLL_CLK_CTRL_AHB_POST_DIV_MASK		0x1f
+#define AR934X_PLL_CLK_CTRL_CPUCLK_FROM_CPUPLL		BIT(20)
+#define AR934X_PLL_CLK_CTRL_DDRCLK_FROM_DDRPLL		BIT(21)
+#define AR934X_PLL_CLK_CTRL_AHBCLK_FROM_DDRPLL		BIT(24)
+
+#define AR934X_PLL_SWITCH_CLK_CTRL_MDIO_CLK_SEL		BIT(6)
+
+#define AR934X_PLL_DDR_DIT_FRAC_MAX_SHIFT		0
+#define AR934X_PLL_DDR_DIT_FRAC_MAX_MASK		0x3ff
+#define AR934X_PLL_DDR_DIT_FRAC_MIN_SHIFT		10
+#define AR934X_PLL_DDR_DIT_FRAC_MIN_MASK		0x3ff
+#define AR934X_PLL_DDR_DIT_FRAC_STEP_SHIFT		20
+#define AR934X_PLL_DDR_DIT_FRAC_STEP_MASK		0x3f
+#define AR934X_PLL_DDR_DIT_UPD_CNT_SHIFT		27
+#define AR934X_PLL_DDR_DIT_UPD_CNT_MASK			0x3f
+#define AR934X_PLL_DDR_DIT_DITHER_EN			BIT(31)
+
+#define AR934X_PLL_CPU_DIT_FRAC_MAX_SHIFT		0
+#define AR934X_PLL_CPU_DIT_FRAC_MAX_MASK		0x3f
+#define AR934X_PLL_CPU_DIT_FRAC_MIN_SHIFT		6
+#define AR934X_PLL_CPU_DIT_FRAC_MIN_MASK		0x3f
+#define AR934X_PLL_CPU_DIT_FRAC_STEP_SHIFT		12
+#define AR934X_PLL_CPU_DIT_FRAC_STEP_MASK		0x3f
+#define AR934X_PLL_CPU_DIT_UPD_CNT_SHIFT		18
+#define AR934X_PLL_CPU_DIT_UPD_CNT_MASK			0x3f
+#define AR934X_PLL_CPU_DIT_DITHER_EN			BIT(31)
+
+#define QCA953X_PLL_CPU_CONFIG_REG			0x00
+#define QCA953X_PLL_DDR_CONFIG_REG			0x04
+#define QCA953X_PLL_CLK_CTRL_REG			0x08
+#define QCA953X_PLL_SWITCH_CLOCK_CONTROL_REG		0x24
+#define QCA953X_PLL_ETH_XMII_CONTROL_REG		0x2c
+#define QCA953X_PLL_DDR_DIT_FRAC_REG			0x44
+#define QCA953X_PLL_CPU_DIT_FRAC_REG			0x48
+
+#define QCA953X_PLL_CPU_CONFIG_NFRAC_SHIFT		0
+#define QCA953X_PLL_CPU_CONFIG_NFRAC_MASK		0x3f
+#define QCA953X_PLL_CPU_CONFIG_NINT_SHIFT		6
+#define QCA953X_PLL_CPU_CONFIG_NINT_MASK		0x3f
+#define QCA953X_PLL_CPU_CONFIG_REFDIV_SHIFT		12
+#define QCA953X_PLL_CPU_CONFIG_REFDIV_MASK		0x1f
+#define QCA953X_PLL_CPU_CONFIG_OUTDIV_SHIFT		19
+#define QCA953X_PLL_CPU_CONFIG_OUTDIV_MASK		0x7
+
+#define QCA953X_PLL_DDR_CONFIG_NFRAC_SHIFT		0
+#define QCA953X_PLL_DDR_CONFIG_NFRAC_MASK		0x3ff
+#define QCA953X_PLL_DDR_CONFIG_NINT_SHIFT		10
+#define QCA953X_PLL_DDR_CONFIG_NINT_MASK		0x3f
+#define QCA953X_PLL_DDR_CONFIG_REFDIV_SHIFT		16
+#define QCA953X_PLL_DDR_CONFIG_REFDIV_MASK		0x1f
+#define QCA953X_PLL_DDR_CONFIG_OUTDIV_SHIFT		23
+#define QCA953X_PLL_DDR_CONFIG_OUTDIV_MASK		0x7
+
+#define QCA953X_PLL_CONFIG_PWD		BIT(30)
+
+#define QCA953X_PLL_CLK_CTRL_CPU_PLL_BYPASS		BIT(2)
+#define QCA953X_PLL_CLK_CTRL_DDR_PLL_BYPASS		BIT(3)
+#define QCA953X_PLL_CLK_CTRL_AHB_PLL_BYPASS		BIT(4)
+#define QCA953X_PLL_CLK_CTRL_CPU_POST_DIV_SHIFT		5
+#define QCA953X_PLL_CLK_CTRL_CPU_POST_DIV_MASK		0x1f
+#define QCA953X_PLL_CLK_CTRL_DDR_POST_DIV_SHIFT		10
+#define QCA953X_PLL_CLK_CTRL_DDR_POST_DIV_MASK		0x1f
+#define QCA953X_PLL_CLK_CTRL_AHB_POST_DIV_SHIFT		15
+#define QCA953X_PLL_CLK_CTRL_AHB_POST_DIV_MASK		0x1f
+#define QCA953X_PLL_CLK_CTRL_CPUCLK_FROM_CPUPLL		BIT(20)
+#define QCA953X_PLL_CLK_CTRL_DDRCLK_FROM_DDRPLL		BIT(21)
+#define QCA953X_PLL_CLK_CTRL_AHBCLK_FROM_DDRPLL		BIT(24)
+
+#define QCA953X_PLL_CPU_DIT_FRAC_MAX_SHIFT		0
+#define QCA953X_PLL_CPU_DIT_FRAC_MAX_MASK		0x3f
+#define QCA953X_PLL_CPU_DIT_FRAC_MIN_SHIFT		6
+#define QCA953X_PLL_CPU_DIT_FRAC_MIN_MASK		0x3f
+#define QCA953X_PLL_CPU_DIT_FRAC_STEP_SHIFT		12
+#define QCA953X_PLL_CPU_DIT_FRAC_STEP_MASK		0x3f
+#define QCA953X_PLL_CPU_DIT_UPD_CNT_SHIFT		18
+#define QCA953X_PLL_CPU_DIT_UPD_CNT_MASK		0x3f
+
+#define QCA953X_PLL_DDR_DIT_FRAC_MAX_SHIFT		0
+#define QCA953X_PLL_DDR_DIT_FRAC_MAX_MASK		0x3ff
+#define QCA953X_PLL_DDR_DIT_FRAC_MIN_SHIFT		9
+#define QCA953X_PLL_DDR_DIT_FRAC_MIN_MASK		0x3ff
+#define QCA953X_PLL_DDR_DIT_FRAC_STEP_SHIFT		20
+#define QCA953X_PLL_DDR_DIT_FRAC_STEP_MASK		0x3f
+#define QCA953X_PLL_DDR_DIT_UPD_CNT_SHIFT		27
+#define QCA953X_PLL_DDR_DIT_UPD_CNT_MASK		0x3f
+
+#define QCA953X_PLL_DIT_FRAC_EN				BIT(31)
+
+#define QCA955X_PLL_CPU_CONFIG_REG			0x00
+#define QCA955X_PLL_DDR_CONFIG_REG			0x04
+#define QCA955X_PLL_CLK_CTRL_REG			0x08
+#define QCA955X_PLL_ETH_XMII_CONTROL_REG		0x28
+#define QCA955X_PLL_ETH_SGMII_CONTROL_REG		0x48
+
+#define QCA955X_PLL_CPU_CONFIG_NFRAC_SHIFT		0
+#define QCA955X_PLL_CPU_CONFIG_NFRAC_MASK		0x3f
+#define QCA955X_PLL_CPU_CONFIG_NINT_SHIFT		6
+#define QCA955X_PLL_CPU_CONFIG_NINT_MASK		0x3f
+#define QCA955X_PLL_CPU_CONFIG_REFDIV_SHIFT		12
+#define QCA955X_PLL_CPU_CONFIG_REFDIV_MASK		0x1f
+#define QCA955X_PLL_CPU_CONFIG_OUTDIV_SHIFT		19
+#define QCA955X_PLL_CPU_CONFIG_OUTDIV_MASK		0x3
+
+#define QCA955X_PLL_DDR_CONFIG_NFRAC_SHIFT		0
+#define QCA955X_PLL_DDR_CONFIG_NFRAC_MASK		0x3ff
+#define QCA955X_PLL_DDR_CONFIG_NINT_SHIFT		10
+#define QCA955X_PLL_DDR_CONFIG_NINT_MASK		0x3f
+#define QCA955X_PLL_DDR_CONFIG_REFDIV_SHIFT		16
+#define QCA955X_PLL_DDR_CONFIG_REFDIV_MASK		0x1f
+#define QCA955X_PLL_DDR_CONFIG_OUTDIV_SHIFT		23
+#define QCA955X_PLL_DDR_CONFIG_OUTDIV_MASK		0x7
+
+#define QCA955X_PLL_CLK_CTRL_CPU_PLL_BYPASS		BIT(2)
+#define QCA955X_PLL_CLK_CTRL_DDR_PLL_BYPASS		BIT(3)
+#define QCA955X_PLL_CLK_CTRL_AHB_PLL_BYPASS		BIT(4)
+#define QCA955X_PLL_CLK_CTRL_CPU_POST_DIV_SHIFT		5
+#define QCA955X_PLL_CLK_CTRL_CPU_POST_DIV_MASK		0x1f
+#define QCA955X_PLL_CLK_CTRL_DDR_POST_DIV_SHIFT		10
+#define QCA955X_PLL_CLK_CTRL_DDR_POST_DIV_MASK		0x1f
+#define QCA955X_PLL_CLK_CTRL_AHB_POST_DIV_SHIFT		15
+#define QCA955X_PLL_CLK_CTRL_AHB_POST_DIV_MASK		0x1f
+#define QCA955X_PLL_CLK_CTRL_CPUCLK_FROM_CPUPLL		BIT(20)
+#define QCA955X_PLL_CLK_CTRL_DDRCLK_FROM_DDRPLL		BIT(21)
+#define QCA955X_PLL_CLK_CTRL_AHBCLK_FROM_DDRPLL		BIT(24)
+
+#define QCA956X_PLL_CPU_CONFIG_REG			0x00
+#define QCA956X_PLL_CPU_CONFIG1_REG			0x04
+#define QCA956X_PLL_DDR_CONFIG_REG			0x08
+#define QCA956X_PLL_DDR_CONFIG1_REG			0x0c
+#define QCA956X_PLL_CLK_CTRL_REG			0x10
+
+#define QCA956X_PLL_CPU_CONFIG_REFDIV_SHIFT		12
+#define QCA956X_PLL_CPU_CONFIG_REFDIV_MASK		0x1f
+#define QCA956X_PLL_CPU_CONFIG_OUTDIV_SHIFT		19
+#define QCA956X_PLL_CPU_CONFIG_OUTDIV_MASK		0x7
+
+#define QCA956X_PLL_CPU_CONFIG1_NFRAC_L_SHIFT		0
+#define QCA956X_PLL_CPU_CONFIG1_NFRAC_L_MASK		0x1f
+#define QCA956X_PLL_CPU_CONFIG1_NFRAC_H_SHIFT		5
+#define QCA956X_PLL_CPU_CONFIG1_NFRAC_H_MASK		0x3fff
+#define QCA956X_PLL_CPU_CONFIG1_NINT_SHIFT		18
+#define QCA956X_PLL_CPU_CONFIG1_NINT_MASK		0x1ff
+
+#define QCA956X_PLL_DDR_CONFIG_REFDIV_SHIFT		16
+#define QCA956X_PLL_DDR_CONFIG_REFDIV_MASK		0x1f
+#define QCA956X_PLL_DDR_CONFIG_OUTDIV_SHIFT		23
+#define QCA956X_PLL_DDR_CONFIG_OUTDIV_MASK		0x7
+
+#define QCA956X_PLL_DDR_CONFIG1_NFRAC_L_SHIFT		0
+#define QCA956X_PLL_DDR_CONFIG1_NFRAC_L_MASK		0x1f
+#define QCA956X_PLL_DDR_CONFIG1_NFRAC_H_SHIFT		5
+#define QCA956X_PLL_DDR_CONFIG1_NFRAC_H_MASK		0x3fff
+#define QCA956X_PLL_DDR_CONFIG1_NINT_SHIFT		18
+#define QCA956X_PLL_DDR_CONFIG1_NINT_MASK		0x1ff
+
+#define QCA956X_PLL_CLK_CTRL_CPU_PLL_BYPASS		BIT(2)
+#define QCA956X_PLL_CLK_CTRL_DDR_PLL_BYPASS		BIT(3)
+#define QCA956X_PLL_CLK_CTRL_AHB_PLL_BYPASS		BIT(4)
+#define QCA956X_PLL_CLK_CTRL_CPU_POST_DIV_SHIFT		5
+#define QCA956X_PLL_CLK_CTRL_CPU_POST_DIV_MASK		0x1f
+#define QCA956X_PLL_CLK_CTRL_DDR_POST_DIV_SHIFT		10
+#define QCA956X_PLL_CLK_CTRL_DDR_POST_DIV_MASK		0x1f
+#define QCA956X_PLL_CLK_CTRL_AHB_POST_DIV_SHIFT		15
+#define QCA956X_PLL_CLK_CTRL_AHB_POST_DIV_MASK		0x1f
+#define QCA956X_PLL_CLK_CTRL_CPU_DDRCLK_FROM_DDRPLL	BIT(20)
+#define QCA956X_PLL_CLK_CTRL_CPU_DDRCLK_FROM_CPUPLL	BIT(21)
+#define QCA956X_PLL_CLK_CTRL_AHBCLK_FROM_DDRPLL		BIT(24)
+
+/*
+ * USB_CONFIG block
+ */
+#define AR71XX_USB_CTRL_REG_FLADJ			0x00
+#define AR71XX_USB_CTRL_REG_CONFIG			0x04
+
+/*
+ * RESET block
+ */
+#define AR71XX_RESET_REG_TIMER				0x00
+#define AR71XX_RESET_REG_TIMER_RELOAD			0x04
+#define AR71XX_RESET_REG_WDOG_CTRL			0x08
+#define AR71XX_RESET_REG_WDOG				0x0c
+#define AR71XX_RESET_REG_MISC_INT_STATUS		0x10
+#define AR71XX_RESET_REG_MISC_INT_ENABLE		0x14
+#define AR71XX_RESET_REG_PCI_INT_STATUS			0x18
+#define AR71XX_RESET_REG_PCI_INT_ENABLE			0x1c
+#define AR71XX_RESET_REG_GLOBAL_INT_STATUS		0x20
+#define AR71XX_RESET_REG_RESET_MODULE			0x24
+#define AR71XX_RESET_REG_PERFC_CTRL			0x2c
+#define AR71XX_RESET_REG_PERFC0				0x30
+#define AR71XX_RESET_REG_PERFC1				0x34
+#define AR71XX_RESET_REG_REV_ID				0x90
+
+#define AR913X_RESET_REG_GLOBAL_INT_STATUS		0x18
+#define AR913X_RESET_REG_RESET_MODULE			0x1c
+#define AR913X_RESET_REG_PERF_CTRL			0x20
+#define AR913X_RESET_REG_PERFC0				0x24
+#define AR913X_RESET_REG_PERFC1				0x28
+
+#define AR724X_RESET_REG_RESET_MODULE			0x1c
+
+#define AR933X_RESET_REG_RESET_MODULE			0x1c
+#define AR933X_RESET_REG_BOOTSTRAP			0xac
+
+#define AR934X_RESET_REG_RESET_MODULE			0x1c
+#define AR934X_RESET_REG_BOOTSTRAP			0xb0
+#define AR934X_RESET_REG_PCIE_WMAC_INT_STATUS		0xac
+
+#define QCA953X_RESET_REG_RESET_MODULE			0x1c
+#define QCA953X_RESET_REG_BOOTSTRAP			0xb0
+#define QCA953X_RESET_REG_PCIE_WMAC_INT_STATUS		0xac
+
+#define QCA955X_RESET_REG_RESET_MODULE			0x1c
+#define QCA955X_RESET_REG_BOOTSTRAP			0xb0
+#define QCA955X_RESET_REG_EXT_INT_STATUS		0xac
+
+#define QCA956X_RESET_REG_RESET_MODULE			0x1c
+#define QCA956X_RESET_REG_BOOTSTRAP			0xb0
+#define QCA956X_RESET_REG_EXT_INT_STATUS		0xac
+
+#define MISC_INT_MIPS_SI_TIMERINT_MASK			BIT(28)
+#define MISC_INT_ETHSW					BIT(12)
+#define MISC_INT_TIMER4					BIT(10)
+#define MISC_INT_TIMER3					BIT(9)
+#define MISC_INT_TIMER2					BIT(8)
+#define MISC_INT_DMA					BIT(7)
+#define MISC_INT_OHCI					BIT(6)
+#define MISC_INT_PERFC					BIT(5)
+#define MISC_INT_WDOG					BIT(4)
+#define MISC_INT_UART					BIT(3)
+#define MISC_INT_GPIO					BIT(2)
+#define MISC_INT_ERROR					BIT(1)
+#define MISC_INT_TIMER					BIT(0)
+
+#define AR71XX_RESET_EXTERNAL				BIT(28)
+#define AR71XX_RESET_FULL_CHIP				BIT(24)
+#define AR71XX_RESET_CPU_NMI				BIT(21)
+#define AR71XX_RESET_CPU_COLD				BIT(20)
+#define AR71XX_RESET_DMA				BIT(19)
+#define AR71XX_RESET_SLIC				BIT(18)
+#define AR71XX_RESET_STEREO				BIT(17)
+#define AR71XX_RESET_DDR				BIT(16)
+#define AR71XX_RESET_GE1_MAC				BIT(13)
+#define AR71XX_RESET_GE1_PHY				BIT(12)
+#define AR71XX_RESET_USBSUS_OVERRIDE			BIT(10)
+#define AR71XX_RESET_GE0_MAC				BIT(9)
+#define AR71XX_RESET_GE0_PHY				BIT(8)
+#define AR71XX_RESET_USB_OHCI_DLL			BIT(6)
+#define AR71XX_RESET_USB_HOST				BIT(5)
+#define AR71XX_RESET_USB_PHY				BIT(4)
+#define AR71XX_RESET_PCI_BUS				BIT(1)
+#define AR71XX_RESET_PCI_CORE				BIT(0)
+
+#define AR7240_RESET_USB_HOST				BIT(5)
+#define AR7240_RESET_OHCI_DLL				BIT(3)
+
+#define AR724X_RESET_GE1_MDIO				BIT(23)
+#define AR724X_RESET_GE0_MDIO				BIT(22)
+#define AR724X_RESET_PCIE_PHY_SERIAL			BIT(10)
+#define AR724X_RESET_PCIE_PHY				BIT(7)
+#define AR724X_RESET_PCIE				BIT(6)
+#define AR724X_RESET_USB_HOST				BIT(5)
+#define AR724X_RESET_USB_PHY				BIT(4)
+#define AR724X_RESET_USBSUS_OVERRIDE			BIT(3)
+
+#define AR913X_RESET_AMBA2WMAC				BIT(22)
+#define AR913X_RESET_USBSUS_OVERRIDE			BIT(10)
+#define AR913X_RESET_USB_HOST				BIT(5)
+#define AR913X_RESET_USB_PHY				BIT(4)
+
+#define AR933X_RESET_GE1_MDIO				BIT(23)
+#define AR933X_RESET_GE0_MDIO				BIT(22)
+#define AR933X_RESET_GE1_MAC				BIT(13)
+#define AR933X_RESET_WMAC				BIT(11)
+#define AR933X_RESET_GE0_MAC				BIT(9)
+#define AR933X_RESET_ETH_SWITCH				BIT(8)
+#define AR933X_RESET_USB_HOST				BIT(5)
+#define AR933X_RESET_USB_PHY				BIT(4)
+#define AR933X_RESET_USBSUS_OVERRIDE			BIT(3)
+
+#define AR934X_RESET_HOST				BIT(31)
+#define AR934X_RESET_SLIC				BIT(30)
+#define AR934X_RESET_HDMA				BIT(29)
+#define AR934X_RESET_EXTERNAL				BIT(28)
+#define AR934X_RESET_RTC				BIT(27)
+#define AR934X_RESET_PCIE_EP_INT			BIT(26)
+#define AR934X_RESET_CHKSUM_ACC				BIT(25)
+#define AR934X_RESET_FULL_CHIP				BIT(24)
+#define AR934X_RESET_GE1_MDIO				BIT(23)
+#define AR934X_RESET_GE0_MDIO				BIT(22)
+#define AR934X_RESET_CPU_NMI				BIT(21)
+#define AR934X_RESET_CPU_COLD				BIT(20)
+#define AR934X_RESET_HOST_RESET_INT			BIT(19)
+#define AR934X_RESET_PCIE_EP				BIT(18)
+#define AR934X_RESET_UART1				BIT(17)
+#define AR934X_RESET_DDR				BIT(16)
+#define AR934X_RESET_USB_PHY_PLL_PWD_EXT		BIT(15)
+#define AR934X_RESET_NANDF				BIT(14)
+#define AR934X_RESET_GE1_MAC				BIT(13)
+#define AR934X_RESET_ETH_SWITCH_ANALOG			BIT(12)
+#define AR934X_RESET_USB_PHY_ANALOG			BIT(11)
+#define AR934X_RESET_HOST_DMA_INT			BIT(10)
+#define AR934X_RESET_GE0_MAC				BIT(9)
+#define AR934X_RESET_ETH_SWITCH				BIT(8)
+#define AR934X_RESET_PCIE_PHY				BIT(7)
+#define AR934X_RESET_PCIE				BIT(6)
+#define AR934X_RESET_USB_HOST				BIT(5)
+#define AR934X_RESET_USB_PHY				BIT(4)
+#define AR934X_RESET_USBSUS_OVERRIDE			BIT(3)
+#define AR934X_RESET_LUT				BIT(2)
+#define AR934X_RESET_MBOX				BIT(1)
+#define AR934X_RESET_I2S				BIT(0)
+
+#define QCA953X_RESET_USB_EXT_PWR			BIT(29)
+#define QCA953X_RESET_EXTERNAL				BIT(28)
+#define QCA953X_RESET_RTC				BIT(27)
+#define QCA953X_RESET_FULL_CHIP				BIT(24)
+#define QCA953X_RESET_GE1_MDIO				BIT(23)
+#define QCA953X_RESET_GE0_MDIO				BIT(22)
+#define QCA953X_RESET_CPU_NMI				BIT(21)
+#define QCA953X_RESET_CPU_COLD				BIT(20)
+#define QCA953X_RESET_DDR				BIT(16)
+#define QCA953X_RESET_USB_PHY_PLL_PWD_EXT		BIT(15)
+#define QCA953X_RESET_GE1_MAC				BIT(13)
+#define QCA953X_RESET_ETH_SWITCH_ANALOG			BIT(12)
+#define QCA953X_RESET_USB_PHY_ANALOG			BIT(11)
+#define QCA953X_RESET_GE0_MAC				BIT(9)
+#define QCA953X_RESET_ETH_SWITCH			BIT(8)
+#define QCA953X_RESET_PCIE_PHY				BIT(7)
+#define QCA953X_RESET_PCIE				BIT(6)
+#define QCA953X_RESET_USB_HOST				BIT(5)
+#define QCA953X_RESET_USB_PHY				BIT(4)
+#define QCA953X_RESET_USBSUS_OVERRIDE			BIT(3)
+
+#define QCA955X_RESET_HOST				BIT(31)
+#define QCA955X_RESET_SLIC				BIT(30)
+#define QCA955X_RESET_HDMA				BIT(29)
+#define QCA955X_RESET_EXTERNAL				BIT(28)
+#define QCA955X_RESET_RTC				BIT(27)
+#define QCA955X_RESET_PCIE_EP_INT			BIT(26)
+#define QCA955X_RESET_CHKSUM_ACC			BIT(25)
+#define QCA955X_RESET_FULL_CHIP				BIT(24)
+#define QCA955X_RESET_GE1_MDIO				BIT(23)
+#define QCA955X_RESET_GE0_MDIO				BIT(22)
+#define QCA955X_RESET_CPU_NMI				BIT(21)
+#define QCA955X_RESET_CPU_COLD				BIT(20)
+#define QCA955X_RESET_HOST_RESET_INT			BIT(19)
+#define QCA955X_RESET_PCIE_EP				BIT(18)
+#define QCA955X_RESET_UART1				BIT(17)
+#define QCA955X_RESET_DDR				BIT(16)
+#define QCA955X_RESET_USB_PHY_PLL_PWD_EXT		BIT(15)
+#define QCA955X_RESET_NANDF				BIT(14)
+#define QCA955X_RESET_GE1_MAC				BIT(13)
+#define QCA955X_RESET_SGMII_ANALOG			BIT(12)
+#define QCA955X_RESET_USB_PHY_ANALOG			BIT(11)
+#define QCA955X_RESET_HOST_DMA_INT			BIT(10)
+#define QCA955X_RESET_GE0_MAC				BIT(9)
+#define QCA955X_RESET_SGMII				BIT(8)
+#define QCA955X_RESET_PCIE_PHY				BIT(7)
+#define QCA955X_RESET_PCIE				BIT(6)
+#define QCA955X_RESET_USB_HOST				BIT(5)
+#define QCA955X_RESET_USB_PHY				BIT(4)
+#define QCA955X_RESET_USBSUS_OVERRIDE			BIT(3)
+#define QCA955X_RESET_LUT				BIT(2)
+#define QCA955X_RESET_MBOX				BIT(1)
+#define QCA955X_RESET_I2S				BIT(0)
+
+#define AR933X_BOOTSTRAP_MDIO_GPIO_EN			BIT(18)
+#define AR933X_BOOTSTRAP_DDR2				BIT(13)
+#define AR933X_BOOTSTRAP_EEPBUSY			BIT(4)
+#define AR933X_BOOTSTRAP_REF_CLK_40			BIT(0)
+
+#define AR934X_BOOTSTRAP_SW_OPTION8			BIT(23)
+#define AR934X_BOOTSTRAP_SW_OPTION7			BIT(22)
+#define AR934X_BOOTSTRAP_SW_OPTION6			BIT(21)
+#define AR934X_BOOTSTRAP_SW_OPTION5			BIT(20)
+#define AR934X_BOOTSTRAP_SW_OPTION4			BIT(19)
+#define AR934X_BOOTSTRAP_SW_OPTION3			BIT(18)
+#define AR934X_BOOTSTRAP_SW_OPTION2			BIT(17)
+#define AR934X_BOOTSTRAP_SW_OPTION1			BIT(16)
+#define AR934X_BOOTSTRAP_USB_MODE_DEVICE		BIT(7)
+#define AR934X_BOOTSTRAP_PCIE_RC			BIT(6)
+#define AR934X_BOOTSTRAP_EJTAG_MODE			BIT(5)
+#define AR934X_BOOTSTRAP_REF_CLK_40			BIT(4)
+#define AR934X_BOOTSTRAP_BOOT_FROM_SPI			BIT(2)
+#define AR934X_BOOTSTRAP_SDRAM_DISABLED			BIT(1)
+#define AR934X_BOOTSTRAP_DDR1				BIT(0)
+
+#define QCA953X_BOOTSTRAP_SW_OPTION2			BIT(12)
+#define QCA953X_BOOTSTRAP_SW_OPTION1			BIT(11)
+#define QCA953X_BOOTSTRAP_EJTAG_MODE			BIT(5)
+#define QCA953X_BOOTSTRAP_REF_CLK_40			BIT(4)
+#define QCA953X_BOOTSTRAP_SDRAM_DISABLED		BIT(1)
+#define QCA953X_BOOTSTRAP_DDR1				BIT(0)
+
+#define QCA955X_BOOTSTRAP_REF_CLK_40			BIT(4)
+
+#define QCA956X_BOOTSTRAP_REF_CLK_40			BIT(2)
+
+#define AR934X_PCIE_WMAC_INT_WMAC_MISC			BIT(0)
+#define AR934X_PCIE_WMAC_INT_WMAC_TX			BIT(1)
+#define AR934X_PCIE_WMAC_INT_WMAC_RXLP			BIT(2)
+#define AR934X_PCIE_WMAC_INT_WMAC_RXHP			BIT(3)
+#define AR934X_PCIE_WMAC_INT_PCIE_RC			BIT(4)
+#define AR934X_PCIE_WMAC_INT_PCIE_RC0			BIT(5)
+#define AR934X_PCIE_WMAC_INT_PCIE_RC1			BIT(6)
+#define AR934X_PCIE_WMAC_INT_PCIE_RC2			BIT(7)
+#define AR934X_PCIE_WMAC_INT_PCIE_RC3			BIT(8)
+#define AR934X_PCIE_WMAC_INT_WMAC_ALL \
+	(AR934X_PCIE_WMAC_INT_WMAC_MISC | AR934X_PCIE_WMAC_INT_WMAC_TX | \
+	 AR934X_PCIE_WMAC_INT_WMAC_RXLP | AR934X_PCIE_WMAC_INT_WMAC_RXHP)
+
+#define AR934X_PCIE_WMAC_INT_PCIE_ALL \
+	(AR934X_PCIE_WMAC_INT_PCIE_RC | AR934X_PCIE_WMAC_INT_PCIE_RC0 | \
+	 AR934X_PCIE_WMAC_INT_PCIE_RC1 | AR934X_PCIE_WMAC_INT_PCIE_RC2 | \
+	 AR934X_PCIE_WMAC_INT_PCIE_RC3)
+
+#define QCA953X_PCIE_WMAC_INT_WMAC_MISC			BIT(0)
+#define QCA953X_PCIE_WMAC_INT_WMAC_TX			BIT(1)
+#define QCA953X_PCIE_WMAC_INT_WMAC_RXLP			BIT(2)
+#define QCA953X_PCIE_WMAC_INT_WMAC_RXHP			BIT(3)
+#define QCA953X_PCIE_WMAC_INT_PCIE_RC			BIT(4)
+#define QCA953X_PCIE_WMAC_INT_PCIE_RC0			BIT(5)
+#define QCA953X_PCIE_WMAC_INT_PCIE_RC1			BIT(6)
+#define QCA953X_PCIE_WMAC_INT_PCIE_RC2			BIT(7)
+#define QCA953X_PCIE_WMAC_INT_PCIE_RC3			BIT(8)
+#define QCA953X_PCIE_WMAC_INT_WMAC_ALL \
+	(QCA953X_PCIE_WMAC_INT_WMAC_MISC | QCA953X_PCIE_WMAC_INT_WMAC_TX | \
+	 QCA953X_PCIE_WMAC_INT_WMAC_RXLP | QCA953X_PCIE_WMAC_INT_WMAC_RXHP)
+
+#define QCA953X_PCIE_WMAC_INT_PCIE_ALL \
+	(QCA953X_PCIE_WMAC_INT_PCIE_RC | QCA953X_PCIE_WMAC_INT_PCIE_RC0 | \
+	 QCA953X_PCIE_WMAC_INT_PCIE_RC1 | QCA953X_PCIE_WMAC_INT_PCIE_RC2 | \
+	 QCA953X_PCIE_WMAC_INT_PCIE_RC3)
+
+#define QCA955X_EXT_INT_WMAC_MISC			BIT(0)
+#define QCA955X_EXT_INT_WMAC_TX				BIT(1)
+#define QCA955X_EXT_INT_WMAC_RXLP			BIT(2)
+#define QCA955X_EXT_INT_WMAC_RXHP			BIT(3)
+#define QCA955X_EXT_INT_PCIE_RC1			BIT(4)
+#define QCA955X_EXT_INT_PCIE_RC1_INT0			BIT(5)
+#define QCA955X_EXT_INT_PCIE_RC1_INT1			BIT(6)
+#define QCA955X_EXT_INT_PCIE_RC1_INT2			BIT(7)
+#define QCA955X_EXT_INT_PCIE_RC1_INT3			BIT(8)
+#define QCA955X_EXT_INT_PCIE_RC2			BIT(12)
+#define QCA955X_EXT_INT_PCIE_RC2_INT0			BIT(13)
+#define QCA955X_EXT_INT_PCIE_RC2_INT1			BIT(14)
+#define QCA955X_EXT_INT_PCIE_RC2_INT2			BIT(15)
+#define QCA955X_EXT_INT_PCIE_RC2_INT3			BIT(16)
+#define QCA955X_EXT_INT_USB1				BIT(24)
+#define QCA955X_EXT_INT_USB2				BIT(28)
+
+#define QCA955X_EXT_INT_WMAC_ALL \
+	(QCA955X_EXT_INT_WMAC_MISC | QCA955X_EXT_INT_WMAC_TX | \
+	 QCA955X_EXT_INT_WMAC_RXLP | QCA955X_EXT_INT_WMAC_RXHP)
+
+#define QCA955X_EXT_INT_PCIE_RC1_ALL \
+	(QCA955X_EXT_INT_PCIE_RC1 | QCA955X_EXT_INT_PCIE_RC1_INT0 | \
+	 QCA955X_EXT_INT_PCIE_RC1_INT1 | QCA955X_EXT_INT_PCIE_RC1_INT2 | \
+	 QCA955X_EXT_INT_PCIE_RC1_INT3)
+
+#define QCA955X_EXT_INT_PCIE_RC2_ALL \
+	(QCA955X_EXT_INT_PCIE_RC2 | QCA955X_EXT_INT_PCIE_RC2_INT0 | \
+	 QCA955X_EXT_INT_PCIE_RC2_INT1 | QCA955X_EXT_INT_PCIE_RC2_INT2 | \
+	 QCA955X_EXT_INT_PCIE_RC2_INT3)
+
+#define QCA956X_EXT_INT_WMAC_MISC			BIT(0)
+#define QCA956X_EXT_INT_WMAC_TX				BIT(1)
+#define QCA956X_EXT_INT_WMAC_RXLP			BIT(2)
+#define QCA956X_EXT_INT_WMAC_RXHP			BIT(3)
+#define QCA956X_EXT_INT_PCIE_RC1			BIT(4)
+#define QCA956X_EXT_INT_PCIE_RC1_INT0			BIT(5)
+#define QCA956X_EXT_INT_PCIE_RC1_INT1			BIT(6)
+#define QCA956X_EXT_INT_PCIE_RC1_INT2			BIT(7)
+#define QCA956X_EXT_INT_PCIE_RC1_INT3			BIT(8)
+#define QCA956X_EXT_INT_PCIE_RC2			BIT(12)
+#define QCA956X_EXT_INT_PCIE_RC2_INT0			BIT(13)
+#define QCA956X_EXT_INT_PCIE_RC2_INT1			BIT(14)
+#define QCA956X_EXT_INT_PCIE_RC2_INT2			BIT(15)
+#define QCA956X_EXT_INT_PCIE_RC2_INT3			BIT(16)
+#define QCA956X_EXT_INT_USB1				BIT(24)
+#define QCA956X_EXT_INT_USB2				BIT(28)
+
+#define QCA956X_EXT_INT_WMAC_ALL \
+	(QCA956X_EXT_INT_WMAC_MISC | QCA956X_EXT_INT_WMAC_TX | \
+	 QCA956X_EXT_INT_WMAC_RXLP | QCA956X_EXT_INT_WMAC_RXHP)
+
+#define QCA956X_EXT_INT_PCIE_RC1_ALL \
+	(QCA956X_EXT_INT_PCIE_RC1 | QCA956X_EXT_INT_PCIE_RC1_INT0 | \
+	 QCA956X_EXT_INT_PCIE_RC1_INT1 | QCA956X_EXT_INT_PCIE_RC1_INT2 | \
+	 QCA956X_EXT_INT_PCIE_RC1_INT3)
+
+#define QCA956X_EXT_INT_PCIE_RC2_ALL \
+	(QCA956X_EXT_INT_PCIE_RC2 | QCA956X_EXT_INT_PCIE_RC2_INT0 | \
+	 QCA956X_EXT_INT_PCIE_RC2_INT1 | QCA956X_EXT_INT_PCIE_RC2_INT2 | \
+	 QCA956X_EXT_INT_PCIE_RC2_INT3)
+
+#define REV_ID_MAJOR_MASK				0xfff0
+#define REV_ID_MAJOR_AR71XX				0x00a0
+#define REV_ID_MAJOR_AR913X				0x00b0
+#define REV_ID_MAJOR_AR7240				0x00c0
+#define REV_ID_MAJOR_AR7241				0x0100
+#define REV_ID_MAJOR_AR7242				0x1100
+#define REV_ID_MAJOR_AR9330				0x0110
+#define REV_ID_MAJOR_AR9331				0x1110
+#define REV_ID_MAJOR_AR9341				0x0120
+#define REV_ID_MAJOR_AR9342				0x1120
+#define REV_ID_MAJOR_AR9344				0x2120
+#define REV_ID_MAJOR_QCA9533				0x0140
+#define REV_ID_MAJOR_QCA9533_V2				0x0160
+#define REV_ID_MAJOR_QCA9556				0x0130
+#define REV_ID_MAJOR_QCA9558				0x1130
+#define REV_ID_MAJOR_TP9343				0x0150
+#define REV_ID_MAJOR_QCA9561				0x1150
+
+#define AR71XX_REV_ID_MINOR_MASK			0x3
+#define AR71XX_REV_ID_MINOR_AR7130			0x0
+#define AR71XX_REV_ID_MINOR_AR7141			0x1
+#define AR71XX_REV_ID_MINOR_AR7161			0x2
+#define AR913X_REV_ID_MINOR_AR9130			0x0
+#define AR913X_REV_ID_MINOR_AR9132			0x1
+
+#define AR71XX_REV_ID_REVISION_MASK			0x3
+#define AR71XX_REV_ID_REVISION_SHIFT			2
+#define AR71XX_REV_ID_REVISION2_MASK			0xf
+
+/*
+ * RTC block
+ */
+#define AR933X_RTC_REG_RESET				0x40
+#define AR933X_RTC_REG_STATUS				0x44
+#define AR933X_RTC_REG_DERIVED				0x48
+#define AR933X_RTC_REG_FORCE_WAKE			0x4c
+#define AR933X_RTC_REG_INT_CAUSE			0x50
+#define AR933X_RTC_REG_CAUSE_CLR			0x50
+#define AR933X_RTC_REG_INT_ENABLE			0x54
+#define AR933X_RTC_REG_INT_MASKE			0x58
+
+#define QCA953X_RTC_REG_SYNC_RESET			0x40
+#define QCA953X_RTC_REG_SYNC_STATUS			0x44
+
+/*
+ * SPI block
+ */
+#define AR71XX_SPI_REG_FS				0x00
+#define AR71XX_SPI_REG_CTRL				0x04
+#define AR71XX_SPI_REG_IOC				0x08
+#define AR71XX_SPI_REG_RDS				0x0c
+
+#define AR71XX_SPI_FS_GPIO				BIT(0)
+
+#define AR71XX_SPI_CTRL_RD				BIT(6)
+#define AR71XX_SPI_CTRL_DIV_MASK			0x3f
+
+#define AR71XX_SPI_IOC_DO				BIT(0)
+#define AR71XX_SPI_IOC_CLK				BIT(8)
+#define AR71XX_SPI_IOC_CS(n)				BIT(16 + (n))
+#define AR71XX_SPI_IOC_CS0				AR71XX_SPI_IOC_CS(0)
+#define AR71XX_SPI_IOC_CS1				AR71XX_SPI_IOC_CS(1)
+#define AR71XX_SPI_IOC_CS2				AR71XX_SPI_IOC_CS(2)
+#define AR71XX_SPI_IOC_CS_ALL \
+	(AR71XX_SPI_IOC_CS0 | AR71XX_SPI_IOC_CS1 | AR71XX_SPI_IOC_CS2)
+
+/*
+ * GPIO block
+ */
+#define AR71XX_GPIO_REG_OE				0x00
+#define AR71XX_GPIO_REG_IN				0x04
+#define AR71XX_GPIO_REG_OUT				0x08
+#define AR71XX_GPIO_REG_SET				0x0c
+#define AR71XX_GPIO_REG_CLEAR				0x10
+#define AR71XX_GPIO_REG_INT_MODE			0x14
+#define AR71XX_GPIO_REG_INT_TYPE			0x18
+#define AR71XX_GPIO_REG_INT_POLARITY			0x1c
+#define AR71XX_GPIO_REG_INT_PENDING			0x20
+#define AR71XX_GPIO_REG_INT_ENABLE			0x24
+#define AR71XX_GPIO_REG_FUNC				0x28
+#define AR933X_GPIO_REG_FUNC				0x30
+
+#define AR934X_GPIO_REG_OUT_FUNC0			0x2c
+#define AR934X_GPIO_REG_OUT_FUNC1			0x30
+#define AR934X_GPIO_REG_OUT_FUNC2			0x34
+#define AR934X_GPIO_REG_OUT_FUNC3			0x38
+#define AR934X_GPIO_REG_OUT_FUNC4			0x3c
+#define AR934X_GPIO_REG_OUT_FUNC5			0x40
+#define AR934X_GPIO_REG_FUNC				0x6c
+
+#define QCA953X_GPIO_REG_OUT_FUNC0			0x2c
+#define QCA953X_GPIO_REG_OUT_FUNC1			0x30
+#define QCA953X_GPIO_REG_OUT_FUNC2			0x34
+#define QCA953X_GPIO_REG_OUT_FUNC3			0x38
+#define QCA953X_GPIO_REG_OUT_FUNC4			0x3c
+#define QCA953X_GPIO_REG_IN_ENABLE0			0x44
+#define QCA953X_GPIO_REG_FUNC				0x6c
+
+#define QCA955X_GPIO_REG_OUT_FUNC0			0x2c
+#define QCA955X_GPIO_REG_OUT_FUNC1			0x30
+#define QCA955X_GPIO_REG_OUT_FUNC2			0x34
+#define QCA955X_GPIO_REG_OUT_FUNC3			0x38
+#define QCA955X_GPIO_REG_OUT_FUNC4			0x3c
+#define QCA955X_GPIO_REG_OUT_FUNC5			0x40
+#define QCA955X_GPIO_REG_FUNC				0x6c
+
+#define QCA956X_GPIO_REG_OUT_FUNC0			0x2c
+#define QCA956X_GPIO_REG_OUT_FUNC1			0x30
+#define QCA956X_GPIO_REG_OUT_FUNC2			0x34
+#define QCA956X_GPIO_REG_OUT_FUNC3			0x38
+#define QCA956X_GPIO_REG_OUT_FUNC4			0x3c
+#define QCA956X_GPIO_REG_OUT_FUNC5			0x40
+#define QCA956X_GPIO_REG_IN_ENABLE0			0x44
+#define QCA956X_GPIO_REG_IN_ENABLE3			0x50
+#define QCA956X_GPIO_REG_FUNC				0x6c
+
+#define AR71XX_GPIO_FUNC_STEREO_EN			BIT(17)
+#define AR71XX_GPIO_FUNC_SLIC_EN			BIT(16)
+#define AR71XX_GPIO_FUNC_SPI_CS2_EN			BIT(13)
+#define AR71XX_GPIO_FUNC_SPI_CS1_EN			BIT(12)
+#define AR71XX_GPIO_FUNC_UART_EN			BIT(8)
+#define AR71XX_GPIO_FUNC_USB_OC_EN			BIT(4)
+#define AR71XX_GPIO_FUNC_USB_CLK_EN			BIT(0)
+
+#define AR724X_GPIO_FUNC_GE0_MII_CLK_EN			BIT(19)
+#define AR724X_GPIO_FUNC_SPI_EN				BIT(18)
+#define AR724X_GPIO_FUNC_SPI_CS_EN2			BIT(14)
+#define AR724X_GPIO_FUNC_SPI_CS_EN1			BIT(13)
+#define AR724X_GPIO_FUNC_CLK_OBS5_EN			BIT(12)
+#define AR724X_GPIO_FUNC_CLK_OBS4_EN			BIT(11)
+#define AR724X_GPIO_FUNC_CLK_OBS3_EN			BIT(10)
+#define AR724X_GPIO_FUNC_CLK_OBS2_EN			BIT(9)
+#define AR724X_GPIO_FUNC_CLK_OBS1_EN			BIT(8)
+#define AR724X_GPIO_FUNC_ETH_SWITCH_LED4_EN		BIT(7)
+#define AR724X_GPIO_FUNC_ETH_SWITCH_LED3_EN		BIT(6)
+#define AR724X_GPIO_FUNC_ETH_SWITCH_LED2_EN		BIT(5)
+#define AR724X_GPIO_FUNC_ETH_SWITCH_LED1_EN		BIT(4)
+#define AR724X_GPIO_FUNC_ETH_SWITCH_LED0_EN		BIT(3)
+#define AR724X_GPIO_FUNC_UART_RTS_CTS_EN		BIT(2)
+#define AR724X_GPIO_FUNC_UART_EN			BIT(1)
+#define AR724X_GPIO_FUNC_JTAG_DISABLE			BIT(0)
+
+#define AR913X_GPIO_FUNC_WMAC_LED_EN			BIT(22)
+#define AR913X_GPIO_FUNC_EXP_PORT_CS_EN			BIT(21)
+#define AR913X_GPIO_FUNC_I2S_REFCLKEN			BIT(20)
+#define AR913X_GPIO_FUNC_I2S_MCKEN			BIT(19)
+#define AR913X_GPIO_FUNC_I2S1_EN			BIT(18)
+#define AR913X_GPIO_FUNC_I2S0_EN			BIT(17)
+#define AR913X_GPIO_FUNC_SLIC_EN			BIT(16)
+#define AR913X_GPIO_FUNC_UART_RTSCTS_EN			BIT(9)
+#define AR913X_GPIO_FUNC_UART_EN			BIT(8)
+#define AR913X_GPIO_FUNC_USB_CLK_EN			BIT(4)
+
+#define AR933X_GPIO(x)					BIT(x)
+#define AR933X_GPIO_FUNC_SPDIF2TCK			BIT(31)
+#define AR933X_GPIO_FUNC_SPDIF_EN			BIT(30)
+#define AR933X_GPIO_FUNC_I2SO_22_18_EN			BIT(29)
+#define AR933X_GPIO_FUNC_I2S_MCK_EN			BIT(27)
+#define AR933X_GPIO_FUNC_I2SO_EN			BIT(26)
+#define AR933X_GPIO_FUNC_ETH_SWITCH_LED_DUPL		BIT(25)
+#define AR933X_GPIO_FUNC_ETH_SWITCH_LED_COLL		BIT(24)
+#define AR933X_GPIO_FUNC_ETH_SWITCH_LED_ACT		BIT(23)
+#define AR933X_GPIO_FUNC_SPI_EN				BIT(18)
+#define AR933X_GPIO_FUNC_RES_TRUE			BIT(15)
+#define AR933X_GPIO_FUNC_SPI_CS_EN2			BIT(14)
+#define AR933X_GPIO_FUNC_SPI_CS_EN1			BIT(13)
+#define AR933X_GPIO_FUNC_XLNA_EN			BIT(12)
+#define AR933X_GPIO_FUNC_ETH_SWITCH_LED4_EN		BIT(7)
+#define AR933X_GPIO_FUNC_ETH_SWITCH_LED3_EN		BIT(6)
+#define AR933X_GPIO_FUNC_ETH_SWITCH_LED2_EN		BIT(5)
+#define AR933X_GPIO_FUNC_ETH_SWITCH_LED1_EN		BIT(4)
+#define AR933X_GPIO_FUNC_ETH_SWITCH_LED0_EN		BIT(3)
+#define AR933X_GPIO_FUNC_UART_RTS_CTS_EN		BIT(2)
+#define AR933X_GPIO_FUNC_UART_EN			BIT(1)
+#define AR933X_GPIO_FUNC_JTAG_DISABLE			BIT(0)
+
+#define AR934X_GPIO_FUNC_CLK_OBS7_EN			BIT(9)
+#define AR934X_GPIO_FUNC_CLK_OBS6_EN			BIT(8)
+#define AR934X_GPIO_FUNC_CLK_OBS5_EN			BIT(7)
+#define AR934X_GPIO_FUNC_CLK_OBS4_EN			BIT(6)
+#define AR934X_GPIO_FUNC_CLK_OBS3_EN			BIT(5)
+#define AR934X_GPIO_FUNC_CLK_OBS2_EN			BIT(4)
+#define AR934X_GPIO_FUNC_CLK_OBS1_EN			BIT(3)
+#define AR934X_GPIO_FUNC_CLK_OBS0_EN			BIT(2)
+#define AR934X_GPIO_FUNC_JTAG_DISABLE			BIT(1)
+
+#define AR934X_GPIO_OUT_GPIO				0
+#define AR934X_GPIO_OUT_SPI_CS1				7
+#define AR934X_GPIO_OUT_LED_LINK0			41
+#define AR934X_GPIO_OUT_LED_LINK1			42
+#define AR934X_GPIO_OUT_LED_LINK2			43
+#define AR934X_GPIO_OUT_LED_LINK3			44
+#define AR934X_GPIO_OUT_LED_LINK4			45
+#define AR934X_GPIO_OUT_EXT_LNA0			46
+#define AR934X_GPIO_OUT_EXT_LNA1			47
+
+#define QCA953X_GPIO(x)					BIT(x)
+#define QCA953X_GPIO_MUX_MASK(x)			(0xff << (x))
+#define QCA953X_GPIO_OUT_MUX_SPI_CS1			10
+#define QCA953X_GPIO_OUT_MUX_SPI_CS2			11
+#define QCA953X_GPIO_OUT_MUX_SPI_CS0			9
+#define QCA953X_GPIO_OUT_MUX_SPI_CLK			8
+#define QCA953X_GPIO_OUT_MUX_SPI_MOSI			12
+#define QCA953X_GPIO_OUT_MUX_UART0_SOUT			22
+#define QCA953X_GPIO_OUT_MUX_LED_LINK1			41
+#define QCA953X_GPIO_OUT_MUX_LED_LINK2			42
+#define QCA953X_GPIO_OUT_MUX_LED_LINK3			43
+#define QCA953X_GPIO_OUT_MUX_LED_LINK4			44
+#define QCA953X_GPIO_OUT_MUX_LED_LINK5			45
+
+#define QCA953X_GPIO_IN_MUX_UART0_SIN			9
+#define QCA953X_GPIO_IN_MUX_SPI_DATA_IN			8
+
+#define QCA956X_GPIO_OUT_MUX_GE0_MDO			32
+#define QCA956X_GPIO_OUT_MUX_GE0_MDC			33
+
+#define AR71XX_GPIO_COUNT				16
+#define AR7240_GPIO_COUNT				18
+#define AR7241_GPIO_COUNT				20
+#define AR913X_GPIO_COUNT				22
+#define AR933X_GPIO_COUNT				30
+#define AR934X_GPIO_COUNT				23
+#define QCA953X_GPIO_COUNT				18
+#define QCA955X_GPIO_COUNT				24
+#define QCA956X_GPIO_COUNT				23
+
+/*
+ * SRIF block
+ */
+#define AR933X_SRIF_DDR_DPLL1_REG			0x240
+#define AR933X_SRIF_DDR_DPLL2_REG			0x244
+#define AR933X_SRIF_DDR_DPLL3_REG			0x248
+#define AR933X_SRIF_DDR_DPLL4_REG			0x24c
+
+#define AR934X_SRIF_CPU_DPLL1_REG			0x1c0
+#define AR934X_SRIF_CPU_DPLL2_REG			0x1c4
+#define AR934X_SRIF_CPU_DPLL3_REG			0x1c8
+#define AR934X_SRIF_CPU_DPLL4_REG			0x1cc
+
+#define AR934X_SRIF_DDR_DPLL1_REG			0x240
+#define AR934X_SRIF_DDR_DPLL2_REG			0x244
+#define AR934X_SRIF_DDR_DPLL3_REG			0x248
+#define AR934X_SRIF_DDR_DPLL4_REG			0x24c
+
+#define AR934X_SRIF_DPLL1_REFDIV_SHIFT			27
+#define AR934X_SRIF_DPLL1_REFDIV_MASK			0x1f
+#define AR934X_SRIF_DPLL1_NINT_SHIFT			18
+#define AR934X_SRIF_DPLL1_NINT_MASK			0x1ff
+#define AR934X_SRIF_DPLL1_NFRAC_MASK			0x0003ffff
+
+#define AR934X_SRIF_DPLL2_LOCAL_PLL			BIT(30)
+#define AR934X_SRIF_DPLL2_OUTDIV_SHIFT			13
+#define AR934X_SRIF_DPLL2_OUTDIV_MASK			0x7
+
+#define QCA953X_SRIF_BB_DPLL1_REG			0x180
+#define QCA953X_SRIF_BB_DPLL2_REG			0x184
+#define QCA953X_SRIF_BB_DPLL3_REG			0x188
+
+#define QCA953X_SRIF_CPU_DPLL1_REG			0x1c0
+#define QCA953X_SRIF_CPU_DPLL2_REG			0x1c4
+#define QCA953X_SRIF_CPU_DPLL3_REG			0x1c8
+
+#define QCA953X_SRIF_DDR_DPLL1_REG			0x240
+#define QCA953X_SRIF_DDR_DPLL2_REG			0x244
+#define QCA953X_SRIF_DDR_DPLL3_REG			0x248
+
+#define QCA953X_SRIF_PCIE_DPLL1_REG			0xc00
+#define QCA953X_SRIF_PCIE_DPLL2_REG			0xc04
+#define QCA953X_SRIF_PCIE_DPLL3_REG			0xc08
+
+#define QCA953X_SRIF_PMU1_REG				0xc40
+#define QCA953X_SRIF_PMU2_REG				0xc44
+
+#define QCA953X_SRIF_DPLL1_REFDIV_SHIFT			27
+#define QCA953X_SRIF_DPLL1_REFDIV_MASK			0x1f
+
+#define QCA953X_SRIF_DPLL1_NINT_SHIFT			18
+#define QCA953X_SRIF_DPLL1_NINT_MASK			0x1ff
+#define QCA953X_SRIF_DPLL1_NFRAC_MASK			0x0003ffff
+
+#define QCA953X_SRIF_DPLL2_LOCAL_PLL			BIT(30)
+
+#define QCA953X_SRIF_DPLL2_KI_SHIFT			29
+#define QCA953X_SRIF_DPLL2_KI_MASK			0x3
+
+#define QCA953X_SRIF_DPLL2_KD_SHIFT			25
+#define QCA953X_SRIF_DPLL2_KD_MASK			0xf
+
+#define QCA953X_SRIF_DPLL2_PWD				BIT(22)
+
+#define QCA953X_SRIF_DPLL2_OUTDIV_SHIFT			13
+#define QCA953X_SRIF_DPLL2_OUTDIV_MASK			0x7
+
+/*
+ * MII_CTRL block
+ */
+#define AR71XX_MII_REG_MII0_CTRL			0x00
+#define AR71XX_MII_REG_MII1_CTRL			0x04
+
+#define AR71XX_MII_CTRL_IF_MASK				3
+#define AR71XX_MII_CTRL_SPEED_SHIFT			4
+#define AR71XX_MII_CTRL_SPEED_MASK			3
+#define AR71XX_MII_CTRL_SPEED_10			0
+#define AR71XX_MII_CTRL_SPEED_100			1
+#define AR71XX_MII_CTRL_SPEED_1000			2
+
+#define AR71XX_MII0_CTRL_IF_GMII			0
+#define AR71XX_MII0_CTRL_IF_MII				1
+#define AR71XX_MII0_CTRL_IF_RGMII			2
+#define AR71XX_MII0_CTRL_IF_RMII			3
+
+#define AR71XX_MII1_CTRL_IF_RGMII			0
+#define AR71XX_MII1_CTRL_IF_RMII			1
+
+/*
+ * AR933X GMAC interface
+ */
+#define AR933X_GMAC_REG_ETH_CFG				0x00
+
+#define AR933X_ETH_CFG_RGMII_GE0			BIT(0)
+#define AR933X_ETH_CFG_MII_GE0				BIT(1)
+#define AR933X_ETH_CFG_GMII_GE0				BIT(2)
+#define AR933X_ETH_CFG_MII_GE0_MASTER			BIT(3)
+#define AR933X_ETH_CFG_MII_GE0_SLAVE			BIT(4)
+#define AR933X_ETH_CFG_MII_GE0_ERR_EN			BIT(5)
+#define AR933X_ETH_CFG_SW_PHY_SWAP			BIT(7)
+#define AR933X_ETH_CFG_SW_PHY_ADDR_SWAP			BIT(8)
+#define AR933X_ETH_CFG_RMII_GE0				BIT(9)
+#define AR933X_ETH_CFG_RMII_GE0_SPD_10			0
+#define AR933X_ETH_CFG_RMII_GE0_SPD_100			BIT(10)
+
+/*
+ * AR934X GMAC Interface
+ */
+#define AR934X_GMAC_REG_ETH_CFG				0x00
+
+#define AR934X_ETH_CFG_RGMII_GMAC0			BIT(0)
+#define AR934X_ETH_CFG_MII_GMAC0			BIT(1)
+#define AR934X_ETH_CFG_GMII_GMAC0			BIT(2)
+#define AR934X_ETH_CFG_MII_GMAC0_MASTER			BIT(3)
+#define AR934X_ETH_CFG_MII_GMAC0_SLAVE			BIT(4)
+#define AR934X_ETH_CFG_MII_GMAC0_ERR_EN			BIT(5)
+#define AR934X_ETH_CFG_SW_ONLY_MODE			BIT(6)
+#define AR934X_ETH_CFG_SW_PHY_SWAP			BIT(7)
+#define AR934X_ETH_CFG_SW_APB_ACCESS			BIT(9)
+#define AR934X_ETH_CFG_RMII_GMAC0			BIT(10)
+#define AR933X_ETH_CFG_MII_CNTL_SPEED			BIT(11)
+#define AR934X_ETH_CFG_RMII_GMAC0_MASTER			BIT(12)
+#define AR933X_ETH_CFG_SW_ACC_MSB_FIRST			BIT(13)
+#define AR934X_ETH_CFG_RXD_DELAY			BIT(14)
+#define AR934X_ETH_CFG_RXD_DELAY_MASK			0x3
+#define AR934X_ETH_CFG_RXD_DELAY_SHIFT			14
+#define AR934X_ETH_CFG_RDV_DELAY			BIT(16)
+#define AR934X_ETH_CFG_RDV_DELAY_MASK			0x3
+#define AR934X_ETH_CFG_RDV_DELAY_SHIFT			16
+
+/*
+ * QCA953X GMAC Interface
+ */
+#define QCA953X_GMAC_REG_ETH_CFG			0x00
+
+#define QCA953X_ETH_CFG_SW_ONLY_MODE			BIT(6)
+#define QCA953X_ETH_CFG_SW_PHY_SWAP			BIT(7)
+#define QCA953X_ETH_CFG_SW_APB_ACCESS			BIT(9)
+#define QCA953X_ETH_CFG_SW_ACC_MSB_FIRST		BIT(13)
+
+/*
+ * QCA955X GMAC Interface
+ */
+
+#define QCA955X_GMAC_REG_ETH_CFG			0x00
+
+#define QCA955X_ETH_CFG_RGMII_EN			BIT(0)
+#define QCA955X_ETH_CFG_GE0_SGMII			BIT(6)
+
+#endif /* __ASM_AR71XX_H */
diff --git a/arch/mips/mach-ath79/include/mach/ath79.h b/arch/mips/mach-ath79/include/mach/ath79.h
new file mode 100644
index 0000000000000000000000000000000000000000..17af08223f740621417c9c8f411c8e88af293435
--- /dev/null
+++ b/arch/mips/mach-ath79/include/mach/ath79.h
@@ -0,0 +1,149 @@
+/*
+ * Atheros AR71XX/AR724X/AR913X common definitions
+ *
+ * Copyright (C) 2015-2016 Wills Wang <wills.wang@live.com>
+ * Copyright (C) 2008-2011 Gabor Juhos <juhosg@openwrt.org>
+ * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#ifndef __ASM_MACH_ATH79_H
+#define __ASM_MACH_ATH79_H
+
+#include <linux/types.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+enum ath79_soc_type {
+	ATH79_SOC_UNKNOWN,
+	ATH79_SOC_AR7130,
+	ATH79_SOC_AR7141,
+	ATH79_SOC_AR7161,
+	ATH79_SOC_AR7240,
+	ATH79_SOC_AR7241,
+	ATH79_SOC_AR7242,
+	ATH79_SOC_AR9130,
+	ATH79_SOC_AR9132,
+	ATH79_SOC_AR9330,
+	ATH79_SOC_AR9331,
+	ATH79_SOC_AR9341,
+	ATH79_SOC_AR9342,
+	ATH79_SOC_AR9344,
+	ATH79_SOC_QCA9533,
+	ATH79_SOC_QCA9556,
+	ATH79_SOC_QCA9558,
+	ATH79_SOC_TP9343,
+	ATH79_SOC_QCA9561,
+};
+
+static inline int soc_is_ar71xx(void)
+{
+	return gd->arch.soc == ATH79_SOC_AR7130 ||
+		gd->arch.soc == ATH79_SOC_AR7141 ||
+		gd->arch.soc == ATH79_SOC_AR7161;
+}
+
+static inline int soc_is_ar724x(void)
+{
+	return gd->arch.soc == ATH79_SOC_AR7240 ||
+		gd->arch.soc == ATH79_SOC_AR7241 ||
+		gd->arch.soc == ATH79_SOC_AR7242;
+}
+
+static inline int soc_is_ar7240(void)
+{
+	return gd->arch.soc == ATH79_SOC_AR7240;
+}
+
+static inline int soc_is_ar7241(void)
+{
+	return gd->arch.soc == ATH79_SOC_AR7241;
+}
+
+static inline int soc_is_ar7242(void)
+{
+	return gd->arch.soc == ATH79_SOC_AR7242;
+}
+
+static inline int soc_is_ar913x(void)
+{
+	return gd->arch.soc == ATH79_SOC_AR9130 ||
+		gd->arch.soc == ATH79_SOC_AR9132;
+}
+
+static inline int soc_is_ar933x(void)
+{
+	return gd->arch.soc == ATH79_SOC_AR9330 ||
+		gd->arch.soc == ATH79_SOC_AR9331;
+}
+
+static inline int soc_is_ar9341(void)
+{
+	return gd->arch.soc == ATH79_SOC_AR9341;
+}
+
+static inline int soc_is_ar9342(void)
+{
+	return gd->arch.soc == ATH79_SOC_AR9342;
+}
+
+static inline int soc_is_ar9344(void)
+{
+	return gd->arch.soc == ATH79_SOC_AR9344;
+}
+
+static inline int soc_is_ar934x(void)
+{
+	return soc_is_ar9341() ||
+		soc_is_ar9342() ||
+		soc_is_ar9344();
+}
+
+static inline int soc_is_qca9533(void)
+{
+	return gd->arch.soc == ATH79_SOC_QCA9533;
+}
+
+static inline int soc_is_qca953x(void)
+{
+	return soc_is_qca9533();
+}
+
+static inline int soc_is_qca9556(void)
+{
+	return gd->arch.soc == ATH79_SOC_QCA9556;
+}
+
+static inline int soc_is_qca9558(void)
+{
+	return gd->arch.soc == ATH79_SOC_QCA9558;
+}
+
+static inline int soc_is_qca955x(void)
+{
+	return soc_is_qca9556() || soc_is_qca9558();
+}
+
+static inline int soc_is_tp9343(void)
+{
+	return gd->arch.soc == ATH79_SOC_TP9343;
+}
+
+static inline int soc_is_qca9561(void)
+{
+	return gd->arch.soc == ATH79_SOC_QCA9561;
+}
+
+static inline int soc_is_qca956x(void)
+{
+	return soc_is_tp9343() || soc_is_qca9561();
+}
+
+int ath79_eth_reset(void);
+int ath79_usb_reset(void);
+
+void ar934x_pll_init(const u16 cpu_mhz, const u16 ddr_mhz, const u16 ahb_mhz);
+void ar934x_ddr_init(const u16 cpu_mhz, const u16 ddr_mhz, const u16 ahb_mhz);
+
+#endif /* __ASM_MACH_ATH79_H */
diff --git a/arch/mips/mach-ath79/include/mach/ddr.h b/arch/mips/mach-ath79/include/mach/ddr.h
new file mode 100644
index 0000000000000000000000000000000000000000..181179aebfde2620f00650055bf98ffcdf3ec0ab
--- /dev/null
+++ b/arch/mips/mach-ath79/include/mach/ddr.h
@@ -0,0 +1,13 @@
+/*
+ * Copyright (C) 2015-2016 Wills Wang <wills.wang@live.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#ifndef __ASM_MACH_DDR_H
+#define __ASM_MACH_DDR_H
+
+void ddr_init(void);
+void ddr_tap_tuning(void);
+
+#endif /* __ASM_MACH_DDR_H */
diff --git a/arch/mips/mach-ath79/include/mach/reset.h b/arch/mips/mach-ath79/include/mach/reset.h
new file mode 100644
index 0000000000000000000000000000000000000000..c383bfe608672e602e5d5bf13856ae1987f4e195
--- /dev/null
+++ b/arch/mips/mach-ath79/include/mach/reset.h
@@ -0,0 +1,14 @@
+/*
+ * Copyright (C) 2015-2016 Wills Wang <wills.wang@live.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#ifndef __ASM_MACH_RESET_H
+#define __ASM_MACH_RESET_H
+
+#include <linux/types.h>
+
+u32 get_bootstrap(void);
+
+#endif /* __ASM_MACH_RESET_H */
diff --git a/arch/mips/mach-ath79/qca953x/Makefile b/arch/mips/mach-ath79/qca953x/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..fd74f0c2ae511afcb29b4cf558bb98336cfc9e56
--- /dev/null
+++ b/arch/mips/mach-ath79/qca953x/Makefile
@@ -0,0 +1,7 @@
+#
+# SPDX-License-Identifier:	GPL-2.0+
+#
+
+obj-y += clk.o
+obj-y += ddr.o
+obj-y += lowlevel_init.o
diff --git a/arch/mips/mach-ath79/qca953x/clk.c b/arch/mips/mach-ath79/qca953x/clk.c
new file mode 100644
index 0000000000000000000000000000000000000000..ef0a28e5054a86986918d06fe64aeda7ec33a66f
--- /dev/null
+++ b/arch/mips/mach-ath79/qca953x/clk.c
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2015-2016 Wills Wang <wills.wang@live.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <asm/addrspace.h>
+#include <asm/types.h>
+#include <mach/ar71xx_regs.h>
+#include <mach/reset.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+static u32 qca953x_get_xtal(void)
+{
+	u32 val;
+
+	val = get_bootstrap();
+	if (val & QCA953X_BOOTSTRAP_REF_CLK_40)
+		return 40000000;
+	else
+		return 25000000;
+}
+
+int get_serial_clock(void)
+{
+	return qca953x_get_xtal();
+}
+
+int get_clocks(void)
+{
+	void __iomem *regs;
+	u32 val, ctrl, xtal, pll, div;
+
+	regs = map_physmem(AR71XX_PLL_BASE, AR71XX_PLL_SIZE,
+			   MAP_NOCACHE);
+
+	xtal = qca953x_get_xtal();
+	ctrl = readl(regs + QCA953X_PLL_CLK_CTRL_REG);
+	val = readl(regs + QCA953X_PLL_CPU_CONFIG_REG);
+
+	/* VCOOUT = XTAL * DIV_INT */
+	div = (val >> QCA953X_PLL_CPU_CONFIG_REFDIV_SHIFT)
+			& QCA953X_PLL_CPU_CONFIG_REFDIV_MASK;
+	pll = xtal / div;
+
+	/* PLLOUT = VCOOUT * (1/2^OUTDIV) */
+	div = (val >> QCA953X_PLL_CPU_CONFIG_NINT_SHIFT)
+			& QCA953X_PLL_CPU_CONFIG_NINT_MASK;
+	pll *= div;
+	div = (val >> QCA953X_PLL_CPU_CONFIG_OUTDIV_SHIFT)
+			& QCA953X_PLL_CPU_CONFIG_OUTDIV_MASK;
+	if (!div)
+		div = 1;
+	pll >>= div;
+
+	/* CPU_CLK = PLLOUT / CPU_POST_DIV */
+	div = ((ctrl >> QCA953X_PLL_CLK_CTRL_CPU_POST_DIV_SHIFT)
+			& QCA953X_PLL_CLK_CTRL_CPU_POST_DIV_MASK) + 1;
+	gd->cpu_clk = pll / div;
+
+
+	val = readl(regs + QCA953X_PLL_DDR_CONFIG_REG);
+	/* VCOOUT = XTAL * DIV_INT */
+	div = (val >> QCA953X_PLL_DDR_CONFIG_REFDIV_SHIFT)
+			& QCA953X_PLL_DDR_CONFIG_REFDIV_MASK;
+	pll = xtal / div;
+
+	/* PLLOUT = VCOOUT * (1/2^OUTDIV) */
+	div = (val >> QCA953X_PLL_DDR_CONFIG_NINT_SHIFT)
+			& QCA953X_PLL_DDR_CONFIG_NINT_MASK;
+	pll *= div;
+	div = (val >> QCA953X_PLL_DDR_CONFIG_OUTDIV_SHIFT)
+			& QCA953X_PLL_DDR_CONFIG_OUTDIV_MASK;
+	if (!div)
+		div = 1;
+	pll >>= div;
+
+	/* DDR_CLK = PLLOUT / DDR_POST_DIV */
+	div = ((ctrl >> QCA953X_PLL_CLK_CTRL_DDR_POST_DIV_SHIFT)
+			& QCA953X_PLL_CLK_CTRL_DDR_POST_DIV_MASK) + 1;
+	gd->mem_clk = pll / div;
+
+	div = ((ctrl >> QCA953X_PLL_CLK_CTRL_AHB_POST_DIV_SHIFT)
+			& QCA953X_PLL_CLK_CTRL_AHB_POST_DIV_MASK) + 1;
+	if (ctrl & QCA953X_PLL_CLK_CTRL_AHBCLK_FROM_DDRPLL) {
+		/* AHB_CLK = DDR_CLK / AHB_POST_DIV */
+		gd->bus_clk = gd->mem_clk / (div + 1);
+	} else {
+		/* AHB_CLK = CPU_CLK / AHB_POST_DIV */
+		gd->bus_clk = gd->cpu_clk / (div + 1);
+	}
+
+	return 0;
+}
+
+ulong get_bus_freq(ulong dummy)
+{
+	if (!gd->bus_clk)
+		get_clocks();
+	return gd->bus_clk;
+}
+
+ulong get_ddr_freq(ulong dummy)
+{
+	if (!gd->mem_clk)
+		get_clocks();
+	return gd->mem_clk;
+}
diff --git a/arch/mips/mach-ath79/qca953x/ddr.c b/arch/mips/mach-ath79/qca953x/ddr.c
new file mode 100644
index 0000000000000000000000000000000000000000..ac0130cff0eb36458274d0aa08d9056236cd7d4a
--- /dev/null
+++ b/arch/mips/mach-ath79/qca953x/ddr.c
@@ -0,0 +1,472 @@
+/*
+ * Copyright (C) 2015-2016 Wills Wang <wills.wang@live.com>
+ * Based on Atheros LSDK/QSDK
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <asm/addrspace.h>
+#include <asm/types.h>
+#include <mach/ar71xx_regs.h>
+#include <mach/reset.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#define DDR_CTRL_UPD_EMR3S      BIT(5)
+#define DDR_CTRL_UPD_EMR2S      BIT(4)
+#define DDR_CTRL_PRECHARGE      BIT(3)
+#define DDR_CTRL_AUTO_REFRESH   BIT(2)
+#define DDR_CTRL_UPD_EMRS       BIT(1)
+#define DDR_CTRL_UPD_MRS        BIT(0)
+
+#define DDR_REFRESH_EN          BIT(14)
+#define DDR_REFRESH_M           0x3ff
+#define DDR_REFRESH(x)          ((x) & DDR_REFRESH_M)
+#define DDR_REFRESH_VAL         (DDR_REFRESH_EN | DDR_REFRESH(312))
+
+#define DDR_TRAS_S              0
+#define DDR_TRAS_M              0x1f
+#define DDR_TRAS(x)             (((x) & DDR_TRAS_M) << DDR_TRAS_S)
+#define DDR_TRCD_M              0xf
+#define DDR_TRCD_S              5
+#define DDR_TRCD(x)             (((x) & DDR_TRCD_M) << DDR_TRCD_S)
+#define DDR_TRP_M               0xf
+#define DDR_TRP_S               9
+#define DDR_TRP(x)              (((x) & DDR_TRP_M) << DDR_TRP_S)
+#define DDR_TRRD_M              0xf
+#define DDR_TRRD_S              13
+#define DDR_TRRD(x)             (((x) & DDR_TRRD_M) << DDR_TRRD_S)
+#define DDR_TRFC_M              0x7f
+#define DDR_TRFC_S              17
+#define DDR_TRFC(x)             (((x) & DDR_TRFC_M) << DDR_TRFC_S)
+#define DDR_TMRD_M              0xf
+#define DDR_TMRD_S              23
+#define DDR_TMRD(x)             (((x) & DDR_TMRD_M) << DDR_TMRD_S)
+#define DDR_CAS_L_M             0x17
+#define DDR_CAS_L_S             27
+#define DDR_CAS_L(x)            (((x) & DDR_CAS_L_M) << DDR_CAS_L_S)
+#define DDR_OPEN                BIT(30)
+#define DDR1_CONF_REG_VAL       (DDR_TRAS(16) | DDR_TRCD(6) | \
+				 DDR_TRP(6) | DDR_TRRD(4) | \
+				 DDR_TRFC(7) | DDR_TMRD(5) | \
+				 DDR_CAS_L(7) | DDR_OPEN)
+#define DDR2_CONF_REG_VAL       (DDR_TRAS(27) | DDR_TRCD(9) | \
+				 DDR_TRP(9) | DDR_TRRD(7) | \
+				 DDR_TRFC(21) | DDR_TMRD(15) | \
+				 DDR_CAS_L(17) | DDR_OPEN)
+
+#define DDR_BURST_LEN_S         0
+#define DDR_BURST_LEN_M         0xf
+#define DDR_BURST_LEN(x)        ((x) << DDR_BURST_LEN_S)
+#define DDR_BURST_TYPE          BIT(4)
+#define DDR_CNTL_OE_EN          BIT(5)
+#define DDR_PHASE_SEL           BIT(6)
+#define DDR_CKE                 BIT(7)
+#define DDR_TWR_S               8
+#define DDR_TWR_M               0xf
+#define DDR_TWR(x)              (((x) & DDR_TWR_M) << DDR_TWR_S)
+#define DDR_TRTW_S              12
+#define DDR_TRTW_M              0x1f
+#define DDR_TRTW(x)             (((x) & DDR_TRTW_M) << DDR_TRTW_S)
+#define DDR_TRTP_S              17
+#define DDR_TRTP_M              0xf
+#define DDR_TRTP(x)             (((x) & DDR_TRTP_M) << DDR_TRTP_S)
+#define DDR_TWTR_S              21
+#define DDR_TWTR_M              0x1f
+#define DDR_TWTR(x)             (((x) & DDR_TWTR_M) << DDR_TWTR_S)
+#define DDR_G_OPEN_L_S          26
+#define DDR_G_OPEN_L_M          0xf
+#define DDR_G_OPEN_L(x)         ((x) << DDR_G_OPEN_L_S)
+#define DDR_HALF_WIDTH_LOW      BIT(31)
+#define DDR1_CONF2_REG_VAL      (DDR_BURST_LEN(8) | DDR_CNTL_OE_EN | \
+				 DDR_CKE | DDR_TWR(13) | DDR_TRTW(14) | \
+				 DDR_TRTP(8) | DDR_TWTR(14) | \
+				 DDR_G_OPEN_L(6) | DDR_HALF_WIDTH_LOW)
+#define DDR2_CONF2_REG_VAL      (DDR_BURST_LEN(8) | DDR_CNTL_OE_EN | \
+				 DDR_CKE | DDR_TWR(1) | DDR_TRTW(14) | \
+				 DDR_TRTP(9) | DDR_TWTR(21) | \
+				 DDR_G_OPEN_L(8) | DDR_HALF_WIDTH_LOW)
+
+#define DDR_TWR_MSB             BIT(3)
+#define DDR_TRAS_MSB            BIT(2)
+#define DDR_TRFC_MSB_M          0x3
+#define DDR_TRFC_MSB(x)         (x)
+#define DDR1_CONF3_REG_VAL      0
+#define DDR2_CONF3_REG_VAL      (DDR_TWR_MSB | DDR_TRFC_MSB(2))
+
+#define DDR_CTL_SRAM_TSEL       BIT(30)
+#define DDR_CTL_SRAM_GE0_SYNC   BIT(20)
+#define DDR_CTL_SRAM_GE1_SYNC   BIT(19)
+#define DDR_CTL_SRAM_USB_SYNC   BIT(18)
+#define DDR_CTL_SRAM_PCIE_SYNC  BIT(17)
+#define DDR_CTL_SRAM_WMAC_SYNC  BIT(16)
+#define DDR_CTL_SRAM_MISC1_SYNC BIT(15)
+#define DDR_CTL_SRAM_MISC2_SYNC BIT(14)
+#define DDR_CTL_PAD_DDR2_SEL    BIT(6)
+#define DDR_CTL_HALF_WIDTH      BIT(1)
+#define DDR_CTL_CONFIG_VAL      (DDR_CTL_SRAM_TSEL | \
+				 DDR_CTL_SRAM_GE0_SYNC | \
+				 DDR_CTL_SRAM_GE1_SYNC | \
+				 DDR_CTL_SRAM_USB_SYNC | \
+				 DDR_CTL_SRAM_PCIE_SYNC | \
+				 DDR_CTL_SRAM_WMAC_SYNC | \
+				 DDR_CTL_HALF_WIDTH)
+
+#define DDR_BURST_GE0_MAX_BL_S  0
+#define DDR_BURST_GE0_MAX_BL_M  0xf
+#define DDR_BURST_GE0_MAX_BL(x) \
+	(((x) & DDR_BURST_GE0_MAX_BL_M) << DDR_BURST_GE0_MAX_BL_S)
+#define DDR_BURST_GE1_MAX_BL_S  4
+#define DDR_BURST_GE1_MAX_BL_M  0xf
+#define DDR_BURST_GE1_MAX_BL(x) \
+	(((x) & DDR_BURST_GE1_MAX_BL_M) << DDR_BURST_GE1_MAX_BL_S)
+#define DDR_BURST_PCIE_MAX_BL_S 8
+#define DDR_BURST_PCIE_MAX_BL_M 0xf
+#define DDR_BURST_PCIE_MAX_BL(x) \
+	(((x) & DDR_BURST_PCIE_MAX_BL_M) << DDR_BURST_PCIE_MAX_BL_S)
+#define DDR_BURST_USB_MAX_BL_S  12
+#define DDR_BURST_USB_MAX_BL_M  0xf
+#define DDR_BURST_USB_MAX_BL(x) \
+	(((x) & DDR_BURST_USB_MAX_BL_M) << DDR_BURST_USB_MAX_BL_S)
+#define DDR_BURST_CPU_MAX_BL_S  16
+#define DDR_BURST_CPU_MAX_BL_M  0xf
+#define DDR_BURST_CPU_MAX_BL(x) \
+	(((x) & DDR_BURST_CPU_MAX_BL_M) << DDR_BURST_CPU_MAX_BL_S)
+#define DDR_BURST_RD_MAX_BL_S   20
+#define DDR_BURST_RD_MAX_BL_M   0xf
+#define DDR_BURST_RD_MAX_BL(x) \
+	(((x) & DDR_BURST_RD_MAX_BL_M) << DDR_BURST_RD_MAX_BL_S)
+#define DDR_BURST_WR_MAX_BL_S   24
+#define DDR_BURST_WR_MAX_BL_M   0xf
+#define DDR_BURST_WR_MAX_BL(x) \
+	(((x) & DDR_BURST_WR_MAX_BL_M) << DDR_BURST_WR_MAX_BL_S)
+#define DDR_BURST_RWP_MASK_EN_S 28
+#define DDR_BURST_RWP_MASK_EN_M 0x3
+#define DDR_BURST_RWP_MASK_EN(x) \
+	(((x) & DDR_BURST_RWP_MASK_EN_M) << DDR_BURST_RWP_MASK_EN_S)
+#define DDR_BURST_CPU_PRI_BE    BIT(30)
+#define DDR_BURST_CPU_PRI       BIT(31)
+#define DDR_BURST_VAL           (DDR_BURST_CPU_PRI_BE | \
+				 DDR_BURST_RWP_MASK_EN(3) | \
+				 DDR_BURST_WR_MAX_BL(4) | \
+				 DDR_BURST_RD_MAX_BL(4) | \
+				 DDR_BURST_CPU_MAX_BL(4) | \
+				 DDR_BURST_USB_MAX_BL(4) | \
+				 DDR_BURST_PCIE_MAX_BL(4) | \
+				 DDR_BURST_GE1_MAX_BL(4) | \
+				 DDR_BURST_GE0_MAX_BL(4))
+
+#define DDR_BURST_WMAC_MAX_BL_S 0
+#define DDR_BURST_WMAC_MAX_BL_M 0xf
+#define DDR_BURST_WMAC_MAX_BL(x) \
+	(((x) & DDR_BURST_WMAC_MAX_BL_M) << DDR_BURST_WMAC_MAX_BL_S)
+#define DDR_BURST2_VAL          DDR_BURST_WMAC_MAX_BL(4)
+
+#define DDR2_CONF_TWL_S         10
+#define DDR2_CONF_TWL_M         0xf
+#define DDR2_CONF_TWL(x) \
+	(((x) & DDR2_CONF_TWL_M) << DDR2_CONF_TWL_S)
+#define DDR2_CONF_ODT           BIT(9)
+#define DDR2_CONF_TFAW_S        2
+#define DDR2_CONF_TFAW_M        0x3f
+#define DDR2_CONF_TFAW(x) \
+	(((x) & DDR2_CONF_TFAW_M) << DDR2_CONF_TFAW_S)
+#define DDR2_CONF_EN            BIT(0)
+#define DDR2_CONF_VAL           (DDR2_CONF_TWL(5) | \
+				 DDR2_CONF_TFAW(31) | \
+				 DDR2_CONF_ODT | \
+				 DDR2_CONF_EN)
+
+#define DDR1_EXT_MODE_VAL       0
+#define DDR2_EXT_MODE_VAL       0x402
+#define DDR2_EXT_MODE_OCD_VAL   0x782
+#define DDR1_MODE_DLL_VAL       0x133
+#define DDR2_MODE_DLL_VAL       0x143
+#define DDR1_MODE_VAL           0x33
+#define DDR2_MODE_VAL           0x43
+#define DDR1_TAP_VAL            0x20
+#define DDR2_TAP_VAL            0x10
+
+#define DDR_REG_BIST_MASK_ADDR_0        0x2c
+#define DDR_REG_BIST_MASK_ADDR_1        0x30
+#define DDR_REG_BIST_MASK_AHB_GE0_0     0x34
+#define DDR_REG_BIST_COMP_AHB_GE0_0     0x38
+#define DDR_REG_BIST_MASK_AHB_GE1_0     0x3c
+#define DDR_REG_BIST_COMP_AHB_GE1_0     0x40
+#define DDR_REG_BIST_COMP_ADDR_0        0x64
+#define DDR_REG_BIST_COMP_ADDR_1        0x68
+#define DDR_REG_BIST_MASK_AHB_GE0_1     0x6c
+#define DDR_REG_BIST_COMP_AHB_GE0_1     0x70
+#define DDR_REG_BIST_MASK_AHB_GE1_1     0x74
+#define DDR_REG_BIST_COMP_AHB_GE1_1     0x78
+#define DDR_REG_BIST                    0x11c
+#define DDR_REG_BIST_STATUS             0x120
+
+#define DDR_BIST_COMP_CNT_S     1
+#define DDR_BIST_COMP_CNT_M     0xff
+#define DDR_BIST_COMP_CNT(x) \
+	(((x) & DDR_BIST_COMP_CNT_M) << DDR_BIST_COMP_CNT_S)
+#define DDR_BIST_COMP_CNT_MASK \
+	(DDR_BIST_COMP_CNT_M << DDR_BIST_COMP_CNT_S)
+#define DDR_BIST_TEST_START     BIT(0)
+#define DDR_BIST_STATUS_DONE    BIT(0)
+
+/* 4 Row Address Bits, 4 Column Address Bits, 2 BA bits */
+#define DDR_BIST_MASK_ADDR_VAL  0xfa5de83f
+
+#define DDR_TAP_MAGIC_VAL       0xaa55aa55
+#define DDR_TAP_MAX_VAL         0x40
+
+void ddr_init(void)
+{
+	void __iomem *regs;
+	u32 val;
+
+	regs = map_physmem(AR71XX_DDR_CTRL_BASE, AR71XX_DDR_CTRL_SIZE,
+			   MAP_NOCACHE);
+	val = get_bootstrap();
+	if (val & QCA953X_BOOTSTRAP_DDR1) {
+		writel(DDR_CTL_CONFIG_VAL, regs + QCA953X_DDR_REG_CTL_CONF);
+		udelay(10);
+
+		/* For 16-bit DDR */
+		writel(0xffff, regs + AR71XX_DDR_REG_RD_CYCLE);
+		udelay(100);
+
+		/* Burst size */
+		writel(DDR_BURST_VAL, regs + QCA953X_DDR_REG_BURST);
+		udelay(100);
+		writel(DDR_BURST2_VAL, regs + QCA953X_DDR_REG_BURST2);
+		udelay(100);
+
+		/* AHB maximum timeout */
+		writel(0xfffff, regs + QCA953X_DDR_REG_TIMEOUT_MAX);
+		udelay(100);
+
+		/* DRAM timing */
+		writel(DDR1_CONF_REG_VAL, regs + AR71XX_DDR_REG_CONFIG);
+		udelay(100);
+		writel(DDR1_CONF2_REG_VAL, regs + AR71XX_DDR_REG_CONFIG2);
+		udelay(100);
+		writel(DDR1_CONF3_REG_VAL, regs + QCA953X_DDR_REG_CONFIG3);
+		udelay(100);
+
+		/* Precharge All */
+		writel(DDR_CTRL_PRECHARGE, regs + AR71XX_DDR_REG_CONTROL);
+		udelay(100);
+
+		/* ODT disable, Full strength, Enable DLL */
+		writel(DDR1_EXT_MODE_VAL, regs + AR71XX_DDR_REG_EMR);
+		udelay(100);
+
+		/* Update Extended Mode Register Set (EMRS) */
+		writel(DDR_CTRL_UPD_EMRS, regs + AR71XX_DDR_REG_CONTROL);
+		udelay(100);
+
+		/* Reset DLL, CAS Latency 3, Burst Length 8 */
+		writel(DDR1_MODE_DLL_VAL, regs + AR71XX_DDR_REG_MODE);
+		udelay(100);
+
+		/* Update Mode Register Set (MRS) */
+		writel(DDR_CTRL_UPD_MRS, regs + AR71XX_DDR_REG_CONTROL);
+		udelay(100);
+
+		/* Precharge All */
+		writel(DDR_CTRL_PRECHARGE, regs + AR71XX_DDR_REG_CONTROL);
+		udelay(100);
+
+		/* Auto Refresh */
+		writel(DDR_CTRL_AUTO_REFRESH, regs + AR71XX_DDR_REG_CONTROL);
+		udelay(100);
+		writel(DDR_CTRL_AUTO_REFRESH, regs + AR71XX_DDR_REG_CONTROL);
+		udelay(100);
+
+		/* Normal DLL, CAS Latency 3, Burst Length 8 */
+		writel(DDR1_MODE_VAL, regs + AR71XX_DDR_REG_MODE);
+		udelay(100);
+
+		/* Update Mode Register Set (MRS) */
+		writel(DDR_CTRL_UPD_MRS, regs + AR71XX_DDR_REG_CONTROL);
+		udelay(100);
+
+		/* Refresh time control */
+		writel(DDR_REFRESH_VAL, regs + AR71XX_DDR_REG_REFRESH);
+		udelay(100);
+
+		/* DQS 0 Tap Control */
+		writel(DDR1_TAP_VAL, regs + AR71XX_DDR_REG_TAP_CTRL0);
+
+		/* DQS 1 Tap Control */
+		writel(DDR1_TAP_VAL, regs + AR71XX_DDR_REG_TAP_CTRL1);
+	} else {
+		writel(DDR_CTRL_UPD_EMR2S, regs + AR71XX_DDR_REG_CONTROL);
+		udelay(10);
+		writel(DDR_CTRL_UPD_EMR3S, regs + AR71XX_DDR_REG_CONTROL);
+		udelay(10);
+		writel(DDR_CTL_CONFIG_VAL | DDR_CTL_PAD_DDR2_SEL,
+		       regs + QCA953X_DDR_REG_CTL_CONF);
+		udelay(10);
+
+		/* For 16-bit DDR */
+		writel(0xffff, regs + AR71XX_DDR_REG_RD_CYCLE);
+		udelay(100);
+
+		/* Burst size */
+		writel(DDR_BURST_VAL, regs + QCA953X_DDR_REG_BURST);
+		udelay(100);
+		writel(DDR_BURST2_VAL, regs + QCA953X_DDR_REG_BURST2);
+		udelay(100);
+
+		/* AHB maximum timeout */
+		writel(0xfffff, regs + QCA953X_DDR_REG_TIMEOUT_MAX);
+		udelay(100);
+
+		/* DRAM timing */
+		writel(DDR2_CONF_REG_VAL, regs + AR71XX_DDR_REG_CONFIG);
+		udelay(100);
+		writel(DDR2_CONF2_REG_VAL, regs + AR71XX_DDR_REG_CONFIG2);
+		udelay(100);
+		writel(DDR2_CONF3_REG_VAL, regs + QCA953X_DDR_REG_CONFIG3);
+		udelay(100);
+
+		/* Enable DDR2 */
+		writel(DDR2_CONF_VAL, regs + QCA953X_DDR_REG_DDR2_CONFIG);
+		udelay(100);
+
+		/* Precharge All */
+		writel(DDR_CTRL_PRECHARGE, regs + AR71XX_DDR_REG_CONTROL);
+		udelay(100);
+
+		/* Update Extended Mode Register 2 Set (EMR2S) */
+		writel(DDR_CTRL_UPD_EMR2S, regs + AR71XX_DDR_REG_CONTROL);
+		udelay(100);
+
+		/* Update Extended Mode Register 3 Set (EMR3S) */
+		writel(DDR_CTRL_UPD_EMR3S, regs + AR71XX_DDR_REG_CONTROL);
+		udelay(100);
+
+		/* 150 ohm, Reduced strength, Enable DLL */
+		writel(DDR2_EXT_MODE_VAL, regs + AR71XX_DDR_REG_EMR);
+		udelay(100);
+
+		/* Update Extended Mode Register Set (EMRS) */
+		writel(DDR_CTRL_UPD_EMRS, regs + AR71XX_DDR_REG_CONTROL);
+		udelay(100);
+
+		/* Reset DLL, CAS Latency 4, Burst Length 8 */
+		writel(DDR2_MODE_DLL_VAL, regs + AR71XX_DDR_REG_MODE);
+		udelay(100);
+
+		/* Update Mode Register Set (MRS) */
+		writel(DDR_CTRL_UPD_MRS, regs + AR71XX_DDR_REG_CONTROL);
+		udelay(100);
+
+		/* Precharge All */
+		writel(DDR_CTRL_PRECHARGE, regs + AR71XX_DDR_REG_CONTROL);
+		udelay(100);
+
+		/* Auto Refresh */
+		writel(DDR_CTRL_AUTO_REFRESH, regs + AR71XX_DDR_REG_CONTROL);
+		udelay(100);
+		writel(DDR_CTRL_AUTO_REFRESH, regs + AR71XX_DDR_REG_CONTROL);
+		udelay(100);
+
+		/* Normal DLL, CAS Latency 4, Burst Length 8 */
+		writel(DDR2_MODE_VAL, regs + AR71XX_DDR_REG_MODE);
+		udelay(100);
+
+		/* Mode Register Set (MRS) */
+		writel(DDR_CTRL_UPD_MRS, regs + AR71XX_DDR_REG_CONTROL);
+		udelay(100);
+
+		/* Enable OCD, Enable DLL, Reduced Drive Strength */
+		writel(DDR2_EXT_MODE_OCD_VAL, regs + AR71XX_DDR_REG_EMR);
+		udelay(100);
+
+		/* Update Extended Mode Register Set (EMRS) */
+		writel(DDR_CTRL_UPD_EMRS, regs + AR71XX_DDR_REG_CONTROL);
+		udelay(100);
+
+		/* OCD diable, Enable DLL, Reduced Drive Strength */
+		writel(DDR2_EXT_MODE_VAL, regs + AR71XX_DDR_REG_EMR);
+		udelay(100);
+
+		/* Update Extended Mode Register Set (EMRS) */
+		writel(DDR_CTRL_UPD_EMRS, regs + AR71XX_DDR_REG_CONTROL);
+		udelay(100);
+
+		/* Refresh time control */
+		writel(DDR_REFRESH_VAL, regs + AR71XX_DDR_REG_REFRESH);
+		udelay(100);
+
+		/* DQS 0 Tap Control */
+		writel(DDR2_TAP_VAL, regs + AR71XX_DDR_REG_TAP_CTRL0);
+
+		/* DQS 1 Tap Control */
+		writel(DDR2_TAP_VAL, regs + AR71XX_DDR_REG_TAP_CTRL1);
+	}
+}
+
+void ddr_tap_tuning(void)
+{
+	void __iomem *regs;
+	u32 val, pass, tap, cnt, tap_val, last, first;
+
+	regs = map_physmem(AR71XX_DDR_CTRL_BASE, AR71XX_DDR_CTRL_SIZE,
+			   MAP_NOCACHE);
+
+	tap_val = readl(regs + AR71XX_DDR_REG_TAP_CTRL0);
+	first = DDR_TAP_MAGIC_VAL;
+	last = 0;
+	cnt = 0;
+	tap = 0;
+
+	do {
+		writel(tap, regs + AR71XX_DDR_REG_TAP_CTRL0);
+		writel(tap, regs + AR71XX_DDR_REG_TAP_CTRL1);
+
+		writel(DDR_BIST_COMP_CNT(8), regs + DDR_REG_BIST_COMP_ADDR_1);
+		writel(DDR_BIST_MASK_ADDR_VAL, regs + DDR_REG_BIST_MASK_ADDR_0);
+		writel(0xffff, regs + DDR_REG_BIST_COMP_AHB_GE0_1);
+		writel(0xffff, regs + DDR_REG_BIST_COMP_AHB_GE1_0);
+		writel(0xffff, regs + DDR_REG_BIST_COMP_AHB_GE1_1);
+		writel(0xffff, regs + DDR_REG_BIST_MASK_AHB_GE0_0);
+		writel(0xffff, regs + DDR_REG_BIST_MASK_AHB_GE0_1);
+		writel(0xffff, regs + DDR_REG_BIST_MASK_AHB_GE1_0);
+		writel(0xffff, regs + DDR_REG_BIST_MASK_AHB_GE1_1);
+		writel(0xffff, regs + DDR_REG_BIST_COMP_AHB_GE0_0);
+
+		/* Start BIST test */
+		writel(DDR_BIST_TEST_START, regs + DDR_REG_BIST);
+
+		do {
+			val = readl(regs + DDR_REG_BIST_STATUS);
+		} while (!(val & DDR_BIST_STATUS_DONE));
+
+		/* Stop BIST test */
+		writel(0, regs + DDR_REG_BIST);
+
+		pass = val & DDR_BIST_COMP_CNT_MASK;
+		pass ^= DDR_BIST_COMP_CNT(8);
+		if (!pass) {
+			if (first != DDR_TAP_MAGIC_VAL) {
+				last = tap;
+			} else  {
+				first = tap;
+				last = tap;
+			}
+			cnt++;
+		}
+		tap++;
+	} while (tap < DDR_TAP_MAX_VAL);
+
+	if (cnt) {
+		tap_val = (first + last) / 2;
+		tap_val %= DDR_TAP_MAX_VAL;
+	}
+
+	writel(tap_val, regs + AR71XX_DDR_REG_TAP_CTRL0);
+	writel(tap_val, regs + AR71XX_DDR_REG_TAP_CTRL1);
+}
diff --git a/arch/mips/mach-ath79/qca953x/lowlevel_init.S b/arch/mips/mach-ath79/qca953x/lowlevel_init.S
new file mode 100644
index 0000000000000000000000000000000000000000..d7038faa6afbe04f58ee3a194b311eecdef576c3
--- /dev/null
+++ b/arch/mips/mach-ath79/qca953x/lowlevel_init.S
@@ -0,0 +1,186 @@
+/*
+ * Copyright (C) 2015-2016 Wills Wang <wills.wang@live.com>
+ * Based on Atheros LSDK/QSDK
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <config.h>
+#include <asm/asm.h>
+#include <asm/regdef.h>
+#include <asm/mipsregs.h>
+#include <asm/addrspace.h>
+#include <mach/ar71xx_regs.h>
+
+#define MK_PLL_CONF(divint, refdiv, range, outdiv) \
+     (((0x3F & divint) << 10) | \
+     ((0x1F & refdiv) << 16) | \
+     ((0x1 & range)   << 21) | \
+     ((0x7 & outdiv)  << 23) )
+
+#define MK_CLK_CNTL(cpudiv, ddrdiv, ahbdiv) \
+    (((0x3 & (cpudiv - 1)) << 5)  | \
+    ((0x3 & (ddrdiv - 1)) << 10) | \
+    ((0x3 & (ahbdiv - 1)) << 15) )
+
+#define SET_FIELD(name, v)      (((v) & QCA953X_##name##_MASK) << \
+				 QCA953X_##name##_SHIFT)
+
+#define DPLL2_KI(v)             SET_FIELD(SRIF_DPLL2_KI, v)
+#define DPLL2_KD(v)             SET_FIELD(SRIF_DPLL2_KD, v)
+#define DPLL2_PWD               QCA953X_SRIF_DPLL2_PWD
+#define MK_DPLL2(ki, kd)        (DPLL2_KI(ki) | DPLL2_KD(kd) | DPLL2_PWD)
+
+#define PLL_CPU_NFRAC(v)        SET_FIELD(PLL_CPU_CONFIG_NFRAC, v)
+#define PLL_CPU_NINT(v)         SET_FIELD(PLL_CPU_CONFIG_NINT, v)
+#define PLL_CPU_REFDIV(v)       SET_FIELD(PLL_CPU_CONFIG_REFDIV, v)
+#define PLL_CPU_OUTDIV(v)       SET_FIELD(PLL_CPU_CONFIG_OUTDIV, v)
+#define MK_PLL_CPU_CONF(frac, nint, ref, outdiv) \
+				(PLL_CPU_NFRAC(frac) | \
+				 PLL_CPU_NINT(nint) | \
+				 PLL_CPU_REFDIV(ref) | \
+				 PLL_CPU_OUTDIV(outdiv))
+
+#define PLL_DDR_NFRAC(v)        SET_FIELD(PLL_DDR_CONFIG_NFRAC, v)
+#define PLL_DDR_NINT(v)         SET_FIELD(PLL_DDR_CONFIG_NINT, v)
+#define PLL_DDR_REFDIV(v)       SET_FIELD(PLL_DDR_CONFIG_REFDIV, v)
+#define PLL_DDR_OUTDIV(v)       SET_FIELD(PLL_DDR_CONFIG_OUTDIV, v)
+#define MK_PLL_DDR_CONF(frac, nint, ref, outdiv) \
+				(PLL_DDR_NFRAC(frac) | \
+				 PLL_DDR_REFDIV(ref) | \
+				 PLL_DDR_NINT(nint) | \
+				 PLL_DDR_OUTDIV(outdiv) | \
+				 QCA953X_PLL_CONFIG_PWD)
+
+#define PLL_CPU_CONF_VAL        MK_PLL_CPU_CONF(0, 26, 1, 0)
+#define PLL_DDR_CONF_VAL        MK_PLL_DDR_CONF(0, 15, 1, 0)
+
+#define PLL_CLK_CTRL_PLL_BYPASS (QCA953X_PLL_CLK_CTRL_CPU_PLL_BYPASS | \
+				 QCA953X_PLL_CLK_CTRL_DDR_PLL_BYPASS | \
+				 QCA953X_PLL_CLK_CTRL_AHB_PLL_BYPASS)
+
+#define PLL_CLK_CTRL_CPU_DIV(v) SET_FIELD(PLL_CLK_CTRL_CPU_POST_DIV, v)
+#define PLL_CLK_CTRL_DDR_DIV(v) SET_FIELD(PLL_CLK_CTRL_DDR_POST_DIV, v)
+#define PLL_CLK_CTRL_AHB_DIV(v) SET_FIELD(PLL_CLK_CTRL_AHB_POST_DIV, v)
+#define MK_PLL_CLK_CTRL(cpu, ddr, ahb) \
+				(PLL_CLK_CTRL_CPU_DIV(cpu) | \
+				 PLL_CLK_CTRL_DDR_DIV(ddr) | \
+				 PLL_CLK_CTRL_AHB_DIV(ahb))
+#define PLL_CLK_CTRL_VAL    (MK_PLL_CLK_CTRL(0, 0, 2) | \
+			     PLL_CLK_CTRL_PLL_BYPASS | \
+			     QCA953X_PLL_CLK_CTRL_CPUCLK_FROM_CPUPLL | \
+			     QCA953X_PLL_CLK_CTRL_DDRCLK_FROM_DDRPLL)
+
+#define PLL_DDR_DIT_FRAC_MAX(v)     SET_FIELD(PLL_DDR_DIT_FRAC_MAX, v)
+#define PLL_DDR_DIT_FRAC_MIN(v)     SET_FIELD(PLL_DDR_DIT_FRAC_MIN, v)
+#define PLL_DDR_DIT_FRAC_STEP(v)    SET_FIELD(PLL_DDR_DIT_FRAC_STEP, v)
+#define PLL_DDR_DIT_UPD_CNT(v)      SET_FIELD(PLL_DDR_DIT_UPD_CNT, v)
+#define PLL_CPU_DIT_FRAC_MAX(v)     SET_FIELD(PLL_CPU_DIT_FRAC_MAX, v)
+#define PLL_CPU_DIT_FRAC_MIN(v)     SET_FIELD(PLL_CPU_DIT_FRAC_MIN, v)
+#define PLL_CPU_DIT_FRAC_STEP(v)    SET_FIELD(PLL_CPU_DIT_FRAC_STEP, v)
+#define PLL_CPU_DIT_UPD_CNT(v)      SET_FIELD(PLL_CPU_DIT_UPD_CNT, v)
+#define MK_PLL_DDR_DIT_FRAC(max, min, step, cnt) \
+				(QCA953X_PLL_DIT_FRAC_EN | \
+				 PLL_DDR_DIT_FRAC_MAX(max) | \
+				 PLL_DDR_DIT_FRAC_MIN(min) | \
+				 PLL_DDR_DIT_FRAC_STEP(step) | \
+				 PLL_DDR_DIT_UPD_CNT(cnt))
+#define MK_PLL_CPU_DIT_FRAC(max, min, step, cnt) \
+				(QCA953X_PLL_DIT_FRAC_EN | \
+				 PLL_CPU_DIT_FRAC_MAX(max) | \
+				 PLL_CPU_DIT_FRAC_MIN(min) | \
+				 PLL_CPU_DIT_FRAC_STEP(step) | \
+				 PLL_CPU_DIT_UPD_CNT(cnt))
+#define PLL_CPU_DIT_FRAC_VAL    MK_PLL_CPU_DIT_FRAC(63, 0, 1, 15)
+#define PLL_DDR_DIT_FRAC_VAL    MK_PLL_DDR_DIT_FRAC(763, 635, 1, 15)
+
+    .text
+    .set noreorder
+
+LEAF(lowlevel_init)
+	/* RTC Reset */
+	li      t0, CKSEG1ADDR(AR71XX_RESET_BASE)
+	lw      t1, QCA953X_RESET_REG_RESET_MODULE(t0)
+	li      t2, 0x08000000
+	or      t1, t1, t2
+	sw      t1, QCA953X_RESET_REG_RESET_MODULE(t0)
+	nop
+	lw      t1, QCA953X_RESET_REG_RESET_MODULE(t0)
+	li      t2, 0xf7ffffff
+	and     t1, t1, t2
+	sw      t1, QCA953X_RESET_REG_RESET_MODULE(t0)
+	nop
+
+	/* RTC Force Wake */
+	li      t0, CKSEG1ADDR(QCA953X_RTC_BASE)
+	li      t1, 0x01
+	sw      t1, QCA953X_RTC_REG_SYNC_RESET(t0)
+	nop
+	nop
+
+	/* Wait for RTC in on state */
+1:
+	lw      t1, QCA953X_RTC_REG_SYNC_STATUS(t0)
+	andi    t1, t1, 0x02
+	beqz    t1, 1b
+	nop
+
+	li      t0, CKSEG1ADDR(QCA953X_SRIF_BASE)
+	li      t1, MK_DPLL2(2, 16)
+	sw      t1, QCA953X_SRIF_BB_DPLL2_REG(t0)
+	sw      t1, QCA953X_SRIF_PCIE_DPLL2_REG(t0)
+	sw      t1, QCA953X_SRIF_DDR_DPLL2_REG(t0)
+	sw      t1, QCA953X_SRIF_CPU_DPLL2_REG(t0)
+
+	li      t0, CKSEG1ADDR(AR71XX_PLL_BASE)
+	lw      t1, QCA953X_PLL_CLK_CTRL_REG(t0)
+	ori     t1, PLL_CLK_CTRL_PLL_BYPASS
+	sw      t1, QCA953X_PLL_CLK_CTRL_REG(t0)
+	nop
+
+	li      t1, PLL_CPU_CONF_VAL
+	sw      t1, QCA953X_PLL_CPU_CONFIG_REG(t0)
+	nop
+
+	li      t1, PLL_DDR_CONF_VAL
+	sw      t1, QCA953X_PLL_DDR_CONFIG_REG(t0)
+	nop
+
+	li      t1, PLL_CLK_CTRL_VAL
+	sw      t1, QCA953X_PLL_CLK_CTRL_REG(t0)
+	nop
+
+	lw      t1, QCA953X_PLL_CPU_CONFIG_REG(t0)
+	li      t2, ~QCA953X_PLL_CONFIG_PWD
+	and     t1, t1, t2
+	sw      t1, QCA953X_PLL_CPU_CONFIG_REG(t0)
+	nop
+
+	lw      t1, QCA953X_PLL_DDR_CONFIG_REG(t0)
+	li      t2, ~QCA953X_PLL_CONFIG_PWD
+	and     t1, t1, t2
+	sw      t1, QCA953X_PLL_DDR_CONFIG_REG(t0)
+	nop
+
+	lw      t1, QCA953X_PLL_CLK_CTRL_REG(t0)
+	li      t2, ~PLL_CLK_CTRL_PLL_BYPASS
+	and     t1, t1, t2
+	sw      t1, QCA953X_PLL_CLK_CTRL_REG(t0)
+	nop
+
+	li      t1, PLL_DDR_DIT_FRAC_VAL
+	sw      t1, QCA953X_PLL_DDR_DIT_FRAC_REG(t0)
+	nop
+
+	li      t1, PLL_CPU_DIT_FRAC_VAL
+	sw      t1, QCA953X_PLL_CPU_DIT_FRAC_REG(t0)
+	nop
+
+	li      t0, CKSEG1ADDR(AR71XX_RESET_BASE)
+	lui     t1, 0x03fc
+	sw      t1, 0xb4(t0)
+
+	nop
+	jr ra
+	 nop
+    END(lowlevel_init)
diff --git a/arch/mips/mach-ath79/reset.c b/arch/mips/mach-ath79/reset.c
new file mode 100644
index 0000000000000000000000000000000000000000..188eccb9bfebae195d51c8837d19b2484181884d
--- /dev/null
+++ b/arch/mips/mach-ath79/reset.c
@@ -0,0 +1,208 @@
+/*
+ * Copyright (C) 2015-2016 Wills Wang <wills.wang@live.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <asm/errno.h>
+#include <asm/io.h>
+#include <asm/addrspace.h>
+#include <asm/types.h>
+#include <mach/ath79.h>
+#include <mach/ar71xx_regs.h>
+
+void _machine_restart(void)
+{
+	void __iomem *base;
+	u32 reg = 0;
+
+	base = map_physmem(AR71XX_RESET_BASE, AR71XX_RESET_SIZE,
+			   MAP_NOCACHE);
+	if (soc_is_ar71xx())
+		reg = AR71XX_RESET_REG_RESET_MODULE;
+	else if (soc_is_ar724x())
+		reg = AR724X_RESET_REG_RESET_MODULE;
+	else if (soc_is_ar913x())
+		reg = AR913X_RESET_REG_RESET_MODULE;
+	else if (soc_is_ar933x())
+		reg = AR933X_RESET_REG_RESET_MODULE;
+	else if (soc_is_ar934x())
+		reg = AR934X_RESET_REG_RESET_MODULE;
+	else if (soc_is_qca953x())
+		reg = QCA953X_RESET_REG_RESET_MODULE;
+	else if (soc_is_qca955x())
+		reg = QCA955X_RESET_REG_RESET_MODULE;
+	else if (soc_is_qca956x())
+		reg = QCA956X_RESET_REG_RESET_MODULE;
+	else
+		puts("Reset register not defined for this SOC\n");
+
+	if (reg)
+		setbits_be32(base + reg, AR71XX_RESET_FULL_CHIP);
+
+	while (1)
+		/* NOP */;
+}
+
+u32 get_bootstrap(void)
+{
+	void __iomem *base;
+	u32 reg = 0;
+
+	base = map_physmem(AR71XX_RESET_BASE, AR71XX_RESET_SIZE,
+			   MAP_NOCACHE);
+	if (soc_is_ar933x())
+		reg = AR933X_RESET_REG_BOOTSTRAP;
+	else if (soc_is_ar934x())
+		reg = AR934X_RESET_REG_BOOTSTRAP;
+	else if (soc_is_qca953x())
+		reg = QCA953X_RESET_REG_BOOTSTRAP;
+	else if (soc_is_qca955x())
+		reg = QCA955X_RESET_REG_BOOTSTRAP;
+	else if (soc_is_qca956x())
+		reg = QCA956X_RESET_REG_BOOTSTRAP;
+	else
+		puts("Bootstrap register not defined for this SOC\n");
+
+	if (reg)
+		return readl(base + reg);
+
+	return 0;
+}
+
+static int eth_init_ar933x(void)
+{
+	void __iomem *rregs = map_physmem(AR71XX_RESET_BASE, AR71XX_RESET_SIZE,
+					  MAP_NOCACHE);
+	void __iomem *pregs = map_physmem(AR71XX_PLL_BASE, AR71XX_PLL_SIZE,
+					  MAP_NOCACHE);
+	void __iomem *gregs = map_physmem(AR933X_GMAC_BASE, AR933X_GMAC_SIZE,
+					  MAP_NOCACHE);
+	const u32 mask = AR933X_RESET_GE0_MAC | AR933X_RESET_GE0_MDIO |
+			 AR933X_RESET_GE1_MAC | AR933X_RESET_GE1_MDIO |
+			 AR933X_RESET_ETH_SWITCH;
+
+	/* Clear MDIO slave EN bit. */
+	clrbits_be32(rregs + AR933X_RESET_REG_BOOTSTRAP, BIT(17));
+	mdelay(10);
+
+	/* Get Atheros S26 PHY out of reset. */
+	clrsetbits_be32(pregs + AR934X_PLL_SWITCH_CLOCK_CONTROL_REG,
+			0x1f, 0x10);
+	mdelay(10);
+
+	setbits_be32(rregs + AR933X_RESET_REG_RESET_MODULE, mask);
+	mdelay(10);
+	clrbits_be32(rregs + AR933X_RESET_REG_RESET_MODULE, mask);
+	mdelay(10);
+
+	/* Configure AR93xx GMAC register. */
+	clrsetbits_be32(gregs + AR933X_GMAC_REG_ETH_CFG,
+			AR933X_ETH_CFG_MII_GE0_MASTER |
+			AR933X_ETH_CFG_MII_GE0_SLAVE,
+			AR933X_ETH_CFG_MII_GE0_SLAVE);
+	return 0;
+}
+
+static int eth_init_ar934x(void)
+{
+	void __iomem *rregs = map_physmem(AR71XX_RESET_BASE, AR71XX_RESET_SIZE,
+					  MAP_NOCACHE);
+	void __iomem *pregs = map_physmem(AR71XX_PLL_BASE, AR71XX_PLL_SIZE,
+					  MAP_NOCACHE);
+	void __iomem *gregs = map_physmem(AR934X_GMAC_BASE, AR934X_GMAC_SIZE,
+					  MAP_NOCACHE);
+	const u32 mask = AR934X_RESET_GE0_MAC | AR934X_RESET_GE0_MDIO |
+			 AR934X_RESET_GE1_MAC | AR934X_RESET_GE1_MDIO |
+			 AR934X_RESET_ETH_SWITCH_ANALOG;
+	u32 reg;
+
+	reg = readl(rregs + AR934X_RESET_REG_BOOTSTRAP);
+	if (reg & AR934X_BOOTSTRAP_REF_CLK_40)
+		writel(0x570, pregs + AR934X_PLL_SWITCH_CLOCK_CONTROL_REG);
+	else
+		writel(0x271, pregs + AR934X_PLL_SWITCH_CLOCK_CONTROL_REG);
+	writel(BIT(26) | BIT(25), pregs + AR934X_PLL_ETH_XMII_CONTROL_REG);
+
+	setbits_be32(rregs + AR934X_RESET_REG_RESET_MODULE, mask);
+	mdelay(1);
+	clrbits_be32(rregs + AR934X_RESET_REG_RESET_MODULE, mask);
+	mdelay(1);
+
+	/* Configure AR934x GMAC register. */
+	writel(AR934X_ETH_CFG_RGMII_GMAC0, gregs + AR934X_GMAC_REG_ETH_CFG);
+	return 0;
+}
+
+int ath79_eth_reset(void)
+{
+	/*
+	 * Un-reset ethernet. DM still doesn't have any notion of reset
+	 * framework, so we do it by hand here.
+	 */
+	if (soc_is_ar933x())
+		return eth_init_ar933x();
+	if (soc_is_ar934x())
+		return eth_init_ar934x();
+
+	return -EINVAL;
+}
+
+static int usb_reset_ar933x(void __iomem *reset_regs)
+{
+	/* Ungate the USB block */
+	setbits_be32(reset_regs + AR933X_RESET_REG_RESET_MODULE,
+		     AR933X_RESET_USBSUS_OVERRIDE);
+	mdelay(1);
+	clrbits_be32(reset_regs + AR933X_RESET_REG_RESET_MODULE,
+		     AR933X_RESET_USB_HOST);
+	mdelay(1);
+	clrbits_be32(reset_regs + AR933X_RESET_REG_RESET_MODULE,
+		     AR933X_RESET_USB_PHY);
+	mdelay(1);
+
+	return 0;
+}
+
+static int usb_reset_ar934x(void __iomem *reset_regs)
+{
+	/* Ungate the USB block */
+	setbits_be32(reset_regs + AR934X_RESET_REG_RESET_MODULE,
+		     AR934X_RESET_USBSUS_OVERRIDE);
+	mdelay(1);
+	clrbits_be32(reset_regs + AR934X_RESET_REG_RESET_MODULE,
+		     AR934X_RESET_USB_PHY);
+	mdelay(1);
+	clrbits_be32(reset_regs + AR934X_RESET_REG_RESET_MODULE,
+		     AR934X_RESET_USB_PHY_ANALOG);
+	mdelay(1);
+	clrbits_be32(reset_regs + AR934X_RESET_REG_RESET_MODULE,
+		     AR934X_RESET_USB_HOST);
+	mdelay(1);
+
+	return 0;
+}
+
+int ath79_usb_reset(void)
+{
+	void __iomem *usbc_regs = map_physmem(AR71XX_USB_CTRL_BASE,
+					      AR71XX_USB_CTRL_SIZE,
+					      MAP_NOCACHE);
+	void __iomem *reset_regs = map_physmem(AR71XX_RESET_BASE,
+					       AR71XX_RESET_SIZE,
+					       MAP_NOCACHE);
+	/*
+	 * Turn on the Buff and Desc swap bits.
+	 * NOTE: This write into an undocumented register in mandatory to
+	 *       get the USB controller operational in BigEndian mode.
+	 */
+	writel(0xf0000, usbc_regs + AR71XX_USB_CTRL_REG_CONFIG);
+
+	if (soc_is_ar933x())
+		return usb_reset_ar933x(reset_regs);
+	if (soc_is_ar934x())
+		return usb_reset_ar934x(reset_regs);
+
+	return -EINVAL;
+}
diff --git a/board/imgtec/malta/lowlevel_init.S b/board/imgtec/malta/lowlevel_init.S
index ae09c27d07ec61d1743e89ceafff94fda82fa2dd..534db1d83245b010a086fc8523741ce2235068cd 100644
--- a/board/imgtec/malta/lowlevel_init.S
+++ b/board/imgtec/malta/lowlevel_init.S
@@ -24,7 +24,6 @@
 
 	.text
 	.set noreorder
-	.set mips32
 
 	.globl	lowlevel_init
 lowlevel_init:
diff --git a/board/qca/ap121/Kconfig b/board/qca/ap121/Kconfig
new file mode 100644
index 0000000000000000000000000000000000000000..f7e768ad586f7a1ccded2e11792ae52ee994a081
--- /dev/null
+++ b/board/qca/ap121/Kconfig
@@ -0,0 +1,12 @@
+if TARGET_AP121
+
+config SYS_VENDOR
+	default "qca"
+
+config SYS_BOARD
+	default "ap121"
+
+config SYS_CONFIG_NAME
+	default "ap121"
+
+endif
diff --git a/board/qca/ap121/MAINTAINERS b/board/qca/ap121/MAINTAINERS
new file mode 100644
index 0000000000000000000000000000000000000000..8b02988d605603f14e804785e0969571f2e591d0
--- /dev/null
+++ b/board/qca/ap121/MAINTAINERS
@@ -0,0 +1,6 @@
+AP121 BOARD
+M:	Wills Wang <wills.wang@live.com>
+S:	Maintained
+F:	board/qca/ap121/
+F:	include/configs/ap121.h
+F:	configs/ap121_defconfig
diff --git a/board/qca/ap121/Makefile b/board/qca/ap121/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..ced5432e86f82500bb7f299f1a747e5a0f33f591
--- /dev/null
+++ b/board/qca/ap121/Makefile
@@ -0,0 +1,5 @@
+#
+# SPDX-License-Identifier:	GPL-2.0+
+#
+
+obj-y	= ap121.o
diff --git a/board/qca/ap121/ap121.c b/board/qca/ap121/ap121.c
new file mode 100644
index 0000000000000000000000000000000000000000..d6c60fea86d9adf26bbad582056133456c79f628
--- /dev/null
+++ b/board/qca/ap121/ap121.c
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2015-2016 Wills Wang <wills.wang@live.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <asm/addrspace.h>
+#include <asm/types.h>
+#include <mach/ar71xx_regs.h>
+#include <mach/ddr.h>
+#include <debug_uart.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#ifdef CONFIG_DEBUG_UART_BOARD_INIT
+void board_debug_uart_init(void)
+{
+	void __iomem *regs;
+	u32 val;
+
+	regs = map_physmem(AR71XX_GPIO_BASE, AR71XX_GPIO_SIZE,
+			   MAP_NOCACHE);
+
+	/*
+	 * GPIO9 as input, GPIO10 as output
+	 */
+	val = readl(regs + AR71XX_GPIO_REG_OE);
+	val &= ~AR933X_GPIO(9);
+	val |= AR933X_GPIO(10);
+	writel(val, regs + AR71XX_GPIO_REG_OE);
+
+	/*
+	 * Enable UART, GPIO9 as UART_SI, GPIO10 as UART_SO
+	 */
+	val = readl(regs + AR71XX_GPIO_REG_FUNC);
+	val |= AR933X_GPIO_FUNC_UART_EN | AR933X_GPIO_FUNC_RES_TRUE;
+	writel(val, regs + AR71XX_GPIO_REG_FUNC);
+}
+#endif
+
+int board_early_init_f(void)
+{
+#ifdef CONFIG_DEBUG_UART
+	debug_uart_init();
+#endif
+	ddr_init();
+	return 0;
+}
diff --git a/board/qca/ap143/Kconfig b/board/qca/ap143/Kconfig
new file mode 100644
index 0000000000000000000000000000000000000000..4cdac0d06d052a9e55a5762c87514799bf28e8ce
--- /dev/null
+++ b/board/qca/ap143/Kconfig
@@ -0,0 +1,12 @@
+if TARGET_AP143
+
+config SYS_VENDOR
+	default "qca"
+
+config SYS_BOARD
+	default "ap143"
+
+config SYS_CONFIG_NAME
+	default "ap143"
+
+endif
diff --git a/board/qca/ap143/MAINTAINERS b/board/qca/ap143/MAINTAINERS
new file mode 100644
index 0000000000000000000000000000000000000000..11cb14fc74ddbae6ab609afe40158595e9313e39
--- /dev/null
+++ b/board/qca/ap143/MAINTAINERS
@@ -0,0 +1,6 @@
+AP143 BOARD
+M:	Wills Wang <wills.wang@live.com>
+S:	Maintained
+F:	board/qca/ap143/
+F:	include/configs/ap143.h
+F:	configs/ap143_defconfig
diff --git a/board/qca/ap143/Makefile b/board/qca/ap143/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..00f78376ec5fbe558ea67714f8bb06c1e4d55ad0
--- /dev/null
+++ b/board/qca/ap143/Makefile
@@ -0,0 +1,5 @@
+#
+# SPDX-License-Identifier:	GPL-2.0+
+#
+
+obj-y	= ap143.o
diff --git a/board/qca/ap143/ap143.c b/board/qca/ap143/ap143.c
new file mode 100644
index 0000000000000000000000000000000000000000..1572472ca3059eb568aa9455de24e69fb2b4895c
--- /dev/null
+++ b/board/qca/ap143/ap143.c
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2015-2016 Wills Wang <wills.wang@live.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <asm/addrspace.h>
+#include <asm/types.h>
+#include <mach/ar71xx_regs.h>
+#include <mach/ddr.h>
+#include <debug_uart.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#ifdef CONFIG_DEBUG_UART_BOARD_INIT
+void board_debug_uart_init(void)
+{
+	void __iomem *regs;
+	u32 val;
+
+	regs = map_physmem(AR71XX_GPIO_BASE, AR71XX_GPIO_SIZE,
+			   MAP_NOCACHE);
+
+	/*
+	 * GPIO9 as input, GPIO10 as output
+	 */
+	val = readl(regs + AR71XX_GPIO_REG_OE);
+	val |= QCA953X_GPIO(9);
+	val &= ~QCA953X_GPIO(10);
+	writel(val, regs + AR71XX_GPIO_REG_OE);
+
+	/*
+	 * Enable GPIO10 as UART0_SOUT
+	 */
+	val = readl(regs + QCA953X_GPIO_REG_OUT_FUNC2);
+	val &= ~QCA953X_GPIO_MUX_MASK(16);
+	val |= QCA953X_GPIO_OUT_MUX_UART0_SOUT << 16;
+	writel(val, regs + QCA953X_GPIO_REG_OUT_FUNC2);
+
+	/*
+	 * Enable GPIO9 as UART0_SIN
+	 */
+	val = readl(regs + QCA953X_GPIO_REG_IN_ENABLE0);
+	val &= ~QCA953X_GPIO_MUX_MASK(8);
+	val |= QCA953X_GPIO_IN_MUX_UART0_SIN << 8;
+	writel(val, regs + QCA953X_GPIO_REG_IN_ENABLE0);
+
+	/*
+	 * Enable GPIO10 output
+	 */
+	val = readl(regs + AR71XX_GPIO_REG_OUT);
+	val |= QCA953X_GPIO(10);
+	writel(val, regs + AR71XX_GPIO_REG_OUT);
+}
+#endif
+
+int board_early_init_f(void)
+{
+#ifdef CONFIG_DEBUG_UART
+	debug_uart_init();
+#endif
+	ddr_init();
+	return 0;
+}
diff --git a/board/tplink/wdr4300/Kconfig b/board/tplink/wdr4300/Kconfig
new file mode 100644
index 0000000000000000000000000000000000000000..902abf560d10a8a4414e0bfbf503bac5e21fd09f
--- /dev/null
+++ b/board/tplink/wdr4300/Kconfig
@@ -0,0 +1,15 @@
+if BOARD_TPLINK_WDR4300
+
+config SYS_VENDOR
+	default "tplink"
+
+config SYS_SOC
+	default "ath79"
+
+config SYS_BOARD
+	default "wdr4300"
+
+config SYS_CONFIG_NAME
+	default "tplink_wdr4300"
+
+endif
diff --git a/board/tplink/wdr4300/MAINTAINERS b/board/tplink/wdr4300/MAINTAINERS
new file mode 100644
index 0000000000000000000000000000000000000000..db239c291a765f24399d04de0e6f44a7f79a3864
--- /dev/null
+++ b/board/tplink/wdr4300/MAINTAINERS
@@ -0,0 +1,6 @@
+TPLINK_WDR4300 BOARD
+M:	Marek Vasut <marex@denx.de>
+S:	Maintained
+F:	board/tplink/wdr4300/
+F:	include/configs/tplink_wdr4300.h
+F:	configs/tplink_wdr4300_defconfig
diff --git a/board/tplink/wdr4300/Makefile b/board/tplink/wdr4300/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..4f0c2966287908d9496d54e364298dcce6240a17
--- /dev/null
+++ b/board/tplink/wdr4300/Makefile
@@ -0,0 +1,5 @@
+#
+# SPDX-License-Identifier:	GPL-2.0+
+#
+
+obj-y	= wdr4300.o
diff --git a/board/tplink/wdr4300/wdr4300.c b/board/tplink/wdr4300/wdr4300.c
new file mode 100644
index 0000000000000000000000000000000000000000..6e070fd55803bea739c006f9e50d3949d789cab6
--- /dev/null
+++ b/board/tplink/wdr4300/wdr4300.c
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2016 Marek Vasut <marex@denx.de>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <asm/addrspace.h>
+#include <asm/types.h>
+#include <mach/ath79.h>
+#include <mach/ar71xx_regs.h>
+#include <mach/ddr.h>
+#include <debug_uart.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#ifdef CONFIG_USB
+static void wdr4300_usb_start(void)
+{
+	void __iomem *gpio_regs = map_physmem(AR71XX_GPIO_BASE,
+					      AR71XX_GPIO_SIZE, MAP_NOCACHE);
+	if (!gpio_regs)
+		return;
+
+	/* Power up the USB HUB. */
+	clrbits_be32(gpio_regs + AR71XX_GPIO_REG_OE, BIT(21) | BIT(22));
+	writel(BIT(21) | BIT(22), gpio_regs + AR71XX_GPIO_REG_SET);
+	mdelay(1);
+
+	ath79_usb_reset();
+}
+#else
+static inline void wdr4300_usb_start(void) {}
+#endif
+
+#ifdef CONFIG_BOARD_EARLY_INIT_F
+int board_early_init_f(void)
+{
+	void __iomem *regs;
+
+	regs = map_physmem(AR71XX_GPIO_BASE, AR71XX_GPIO_SIZE,
+			   MAP_NOCACHE);
+
+	/* Assure JTAG is not disconnected. */
+	writel(0x40, regs + AR934X_GPIO_REG_FUNC);
+
+	/* Configure default GPIO input/output regs. */
+	writel(0x3031b, regs + AR71XX_GPIO_REG_OE);
+	writel(0x0f804, regs + AR71XX_GPIO_REG_OUT);
+
+	/* Configure pin multiplexing. */
+	writel(0x00000000, regs + AR934X_GPIO_REG_OUT_FUNC0);
+	writel(0x0b0a0980, regs + AR934X_GPIO_REG_OUT_FUNC1);
+	writel(0x00180000, regs + AR934X_GPIO_REG_OUT_FUNC2);
+	writel(0x00000000, regs + AR934X_GPIO_REG_OUT_FUNC3);
+	writel(0x0000004d, regs + AR934X_GPIO_REG_OUT_FUNC4);
+	writel(0x00000000, regs + AR934X_GPIO_REG_OUT_FUNC5);
+
+#ifdef CONFIG_DEBUG_UART
+	debug_uart_init();
+#endif
+
+#ifndef CONFIG_SKIP_LOWLEVEL_INIT
+	ar934x_pll_init(560, 480, 240);
+	ar934x_ddr_init(560, 480, 240);
+#endif
+
+	wdr4300_usb_start();
+	ath79_eth_reset();
+
+	return 0;
+}
+#endif
diff --git a/cmd/bdinfo.c b/cmd/bdinfo.c
index 8eda68b4f9972e1be0bb46f1c69f76be893402d6..1c4bed96b5b75fc753cfb89485202cb4fb19f22d 100644
--- a/cmd/bdinfo.c
+++ b/cmd/bdinfo.c
@@ -341,6 +341,8 @@ int do_bdinfo(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 	print_eth(0);
 	printf("ip_addr     = %s\n", getenv("ipaddr"));
 	printf("baudrate    = %u bps\n", gd->baudrate);
+	print_num("relocaddr", gd->relocaddr);
+	print_num("reloc off", gd->reloc_off);
 
 	return 0;
 }
diff --git a/configs/ap121_defconfig b/configs/ap121_defconfig
new file mode 100644
index 0000000000000000000000000000000000000000..7604e2ee16f16c94ceb447adee8696c34055ec0c
--- /dev/null
+++ b/configs/ap121_defconfig
@@ -0,0 +1,47 @@
+CONFIG_MIPS=y
+CONFIG_SYS_MALLOC_F_LEN=0x2000
+CONFIG_DM_SERIAL=y
+CONFIG_DM_SPI=y
+CONFIG_DM_SPI_FLASH=y
+CONFIG_ARCH_ATH79=y
+CONFIG_DEFAULT_DEVICE_TREE="ap121"
+CONFIG_SYS_PROMPT="ap121 # "
+# CONFIG_CMD_BDI is not set
+# CONFIG_CMD_CONSOLE is not set
+# CONFIG_CMD_ELF is not set
+# CONFIG_CMD_IMLS is not set
+# CONFIG_CMD_XIMG is not set
+# CONFIG_CMD_EXPORTENV is not set
+# CONFIG_CMD_IMPORTENV is not set
+# CONFIG_CMD_EDITENV is not set
+# CONFIG_CMD_CRC32 is not set
+# CONFIG_CMD_FLASH is not set
+CONFIG_CMD_SF=y
+CONFIG_CMD_SPI=y
+# CONFIG_CMD_FPGA is not set
+# CONFIG_CMD_NET is not set
+# CONFIG_CMD_NFS is not set
+CONFIG_SPI_FLASH=y
+CONFIG_SPI_FLASH_BAR=y
+CONFIG_SPI_FLASH_ATMEL=y
+CONFIG_SPI_FLASH_EON=y
+CONFIG_SPI_FLASH_GIGADEVICE=y
+CONFIG_SPI_FLASH_MACRONIX=y
+CONFIG_SPI_FLASH_SPANSION=y
+CONFIG_SPI_FLASH_STMICRO=y
+CONFIG_SPI_FLASH_SST=y
+CONFIG_SPI_FLASH_WINBOND=y
+CONFIG_SPI_FLASH_DATAFLASH=y
+CONFIG_SPI_FLASH_MTD=y
+CONFIG_PINCTRL=y
+CONFIG_PINCONF=y
+CONFIG_AR933X_PINCTRL=y
+CONFIG_DEBUG_UART=y
+CONFIG_DEBUG_UART_AR933X=y
+CONFIG_DEBUG_UART_BASE=0xb8020000
+CONFIG_DEBUG_UART_CLOCK=25000000
+CONFIG_DEBUG_UART_BOARD_INIT=y
+CONFIG_AR933X_UART=y
+CONFIG_ATH79_SPI=y
+CONFIG_USE_PRIVATE_LIBGCC=y
+CONFIG_OF_LIBFDT=y
diff --git a/configs/ap143_defconfig b/configs/ap143_defconfig
new file mode 100644
index 0000000000000000000000000000000000000000..1aa6e5d7abdac2e0fb372c8b5940268ed597c779
--- /dev/null
+++ b/configs/ap143_defconfig
@@ -0,0 +1,47 @@
+CONFIG_MIPS=y
+CONFIG_SYS_MALLOC_F_LEN=0x800
+CONFIG_DM_SERIAL=y
+CONFIG_DM_SPI=y
+CONFIG_DM_SPI_FLASH=y
+CONFIG_ARCH_ATH79=y
+CONFIG_TARGET_AP143=y
+CONFIG_DEFAULT_DEVICE_TREE="ap143"
+CONFIG_SYS_PROMPT="ap143 # "
+# CONFIG_CMD_BDI is not set
+# CONFIG_CMD_CONSOLE is not set
+# CONFIG_CMD_ELF is not set
+# CONFIG_CMD_IMLS is not set
+# CONFIG_CMD_XIMG is not set
+# CONFIG_CMD_EXPORTENV is not set
+# CONFIG_CMD_IMPORTENV is not set
+# CONFIG_CMD_EDITENV is not set
+# CONFIG_CMD_CRC32 is not set
+# CONFIG_CMD_FLASH is not set
+CONFIG_CMD_SF=y
+CONFIG_CMD_SPI=y
+# CONFIG_CMD_FPGA is not set
+# CONFIG_CMD_NET is not set
+# CONFIG_CMD_NFS is not set
+CONFIG_SPI_FLASH=y
+CONFIG_SPI_FLASH_BAR=y
+CONFIG_SPI_FLASH_ATMEL=y
+CONFIG_SPI_FLASH_EON=y
+CONFIG_SPI_FLASH_GIGADEVICE=y
+CONFIG_SPI_FLASH_MACRONIX=y
+CONFIG_SPI_FLASH_SPANSION=y
+CONFIG_SPI_FLASH_STMICRO=y
+CONFIG_SPI_FLASH_SST=y
+CONFIG_SPI_FLASH_WINBOND=y
+CONFIG_SPI_FLASH_DATAFLASH=y
+CONFIG_SPI_FLASH_MTD=y
+CONFIG_PINCTRL=y
+CONFIG_QCA953X_PINCTRL=y
+CONFIG_DEBUG_UART=y
+CONFIG_DEBUG_UART_BASE=0xb8020000
+CONFIG_DEBUG_UART_CLOCK=25000000
+CONFIG_DEBUG_UART_SHIFT=2
+CONFIG_DEBUG_UART_BOARD_INIT=y
+CONFIG_SYS_NS16550=y
+CONFIG_ATH79_SPI=y
+CONFIG_USE_PRIVATE_LIBGCC=y
+CONFIG_OF_LIBFDT=y
diff --git a/configs/tplink_wdr4300_defconfig b/configs/tplink_wdr4300_defconfig
new file mode 100644
index 0000000000000000000000000000000000000000..b1af2f6f35f236906d902943eb2fb658e8132479
--- /dev/null
+++ b/configs/tplink_wdr4300_defconfig
@@ -0,0 +1,43 @@
+CONFIG_MIPS=y
+CONFIG_ARCH_ATH79=y
+CONFIG_BOARD_TPLINK_WDR4300=y
+CONFIG_SYS_MALLOC_F_LEN=0x2000
+CONFIG_SYS_NS16550=y
+CONFIG_DM_SERIAL=y
+CONFIG_DEFAULT_DEVICE_TREE="tplink_wdr4300"
+# CONFIG_CMD_ELF is not set
+# CONFIG_CMD_IMLS is not set
+# CONFIG_CMD_XIMG is not set
+# CONFIG_CMD_FLASH is not set
+# CONFIG_CMD_FPGA is not set
+CONFIG_CMD_NET=y
+CONFIG_CMD_NFS=y
+CONFIG_CMD_DHCP=y
+CONFIG_CMD_PING=y
+CONFIG_NET_RANDOM_ETHADDR=y
+CONFIG_DM_ETH=y
+CONFIG_AG7XXX=y
+CONFIG_CLK=y
+CONFIG_CMD_USB=y
+CONFIG_USB=y
+CONFIG_DM_USB=y
+CONFIG_USB_EHCI_HCD=y
+CONFIG_USB_EHCI_GENERIC=y
+CONFIG_USB_STORAGE=y
+CONFIG_ATH79_SPI=y
+CONFIG_DM_SPI=y
+CONFIG_DM_SPI_FLASH=y
+CONFIG_CMD_SF=y
+CONFIG_CMD_SPI=y
+CONFIG_SPI_FLASH=y
+CONFIG_SPI_FLASH_ATMEL=y
+CONFIG_SPI_FLASH_EON=y
+CONFIG_SPI_FLASH_GIGADEVICE=y
+CONFIG_SPI_FLASH_MACRONIX=y
+CONFIG_SPI_FLASH_SPANSION=y
+CONFIG_SPI_FLASH_STMICRO=y
+CONFIG_SPI_FLASH_SST=y
+CONFIG_SPI_FLASH_WINBOND=y
+CONFIG_SPI_FLASH_DATAFLASH=y
+CONFIG_SPI_FLASH_MTD=y
+CONFIG_PINCTRL=y
diff --git a/doc/device-tree-bindings/serial/qca,ar9330-uart.txt b/doc/device-tree-bindings/serial/qca,ar9330-uart.txt
new file mode 100644
index 0000000000000000000000000000000000000000..ec576a1ce97b8fe8fa362ecb4892dc7a461ea617
--- /dev/null
+++ b/doc/device-tree-bindings/serial/qca,ar9330-uart.txt
@@ -0,0 +1,24 @@
+* Qualcomm Atheros AR9330 High-Speed UART
+
+Required properties:
+
+- compatible: Must be "qca,ar9330-uart"
+
+- reg: Specifies the physical base address of the controller and
+  the length of the memory mapped region.
+
+Additional requirements:
+
+  Each UART port must have an alias correctly numbered in "aliases"
+  node.
+
+Example:
+
+	aliases {
+		serial0 = &uart0;
+	};
+
+	uart0: uart@18020000 {
+		compatible = "qca,ar9330-uart";
+		reg = <0x18020000 0x14>;
+	};
diff --git a/doc/device-tree-bindings/spi/spi-ath79.txt b/doc/device-tree-bindings/spi/spi-ath79.txt
new file mode 100644
index 0000000000000000000000000000000000000000..3fd9d67a2b28194633647f97da5b29d37a56be7d
--- /dev/null
+++ b/doc/device-tree-bindings/spi/spi-ath79.txt
@@ -0,0 +1,19 @@
+Binding for Qualcomm Atheros AR7xxx/AR9xxx SPI controller
+
+Required properties:
+- compatible: has to be "qca,<soc-type>-spi", "qca,ar7100-spi" as fallback.
+- reg: Base address and size of the controllers memory area
+- #address-cells: <1>, as required by generic SPI binding.
+- #size-cells: <0>, also as required by generic SPI binding.
+
+Child nodes as per the generic SPI binding.
+
+Example:
+
+	spi@1f000000 {
+		compatible = "qca,ar9132-spi", "qca,ar7100-spi";
+		reg = <0x1f000000 0x10>;
+
+		#address-cells = <1>;
+		#size-cells = <0>;
+	};
diff --git a/drivers/mtd/Kconfig b/drivers/mtd/Kconfig
index c58841e7d87dcc495a3369972ff99c12db1091c5..390e9e4ea3f64fa953f68751ea8f1a8c1b073bcd 100644
--- a/drivers/mtd/Kconfig
+++ b/drivers/mtd/Kconfig
@@ -28,6 +28,13 @@ config ALTERA_QSPI
 	  NOR flash to parallel flash interface. Please find details on the
 	  "Embedded Peripherals IP User Guide" of Altera.
 
+config FLASH_PIC32
+	bool "Microchip PIC32 Flash driver"
+	depends on MACH_PIC32 && MTD
+	help
+	  This enables access to Microchip PIC32 internal non-CFI flash
+	  chips through PIC32 Non-Volatile-Memory Controller.
+
 endmenu
 
 source "drivers/mtd/nand/Kconfig"
diff --git a/drivers/mtd/Makefile b/drivers/mtd/Makefile
index 703700aae0b4ff391f67254e74558309d57e8fd9..bd680a784f53d2348d89a1ef582c8554c4dc6de1 100644
--- a/drivers/mtd/Makefile
+++ b/drivers/mtd/Makefile
@@ -19,5 +19,6 @@ obj-$(CONFIG_HAS_DATAFLASH) += dataflash.o
 obj-$(CONFIG_FTSMC020) += ftsmc020.o
 obj-$(CONFIG_FLASH_CFI_LEGACY) += jedec_flash.o
 obj-$(CONFIG_MW_EEPROM) += mw_eeprom.o
+obj-$(CONFIG_FLASH_PIC32) += pic32_flash.o
 obj-$(CONFIG_ST_SMI) += st_smi.o
 obj-$(CONFIG_STM32_FLASH) += stm32_flash.o
diff --git a/drivers/mtd/pic32_flash.c b/drivers/mtd/pic32_flash.c
new file mode 100644
index 0000000000000000000000000000000000000000..9166fcd9803f75a0376896632c4400f833c17b5f
--- /dev/null
+++ b/drivers/mtd/pic32_flash.c
@@ -0,0 +1,444 @@
+/*
+ * Copyright (C) 2015
+ * Cristian Birsan <cristian.birsan@microchip.com>
+ * Purna Chandra Mandal <purna.mandal@microchip.com>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <fdt_support.h>
+#include <flash.h>
+#include <mach/pic32.h>
+#include <wait_bit.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/* NVM Controller registers */
+struct pic32_reg_nvm {
+	struct pic32_reg_atomic ctrl;
+	struct pic32_reg_atomic key;
+	struct pic32_reg_atomic addr;
+	struct pic32_reg_atomic data;
+};
+
+/* NVM operations */
+#define NVMOP_NOP		0
+#define NVMOP_WORD_WRITE	1
+#define NVMOP_PAGE_ERASE	4
+
+/* NVM control bits */
+#define NVM_WR			BIT(15)
+#define NVM_WREN		BIT(14)
+#define NVM_WRERR		BIT(13)
+#define NVM_LVDERR		BIT(12)
+
+/* NVM programming unlock register */
+#define LOCK_KEY		0x0
+#define UNLOCK_KEY1		0xaa996655
+#define UNLOCK_KEY2		0x556699aa
+
+/*
+ * PIC32 flash banks consist of number of pages, each page
+ * into number of rows and rows into number of words.
+ * Here we will maintain page information instead of sector.
+ */
+flash_info_t flash_info[CONFIG_SYS_MAX_FLASH_BANKS];
+static struct pic32_reg_nvm *nvm_regs_p;
+
+static inline void flash_initiate_operation(u32 nvmop)
+{
+	/* set operation */
+	writel(nvmop, &nvm_regs_p->ctrl.raw);
+
+	/* enable flash write */
+	writel(NVM_WREN, &nvm_regs_p->ctrl.set);
+
+	/* unlock sequence */
+	writel(LOCK_KEY, &nvm_regs_p->key.raw);
+	writel(UNLOCK_KEY1, &nvm_regs_p->key.raw);
+	writel(UNLOCK_KEY2, &nvm_regs_p->key.raw);
+
+	/* initiate operation */
+	writel(NVM_WR, &nvm_regs_p->ctrl.set);
+}
+
+static int flash_wait_till_busy(const char *func, ulong timeout)
+{
+	int ret = wait_for_bit(__func__, &nvm_regs_p->ctrl.raw,
+			       NVM_WR, false, timeout, false);
+
+	return ret ? ERR_TIMOUT : ERR_OK;
+}
+
+static inline int flash_complete_operation(void)
+{
+	u32 tmp;
+
+	tmp = readl(&nvm_regs_p->ctrl.raw);
+	if (tmp & NVM_WRERR) {
+		printf("Error in Block Erase - Lock Bit may be set!\n");
+		flash_initiate_operation(NVMOP_NOP);
+		return ERR_PROTECTED;
+	}
+
+	if (tmp & NVM_LVDERR) {
+		printf("Error in Block Erase - low-vol detected!\n");
+		flash_initiate_operation(NVMOP_NOP);
+		return ERR_NOT_ERASED;
+	}
+
+	/* disable flash write or erase operation */
+	writel(NVM_WREN, &nvm_regs_p->ctrl.clr);
+
+	return ERR_OK;
+}
+
+/*
+ * Erase flash sectors, returns:
+ * ERR_OK - OK
+ * ERR_INVAL - invalid sector arguments
+ * ERR_TIMOUT - write timeout
+ * ERR_NOT_ERASED - Flash not erased
+ * ERR_UNKNOWN_FLASH_VENDOR - incorrect flash
+ */
+int flash_erase(flash_info_t *info, int s_first, int s_last)
+{
+	ulong sect_start, sect_end, flags;
+	int prot, sect;
+	int rc;
+
+	if ((info->flash_id & FLASH_VENDMASK) != FLASH_MAN_MCHP) {
+		printf("Can't erase unknown flash type %08lx - aborted\n",
+		       info->flash_id);
+		return ERR_UNKNOWN_FLASH_VENDOR;
+	}
+
+	if ((s_first < 0) || (s_first > s_last)) {
+		printf("- no sectors to erase\n");
+		return ERR_INVAL;
+	}
+
+	prot = 0;
+	for (sect = s_first; sect <= s_last; ++sect) {
+		if (info->protect[sect])
+			prot++;
+	}
+
+	if (prot)
+		printf("- Warning: %d protected sectors will not be erased!\n",
+		       prot);
+	else
+		printf("\n");
+
+	/* erase on unprotected sectors */
+	for (sect = s_first; sect <= s_last; sect++) {
+		if (info->protect[sect])
+			continue;
+
+		/* disable interrupts */
+		flags = disable_interrupts();
+
+		/* write destination page address (physical) */
+		sect_start = CPHYSADDR(info->start[sect]);
+		writel(sect_start, &nvm_regs_p->addr.raw);
+
+		/* page erase */
+		flash_initiate_operation(NVMOP_PAGE_ERASE);
+
+		/* wait */
+		rc = flash_wait_till_busy(__func__,
+					  CONFIG_SYS_FLASH_ERASE_TOUT);
+
+		/* re-enable interrupts if necessary */
+		if (flags)
+			enable_interrupts();
+
+		if (rc != ERR_OK)
+			return rc;
+
+		rc = flash_complete_operation();
+		if (rc != ERR_OK)
+			return rc;
+
+		/*
+		 * flash content is updated but cache might contain stale
+		 * data, so invalidate dcache.
+		 */
+		sect_end = info->start[sect] + info->size / info->sector_count;
+		invalidate_dcache_range(info->start[sect], sect_end);
+	}
+
+	printf(" done\n");
+	return ERR_OK;
+}
+
+int page_erase(flash_info_t *info, int sect)
+{
+	return 0;
+}
+
+/* Write a word to flash */
+static int write_word(flash_info_t *info, ulong dest, ulong word)
+{
+	ulong flags;
+	int rc;
+
+	/* read flash to check if it is sufficiently erased */
+	if ((readl((void __iomem *)dest) & word) != word) {
+		printf("Error, Flash not erased!\n");
+		return ERR_NOT_ERASED;
+	}
+
+	/* disable interrupts */
+	flags = disable_interrupts();
+
+	/* update destination page address (physical) */
+	writel(CPHYSADDR(dest), &nvm_regs_p->addr.raw);
+	writel(word, &nvm_regs_p->data.raw);
+
+	/* word write */
+	flash_initiate_operation(NVMOP_WORD_WRITE);
+
+	/* wait for operation to complete */
+	rc = flash_wait_till_busy(__func__, CONFIG_SYS_FLASH_WRITE_TOUT);
+
+	/* re-enable interrupts if necessary */
+	if (flags)
+		enable_interrupts();
+
+	if (rc != ERR_OK)
+		return rc;
+
+	return flash_complete_operation();
+}
+
+/*
+ * Copy memory to flash, returns:
+ * ERR_OK - OK
+ * ERR_TIMOUT - write timeout
+ * ERR_NOT_ERASED - Flash not erased
+ */
+int write_buff(flash_info_t *info, uchar *src, ulong addr, ulong cnt)
+{
+	ulong dst, tmp_le, len = cnt;
+	int i, l, rc;
+	uchar *cp;
+
+	/* get lower word aligned address */
+	dst = (addr & ~3);
+
+	/* handle unaligned start bytes */
+	l = addr - dst;
+	if (l != 0) {
+		tmp_le = 0;
+		for (i = 0, cp = (uchar *)dst; i < l; ++i, ++cp)
+			tmp_le |= *cp << (i * 8);
+
+		for (; (i < 4) && (cnt > 0); ++i, ++src, --cnt, ++cp)
+			tmp_le |= *src << (i * 8);
+
+		for (; (cnt == 0) && (i < 4); ++i, ++cp)
+			tmp_le |= *cp << (i * 8);
+
+		rc = write_word(info, dst, tmp_le);
+		if (rc)
+			goto out;
+
+		dst += 4;
+	}
+
+	/* handle word aligned part */
+	while (cnt >= 4) {
+		tmp_le = src[0] | src[1] << 8 | src[2] << 16 | src[3] << 24;
+		rc = write_word(info, dst, tmp_le);
+		if (rc)
+			goto out;
+		src += 4;
+		dst += 4;
+		cnt -= 4;
+	}
+
+	if (cnt == 0) {
+		rc = ERR_OK;
+		goto out;
+	}
+
+	/* handle unaligned tail bytes */
+	tmp_le = 0;
+	for (i = 0, cp = (uchar *)dst; (i < 4) && (cnt > 0); ++i, ++cp) {
+		tmp_le |= *src++ << (i * 8);
+		--cnt;
+	}
+
+	for (; i < 4; ++i, ++cp)
+		tmp_le |= *cp << (i * 8);
+
+	rc = write_word(info, dst, tmp_le);
+out:
+	/*
+	 * flash content updated by nvm controller but CPU cache might
+	 * have stale data, so invalidate dcache.
+	 */
+	invalidate_dcache_range(addr, addr + len);
+
+	printf(" done\n");
+	return rc;
+}
+
+void flash_print_info(flash_info_t *info)
+{
+	int i;
+
+	if (info->flash_id == FLASH_UNKNOWN) {
+		printf("missing or unknown FLASH type\n");
+		return;
+	}
+
+	switch (info->flash_id & FLASH_VENDMASK) {
+	case FLASH_MAN_MCHP:
+		printf("Microchip Technology ");
+		break;
+	default:
+		printf("Unknown Vendor ");
+		break;
+	}
+
+	switch (info->flash_id & FLASH_TYPEMASK) {
+	case FLASH_MCHP100T:
+		printf("Internal (8 Mbit, 64 x 16k)\n");
+		break;
+	default:
+		printf("Unknown Chip Type\n");
+		break;
+	}
+
+	printf("  Size: %ld MB in %d Sectors\n",
+	       info->size >> 20, info->sector_count);
+
+	printf("  Sector Start Addresses:");
+	for (i = 0; i < info->sector_count; ++i) {
+		if ((i % 5) == 0)
+			printf("\n   ");
+
+		printf(" %08lX%s", info->start[i],
+		       info->protect[i] ? " (RO)" : "     ");
+	}
+	printf("\n");
+}
+
+unsigned long flash_init(void)
+{
+	unsigned long size = 0;
+	struct udevice *dev;
+	int bank;
+
+	/* probe every MTD device */
+	for (uclass_first_device(UCLASS_MTD, &dev); dev;
+	     uclass_next_device(&dev)) {
+		/* nop */
+	}
+
+	/* calc total flash size */
+	for (bank = 0; bank < CONFIG_SYS_MAX_FLASH_BANKS; ++bank)
+		size += flash_info[bank].size;
+
+	return size;
+}
+
+static void pic32_flash_bank_init(flash_info_t *info,
+				  ulong base, ulong size)
+{
+	ulong sect_size;
+	int sect;
+
+	/* device & manufacturer code */
+	info->flash_id = FLASH_MAN_MCHP | FLASH_MCHP100T;
+	info->sector_count = CONFIG_SYS_MAX_FLASH_SECT;
+	info->size = size;
+
+	/* update sector (i.e page) info */
+	sect_size = info->size / info->sector_count;
+	for (sect = 0; sect < info->sector_count; sect++) {
+		info->start[sect] = base;
+		/* protect each sector by default */
+		info->protect[sect] = 1;
+		base += sect_size;
+	}
+}
+
+static int pic32_flash_probe(struct udevice *dev)
+{
+	void *blob = (void *)gd->fdt_blob;
+	int node = dev->of_offset;
+	const char *list, *end;
+	const fdt32_t *cell;
+	unsigned long addr, size;
+	int parent, addrc, sizec;
+	flash_info_t *info;
+	int len, idx;
+
+	/*
+	 * decode regs. there are multiple reg tuples, and they need to
+	 * match with reg-names.
+	 */
+	parent = fdt_parent_offset(blob, node);
+	of_bus_default_count_cells(blob, parent, &addrc, &sizec);
+	list = fdt_getprop(blob, node, "reg-names", &len);
+	if (!list)
+		return -ENOENT;
+
+	end = list + len;
+	cell = fdt_getprop(blob, node, "reg", &len);
+	if (!cell)
+		return -ENOENT;
+
+	for (idx = 0, info = &flash_info[0]; list < end;) {
+		addr = fdt_translate_address((void *)blob, node, cell + idx);
+		size = fdt_addr_to_cpu(cell[idx + addrc]);
+		len = strlen(list);
+		if (!strncmp(list, "nvm", len)) {
+			/* NVM controller */
+			nvm_regs_p = ioremap(addr, size);
+		} else if (!strncmp(list, "bank", 4)) {
+			/* Flash bank: use kseg0 cached address */
+			pic32_flash_bank_init(info, CKSEG0ADDR(addr), size);
+			info++;
+		}
+		idx += addrc + sizec;
+		list += len + 1;
+	}
+
+	/* disable flash write/erase operations */
+	writel(NVM_WREN, &nvm_regs_p->ctrl.clr);
+
+#if (CONFIG_SYS_MONITOR_BASE >= CONFIG_SYS_FLASH_BASE)
+	/* monitor protection ON by default */
+	flash_protect(FLAG_PROTECT_SET,
+		      CONFIG_SYS_MONITOR_BASE,
+		      CONFIG_SYS_MONITOR_BASE + monitor_flash_len - 1,
+		      &flash_info[0]);
+#endif
+
+#ifdef CONFIG_ENV_IS_IN_FLASH
+	/* ENV protection ON by default */
+	flash_protect(FLAG_PROTECT_SET,
+		      CONFIG_ENV_ADDR,
+		      CONFIG_ENV_ADDR + CONFIG_ENV_SECT_SIZE - 1,
+		      &flash_info[0]);
+#endif
+	return 0;
+}
+
+static const struct udevice_id pic32_flash_ids[] = {
+	{ .compatible = "microchip,pic32mzda-flash" },
+	{}
+};
+
+U_BOOT_DRIVER(pic32_flash) = {
+	.name	= "pic32_flash",
+	.id	= UCLASS_MTD,
+	.of_match = pic32_flash_ids,
+	.probe	= pic32_flash_probe,
+};
diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig
index 2a69babec441966da37b0874fd014516a1fe8518..567b7662d00d915e309fb029316ba52a60aa8271 100644
--- a/drivers/pinctrl/Kconfig
+++ b/drivers/pinctrl/Kconfig
@@ -105,6 +105,24 @@ config SPL_PINCONF
 
 if PINCTRL || SPL_PINCTRL
 
+config AR933X_PINCTRL
+	bool "QCA/Athores ar933x pin control driver"
+	depends on DM && SOC_AR933X
+	help
+	  Support pin multiplexing control on QCA/Athores ar933x SoCs.
+	  The driver is controlled by a device tree node which contains
+	  both the GPIO definitions and pin control functions for each
+	  available multiplex function.
+
+config QCA953X_PINCTRL
+	bool "QCA/Athores qca953x pin control driver"
+	depends on DM && SOC_QCA953X
+	help
+	  Support pin multiplexing control on QCA/Athores qca953x SoCs.
+	  The driver is controlled by a device tree node which contains
+	  both the GPIO definitions and pin control functions for each
+	  available multiplex function.
+
 config ROCKCHIP_PINCTRL
 	bool "Rockchip pin control driver"
 	depends on DM
diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile
index 37dc904640e417bc92a5ec0ba043ad49ca862c90..b99ed2f1916f338baafdc7abd252f22bcd52b976 100644
--- a/drivers/pinctrl/Makefile
+++ b/drivers/pinctrl/Makefile
@@ -6,6 +6,7 @@ obj-y					+= pinctrl-uclass.o
 obj-$(CONFIG_$(SPL_)PINCTRL_GENERIC)	+= pinctrl-generic.o
 
 obj-y					+= nxp/
+obj-$(CONFIG_ARCH_ATH79) += ath79/
 obj-$(CONFIG_ARCH_ROCKCHIP) += rockchip/
 obj-$(CONFIG_PINCTRL_SANDBOX)	+= pinctrl-sandbox.o
 
diff --git a/drivers/pinctrl/ath79/Makefile b/drivers/pinctrl/ath79/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..dcea10ace6a724a0a04c676a4c4d3f0c63c3eca6
--- /dev/null
+++ b/drivers/pinctrl/ath79/Makefile
@@ -0,0 +1,6 @@
+#
+# SPDX-License-Identifier:	GPL-2.0+
+#
+
+obj-$(CONFIG_AR933X_PINCTRL) += pinctrl_ar933x.o
+obj-$(CONFIG_QCA953x_PINCTRL) += pinctrl_qca953x.o
diff --git a/drivers/pinctrl/ath79/pinctrl_ar933x.c b/drivers/pinctrl/ath79/pinctrl_ar933x.c
new file mode 100644
index 0000000000000000000000000000000000000000..e3f64b63553cd6aaba741edd062b0f6ff8a668b8
--- /dev/null
+++ b/drivers/pinctrl/ath79/pinctrl_ar933x.c
@@ -0,0 +1,136 @@
+/*
+ * Copyright (C) 2015-2016 Wills Wang <wills.wang@live.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <asm/io.h>
+#include <dm/pinctrl.h>
+#include <mach/ar71xx_regs.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+enum periph_id {
+	PERIPH_ID_UART0,
+	PERIPH_ID_SPI0,
+	PERIPH_ID_NONE = -1,
+};
+
+struct ar933x_pinctrl_priv {
+	void __iomem *regs;
+};
+
+static void pinctrl_ar933x_spi_config(struct ar933x_pinctrl_priv *priv, int cs)
+{
+	switch (cs) {
+	case 0:
+		clrsetbits_be32(priv->regs + AR71XX_GPIO_REG_OE,
+				AR933X_GPIO(4), AR933X_GPIO(3) |
+				AR933X_GPIO(5) | AR933X_GPIO(2));
+		setbits_be32(priv->regs + AR71XX_GPIO_REG_FUNC,
+			     AR933X_GPIO_FUNC_SPI_EN |
+			     AR933X_GPIO_FUNC_RES_TRUE);
+		break;
+	}
+}
+
+static void pinctrl_ar933x_uart_config(struct ar933x_pinctrl_priv *priv, int uart_id)
+{
+	switch (uart_id) {
+	case PERIPH_ID_UART0:
+		clrsetbits_be32(priv->regs + AR71XX_GPIO_REG_OE,
+				AR933X_GPIO(9), AR933X_GPIO(10));
+		setbits_be32(priv->regs + AR71XX_GPIO_REG_FUNC,
+			     AR933X_GPIO_FUNC_UART_EN |
+			     AR933X_GPIO_FUNC_RES_TRUE);
+		break;
+	}
+}
+
+static int ar933x_pinctrl_request(struct udevice *dev, int func, int flags)
+{
+	struct ar933x_pinctrl_priv *priv = dev_get_priv(dev);
+
+	debug("%s: func=%x, flags=%x\n", __func__, func, flags);
+	switch (func) {
+	case PERIPH_ID_SPI0:
+		pinctrl_ar933x_spi_config(priv, flags);
+		break;
+	case PERIPH_ID_UART0:
+		pinctrl_ar933x_uart_config(priv, func);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int ar933x_pinctrl_get_periph_id(struct udevice *dev,
+					struct udevice *periph)
+{
+	u32 cell[2];
+	int ret;
+
+	ret = fdtdec_get_int_array(gd->fdt_blob, periph->of_offset,
+				   "interrupts", cell, ARRAY_SIZE(cell));
+	if (ret < 0)
+		return -EINVAL;
+
+	switch (cell[0]) {
+	case 128:
+		return PERIPH_ID_UART0;
+	case 129:
+		return PERIPH_ID_SPI0;
+	}
+	return -ENOENT;
+}
+
+static int ar933x_pinctrl_set_state_simple(struct udevice *dev,
+					   struct udevice *periph)
+{
+	int func;
+
+	func = ar933x_pinctrl_get_periph_id(dev, periph);
+	if (func < 0)
+		return func;
+	return ar933x_pinctrl_request(dev, func, 0);
+}
+
+static struct pinctrl_ops ar933x_pinctrl_ops = {
+	.set_state_simple	= ar933x_pinctrl_set_state_simple,
+	.request	= ar933x_pinctrl_request,
+	.get_periph_id	= ar933x_pinctrl_get_periph_id,
+};
+
+static int ar933x_pinctrl_probe(struct udevice *dev)
+{
+	struct ar933x_pinctrl_priv *priv = dev_get_priv(dev);
+	fdt_addr_t addr;
+
+	addr = dev_get_addr(dev);
+	if (addr == FDT_ADDR_T_NONE)
+		return -EINVAL;
+
+	priv->regs = map_physmem(addr,
+				 AR71XX_GPIO_SIZE,
+				 MAP_NOCACHE);
+	return 0;
+}
+
+static const struct udevice_id ar933x_pinctrl_ids[] = {
+	{ .compatible = "qca,ar933x-pinctrl" },
+	{ }
+};
+
+U_BOOT_DRIVER(pinctrl_ar933x) = {
+	.name		= "pinctrl_ar933x",
+	.id		= UCLASS_PINCTRL,
+	.of_match	= ar933x_pinctrl_ids,
+	.priv_auto_alloc_size = sizeof(struct ar933x_pinctrl_priv),
+	.ops		= &ar933x_pinctrl_ops,
+	.probe		= ar933x_pinctrl_probe,
+};
diff --git a/drivers/pinctrl/ath79/pinctrl_qca953x.c b/drivers/pinctrl/ath79/pinctrl_qca953x.c
new file mode 100644
index 0000000000000000000000000000000000000000..d02597e968aca76fd1edc5b1482e1030cad48ab9
--- /dev/null
+++ b/drivers/pinctrl/ath79/pinctrl_qca953x.c
@@ -0,0 +1,156 @@
+/*
+ * Copyright (C) 2015-2016 Wills Wang <wills.wang@live.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <asm/io.h>
+#include <dm/pinctrl.h>
+#include <mach/ar71xx_regs.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+enum periph_id {
+	PERIPH_ID_UART0,
+	PERIPH_ID_SPI0,
+	PERIPH_ID_NONE = -1,
+};
+
+struct qca953x_pinctrl_priv {
+	void __iomem *regs;
+};
+
+static void pinctrl_qca953x_spi_config(struct qca953x_pinctrl_priv *priv, int cs)
+{
+	switch (cs) {
+	case 0:
+		clrsetbits_be32(priv->regs + AR71XX_GPIO_REG_OE,
+				QCA953X_GPIO(5) | QCA953X_GPIO(6) |
+				QCA953X_GPIO(7), QCA953X_GPIO(8));
+
+		clrsetbits_be32(priv->regs + QCA953X_GPIO_REG_OUT_FUNC1,
+				QCA953X_GPIO_MUX_MASK(8) |
+				QCA953X_GPIO_MUX_MASK(16) |
+				QCA953X_GPIO_MUX_MASK(24),
+				(QCA953X_GPIO_OUT_MUX_SPI_CS0 << 8) |
+				(QCA953X_GPIO_OUT_MUX_SPI_CLK << 16) |
+				(QCA953X_GPIO_OUT_MUX_SPI_MOSI << 24));
+
+		clrsetbits_be32(priv->regs + QCA953X_GPIO_REG_IN_ENABLE0,
+				QCA953X_GPIO_MUX_MASK(0),
+				QCA953X_GPIO_IN_MUX_SPI_DATA_IN);
+
+		setbits_be32(priv->regs + AR71XX_GPIO_REG_OUT,
+			     QCA953X_GPIO(8));
+		break;
+	}
+}
+
+static void pinctrl_qca953x_uart_config(struct qca953x_pinctrl_priv *priv, int uart_id)
+{
+	switch (uart_id) {
+	case PERIPH_ID_UART0:
+		clrsetbits_be32(priv->regs + AR71XX_GPIO_REG_OE,
+				QCA953X_GPIO(9), QCA953X_GPIO(10));
+
+		clrsetbits_be32(priv->regs + QCA953X_GPIO_REG_OUT_FUNC2,
+				QCA953X_GPIO_MUX_MASK(16),
+				QCA953X_GPIO_OUT_MUX_UART0_SOUT << 16);
+
+		clrsetbits_be32(priv->regs + QCA953X_GPIO_REG_IN_ENABLE0,
+				QCA953X_GPIO_MUX_MASK(8),
+				QCA953X_GPIO_IN_MUX_UART0_SIN << 8);
+
+		setbits_be32(priv->regs + AR71XX_GPIO_REG_OUT,
+			     QCA953X_GPIO(10));
+		break;
+	}
+}
+
+static int qca953x_pinctrl_request(struct udevice *dev, int func, int flags)
+{
+	struct qca953x_pinctrl_priv *priv = dev_get_priv(dev);
+
+	debug("%s: func=%x, flags=%x\n", __func__, func, flags);
+	switch (func) {
+	case PERIPH_ID_SPI0:
+		pinctrl_qca953x_spi_config(priv, flags);
+		break;
+	case PERIPH_ID_UART0:
+		pinctrl_qca953x_uart_config(priv, func);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int qca953x_pinctrl_get_periph_id(struct udevice *dev,
+					struct udevice *periph)
+{
+	u32 cell[2];
+	int ret;
+
+	ret = fdtdec_get_int_array(gd->fdt_blob, periph->of_offset,
+				   "interrupts", cell, ARRAY_SIZE(cell));
+	if (ret < 0)
+		return -EINVAL;
+
+	switch (cell[0]) {
+	case 128:
+		return PERIPH_ID_UART0;
+	case 129:
+		return PERIPH_ID_SPI0;
+	}
+	return -ENOENT;
+}
+
+static int qca953x_pinctrl_set_state_simple(struct udevice *dev,
+					   struct udevice *periph)
+{
+	int func;
+
+	func = qca953x_pinctrl_get_periph_id(dev, periph);
+	if (func < 0)
+		return func;
+	return qca953x_pinctrl_request(dev, func, 0);
+}
+
+static struct pinctrl_ops qca953x_pinctrl_ops = {
+	.set_state_simple	= qca953x_pinctrl_set_state_simple,
+	.request	= qca953x_pinctrl_request,
+	.get_periph_id	= qca953x_pinctrl_get_periph_id,
+};
+
+static int qca953x_pinctrl_probe(struct udevice *dev)
+{
+	struct qca953x_pinctrl_priv *priv = dev_get_priv(dev);
+	fdt_addr_t addr;
+
+	addr = dev_get_addr(dev);
+	if (addr == FDT_ADDR_T_NONE)
+		return -EINVAL;
+
+	priv->regs = map_physmem(addr,
+				 AR71XX_GPIO_SIZE,
+				 MAP_NOCACHE);
+	return 0;
+}
+
+static const struct udevice_id qca953x_pinctrl_ids[] = {
+	{ .compatible = "qca,qca953x-pinctrl" },
+	{ }
+};
+
+U_BOOT_DRIVER(pinctrl_qca953x) = {
+	.name		= "pinctrl_qca953x",
+	.id		= UCLASS_PINCTRL,
+	.of_match	= qca953x_pinctrl_ids,
+	.priv_auto_alloc_size = sizeof(struct qca953x_pinctrl_priv),
+	.ops		= &qca953x_pinctrl_ops,
+	.probe		= qca953x_pinctrl_probe,
+};
diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig
index a9a5d475dd728d6162889a4772519a5c97c757da..2497ae90a09051b2fa055b8e2f5d53c06cca23cb 100644
--- a/drivers/serial/Kconfig
+++ b/drivers/serial/Kconfig
@@ -89,6 +89,15 @@ config DEBUG_UART_ALTERA_UART
 	  You will need to provide parameters to make this work. The driver will
 	  be available until the real driver model serial is running.
 
+config DEBUG_UART_AR933X
+	bool "QCA/Atheros ar933x"
+	depends on AR933X_UART
+	help
+	  Select this to enable a debug UART using the ar933x uart driver.
+	  You will need to provide parameters to make this work. The
+	  driver will be available until the real driver model serial is
+	  running.
+
 config DEBUG_UART_NS16550
 	bool "ns16550"
 	help
@@ -263,6 +272,15 @@ config ALTERA_UART
 	  Select this to enable an UART for Altera devices. Please find
 	  details on the "Embedded Peripherals IP User Guide" of Altera.
 
+config AR933X_UART
+	bool "QCA/Atheros ar933x UART support"
+	depends on DM_SERIAL && SOC_AR933X
+	help
+	  Select this to enable UART support for QCA/Atheros ar933x
+	  devices. This driver uses driver model and requires a device
+	  tree binding to operate, please refer to the document at
+	  doc/device-tree-bindings/serial/qca,ar9330-uart.txt.
+
 config FSL_LPUART
 	bool "Freescale LPUART support"
 	help
diff --git a/drivers/serial/Makefile b/drivers/serial/Makefile
index b0ac9d8a5639ca05a4dcdc54c4cd7a5e8ca2274b..9def128e8908e22fa0624d492ac847c95b33cd2c 100644
--- a/drivers/serial/Makefile
+++ b/drivers/serial/Makefile
@@ -17,6 +17,7 @@ endif
 
 obj-$(CONFIG_ALTERA_UART) += altera_uart.o
 obj-$(CONFIG_ALTERA_JTAG_UART) += altera_jtag_uart.o
+obj-$(CONFIG_AR933X_UART) += serial_ar933x.o
 obj-$(CONFIG_ARM_DCC) += arm_dcc.o
 obj-$(CONFIG_ATMEL_USART) += atmel_usart.o
 obj-$(CONFIG_EFI_APP) += serial_efi.o
diff --git a/drivers/serial/serial_ar933x.c b/drivers/serial/serial_ar933x.c
new file mode 100644
index 0000000000000000000000000000000000000000..aae66dc682b222f120d2d1221af1408465b7a7a2
--- /dev/null
+++ b/drivers/serial/serial_ar933x.c
@@ -0,0 +1,243 @@
+/*
+ * Copyright (C) 2015-2016 Wills Wang <wills.wang@live.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <div64.h>
+#include <errno.h>
+#include <serial.h>
+#include <asm/io.h>
+#include <asm/addrspace.h>
+#include <asm/types.h>
+#include <dm/pinctrl.h>
+#include <mach/ar71xx_regs.h>
+
+#define AR933X_UART_DATA_REG            0x00
+#define AR933X_UART_CS_REG              0x04
+#define AR933X_UART_CLK_REG             0x08
+
+#define AR933X_UART_DATA_TX_RX_MASK     0xff
+#define AR933X_UART_DATA_RX_CSR         BIT(8)
+#define AR933X_UART_DATA_TX_CSR         BIT(9)
+#define AR933X_UART_CS_IF_MODE_S        2
+#define AR933X_UART_CS_IF_MODE_M        0x3
+#define AR933X_UART_CS_IF_MODE_DTE      1
+#define AR933X_UART_CS_IF_MODE_DCE      2
+#define AR933X_UART_CS_TX_RDY_ORIDE     BIT(7)
+#define AR933X_UART_CS_RX_RDY_ORIDE     BIT(8)
+#define AR933X_UART_CLK_STEP_M          0xffff
+#define AR933X_UART_CLK_SCALE_M         0xfff
+#define AR933X_UART_CLK_SCALE_S         16
+#define AR933X_UART_CLK_STEP_S          0
+
+struct ar933x_serial_priv {
+	void __iomem *regs;
+};
+
+/*
+ * Baudrate algorithm come from Linux/drivers/tty/serial/ar933x_uart.c
+ * baudrate = (clk / (scale + 1)) * (step * (1 / 2^17))
+ */
+static u32 ar933x_serial_get_baud(u32 clk, u32 scale, u32 step)
+{
+	u64 t;
+	u32 div;
+
+	div = (2 << 16) * (scale + 1);
+	t = clk;
+	t *= step;
+	t += (div / 2);
+	do_div(t, div);
+
+	return t;
+}
+
+static void ar933x_serial_get_scale_step(u32 clk, u32 baud,
+					 u32 *scale, u32 *step)
+{
+	u32 tscale, baudrate;
+	long min_diff;
+
+	*scale = 0;
+	*step = 0;
+
+	min_diff = baud;
+	for (tscale = 0; tscale < AR933X_UART_CLK_SCALE_M; tscale++) {
+		u64 tstep;
+		int diff;
+
+		tstep = baud * (tscale + 1);
+		tstep *= (2 << 16);
+		do_div(tstep, clk);
+
+		if (tstep > AR933X_UART_CLK_STEP_M)
+			break;
+
+		baudrate = ar933x_serial_get_baud(clk, tscale, tstep);
+		diff = abs(baudrate - baud);
+		if (diff < min_diff) {
+			min_diff = diff;
+			*scale = tscale;
+			*step = tstep;
+		}
+	}
+}
+
+static int ar933x_serial_setbrg(struct udevice *dev, int baudrate)
+{
+	struct ar933x_serial_priv *priv = dev_get_priv(dev);
+	u32 val, scale, step;
+
+	val = get_serial_clock();
+	ar933x_serial_get_scale_step(val, baudrate, &scale, &step);
+
+	val  = (scale & AR933X_UART_CLK_SCALE_M)
+			<< AR933X_UART_CLK_SCALE_S;
+	val |= (step & AR933X_UART_CLK_STEP_M)
+			<< AR933X_UART_CLK_STEP_S;
+	writel(val, priv->regs + AR933X_UART_CLK_REG);
+
+	return 0;
+}
+
+static int ar933x_serial_putc(struct udevice *dev, const char c)
+{
+	struct ar933x_serial_priv *priv = dev_get_priv(dev);
+	u32 data;
+
+	data = readl(priv->regs + AR933X_UART_DATA_REG);
+	if (!(data & AR933X_UART_DATA_TX_CSR))
+		return -EAGAIN;
+
+	data  = (u32)c | AR933X_UART_DATA_TX_CSR;
+	writel(data, priv->regs + AR933X_UART_DATA_REG);
+
+	return 0;
+}
+
+static int ar933x_serial_getc(struct udevice *dev)
+{
+	struct ar933x_serial_priv *priv = dev_get_priv(dev);
+	u32 data;
+
+	data = readl(priv->regs + AR933X_UART_DATA_REG);
+	if (!(data & AR933X_UART_DATA_RX_CSR))
+		return -EAGAIN;
+
+	writel(AR933X_UART_DATA_RX_CSR, priv->regs + AR933X_UART_DATA_REG);
+	return data & AR933X_UART_DATA_TX_RX_MASK;
+}
+
+static int ar933x_serial_pending(struct udevice *dev, bool input)
+{
+	struct ar933x_serial_priv *priv = dev_get_priv(dev);
+	u32 data;
+
+	data = readl(priv->regs + AR933X_UART_DATA_REG);
+	if (input)
+		return (data & AR933X_UART_DATA_RX_CSR) ? 1 : 0;
+	else
+		return (data & AR933X_UART_DATA_TX_CSR) ? 0 : 1;
+}
+
+static int ar933x_serial_probe(struct udevice *dev)
+{
+	struct ar933x_serial_priv *priv = dev_get_priv(dev);
+	fdt_addr_t addr;
+	u32 val;
+
+	addr = dev_get_addr(dev);
+	if (addr == FDT_ADDR_T_NONE)
+		return -EINVAL;
+
+	priv->regs = map_physmem(addr, AR933X_UART_SIZE,
+				 MAP_NOCACHE);
+
+	/*
+	 * UART controller configuration:
+	 * - no DMA
+	 * - no interrupt
+	 * - DCE mode
+	 * - no flow control
+	 * - set RX ready oride
+	 * - set TX ready oride
+	 */
+	val = (AR933X_UART_CS_IF_MODE_DCE << AR933X_UART_CS_IF_MODE_S) |
+	      AR933X_UART_CS_TX_RDY_ORIDE | AR933X_UART_CS_RX_RDY_ORIDE;
+	writel(val, priv->regs + AR933X_UART_CS_REG);
+	return 0;
+}
+
+static const struct dm_serial_ops ar933x_serial_ops = {
+	.putc = ar933x_serial_putc,
+	.pending = ar933x_serial_pending,
+	.getc = ar933x_serial_getc,
+	.setbrg = ar933x_serial_setbrg,
+};
+
+static const struct udevice_id ar933x_serial_ids[] = {
+	{ .compatible = "qca,ar9330-uart" },
+	{ }
+};
+
+U_BOOT_DRIVER(serial_ar933x) = {
+	.name   = "serial_ar933x",
+	.id = UCLASS_SERIAL,
+	.of_match = ar933x_serial_ids,
+	.priv_auto_alloc_size = sizeof(struct ar933x_serial_priv),
+	.probe = ar933x_serial_probe,
+	.ops    = &ar933x_serial_ops,
+	.flags = DM_FLAG_PRE_RELOC,
+};
+
+#ifdef CONFIG_DEBUG_UART_AR933X
+
+#include <debug_uart.h>
+
+static inline void _debug_uart_init(void)
+{
+	void __iomem *regs = (void *)CONFIG_DEBUG_UART_BASE;
+	u32 val, scale, step;
+
+	/*
+	 * UART controller configuration:
+	 * - no DMA
+	 * - no interrupt
+	 * - DCE mode
+	 * - no flow control
+	 * - set RX ready oride
+	 * - set TX ready oride
+	 */
+	val = (AR933X_UART_CS_IF_MODE_DCE << AR933X_UART_CS_IF_MODE_S) |
+	      AR933X_UART_CS_TX_RDY_ORIDE | AR933X_UART_CS_RX_RDY_ORIDE;
+	writel(val, regs + AR933X_UART_CS_REG);
+
+	ar933x_serial_get_scale_step(CONFIG_DEBUG_UART_CLOCK,
+				     CONFIG_BAUDRATE, &scale, &step);
+
+	val  = (scale & AR933X_UART_CLK_SCALE_M)
+			<< AR933X_UART_CLK_SCALE_S;
+	val |= (step & AR933X_UART_CLK_STEP_M)
+			<< AR933X_UART_CLK_STEP_S;
+	writel(val, regs + AR933X_UART_CLK_REG);
+}
+
+static inline void _debug_uart_putc(int c)
+{
+	void __iomem *regs = (void *)CONFIG_DEBUG_UART_BASE;
+	u32 data;
+
+	do {
+		data = readl(regs + AR933X_UART_DATA_REG);
+	} while (!(data & AR933X_UART_DATA_TX_CSR));
+
+	data  = (u32)c | AR933X_UART_DATA_TX_CSR;
+	writel(data, regs + AR933X_UART_DATA_REG);
+}
+
+DEBUG_UART_FUNCS
+
+#endif
diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
index f0258f84afeb64a0ac8c1e7ecbe9ee52fc99c0ea..b7fd8e53a2f62d6cd1f7aefa91f82e89c7fe5aea 100644
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -23,6 +23,15 @@ config ALTERA_SPI
 	  IP core. Please find details on the "Embedded Peripherals IP
 	  User Guide" of Altera.
 
+config ATH79_SPI
+	bool "Atheros SPI driver"
+	depends on ARCH_ATH79
+	help
+	  Enable the Atheros ar7xxx/ar9xxx SoC SPI driver, it was used
+	  to access SPI NOR flash and other SPI peripherals. This driver
+	  uses driver model and requires a device tree binding to operate.
+	  please refer to doc/device-tree-bindings/spi/spi-ath79.txt.
+
 config CADENCE_QSPI
 	bool "Cadence QSPI driver"
 	help
diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
index 3eca7456d6a6bf865726fe27216365f30e6c1327..7fb2926e78135129939dbad3e789a8d8a0d67ed9 100644
--- a/drivers/spi/Makefile
+++ b/drivers/spi/Makefile
@@ -17,6 +17,7 @@ endif
 
 obj-$(CONFIG_ALTERA_SPI) += altera_spi.o
 obj-$(CONFIG_ARMADA100_SPI) += armada100_spi.o
+obj-$(CONFIG_ATH79_SPI) += ath79_spi.o
 obj-$(CONFIG_ATMEL_DATAFLASH_SPI) += atmel_dataflash_spi.o
 obj-$(CONFIG_ATMEL_SPI) += atmel_spi.o
 obj-$(CONFIG_BFIN_SPI) += bfin_spi.o
diff --git a/drivers/spi/ath79_spi.c b/drivers/spi/ath79_spi.c
new file mode 100644
index 0000000000000000000000000000000000000000..b18c733b670f96b6a2263014a2fb2ce81fc4fea0
--- /dev/null
+++ b/drivers/spi/ath79_spi.c
@@ -0,0 +1,228 @@
+/*
+ * Copyright (C) 2015-2016 Wills Wang <wills.wang@live.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <spi.h>
+#include <dm.h>
+#include <div64.h>
+#include <errno.h>
+#include <asm/io.h>
+#include <asm/addrspace.h>
+#include <asm/types.h>
+#include <dm/pinctrl.h>
+#include <mach/ar71xx_regs.h>
+
+/* CLOCK_DIVIDER = 3 (SPI clock = 200 / 8 ~ 25 MHz) */
+#define ATH79_SPI_CLK_DIV(x)           (((x) >> 1) - 1)
+#define ATH79_SPI_RRW_DELAY_FACTOR     12000
+#define ATH79_SPI_MHZ                  (1000 * 1000)
+
+struct ath79_spi_priv {
+	void __iomem *regs;
+	u32 rrw_delay;
+};
+
+static void spi_cs_activate(struct udevice *dev)
+{
+	struct udevice *bus = dev_get_parent(dev);
+	struct ath79_spi_priv *priv = dev_get_priv(bus);
+
+	writel(AR71XX_SPI_FS_GPIO, priv->regs + AR71XX_SPI_REG_FS);
+	writel(AR71XX_SPI_IOC_CS_ALL, priv->regs + AR71XX_SPI_REG_IOC);
+}
+
+static void spi_cs_deactivate(struct udevice *dev)
+{
+	struct udevice *bus = dev_get_parent(dev);
+	struct ath79_spi_priv *priv = dev_get_priv(bus);
+
+	writel(AR71XX_SPI_IOC_CS_ALL, priv->regs + AR71XX_SPI_REG_IOC);
+	writel(0, priv->regs + AR71XX_SPI_REG_FS);
+}
+
+static int ath79_spi_claim_bus(struct udevice *dev)
+{
+	return 0;
+}
+
+static int ath79_spi_release_bus(struct udevice *dev)
+{
+	return 0;
+}
+
+static int ath79_spi_xfer(struct udevice *dev, unsigned int bitlen,
+		const void *dout, void *din, unsigned long flags)
+{
+	struct udevice *bus = dev_get_parent(dev);
+	struct ath79_spi_priv *priv = dev_get_priv(bus);
+	struct dm_spi_slave_platdata *slave = dev_get_parent_platdata(dev);
+	u8 *rx = din;
+	const u8 *tx = dout;
+	u8 curbyte, curbitlen, restbits;
+	u32 bytes = bitlen / 8;
+	u32 out, in;
+	u64 tick;
+
+	if (flags & SPI_XFER_BEGIN)
+		spi_cs_activate(dev);
+
+	restbits = (bitlen % 8);
+	if (restbits)
+		bytes++;
+
+	out = AR71XX_SPI_IOC_CS_ALL & ~(AR71XX_SPI_IOC_CS(slave->cs));
+	while (bytes > 0) {
+		bytes--;
+		curbyte = 0;
+		if (tx)
+			curbyte = *tx++;
+
+		if (restbits && !bytes) {
+			curbitlen = restbits;
+			curbyte <<= 8 - restbits;
+		} else {
+			curbitlen = 8;
+		}
+
+		for (curbyte <<= (8 - curbitlen); curbitlen; curbitlen--) {
+			if (curbyte & 0x80)
+				out |= AR71XX_SPI_IOC_DO;
+			else
+				out &= ~(AR71XX_SPI_IOC_DO);
+
+			writel(out, priv->regs + AR71XX_SPI_REG_IOC);
+
+			/* delay for low level */
+			if (priv->rrw_delay) {
+				tick = get_ticks() + priv->rrw_delay;
+				while (get_ticks() < tick)
+					/*NOP*/;
+			}
+
+			writel(out | AR71XX_SPI_IOC_CLK,
+			       priv->regs + AR71XX_SPI_REG_IOC);
+
+			/* delay for high level */
+			if (priv->rrw_delay) {
+				tick = get_ticks() + priv->rrw_delay;
+				while (get_ticks() < tick)
+					/*NOP*/;
+			}
+
+			curbyte <<= 1;
+		}
+
+		if (!bytes)
+			writel(out, priv->regs + AR71XX_SPI_REG_IOC);
+
+		in = readl(priv->regs + AR71XX_SPI_REG_RDS);
+		if (rx) {
+			if (restbits && !bytes)
+				*rx++ = (in << (8 - restbits));
+			else
+				*rx++ = in;
+		}
+	}
+
+	if (flags & SPI_XFER_END)
+		spi_cs_deactivate(dev);
+
+	return 0;
+}
+
+
+static int ath79_spi_set_speed(struct udevice *bus, uint speed)
+{
+	struct ath79_spi_priv *priv = dev_get_priv(bus);
+	u32 val, div = 0;
+	u64 time;
+
+	if (speed)
+		div = get_bus_freq(0) / speed;
+
+	if (div > 63)
+		div = 63;
+
+	if (div < 5)
+		div = 5;
+
+	/* calculate delay */
+	time = get_tbclk();
+	do_div(time, speed / 2);
+	val = get_bus_freq(0) / ATH79_SPI_MHZ;
+	val = ATH79_SPI_RRW_DELAY_FACTOR / val;
+	if (time > val)
+		priv->rrw_delay = time - val + 1;
+	else
+		priv->rrw_delay = 0;
+
+	writel(AR71XX_SPI_FS_GPIO, priv->regs + AR71XX_SPI_REG_FS);
+	clrsetbits_be32(priv->regs + AR71XX_SPI_REG_CTRL,
+			AR71XX_SPI_CTRL_DIV_MASK,
+			ATH79_SPI_CLK_DIV(div));
+	writel(0, priv->regs + AR71XX_SPI_REG_FS);
+	return 0;
+}
+
+static int ath79_spi_set_mode(struct udevice *bus, uint mode)
+{
+	return 0;
+}
+
+static int ath79_spi_probe(struct udevice *bus)
+{
+	struct ath79_spi_priv *priv = dev_get_priv(bus);
+	fdt_addr_t addr;
+
+	addr = dev_get_addr(bus);
+	if (addr == FDT_ADDR_T_NONE)
+		return -EINVAL;
+
+	priv->regs = map_physmem(addr,
+				 AR71XX_SPI_SIZE,
+				 MAP_NOCACHE);
+
+	/* Init SPI Hardware, disable remap, set clock */
+	writel(AR71XX_SPI_FS_GPIO, priv->regs + AR71XX_SPI_REG_FS);
+	writel(AR71XX_SPI_CTRL_RD | ATH79_SPI_CLK_DIV(8),
+	       priv->regs + AR71XX_SPI_REG_CTRL);
+	writel(0, priv->regs + AR71XX_SPI_REG_FS);
+
+	return 0;
+}
+
+static int ath79_cs_info(struct udevice *bus, uint cs,
+			   struct spi_cs_info *info)
+{
+	/* Always allow activity on CS 0/1/2 */
+	if (cs >= 3)
+		return -ENODEV;
+
+	return 0;
+}
+
+static const struct dm_spi_ops ath79_spi_ops = {
+	.claim_bus  = ath79_spi_claim_bus,
+	.release_bus    = ath79_spi_release_bus,
+	.xfer       = ath79_spi_xfer,
+	.set_speed  = ath79_spi_set_speed,
+	.set_mode   = ath79_spi_set_mode,
+	.cs_info    = ath79_cs_info,
+};
+
+static const struct udevice_id ath79_spi_ids[] = {
+	{ .compatible = "qca,ar7100-spi" },
+	{}
+};
+
+U_BOOT_DRIVER(ath79_spi) = {
+	.name   = "ath79_spi",
+	.id = UCLASS_SPI,
+	.of_match = ath79_spi_ids,
+	.ops    = &ath79_spi_ops,
+	.priv_auto_alloc_size = sizeof(struct ath79_spi_priv),
+	.probe  = ath79_spi_probe,
+};
diff --git a/examples/api/Makefile b/examples/api/Makefile
index 4e9b8ea17dcc6ffd49c34de6ec6a0febd2e36028..6cffee74652f944d9d9bc9ed812b4177432f98af 100644
--- a/examples/api/Makefile
+++ b/examples/api/Makefile
@@ -11,8 +11,12 @@ ifeq ($(ARCH),arm)
 LOAD_ADDR = 0x1000000
 endif
 ifeq ($(ARCH),mips)
+ifdef CONFIG_64BIT
+LOAD_ADDR = 0xffffffff80200000
+else
 LOAD_ADDR = 0x80200000
 endif
+endif
 
 # Resulting ELF and binary exectuables will be named demo and demo.bin
 extra-y = demo
diff --git a/examples/api/crt0.S b/examples/api/crt0.S
index ced2c82e5ffcacb5702cd0a9a841a559cad8d74e..5a7049d6b4b721f71a85948364d24217e93030ec 100644
--- a/examples/api/crt0.S
+++ b/examples/api/crt0.S
@@ -41,28 +41,29 @@ syscall:
 	ldr	pc, [ip]
 
 #elif defined(CONFIG_MIPS)
+#include <asm/asm.h>
 	.text
 	.globl __start
 	.ent __start
 __start:
-	sw	$sp, search_hint
+	PTR_S	$sp, search_hint
 	b	main
 	.end __start
 
 	.globl syscall
 	.ent syscall
 syscall:
-	sw	$ra, return_addr
-	lw	$t9, syscall_ptr
+	PTR_S	$ra, return_addr
+	PTR_L	$t9, syscall_ptr
 	jalr	$t9
 	nop
-	lw	$ra, return_addr
+	PTR_L	$ra, return_addr
 	jr	$ra
 	nop
 	.end syscall
 
 return_addr:
-	.align 4
+	.align 8
 	.long 0
 #else
 #error No support for this arch!
@@ -70,7 +71,7 @@ return_addr:
 
 	.globl syscall_ptr
 syscall_ptr:
-	.align	4
+	.align	8
 	.long	0
 
 	.globl search_hint
diff --git a/examples/api/glue.c b/examples/api/glue.c
index d619518d42a64a19c0ba6ea61e0c0b1c9cd930f6..8aabf32c899acb2e3c8990db52e16f235f68c0a2 100644
--- a/examples/api/glue.c
+++ b/examples/api/glue.c
@@ -77,7 +77,7 @@ int ub_getc(void)
 {
 	int c;
 
-	if (!syscall(API_GETC, NULL, (uint32_t)&c))
+	if (!syscall(API_GETC, NULL, &c))
 		return -1;
 
 	return c;
@@ -87,7 +87,7 @@ int ub_tstc(void)
 {
 	int t;
 
-	if (!syscall(API_TSTC, NULL, (uint32_t)&t))
+	if (!syscall(API_TSTC, NULL, &t))
 		return -1;
 
 	return t;
@@ -95,12 +95,12 @@ int ub_tstc(void)
 
 void ub_putc(char c)
 {
-	syscall(API_PUTC, NULL, (uint32_t)&c);
+	syscall(API_PUTC, NULL, &c);
 }
 
 void ub_puts(const char *s)
 {
-	syscall(API_PUTS, NULL, (uint32_t)s);
+	syscall(API_PUTS, NULL, s);
 }
 
 /****************************************
@@ -126,7 +126,7 @@ struct sys_info * ub_get_sys_info(void)
 	si.mr_no = UB_MAX_MR;
 	memset(&mr, 0, sizeof(mr));
 
-	if (!syscall(API_GET_SYS_INFO, &err, (u_int32_t)&si))
+	if (!syscall(API_GET_SYS_INFO, &err, &si))
 		return NULL;
 
 	return ((err) ? NULL : &si);
@@ -344,7 +344,7 @@ char * ub_env_get(const char *name)
 {
 	char *value;
 
-	if (!syscall(API_ENV_GET, NULL, (uint32_t)name, (uint32_t)&value))
+	if (!syscall(API_ENV_GET, NULL, name, &value))
 		return NULL;
 
 	return value;
@@ -352,7 +352,7 @@ char * ub_env_get(const char *name)
 
 void ub_env_set(const char *name, char *value)
 {
-	syscall(API_ENV_SET, NULL, (uint32_t)name, (uint32_t)value);
+	syscall(API_ENV_SET, NULL, name, value);
 }
 
 static char env_name[256];
@@ -369,7 +369,7 @@ const char * ub_env_enum(const char *last)
 	 * 'name=val' string), since the API_ENUM_ENV call uses envmatch()
 	 * internally, which handles such case
 	 */
-	if (!syscall(API_ENV_ENUM, NULL, (uint32_t)last, (uint32_t)&env))
+	if (!syscall(API_ENV_ENUM, NULL, last, &env))
 		return NULL;
 
 	if (!env)
@@ -396,7 +396,7 @@ int ub_display_get_info(int type, struct display_info *di)
 {
 	int err = 0;
 
-	if (!syscall(API_DISPLAY_GET_INFO, &err, (uint32_t)type, (uint32_t)di))
+	if (!syscall(API_DISPLAY_GET_INFO, &err, type, di))
 		return API_ESYSC;
 
 	return err;
diff --git a/examples/standalone/stubs.c b/examples/standalone/stubs.c
index 920a0a9cf3b4ae96c2ba3aa21394dde4fd50318b..0d62067e03be4cbf97e1cd8c38adf503f9120700 100644
--- a/examples/standalone/stubs.c
+++ b/examples/standalone/stubs.c
@@ -65,6 +65,23 @@ gd_t *global_data;
 	: : "i"(offsetof(gd_t, jt)), "i"(FO(x)) : "ip");
 #endif
 #elif defined(CONFIG_MIPS)
+#ifdef CONFIG_CPU_MIPS64
+/*
+ * k0 ($26) holds the pointer to the global_data; t9 ($25) is a call-
+ * clobbered register that is also used to set gp ($26). Note that the
+ * jr instruction also executes the instruction immediately following
+ * it; however, GCC/mips generates an additional `nop' after each asm
+ * statement
+ */
+#define EXPORT_FUNC(f, a, x, ...) \
+	asm volatile (			\
+"	.globl " #x "\n"		\
+#x ":\n"				\
+"	ld	$25, %0($26)\n"		\
+"	ld	$25, %1($25)\n"		\
+"	jr	$25\n"			\
+        : : "i"(offsetof(gd_t, jt)), "i"(FO(x)) : "t9");
+#else
 /*
  * k0 ($26) holds the pointer to the global_data; t9 ($25) is a call-
  * clobbered register that is also used to set gp ($26). Note that the
@@ -80,6 +97,7 @@ gd_t *global_data;
 "	lw	$25, %1($25)\n"		\
 "	jr	$25\n"			\
 	: : "i"(offsetof(gd_t, jt)), "i"(FO(x)) : "t9");
+#endif
 #elif defined(CONFIG_NIOS2)
 /*
  * gp holds the pointer to the global_data, r8 is call-clobbered
diff --git a/include/ata.h b/include/ata.h
index 9d6f59c97bfaae7ea8482eb03468533465901d9c..dde377c99ec92423093733c24008c1508ddcd915 100644
--- a/include/ata.h
+++ b/include/ata.h
@@ -126,7 +126,7 @@
 
 #define ATA_BLOCKSIZE	512	/* bytes */
 #define ATA_BLOCKSHIFT	9	/* 2 ^ ATA_BLOCKSIZESHIFT = 512 */
-#define ATA_SECTORWORDS	(512 / sizeof(unsigned long))
+#define ATA_SECTORWORDS	(512 / sizeof(uint32_t))
 
 #ifndef ATA_RESET_TIME
 #define ATA_RESET_TIME	60	/* spec allows up to 31 seconds */
diff --git a/include/configs/ap121.h b/include/configs/ap121.h
new file mode 100644
index 0000000000000000000000000000000000000000..2beffa4805b33c34e2c1fb8526bc31424185b306
--- /dev/null
+++ b/include/configs/ap121.h
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2015-2016 Wills Wang <wills.wang@live.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#ifndef __CONFIG_H
+#define __CONFIG_H
+
+#define CONFIG_SYS_TEXT_BASE            0x9f000000
+
+#define CONFIG_DISPLAY_CPUINFO
+#define CONFIG_DISPLAY_BOARDINFO
+#define CONFIG_BOARD_EARLY_INIT_F
+
+#define CONFIG_SYS_HZ                   1000
+#define CONFIG_SYS_MHZ                  200
+#define CONFIG_SYS_MIPS_TIMER_FREQ      (CONFIG_SYS_MHZ * 1000000)
+
+/* Cache Configuration */
+#define CONFIG_SYS_DCACHE_SIZE          0x8000
+#define CONFIG_SYS_ICACHE_SIZE          0x10000
+#define CONFIG_SYS_CACHELINE_SIZE       32
+
+#define CONFIG_SYS_MONITOR_BASE         CONFIG_SYS_TEXT_BASE
+
+#define CONFIG_SYS_MALLOC_LEN           0x40000
+#define CONFIG_SYS_BOOTPARAMS_LEN       0x20000
+
+#define CONFIG_SYS_SDRAM_BASE           0x80000000
+#define CONFIG_SYS_LOAD_ADDR            0x81000000
+
+#define CONFIG_SYS_NO_FLASH
+
+#define CONFIG_SYS_INIT_RAM_ADDR        0xbd000000
+#define CONFIG_SYS_INIT_RAM_SIZE        0x8000
+#define CONFIG_SYS_INIT_SP_ADDR \
+	(CONFIG_SYS_INIT_RAM_ADDR + CONFIG_SYS_INIT_RAM_SIZE - 1)
+
+#define CONFIG_BAUDRATE                 115200
+#define CONFIG_SYS_BAUDRATE_TABLE \
+	{9600, 19200, 38400, 57600, 115200}
+
+#define CONFIG_BOOTDELAY                3
+#define CONFIG_BOOTARGS                 "console=ttyS0,115200 " \
+					"root=/dev/mtdblock2 " \
+					"rootfstype=squashfs"
+#define CONFIG_BOOTCOMMAND              "sf probe;" \
+					"mtdparts default;" \
+					"bootm 0x9f300000"
+#define CONFIG_LZMA
+
+#define MTDIDS_DEFAULT                  "nor0=spi-flash.0"
+#define MTDPARTS_DEFAULT                "mtdparts=spi-flash.0:" \
+					"256k(u-boot),64k(u-boot-env)," \
+					"2752k(rootfs),896k(uImage)," \
+					"64k(NVRAM),64k(ART)"
+
+#define CONFIG_ENV_SPI_MAX_HZ           25000000
+#define CONFIG_ENV_IS_IN_SPI_FLASH
+#define CONFIG_ENV_OFFSET               0x40000
+#define CONFIG_ENV_SECT_SIZE            0x10000
+#define CONFIG_ENV_SIZE                 0x10000
+
+/*
+ * Command
+ */
+#define CONFIG_CMD_MTDPARTS
+
+/* Miscellaneous configurable options */
+#define CONFIG_SYS_CBSIZE               256
+#define CONFIG_SYS_MAXARGS              16
+#define CONFIG_SYS_PBSIZE               (CONFIG_SYS_CBSIZE + \
+					sizeof(CONFIG_SYS_PROMPT) + 16)
+#define CONFIG_SYS_LONGHELP
+#define CONFIG_CMDLINE_EDITING
+#define CONFIG_AUTO_COMPLETE
+
+/*
+ * Diagnostics
+ */
+#define CONFIG_SYS_MEMTEST_START        0x80100000
+#define CONFIG_SYS_MEMTEST_END          0x83f00000
+#define CONFIG_CMD_MEMTEST
+
+#endif  /* __CONFIG_H */
diff --git a/include/configs/ap143.h b/include/configs/ap143.h
new file mode 100644
index 0000000000000000000000000000000000000000..7b69e10be442e948553de8343ce8f159647e61b6
--- /dev/null
+++ b/include/configs/ap143.h
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2015-2016 Wills Wang <wills.wang@live.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#ifndef __CONFIG_H
+#define __CONFIG_H
+
+#define CONFIG_SYS_TEXT_BASE            0x9f000000
+
+#define CONFIG_DISPLAY_CPUINFO
+#define CONFIG_DISPLAY_BOARDINFO
+#define CONFIG_BOARD_EARLY_INIT_F
+
+#define CONFIG_SYS_HZ                   1000
+#define CONFIG_SYS_MHZ                  325
+#define CONFIG_SYS_MIPS_TIMER_FREQ      (CONFIG_SYS_MHZ * 1000000)
+
+/* Cache Configuration */
+#define CONFIG_SYS_DCACHE_SIZE          0x8000
+#define CONFIG_SYS_ICACHE_SIZE          0x10000
+#define CONFIG_SYS_CACHELINE_SIZE       32
+
+#define CONFIG_SYS_MONITOR_BASE         CONFIG_SYS_TEXT_BASE
+
+#define CONFIG_SYS_MALLOC_LEN           0x40000
+#define CONFIG_SYS_BOOTPARAMS_LEN       0x20000
+
+#define CONFIG_SYS_SDRAM_BASE           0x80000000
+#define CONFIG_SYS_LOAD_ADDR            0x81000000
+
+#define CONFIG_SYS_NO_FLASH
+
+#define CONFIG_SYS_INIT_RAM_ADDR        0xbd000000
+#define CONFIG_SYS_INIT_RAM_SIZE        0x2000
+#define CONFIG_SYS_INIT_SP_ADDR \
+	(CONFIG_SYS_INIT_RAM_ADDR + CONFIG_SYS_INIT_RAM_SIZE - 1)
+
+/*
+ * Serial Port
+ */
+#define CONFIG_SYS_NS16550_CLK          25000000
+#define CONFIG_BAUDRATE                 115200
+#define CONFIG_SYS_BAUDRATE_TABLE \
+	{9600, 19200, 38400, 57600, 115200}
+
+#define CONFIG_BOOTDELAY                3
+#define CONFIG_BOOTARGS                 "console=ttyS0,115200 " \
+					"root=/dev/mtdblock2 " \
+					"rootfstype=squashfs"
+#define CONFIG_BOOTCOMMAND              "sf probe;" \
+					"mtdparts default;" \
+					"bootm 0x9f300000"
+#define CONFIG_LZMA
+
+#define MTDIDS_DEFAULT                  "nor0=spi-flash.0"
+#define MTDPARTS_DEFAULT                "mtdparts=spi-flash.0:" \
+					"256k(u-boot),64k(u-boot-env)," \
+					"2752k(rootfs),896k(uImage)," \
+					"64k(NVRAM),64k(ART)"
+
+#define CONFIG_ENV_SPI_MAX_HZ           25000000
+#define CONFIG_ENV_IS_IN_SPI_FLASH
+#define CONFIG_ENV_OFFSET               0x40000
+#define CONFIG_ENV_SECT_SIZE            0x10000
+#define CONFIG_ENV_SIZE                 0x10000
+
+/*
+ * Command
+ */
+#define CONFIG_CMD_MTDPARTS
+
+/* Miscellaneous configurable options */
+#define CONFIG_SYS_CBSIZE               256
+#define CONFIG_SYS_MAXARGS              16
+#define CONFIG_SYS_PBSIZE               (CONFIG_SYS_CBSIZE + \
+					sizeof(CONFIG_SYS_PROMPT) + 16)
+#define CONFIG_SYS_LONGHELP
+#define CONFIG_CMDLINE_EDITING
+#define CONFIG_AUTO_COMPLETE
+
+/*
+ * Diagnostics
+ */
+#define CONFIG_SYS_MEMTEST_START        0x80100000
+#define CONFIG_SYS_MEMTEST_END          0x83f00000
+#define CONFIG_CMD_MEMTEST
+
+#endif  /* __CONFIG_H */
diff --git a/include/configs/qemu-mips.h b/include/configs/qemu-mips.h
index a7cd00350d4daa8ee2cd70524d5053597935a841..702967c4e8e5cdf93afca6851b13e5d5e60059f6 100644
--- a/include/configs/qemu-mips.h
+++ b/include/configs/qemu-mips.h
@@ -58,6 +58,10 @@
 #define CONFIG_CMD_IDE
 #define CONFIG_DOS_PARTITION
 
+#ifdef CONFIG_SYS_BIG_ENDIAN
+#define CONFIG_IDE_SWAP_IO
+#endif
+
 #define CONFIG_SYS_IDE_MAXBUS		2
 #define CONFIG_SYS_ATA_IDE0_OFFSET	0x1f0
 #define CONFIG_SYS_ATA_IDE1_OFFSET	0x170
diff --git a/include/configs/qemu-mips64.h b/include/configs/qemu-mips64.h
index 394382c4587fdbae552f1b3a4ef8e9fb72ace72f..239454984ae046ea10d25555ed4b307434c84561 100644
--- a/include/configs/qemu-mips64.h
+++ b/include/configs/qemu-mips64.h
@@ -58,6 +58,10 @@
 #define CONFIG_CMD_IDE
 #define CONFIG_DOS_PARTITION
 
+#ifdef CONFIG_SYS_BIG_ENDIAN
+#define CONFIG_IDE_SWAP_IO
+#endif
+
 #define CONFIG_SYS_IDE_MAXBUS		2
 #define CONFIG_SYS_ATA_IDE0_OFFSET	0x1f0
 #define CONFIG_SYS_ATA_IDE1_OFFSET	0x170
diff --git a/include/configs/tplink_wdr4300.h b/include/configs/tplink_wdr4300.h
new file mode 100644
index 0000000000000000000000000000000000000000..2b9e92ed2b18e9a47f8e4a0c0ed2740ee1446ead
--- /dev/null
+++ b/include/configs/tplink_wdr4300.h
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2016 Marek Vasut <marex@denx.de>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#ifndef __CONFIG_H
+#define __CONFIG_H
+
+#define CONFIG_SYS_TEXT_BASE		0xa1000000
+
+#define CONFIG_DISPLAY_CPUINFO
+#define CONFIG_DISPLAY_BOARDINFO
+#define CONFIG_BOARD_EARLY_INIT_F
+
+#define CONFIG_SYS_HZ			1000
+#define CONFIG_SYS_MHZ			280
+#define CONFIG_SYS_MIPS_TIMER_FREQ	(CONFIG_SYS_MHZ * 1000000)
+
+/* Cache Configuration */
+#define CONFIG_SYS_DCACHE_SIZE		0x8000
+#define CONFIG_SYS_ICACHE_SIZE		0x10000
+#define CONFIG_SYS_CACHELINE_SIZE	32
+
+#define CONFIG_SYS_MONITOR_BASE		CONFIG_SYS_TEXT_BASE
+
+#define CONFIG_SYS_MALLOC_LEN		0x40000
+#define CONFIG_SYS_BOOTPARAMS_LEN	0x20000
+
+#define CONFIG_SYS_SDRAM_BASE		0xa0000000
+#define CONFIG_SYS_LOAD_ADDR		0xa1000000
+#define CONFIG_LOADADDR			CONFIG_SYS_LOAD_ADDR
+
+#define CONFIG_SYS_NO_FLASH
+
+#define CONFIG_SYS_INIT_RAM_ADDR	0xbd000000
+#define CONFIG_SYS_INIT_RAM_SIZE	0x8000
+#define CONFIG_SYS_INIT_SP_ADDR		\
+	(CONFIG_SYS_INIT_RAM_ADDR + CONFIG_SYS_INIT_RAM_SIZE)
+
+/*
+ * Serial Port
+ */
+#define CONFIG_SYS_NS16550_CLK		40000000
+#define CONFIG_BAUDRATE			115200
+#define CONFIG_SYS_BAUDRATE_TABLE \
+	{9600, 19200, 38400, 57600, 115200}
+
+#define CONFIG_BOOTDELAY		3
+#define CONFIG_BOOTARGS			\
+	"console=ttyS0,115200 root=/dev/mtdblock2 rootfstype=squashfs"
+#define CONFIG_BOOTCOMMAND		\
+	"dhcp 192.168.1.1:wdr4300.fit && bootm $loadaddr"
+#define CONFIG_LZMA
+
+#define CONFIG_ENV_IS_NOWHERE
+#define CONFIG_ENV_SIZE			0x10000
+
+/*
+ * Command
+ */
+/* Miscellaneous configurable options */
+#define CONFIG_SYS_LONGHELP
+#define CONFIG_SYS_CBSIZE	1024		/* Console I/O buffer size */
+#define CONFIG_SYS_MAXARGS	32		/* Max number of command args */
+#define CONFIG_SYS_BARGSIZE	CONFIG_SYS_CBSIZE
+						/* Boot argument buffer size */
+#define CONFIG_VERSION_VARIABLE			/* U-BOOT version */
+#define CONFIG_AUTO_COMPLETE			/* Command auto complete */
+#define CONFIG_CMDLINE_EDITING			/* Command history etc */
+#define CONFIG_SYS_HUSH_PARSER
+#define CONFIG_SYS_PROMPT_HUSH_PS2	"> "
+
+/* USB, USB storage, USB ethernet */
+#define CONFIG_EHCI_MMIO_BIG_ENDIAN
+#define CONFIG_EHCI_DESC_BIG_ENDIAN
+#define CONFIG_EHCI_IS_TDI
+
+#define CONFIG_DOS_PARTITION
+
+/*
+ * Diagnostics
+ */
+#define CONFIG_SYS_MEMTEST_START	0x80100000
+#define CONFIG_SYS_MEMTEST_END		0x83f00000
+#define CONFIG_CMD_MEMTEST
+
+#define CONFIG_USE_PRIVATE_LIBGCC
+
+#define CONFIG_CMD_MII
+#define CONFIG_PHY_GIGE
+
+#endif  /* __CONFIG_H */
diff --git a/include/flash.h b/include/flash.h
index c6321a02ef8e5d4f89f5288f1910bad888e37d60..2a5e13a13d380b9c131a74c97900e4663d11e7b0 100644
--- a/include/flash.h
+++ b/include/flash.h
@@ -400,6 +400,9 @@ extern flash_info_t *flash_get_info(ulong base);
 #define FLASH_STM800DT	0x00D7		/* STM M29W800DT (1M = 64K x 16, top)	*/
 #define FLASH_STM800DB	0x005B		/* STM M29W800DB (1M = 64K x 16, bottom)*/
 
+#define FLASH_MCHP100T	0x0060		/* MCHP internal (1M = 64K x 16) */
+#define FLASH_MCHP100B	0x0061		/* MCHP internal (1M = 64K x 16) */
+
 #define FLASH_28F400_T	0x0062		/* MT  28F400B3 ID (  4M = 256K x 16 )	*/
 #define FLASH_28F400_B	0x0063		/* MT  28F400B3 ID (  4M = 256K x 16 )	*/
 
@@ -486,7 +489,7 @@ extern flash_info_t *flash_get_info(ulong base);
 #define FLASH_MAN_SHARP 0x00500000
 #define FLASH_MAN_ATM	0x00600000
 #define FLASH_MAN_CFI	0x01000000
-
+#define FLASH_MAN_MCHP	0x02000000	/* Microchip Technology		*/
 
 #define FLASH_TYPEMASK	0x0000FFFF	/* extract FLASH type	information	*/
 #define FLASH_VENDMASK	0xFFFF0000	/* extract FLASH vendor information	*/