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"