Porting OpenWrt to WinkHub v1

Hi folks,

I am trying to port OpenWrt to the Wink Hub v1, which is an i.MX28-based board with a whole bunch of IoT radios attached via serial ports. The standard flash has updater_kernel and updater-root partitions intended for recovery and update purposes, which appears to be ideal for messing around with OpenWrt, but still keep the ability to boot back to a working OS.
I have downloaded the duckbill i.MX28 kernel from the 19.07.2 release, and have written it to /dev/mtd1 using nandwrite. (This is a whole other story, having started with dd and caused a whole bunch of ECC bitflip errors on the NAND, I had to work around that by erasing the partition inside u-boot to get rid of the errors!)
Unfortunately, while loading the kernel from mtd updater-kernel works, and iminfo reports the correct header information, the kernel fails to boot.

U-Boot 2014.01-14400-gda781c6-dirty (Apr 30 2014 - 22:35:38)

CPU:   Freescale i.MX28 rev1.2 at 454 MHz
BOOT:  NAND, 3V3
DRAM:  64 MiB
NAND:  128 MiB
In:    serial
Out:   serial
Err:   serial
Net:   FEC0 [PRIME]
Hit any key to stop autoboot:  0 
=> setenv bootargs 'noinitrd console=ttyS0,115200 rootfstype=ubifs ubi.mtd=5 root=ubi0:rootfs rw gpmi'; mtdparts default && ubi part database && ubifsmount ubi0:database && ubifsload ${loadaddr} openwrt-19.07.1-mxs-uImage 1799536 && bootm ${loadaddr}
UBI: attaching mtd1 to ubi0
UBI: physical eraseblock size:   131072 bytes (128 KiB)
UBI: logical eraseblock size:    126976 bytes
UBI: smallest flash I/O unit:    2048
UBI: VID header offset:          2048 (aligned 2048)
UBI: data offset:                4096
UBI: attached mtd1 to ubi0
UBI: MTD device name:            "mtd=3"
UBI: MTD device size:            8 MiB
UBI: number of good PEBs:        64
UBI: number of bad PEBs:         0
UBI: max. allowed volumes:       128
UBI: wear-leveling threshold:    4096
UBI: number of internal volumes: 1
UBI: number of user volumes:     1
UBI: available PEBs:             6
UBI: total number of reserved PEBs: 58
UBI: number of PEBs reserved for bad PEB handling: 2
UBI: max/mean erase counter: 63/45
UBIFS: mounted UBI device 0, volume 0, name "database"
UBIFS: mounted read-only
UBIFS: file system size:   5459968 bytes (5332 KiB, 5 MiB, 43 LEBs)
UBIFS: journal size:       1015809 bytes (992 KiB, 0 MiB, 6 LEBs)
UBIFS: media format:       w4/r0 (latest is w4/r0)
UBIFS: default compressor: LZO
UBIFS: reserved for root:  269835 bytes (263 KiB)
Loading file 'openwrt-19.07.1-mxs-uImage' to addr 0x42000000 with size 1799536 (0x001b7570)...
Done
## Booting kernel from Legacy Image at 42000000 ...
   Image Name:   ARM OpenWrt Linux-4.14.167
   Created:      2020-01-29  16:05:35 UTC
   Image Type:   ARM Linux Kernel Image (uncompressed)
   Data Size:    1799472 Bytes = 1.7 MiB
   Load Address: 40008000
   Entry Point:  40008000
   Verifying Checksum ... OK
   Loading Kernel Image ... OK

Starting kernel ...

I have actually tried writing the OpenWrt kernel to a USBIFS partition as well, and copying the kernel from there, but it fails in exactly the same way as it does if I load it from mtd1/updater-kernel.

Does anyone have any ideas as to why the modern kernel won't boot, while the ancient 2.6.35 one provided by the vendor does? My first thought is that the method that u-boot uses to pass bootargs to the kernel has changed, and as a result, the kernel is not aware of the available serial port for boot-time logging. But I have no idea what it should be doing, or how to check.

What's the corresponding output when the legacy vendor supplied kernel boots? Can you post that?

Truncated boot log, showing the u-boot environment settings, and the initial boot messages from the vendor kernel.
Full boot log available here: https://pastebin.com/swviZcPa

