Support for (unbranded) MT7620a

I’m trying to add support for a no-name MT7620a router with a Marvell/ASR modem but I’ve been running into issues. I followed the developer guides and searched the commits but couldn’t find any for debugging. I’ve added the necessary modules for SquashFS, modem support, USB, and other stuff but every build ends up with a kernel panic. The logs don’t provide a clear indication of what’s causing the issue.

I even tried creating a minimal build with no additional modules or packages, but the kernel panic still occurs. Interestingly, I tested loading a few InitramFS images from a different MT7620A device, and it booted successfully. However, only the Ethernet interface was functional, and the device became noticeably warm after a few minutes.

Here are the boot logs:

Bytes transferred = 5202088 (4f60a8 hex)
NetBootFileXferSize= 004f60a8
Automatic boot of image at addr 0x80A00000 ...
## Booting image at 80a00000 ...
   Image Name:   MIPS OpenWrt Linux-5.15.167
   Image Type:   MIPS Linux Kernel Image (lzma compressed)
   Data Size:    5202024 Bytes =  5 MB
   Load Address: 80000000
   Entry Point:  80000000
   Verifying Checksum ... OK
   Uncompressing Kernel Image ... OK
No initrd
## Transferring control to Linux (at address 80000000) ...
## Giving linux memsize in MB, 128

Starting kernel ...

