From: Caleb James DeLisle Date: Mon, 1 Sep 2025 10:10:56 +0000 (+0000) Subject: econet: Add new target SmartFiber XP8421-B X-Git-Url: http://git.openwrt.org/?a=commitdiff_plain;h=ef2785a2d01bb6c8ab42b23f7706983b05be120b;p=openwrt%2Fstaging%2Fnbd.git econet: Add new target SmartFiber XP8421-B The SmartFiber XP8421-B is a fiber modem which is available for $20 online and has 512MB of memory, 256MB of SPI NAND flash and 2 USB 2.0 ports in addition to ethernet, wifi and XPON. Because EcoNet is not currently producing evaluation boards, the XP8421-B stands in as a convenient, low cost, off-the-shelf, representitive example of the capabilities of the EN751221 econet processor. This is also the example board that is included in the upstream Linux patchset. The XP8421-B, and apparently many other devices of this platform, use a dual-image layout. I have chosen to reuse this to support dual-boot between OpenWRT and the factory firmware. Certain design decisions were made with the goal of not overwriting data that is used by the factory OS. This commit also introduces a utility for switching between OS_A and OS_B which are used for OpenWRT and Factory OS respectively. Flashing instructions (from bootloader): Build and then locate the squashfs-tclinux.trx image file Get the length of that file in hex: printf '%X\n' "$(stat -c%s the-file-squashfs-tclinux.trx)" Connect to device with xmodem capability, e.g. picocom --send-cmd lsx -vv -b 115200 /dev/ttyUSB0 Switch device on and press a key within 3 seconds Enter bootloader username and password: telecomadmin nE7jA%5m Type: xmdm 80020000 Quickly start xmodem and send the file, in picocom that is ctrl+a ctrl+s enter If the transfer fails to start, wait 30 seconds to a minute for the bootloader prompt to return and then try the command again. Once the transfer has completed successfully, type the following flash 80000 80020000 Type go or simply restart the device to boot into OpenWRT Signed-off-by: Caleb James DeLisle Link: https://github.com/openwrt/openwrt/pull/19021 Signed-off-by: Hauke Mehrtens --- diff --git a/target/linux/econet/base-files/sbin/en75_chboot b/target/linux/econet/base-files/sbin/en75_chboot new file mode 100755 index 0000000000..5780190000 --- /dev/null +++ b/target/linux/econet/base-files/sbin/en75_chboot @@ -0,0 +1,112 @@ +#!/bin/sh +# SPDX-License-Identifier: GPL-2.0 + +set -e + +part= +offset_blocks= +block_size= +code_openwrt= +code_factory= +code_offset= + +read_nand() { + dd "if=$part" "of=$file" "bs=$block_size" "skip=$offset_blocks" count=1 2>/dev/null +} + +write_nand() { + flash_erase -N -q "$part" $((offset_blocks * block_size)) 1 + dd "if=$file" "of=$part" "bs=$block_size" "seek=$offset_blocks" count=1 2>/dev/null +} + +part_named() { + name=$1 + pn=$(grep "$name" < /proc/mtd | sed 's/:.*//') + if [ -z "$pn" ]; then + echo "Partition not found: $name" + exit 1 + fi + echo "/dev/$pn" +} + +to_hex() { + hexdump -v -e '1/1 "%02x"' +} + +from_hex() { + sed 's/\([0-9a-fA-F]\{2\}\)/echo -n -e "\\x\1"\n/g' | sh +} + +check() { + stored_code=$(dd \ + "if=$part" \ + bs=1 \ + skip=$((offset_blocks * block_size + code_offset)) \ + count=$((${#code_openwrt} / 2)) \ + 2>/dev/null | to_hex + ) + if [ "$stored_code" = "$code_openwrt" ]; then + echo "Current boot flag set to OS A (OpenWrt)" + elif [ "$stored_code" = "$code_factory" ]; then + echo "Current boot flag set to OS B (Factory)" + else + echo "Current boot flag unknown: $stored_code" + fi +} + +switch() { + switch_to=$1 + + echo "Switching boot flag to $switch_to" + file=$(mktemp) + read_nand + if [ "$switch_to" = "factory" ]; then + echo "$code_factory" | from_hex | \ + dd "of=$file" bs=1 "seek=$code_offset" conv=notrunc 2>/dev/null + elif [ "$switch_to" = "openwrt" ]; then + echo "$code_openwrt" | from_hex | \ + dd "of=$file" bs=1 "seek=$code_offset" conv=notrunc 2>/dev/null + else + echo "Invalid switch_to: $switch_to" + exit 1 + fi + write_nand + rm "$file" + echo "Flash write complete" + check +} + +main() { + machine=$(sed -n -e 's/^machine\s\+:\s\+//p' < /proc/cpuinfo) + if [ "$machine" = "TP-Link Archer VR1200v (v2)" ]; then + # 03fe0000 + part=$(part_named '"reserve"') + offset_blocks=0 + block_size=$((1024 * 128)) + code_offset=0 + code_openwrt=0000000101000002 + code_factory=0000000101010003 + elif [ "$machine" = "SmartFiber XP8421-B" ]; then + # 0dfc0000 + part=$(part_named '"reservearea"') + offset_blocks=12 + block_size=$((1024 * 128)) + code_offset=0 + code_openwrt=30000000 + code_factory=31000000 + else + echo "Unsupported machine: $machine" + exit 1 + fi + + if [ "$1" = "factory" ]; then + switch factory + elif [ "$1" = "openwrt" ]; then + switch openwrt + else + echo "Usage: $0 factory|openwrt # Change boot flag to Factory OS or OpenWrt" + check + exit 1 + fi +} +main "$@" diff --git a/target/linux/econet/dts/en751221_smartfiber_xp8421-b.dts b/target/linux/econet/dts/en751221_smartfiber_xp8421-b.dts new file mode 100644 index 0000000000..45654492a8 --- /dev/null +++ b/target/linux/econet/dts/en751221_smartfiber_xp8421-b.dts @@ -0,0 +1,82 @@ +// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +/dts-v1/; + +#include "en751221.dtsi" + +/ { + model = "SmartFiber XP8421-B"; + compatible = "smartfiber,xp8421-b", "econet,en751221"; + + memory@0 { + device_type = "memory"; + reg = <0x00000000 0x1c000000>; + }; + + chosen { + stdout-path = "/serial@1fbf0000:115200"; + linux,usable-memory-range = <0x00020000 0x1bfe0000>; + }; +}; + +&nand { + status = "okay"; + econet,bmt; + + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + partition@0 { + label = "bootloader"; + reg = <0x0 0x40000>; + read-only; + }; + + partition@40000 { + label = "romfile"; + reg = <0x40000 0x40000>; + read-only; + }; + + partition@80000 { + label = "tclinux"; + reg = <0x80000 0x1400000>; + read-only; + econet,enable-remap; + }; + + /* Nested inside of tclinux */ + partition@480000 { + label = "rootfs"; + reg = <0x480000 0xf80000>; + linux,rootfs; + read-only; + }; + + partition@1480000 { + label = "tclinux_alt"; + reg = <0x1480000 0x1400000>; + }; + + partition@2880000 { + label = "openjdk"; + reg = <0x2880000 0x2000000>; + }; + + partition@4880000 { + label = "ubifs"; + reg = <0x4880000 0x9100000>; + }; + + partition@d980000 { + label = "unknown"; + reg = <0xd980000 0x4c0000>; + }; + + partition@de40000 { + label = "reservearea"; + reg = <0xde40000 0x1c0000>; + }; + }; +}; diff --git a/target/linux/econet/image/Makefile b/target/linux/econet/image/Makefile index 433f6ea679..95bff987cf 100644 --- a/target/linux/econet/image/Makefile +++ b/target/linux/econet/image/Makefile @@ -5,6 +5,29 @@ define Target/Description Build firmware images for EcoNet MIPS based boards. endef -# Devices will come in a later commit. +# tclinux-trx is the default format used in the SDK +define Build/tclinux-trx + ./tclinux-trx.sh $@ $(IMAGE_ROOTFS) $(VERSION_DIST)-$(REVISION) > $@.new + mv $@.new $@ +endef + +# tclinux bootloader requires LZMA, BUT only provides 7.5MB of space +# to decompress into. So we use vmlinuz and decompress twice. +define Device/Default + DEVICE_DTS_DIR := ../dts + KERNEL_SIZE := 7480k + KERNEL_NAME := vmlinuz.bin + KERNEL_LOADADDR := 0x80020000 + KERNEL := kernel-bin | append-dtb +endef + +define Device/smartfiber_xp8421-b + DEVICE_VENDOR := SmartFiber + DEVICE_MODEL := XP8421-B + DEVICE_DTS := en751221_smartfiber_xp8421-b + IMAGES := tclinux.trx + IMAGE/tclinux.trx := append-kernel | lzma | tclinux-trx +endef +TARGET_DEVICES += smartfiber_xp8421-b $(eval $(call BuildImage)) diff --git a/target/linux/econet/image/tclinux-trx.sh b/target/linux/econet/image/tclinux-trx.sh new file mode 100755 index 0000000000..90a88d0543 --- /dev/null +++ b/target/linux/econet/image/tclinux-trx.sh @@ -0,0 +1,118 @@ +#!/bin/sh +# SPDX-License-Identifier: GPL-2.0 + +set -e + +# This is not necessary, but it makes finding the rootfs easier. +PAD_ROOTFS_OFFSET_TO=4194304 + +# Constant +HDRLEN=256 + +die() { + echo "$1" >&2 + exit 1 +} + +[ $# -eq 3 ] || die "SYNTAX: $0 " +kernel=$1 +rootfs=$2 +version=$3 +which zytrx >/dev/null || die "zytrx not found in PATH $PATH" +[ -f "$kernel" ] || die "Kernel file not found: $kernel" +[ -f "$rootfs" ] || die "Rootfs file not found: $rootfs" +[ "$(echo "$version" | wc -c)" -lt 32 ] || die "Version string too long: $version" + +kernel_len=$(stat -c '%s' "$kernel") +header_plus_kernel_len=$(($HDRLEN + $kernel_len)) +rootfs_len=$(stat -c '%s' "$rootfs") + +if [ "$PAD_ROOTFS_OFFSET_TO" -gt "$header_plus_kernel_len" ]; then + padding_len=$(($PAD_ROOTFS_OFFSET_TO - $header_plus_kernel_len)) +else + padding_len=0 +fi + +echo "padding_len: $padding_len" >&2 + +padded_rootfs_len=$(($padding_len + $rootfs_len)) + +echo "padded_rootfs_len: $padded_rootfs_len" >&2 + +total_len=$(($header_plus_kernel_len + $padded_rootfs_len)) + +echo "total_len: $total_len" >&2 + +padding() { + head -c $padding_len /dev/zero | tr '\0' '\377' +} + +to_hex() { + hexdump -v -e '1/1 "%02x"' +} + +from_hex() { + perl -pe 's/\s+//g; s/(..)/chr(hex($1))/ge' +} + +trx_crc32() { + tmpfile=$(mktemp) + outtmpfile=$(mktemp) + cat "$kernel" > "$tmpfile" + padding >> "$tmpfile" + cat "$rootfs" >> "$tmpfile" + # We just need a CRC-32/JAMCRC of the concatnated files + # There's no readily available tool for this, but zytrx does create one when + # creating their TRX header, so we just use that. + zytrx \ + -B NR7101 \ + -v x \ + -i "$tmpfile" \ + -o "$outtmpfile" >/dev/null + dd if="$outtmpfile" bs=4 count=1 skip=3 | to_hex + rm "$tmpfile" "$outtmpfile" >/dev/null +} + +tclinux_trx_hdr() { + # TRX header magic + printf '2RDH' | to_hex + + # Length of the header + printf '%08x\n' "$HDRLEN" + + # Length of header + content + printf '%08x\n' "$total_len" + + # crc32 of the content + trx_crc32 + + # version + echo "$version" | to_hex + head -c "$((32 - $(echo "$version" | wc -c)))" /dev/zero | to_hex + + # customer version + head -c 32 /dev/zero | to_hex + + # kernel length + printf '%08x\n' "$kernel_len" + + # rootfs length + printf '%08x\n' "$padded_rootfs_len" + + # romfile length (0) + printf '00000000\n' + + # "model" (32 bytes of zeros) + head -c 32 /dev/zero | to_hex + + # Load address (CONFIG_ZBOOT_LOAD_ADDRESS) + printf '80020000\n' + + # "reserved" 128 bytes of zeros + head -c 128 /dev/zero | to_hex +} + +tclinux_trx_hdr | from_hex +cat "$kernel" +padding +cat "$rootfs"