U-Boot 2014.01-14400-gda781c6-dirty (Apr 30 2014 - 22:35:38)

CPU:   Freescale i.MX28 rev1.2 at 454 MHz
BOOT:  NAND, 3V3
DRAM:  64 MiB
NAND:  128 MiB
In:    serial
Out:   serial
Err:   serial
Net:   FEC0 [PRIME]
Hit any key to stop autoboot:  0 
=> 
=> printenv
app_boot=run appboot_args && nand read ${loadaddr} app-kernel 0x00400000 && bootm ${loadaddr}
app_boot_bad=run updater_args; setenv bootargs ${bootargs} badapp; nand read ${loadaddr} updater-kernel 0x00300000; bootm ${loadaddr}
appboot_args=setenv bootargs 'noinitrd console=ttyAM0,115200 rootfstype=ubifs ubi.mtd=5 root=ubi0:rootfs rw gpmi';
baudrate=115200
bd_addr=0021CC06B4DA
boot_app=run app_boot || run app_boot_bad
boot_getflag=mtdparts default && ubi part database && ubifsmount ubi0:database && mw 42000000 0 8 && ubifsload 42000000 DO_UPDATE 1 && run boot_logic
boot_logic=mw 42000004 30; if cmp 42000000 42000004 1; then run boot_app; else run boot_updater; fi;
boot_updater=run updater_boot || run updater_boot_bad
bootcmd=mtdparts default; run boot_getflag || echo Falling back to updater...; run boot_updater
bootdelay=1
bootfile=uImage
ethact=FEC0
ethaddr=00:04:00:00:00:00
ethprime=FEC0
loadaddr=0x42000000
serialno=142103108WZD1
stderr=serial
stdin=serial
stdout=serial
updater_args=setenv bootargs 'noinitrd console=ttyAM0,115200 rootfstype=ubifs ubi.mtd=2 root=ubi0:rootfs rw gpmi';
updater_boot=run updater_args && nand read ${loadaddr} updater-kernel 0x00300000 && bootm ${loadaddr}
updater_boot_bad=run appboot_args; setenv bootargs ${bootargs} badupdater; nand read ${loadaddr} app-kernel 0x00400000; bootm ${loadaddr}
ver=U-Boot 2014.01-14400-gda781c6-dirty (Apr 30 2014 - 22:35:38)

Environment size: 1456/16379 bytes
=> setenv bootargs 'noinitrd console=ttyAM0,115200 rootfstype=ubifs ubi.mtd=5 root=ubi0:rootfs rw gpmi';
=> mtdparts default
=> nand read ${loadaddr} app-kernel 0x00400000 && bootm ${loadaddr}

NAND read: device 0 offset 0x2b00000, size 0x400000
 4194304 bytes read: OK
## Booting kernel from Legacy Image at 42000000 ...
   Image Name:   Linux-2.6.35.3-flex-dvt
   Created:      2014-04-30   3:15:35 UTC
   Image Type:   ARM Linux Kernel Image (uncompressed)
   Data Size:    1928460 Bytes = 1.8 MiB
   Load Address: 40008000
   Entry Point:  40008000
   Verifying Checksum ... OK
   Loading Kernel Image ... OK

Starting kernel ...

Uncompressing Linux... done, booting the kernel.
Linux version 2.6.35.3-flex-dvt (saurabh@localhost.localdomain) (gcc version 4.4.4 (4.4.4_09.06.2010) ) #32 PREEMPT Tue Apr 29 23:15:31 EDT 2014
CPU: ARM926EJ-S [41069265] revision 5 (ARMv5TEJ), cr=00053177
CPU: VIVT data cache, VIVT instruction cache
Machine: Freescale MX28EVK board
Memory policy: ECC disabled, Data cache writeback
Built 1 zonelists in Zone order, mobility grouping on.  Total pages: 16256
Kernel command line: noinitrd console=ttyAM0,115200 rootfstype=ubifs ubi.mtd=5 root=ubi0:rootfs rw gpmi
PID hash table entries: 256 (order: -2, 1024 bytes)
Dentry cache hash table entries: 8192 (order: 3, 32768 bytes)
Inode-cache hash table entries: 4096 (order: 2, 16384 bytes)
Memory: 64MB = 64MB total
Memory: 60784k/60784k available, 4752k reserved, 0K highmem
Virtual kernel memory layout:
    vector  : 0xffff0000 - 0xffff1000   (   4 kB)
    fixmap  : 0xfff00000 - 0xfffe0000   ( 896 kB)
    DMA     : 0xfde00000 - 0xffe00000   (  32 MB)
    vmalloc : 0x84800000 - 0xf0000000   (1720 MB)
    lowmem  : 0x80000000 - 0x84000000   (  64 MB)
    modules : 0x7f000000 - 0x80000000   (  16 MB)
      .init : 0x80008000 - 0x80027000   ( 124 kB)
      .text : 0x80027000 - 0x803b6000   (3644 kB)
      .data : 0x803b6000 - 0x803deec0   ( 164 kB)