[    0.000000] Linux version 5.15.167 (connor@DesktopPC-n3) (mipsel-openwrt-linux-musl-gcc (OpenWrt GCC 12.3.0 r24106-10cc5fcd00) 12.3.0, GNU ld (GNU Binutils) 2.40.0) #0 Mon Sep 23 12:34:46 2024
[    0.000000] Board has DDR2
[    0.000000] Analog PMU set to hw control
[    0.000000] Digital PMU set to hw control
[    0.000000] SoC Type: MediaTek MT7620A ver:2 eco:6
[    0.000000] printk: bootconsole [early0] enabled
[    0.000000] CPU0 revision is: 00019650 (MIPS 24KEc)
[    0.000000] MIPS: machine is SmartInc Prodv1-9c
[    0.000000] Initrd not found or empty - disabling initrd
[    0.000000] Primary instruction cache 64kB, VIPT, 4-way, linesize 32 bytes.
[    0.000000] Primary data cache 32kB, 4-way, PIPT, no aliases, linesize 32 bytes
[    0.000000] Zone ranges:
[    0.000000]   Normal   [mem 0x0000000000000000-0x0000000007ffffff]
[    0.000000] Movable zone start for each node
[    0.000000] Early memory node ranges
[    0.000000]   node   0: [mem 0x0000000000000000-0x0000000007ffffff]
[    0.000000] Initmem setup node 0 [mem 0x0000000000000000-0x0000000007ffffff]
[    0.000000] Built 1 zonelists, mobility grouping on.  Total pages: 32480
[    0.000000] Kernel command line: console=ttyS0,57600 rootfstype=squashfs,jffs2
[    0.000000] Dentry cache hash table entries: 16384 (order: 4, 65536 bytes, linear)
[    0.000000] Inode-cache hash table entries: 8192 (order: 3, 32768 bytes, linear)
[    0.000000] Writing ErrCtl register=0007a12b
[    0.000000] Readback ErrCtl register=0007a12b
[    0.000000] mem auto-init: stack:off, heap alloc:off, heap free:off
[    0.000000] Memory: 118180K/131072K available (5545K kernel code, 604K rwdata, 1188K rodata, 3984K init, 215K bss, 12892K reserved, 0K cma-reserved)
[    0.000000] SLUB: HWalign=32, Order=0-3, MinObjects=0, CPUs=1, Nodes=1
[    0.000000] NR_IRQS: 256
[    0.000000] CPU Clock: 580MHz
[    0.000000] clocksource: systick: mask: 0xffff max_cycles: 0xffff, max_idle_ns: 583261500 ns
[    0.000000] systick: enable autosleep mode
[    0.000000] systick: running - mult: 214748, shift: 32
[    0.000000] clocksource: MIPS: mask: 0xffffffff max_cycles: 0xffffffff, max_idle_ns: 6590553264 ns
[    0.000002] sched_clock: 32 bits at 290MHz, resolution 3ns, wraps every 7405115902ns
[    0.015564] Calibrating delay loop... 385.84 BogoMIPS (lpj=1929216)
[    0.087785] pid_max: default: 32768 minimum: 301
[    0.098134] Mount-cache hash table entries: 1024 (order: 0, 4096 bytes, linear)
[    0.112566] Mountpoint-cache hash table entries: 1024 (order: 0, 4096 bytes, linear)
[    0.137859] clocksource: jiffies: mask: 0xffffffff max_cycles: 0xffffffff, max_idle_ns: 19112604462750000 ns
[    0.157367] futex hash table entries: 256 (order: -1, 3072 bytes, linear)
[    0.171078] pinctrl core: initialized pinctrl subsystem
[    0.182909] NET: Registered PF_NETLINK/PF_ROUTE protocol family
[    0.199611] rt2880-pinmux pinctrl: there is not valid maps for state default
[    0.230103] rt2880_gpio 10000600.gpio: registering 24 gpios
[    0.241175] rt2880_gpio 10000600.gpio: registering 24 irq handlers
[    0.256080] clocksource: Switched to clocksource systick
[    0.268384] NET: Registered PF_INET protocol family
[    0.278341] IP idents hash table entries: 2048 (order: 2, 16384 bytes, linear)
[    0.293544] tcp_listen_portaddr_hash hash table entries: 1024 (order: 0, 4096 bytes, linear)
[    0.310312] Table-perturb hash table entries: 65536 (order: 6, 262144 bytes, linear)
[    0.325636] TCP established hash table entries: 1024 (order: 0, 4096 bytes, linear)
[    0.340877] TCP bind hash table entries: 1024 (order: 0, 4096 bytes, linear)
[    0.354896] TCP: Hash tables configured (established 1024 bind 1024)
[    0.367723] UDP hash table entries: 256 (order: 0, 4096 bytes, linear)
[    0.380659] UDP-Lite hash table entries: 256 (order: 0, 4096 bytes, linear)
[    0.394964] NET: Registered PF_UNIX/PF_LOCAL protocol family
[    0.406216] PCI: CLS 0 bytes, default 32
[    0.414170] rt-timer 10000100.timer: maximum frequency is 1220Hz
[    1.118345] workingset: timestamp_bits=14 max_order=15 bucket_order=1
[    1.138677] squashfs: version 4.0 (2009/01/31) Phillip Lougher
[    1.150210] jffs2: version 2.2 (NAND) (SUMMARY) (LZMA) (RTIME) (CMODE_PRIORITY) (c) 2001-2006 Red Hat, Inc.
[    1.173468] Serial: 8250/16550 driver, 2 ports, IRQ sharing disabled
[    1.187483] printk: console [ttyS0] disabled
[    1.195936] 10000c00.uartlite: ttyS0 at MMIO 0x10000c00 (irq = 20, base_baud = 2500000) is a Palmchip BK-3103
[    1.215677] printk: console [ttyS0] enabled
[    1.215677] printk: console [ttyS0] enabled
[    1.232199] printk: bootconsole [early0] disabled
[    1.232199] printk: bootconsole [early0] disabled
[    1.259206] spi spi0.0: force spi mode3
[    1.267833] spi-nor spi0.0: mx25l12805d (16384 Kbytes)
[    1.278291] 5 fixed-partitions partitions found on MTD device spi0.0
[    1.291001] Creating 5 MTD partitions on "spi0.0":
[    1.300610] 0x000000000000-0x000000030000 : "bootloader"
[    1.312975] 0x000000030000-0x000000040000 : "config"
[    1.324507] 0x000000040000-0x000000050000 : "factory"
[    1.336427] 0x000000050000-0x000000060000 : "kernel"
[    1.347921] 0x000000060000-0x000000080000 : "rootfs"
[    1.359599] mtd: setting mtd4 (rootfs) as root device
[    1.369938] mtdsplit: no squashfs found in "rootfs"
[    1.396195] gsw: setting port4 to ephy mode
[    1.404709] mtk_soc_eth 10100000.ethernet: generated random MAC address 02:7e:43:78:d1:02
[    1.421062] mtk_soc_eth 10100000.ethernet: mdio-bus disabled
[    1.432576] mtk_soc_eth 10100000.ethernet: loaded mt7620 driver
[    1.445265] mtk_soc_eth 10100000.ethernet eth0: mediatek frame engine at 0xb0100000, irq 5
[    1.462589] rt2880_wdt 10000120.watchdog: Initialized
[    1.474730] NET: Registered PF_INET6 protocol family
[    2.147991] Segment Routing with IPv6
[    2.155426] In-situ OAM (IOAM) with IPv6
[    2.163469] NET: Registered PF_PACKET protocol family
[    2.173646] 8021q: 802.1Q VLAN Support v1.8
[    2.184536] clk: Disabling unused clocks
[    3.629999] mtk_soc_eth 10100000.ethernet eth0: port 4 link up (100Mbps/Full duplex)
[    6.918012] Freeing unused kernel image (initmem) memory: 3984K
[    6.929866] This architecture does not have kernel memory protection.
[    6.942722] Run /init as init process
switch_root: can[    7.609469] Kernel panic - not syncing: Attempted to kill init! exitcode=0x00000100
[    7.627410] Rebooting in 1 seconds..

