diff --git a/target/linux/ar71xx/base-files/etc/diag.sh b/target/linux/ar71xx/base-files/etc/diag.sh index 0bcb273359..ce2b9bad50 100644 --- a/target/linux/ar71xx/base-files/etc/diag.sh +++ b/target/linux/ar71xx/base-files/etc/diag.sh @@ -328,6 +328,9 @@ get_status_led() { wrt400n) status_led="wrt400n:blue:wps" ;; + wap4410n) + status_led="wrt4410n:green:power" + ;; wrt160nl) status_led="wrt160nl:blue:wps" ;; 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 ea19de9087..51095a9a5e 100755 --- a/target/linux/ar71xx/base-files/etc/uci-defaults/02_network +++ b/target/linux/ar71xx/base-files/etc/uci-defaults/02_network @@ -341,6 +341,7 @@ tl-wa901nd-v3 |\ tl-wr703n |\ tube2h |\ wndap360 |\ +wap4410n |\ mynet-rext |\ wp543) ucidef_set_interface_lan "eth0" diff --git a/target/linux/ar71xx/base-files/lib/ar71xx.sh b/target/linux/ar71xx/base-files/lib/ar71xx.sh index 9943d6918a..dd13948c40 100755 --- a/target/linux/ar71xx/base-files/lib/ar71xx.sh +++ b/target/linux/ar71xx/base-files/lib/ar71xx.sh @@ -880,6 +880,9 @@ ar71xx_board_detect() { *WRT400N) name="wrt400n" ;; + *WAP4410N) + name="wap4410n" + ;; *"WZR-450HP2") name="wzr-450hp2" ;; diff --git a/target/linux/ar71xx/base-files/lib/upgrade/platform.sh b/target/linux/ar71xx/base-files/lib/upgrade/platform.sh index 37a2e7b0ee..73d8b0d7f6 100755 --- a/target/linux/ar71xx/base-files/lib/upgrade/platform.sh +++ b/target/linux/ar71xx/base-files/lib/upgrade/platform.sh @@ -233,6 +233,7 @@ platform_check_image() { nanostation-m-xw | \ rw2458n | \ wpj531 | \ + wap4410n | \ wndap360 | \ wpj344 | \ wzr-hp-g300nh2 | \ diff --git a/target/linux/ar71xx/config-3.18 b/target/linux/ar71xx/config-3.18 index 0680dd0440..02857d5d2d 100644 --- a/target/linux/ar71xx/config-3.18 +++ b/target/linux/ar71xx/config-3.18 @@ -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_WAP4410N=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 index 0000000000..f2cf071fc8 --- /dev/null +++ b/target/linux/ar71xx/files/arch/mips/ath79/mach-wap4410n.c @@ -0,0 +1,285 @@ +/* + * Cisco WAP4410N board support + * + * Copyright (C) 2014 Caleb James DeLisle + * Copyright (C) 2015 Ryan A Young + * + * 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 +#include +#include +#include +#include + +#include + +#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 +); diff --git a/target/linux/ar71xx/generic/profiles/linksys.mk b/target/linux/ar71xx/generic/profiles/linksys.mk index bedf3a3d49..0a7a89768b 100644 --- a/target/linux/ar71xx/generic/profiles/linksys.mk +++ b/target/linux/ar71xx/generic/profiles/linksys.mk @@ -23,5 +23,15 @@ define Profile/WRT400N/Description 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,WAP4410N)) diff --git a/target/linux/ar71xx/image/Makefile b/target/linux/ar71xx/image/Makefile index 0235287e16..e43d95dd4a 100644 --- a/target/linux/ar71xx/image/Makefile +++ b/target/linux/ar71xx/image/Makefile @@ -1254,6 +1254,8 @@ define Image/Build/WRT400N 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)) @@ -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,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))