ar71xx: Add support for Cisco-Linksys WAP4410N
authorJohn Crispin <john@openwrt.org>
Tue, 7 Jul 2015 18:06:39 +0000 (18:06 +0000)
committerJohn Crispin <john@openwrt.org>
Tue, 7 Jul 2015 18:06:39 +0000 (18:06 +0000)
This patch adds support for the Cisco WAP4410N, an access point that uses the
AR9132 SoC. Web upgrades from stock are not yet possible, UART access required
for the initial flash.

Signed-off-by: Ryan A Young <rayoung@utexas.edu>
SVN-Revision: 46250

target/linux/ar71xx/base-files/etc/diag.sh
target/linux/ar71xx/base-files/etc/uci-defaults/02_network
target/linux/ar71xx/base-files/lib/ar71xx.sh
target/linux/ar71xx/base-files/lib/upgrade/platform.sh
target/linux/ar71xx/config-3.18
target/linux/ar71xx/files/arch/mips/ath79/mach-wap4410n.c [new file with mode: 0644]
target/linux/ar71xx/generic/profiles/linksys.mk
target/linux/ar71xx/image/Makefile

index 0bcb2733594761352d6182c39b7d138e576c2929..ce2b9bad50945898e9711b044a52a715f8103830 100644 (file)
@@ -328,6 +328,9 @@ get_status_led() {
        wrt400n)
                status_led="wrt400n:blue:wps"
                ;;
        wrt400n)
                status_led="wrt400n:blue:wps"
                ;;
+       wap4410n)
+               status_led="wrt4410n:green:power"
+               ;;
        wrt160nl)
                status_led="wrt160nl:blue:wps"
                ;;
        wrt160nl)
                status_led="wrt160nl:blue:wps"
                ;;
index ea19de9087e467d6b5b0864bda0745a566a28087..51095a9a5e16ee61cf1894977d4fdeb366a7344f 100755 (executable)
@@ -341,6 +341,7 @@ tl-wa901nd-v3 |\
 tl-wr703n |\
 tube2h |\
 wndap360 |\
 tl-wr703n |\
 tube2h |\
 wndap360 |\
+wap4410n |\
 mynet-rext |\
 wp543)
        ucidef_set_interface_lan "eth0"
 mynet-rext |\
 wp543)
        ucidef_set_interface_lan "eth0"
index 9943d6918a0ec1c6c107da6c0bba8d8e721a6429..dd13948c40d616fbfa1bc76f258acc0d838b8f81 100755 (executable)
@@ -880,6 +880,9 @@ ar71xx_board_detect() {
        *WRT400N)
                name="wrt400n"
                ;;
        *WRT400N)
                name="wrt400n"
                ;;
+       *WAP4410N)
+               name="wap4410n"
+               ;;
        *"WZR-450HP2")
                name="wzr-450hp2"
                ;;
        *"WZR-450HP2")
                name="wzr-450hp2"
                ;;