Does anyone have insights into what might be causing this or how I can debug it further?

Thanks in advance!

Your build is looking for /init on mtd4, but on mtd4, no valid filesystem was found. I suppose you didn't build an initramfs image or are not booting an initramfs image (or the build didn't succeed) - at least, it's not finding your rootfs.

It's hard to diagnose more without seeing your build recipe (i.e. the image generation Makefile).

Check flash partitioning. I am sure that this variant:

is incorrect.
Or show your current dts-file

I'm not sure why but the kernel panic is gone (at least for InitramFS.bin). The issue occurred when I used dnsmasq and atftpd on Linux but not on Windows with tftpd64. The Makefile is still the same as I cloned it:

DEVICE_VARS += LOADER_TYPE LOADER_FLASH_OFFS LZMA_TEXT_START
DEVICE_VARS += NETGEAR_BOARD_ID NETGEAR_HW_ID
DEVICE_VARS += NETGEAR_ENC_MODEL NETGEAR_ENC_REGION NETGEAR_ENC_HW_ID_LIST NETGEAR_ENC_MODEL_LIST
DEVICE_VARS += BUFFALO_TAG_PLATFORM BUFFALO_TAG_VERSION BUFFALO_TAG_MINOR
DEVICE_VARS += SEAMA_SIGNATURE SEAMA_MTDBLOCK
DEVICE_VARS += SERCOMM_HWNAME SERCOMM_HWID SERCOMM_HWVER SERCOMM_SWVER
DEVICE_VARS += SERCOMM_PAD JCG_MAXSIZE

loadaddr-y := 0x80000000
loadaddr-$(CONFIG_TARGET_ramips_rt288x) := 0x88000000
loadaddr-$(CONFIG_TARGET_ramips_mt7621) := 0x80001000

ldrplatform-y := ralink
ldrplatform-$(CONFIG_TARGET_ramips_mt7621) := mt7621

ldrflashstart-y := 0x1c000000
ldrflashstart-$(CONFIG_TARGET_ramips_mt7621) := 0x1fc00000

LOADADDR := $(loadaddr-y)
LOADER_PLATFORM := $(ldrplatform-y)
LOADER_FLASH_START := $(ldrflashstart-y)

KERNEL_DTB = kernel-bin | append-dtb | lzma

