MNT Reform

From Gentoo Wiki
Jump to:navigation Jump to:search
Resources

MNT Reform is an ARM Cortex-A53 powered open hardware laptop.

Hardware

root #lspci
0000:00:00.0 PCI bridge: Synopsys, Inc. DWC_usb3 / PCIe bridge (rev 01)
0000:01:00.0 Network controller: Qualcomm Atheros AR928X Wireless Network Adapter (PCI-Express) (rev 01)
0001:00:00.0 PCI bridge: Synopsys, Inc. DWC_usb3 / PCIe bridge (rev 01)
0001:01:00.0 Non-Volatile memory controller: Silicon Motion, Inc. Device 2263 (rev 03)
root #lsusb
Bus 001 Device 006: ID 03eb:2042 Atmel Corp. LUFA Keyboard Demo Application
Bus 004 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub
Bus 001 Device 005: ID 03eb:2041 Atmel Corp. LUFA Mouse Demo Application
Bus 001 Device 002: ID 0451:8142 Texas Instruments, Inc. TUSB8041 4-Port Hub
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
Bus 002 Device 002: ID 0451:8140 Texas Instruments, Inc. TUSB8041 4-Port Hub
Bus 002 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub
Bus 003 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
root #cat /proc/cpuinfo
processor	: 0
BogoMIPS	: 16.66
Features	: fp asimd evtstrm aes pmull sha1 sha2 crc32 cpuid
CPU implementer	: 0x41
CPU architecture: 8
CPU variant	: 0x0
CPU part	: 0xd03
CPU revision	: 4

processor	: 1
BogoMIPS	: 16.66
Features	: fp asimd evtstrm aes pmull sha1 sha2 crc32 cpuid
CPU implementer	: 0x41
CPU architecture: 8
CPU variant	: 0x0
CPU part	: 0xd03
CPU revision	: 4

processor	: 2
BogoMIPS	: 16.66
Features	: fp asimd evtstrm aes pmull sha1 sha2 crc32 cpuid
CPU implementer	: 0x41
CPU architecture: 8
CPU variant	: 0x0
CPU part	: 0xd03
CPU revision	: 4

processor	: 3
BogoMIPS	: 16.66
Features	: fp asimd evtstrm aes pmull sha1 sha2 crc32 cpuid
CPU implementer	: 0x41
CPU architecture: 8
CPU variant	: 0x0
CPU part	: 0xd03
CPU revision	: 4

Installation

Installing Gentoo on the MNT Reform is very similar to how one installs Gentoo on just about any desktop / laptop system. The only parts that need special attention are the bootloader and the kernel.

u-boot

The MNT Reform boots using the u-boot bootloader. There is a patched version available in a separate repository. This bootloader can be used on either an SD-card or on the internal storage, or on both of them.

Unmodified, the bootloader will first attempt to find an OS on the SD card when one is present. For that purpose, it will search the SD-cards first partition for a file /boot.scr and if it can't find that file, for /boot/boot.scr with boot.scr being a u-boot script. If no SD-card is present or none of the above files can be found on the SD-card, the bootloader will then proceed to search for the same files on the first partition of the internal storage.

The exact behavior can be studied and / or modified in the file board/boundary/nitrogen8m_som/nitrogen8m_som.c of the above-mentioned repository.

To build the bootloader, run these commands:

root # cd /usr/src
root # cd u-boot
root # cp mntreform-config .config
root # make flash.bin

To install the bootloader to a device, run this command:

root #dd if=./flash.bin of=/dev/mmcblk1 conv=notrunc bs=1k seek=33

With /dev/mmcblk1 being the SD-card to install it to.

boot script

The bootloader, as prepared above, will load a boot script. This boot script contains the further details on how to load the kernel, device tree, initrd and pass the kernel command line parameters.

The official images for the MNT Reform use a Debian tool called flash-kernel to generate the boot script. But it can pretty easily be done by hand.

First, install the u-boot utilities:

root #emerge --ask dev-embedded/u-boot-tools

Now, a boot script is needed in human-readable text form. Start out with the same template as used by Debian's flash-kernel. The file is located at: https://salsa.debian.org/installer-team/flash-kernel/-/blob/master/bootscript/arm64/bootscr.uboot-generic

Place that in a file boot.txt, then edit it. Primarily, replace the @@LINUX_KERNEL_CMDLINE_DEFAULTS@@ and @@LINUX_KERNEL_CMDLINE@@ values. The values used in the official Image (as of v3) are ro no_console_suspend cma=512M pci=nomsi and console=ttymxc1,115200 console=tty1 respectively.

Replace @@KERNEL_VERSION@@ with the kernel version information and remove the @@UBOOT_ENV_EXTRA@@ part.

Once satisfied, compile it by running:

root #mkimage -A arm -O linux -T script -C none -a 0x0 -e 0x0 -n "boot script" -d boot.txt boot.scr

The while compiling, the file's header information will be printed. To show that information later, run:

root #dumpimage -l boot.scr

The output is supposed to look a bit like this:

Image Name:   boot script
Created:      Mon Mar 14 15:31:46 2022
Image Type:   ARM Linux Script (uncompressed)
Data Size:    2441 Bytes = 2.38 KiB = 0.00 MiB
Load Address: 00000000
Entry Point:  00000000
Contents:
   Image 0: 2433 Bytes = 2.38 KiB = 0.00 MiB

Here is the complete boot script used when creating this tutorial:

root #cat boot.txt
# sh-kernel: bootscr.uboot-generic
#

# Bootscript using the new unified bootcmd handling
#
# Expects to be called with the following environment variables set:
#
#  devtype              e.g. mmc/scsi etc
#  devnum               The device number of the given type
#  bootpart             The partition containing the boot files
#  distro_bootpart      The partition containing the boot files
#                       (introduced in u-boot mainline 2016.01)
#  prefix               Prefix within the boot partiion to the boot files
#  kernel_addr_r        Address to load the kernel to
#  fdt_addr_r           Address to load the FDT to
#  ramdisk_addr_r       Address to load the initrd to.
#
# The uboot must support the booti and generic filesystem load commands.

if test -n "${console}"; then
  setenv bootargs "${bootargs} console=${console}"
fi

setenv bootargs ro no_console_suspend cma=512M pci=nomsi ${bootargs} console=ttymxc1,115200 console=tty1 root=UUID=8709fad5-63c9-48db-83f3-5bf64ac2873b rd.luks.uuid=03741e41-0882-4327-8805-bb4c5b3be2da rd.luks.allow-discards root_trim=yes

# setenv bootpart "1"
# setenv prefix "/"
# setenv kernel_addr_r "0x40480000"
# setenv fdt_addr_r "0x50000000"
# setenv ramdisk_addr_r "0x51000000"

if test -z "${fk_kvers}"; then
   setenv fk_kvers '6.1.8-mnt-reform2'
fi

# These two blocks should be the same apart from the use of
# ${fk_kvers} in the first, the syntax supported by u-boot does not
# lend itself to removing this duplication.

setenv fdtpath dtb-${fk_kvers}

if test -z "${distro_bootpart}"; then
  setenv partition ${bootpart}
else
  setenv partition ${distro_bootpart}
fi


# place here any u-boot commands to be executed before boot

load ${devtype} ${devnum}:${partition} ${kernel_addr_r} ${prefix}vmlinuz-${fk_kvers} \
&& load ${devtype} ${devnum}:${partition} ${fdt_addr_r} ${prefix}${fdtpath} \
&& load ${devtype} ${devnum}:${partition} ${ramdisk_addr_r} ${prefix}initramfs-${fk_kvers}.img \
&& echo "Booting Debian ${fk_kvers} from ${devtype} ${devnum}:${partition}..." \
&& booti ${kernel_addr_r} ${ramdisk_addr_r}:${filesize} ${fdt_addr_r}