index 37a2e7b0ee118780166c1af3c856691b6a9cd2af..73d8b0d7f64b6c88b5c657e25414d2d7aa0c4c57 100755 (executable)
@@ -233,6 +233,7 @@ platform_check_image() {
        nanostation-m-xw | \
        rw2458n | \
        wpj531 | \
        nanostation-m-xw | \
        rw2458n | \
        wpj531 | \
+       wap4410n | \
        wndap360 | \
        wpj344 | \
        wzr-hp-g300nh2 | \
        wndap360 | \
        wpj344 | \
        wzr-hp-g300nh2 | \
index 0680dd0440dd47cfe227537b9a2467798156351b..02857d5d2de5cacfbe5893b1146fb5e35318b0e4 100644 (file)
@@ -148,6 +148,7 @@ CONFIG_ATH79_MACH_WPJ531=y
 CONFIG_ATH79_MACH_WPJ558=y
 CONFIG_ATH79_MACH_WRT160NL=y
 CONFIG_ATH79_MACH_WRT400N=y
 CONFIG_ATH79_MACH_WPJ558=y
 CONFIG_ATH79_MACH_WRT160NL=y
 CONFIG_ATH79_MACH_WRT400N=y
+CONFIG_ATH79_MACH_WAP4410N=y
 CONFIG_ATH79_MACH_WZR_450HP2=y
 CONFIG_ATH79_MACH_WZR_HP_AG300H=y
 CONFIG_ATH79_MACH_WZR_HP_G300NH=y
 CONFIG_ATH79_MACH_WZR_450HP2=y
 CONFIG_ATH79_MACH_WZR_HP_AG300H=y
 CONFIG_ATH79_MACH_WZR_HP_G300NH=y
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/mach-wap4410n.c b/target/linux/ar71xx/files/arch/mips/ath79/mach-wap4410n.c
new file mode 100644 (file)
index 0000000..f2cf071
--- /dev/null
@@ -0,0 +1,285 @@
+/*
+ *  Cisco WAP4410N board support
+ *
+ *  Copyright (C) 2014 Caleb James DeLisle <cjd@cjdns.fr>
+ *  Copyright (C) 2015 Ryan A Young <rayoung@utexas.edu>
+ *
+ *  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, or (at your option) any later version.
+ */
+#include <linux/platform_device.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <linux/mtd/physmap.h>
+#include <linux/nxp_74hc153.h>
+
+#include <asm/mach-ath79/ath79.h>
+
+#include "dev-eth.h"
+#include "dev-gpio-buttons.h"
+#include "dev-leds-gpio.h"
+#include "dev-usb.h"
+#include "dev-wmac.h"
+#include "machtypes.h"
+
+/* -------------- begin flash device -------------- */
+
+#define FLASH_BASE 0xbf000000
+
+/* where the actual art data is within the art partition. */
+#define ART_DATA_OFFSET 0x1000
+
+/* If changed, make sure to change image/Makefile too! */
+#define KERN_SIZE 0x190000
+
+/* Flash layout: u-boot/include/upgrade.h in cisco's GPL dump */
+#define FLASH_SIZE                     (0x800000)
+#define BOOT_SIZE                      (0x40000)
+#define NVRAM_SIZE                     (0x10000)
+#define ART_SIZE                       (0x10000)
+/*
+ * Note that this is different from upgrade.h, in which ENV_SIZE is 0x10000.
+ * This is because the sercomm header is located in the upper end of the root
+ * section instead of the env section, and it must not be overwritten by rootfs.
+ */
+#define ENV_SIZE                       (0x20000)
+
+#define NODE_INFO_OFFSET (BOOT_SIZE - 0x90)
+struct wap4410n_node_info {
+       /** Serial number written on back of device. */
+       char serial_no[16];
+
+       /** Internal to Sercomm (?), France = { domain: 0x80, country: 0x00 } */
+       uint8_t domain;
+       uint8_t country;
+
+       /** written on the board, eg: 13 */
+       uint8_t hw_ver;
+
+       uint8_t zero0[5];
+
+       /** ASCII numeric digits */
+       char wps_pin[8];
+
+       uint8_t zero1[16];
+
+       uint8_t mac_addr[6];
+
+       uint8_t zero2[3];
+
+       /** 31734572436f4d6d -> "1sErCoMm" does not seem to be checked. */
+       char magic_1sErCoMm[8];
+
+       /** 00010000 (offset 0x41, completely unaligned) */
+       uint8_t unknown0[4];
+
+       /** Used by upslug2 protocol */
+       uint8_t hardware_id[32];
+
+       /** 0000240800008000000000030000200400000008 */
+       uint8_t unknown1[20];
+
+       /** 734572436f4d6d -> "sErCoMm" */
+       uint8_t magic_sErCoMm[7];
+
+       uint8_t zero3[16];
+};
+
+#define UPGRADE_INFO_OFFSET    0x7dfff0
+struct wap4410n_upgrade_info {
+       /** Stock WAP4410: 2408 */
+       uint16_t product_id;
+
+       /** Always 8000 */
+       uint16_t protocol;
+
+       /** 2007 -> v2.0.7.x */
+       uint16_t fw_version;
+
+       /** 90f7 same value as NSLU2 */
+       uint16_t unknown0;
+
+       /** bootloader checks this and will "soft brick" if it's not correct. */
+       uint8_t eRcOmM[6];
+
+       uint8_t pad[2];
+};
+
+/*
+ * An instruction in the bootloader which checks that 0x7dfff8 == "eRcOmM" and
+ * bricks if it's not.
+ * If this instruction is overwritten with a zero, you get 64k of extra space.
+ * 2406 0006 1440 000a 8fbc 0020 <-- unpatched
+ * 2406 0006 0000 0000 8fbc 0020 <-- patched
+ */
+#define SERCOMM_CHECK_LAST_INSN   0x24060006
+#define SERCOMM_CHECK_INSN_OFFSET 0x19e08
+#define SERCOMM_CHECK_NEXT_INSN   0x8fbc0020
+
+
+/* Little bit of arithmatic on the flash layout. */
+#define NVRAM_OFFSET BOOT_SIZE
+#define KERN_OFFSET (NVRAM_OFFSET + NVRAM_SIZE)
+#define ROOT_OFFSET (KERN_OFFSET + KERN_SIZE)
+#define ART_OFFSET (FLASH_SIZE - ART_SIZE)
+#define ENV_OFFSET (ART_OFFSET - ENV_SIZE)
+/* rootfs is whatever is left. */
+#define ROOT_SIZE (ENV_OFFSET - ROOT_OFFSET)
+
+#define PART(b, s, n, f) { .name = n, .offset = b, .size = s, .mask_flags = f }
+static struct mtd_partition wap4410n_flash_partitions[] = {
+       PART(0x00000000,   BOOT_SIZE,  "u-boot",         MTD_WRITEABLE),
+       PART(NVRAM_OFFSET, NVRAM_SIZE, "u-boot-env", MTD_WRITEABLE),
+       PART(KERN_OFFSET,  KERN_SIZE,  "kernel",         0),
+       PART(ROOT_OFFSET,  ROOT_SIZE,  "rootfs",         0),
+       PART(ENV_OFFSET,   ENV_SIZE,   "sercomm",       MTD_WRITEABLE),
+       PART(ART_OFFSET,   ART_SIZE,   "art",           MTD_WRITEABLE),
+
+       /* Pseudo-partition over whole upgradable space, used by sysupgrade. */
+       PART(KERN_OFFSET, KERN_SIZE + ROOT_SIZE, "firmware", 0)
+};
+#undef PART
+
+static struct physmap_flash_data wap4410n_flash_data = {
+       .width          = 2,
+       .parts          = wap4410n_flash_partitions,
+       .nr_parts       = ARRAY_SIZE(wap4410n_flash_partitions),
+};
+
+static struct resource wap4410n_flash_resources[] = {
+       [0] = {
+               .start  = FLASH_BASE,
+               .end    = FLASH_BASE + FLASH_SIZE - 1,
+               .flags  = IORESOURCE_MEM,
+       },
+};
+
+static struct platform_device wap4410n_flash_device = {
+       .name              = "physmap-flash",
+       .id                      = -1,
+       .resource               = wap4410n_flash_resources,
+       .num_resources  = ARRAY_SIZE(wap4410n_flash_resources),
+       .dev                    = { .platform_data = &wap4410n_flash_data }
+};
+
+
+static void __init wap4410n_flash_reg(void)
+{
+       uint32_t *insn = (uint32_t *) (FLASH_BASE + SERCOMM_CHECK_INSN_OFFSET);
+       int i;
+       if (SERCOMM_CHECK_LAST_INSN != insn[-1] ||
+               SERCOMM_CHECK_NEXT_INSN != insn[1]) {
+               printk(KERN_INFO "Unrecognized bootloader, costs 64k storage");
+       } else if (insn[0]) {
+               printk(KERN_INFO "eRcOmM check at %p in uboot, costs 64k storage",
+                               (void *)insn);
+       } else {
+               printk(KERN_INFO "eRcOmM check at %p patched, gain 64k storage",
+                               (void *)insn);
+               wap4410n_flash_partitions[3].size +=
+                       wap4410n_flash_partitions[4].size;
+               wap4410n_flash_data.nr_parts--;
+               for (i = 4; i < wap4410n_flash_data.nr_parts; i++) {
+                       memcpy(&wap4410n_flash_partitions[i],
+                                  &wap4410n_flash_partitions[i + 1],
+                                  sizeof(struct mtd_partition));
+               }
+       }
+       platform_device_register(&wap4410n_flash_device);
+}
+
+/* -------------- end flash device -------------- */
+
+
+/* -------------------- GPIO -------------------- */
+
+#define LED_WIRELESS                     0
+#define LED_POWER                               1
+#define KEYS_POLL_INTERVAL             20      /* msecs */
+#define KEYS_DEBOUNE_INTERVAL  (3 * KEYS_POLL_INTERVAL)
+
+/* 2 lights are gpio, other 2 are hardwired. */
+static struct gpio_led wap4410n_leds_gpio[] __initdata = {
+       {
+               .name           = "wrt4410n:green:power",
+               .gpio           = LED_POWER,
+               .active_low  = 1,
+       },
+       {
+               .name           = "wrt4410n:green:wireless",
+               .gpio           = LED_WIRELESS,
+               .active_low  = 1,
+       },
+};
+
+static struct gpio_keys_button wap4410n_gpio_keys[] __initdata = {
+       {
+               .desc           = "reset",
+               .type           = EV_KEY,
+               .code           = KEY_RESTART,
+               .debounce_interval = KEYS_DEBOUNE_INTERVAL,
+               .gpio           = 21,
+               .active_low  = 1,
+       }
+};
+
+static void __init wap4410n_gpio_reg(void)
+{
+       ath79_register_gpio_keys_polled(
+               -1,
+               KEYS_POLL_INTERVAL,
+               ARRAY_SIZE(wap4410n_gpio_keys),
+               wap4410n_gpio_keys
+       );
+       ath79_register_leds_gpio(
+               -1,
+                ARRAY_SIZE(wap4410n_leds_gpio),
+                wap4410n_leds_gpio
+       );
+}
+
+/* -------------------- end GPIO -------------------- */
+
+/** Never called, just for build time verification. */
+static void wap4410n_build_verify(void)
+{
+       BUILD_BUG_ON((KERN_SIZE / 0x10000 * 0x10000) != KERN_SIZE);
+       BUILD_BUG_ON(sizeof(struct wap4410n_upgrade_info) != 16);
+       BUILD_BUG_ON(sizeof(struct wap4410n_node_info) != 0x90);
+}
+
+static void __init wap4410n_setup(void)
+{
+       struct wap4410n_node_info *ni = (struct wap4410n_node_info *)
+               (FLASH_BASE + NODE_INFO_OFFSET);
+       uint8_t *art = (uint8_t *)
+               (FLASH_BASE + FLASH_SIZE - ART_SIZE + ART_DATA_OFFSET);
+
+       ath79_init_mac(ath79_eth0_data.mac_addr, ni->mac_addr, 0);
+
+       ath79_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_RGMII;
+       /* TODO: SPEED_1000 causes a silent failure, testing needed. */
+       ath79_eth0_data.speed = SPEED_100;
+       ath79_eth0_data.duplex = DUPLEX_FULL;
+       ath79_register_eth(0);
+
+       ath79_register_usb();
+
+       wap4410n_flash_reg();
+
+       ath79_register_wmac(art, ni->mac_addr);
+
+       wap4410n_gpio_reg();
+
+       /* silence compiler warning */
+       if (0)
+               wap4410n_build_verify();
+}
+
+MIPS_MACHINE(
+       ATH79_MACH_WAP4410N,
+       "WAP4410N",
+       "Linksys WAP4410N",
+       wap4410n_setup
+);
index bedf3a3d49d50cd92953c939c0100f194f595297..0a7a89768b0a2281eb9c1fb1202b12157d49adb2 100644 (file)
@@ -23,5 +23,15 @@ define Profile/WRT400N/Description
        Package set optimized for the Linksys WRT400N.
 endef
 
        Package set optimized for the Linksys WRT400N.
 endef
 
+define Profile/WAP4410N
+       NAME:=Linksys WAP4410N
+       PACKAGES:=
+endef
+
+define Profile/WAP4410N/Description
+       Package set optimized for the Linksys WAP4410N.
+endef
+
 $(eval $(call Profile,WRT160NL))
 $(eval $(call Profile,WRT400N))
 $(eval $(call Profile,WRT160NL))
 $(eval $(call Profile,WRT400N))
+$(eval $(call Profile,WAP4410N))
index 0235287e161f1f2a879ae6603f0da8ee859110a3..e43d95dd4a17c9dbbeceb83fd2c6480769916e8c 100644 (file)
@@ -1254,6 +1254,8 @@ define Image/Build/WRT400N
        fi
 endef
 
        fi
 endef
 
+Image/Build/WAP4410N/buildkernel=$(call MkuImageGzip,$(2),$(3))
+Image/Build/WAP4410N=$(call Sysupgrade/KRuImage,$(1),$(2),1638400,6356992)
 
 define Image/Build/CameoAP94/buildkernel
        $(call MkuImageLzma,$(2),$(3) $(4))
 
 define Image/Build/CameoAP94/buildkernel
        $(call MkuImageLzma,$(2),$(3) $(4))
@@ -2141,6 +2143,7 @@ $(eval $(call SingleProfile,WHRHPG300N,64kraw,WHRHPGN,whr-hp-gn,WHR-HP-GN,ttyS0,
 $(eval $(call SingleProfile,WHRHPG300N,64kraw,WLAEAG300N,wlae-ag300n,WLAE-AG300N,ttyS0,115200,$$(whrhpg300n_mtdlayout),WLAE-AG300N))
 
 $(eval $(call SingleProfile,WRT400N,64k,WRT400N,wrt400n,WRT400N,ttyS0,115200))
 $(eval $(call SingleProfile,WHRHPG300N,64kraw,WLAEAG300N,wlae-ag300n,WLAE-AG300N,ttyS0,115200,$$(whrhpg300n_mtdlayout),WLAE-AG300N))
 
 $(eval $(call SingleProfile,WRT400N,64k,WRT400N,wrt400n,WRT400N,ttyS0,115200))
+$(eval $(call SingleProfile,WAP4410N,64k,WAP4410N,wap4410n,WAP4410N,ttyS0,115200))
 
 $(eval $(call SingleProfile,WZRHP128K,128kraw,WZRHPG300NH,wzr-hp-g300nh,WZR-HP-G300NH,ttyS0,115200,WZR-HP-G300NH))
 $(eval $(call SingleProfile,WZRHP64K,64kraw,WZRHPG300NH2,wzr-hp-g300nh2,WZR-HP-G300NH2,ttyS0,115200,WZR-HP-G300NH2))
 
 $(eval $(call SingleProfile,WZRHP128K,128kraw,WZRHPG300NH,wzr-hp-g300nh,WZR-HP-G300NH,ttyS0,115200,WZR-HP-G300NH))
 $(eval $(call SingleProfile,WZRHP64K,64kraw,WZRHPG300NH2,wzr-hp-g300nh2,WZR-HP-G300NH2,ttyS0,115200,WZR-HP-G300NH2))