FON2601 is a wireless router.
Specification:
- SoC: Mediatek MT7620A (580MHz)
- RAM: 128 MiB
- ROM: 16 MiB SPI Flash
- Wireless:
for 11b/g/n (upto 300 Mbps): MT7620A built-in WMAC
for 11a/n/ac (upto 867 Mbps): MT7662E
- Ethernet LAN: 1 port, upto 100 Mbps
- Ethernet WAN: 1 port, upto 1000 Mbps
- USB: 1 port (USB 2.0 host)
- LEDs: 4 (all can be controlled by SoC's GPIO)
- buttons: 1 (Displayed as "WPS" on enclosure)
- serial port: 57600n8
pins: Vcc(3.3V), Rx, Tx, GND
(left to right, viewed from outside of board)
Installation (only available via UART):
1. download sysupgrade binary image by wget command
2. write sysupgrade binary image to Flash
command is:
mtd write sysupgrade.bin firmware
3. reboot
Important Notice:
Only one button is displayed as "WPS" on enclosure.
However, it is configured as "reset" (factory resetting feature).
Signed-off-by: NOGUCHI Hiroshi <drvlabo@gmail.com>
[removed unrelated openwrt-keyring revert, missing -Wall for uimage_padhdr]
Signed-off-by: Petr Štetiar <ynezz@true.cz>
/*
* uimage_header itself is only 64B, but it may be prepended with another data.
- * Currently the biggest size is for Edimax devices: 20B + 64B
+ * Currently the biggest size is for Fon(Foxconn) devices: 64B + 32B
*/
-#define MAX_HEADER_LEN 84
+#define MAX_HEADER_LEN 96
#define IH_MAGIC 0x27051956 /* Image Magic Number */
#define IH_NMLEN 32 /* Image Name Length */
* __mtdsplit_parse_uimage - scan partition and create kernel + rootfs parts
*
* @find_header: function to call for a block of data that will return offset
- * of a valid uImage header if found
+ * and tail padding length of a valid uImage header if found
*/
static int __mtdsplit_parse_uimage(struct mtd_info *master,
- const struct mtd_partition **pparts,
- struct mtd_part_parser_data *data,
- ssize_t (*find_header)(u_char *buf, size_t len))
+ const struct mtd_partition **pparts,
+ struct mtd_part_parser_data *data,
+ ssize_t (*find_header)(u_char *buf, size_t len, int *extralen))
{
struct mtd_partition *parts;
u_char *buf;
size_t rootfs_size = 0;
int uimage_part, rf_part;
int ret;
+ int extralen;
enum mtdsplit_part_type type;
nr_parts = 2;
if (ret)
continue;
- ret = find_header(buf, MAX_HEADER_LEN);
+ extralen = 0;
+ ret = find_header(buf, MAX_HEADER_LEN, &extralen);
if (ret < 0) {
pr_debug("no valid uImage found in \"%s\" at offset %llx\n",
master->name, (unsigned long long) offset);
}
header = (struct uimage_header *)(buf + ret);
- uimage_size = sizeof(*header) + be32_to_cpu(header->ih_size) + ret;
+ uimage_size = sizeof(*header) +
+ be32_to_cpu(header->ih_size) + ret + extralen;
+
if ((offset + uimage_size) > master->size) {
pr_debug("uImage exceeds MTD device \"%s\"\n",
master->name);
return ret;
}
-static ssize_t uimage_verify_default(u_char *buf, size_t len)
+static ssize_t uimage_verify_default(u_char *buf, size_t len, int *extralen)
{
struct uimage_header *header = (struct uimage_header *)buf;
#define FW_MAGIC_WNDR3700V2 0x33373031
#define FW_MAGIC_WPN824N 0x31313030
-static ssize_t uimage_verify_wndr3700(u_char *buf, size_t len)
+static ssize_t uimage_verify_wndr3700(u_char *buf, size_t len, int *extralen)
{
struct uimage_header *header = (struct uimage_header *)buf;
uint8_t expected_type = IH_TYPE_FILESYSTEM;
#define FW_EDIMAX_OFFSET 20
#define FW_MAGIC_EDIMAX 0x43535953
-static ssize_t uimage_find_edimax(u_char *buf, size_t len)
+static ssize_t uimage_find_edimax(u_char *buf, size_t len, int *extralen)
{
u32 *magic;
if (be32_to_cpu(*magic) != FW_MAGIC_EDIMAX)
return -EINVAL;
- if (!uimage_verify_default(buf + FW_EDIMAX_OFFSET, len))
+ if (!uimage_verify_default(buf + FW_EDIMAX_OFFSET, len, extralen))
return FW_EDIMAX_OFFSET;
return -EINVAL;
.type = MTD_PARSER_TYPE_FIRMWARE,
};
+
+/**************************************************
+ * Fon(Foxconn)
+ **************************************************/
+
+#define FONFXC_PAD_LEN 32
+
+static ssize_t uimage_find_fonfxc(u_char *buf, size_t len, int *extralen)
+{
+ if (uimage_verify_default(buf, len, extralen) < 0)
+ return -EINVAL;
+
+ *extralen = FONFXC_PAD_LEN;
+
+ return 0;
+}
+
+static int
+mtdsplit_uimage_parse_fonfxc(struct mtd_info *master,
+ const struct mtd_partition **pparts,
+ struct mtd_part_parser_data *data)
+{
+ return __mtdsplit_parse_uimage(master, pparts, data,
+ uimage_find_fonfxc);
+}
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 9, 0)
+static const struct of_device_id mtdsplit_uimage_fonfxc_of_match_table[] = {
+ { .compatible = "fonfxc,uimage" },
+ {},
+};
+#endif
+
+static struct mtd_part_parser uimage_fonfxc_parser = {
+ .owner = THIS_MODULE,
+ .name = "fonfxc-fw",
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 9, 0)
+ .of_match_table = mtdsplit_uimage_fonfxc_of_match_table,
+#endif
+ .parse_fn = mtdsplit_uimage_parse_fonfxc,
+ .type = MTD_PARSER_TYPE_FIRMWARE,
+};
+
/**************************************************
* Init
**************************************************/
register_mtd_parser(&uimage_generic_parser);
register_mtd_parser(&uimage_netgear_parser);
register_mtd_parser(&uimage_edimax_parser);
+ register_mtd_parser(&uimage_fonfxc_parser);
return 0;
}
ucidef_add_switch "switch1" \
"1:lan" "2:lan" "3:lan" "4:lan" "0:wan" "6@eth0"
;;
+ fon,fon2601)
+ ucidef_add_switch "switch0" \
+ "0:lan" "4:wan" "6@eth0"
+ ;;
gehua,ghl-r-001)
ucidef_add_switch "switch0" \
"0:lan" "1:lan" "2:lan" "4:wan" "6@eth0"
--- /dev/null
+// SPDX-License-Identifier: GPL-2.0
+/dts-v1/;
+
+#include "mt7620a.dtsi"
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/input/input.h>
+
+/ {
+ compatible = "fon,fon2601", "ralink,mt7620a-soc";
+ model = "Fon FON2601";
+
+ aliases {
+ led-boot = &led_power;
+ led-failsafe = &led_power;
+ led-running = &led_power;
+ led-upgrade = &led_power;
+ };
+
+ leds {
+ compatible = "gpio-leds";
+
+ led_power: power_r {
+ label = "fon2601:red:power";
+ gpios = <&gpio0 9 GPIO_ACTIVE_LOW>;
+ };
+
+ internet_g {
+ label = "fon2601:green:internet";
+ gpios = <&gpio0 10 GPIO_ACTIVE_LOW>;
+ };
+
+ net_g {
+ label = "fon2601:green:net";
+ gpios = <&gpio0 12 GPIO_ACTIVE_LOW>;
+ };
+
+ wifi_g {
+ label = "fon2601:green:wifi";
+ gpios = <&gpio0 14 GPIO_ACTIVE_LOW>;
+ };
+ };
+
+ keys {
+ compatible = "gpio-keys";
+
+ reset {
+ label = "reset";
+ gpios = <&gpio0 2 GPIO_ACTIVE_LOW>;
+ linux,code = <KEY_RESTART>;
+ };
+ };
+};
+
+&spi0 {
+ status = "okay";
+
+ flash@0 {
+ compatible = "jedec,spi-nor";
+ reg = <0>;
+ spi-max-frequency = <10000000>;
+
+ partitions {
+ compatible = "fixed-partitions";
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ partition@0 {
+ label = "u-boot";
+ reg = <0x0 0x30000>;
+ read-only;
+ };
+
+ partition@30000 {
+ label = "u-boot-env";
+ reg = <0x30000 0x10000>;
+ read-only;
+ };
+
+ factory: partition@40000 {
+ label = "factory";
+ reg = <0x40000 0x10000>;
+ read-only;
+ };
+
+ partition@50000 {
+ compatible = "fonfxc,uimage";
+ label = "firmware";
+ reg = <0x50000 0xf90000>;
+ };
+
+ partition@fe0000 {
+ label = "board_data";
+ reg = <0xfe0000 0x20000>;
+ read-only;
+ };
+ };
+ };
+};
+
+&state_default {
+ gpio {
+ ralink,group = "i2c", "uartf";
+ ralink,function = "gpio";
+ };
+ nd_sd {
+ ralink,group = "nd_sd";
+ ralink,function = "sd";
+ };
+ spi_cs {
+ ralink,group = "spi refclk";
+ ralink,function = "spi refclk";
+ };
+};
+
+ðernet {
+ pinctrl-names = "default";
+ pinctrl-0 = <&rgmii2_pins &mdio_pins>;
+
+ mtd-mac-address = <&factory 0x4>;
+
+ port@4 {
+ status = "okay";
+ phy-handle = <&phy4>;
+ phy-mode = "rgmii";
+ };
+
+ mdio-bus {
+ status = "okay";
+
+ phy4: ethernet-phy@4 {
+ reg = <4>;
+ phy-mode = "rgmii";
+ };
+ };
+};
+
+&gsw {
+ mediatek,port4 = "gmac";
+};
+
+&wmac {
+ ralink,mtd-eeprom = <&factory 0>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pa_pins>, <&wled_pins>;
+};
+
+&pcie {
+ status = "okay";
+};
+&pcie0 {
+ wifi@0,0 {
+ compatible = "pci14c3,7662";
+ reg = <0x0000 0 0 0 0>;
+ mediatek,mtd-eeprom = <&factory 0x8000>;
+ ieee80211-freq-limit = <5000000 6000000>;
+ };
+};
+
+&ehci {
+ status = "okay";
+};
+
+&ohci {
+ status = "okay";
+};
$(call Build/sercom-seal,-f)
endef
+define Build/fonfxcimage
+ uimage_padhdr -i $@ -o $@.new
+ mv $@.new $@
+endef
+
ifeq ($(SUBTARGET),rt288x)
include rt288x.mk
endif
endef
TARGET_DEVICES += elecom_wrh-300cr
+define Device/fon_fon2601
+ MTK_SOC := mt7620a
+ IMAGE_SIZE := 15936k
+ DEVICE_VENDOR := Fon
+ DEVICE_MODEL := FON2601
+ DEVICE_PACKAGES := kmod-mt76x2 kmod-usb2 kmod-usb-ohci
+ KERNEL_INITRAMFS := $$(KERNEL) | fonfxcimage
+ IMAGE/sysupgrade.bin := append-kernel | append-rootfs |\
+ fonfxcimage |\
+ pad-rootfs | append-metadata | check-size $$$$(IMAGE_SIZE)
+endef
+TARGET_DEVICES += fon_fon2601
+
define Device/glinet_gl-mt300a
MTK_SOC := mt7620a
IMAGE_SIZE := 15872k
$(call cc,dns313-header, -Wall)
$(call cc,mksercommfw, -Wall)
$(call cc,nec-enc, -Wall --std=gnu99)
+ $(call cc,uimage_padhdr, -Wall -lz)
endef
define Host/Install
--- /dev/null
+/*
+ * uimage_padhdr.c : add zero paddings after the tail of uimage header
+ *
+ * Copyright (C) 2019 NOGUCHI Hiroshi <drvlabo@gmail.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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <stdio.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <arpa/inet.h>
+#include <zlib.h>
+
+
+/* from u-boot/include/image.h */
+#define IH_MAGIC 0x27051956 /* Image Magic Number */
+#define IH_NMLEN 32 /* Image Name Length */
+
+/*
+ * Legacy format image header,
+ * all data in network byte order (aka natural aka bigendian).
+ */
+typedef struct image_header {
+ uint32_t ih_magic; /* Image Header Magic Number */
+ uint32_t ih_hcrc; /* Image Header CRC Checksum */
+ uint32_t ih_time; /* Image Creation Timestamp */
+ uint32_t ih_size; /* Image Data Size */
+ uint32_t ih_load; /* Data Load Address */
+ uint32_t ih_ep; /* Entry Point Address */
+ uint32_t ih_dcrc; /* Image Data CRC Checksum */
+ uint8_t ih_os; /* Operating System */
+ uint8_t ih_arch; /* CPU architecture */
+ uint8_t ih_type; /* Image Type */
+ uint8_t ih_comp; /* Compression Type */
+ uint8_t ih_name[IH_NMLEN]; /* Image Name */
+} image_header_t;
+
+
+/* default padding size */
+#define IH_PAD_BYTES (32)
+
+
+static void usage(char *prog)
+{
+ fprintf(stderr,
+ "%s -i <input_uimage_file> -o <output_file> [-l <padding bytes>]\n",
+ prog);
+}
+
+int main(int argc, char *argv[])
+{
+ struct stat statbuf;
+ u_int8_t *filebuf;
+ int ifd;
+ int ofd;
+ ssize_t rsz;
+ u_int32_t crc_recalc;
+ image_header_t *imgh;
+ int opt;
+ char *infname = NULL;
+ char *outfname = NULL;
+ int padsz = IH_PAD_BYTES;
+ int ltmp;
+
+ while ((opt = getopt(argc, argv, "i:o:l:")) != -1) {
+ switch (opt) {
+ case 'i':
+ infname = optarg;
+ break;
+ case 'o':
+ outfname = optarg;
+ break;
+ case 'l':
+ ltmp = strtol(optarg, NULL, 0);
+ if (ltmp > 0)
+ padsz = ltmp;
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (!infname || !outfname) {
+ usage(argv[0]);
+ exit(1);
+ }
+
+ if (stat(infname, &statbuf) < 0) {
+ fprintf(stderr,
+ "could not find input file. (errno = %d)\n", errno);
+ exit(1);
+ }
+
+ filebuf = malloc(statbuf.st_size + padsz);
+ if (!filebuf) {
+ fprintf(stderr, "buffer allocation failed\n");
+ exit(1);
+ }
+
+ ifd = open(infname, O_RDONLY);
+ if (ifd < 0) {
+ fprintf(stderr,
+ "could not open input file. (errno = %d)\n", errno);
+ exit(1);
+ }
+
+ ofd = open(outfname, O_WRONLY | O_CREAT, 0644);
+ if (ofd < 0) {
+ fprintf(stderr,
+ "could not open output file. (errno = %d)\n", errno);
+ exit(1);
+ }
+
+ rsz = read(ifd, filebuf, sizeof(*imgh));
+ if (rsz != sizeof(*imgh)) {
+ fprintf(stderr,
+ "could not read input file (errno = %d).\n", errno);
+ exit(1);
+ }
+
+ memset(&(filebuf[sizeof(*imgh)]), 0, padsz);
+
+ rsz = read(ifd, &(filebuf[sizeof(*imgh) + padsz]),
+ statbuf.st_size - sizeof(*imgh));
+ if (rsz != (int32_t)(statbuf.st_size - sizeof(*imgh))) {
+ fprintf(stderr,
+ "could not read input file (errno = %d).\n", errno);
+ exit(1);
+ }
+
+ imgh = (image_header_t *)filebuf;
+
+ imgh->ih_hcrc = 0;
+ crc_recalc = crc32(0, filebuf, sizeof(*imgh) + padsz);
+ imgh->ih_hcrc = htonl(crc_recalc);
+
+ rsz = write(ofd, filebuf, statbuf.st_size + padsz);
+ if (rsz != (int32_t)statbuf.st_size + padsz) {
+ fprintf(stderr,
+ "could not write output file (errnor = %d).\n", errno);
+ exit(1);
+ }
+
+ return 0;
+}