VoCore2: install python3

Currently we can directly use python3.6 on VoCore2.
Install python3 is easy, need to download some ipk packages.
I have uploaded them to http://vonger.cn/misc/vocore2/ipk/
Download the ipk files to VoCore2 /tmp folder, call opkg install *.ipk to install.

note: or download from http://downloads.openwrt.org/releases/18.06.5/packages/mipsel_24kc/packages/, it should be latest version.

Then in VoCore2 directly call python3 to run it.

VoCore2: develop SPI driver 5

In order to start further hack on MT7628 spi driver, must make the test process clear first.

I am using spidev_test.c in linux kernel for the test.
To compile it,
1. enable spidev in make menuconfig -> Kernel Modules -> SPI Support -> kmod-spi-dev
2. enable spidev_test in make menuconfig -> Utilities -> spidev_test

For firmware part, need to prepare DTS.
add this to openwrt/target/linux/ramips/dts/VOCORE2.dts:&spi0

        spidev@1 {
                #address-cells = <1>;
                #size-cells = <1>;
                compatible = "rohm,dh2228fv";
                reg = <1>;
                spi-max-frequency = <100000000>;
        };

modify one line to enable spi0 cs1 in openwrt/target/linux/ramips/dts/mt7628an.dtsi
note: this should be optional, without it still work for me, because the cs1 register is default set to cs1 already.

-pinctrl-0 = <&spi_pins>;
+pinctrl-0 = <&spi_pins>, <&spi_cs1_pins>;

And we can use this way to add more SPI device by set some GPIO as CS pin. Later I will write a patch for it.

compatible = “rohm,dh2228fv” this line is necessary, without it, kernel will complain…but actually we do not care which type of device is used.
spi-max-frequency = <100000000> this line means max spi we can set upto 100MHz, I do not think its SPI can reach 100MHz. And from my test, 66MHz should be its max speed. Anyway, without DMA, even 10MHz it can not reach.

spi-mt7621.c this spi driver full duplex mode do not allow buffer size more than 16byte, we use half duplex to avoid issue when test, remove it.

static int mt7621_spi_transfer_one_message(struct spi_master *master,
                                           struct spi_message *m)
{
        struct spi_device *spi = m->spi;
/*
#ifdef CONFIG_SOC_MT7620
      int cs = spi->chip_select;

      if (cs)
              return mt7621_spi_transfer_full_duplex(master, m);
#endif
*/
        return mt7621_spi_transfer_half_duplex(master, m);
}

OK, now we can make the firmware and start to test the origin spi driver.

call “spidev_test -D /dev/spidev0.1 -p 12345678901234567890”, works normal.

VoCore2: Compile on new MacOS SDK issue

Every time when macos update to new version, always broken something, I guess that is an important reason it has very few virus.

When I compile openwrt 18.06.5 in macos, I get new problems.

1. GCC compiler version must greater than 4.8

I have no idea about this issue…it works before, I do not remember I change anything.

Solution:
brew install gcc@9
ln -s /usr/local/bin/gcc-9 /usr/local/bin/gcc
ln -s /usr/local/bin/g++-9 /usr/local/bin/g++
add /usr/local/bin to $PATH(in ~/.profile), set it at higher level than /usr/bin to cover macos default gcc path.

2. variably modified ‘bytes’ at file scope

I think this is because xcode update change the header file…
in standard C language, array size must be const, a fixed number.

This is not allowed(as I remember this way is allowed in C++?):
const int kAuthorizationExternalFormLength = 32;
int array[kAuthorizationExternalFormLength];

But this is OK:
#define kAuthorizationExternalFormLength 32
int array[kAuthorizationExternalFormLength];

Solution:

sudo vi /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/System/Library/Frameworks/Security.framework/Headers/Authorization.h

directly change const to #define. Ugly but works 🙂

3. Emm, after a while, cmake can not compile…
Solution:
rm /usr/local/bin/gcc /usr/local/bin/g++
ln -s /usr/bin/gcc /usr/local/bin/gcc
ln -s /usr/bin/g++ /usr/local/bin/g++

change it back, then works…maybe I should directly patch openwrt Makefile. :’)

Finally I find a better solution
Once 1 passed, we can change it back to gcc 4.2.1 which is macos clang, then everything works normal. so weird.

VoCore2: 3D module

I make a simple 3D module of VoCore2, hopefully this can help more or less. 🙂

Link: http://vonger.cn/misc/vocore2/vocore2.3d.stp.zip

Preview:

VoCore2: WDS (Mesh Network)