define Build/jcg-header
	$(STAGING_DIR_HOST)/bin/jcgimage -v $(1) \
		$(if $(JCG_MAXSIZE), -m $$(($(subst k, * 1024,$(JCG_MAXSIZE)))),) \
		-u $@ -o $@.new
	mv $@.new $@
endef

define Build/loader-common
	rm -rf $@.src
	$(MAKE) -C lzma-loader \
		PKG_BUILD_DIR="$@.src" \
		TARGET_DIR="$(dir $@)" LOADER_NAME="$(notdir $@)" \
		BOARD="$(BOARDNAME)" PLATFORM="$(LOADER_PLATFORM)" \
		LZMA_TEXT_START=$(LZMA_TEXT_START) \
		LOADADDR=$(LOADADDR) \
		SUBTARGET=$(SUBTARGET) \
		$(1) compile loader.$(LOADER_TYPE)
	mv "$@.$(LOADER_TYPE)" "$@"
	rm -rf $@.src
endef

define Build/loader-kernel
	$(call Build/loader-common,LOADER_DATA="$@")
endef

define Build/loader-okli-compile
	$(call Build/loader-common, \
		FLASH_START=$(LOADER_FLASH_START) \
		FLASH_OFFS=$(LOADER_FLASH_OFFS) \
		FLASH_MAX=0 \
	)
endef

define Build/append-loader-okli
	cat "$(KDIR)/loader-$(word 1,$(1)).$(LOADER_TYPE)" >> "$@"
endef

# combine kernel and rootfs into one image
# mkdlinkfw <type> <optional extra arguments to mkdlinkfw binary>
define Build/mkdlinkfw
	-$(STAGING_DIR_HOST)/bin/mkdlinkfw \
		-k $(IMAGE_KERNEL) \
		-r $(IMAGE_ROOTFS) \
		-o $@ \
		$(if $(DLINK_IMAGE_OFFSET), -O $(DLINK_IMAGE_OFFSET)) \
		-s $(DLINK_FIRMWARE_SIZE)
endef

define Build/mkdlinkfw-factory
	-$(STAGING_DIR_HOST)/bin/mkdlinkfw \
		-m $(DLINK_ROM_ID) -f $(DLINK_FAMILY_MEMBER) \
		-F $@ \
		-o $@.new \
		$(if $(DLINK_IMAGE_OFFSET), -O $(DLINK_IMAGE_OFFSET)) \
		-s $(DLINK_FIRMWARE_SIZE)
	mv $@.new $@
endef

define Build/mkdlinkfw-loader
	-$(STAGING_DIR_HOST)/bin/mkdlinkfw \
		-k $(KDIR)/loader-$(DEVICE_NAME).bin \
		-r $@ \
		-o $@.new \
		$(if $(DLINK_IMAGE_OFFSET), -O $(DLINK_IMAGE_OFFSET)) \
		-s $(DLINK_FIRMWARE_SIZE)
	mv $@.new $@
endef

define Build/netis-tail
	echo -n $(1) >> $@
	echo -n $(UIMAGE_NAME)-yun | $(MKHASH) md5 | \
		sed 's/../\\\\x&/g' | xargs echo -ne >> $@
endef

define Build/poray-header
	$(STAGING_DIR_HOST)/bin/mkporayfw $(1) -f $@ -o $@.new
	mv $@.new $@
endef

define Build/relocate-kernel
	rm -rf $@.relocate
	$(CP) ../../generic/image/relocate $@.relocate
	$(MAKE) -C $@.relocate KERNEL_ADDR=$(if $(1),$(1),$(KERNEL_LOADADDR)) CROSS_COMPILE=$(TARGET_CROSS)
	( \
		dd if=$@.relocate/loader.bin bs=32 conv=sync && \
		perl -e '@s = stat("$@"); print pack("V", @s[7])' && \
		cat $@ \
	) > $@.new
	mv $@.new $@
	rm -rf $@.relocate
endef

