diff --git a/patches/openwrt/0005-firmware-utils-add-new-tool-tplink-safeloader-for-the-new-TP-LINK-Pharos-devices-CPE210-220-510-520.patch b/patches/openwrt/0005-firmware-utils-add-new-tool-tplink-safeloader-for-the-new-TP-LINK-Pharos-devices-CPE210-220-510-520.patch new file mode 100644 index 00000000..9cc72b6b --- /dev/null +++ b/patches/openwrt/0005-firmware-utils-add-new-tool-tplink-safeloader-for-the-new-TP-LINK-Pharos-devices-CPE210-220-510-520.patch @@ -0,0 +1,570 @@ +From: Matthias Schiffer +Date: Wed, 26 Nov 2014 19:57:39 +0100 +Subject: firmware-utils: add new tool tplink-safeloader for the new TP-LINK Pharos devices (CPE210/220/510/520) + +The new TP-LINK Pharos series uses a new bootloader, the "TP-LINK Safeloader". +It uses an advanced firmware image format, containing an image partition table +and a flash partition table (and image partitions are mapped to the +corresponding flash partitions). The exact image format is documented in the +source code. + +Furthermore, the bootloader expects the kernel image as an ELF executable. + +Signed-off-by: Matthias Schiffer + +diff --git a/tools/firmware-utils/Makefile b/tools/firmware-utils/Makefile +index 4bb53cb..3f9eb56 100644 +--- a/tools/firmware-utils/Makefile ++++ b/tools/firmware-utils/Makefile +@@ -41,6 +41,7 @@ define Host/Compile + $(call cc,mkplanexfw sha1) + $(call cc,mktplinkfw md5) + $(call cc,mktplinkfw2 md5) ++ $(call cc,tplink-safeloader md5, -Wall) + $(call cc,pc1crypt) + $(call cc,osbridge-crc) + $(call cc,wrt400n cyg_crc32) +diff --git a/tools/firmware-utils/src/tplink-safeloader.c b/tools/firmware-utils/src/tplink-safeloader.c +new file mode 100644 +index 0000000..23d703f +--- /dev/null ++++ b/tools/firmware-utils/src/tplink-safeloader.c +@@ -0,0 +1,538 @@ ++/* ++ Copyright (c) 2014, Matthias Schiffer ++ All rights reserved. ++ ++ Redistribution and use in source and binary forms, with or without ++ modification, are permitted provided that the following conditions are met: ++ ++ 1. Redistributions of source code must retain the above copyright notice, ++ this list of conditions and the following disclaimer. ++ 2. Redistributions in binary form must reproduce the above copyright notice, ++ this list of conditions and the following disclaimer in the documentation ++ and/or other materials provided with the distribution. ++ ++ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" ++ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ++ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE ++ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ++ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR ++ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER ++ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, ++ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ++ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++*/ ++ ++ ++/* ++ tplink-safeloader ++ ++ Image generation tool for the TP-LINK SafeLoader as seen on ++ TP-LINK Pharos devices (CPE210/220/510/520) ++*/ ++ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++#include ++#include ++ ++#include "md5.h" ++ ++ ++#define ALIGN(x,a) ({ typeof(a) __a = (a); (((x) + __a - 1) & ~(__a - 1)); }) ++ ++ ++/** An image partition table entry */ ++struct image_partition_entry { ++ const char *name; ++ size_t size; ++ uint8_t *data; ++}; ++ ++/** A flash partition table entry */ ++struct flash_partition_entry { ++ const char *name; ++ uint32_t base; ++ uint32_t size; ++}; ++ ++ ++/** The content of the soft-version structure */ ++struct __attribute__((__packed__)) soft_version { ++ uint32_t magic; ++ uint32_t zero; ++ uint8_t pad1; ++ uint8_t version_major; ++ uint8_t version_minor; ++ uint8_t version_patch; ++ uint8_t year_hi; ++ uint8_t year_lo; ++ uint8_t month; ++ uint8_t day; ++ uint32_t rev; ++ uint8_t pad2; ++}; ++ ++ ++static const uint8_t jffs2_eof_mark[4] = {0xde, 0xad, 0xc0, 0xde}; ++ ++ ++/** ++ Salt for the MD5 hash ++ ++ Fortunately, TP-LINK seems to use the same salt for most devices which use ++ the new image format. ++*/ ++static const uint8_t md5_salt[16] = { ++ 0x7a, 0x2b, 0x15, 0xed, ++ 0x9b, 0x98, 0x59, 0x6d, ++ 0xe5, 0x04, 0xab, 0x44, ++ 0xac, 0x2a, 0x9f, 0x4e, ++}; ++ ++ ++/** Vendor information for CPE210/220/510/520 */ ++static const unsigned char cpe510_vendor[] = "\x00\x00\x00\x1f""CPE510(TP-LINK|UN|N300-5):1.0\r\n"; ++ ++ ++/** ++ The flash partition table for CPE210/220/510/520; ++ it is the same as the one used by the stock images. ++*/ ++static const struct flash_partition_entry cpe510_partitions[] = { ++ {"fs-uboot", 0x00000, 0x20000}, ++ {"partition-table", 0x20000, 0x02000}, ++ {"default-mac", 0x30000, 0x00020}, ++ {"product-info", 0x31100, 0x00100}, ++ {"signature", 0x32000, 0x00400}, ++ {"os-image", 0x40000, 0x170000}, ++ {"soft-version", 0x1b0000, 0x00100}, ++ {"support-list", 0x1b1000, 0x00400}, ++ {"file-system", 0x1c0000, 0x600000}, ++ {"user-config", 0x7c0000, 0x10000}, ++ {"default-config", 0x7d0000, 0x10000}, ++ {"log", 0x7e0000, 0x10000}, ++ {"radio", 0x7f0000, 0x10000}, ++ {NULL, 0, 0} ++}; ++ ++/** ++ The support list for CPE210/220/510/520 ++ ++ The stock images also contain strings for two more devices: BS510 and BS210. ++ At the moment, there exists no public information about these devices. ++*/ ++static const unsigned char cpe510_support_list[] = ++ "\x00\x00\x00\xc8\x00\x00\x00\x00" ++ "SupportList:\r\n" ++ "CPE510(TP-LINK|UN|N300-5):1.0\r\n" ++ "CPE520(TP-LINK|UN|N300-5):1.0\r\n" ++ "CPE210(TP-LINK|UN|N300-2):1.0\r\n" ++ "CPE220(TP-LINK|UN|N300-2):1.0\r\n" ++ "\r\n\xff"; ++ ++ ++/** Allocates a new image partition */ ++struct image_partition_entry alloc_image_partition(const char *name, size_t len) { ++ struct image_partition_entry entry = {name, len, malloc(len)}; ++ if (!entry.data) ++ error(1, errno, "malloc"); ++ ++ return entry; ++} ++ ++/** Frees an image partition */ ++void free_image_partition(struct image_partition_entry entry) { ++ free(entry.data); ++} ++ ++/** Generates the partition-table partition */ ++struct image_partition_entry make_partition_table(const struct flash_partition_entry *p) { ++ struct image_partition_entry entry = alloc_image_partition("partition-table", 0x800); ++ ++ char *s = (char *)entry.data, *end = (char *)(s+entry.size); ++ ++ *(s++) = 0x00; ++ *(s++) = 0x04; ++ *(s++) = 0x00; ++ *(s++) = 0x00; ++ ++ size_t i; ++ for (i = 0; p[i].name; i++) { ++ size_t len = end-s; ++ size_t w = snprintf(s, len, "partition %s base 0x%05x size 0x%05x\n", p[i].name, p[i].base, p[i].size); ++ ++ if (w > len-1) ++ error(1, 0, "flash partition table overflow?"); ++ ++ s += w; ++ } ++ ++ s++; ++ ++ memset(s, 0xff, end-s); ++ ++ return entry; ++} ++ ++ ++/** Generates a binary-coded decimal representation of an integer in the range [0, 99] */ ++static inline uint8_t bcd(uint8_t v) { ++ return 0x10 * (v/10) + v%10; ++} ++ ++ ++/** Generates the soft-version partition */ ++struct image_partition_entry make_soft_version(uint32_t rev) { ++ struct image_partition_entry entry = alloc_image_partition("soft-version", sizeof(struct soft_version)); ++ struct soft_version *s = (struct soft_version *)entry.data; ++ ++ time_t t; ++ if (time(&t) == (time_t)(-1)) ++ error(1, errno, "time"); ++ ++ struct tm *tm = localtime(&t); ++ ++ s->magic = htonl(0x0000000c); ++ s->zero = 0; ++ s->pad1 = 0xff; ++ ++ s->version_major = 0; ++ s->version_minor = 0; ++ s->version_patch = 0; ++ ++ s->year_hi = bcd((1900+tm->tm_year)/100); ++ s->year_lo = bcd(tm->tm_year%100); ++ s->month = bcd(tm->tm_mon+1); ++ s->day = bcd(tm->tm_mday); ++ s->rev = htonl(rev); ++ ++ s->pad2 = 0xff; ++ ++ return entry; ++} ++ ++/** Generates the support-list partition */ ++struct image_partition_entry make_support_list(const unsigned char *support_list, size_t len) { ++ struct image_partition_entry entry = alloc_image_partition("support-list", len); ++ memcpy(entry.data, support_list, len); ++ return entry; ++} ++ ++/** Creates a new image partition with an arbitrary name from a file */ ++struct image_partition_entry read_file(const char *part_name, const char *filename, bool add_jffs2_eof) { ++ struct stat statbuf; ++ ++ if (stat(filename, &statbuf) < 0) ++ error(1, errno, "unable to stat file `%s'", filename); ++ ++ size_t len = statbuf.st_size; ++ ++ if (add_jffs2_eof) ++ len = ALIGN(len, 0x10000) + sizeof(jffs2_eof_mark); ++ ++ struct image_partition_entry entry = alloc_image_partition(part_name, len); ++ ++ FILE *file = fopen(filename, "rb"); ++ if (!file) ++ error(1, errno, "unable to open file `%s'", filename); ++ ++ if (fread(entry.data, statbuf.st_size, 1, file) != 1) ++ error(1, errno, "unable to read file `%s'", filename); ++ ++ if (add_jffs2_eof) { ++ uint8_t *eof = entry.data + statbuf.st_size, *end = entry.data+entry.size; ++ ++ memset(eof, 0xff, end - eof - sizeof(jffs2_eof_mark)); ++ memcpy(end - sizeof(jffs2_eof_mark), jffs2_eof_mark, sizeof(jffs2_eof_mark)); ++ } ++ ++ fclose(file); ++ ++ return entry; ++} ++ ++ ++/** ++ Copies a list of image partitions into an image buffer and generates the image partition table while doing so ++ ++ Example image partition table: ++ ++ fwup-ptn partition-table base 0x00800 size 0x00800 ++ fwup-ptn os-image base 0x01000 size 0x113b45 ++ fwup-ptn file-system base 0x114b45 size 0x1d0004 ++ fwup-ptn support-list base 0x2e4b49 size 0x000d1 ++ ++ Each line of the partition table is terminated with the bytes 09 0d 0a ("\t\r\n"), ++ the end of the partition table is marked with a zero byte. ++ ++ The firmware image must contain at least the partition-table and support-list partitions ++ to be accepted. There aren't any alignment constraints for the image partitions. ++ ++ The partition-table partition contains the actual flash layout; partitions ++ from the image partition table are mapped to the corresponding flash partitions during ++ the firmware upgrade. The support-list partition contains a list of devices supported by ++ the firmware image. ++ ++ The base offsets in the firmware partition table are relative to the end ++ of the vendor information block, so the partition-table partition will ++ actually start at offset 0x1814 of the image. ++ ++ I think partition-table must be the first partition in the firmware image. ++*/ ++void put_partitions(uint8_t *buffer, const struct image_partition_entry *parts) { ++ size_t i; ++ char *image_pt = (char *)buffer, *end = image_pt + 0x800; ++ ++ size_t base = 0x800; ++ for (i = 0; parts[i].name; i++) { ++ memcpy(buffer + base, parts[i].data, parts[i].size); ++ ++ size_t len = end-image_pt; ++ size_t w = snprintf(image_pt, len, "fwup-ptn %s base 0x%05x size 0x%05x\t\r\n", parts[i].name, (unsigned)base, (unsigned)parts[i].size); ++ ++ if (w > len-1) ++ error(1, 0, "image partition table overflow?"); ++ ++ image_pt += w; ++ ++ base += parts[i].size; ++ } ++ ++ image_pt++; ++ ++ memset(image_pt, 0xff, end-image_pt); ++} ++ ++/** Generates and writes the image MD5 checksum */ ++void put_md5(uint8_t *md5, uint8_t *buffer, unsigned int len) { ++ MD5_CTX ctx; ++ ++ MD5_Init(&ctx); ++ MD5_Update(&ctx, md5_salt, (unsigned int)sizeof(md5_salt)); ++ MD5_Update(&ctx, buffer, len); ++ MD5_Final(md5, &ctx); ++} ++ ++ ++/** ++ Generates the firmware image in factory format ++ ++ Image format: ++ ++ Bytes (hex) Usage ++ ----------- ----- ++ 0000-0003 Image size (4 bytes, big endian) ++ 0004-0013 MD5 hash (hash of a 16 byte salt and the image data starting with byte 0x14) ++ 0014-1013 Vendor information (4096 bytes, padded with 0xff; there seem to be older ++ (VxWorks-based) TP-LINK devices which use a smaller vendor information block) ++ 1014-1813 Image partition table (2048 bytes, padded with 0xff) ++ 1814-xxxx Firmware partitions ++*/ ++void * generate_factory_image(const unsigned char *vendor, size_t vendor_len, const struct image_partition_entry *parts, size_t *len) { ++ *len = 0x1814; ++ ++ size_t i; ++ for (i = 0; parts[i].name; i++) ++ *len += parts[i].size; ++ ++ uint8_t *image = malloc(*len); ++ if (!image) ++ error(1, errno, "malloc"); ++ ++ image[0] = *len >> 24; ++ image[1] = *len >> 16; ++ image[2] = *len >> 8; ++ image[3] = *len; ++ ++ memcpy(image+0x14, vendor, vendor_len); ++ memset(image+0x14+vendor_len, 0xff, 4096-vendor_len); ++ ++ put_partitions(image + 0x1014, parts); ++ put_md5(image+0x04, image+0x14, *len-0x14); ++ ++ return image; ++} ++ ++/** ++ Generates the firmware image in sysupgrade format ++ ++ This makes some assumptions about the provided flash and image partition tables and ++ should be generalized when TP-LINK starts building its safeloader into hardware with ++ different flash layouts. ++*/ ++void * generate_sysupgrade_image(const struct flash_partition_entry *flash_parts, const struct image_partition_entry *image_parts, size_t *len) { ++ const struct flash_partition_entry *flash_os_image = &flash_parts[5]; ++ const struct flash_partition_entry *flash_soft_version = &flash_parts[6]; ++ const struct flash_partition_entry *flash_support_list = &flash_parts[7]; ++ const struct flash_partition_entry *flash_file_system = &flash_parts[8]; ++ ++ const struct image_partition_entry *image_os_image = &image_parts[3]; ++ const struct image_partition_entry *image_soft_version = &image_parts[1]; ++ const struct image_partition_entry *image_support_list = &image_parts[2]; ++ const struct image_partition_entry *image_file_system = &image_parts[4]; ++ ++ assert(strcmp(flash_os_image->name, "os-image") == 0); ++ assert(strcmp(flash_soft_version->name, "soft-version") == 0); ++ assert(strcmp(flash_support_list->name, "support-list") == 0); ++ assert(strcmp(flash_file_system->name, "file-system") == 0); ++ ++ assert(strcmp(image_os_image->name, "os-image") == 0); ++ assert(strcmp(image_soft_version->name, "soft-version") == 0); ++ assert(strcmp(image_support_list->name, "support-list") == 0); ++ assert(strcmp(image_file_system->name, "file-system") == 0); ++ ++ if (image_os_image->size > flash_os_image->size) ++ error(1, 0, "kernel image too big (more than %u bytes)", (unsigned)flash_os_image->size); ++ if (image_file_system->size > flash_file_system->size) ++ error(1, 0, "rootfs image too big (more than %u bytes)", (unsigned)flash_file_system->size); ++ ++ *len = flash_file_system->base - flash_os_image->base + image_file_system->size; ++ ++ uint8_t *image = malloc(*len); ++ if (!image) ++ error(1, errno, "malloc"); ++ ++ memset(image, 0xff, *len); ++ ++ memcpy(image, image_os_image->data, image_os_image->size); ++ memcpy(image + flash_soft_version->base - flash_os_image->base, image_soft_version->data, image_soft_version->size); ++ memcpy(image + flash_support_list->base - flash_os_image->base, image_support_list->data, image_support_list->size); ++ memcpy(image + flash_file_system->base - flash_os_image->base, image_file_system->data, image_file_system->size); ++ ++ return image; ++} ++ ++ ++/** Generates an image for CPE210/220/510/520 and writes it to a file */ ++static void do_cpe510(const char *output, const char *kernel_image, const char *rootfs_image, uint32_t rev, bool add_jffs2_eof, bool sysupgrade) { ++ struct image_partition_entry parts[6] = {}; ++ ++ parts[0] = make_partition_table(cpe510_partitions); ++ parts[1] = make_soft_version(rev); ++ parts[2] = make_support_list(cpe510_support_list, sizeof(cpe510_support_list)-1); ++ parts[3] = read_file("os-image", kernel_image, false); ++ parts[4] = read_file("file-system", rootfs_image, add_jffs2_eof); ++ ++ size_t len; ++ void *image; ++ if (sysupgrade) ++ image = generate_sysupgrade_image(cpe510_partitions, parts, &len); ++ else ++ image = generate_factory_image(cpe510_vendor, sizeof(cpe510_vendor)-1, parts, &len); ++ ++ FILE *file = fopen(output, "wb"); ++ if (!file) ++ error(1, errno, "unable to open output file"); ++ ++ if (fwrite(image, len, 1, file) != 1) ++ error(1, 0, "unable to write output file"); ++ ++ fclose(file); ++ ++ free(image); ++ ++ size_t i; ++ for (i = 0; parts[i].name; i++) ++ free_image_partition(parts[i]); ++} ++ ++ ++/** Usage output */ ++void usage(const char *argv0) { ++ fprintf(stderr, ++ "Usage: %s [OPTIONS...]\n" ++ "\n" ++ "Options:\n" ++ " -B create image for the board specified with \n" ++ " -k read kernel image from the file \n" ++ " -r read rootfs image from the file \n" ++ " -o write output to the file \n" ++ " -V sets the revision number to \n" ++ " -j add jffs2 end-of-filesystem markers\n" ++ " -S create sysupgrade instead of factory image\n" ++ " -h show this help\n", ++ argv0 ++ ); ++}; ++ ++ ++int main(int argc, char *argv[]) { ++ const char *board = NULL, *kernel_image = NULL, *rootfs_image = NULL, *output = NULL; ++ bool add_jffs2_eof = false, sysupgrade = false; ++ unsigned rev = 0; ++ ++ while (true) { ++ int c; ++ ++ c = getopt(argc, argv, "B:k:r:o:V:jSh"); ++ if (c == -1) ++ break; ++ ++ switch (c) { ++ case 'B': ++ board = optarg; ++ break; ++ ++ case 'k': ++ kernel_image = optarg; ++ break; ++ ++ case 'r': ++ rootfs_image = optarg; ++ break; ++ ++ case 'o': ++ output = optarg; ++ break; ++ ++ case 'V': ++ sscanf(optarg, "r%u", &rev); ++ break; ++ ++ case 'j': ++ add_jffs2_eof = true; ++ break; ++ ++ case 'S': ++ sysupgrade = true; ++ break; ++ ++ case 'h': ++ usage(argv[0]); ++ return 0; ++ ++ default: ++ usage(argv[0]); ++ return 1; ++ } ++ } ++ ++ if (!board) ++ error(1, 0, "no board has been specified"); ++ if (!kernel_image) ++ error(1, 0, "no kernel image has been specified"); ++ if (!rootfs_image) ++ error(1, 0, "no rootfs image has been specified"); ++ if (!output) ++ error(1, 0, "no output filename has been specified"); ++ ++ if (strcmp(board, "CPE510") == 0) ++ do_cpe510(output, kernel_image, rootfs_image, rev, add_jffs2_eof, sysupgrade); ++ else ++ error(1, 0, "unsupported board %s", board); ++ ++ return 0; ++} diff --git a/patches/openwrt/0006-ar71xx-add-support-for-TP-LINK-CPE210-220-510-520.patch b/patches/openwrt/0006-ar71xx-add-support-for-TP-LINK-CPE210-220-510-520.patch new file mode 100644 index 00000000..1673562f --- /dev/null +++ b/patches/openwrt/0006-ar71xx-add-support-for-TP-LINK-CPE210-220-510-520.patch @@ -0,0 +1,471 @@ +From: Matthias Schiffer +Date: Wed, 26 Nov 2014 19:57:50 +0100 +Subject: ar71xx: add support for TP-LINK CPE210/220/510/520 + +This adds support for the TP-LINK CPE210/220/510/520 (Pharos series). These +devices are very similar to the Ubiquiti NanoStations, but with better specs: +faster CPU, more RAM, 2x2 MIMO. + +Signed-off-by: Matthias Schiffer + +diff --git a/target/linux/ar71xx/base-files/etc/diag.sh b/target/linux/ar71xx/base-files/etc/diag.sh +index 1864b11..4b510dd 100755 +--- a/target/linux/ar71xx/base-files/etc/diag.sh ++++ b/target/linux/ar71xx/base-files/etc/diag.sh +@@ -43,6 +43,9 @@ get_status_led() { + cap4200ag) + status_led="senao:green:pwr" + ;; ++ cpe510) ++ status_led="tp-link:green:link4" ++ ;; + db120) + status_led="db120:green:status" + ;; +diff --git a/target/linux/ar71xx/base-files/etc/uci-defaults/01_leds b/target/linux/ar71xx/base-files/etc/uci-defaults/01_leds +index d3b766d..fb8df40 100755 +--- a/target/linux/ar71xx/base-files/etc/uci-defaults/01_leds ++++ b/target/linux/ar71xx/base-files/etc/uci-defaults/01_leds +@@ -61,6 +61,16 @@ carambola2) + ucidef_set_led_wlan "wlan" "WLAN" "carambola2:green:wlan" "phy0tpt" + ;; + ++cpe510) ++ ucidef_set_led_switch "lan0" "LAN0" "tp-link:green:lan0" "switch0" "0x20" ++ ucidef_set_led_switch "lan1" "LAN1" "tp-link:green:lan1" "switch0" "0x10" ++ ucidef_set_rssimon "wlan0" "40000" "1" ++ ucidef_set_led_rssi "rssilow" "RSSILOW" "tp-link:green:link1" "wlan0" "1" "100" "0" "13" ++ ucidef_set_led_rssi "rssimediumlow" "RSSIMEDIUMLOW" "tp-link:green:link2" "wlan0" "26" "100" "-25" "13" ++ ucidef_set_led_rssi "rssimediumhigh" "RSSIMEDIUMHIGH" "tp-link:green:link3" "wlan0" "51" "100" "-50" "13" ++ ucidef_set_led_rssi "rssihigh" "RSSIHIGH" "tp-link:green:link4" "wlan0" "76" "100" "-75" "13" ++ ;; ++ + db120) + ucidef_set_led_usbdev "usb" "USB" "db120:green:usb" "1-1" + ;; +diff --git a/target/linux/ar71xx/base-files/etc/uci-defaults/02_network b/target/linux/ar71xx/base-files/etc/uci-defaults/02_network +index c5cfd67..a9f00fa 100755 +--- a/target/linux/ar71xx/base-files/etc/uci-defaults/02_network ++++ b/target/linux/ar71xx/base-files/etc/uci-defaults/02_network +@@ -62,6 +62,13 @@ tl-wdr4900-v2) + ucidef_add_switch_vlan "switch0" "2" "1 6" + ;; + ++cpe510) ++ ucidef_set_interfaces_lan_wan "eth0.1" "eth0.2" ++ ucidef_add_switch "switch0" "1" "1" ++ ucidef_add_switch_vlan "switch0" "1" "0t 5" ++ ucidef_add_switch_vlan "switch0" "2" "0t 4" ++ ;; ++ + db120 |\ + rb-2011l | \ + rb-2011uas |\ +diff --git a/target/linux/ar71xx/base-files/lib/ar71xx.sh b/target/linux/ar71xx/base-files/lib/ar71xx.sh +index 5aceaee..0b0a8d6 100755 +--- a/target/linux/ar71xx/base-files/lib/ar71xx.sh ++++ b/target/linux/ar71xx/base-files/lib/ar71xx.sh +@@ -229,6 +229,39 @@ tplink_board_detect() { + AR71XX_MODEL="$model $hwver" + } + ++tplink_pharos_get_model_string() { ++ local part ++ part=$(find_mtd_part 'product-info') ++ [ -z "$part" ] && return 1 ++ ++ # The returned string will end with \r\n, but we don't remove it here ++ # to simplify matching against it in the sysupgrade image check ++ dd if=$part bs=1 skip=4360 2>/dev/null | head -n 1 ++} ++ ++tplink_pharos_board_detect() { ++ local model_string="$(tplink_pharos_get_model_string | tr -d '\r')" ++ local oIFS="$IFS"; IFS=":"; set -- $model_string; IFS="$oIFS" ++ local model ++ ++ case "$1" in ++ 'CPE210(TP-LINK|UN|N300-2)') ++ model='TP-Link CPE210' ++ ;; ++ 'CPE220(TP-LINK|UN|N300-2)') ++ model='TP-Link CPE220' ++ ;; ++ 'CPE510(TP-LINK|UN|N300-5)') ++ model='TP-Link CPE510' ++ ;; ++ 'CPE520(TP-LINK|UN|N300-5)') ++ model='TP-Link CPE520' ++ ;; ++ esac ++ ++ [ -n "$model" ] && AR71XX_MODEL="$model v$2" ++} ++ + ar71xx_board_detect() { + local machine + local name +@@ -302,6 +335,10 @@ ar71xx_board_detect() { + *CAP4200AG) + name="cap4200ag" + ;; ++ *"CPE210/220/510/520") ++ name="cpe510" ++ tplink_pharos_board_detect ++ ;; + *"DB120 reference board") + name="db120" + ;; +@@ -751,11 +788,8 @@ ar71xx_board_detect() { + ;; + esac + +- case "$machine" in +- *TL-WR* | *TL-WA* | *TL-MR* | *TL-WD* | *Archer*) ++ [ -z "$AR71XX_MODEL" ] && [ "${machine:0:8}" = 'TP-LINK ' ] && \ + tplink_board_detect "$machine" +- ;; +- esac + + [ -z "$name" ] && name="unknown" + +diff --git a/target/linux/ar71xx/base-files/lib/upgrade/platform.sh b/target/linux/ar71xx/base-files/lib/upgrade/platform.sh +index 846954c..15e998c 100755 +--- a/target/linux/ar71xx/base-files/lib/upgrade/platform.sh ++++ b/target/linux/ar71xx/base-files/lib/upgrade/platform.sh +@@ -70,6 +70,33 @@ tplink_get_image_boot_size() { + get_image "$@" | dd bs=4 count=1 skip=37 2>/dev/null | hexdump -v -n 4 -e '1/1 "%02x"' + } + ++tplink_pharos_check_image() { ++ local magic_long="$(get_magic_long "$1")" ++ [ "$magic_long" != "7f454c46" ] && { ++ echo "Invalid image magic '$magic_long'" ++ return 1 ++ } ++ ++ local model_string="$(tplink_pharos_get_model_string)" ++ local line ++ ++ # Here $1 is given to dd directly instead of get_image as otherwise the skip ++ # will take almost a second (as dd can't seek then) ++ # ++ # This will fail if the image isn't local, but that's fine: as the ++ # read loop won't be executed at all, it will return true, so the image ++ # is accepted (loading the first 1.5M of a remote image for this check seems ++ # a bit extreme) ++ dd if="$1" bs=1 skip=1511432 count=1024 2>/dev/null | while read line; do ++ [ "$line" == "$model_string" ] && break ++ done || { ++ echo "Unsupported image (model not in support-list)" ++ return 1 ++ } ++ ++ return 0 ++} ++ + seama_get_type_magic() { + get_image "$@" | dd bs=1 count=4 skip=53 2>/dev/null | hexdump -v -n 4 -e '1/1 "%02x"' + } +@@ -214,6 +241,11 @@ platform_check_image() { + return 0 + ;; + ++ cpe510) ++ tplink_pharos_check_image "$1" && return 0 ++ return 1 ++ ;; ++ + dir-825-b1 | \ + tew-673gru) + dir825b_check_image "$1" && return 0 +diff --git a/target/linux/ar71xx/config-3.10 b/target/linux/ar71xx/config-3.10 +index 9a8378a..2f05ec6 100644 +--- a/target/linux/ar71xx/config-3.10 ++++ b/target/linux/ar71xx/config-3.10 +@@ -39,6 +39,7 @@ CONFIG_ATH79_MACH_AW_NR580=y + CONFIG_ATH79_MACH_BHU_BXU2000N2_A=y + CONFIG_ATH79_MACH_CAP4200AG=y + CONFIG_ATH79_MACH_CARAMBOLA2=y ++CONFIG_ATH79_MACH_CPE510=y + CONFIG_ATH79_MACH_DB120=y + CONFIG_ATH79_MACH_DIR_505_A1=y + CONFIG_ATH79_MACH_DIR_600_A1=y +diff --git a/target/linux/ar71xx/files/arch/mips/ath79/mach-cpe510.c b/target/linux/ar71xx/files/arch/mips/ath79/mach-cpe510.c +new file mode 100644 +index 0000000..8bf5c0f +--- /dev/null ++++ b/target/linux/ar71xx/files/arch/mips/ath79/mach-cpe510.c +@@ -0,0 +1,107 @@ ++/* ++ * TP-LINK CPE210/220/510/520 board support ++ * ++ * Copyright (C) 2014 Matthias Schiffer ++ * ++ * 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 ++#include ++ ++#include ++#include ++ ++#include "common.h" ++#include "dev-eth.h" ++#include "dev-gpio-buttons.h" ++#include "dev-leds-gpio.h" ++#include "dev-m25p80.h" ++#include "dev-wmac.h" ++#include "machtypes.h" ++ ++ ++#define CPE510_GPIO_LED_LAN0 11 ++#define CPE510_GPIO_LED_LAN1 12 ++#define CPE510_GPIO_LED_L1 13 ++#define CPE510_GPIO_LED_L2 14 ++#define CPE510_GPIO_LED_L3 15 ++#define CPE510_GPIO_LED_L4 16 ++ ++#define CPE510_GPIO_BTN_RESET 4 ++ ++#define CPE510_KEYS_POLL_INTERVAL 20 /* msecs */ ++#define CPE510_KEYS_DEBOUNCE_INTERVAL (3 * CPE510_KEYS_POLL_INTERVAL) ++ ++ ++static struct gpio_led cpe510_leds_gpio[] __initdata = { ++ { ++ .name = "tp-link:green:lan0", ++ .gpio = CPE510_GPIO_LED_LAN0, ++ .active_low = 1, ++ }, { ++ .name = "tp-link:green:lan1", ++ .gpio = CPE510_GPIO_LED_LAN1, ++ .active_low = 1, ++ }, { ++ .name = "tp-link:green:link1", ++ .gpio = CPE510_GPIO_LED_L1, ++ .active_low = 1, ++ }, { ++ .name = "tp-link:green:link2", ++ .gpio = CPE510_GPIO_LED_L2, ++ .active_low = 1, ++ }, { ++ .name = "tp-link:green:link3", ++ .gpio = CPE510_GPIO_LED_L3, ++ .active_low = 1, ++ }, { ++ .name = "tp-link:green:link4", ++ .gpio = CPE510_GPIO_LED_L4, ++ .active_low = 1, ++ }, ++}; ++ ++static struct gpio_keys_button cpe510_gpio_keys[] __initdata = { ++ { ++ .desc = "Reset button", ++ .type = EV_KEY, ++ .code = KEY_RESTART, ++ .debounce_interval = CPE510_KEYS_DEBOUNCE_INTERVAL, ++ .gpio = CPE510_GPIO_BTN_RESET, ++ .active_low = 1, ++ } ++}; ++ ++ ++static void __init cpe510_setup(void) ++{ ++ u8 *mac = (u8 *) KSEG1ADDR(0x1f830008); ++ u8 *ee = (u8 *) KSEG1ADDR(0x1fff1000); ++ ++ /* Disable JTAG, enabling GPIOs 0-3 */ ++ /* Configure OBS4 line, for GPIO 4*/ ++ ath79_gpio_function_setup(AR934X_GPIO_FUNC_JTAG_DISABLE, ++ AR934X_GPIO_FUNC_CLK_OBS4_EN); ++ ++ ath79_register_leds_gpio(-1, ARRAY_SIZE(cpe510_leds_gpio), ++ cpe510_leds_gpio); ++ ++ ath79_register_gpio_keys_polled(1, CPE510_KEYS_POLL_INTERVAL, ++ ARRAY_SIZE(cpe510_gpio_keys), ++ cpe510_gpio_keys); ++ ++ ath79_register_m25p80(NULL); ++ ++ ath79_register_mdio(1, 0); ++ ath79_init_mac(ath79_eth1_data.mac_addr, mac, 0); ++ ath79_eth1_data.phy_if_mode = PHY_INTERFACE_MODE_GMII; ++ ath79_register_eth(1); ++ ++ ath79_register_wmac(ee, mac); ++} ++ ++MIPS_MACHINE(ATH79_MACH_CPE510, "CPE510", "TP-LINK CPE210/220/510/520", ++ cpe510_setup); +diff --git a/target/linux/ar71xx/generic/profiles/tp-link.mk b/target/linux/ar71xx/generic/profiles/tp-link.mk +index 78333be..a9d170c 100644 +--- a/target/linux/ar71xx/generic/profiles/tp-link.mk ++++ b/target/linux/ar71xx/generic/profiles/tp-link.mk +@@ -16,6 +16,17 @@ endef + $(eval $(call Profile,ARCHERC7)) + + ++define Profile/CPE510 ++ NAME:=TP-LINK CPE210/220/510/520 ++ PACKAGES:=rssileds ++endef ++ ++define Profile/CPE510/Description ++ Package set optimized for the TP-LINK CPE210/220/510/520. ++endef ++$(eval $(call Profile,CPE510)) ++ ++ + define Profile/TLMR10U + NAME:=TP-LINK TL-MR10U + PACKAGES:=kmod-usb-core kmod-usb2 +diff --git a/target/linux/ar71xx/image/Makefile b/target/linux/ar71xx/image/Makefile +index 683c238..5ff7f35 100644 +--- a/target/linux/ar71xx/image/Makefile ++++ b/target/linux/ar71xx/image/Makefile +@@ -261,6 +261,7 @@ cameo_ap121_mtdlayout_8M=mtdparts=spi0.0:64k(u-boot)ro,64k(art)ro,64k(mac)ro,64k + cameo_db120_mtdlayout=mtdparts=spi0.0:64k(uboot)ro,64k(nvram)ro,15936k(firmware),192k(lang)ro,64k(mac)ro,64k(art)ro + cameo_db120_mtdlayout_8M=mtdparts=spi0.0:64k(uboot)ro,64k(nvram)ro,7872k(firmware),128k(lang)ro,64k(art)ro + cap4200ag_mtdlayout=mtdparts=spi0.0:256k(u-boot),64k(u-boot-env),320k(custom)ro,1536k(kernel),12096k(rootfs),2048k(failsafe),64k(art),13632k@0xa0000(firmware) ++cpe510_mtdlayout=mtdparts=spi0.0:128k(u-boot)ro,64k(pation-table)ro,64k(product-info)ro,1536k(kernel),6144k(rootfs),192k(config)ro,64k(ART)ro,7680k@0x40000(firmware) + eap300v2_mtdlayout=mtdparts=spi0.0:256k(u-boot)ro,64k(u-boot-env),320k(custom),13632k(firmware),2048k(failsafe),64k(art)ro + db120_mtdlayout=mtdparts=spi0.0:256k(u-boot)ro,64k(u-boot-env)ro,6336k(rootfs),1408k(kernel),64k(nvram),64k(art)ro,7744k@0x50000(firmware) + cameo_ap94_mtdlayout=mtdparts=spi0.0:256k(uboot)ro,64k(config)ro,6208k(firmware),64k(caldata)ro,1600k(unknown)ro,64k@0x7f0000(caldata_copy) +@@ -811,6 +812,32 @@ define Image/Build/TPLINK-LZMA/initramfs + endef + + ++Image/Build/TPLINK-SAFELOADER/buildkernel=$(call PatchKernelLzma,$(2),$(3) $(4)) ++ ++define Image/Build/TPLINK-SAFELOADER ++ -rm -rf $(KDIR)/lzma-loader ++ $(LOADER_MAKE) LOADER=loader-$(2).elf\ ++ LZMA_TEXT_START=0x80a00000 LOADADDR=0x80060000 \ ++ LOADER_DATA="$(KDIR_TMP)/vmlinux-$(2).bin.lzma" BOARD="$(2)" \ ++ compile loader.elf ++ ++ -$(STAGING_DIR_HOST)/bin/tplink-safeloader \ ++ -B $(5) \ ++ -k $(KDIR)/loader-$(2).elf \ ++ -r $(KDIR)/root.$(1) \ ++ -V $(REVISION) \ ++ -j \ ++ -o $(call factoryname,$(1),$(2)) ++ -$(STAGING_DIR_HOST)/bin/tplink-safeloader \ ++ -B $(5) \ ++ -k $(KDIR)/loader-$(2).elf \ ++ -r $(KDIR)/root.$(1) \ ++ -V $(REVISION) \ ++ -j -S \ ++ -o $(call sysupname,$(1),$(2)) ++endef ++ ++ + define Image/Build/CyberTAN + echo -n '' > $(KDIR_TMP)/empty.bin + $(STAGING_DIR_HOST)/bin/trx -o $(KDIR)/image.tmp \ +@@ -1226,6 +1253,8 @@ $(eval $(call SingleProfile,TPLINK-LZMA,64kraw,TLWDR4310V1,tl-wdr4310-v1,TL-WDR4 + $(eval $(call SingleProfile,TPLINK-LZMA,64kraw,TLWDR4900V2,tl-wdr4900-v2,TL-WDR4900-v2,ttyS0,115200,0x49000002,1,8Mlzma)) + $(eval $(call SingleProfile,TPLINK-LZMA,64kraw,MW4530RV1,mw4530r-v1,TL-WDR4300,ttyS0,115200,0x45300001,1,8Mlzma)) + ++$(eval $(call SingleProfile,TPLINK-SAFELOADER,64kraw,CPE510,cpe210-220-510-520,CPE510,ttyS0,115200,$$(cpe510_mtdlayout),CPE510)) ++ + $(eval $(call SingleProfile,TPLINK-LZMA,64kraw,SMART-300,smart-300,SMART-300,ttyS0,115200,0x93410001,1,8Mlzma)) + + $(eval $(call SingleProfile,TPLINK-LZMA,64kraw,OOLITE,oolite,GS-OOLITE,ttyATH0,115200,0x3C000101,1,16Mlzma)) +diff --git a/target/linux/ar71xx/patches-3.10/610-MIPS-ath79-openwrt-machines.patch b/target/linux/ar71xx/patches-3.10/610-MIPS-ath79-openwrt-machines.patch +index 3669f26..516d52d 100644 +--- a/target/linux/ar71xx/patches-3.10/610-MIPS-ath79-openwrt-machines.patch ++++ b/target/linux/ar71xx/patches-3.10/610-MIPS-ath79-openwrt-machines.patch +@@ -1,6 +1,6 @@ + --- a/arch/mips/ath79/machtypes.h + +++ b/arch/mips/ath79/machtypes.h +-@@ -16,22 +16,144 @@ ++@@ -16,22 +16,145 @@ + + enum ath79_mach_type { + ATH79_MACH_GENERIC = 0, +@@ -24,6 +24,7 @@ + + ATH79_MACH_BHU_BXU2000N2_A1, /* BHU BXU2000n-2 A1 */ + + ATH79_MACH_CAP4200AG, /* Senao CAP4200AG */ + + ATH79_MACH_CARAMBOLA2, /* 8devices Carambola2 */ +++ ATH79_MACH_CPE510, /* TP-LINK CPE510 */ + ATH79_MACH_DB120, /* Atheros DB120 reference board */ + ATH79_MACH_PB44, /* Atheros PB44 reference board */ + + ATH79_MACH_DIR_505_A1, /* D-Link DIR-505 rev. A1 */ +@@ -209,7 +210,7 @@ + config ATH79_MACH_AP121 + bool "Atheros AP121 reference board" + select SOC_AR933X +-@@ -9,64 +64,736 @@ config ATH79_MACH_AP121 ++@@ -9,64 +64,745 @@ config ATH79_MACH_AP121 + select ATH79_DEV_GPIO_BUTTONS + select ATH79_DEV_LEDS_GPIO + select ATH79_DEV_M25P80 +@@ -709,6 +710,15 @@ + + -config ATH79_MACH_AP81 + - bool "Atheros AP81 reference board" +++config ATH79_MACH_CPE510 +++ bool "TP-LINK CPE510 support" +++ select SOC_AR934X +++ select ATH79_DEV_ETH +++ select ATH79_DEV_GPIO_BUTTONS +++ select ATH79_DEV_LEDS_GPIO +++ select ATH79_DEV_M25P80 +++ select ATH79_DEV_WMAC +++ + +config ATH79_MACH_TL_MR11U + + bool "TP-LINK TL-MR11U/TL-MR3040 support" + + select SOC_AR933X +@@ -972,7 +982,7 @@ + + config ATH79_MACH_UBNT_XM + bool "Ubiquiti Networks XM/UniFi boards" +-@@ -83,6 +810,65 @@ config ATH79_MACH_UBNT_XM ++@@ -83,6 +819,65 @@ config ATH79_MACH_UBNT_XM + Say 'Y' here if you want your kernel to support the + Ubiquiti Networks XM (rev 1.0) board. + +@@ -1038,7 +1048,7 @@ + endmenu + + config SOC_AR71XX +-@@ -132,7 +918,10 @@ config ATH79_DEV_DSA ++@@ -132,7 +927,10 @@ config ATH79_DEV_DSA + config ATH79_DEV_ETH + def_bool n + +@@ -1050,7 +1060,7 @@ + def_bool n + + config ATH79_DEV_GPIO_BUTTONS +-@@ -164,4 +953,7 @@ config ATH79_PCI_ATH9K_FIXUP ++@@ -164,4 +962,7 @@ config ATH79_PCI_ATH9K_FIXUP + config ATH79_ROUTERBOOT + def_bool n + +@@ -1060,7 +1070,7 @@ + endif + --- a/arch/mips/ath79/Makefile + +++ b/arch/mips/ath79/Makefile +-@@ -38,9 +38,90 @@ obj-$(CONFIG_ATH79_ROUTERBOOT) += route ++@@ -38,9 +38,91 @@ obj-$(CONFIG_ATH79_ROUTERBOOT) += route + # + # Machines + # +@@ -1079,6 +1089,7 @@ + +obj-$(CONFIG_ATH79_MACH_AW_NR580) += mach-aw-nr580.o + +obj-$(CONFIG_ATH79_MACH_BHU_BXU2000N2_A)+= mach-bhu-bxu2000n2-a.o + +obj-$(CONFIG_ATH79_MACH_CAP4200AG) += mach-cap4200ag.o +++obj-$(CONFIG_ATH79_MACH_CPE510) += mach-cpe510.o + obj-$(CONFIG_ATH79_MACH_DB120) += mach-db120.o + +obj-$(CONFIG_ATH79_MACH_DIR_505_A1) += mach-dir-505-a1.o + +obj-$(CONFIG_ATH79_MACH_DIR_600_A1) += mach-dir-600-a1.o diff --git a/targets/ar71xx-generic/kernel-config b/targets/ar71xx-generic/kernel-config index b216d158..2c97a96d 100644 --- a/targets/ar71xx-generic/kernel-config +++ b/targets/ar71xx-generic/kernel-config @@ -68,6 +68,7 @@ CONFIG_ATH79_MACH_AP136=y CONFIG_ATH79_MACH_AP81=y CONFIG_ATH79_MACH_AP83=y CONFIG_ATH79_MACH_AP96=y +CONFIG_ATH79_MACH_CPE510=y CONFIG_ATH79_MACH_DB120=y CONFIG_ATH79_MACH_PB42=y CONFIG_ATH79_MACH_PB44=y diff --git a/targets/ar71xx-generic/profiles.mk b/targets/ar71xx-generic/profiles.mk index de63e7cc..7f82dae5 100644 --- a/targets/ar71xx-generic/profiles.mk +++ b/targets/ar71xx-generic/profiles.mk @@ -2,6 +2,13 @@ ## TP-Link +# CPE210/220/510/520 +$(eval $(call GluonProfile,CPE510,rssileds)) +$(eval $(call GluonModel,CPE510,cpe210-220-510-520-squashfs,tp-link-cpe210-v1.0)) +$(eval $(call GluonModel,CPE510,cpe210-220-510-520-squashfs,tp-link-cpe220-v1.0)) +$(eval $(call GluonModel,CPE510,cpe210-220-510-520-squashfs,tp-link-cpe510-v1.0)) +$(eval $(call GluonModel,CPE510,cpe210-220-510-520-squashfs,tp-link-cpe520-v1.0)) + # TL-WR703N v1 $(eval $(call GluonProfile,TLWR703)) $(eval $(call GluonModel,TLWR703,tl-wr703n-v1-squashfs,tp-link-tl-wr703n-v1))