diff --git a/target/linux/ramips/base-files/lib/preinit/04_disable_wnce2001_flash_checksumming b/target/linux/ramips/base-files/lib/preinit/04_handle_checksumming
similarity index 62%
rename from target/linux/ramips/base-files/lib/preinit/04_disable_wnce2001_flash_checksumming
rename to target/linux/ramips/base-files/lib/preinit/04_handle_checksumming
index 67a1746f1d3ffdf08f0da30e7cf827efe0250a99..fd06d20c990e98ca03ab59f895442203c89f8c5d 100644
--- a/target/linux/ramips/base-files/lib/preinit/04_disable_wnce2001_flash_checksumming
+++ b/target/linux/ramips/base-files/lib/preinit/04_handle_checksumming
@@ -5,7 +5,7 @@
 # this, so we make sure to zero checksum and size to be checksummed before
 # that happens, so this needs to run very early during boot.
 
-do_wnce2001_checksumming_disable() {
+do_checksumming_disable() {
 	. /lib/ramips.sh
 
 	local board=$(ramips_board_name)
@@ -35,9 +35,22 @@ do_wnce2001_checksumming_disable() {
 			echo "Checksum is already zero, nothing to do."
 		fi
 	;;
+	rt-n56u)
+		echo "Board is ASUS RT-N56U, replacing uImage header..."
+		local firmware_mtd=$(find_mtd_part firmware)
+		local rootfs_mtd=$(find_mtd_part rootfs)
+		local rootfs_data_mtd=$(find_mtd_part rootfs_data)
+		local rootfs_len=$(grep \"rootfs\" /proc/mtd | awk -F' ' '{print "0x"$2}')
+		local rootfs_data_len=$(grep \"rootfs_data\" /proc/mtd | awk -F' ' '{print "0x"$2}')
+		local offset=$(echo "$rootfs_len $rootfs_data_len 0x40" | awk -F' ' '{printf "%i",$1-$2-$3}')
+		local signature=$(dd if=$rootfs_mtd skip=$offset bs=1 count=4 2>/dev/null | hexdump -v -n 4 -e '1/1 "%02x"')
+		if [ "$signature" == "27051956" ]; then
+			dd conv=notrunc if=$rootfs_mtd skip=$offset of=$firmware_mtd bs=1 count=64 2>/dev/null
+		fi
+	;;
 	esac
 
 	return 0
 }
 
-boot_hook_add preinit_main do_wnce2001_checksumming_disable
+boot_hook_add preinit_main do_checksumming_disable
diff --git a/target/linux/ramips/dts/RTN56U.dts b/target/linux/ramips/dts/RTN56U.dts
index b962aa0d231f3e24c1ba497613f0b2ffedf4a7fb..305e36e85b8d332faead44a23fa1f4e65fd66ac5 100644
--- a/target/linux/ramips/dts/RTN56U.dts
+++ b/target/linux/ramips/dts/RTN56U.dts
@@ -43,12 +43,20 @@
 		host-bridge {
 			pci-bridge@1 {
 				status = "okay";
+				wmac@0,0 {
+                                        compatible = "ralink,rt2880-pci", "pciclass060400", "pciclass0604";
+                                        reg = < 0x10000 0 0 0 0 >;
+                                        ralink,eeprom = "rt2x00pci_1_0.eeprom";
+                                };
+
 			};
 		};
 	};
 
 	wmac@10180000 {
+		status = "okay";
 		ralink,2ghz = <0>;
+		ralink,eeprom = "soc_wmac.eeprom";
 	};
 
 	ehci@101c0000 {
diff --git a/target/linux/ramips/image/Makefile b/target/linux/ramips/image/Makefile
index 58a54773c2806073ef983a601f9861ef24d88326..1b342deb7a413ced6b8789611f5d7f60ab7c1571 100644
--- a/target/linux/ramips/image/Makefile
+++ b/target/linux/ramips/image/Makefile
@@ -665,7 +665,13 @@ Image/Build/Profile/DIR645=$(call BuildFirmware/Seama/$(1),$(1),dir-645,DIR-645,
 omniembhpm_mtd_size=16449536
 Image/Build/Profile/OMNIEMBHPM=$(call BuildFirmware/CustomFlash/$(1),$(1),omni-emb-hpm,OMNI-EMB-HPM,$(omniembhpm_mtd_size))
 
-Image/Build/Profile/RTN56U=$(call BuildFirmware/Default8M/$(1),$(1),rt-n56u,RTN56U)
+define BuildFirmware/RTN56U/squashfs
+	$(call BuildFirmware/Default8M/$(1),$(1),rt-n56u,RTN56U)
+	-mkrtn56uimg -s $(call sysupname,$(1),rt-n56u)
+	-cp $(call sysupname,$(1),rt-n56u) $(call imgname,$(1),rt-n56u)-factory.bin
+	-mkrtn56uimg -f $(call imgname,$(1),rt-n56u)-factory.bin
+endef
+Image/Build/Profile/RTN56U=$(call BuildFirmware/RTN56U/$(1),$(1),rt-n56u,RTN56U)
 
 Image/Build/Profile/TEW691GR=$(call BuildFirmware/UMedia/$(1),$(1),tew-691gr,TEW-691GR,0x026910)
 
diff --git a/target/linux/ramips/patches-3.10/0135-mtd-add-rtn56u-support.patch b/target/linux/ramips/patches-3.10/0135-mtd-add-rtn56u-support.patch
new file mode 100644
index 0000000000000000000000000000000000000000..52379916b91057e7b350a20f4e8525e04da82303
--- /dev/null
+++ b/target/linux/ramips/patches-3.10/0135-mtd-add-rtn56u-support.patch
@@ -0,0 +1,28 @@
+--- a/drivers/mtd/mtdpart.c	2014-04-27 10:09:21.566294160 +0300
++++ b/drivers/mtd/mtdpart.c	2014-06-09 11:27:48.952211672 +0300
+@@ -793,8 +793,11 @@
+ {
+ 	struct {
+ 		__be32 magic;
+-		__be32 pad[2];
++		__be32 pad0[2];
+ 		__be32 size;
++		__be32 pad1[4];
++		__be32 name[7];
++		__be32 kern_size;
+ 	} hdr;
+ 	size_t len;
+ 
+@@ -804,7 +807,11 @@
+ 	if (len != sizeof(hdr) || hdr.magic != cpu_to_be32(UBOOT_MAGIC))
+ 		return;
+ 
+-	len = be32_to_cpu(hdr.size) + 0x40;
++	if (hdr.kern_size != 0 && hdr.name[0] == 0)
++		len = be32_to_cpu(hdr.kern_size);
++	else
++		len = be32_to_cpu(hdr.size) + 0x40;
++
+ 	__mtd_add_partition(master, "rootfs", part->offset + len,
+ 			    part->mtd.size - len, false);
+ }
diff --git a/tools/firmware-utils/Makefile b/tools/firmware-utils/Makefile
index 3be80e77abc7700fe20a3fa72dae33a44bcd167f..8f17c3e9233d9611f7b6b389f41f3115783b61d8 100644
--- a/tools/firmware-utils/Makefile
+++ b/tools/firmware-utils/Makefile
@@ -67,6 +67,7 @@ define Host/Compile
 	#$(call cc,mkhilinkfw, -lcrypto)
 	$(call cc,mkdcs932, -Wall)
 	$(call cc,mkheader_gemtek,-lz)
+	$(call cc,mkrtn56uimg, -lz)
 endef
 
 define Host/Install
diff --git a/tools/firmware-utils/src/mkrtn56uimg.c b/tools/firmware-utils/src/mkrtn56uimg.c
new file mode 100644
index 0000000000000000000000000000000000000000..973ab28d06ae587d6e2a0712749795798d09b627
--- /dev/null
+++ b/tools/firmware-utils/src/mkrtn56uimg.c
@@ -0,0 +1,294 @@
+/*
+ *
+ *  Copyright (C) 2014 OpenWrt.org
+ *  Copyright (C) 2014 Mikko Hissa <mikko.hissa@werzek.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify it
+ *  under the terms of the GNU General Public License version 2 as published
+ *  by the Free Software Foundation.
+ *
+ */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <netinet/in.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <time.h>
+#include <unistd.h>
+#include <zlib.h>
+
+#define IH_MAGIC	0x27051956
+#define IH_NMLEN	32
+#define IH_PRODLEN	23
+
+#define IH_TYPE_INVALID		0
+#define IH_TYPE_STANDALONE	1
+#define IH_TYPE_KERNEL		2
+#define IH_TYPE_RAMDISK		3
+#define IH_TYPE_MULTI		4
+#define IH_TYPE_FIRMWARE	5
+#define IH_TYPE_SCRIPT		6
+#define IH_TYPE_FILESYSTEM	7
+
+/*
+ * Compression Types
+ */
+#define IH_COMP_NONE		0
+#define IH_COMP_GZIP		1
+#define IH_COMP_BZIP2		2
+#define IH_COMP_LZMA		3
+
+typedef struct {
+	uint8_t major;
+	uint8_t minor;
+} version_t;
+
+typedef struct {
+	version_t	kernel;
+	version_t	fs;
+	uint8_t		productid[IH_PRODLEN];
+	uint8_t  	sub_fs;
+	uint32_t	ih_ksz;
+} asus_t;
+
+typedef struct image_header {
+	uint32_t	ih_magic;
+	uint32_t	ih_hcrc;
+	uint32_t	ih_time;
+	uint32_t	ih_size;
+	uint32_t	ih_load;
+	uint32_t	ih_ep;
+	uint32_t	ih_dcrc;
+	uint8_t		ih_os;
+	uint8_t		ih_arch;
+	uint8_t		ih_type;
+	uint8_t		ih_comp;
+	union {
+		uint8_t	ih_name[IH_NMLEN];
+		asus_t	asus;
+	} tail;
+} image_header_t;
+
+typedef struct squashfs_sb {
+	uint32_t	s_magic;
+	uint32_t	pad0[9];
+	uint64_t	bytes_used;
+} squashfs_sb_t;
+
+typedef enum {
+	NONE, FACTORY, SYSUPGRADE,
+} op_mode_t;
+
+void
+calc_crc(image_header_t *hdr, void *data, uint32_t len)
+{
+	/*
+	 * Calculate payload checksum
+	 */
+	hdr->ih_dcrc = htonl(crc32(0, data, len));
+	hdr->ih_size = htonl(len);
+	/*
+	 * Calculate header checksum
+	 */
+	hdr->ih_hcrc = 0;
+	hdr->ih_hcrc = htonl(crc32(0, hdr, sizeof(image_header_t)));
+}
+
+
+static void
+usage(const char *progname, int status)
+{
+	FILE *stream = (status != EXIT_SUCCESS) ? stderr : stdout;
+	int i;
+
+	fprintf(stream, "Usage: %s [OPTIONS...]\n", progname);
+	fprintf(stream, "\n"
+			"Options:\n"
+			"  -f <file>		generate a factory flash image <file>\n"
+			"  -s <file>		generate a sysupgrade flash image <file>\n"
+			"  -h			show this screen\n");
+	exit(status);
+}
+
+int
+process_image(char *progname, char *filename, op_mode_t opmode)
+{
+	int 		fd, len;
+	void 		*data, *ptr;
+	char		namebuf[IH_NMLEN];
+	struct 		stat sbuf;
+	uint32_t	checksum, offset_kernel, offset_sqfs, offset_end,
+				offset_sec_header, offset_eb, offset_image_end;
+	squashfs_sb_t *sqs;
+	image_header_t *hdr;
+
+	if ((fd = open(filename, O_RDWR, 0666)) < 0) {
+		fprintf (stderr, "%s: Can't open %s: %s\n",
+			progname, filename, strerror(errno));
+		return (EXIT_FAILURE);
+	}
+
+	if (fstat(fd, &sbuf) < 0) {
+		fprintf (stderr, "%s: Can't stat %s: %s\n",
+			progname, filename, strerror(errno));
+		return (EXIT_FAILURE);
+	}
+
+	if ((unsigned)sbuf.st_size < sizeof(image_header_t)) {
+		fprintf (stderr,
+			"%s: Bad size: \"%s\" is no valid image\n",
+			progname, filename);
+		return (EXIT_FAILURE);
+	}
+
+	ptr = (void *)mmap(0, sbuf.st_size,
+				PROT_READ | PROT_WRITE,
+				MAP_SHARED,
+				fd, 0);
+
+	if ((caddr_t)ptr == (caddr_t)-1) {
+		fprintf (stderr, "%s: Can't read %s: %s\n",
+			progname, filename, strerror(errno));
+		return (EXIT_FAILURE);
+	}
+
+	hdr = ptr;
+
+	if (ntohl(hdr->ih_magic) != IH_MAGIC) {
+		fprintf (stderr,
+			"%s: Bad Magic Number: \"%s\" is no valid image\n",
+			progname, filename);
+		return (EXIT_FAILURE);
+	}
+
+	if (opmode == FACTORY) {
+		strncpy(&namebuf, (char *)&hdr->tail.ih_name, IH_NMLEN);
+		hdr->tail.asus.kernel.major = 0;
+		hdr->tail.asus.kernel.minor = 0;
+		hdr->tail.asus.fs.major = 0;
+		hdr->tail.asus.fs.minor = 0;
+		strncpy((char *)&hdr->tail.asus.productid, "RT-N56U", IH_PRODLEN);
+	}
+
+	if (hdr->tail.asus.ih_ksz == 0)
+		hdr->tail.asus.ih_ksz = htonl(ntohl(hdr->ih_size) + sizeof(image_header_t));
+
+	offset_kernel = sizeof(image_header_t);
+	offset_sqfs = ntohl(hdr->tail.asus.ih_ksz);
+	sqs = ptr + offset_sqfs;
+	offset_sec_header = offset_sqfs + sqs->bytes_used;
+
+	/*
+	 * Reserve space for the second header.
+	 */
+	offset_end = offset_sec_header + sizeof(image_header_t);
+	offset_eb = ((offset_end>>16)+1)<<16;
+
+	if (opmode == FACTORY)
+		offset_image_end = offset_eb + 4;
+	else
+		offset_image_end = sbuf.st_size;
+	/*
+	 * Move the second header at the end of the image.
+	 */
+	offset_end = offset_sec_header;
+	offset_sec_header = offset_eb - sizeof(image_header_t);
+
+	/*
+	 * Remove jffs2 markers between squashfs and eb boundary.
+	 */
+	if (opmode == FACTORY)
+		memset(ptr+offset_end, 0xff ,offset_eb - offset_end);
+
+	/*
+	 * Grow the image if needed.
+	 */
+	if (offset_image_end > sbuf.st_size) {
+		(void) munmap((void *)ptr, sbuf.st_size);
+		ftruncate(fd, offset_image_end);
+		ptr = (void *)mmap(0, offset_image_end,
+						PROT_READ | PROT_WRITE,
+						MAP_SHARED,
+						fd, 0);
+		/*
+		 * jffs2 marker
+		 */
+		if (opmode == FACTORY) {
+			*(uint8_t *)(ptr+offset_image_end-4) = 0xde;
+			*(uint8_t *)(ptr+offset_image_end-3) = 0xad;
+			*(uint8_t *)(ptr+offset_image_end-2) = 0xc0;
+			*(uint8_t *)(ptr+offset_image_end-1) = 0xde;
+		}
+	}
+
+	/*
+	 * Calculate checksums for the second header to be used after flashing.
+	 */
+	if (opmode == FACTORY) {
+		hdr = ptr+offset_sec_header;
+		memcpy(hdr, ptr, sizeof(image_header_t));
+		strncpy((char *)&hdr->tail.ih_name, &namebuf, IH_NMLEN);
+		calc_crc(hdr, ptr+offset_kernel, offset_sqfs - offset_kernel);
+		calc_crc((image_header_t *)ptr, ptr+offset_kernel, offset_image_end - offset_kernel);
+	} else {
+		calc_crc((image_header_t *)ptr, ptr+offset_kernel, offset_sqfs - offset_kernel);
+	}
+
+	if (sbuf.st_size > offset_image_end)
+		(void) munmap((void *)ptr, sbuf.st_size);
+	else
+		(void) munmap((void *)ptr, offset_image_end);
+
+	ftruncate(fd, offset_image_end);
+	(void) close (fd);
+
+	return EXIT_SUCCESS;
+}
+
+int
+main(int argc, char **argv)
+{
+	int 		opt;
+	char 		*filename, *progname;
+	op_mode_t	opmode = NONE;
+
+	progname = argv[0];
+
+	while ((opt = getopt(argc, argv,":s:f:h?")) != -1) {
+		switch (opt) {
+		case 's':
+			opmode = SYSUPGRADE;
+			filename = optarg;
+			break;
+		case 'f':
+			opmode = FACTORY;
+			filename = optarg;
+			break;
+		case 'h':
+			opmode = NONE;
+		default:
+			usage(progname, EXIT_FAILURE);
+			opmode = NONE;
+		}
+	}
+
+	if(filename == NULL)
+		opmode = NONE;
+
+	switch (opmode) {
+	case NONE:
+		usage(progname, EXIT_FAILURE);
+		break;
+	case FACTORY:
+	case SYSUPGRADE:
+		return process_image(progname, filename, opmode);
+		break;
+	}
+
+	return EXIT_SUCCESS;
+}
+