SLUB: Genslabs=11, HWalign=32, Order=0-3, MinObjects=0, CPUs=1, Nodes=1
Hierarchical RCU implementation.
	RCU-based detection of stalled CPUs is disabled.
	Verbose stalled-CPUs detection is disabled.
NR_IRQS:288

As an extra data point, here is a comparison of the files written to that partition:

% file nandbackup/mtd1 openwrt-19.07.1-mxs-uImage 
nandbackup/mtd1:            u-boot legacy uImage, Linux-2.6.35.3-flex-dvt, Linux/ARM, OS Kernel Image (Not compressed), 1928460 bytes, Wed Apr 30 03:15:35 2014, Load Address: 0x40008000, Entry Point: 0x40008000, Header CRC: 0xDF2294AE, Data CRC: 0xCE6AAB35
openwrt-19.07.1-mxs-uImage: u-boot legacy uImage, ARM OpenWrt Linux-4.14.167, Linux/ARM, OS Kernel Image (Not compressed), 1799472 bytes, Wed Jan 29 16:05:35 2020, Load Address: 0x40008000, Entry Point: 0x40008000, Header CRC: 0xFD476D82, Data CRC: 0x70AA943F

Superficially, they appear to be configured the same, from what I can tell.

Any update? Or luck?

Unfortunately not. I haven't really tried much further, though.

My current status is essentially the same as above. I tried a couple of kernel builds, I had thought that perhaps I had the logging set up incorrectly, but that made no difference. But I had actually forgotten about the avenue of checking the differences between parameter passing from uboot to kernel. Perhaps I can simulate something with the old uboot, or alternatively, see if I can get a new uboot onto the device, since I do have JTAG access. That does seem like another good avenue to investigate.

What are your intentions for the Wink? I was hoping to simply expose the radios using ser2net or similar, or even run ZHA or Zigbee2MQTT on the Wink, if I could only get the kernel booting!

Trying this again, I posted to the u-boot list, and was told that modern kernels need the device tree appended to them if the bootloader will not provide them. I tried following the instructions from the poster (check the u-boot list archives for details), but so far I have still not been able to get any output from my own kernels running on the Wink Hub v1.

Ah, the solution appears to be that the kernel naming for the console device has changed between the original kernel version and current mainline. The console should be /dev/ttyAMA0, not /dev/ttyAM0. I still don't have a good booting solution, but I figure I am a lot closer now.

Ok, I now have a booting kernel, with a fairly minimal device tree, based on the mxs imagebuilder download. If I concatenate the device tree to the zImage, make a uImage of it, then write that to the updater-kernel partition, it will try to boot up to the point that it has to mount the UBIFS root partition. It is important to change the console device from ttyAM0 to ttyAMA0 in updater_args, as this name has changed in more modern kernels.

Next step is to create a new target profile that results in a kernel that supports rootfs on ubifs, and creates a base image in a UBIFS that can be flashed to the available partition. For the moment I am experimenting with the updater_kernel and updater-rootfs partitions, but it would obviously make more sense to take over the app-kernel and gpmi-nfc-general-use partitions as they are simply larger.

Does the nand flash come up already or are you not there yet? Can you post your current bootlog and the DTS you have for it?

The NAND flash is now coming up, which is excellent. I can mount the existing UBIFS filesystems as well (although I am currently booting to an initramfs, just to simplify things a bit). My current stumbling block is the BRCMFMAC firmware - it's looking for 4334-sdio, and that doesn't seem to exist at all in the OpenWrt repositories, although I have found it in e.g. the LibreElec repos.