Once I want to use AdHoc as mesh network base…but mt7628 driver do not support it.

Now I just find WDS in the menu…it should be a better way to do mesh, I will study into this, must be a lot of fun 🙂
VoCore2 has so many hidden features, from 2014, it is almost five years, I still can not totally master it.

VoCore2: kermit upload tool

I wrote a simple tool to update vocore2 firmware or uboot through serial port, now upload to github.
This tool might still have bugs…use carefully, I only tested it with VoCore2 uboot. 🙂

Usage is very simple:

1. use usb2ttl connect to your vocore2 uart2(TXD2/RXD2)
2. reboot vocore2 (or power up it), it will show a list of uboot.
3. press ‘0’, call uboot upgrade firmware.
4. once VoCore2 uboot console shows “## Ready for binary (kermit) download to 0x80100000 at 115200 bps…”, close console. then use this tool, call “nkermit [your port] [file]”
The port is the TTY port, for example, in windows, it is COM1, COM2, COM4 etc…in macos it is /dev/tty.xxxxxxxxx. File is the file you want to upload, normally VoCore2 upgrade firmware file is named by date, like 20191127.bin.

github link: https://github.com/vonger/nkermit

VoCore2: Firmware Upgrade to 20191127

New firmware is ready 🙂

In new firmware, the first release of screen driver is embedded, also fix many bugs.
This will be last version for openwrt 18.06.4, next version we will move to openwrt 18.06.5

Download at http://vonger.cn/misc/vocore2/20191127.bin

VoCore2: develop SPI driver 4

Thanks for Leo, I find this new patch https://github.com/openwrt/openwrt/pull/1954.
This patch increases a lot of SPI speed. I have a quick check, looks like it speeds up because of morebuf mode.

...

	/*
	 * Select SPI device 7, enable "more buffer mode" and disable
	 * full-duplex (only half-duplex really works on this chip
	 * reliably)
	 */
	master = mt7621_spi_read(rs, MT7621_SPI_MASTER);
	master |= MASTER_RS_SLAVE_SEL | MASTER_MORE_BUFMODE;
	master &= ~MASTER_FULL_DUPLEX;
	mt7621_spi_write(rs, MT7621_SPI_MASTER, master);

...

static void mt7621_spi_read_half_duplex(struct mt7621_spi *rs,
					int rx_len, u8 *buf)
...
		mt7621_spi_write(rs, MT7621_SPI_MOREBUF, val);

That is nice. A good example about morebuf mode, this should be an important mode for dma. This code saves me a lot time, now I can directly try interrupt and dma.

Currently DMA source address can be fixed and max burst size is 16DWs, in morebuf + half duplex mode we use 8DWs. So DMA should work no problem. We will see later 🙂

VoCore2: boost boot speed

30 seconds to start wifi, it is a long time for some situation.
Why does it take so long time to boost. Let’s check!

Now, prepare a firmware, better compile from source code, so we can easily cut off kernel of Linux.

I am using 20190914.bin firmware.

First try, remove all boot up module from system.

1. mv /etc/init.d /etc/init.d.bak
2. mv /etc/modules.d /etc/modules.d.bak
3. mkdir /etc/init.d
4. mkdir /etc/modules.d

Now reboot, you will get this log, looks like it is able to startup around 9 seconds.


Starting kernel ...