define Build/sercom-footer
	$(call Build/sercom-seal,-f)
endef

define Build/sercom-seal
	$(STAGING_DIR_HOST)/bin/mksercommfw \
		-i $@ \
		-b $(SERCOMM_HWID) \
		-r $(SERCOMM_HWVER) \
		-v $(SERCOMM_SWVER) \
		$(1)
endef

define Build/sign-dlink-ru
	sign_dlink_ru $@ $1 $2
	mv $@.new $@
endef

define Build/trx
	$(STAGING_DIR_HOST)/bin/trx $(1) \
		-o $@ \
		-m $$(($(subst k, * 1024,$(IMAGE_SIZE)))) \
		-f $(IMAGE_KERNEL) \
		-a 4 -f $(IMAGE_ROOTFS)
endef

define Build/uimage-padhdr
	uimage_padhdr $(if $(1),-l $(1)) -i $@ -o $@.new
	mv $@.new $@
endef

define Build/uimage-sgehdr
	uimage_sgehdr -i $@ -o $@.new -m $(DEVICE_MODEL) \
		-h $(DEVICE_VARIANT) -s V1.00000
	mv $@.new $@
endef

define Build/umedia-header
	fix-u-media-header -T 0x46 -B $(1) -i $@ -o $@.new && mv $@.new $@
endef

define Build/wrg-header
	mkwrgimg -i $@ -d "/dev/mtdblock/2" -s $(1) -o $@.new
	mv $@.new $@
endef

define Build/zyimage
	$(STAGING_DIR_HOST)/bin/zyimage $(1) $@
endef

define Device/Default
  PROFILES = Default
  BLOCKSIZE := 64k
  KERNEL := $(KERNEL_DTB) | uImage lzma
  KERNEL_LOADADDR := $(loadaddr-y)
  LZMA_TEXT_START := 0x81800000
  SOC := $(DEFAULT_SOC)
  DEVICE_DTS_DIR := ../dts
  DEVICE_DTS = $$(SOC)_$(1)
  NETGEAR_ENC_MODEL :=
  NETGEAR_ENC_REGION :=
  NETGEAR_ENC_HW_ID_LIST :=
  NETGEAR_ENC_MODEL_LIST :=
  IMAGES := sysupgrade.bin
  COMPILE :=
  sysupgrade_bin := append-kernel | append-rootfs | pad-rootfs
  IMAGE/sysupgrade.bin := append-kernel | append-rootfs | pad-rootfs | check-size | append-metadata
endef

define Device/netgear_sercomm_nor
  DEVICE_VENDOR := NETGEAR
  IMAGES += factory.img
  IMAGE/default := append-kernel | pad-to $$$$(BLOCKSIZE) | append-rootfs | \
	pad-rootfs
  IMAGE/sysupgrade.bin := $$(IMAGE/default) | check-size | append-metadata
  IMAGE/factory.img := pad-extra $$$$(SERCOMM_PAD) | $$(IMAGE/default) | \
	pad-to $$$$(BLOCKSIZE) | sercom-footer | pad-to 128 | \
	zip $$$$(SERCOMM_HWNAME).bin | sercom-seal
endef

define Device/seama
  SEAMA_MTDBLOCK := 2
  IMAGES += factory.bin

  # 64 bytes offset:
  # - 28 bytes seama_header
  # - 36 bytes of META data (4-bytes aligned)
  IMAGE/default := append-kernel | pad-offset $$$$(BLOCKSIZE) 64 | append-rootfs
  IMAGE/sysupgrade.bin := \
	$$(IMAGE/default) | seama | pad-rootfs | check-size | append-metadata
  IMAGE/factory.bin := \
	$$(IMAGE/default) | pad-rootfs -x 64 | seama | seama-seal | check-size
  SEAMA_SIGNATURE :=
endef

define Device/uimage-lzma-loader
  LOADER_TYPE := bin
  KERNEL/lzma-loader := kernel-bin | append-dtb | lzma | loader-kernel
  KERNEL := $$(KERNEL/lzma-loader) | uImage none