My WIP patch and current boot.log is available here: https://gist.github.com/RoganDawes/0b21821408b96ad184abb07d6d01128d

Should apply on top of mainline OpenWrt.

Sounds great! For brcmfmac, there should be nothing stopping you from adding a new package def into package/firmware/linux-firmware/broadcom.mk for the 4334-sdio firmware - it's in the linux-firmware repository. Good to see a new device coming to mxs/ after a long time.

Hi @RoganDawes

Great to see the progress.

The brcmfmac4334-sdio.bin can be found at the official linux-firmware repo:

https://git.kernel.org/pub/scm/linux/kernel/git/firmware/linux-firmware.git/tree/brcm

You will also need a brcmfmac43340-sdio.xxx.txt file, which is board-specific, but hopefully, you will be able to reuse one of the available brcmfmac43340-sdio.xxx.txt files in the linux-firmware repo.

I meant a brcmfmac4334-sdio.xxx.txt file, not brcmfmac43340-sdio.xxx.txt file.

Just to keep some progress out in public:

With Fabio's help, I have managed to get the WiFi interface recognized, as well as able to identify surrounding access points. This using the 4334 firmware bin from the firmware project as mentioned above, and an nvram file for a rockchip 3318-based device, plus an undocumented boardflags3=0x08000000 entry. So far I am still unable to actually associate with any AP (psk2 or open), hostapd reports only a bssid of all zeroes when trying to connect.

wlan0: Trying to associate with SSID 'Dawes'
wlan0: CTRL-EVENT-ASSOC-REJECT bssid=00:00:00:00:00:00 status_code=16
wlan0: Trying to associate with SSID 'Dawes'
wlan0: CTRL-EVENT-ASSOC-REJECT bssid=00:00:00:00:00:00 status_code=16
wlan0: Trying to associate with SSID 'Dawes'
wlan0: CTRL-EVENT-ASSOC-REJECT bssid=00:00:00:00:00:00 status_code=16
wlan0: Trying to associate with SSID 'Dawes'
wlan0: CTRL-EVENT-ASSOC-REJECT bssid=00:00:00:00:00:00 status_code=16
BSSID 2a:d1:27:1b:37:12 ignore list count incremented to 2, ignoring for 10 seconds
wlan0: CTRL-EVENT-SSID-TEMP-DISABLED id=0 ssid="Dawes" auth_failures=1 duration=10 r
eason=CONN_FAILED

I haven't made much progress on this, unfortunately.

I did think that it would be great to have networking on the board, even though the WiFi is not working, and there is no Ethernet port. I do however have a microUSB connector soldered on, and have confirmed that it is correctly wired up by getting the board into Serial Download Protocol mode, enumerating over a microUSB cable to the host. I spent a good part of a day trying to get the chipidea USB OTG driver kmod built into the image, but could never see it being packaged as a kmod. Turns out I have been ignoring the fact that the USB port is not defined in the device tree, and that is the reason that the chipidea driver, which is actually built in to the kernel not as a module, is not loading.

However, I still sit with the conclusion that I really don't understand the separation between a generic architecture configuration that applies to all derivatives, and board specific configuration that would only get built for that particular board. Can anyone help explain this to me? Where is the line drawn? Why is it optional to choose multiple devices to build for, and how does a Kconfig entry actually get activated?

So, the good news is that I am able to build a linux-6.1-based OpenWrt ramdisk, and, using the /root/wireless/nvram.conf from the original manufacturer firmware as /lib/firmware/brcm/brcmfmac4334-sdio.wink,imx28-wink-hub-v1.txt, can get WiFi working!

Now to get the UBI support into the 6.1 kernel configuration, and I should finally be in a position to install something permanently on the flash!

Thought I would update here in case anyone is interested.

I have been able to get a mainline u-boot working on my Wink 1. It was a little tricky because the DDR2 chip on my board seems to be different from the one on the original boards - I guess they changed supplier part way through. This necessitated a different DDR2 initialisation sequence that was a little tricky to figure out. Nonetheless, with the incredible help of Fabio Estevam, I have been able to get both u-boot and Linux mainline booting from flash on my Wink Hub 1.

I now need to figure out how best to reassign the flash partitions to support OpenWrt, and figure out why the radios are not powering on, and then I should be very close to having an OpenWrt build for it, that can be used to bring the hub into a home automation system, such as Home Assistant.