diff --git a/scripts/belkin-header.py b/scripts/belkin-header.py new file mode 100755 index 0000000000..4dc3d2652e --- /dev/null +++ b/scripts/belkin-header.py @@ -0,0 +1,94 @@ +#!/usr/bin/python3 +# SPDX-License-Identifier: GPL-2.0-or-later +# +# Copyright (C) 2024 OpenWrt.org +# +# ./belkin-header.py +# +# This script adds an image header for Belkin devices. As of now only Realtek +# based switches of the Linksys LGS3xxC/LGS3xxMPC series are known to use this +# format. It resembles a U-Boot legacy format image header, all data in network +# byte order (aka natural aka big endian). +# +# Known values for BelkinHeader are +# +# 0x07800001 : RTL838x based switch +# 0x07600001 : RTL93xx based switch +# +# Known values for BelkinModel are +# +# BKS-RTL83xx : RTL838x based switch +# BKS-RTL93xx : RTL93xx based switch + +import argparse +import os +import zlib +import array +import sys +import time + +VERSION1 = 1 +VERSION2 = 1 +VERSION3 = 2 +VERSION4 = 2 +COMPANY = "belkin" +MODULE = "IMG" + +def xcrc32(buf): + return (0xffffffff - zlib.crc32(buf, 0xffffffff)).to_bytes(4, 'big') + +def encode_model(model): + map = " 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz-" + code = bytearray() + + code.append(map.index(model[:1])) + model = model[1:] + model = model + " " * (3 - len(model) % 4) + + while model != "": + b1 = map.index(model[0:1]) + b2 = map.index(model[1:2]) + b3 = map.index(model[2:3]) + b4 = map.index(model[3:4]) + model = model[4:] + + code.append(b1 << 2 | b2 >> 4) + code.append((b2 & 0xf) << 4 | b3 >> 2) + code.append((b3 & 0x3) << 6 | b4) + + return code + +def create_header(buf, belkin_header, belkin_model): + head = bytearray(32) + + head[0:4] = int(belkin_header, 0).to_bytes(4, 'big') + head[8:12] = int(time.time()).to_bytes(4, 'big') + head[12:16] = len(buf).to_bytes(4, 'big') + head[24:28] = xcrc32(buf) + head[28:29] = VERSION1.to_bytes(1) + head[29:30] = VERSION2.to_bytes(1) + head[30:31] = VERSION3.to_bytes(1) + head[31:32] = VERSION4.to_bytes(1) + head[16:16 + len(COMPANY)] = bytes(COMPANY,'ascii') + + mod = MODULE + "-{:1d}.{:02d}.{:02d}.{:02d}".format(VERSION1, VERSION2, VERSION3, VERSION4) + head.extend(bytes(mod,'ascii')) + head.append(0x00) + head.extend(encode_model(belkin_model)) + head.extend(bytes([0x00] * (64 - len(head)))) + + head[4:8] = xcrc32(head) + + return head + +parser = argparse.ArgumentParser(description='Generate Belkin header.') +parser.add_argument('source', type=argparse.FileType('r+b')) +parser.add_argument('dest', type=argparse.FileType('wb')) +parser.add_argument('belkin_header') +parser.add_argument('belkin_model') +args = parser.parse_args() + +buf = bytearray(args.source.read()) +head = create_header(buf, args.belkin_header, args.belkin_model) +args.dest.write(head) +args.dest.write(buf) diff --git a/scripts/linksys-image.sh b/scripts/linksys-image.sh new file mode 100755 index 0000000000..f0398662fb --- /dev/null +++ b/scripts/linksys-image.sh @@ -0,0 +1,76 @@ +#!/bin/sh +# SPDX-License-Identifier: GPL-2.0-or-later +# +# Copyright (C) 2024 OpenWrt.org +# +# This script creates a tar file for the Linksys switches of the LGS3xxC/LGS3xxMPC +# series. It contains not only the OpenWrt firmware but additional scripts that +# are needed for the upgrade. +# +# ./linksys-image.py +# +# Known values for LinksysModel are currently +# +# LGS310MPC 60402010 +# LGS310C 60402060 +# LGS328PC 60401070 +# LGS328PC(RTL8218D) 60401080 +# LGS310MPCv2 60402090 +# LGS328MPC 60412020 +# LGS328C 60412040 +# LGS328MPCv2 60412060 +# LGS352MPC 60422030 +# LGS352C 60422050 +# LGS352MPCv2 60422070 + +# The check script that verifies if the images matches the hardware model +gen_imagecheck() { + echo '#!/bin/sh' + echo 'if [ "$1" = "'${1}'" ]; then' + echo 'echo 0' + echo 'else' + echo 'echo 1' + echo 'fi' +} + +# Generic attributes +gen_fwinfo() { + echo 'FW_VERSION=1.01.100\nBOOT_VERSION=01.00.01' +} + +# The central upgrade script. It allows to install OpenWrt only to first partition. +gen_imageupgrade() { + echo '#!/bin/sh' + echo 'flash_bank=65536' + echo 'filesize=`stat --format=%s ./series_vmlinux.bix`' + echo 'num_bank=`expr \( ${filesize} + ${flash_bank} - 1 \) / ${flash_bank}`' + echo 'filesize_bank=`expr ${num_bank} \* ${flash_bank}`' + echo 'case $1 in' + echo '1)' + echo 'mtd_debug erase $2 0 ${filesize_bank} >/dev/null 2>&1' + echo 'mtd_debug write $2 0 ${filesize} ./series_vmlinux.bix >/dev/null 2>&1' + echo 'mtd_debug read $2 0 100 image1.img >/dev/null 2>&1' + echo 'CreateImage -r ./image1.img > /tmp/app/image1.txt' + echo 'echo 0' + echo ';;' + echo '*)' + echo 'echo 1' + echo 'esac' +} + +tmpdir="$( mktemp -d 2> /dev/null )" +imgdir=$tmpdir/image +mkdir $imgdir + +gen_imagecheck $3 > $imgdir/iss_imagecheck.sh +gen_imageupgrade > $imgdir/iss_imageupgrade.sh +gen_fwinfo > $imgdir/firmware_information.txt + +chmod +x $imgdir/iss_imagecheck.sh +chmod +x $imgdir/iss_imageupgrade.sh + +cp $1 $imgdir/series_vmlinux.bix + +tar cf $2 -C $tmpdir image/ + +rm -rf $tmpdir diff --git a/target/linux/realtek/dts/rtl8380_linksys_lgs310c.dts b/target/linux/realtek/dts/rtl8380_linksys_lgs310c.dts new file mode 100644 index 0000000000..08ef740399 --- /dev/null +++ b/target/linux/realtek/dts/rtl8380_linksys_lgs310c.dts @@ -0,0 +1,212 @@ +// SPDX-License-Identifier: GPL-2.0-or-later OR MIT + +#include +#include +#include + +#include "rtl838x.dtsi" + +/ { + compatible = "linksys,lgs310c", "realtek,rtl838x-soc"; + model = "Linksys LGS310C"; + + aliases { + led-boot = &led_power; + led-failsafe = &led_fault; + led-running = &led_power; + led-upgrade = &led_power; + }; + + memory@0 { + device_type = "memory"; + reg = <0x0 0x10000000>; + }; + + leds: leds { + pinctrl-names = "default"; + pinctrl-0 = <&pinmux_disable_sys_led>; + compatible = "gpio-leds"; + + led_power: led-0 { + function = LED_FUNCTION_POWER; + color = ; + gpios = <&gpio1 3 GPIO_ACTIVE_LOW>; + }; + + led_fault: led-1 { + function = LED_FUNCTION_FAULT; + color = ; + gpios = <&gpio1 2 GPIO_ACTIVE_LOW>; + }; + + }; + + /* i2c of the left SFP cage: port 9 */ + i2c0: i2c-gpio-0 { + compatible = "i2c-gpio"; + sda-gpios = <&gpio1 6 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; + scl-gpios = <&gpio1 31 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; + i2c-gpio,delay-us = <2>; + #address-cells = <1>; + #size-cells = <0>; + }; + + sfp0: sfp-p9 { + compatible = "sff,sfp"; + i2c-bus = <&i2c0>; + los-gpio = <&gpio1 11 GPIO_ACTIVE_HIGH>; + mod-def0-gpio = <&gpio1 12 GPIO_ACTIVE_LOW>; + tx-disable-gpio = <&gpio1 10 GPIO_ACTIVE_HIGH>; + }; + + /* i2c of the right SFP cage: port 10 */ + i2c1: i2c-gpio-1 { + compatible = "i2c-gpio"; + sda-gpios = <&gpio1 7 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; +/* + * ports 9 & 10 use a shared SCL, and are currently not usable in parallel + * So for now disable the SCL on the second port. + * + * scl-gpios = <&gpio1 31 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; + */ + i2c-gpio,scl-open-drain; + i2c-gpio,delay-us = <2>; + #address-cells = <1>; + #size-cells = <0>; + }; + + sfp1: sfp-p10 { + compatible = "sff,sfp"; + i2c-bus = <&i2c1>; + los-gpio = <&gpio1 14 GPIO_ACTIVE_HIGH>; + mod-def0-gpio = <&gpio1 21 GPIO_ACTIVE_LOW>; + tx-disable-gpio = <&gpio1 13 GPIO_ACTIVE_HIGH>; + }; + + keys { + compatible = "gpio-keys"; + + reset { + label = "reset"; + gpios = <&gpio0 11 GPIO_ACTIVE_LOW>; + linux,code = ; + }; + }; + + gpio1: rtl8231-gpio { + compatible = "realtek,rtl8231-gpio"; + #gpio-cells = <2>; + gpio-controller; + indirect-access-bus-id = <0>; + }; +}; + +&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 = <0x00000000 0x80000>; + read-only; + }; + partition@80000 { + label = "u-boot-env"; + reg = <0x00080000 0x10000>; + }; + partition@90000 { + label = "u-boot-env2"; + reg = <0x00090000 0x10000>; + }; + partition@a0000 { + label = "jffs2"; + reg = <0x000a0000 0x500000>; + }; + partition@5a0000 { + label = "firmware"; + compatible = "openwrt,uimage"; + reg = <0x005a0000 0xd30000>; + }; + partition@2d0000 { + label = "kernel2"; + reg = <0x012d0000 0xd30000>; + }; + }; + }; +}; + +&uart1 { + status = "okay"; +}; + +ðernet0 { + mdio: mdio-bus { + compatible = "realtek,rtl838x-mdio"; + regmap = <ðernet0>; + #address-cells = <1>; + #size-cells = <0>; + + INTERNAL_PHY(8) + INTERNAL_PHY(9) + INTERNAL_PHY(10) + INTERNAL_PHY(11) + INTERNAL_PHY(12) + INTERNAL_PHY(13) + INTERNAL_PHY(14) + INTERNAL_PHY(15) + INTERNAL_PHY(24) + INTERNAL_PHY(26) + }; +}; + +&switch0 { + ports { + #address-cells = <1>; + #size-cells = <0>; + + SWITCH_PORT(8, 1, internal) + SWITCH_PORT(9, 2, internal) + SWITCH_PORT(10, 3, internal) + SWITCH_PORT(11, 4, internal) + SWITCH_PORT(12, 5, internal) + SWITCH_PORT(13, 6, internal) + SWITCH_PORT(14, 7, internal) + SWITCH_PORT(15, 8, internal) + + port@24 { + reg = <24>; + label = "lan9"; + phy-handle = <&phy24>; + phy-mode = "1000base-x"; + managed = "in-band-status"; + sfp = <&sfp0>; + }; + + port@26 { + reg = <26>; + label = "lan10"; + phy-handle = <&phy26>; + phy-mode = "1000base-x"; + managed = "in-band-status"; + sfp = <&sfp1>; + }; + + port@28 { + ethernet = <ðernet0>; + reg = <28>; + phy-mode = "internal"; + fixed-link { + speed = <1000>; + full-duplex; + }; + }; + }; +}; diff --git a/target/linux/realtek/image/Makefile b/target/linux/realtek/image/Makefile index 9eed710480..19fab03dba 100644 --- a/target/linux/realtek/image/Makefile +++ b/target/linux/realtek/image/Makefile @@ -6,6 +6,8 @@ include $(INCLUDE_DIR)/image.mk KERNEL_LOADADDR = 0x80100000 DEVICE_VARS += \ + BELKIN_HEADER \ + BELKIN_MODEL \ CAMEO_BOARD_MODEL \ CAMEO_BOARD_VERSION \ CAMEO_CUSTOMER_SIGNATURE \ @@ -14,6 +16,7 @@ DEVICE_VARS += \ CAMEO_ROOTFS_PART \ H3C_DEVICE_ID \ H3C_PRODUCT_ID \ + LINKSYS_HEADER \ ZYXEL_VERS define Build/zyxel-vers @@ -71,6 +74,16 @@ define Build/h3c-vfs mv $@.new $@ endef +define Build/belkin-header + $(SCRIPT_DIR)/belkin-header.py $(@) $(@).new $(BELKIN_HEADER) ${BELKIN_MODEL} + mv $@.new $@ +endef + +define Build/linksys-image + $(SCRIPT_DIR)/linksys-image.sh $(@) $(@).new $(LINKSYS_MODEL) + mv $@.new $@ +endef + define Device/Default PROFILES = Default KERNEL := \ diff --git a/target/linux/realtek/image/rtl838x.mk b/target/linux/realtek/image/rtl838x.mk index c8e1c481ec..01397af931 100644 --- a/target/linux/realtek/image/rtl838x.mk +++ b/target/linux/realtek/image/rtl838x.mk @@ -162,6 +162,27 @@ define Device/iodata_bsh-g24mb endef TARGET_DEVICES += iodata_bsh-g24mb +define Device/linksys_lgs310c + SOC := rtl8380 + IMAGE_SIZE := 13504k + DEVICE_VENDOR := Linksys + DEVICE_MODEL := LGS310C + BELKIN_MODEL := BKS-RTL83xx + BELKIN_HEADER := 0x07800001 + LINKSYS_MODEL := 60402060 + IMAGES += factory.imag + IMAGE/factory.imag := \ + append-kernel | \ + pad-to 64k | \ + append-rootfs | \ + pad-rootfs | \ + check-size | \ + append-metadata | \ + linksys-image | \ + belkin-header +endef +TARGET_DEVICES += linksys_lgs310c + # "NGE" refers to the uImage magic define Device/netgear_nge KERNEL := \