From a1c6a316d2997b6bbee520fb1bf21f3b994f9e52 Mon Sep 17 00:00:00 2001 From: NOGUCHI Hiroshi Date: Fri, 26 Jul 2019 08:11:48 +0900 Subject: [PATCH] ramips: add support for Fon FON2601 MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit 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 [removed unrelated openwrt-keyring revert, missing -Wall for uimage_padhdr] Signed-off-by: Petr Å tetiar --- .../drivers/mtd/mtdsplit/mtdsplit_uimage.c | 72 ++++++-- .../ramips/base-files/etc/board.d/02_network | 4 + .../linux/ramips/dts/mt7620a_fon_fon2601.dts | 166 ++++++++++++++++++ target/linux/ramips/image/Makefile | 5 + target/linux/ramips/image/mt7620.mk | 13 ++ tools/firmware-utils/Makefile | 1 + tools/firmware-utils/src/uimage_padhdr.c | 157 +++++++++++++++++ 7 files changed, 406 insertions(+), 12 deletions(-) create mode 100644 target/linux/ramips/dts/mt7620a_fon_fon2601.dts create mode 100644 tools/firmware-utils/src/uimage_padhdr.c diff --git a/target/linux/generic/files/drivers/mtd/mtdsplit/mtdsplit_uimage.c b/target/linux/generic/files/drivers/mtd/mtdsplit/mtdsplit_uimage.c index aba1c83ad6..091403ae91 100644 --- a/target/linux/generic/files/drivers/mtd/mtdsplit/mtdsplit_uimage.c +++ b/target/linux/generic/files/drivers/mtd/mtdsplit/mtdsplit_uimage.c @@ -24,9 +24,9 @@ /* * 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 */ @@ -80,12 +80,12 @@ read_uimage_header(struct mtd_info *mtd, size_t offset, u_char *buf, * __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; @@ -97,6 +97,7 @@ static int __mtdsplit_parse_uimage(struct mtd_info *master, size_t rootfs_size = 0; int uimage_part, rf_part; int ret; + int extralen; enum mtdsplit_part_type type; nr_parts = 2; @@ -120,7 +121,8 @@ static int __mtdsplit_parse_uimage(struct mtd_info *master, 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); @@ -128,7 +130,9 @@ static int __mtdsplit_parse_uimage(struct mtd_info *master, } 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); @@ -206,7 +210,7 @@ err_free_parts: 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; @@ -269,7 +273,7 @@ static struct mtd_part_parser uimage_generic_parser = { #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; @@ -332,7 +336,7 @@ static struct mtd_part_parser uimage_netgear_parser = { #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; @@ -345,7 +349,7 @@ static ssize_t uimage_find_edimax(u_char *buf, size_t len) 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; @@ -377,6 +381,49 @@ static struct mtd_part_parser uimage_edimax_parser = { .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 **************************************************/ @@ -386,6 +433,7 @@ static int __init mtdsplit_uimage_init(void) 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; } diff --git a/target/linux/ramips/base-files/etc/board.d/02_network b/target/linux/ramips/base-files/etc/board.d/02_network index 95bd2a44f1..2f9a02256e 100755 --- a/target/linux/ramips/base-files/etc/board.d/02_network +++ b/target/linux/ramips/base-files/etc/board.d/02_network @@ -329,6 +329,10 @@ ramips_setup_interfaces() 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" diff --git a/target/linux/ramips/dts/mt7620a_fon_fon2601.dts b/target/linux/ramips/dts/mt7620a_fon_fon2601.dts new file mode 100644 index 0000000000..33329a1049 --- /dev/null +++ b/target/linux/ramips/dts/mt7620a_fon_fon2601.dts @@ -0,0 +1,166 @@ +// SPDX-License-Identifier: GPL-2.0 +/dts-v1/; + +#include "mt7620a.dtsi" + +#include +#include + +/ { + 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 = ; + }; + }; +}; + +&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"; +}; diff --git a/target/linux/ramips/image/Makefile b/target/linux/ramips/image/Makefile index 36f95b6d1c..816146ece5 100644 --- a/target/linux/ramips/image/Makefile +++ b/target/linux/ramips/image/Makefile @@ -147,6 +147,11 @@ define Build/sercom-footer $(call Build/sercom-seal,-f) endef +define Build/fonfxcimage + uimage_padhdr -i $@ -o $@.new + mv $@.new $@ +endef + ifeq ($(SUBTARGET),rt288x) include rt288x.mk endif diff --git a/target/linux/ramips/image/mt7620.mk b/target/linux/ramips/image/mt7620.mk index d7b06076da..455f836168 100644 --- a/target/linux/ramips/image/mt7620.mk +++ b/target/linux/ramips/image/mt7620.mk @@ -372,6 +372,19 @@ define Device/elecom_wrh-300cr 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 diff --git a/tools/firmware-utils/Makefile b/tools/firmware-utils/Makefile index d318788ac5..2d2c96ce0a 100644 --- a/tools/firmware-utils/Makefile +++ b/tools/firmware-utils/Makefile @@ -92,6 +92,7 @@ define Host/Compile $(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 diff --git a/tools/firmware-utils/src/uimage_padhdr.c b/tools/firmware-utils/src/uimage_padhdr.c new file mode 100644 index 0000000000..b5fb97d21f --- /dev/null +++ b/tools/firmware-utils/src/uimage_padhdr.c @@ -0,0 +1,157 @@ +/* + * uimage_padhdr.c : add zero paddings after the tail of uimage header + * + * Copyright (C) 2019 NOGUCHI Hiroshi + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include + + +/* 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 -o [-l ]\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; +} -- 2.30.2