[    0.000000] Linux version 4.14.131 (vonger@Vongers-MacBook-Pro-2.local) (gcc version 7.3.0 (OpenWrt GCC 7.3.0 r7808-ef686b7292)) #0 Thu Jun 27 12:18:52 2019
[    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 MT7628AN ver:1 eco:2
[    0.000000] bootconsole [early0] enabled
[    0.000000] CPU0 revision is: 00019655 (MIPS 24KEc)
[    0.000000] MIPS: machine is VoCore2
[    0.000000] Determined physical RAM map:
[    0.000000]  memory: 08000000 @ 00000000 (usable)
[    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] random: get_random_bytes called from start_kernel+0x90/0x478 with crng_init=0
[    0.000000] Built 1 zonelists, mobility grouping on.  Total pages: 32512
[    0.000000] Kernel command line: console=ttyS2,115200 console=tty0 fbcon=rotate:3 rootfstype=squashfs,jffs2
[    0.000000] PID hash table entries: 512 (order: -1, 2048 bytes)
[    0.000000] Dentry cache hash table entries: 16384 (order: 4, 65536 bytes)
[    0.000000] Inode-cache hash table entries: 8192 (order: 3, 32768 bytes)
[    0.000000] Writing ErrCtl register=00016cbe
[    0.000000] Readback ErrCtl register=00016cbe
[    0.000000] Memory: 125136K/131072K available (3295K kernel code, 176K rwdata, 816K rodata, 184K init, 210K bss, 5936K 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] intc: using register map from devicetree
[    0.000000] CPU Clock: 580MHz
[    0.000000] timer_probe: no matching timers found
[    0.000000] clocksource: MIPS: mask: 0xffffffff max_cycles: 0xffffffff, max_idle_ns: 6590553264 ns
[    0.000011] sched_clock: 32 bits at 290MHz, resolution 3ns, wraps every 7405115902ns
[    0.008031] Console: colour dummy device 80x25
[    0.012460] console [tty0] enabled
[    0.015887] bootconsole [early0] disabled
[    0.000000] Linux version 4.14.131 (vonger@Vongers-MacBook-Pro-2.local) (gcc version 7.3.0 (OpenWrt GCC 7.3.0 r7808-ef686b7292)) #0 Thu Jun 27 12:18:52 2019
[    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 MT7628AN ver:1 eco:2
[    0.000000] bootconsole [early0] enabled
[    0.000000] CPU0 revision is: 00019655 (MIPS 24KEc)
[    0.000000] MIPS: machine is VoCore2
[    0.000000] Determined physical RAM map:
[    0.000000]  memory: 08000000 @ 00000000 (usable)
[    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] random: get_random_bytes called from start_kernel+0x90/0x478 with crng_init=0
[    0.000000] Built 1 zonelists, mobility grouping on.  Total pages: 32512
[    0.000000] Kernel command line: console=ttyS2,115200 console=tty0 fbcon=rotate:3 rootfstype=squashfs,jffs2
[    0.000000] PID hash table entries: 512 (order: -1, 2048 bytes)
[    0.000000] Dentry cache hash table entries: 16384 (order: 4, 65536 bytes)
[    0.000000] Inode-cache hash table entries: 8192 (order: 3, 32768 bytes)
[    0.000000] Writing ErrCtl register=00016cbe
[    0.000000] Readback ErrCtl register=00016cbe
[    0.000000] Memory: 125136K/131072K available (3295K kernel code, 176K rwdata, 816K rodata, 184K init, 210K bss, 5936K 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] intc: using register map from devicetree
[    0.000000] CPU Clock: 580MHz
[    0.000000] timer_probe: no matching timers found
[    0.000000] clocksource: MIPS: mask: 0xffffffff max_cycles: 0xffffffff, max_idle_ns: 6590553264 ns
[    0.000011] sched_clock: 32 bits at 290MHz, resolution 3ns, wraps every 7405115902ns
[    0.008031] Console: colour dummy device 80x25
[    0.012460] console [tty0] enabled
[    0.015887] bootconsole [early0] disabled
[    0.019985] Calibrating delay loop... 385.84 BogoMIPS (lpj=1929216)
[    0.079986] pid_max: default: 32768 minimum: 301
[    0.080256] Mount-cache hash table entries: 1024 (order: 0, 4096 bytes)
[    0.080289] Mountpoint-cache hash table entries: 1024 (order: 0, 4096 bytes)
[    0.086071] clocksource: jiffies: mask: 0xffffffff max_cycles: 0xffffffff, max_idle_ns: 19112604462750000 ns
[    0.086134] futex hash table entries: 256 (order: -1, 3072 bytes)
[    0.086275] pinctrl core: initialized pinctrl subsystem
[    0.086858] NET: Registered protocol family 16
[    0.117626] mt7621_gpio 10000600.gpio: registering 32 gpios
[    0.117933] mt7621_gpio 10000600.gpio: registering 32 gpios
[    0.118181] mt7621_gpio 10000600.gpio: registering 32 gpios
[    0.122205] clocksource: Switched to clocksource MIPS
[    0.129577] NET: Registered protocol family 2
[    0.130562] TCP established hash table entries: 1024 (order: 0, 4096 bytes)
[    0.130628] TCP bind hash table entries: 1024 (order: 0, 4096 bytes)
[    0.130676] TCP: Hash tables configured (established 1024 bind 1024)
[    0.130874] UDP hash table entries: 256 (order: 0, 4096 bytes)
[    0.130931] UDP-Lite hash table entries: 256 (order: 0, 4096 bytes)
[    0.131236] NET: Registered protocol family 1
[    0.147182] Crashlog allocated RAM at address 0x3f00000
[    0.148548] workingset: timestamp_bits=30 max_order=15 bucket_order=0
[    0.154546] squashfs: version 4.0 (2009/01/31) Phillip Lougher
[    0.154646] jffs2: version 2.2 (NAND) (SUMMARY) (LZMA) (RTIME) (CMODE_PRIORITY) (c) 2001-2006 Red Hat, Inc.
[    0.165214] io scheduler noop registered
[    0.165319] io scheduler deadline registered (default)
[    0.166334] Serial: 8250/16550 driver, 3 ports, IRQ sharing disabled
[    0.167733] 10000c00.uartlite: ttyS0 at MMIO 0x10000c00 (irq = 28, base_baud = 2500000) is a 16550A
[    0.168556] 10000d00.uart1: ttyS1 at MMIO 0x10000d00 (irq = 29, base_baud = 2500000) is a 16550A
[    0.169347] 10000e00.uart2: ttyS2 at MMIO 0x10000e00 (irq = 30, base_baud = 2500000) is a 16550A
[    0.575929] console [ttyS2] enabled
[    0.580140] cacheinfo: Failed to find cpu0 device node
[    0.585466] cacheinfo: Unable to detect cache hierarchy for CPU 0
[    0.592524] spi-mt7621 10000b00.spi: sys_freq: 193333333
[    0.602293] m25p80 spi0.0: gd25q128 (16384 Kbytes)
[    0.607306] 4 fixed-partitions partitions found on MTD device spi0.0
[    0.613836] Creating 4 MTD partitions on "spi0.0":
[    0.618760] 0x000000000000-0x000000030000 : "u-boot"
[    0.624825] 0x000000030000-0x000000040000 : "u-boot-env"
[    0.631139] 0x000000040000-0x000000050000 : "factory"
[    0.637312] 0x000000050000-0x000001000000 : "firmware"
[    0.714902] 2 uimage-fw partitions found on MTD device firmware
[    0.721015] 0x000000050000-0x0000001b241c : "kernel"
[    0.727045] 0x0000001b241c-0x000001000000 : "rootfs"
[    0.733053] mtd: device 5 (rootfs) set to be root filesystem
[    0.740445] 1 squashfs-split partitions found on MTD device rootfs
[    0.746881] 0x000000380000-0x000001000000 : "rootfs_data"
[    0.754141] libphy: Fixed MDIO Bus: probed
[    0.768547] rt3050-esw 10110000.esw: link changed 0x00
[    0.777025] mtk_soc_eth 10100000.ethernet eth0: mediatek frame engine at 0xb0100000, irq 5
[    0.786704] NET: Registered protocol family 17
[    0.791363] 8021q: 802.1Q VLAN Support v1.8
[    0.807897] VFS: Mounted root (squashfs filesystem) readonly on device 31:5.
[    0.816223] Freeing unused kernel memory: 184K
[    0.820806] This architecture does not have kernel memory protection.
[    2.100970] init: Console is alive
[    2.104845] init: - watchdog -
[    2.362212] random: fast init done
[    2.883744] kmodloader: loading kernel modules from /etc/modules-boot.d/*
[    2.965047] kmodloader: done loading kernel modules from /etc/modules-boot.d/*
[    2.974500] init: - preinit -
[    4.114342] rt3050-esw 10110000.esw: link changed 0x00
[    7.649323] jffs2: notice: (412) jffs2_build_xattr_subsystem: complete building xattr subsystem, 10 of xdatum (2 unchecked, 7 orphan) and 78 of xref (4 dead, 43 orphan) found.
[    7.667350] mount_root: switching to jffs2 overlay
[    7.692257] overlayfs: upper fs does not support tmpfile.
[    7.705332] urandom-seed: Seed file not found (/etc/urandom.seed)
[    7.909840] procd: - early -
[    7.913758] procd: - watchdog -
[    8.630091] procd: - watchdog -
[    8.633709] procd: - ubus -
[    8.867640] random: ubusd: uninitialized urandom read (4 bytes read)
[    9.024867] random: ubusd: uninitialized urandom read (4 bytes read)
[    9.031955] random: ubusd: uninitialized urandom read (4 bytes read)
[    9.039617] procd: - init -
Please press Enter to activate this console.

9s is still too long, because we did not load wifi driver yet, wifi driver is pretty big and slow…

From begin to 0.82s, everything seems fast and pretty, but after that, at 2.1s, init runs, suddenly, it becomes very slow, we can find an obviously time span at 2.1s, 4.1s and 7.6s.

Emm, why?

I have some guesses:

1. it is because SPI load something from flash and SPI is slow(busy wait, no dma, check my blog about SPI). Once the file system like jffs2 is doing some dirty job, it will slow down the boot.
2. some unknown drivers load by init takes too much time, slow down the boot speed.

As I know, even the driver as big as mt7628.ko(wifi driver), won’t take more than two seconds to load, so it must be something nasty at its boot time.

OpenWrt drivers mostly are port from ralink SDK, they just work but not optimize to the best(maybe ralink is too poor to hire engineer work on this…), so I should have some space to optimize the code. 🙂

My target is to make it boot into 5s, with wifi into 10s.
To be continue…

VoCore2: develop SPI driver 3

Now in the deep zone.

From /proc/interrupts, I know esw, gdma, sdhci etc have interrupts.

Check gdma source code, we can add similar irq code to spi.

static irqreturn_t mt7621_spi_irq(int irq, void *devid)
{
	struct mt7621_spi *rs = (struct mt7621_spi *)devid;
	printk(KERN_INFO "mt7621_spi_irq %d trigger\n", irq);
	return IRQ_HANDLED;
}

...

	irq = platform_get_irq(pdev, 0);
	if (irq < 0) { dev_err(&pdev->dev, "failed to get irq\n");
		return -EINVAL;
	}
	ret = devm_request_irq(&pdev->dev, irq, mt7621_spi_irq,
			0, dev_name(&pdev->dev), rs);
	if (ret) {
		dev_err(&pdev->dev, "failed to request irq\n");
		return ret;
	}

and in vocore2 dts(device tree, mt7628an.dtsi), we also need to add spi interrupt.

                spi0: spi@b00 {
                        compatible = "ralink,mt7621-spi";
                        reg = <0xb00 0x100>;

                        resets = <&rstctrl 18>;
                        reset-names = "spi";

                        #address-cells = <1>;
                        #size-cells = <0>;

                        pinctrl-names = "default";
                        pinctrl-0 = <&spi_pins>;

                        interrupt-parent = <&intc>;
                        interrupts = <11>;

                        status = "disabled";
                };

OK, that all, we can compile and check if this works.

After VoCore2 upgrade ready and flash init ready, we can call mem command(I write this command for easy debug, source code can be downloaded at vocore.io/v2.html) to enable spi interrupt.

mem 0x10000b28 0xe0128a84 

Then, write something through spi, like ‘touch /root/x’, this will create a new file under /root/, so OS will try to use spi write to the flash.

Ouch… I just get endless messages “mt7621_spi_irq 19 trigger” from console, after a while, the system dead.

I guess there must be something wrong in the interrupt code. As I remember, once interrupt is triggered, we must write to some register to clean the interrupt, or it will keep in trigger status, that will cause a deadloop, system will hang up too.

Checking esw(ethernet switch) source code, I find esw 0x00 register is Interrupt Status Register, once you write same thing into the register, it will clean up the interrupt.

So SPI must has something similar.

Finally I find it is 0x10000b34 register, its name is SPI Status. The final bit of it:

Once the register is read by system, the interrupt will be clear, easy 😉

Update IRQ code to the following code

static irqreturn_t mt7621_spi_irq(int irq, void *devid)
{
	struct mt7621_spi *rs = (struct mt7621_spi *)devid;
	u32 reg;

	reg = mt7621_spi_read(rs, MT7621_SPI_STATUS);
	printk(KERN_INFO "mt7621_spi_irq %d trigger, status 0x%08x\n", irq, reg);
	return IRQ_HANDLED;
}

Now once we touch new file into flash, we just get around ten lines of the kernel interrupt log, that means, it works! Check system, spi interrupt is not zero anymore.

root@OpenWrt:~# cat /proc/interrupts 
           CPU0       
  5:        895      MIPS   5  10100000.ethernet
  6:      50378      MIPS   6  ra0
  7:     266055      MIPS   7  timer
 15:          0      INTC   7  10002800.gdma
 19:        138      INTC  11  10000b00.spi
 22:      79014      INTC  14  10130000.sdhci
 25:          2      INTC  17  esw
 26:          1      INTC  18  ehci_hcd:usb1, ohci_hcd:usb2
 30:        440      INTC  22  ttyS2
ERR:          0

Next I will try to combine the interrupt into the source code, this is pretty risk, because once Linux boot up, it is using this driver read from flash.
Next next, if I have any luck go that far, maybe try GDMA with SPI, then we have some fast speed spi devices.