endef

define Device/seama-lzma-loader
  $(Device/seama)
  $(Device/uimage-lzma-loader)
  KERNEL := $$(KERNEL/lzma-loader) | relocate-kernel | lzma -a0
  KERNEL_INITRAMFS := $$(KERNEL/lzma-loader) | uImage none
endef

include $(SUBTARGET).mk

$(eval $(call BuildImage))

The only files I modified was board.d, .config, and mt7620.mk

mt7620.mk
define Device/smartinc_prodv1-9c
  SOC := mt7620a
  IMAGE_SIZE := 16064k
  DEVICE_VENDOR := SmartInc
  DEVICE_MODEL := Prodv1-9c
DEVICE_PACKAGES:= kmod-usb2 kmod-usb-ohci kmod-usb-net-cdc-ether kmod-usb-acm kmod-usb-net-rndis kmod-usb-serial-option
  SUPPORTED_DEVICES += Prodv1-9c
endef
TARGET_DEVICES += smartinc_prodv1-9c

Here is my DTS:

#include "mt7620a.dtsi"

#include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/input/input.h>

/{
	model = "SmartInc Prodv1-9c";
	compatible = "smartinc,prodv1-9c", "mediatek,mt7620a";

	gpio-export {
		compatible = "gpio-export";
		#size-cells = <0>;
		modem_sense {
			gpio-export,name = "modem_sense";
			gpio-export,output = <0>;
			gpios = <&gpio2 5 GPIO_ACTIVE_LOW>;
		};
		modem_power {
			gpio-export,name = "modem_power";
			gpio-export,output = <0>;
			gpios = <&gpio2 9 GPIO_ACTIVE_HIGH>;
		};
	};

	leds {
		compatible = "gpio-leds";
		
		modem_red {
			label = "red:modem";
			gpios = <&gpio2 19 GPIO_ACTIVE_LOW>;
		};

		modem_green {
			label = "green:modem";
			gpios = <&gpio0 8 GPIO_ACTIVE_LOW>;
		};

		modem_blue {
			label = "blue:modem";
			gpios = <&gpio0 7 GPIO_ACTIVE_LOW>;
		};
	};

	keys {
		compatible = "gpio-keys";

		reset {
			label = "reset";
			gpios = <&gpio2 29 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 = "ralink-uboot";
				reg = <0x00000000 0x00030000>;
				read-only;
			};

			partition@30000 {
				label = "tftp-config";
				reg = <0x00030000 0x00010000>;
				read-only;
			};

			factory: partition@40000 {
				label = "factory";
				reg = <0x40000 0x10000>;
				read-only;
			};

			partition@50000 {
				label = "firmware";
				reg = <0x50000 0xfb0000>;
			};
		};
	};

};

&gpio1 {
	status = "okay";
};

&gpio2 {
	status = "okay";
};

&state_default {
	gpio {
		groups = "i2c", "wled", "spi refclk", "uartf", "ephy";
		function = "gpio";
	};
};

&ehci {
	status = "okay";
};

&ohci {
	status = "okay";
};

&ethernet {
	nvmem-cells = <&macaddr_factory_28>;
	nvmem-cell-names = "mac-address";
};

&wmac {
	ralink,mtd-eeprom = <&factory 0x0>;
};

&factory {
	compatible = "nvmem-cells";
	#address-cells = <1>;
	#size-cells = <1>;

	macaddr_factory_28: macaddr@28 {
		reg = <0x28 0x6>;
	};
};

I cross-referenced other DTS's for this one. I don't see why it was refusing to initialize.

By the way is this the right way to set-up the EEPROM for the WiFi? It was loaded successfully during boot but the driver gives an error that RXIQ failed calibration multiple times. The WiFi range is only within a few inches from the device.

The factory partition looks like this:

Not sure if the radio calibration is at 0xD0 because 0x28 onwards are for the Ethernet