load ${devtype} ${devnum}:${partition} ${kernel_addr_r} ${prefix}vmlinuz \
&& load ${devtype} ${devnum}:${partition} ${fdt_addr_r} ${prefix}dtb \
&& load ${devtype} ${devnum}:${partition} ${ramdisk_addr_r} ${prefix}initrd.img \
&& echo "Booting Debian from ${devtype} ${devnum}:${partition}..." \
&& booti ${kernel_addr_r} ${ramdisk_addr_r}:${filesize} ${fdt_addr_r}

Install to SD-card

Having u-boot and the boot script, install them to an SD-card. Since the SD-card will only hold the kernel and initrd, it can be relatively small.

First, prepare the partition table:

root # parted --script /dev/mmcblk1 "mklabel msdos"
root # parted --script /dev/mmcblk1 "mkpart primary ext4 4MiB -1"
root # mkfs.ext4 /dev/mmcblk1p1

Next, write the bootloader to the exact location it needs to be at:

root #dd if=./flash.bin of=/dev/mmcblk1 conv=notrunc bs=1k seek=33

Now, mount the SD-card's first partition, and place the files in a structure like so (using kernel version 5.12.0 in the below example):

├── boot.scr             # The boot script
├── dtb-5.12.0           # The device tree
├── initrd.img-5.12.0    # The initramfs
└── vmlinuz-5.12.0       # The kernel

Install to internal storage

To boot from the internal storage instead of the SD-card, first partition the storage at mmcblk0:

root # parted --script /dev/mmcblk0 "mklabel msdos"
root # parted --script /dev/mmcblk0 "mkpart primary ext4 4MiB -1"
root # mkfs.ext4 /dev/mmcblk0p1

Now, before we can write the bootloader to the internal storage, we have to make it writeable:

root # echo 0 > /sys/class/block/mmcblk0boot0/force_ro

Now, we can write the bootloader:

root #dd if=./flash.bin of=/dev/mmcblk0boot0 conv=notrunc bs=1k seek=33

Now, mount the partition created above and place the files in a structure like so (using kernel version 5.12.0 in the below example):

├── boot.scr             # The boot script
├── dtb-5.12.0           # The device tree
├── initrd.img-5.12.0    # The initramfs
└── vmlinuz-5.12.0       # The kernel

Depending on when you received your MNT Reform, you might have to toggle the DIP switch on the SOM to enable booting from the internal storage.

initrd

When generating an initrd make sure the following kernel modules are included and loaded early, to ensure the display output is working:

  • reset_imx7
  • mux_mmio
  • fixed
  • i2c-imx
  • fan53555
  • i2c_mux_pca954x
  • pwm_imx27
  • pwm_bl
  • panel_edp
  • ti_sn65dsi86
  • imx-dcss
  • phy-fsl-imx8-mipi-dphy
  • nwl-dsi
  • mxsfb
  • usbhid
  • imx8mq-interconnect
  • nvme

The above list is based off this script from the reference image. Depending on which tool you use to generate the initrd, all or some of those might be included automatically.

When using dracut to build the initrd, add a configuration file that looks like this:

FILE /etc/dracut.conf.d/20_mnt-reform-2.conf
force_drivers+=" reset_imx7 mux_mmio fixed i2c-imx fan53555 i2c_mux_pca954x pwm_imx27 pwm_bl panel_edp ti_sn65dsi86 imx-dcss phy-fsl-imx8-mipi-dphy nwl-dsi mxsfb usbhid imx8mq-interconnect nvme "

Kernel

I have created an ebuild for a patched kernel.

This ebuild is based on the sys-kernel/gentoo-kernel and thus includes the usual Gentoo-specific kernel patches and is based on the same configuration as the Gentoo kernel. Additionally, it also incorporates the patches and configuration used in building the reference kernel.

Note that the author of this ebuild is not associated with MNT and this kernel is not officially supported by MNT.

First, add the necessary repository:

root #emerge --ask --verbose app-eselect/eselect-repository
root #eselect repository add mnt-reform2 git https://git.chaostreffbern.ch/vimja/mnt-reform2-overlay.git
root #emerge --sync mnt-reform2

Optionally updated eix:

root #eix-update --repo-name mnt-reform2

Now, install the kernel. Note that this will take about 8 hours on the MNT Reform itself:

root #emerge --ask sys-kernel/mnt-reform2-kernel

By default, this will also trigger initramfs generation through dracut. Make sure to end up with a working initramfs as in the the previous chapter.

As of now, the resulting image is gzip compressed, but u-boot expects an uncompressed kernel image. Manually unpack the image and place it in the correct location for the system to successfully boot:

root #mv /boot/vmlinuz-${kernel_version}-mnt-reform2{,.gz}
root #gunzip /boot/vmlinuz-${kernel_version}-mnt-reform2.gz

Check the format of the resulting file:

root #file /boot/vmlinuz-${kernel_version}-mnt-reform2
/boot/vmlinuz-6.1.8-mnt-reform2: Linux kernel ARM64 boot executable Image, little-endian, 4K pages

Before rebooting the system, please make sure all files are named correctly. In particular, the u-boot boot script expects the kernel to be named vmlinuz-<VERSION> whereas the file installed by this ebuild is called vmlinuz-<VERSION>-mnt-reform2.

The same goes for the initrd which is expected by the boot script to be named initrd.img-<VERSION> whereas the file generated by dracut will be called initramfs-<VERSION>-mnt-reform2.img.

So either rename the files or modify the boot script to make this work.

f0 respawning

With a default arm64 system, error messages like this will appear both on the default TTY in the system log:

Id "f0" respawning too fast: disabled for 5 minutes

To get rid of those, edit the inittab at /etc/inittab and remove or comment out the last line, that looks something like this:

FILE /etc/inittab
# Architecture specific features
f0:12345:respawn:/sbin/agetty 9600 ttyAMA0 vt100

Then, restart the system.

Clock loses time on reboot

The Reform has two Real-time clocks installed in the system - a battery backed up PCF8523 and an on-CPU SNVS. The SNVS clock is powered by the same rail as the i.MX8M CPU and will reset together with the system.

By default, the hwclock is using /dev/rtc0, which might be the wrong clock.

To fix this issue, either remove the rtc-snvs kernel driver, or edit the following line in the /etc/conf.d/hwclock file:

FILE /etc/conf.d/hwclock
clock_args="--rtc /dev/rtc1"

Check which RTC has been assigned to which device by looking at the kernel ring buffer:

user $ dmesg | grep --ignore-case rtc
[    3.556883] rtc-pcf8523 2-0068: registered as rtc0
[    3.563641] rtc-pcf8523 2-0068: setting system clock to 2020-07-13T17:27:26 UTC (1594661246)

In the above example, the PCF8523 is the only RTC and it is assigned to /dev/rtc0.

Build the out-off-tree LPC kernel module

An out of tree kernel module exists that allows the OS to interact with the LPC System controller. Foremost, it makes battery / charge information available in Linux.

The GCC used to compile the module must be the exact same that was used to build the kernel, otherwise, the build will abort with an error.

root # cd /usr/src/
root # cd reform-tools/lpc/

Once compiled, you can now load the module like so:

root # insmod /usr/src/reform-tools/lpc/reform2_lpc.ko

Details about the laptop's power supply is now available through /sys/class/power_supply/8xlifepo4/.

To install the module into a path where it can be handled more easily, run these commands:

root # mkdir --parents /lib/modules/$(uname --kernel-release)/kernel/drivers/other/reform2_lpc
root # cp /usr/src/reform-tools/lpc/reform2_lpc.ko /lib/modules/$(uname --kernel-release)/kernel/drivers/other/reform2_lpc/
root # depmod

You should now be able to load the module lik so:

root # modprobe reform2_lpc