diff --git a/internal/app/machined/pkg/runtime/v1alpha1/board/board.go b/internal/app/machined/pkg/runtime/v1alpha1/board/board.go index a9ba5efe966..f86740777f0 100644 --- a/internal/app/machined/pkg/runtime/v1alpha1/board/board.go +++ b/internal/app/machined/pkg/runtime/v1alpha1/board/board.go @@ -17,6 +17,7 @@ import ( jetsonnano "github.com/siderolabs/talos/internal/app/machined/pkg/runtime/v1alpha1/board/jetson_nano" libretechallh3cch5 "github.com/siderolabs/talos/internal/app/machined/pkg/runtime/v1alpha1/board/libretech_all_h3_cc_h5" nanopir4s "github.com/siderolabs/talos/internal/app/machined/pkg/runtime/v1alpha1/board/nanopi_r4s" + odroidhc4 "github.com/siderolabs/talos/internal/app/machined/pkg/runtime/v1alpha1/board/odroid_hc4" "github.com/siderolabs/talos/internal/app/machined/pkg/runtime/v1alpha1/board/pine64" "github.com/siderolabs/talos/internal/app/machined/pkg/runtime/v1alpha1/board/rock64" rockpi4 "github.com/siderolabs/talos/internal/app/machined/pkg/runtime/v1alpha1/board/rockpi4" @@ -73,6 +74,8 @@ func newBoard(board string) (b runtime.Board, err error) { b = &jetsonnano.JetsonNano{} case constants.BoardNanoPiR4S: b = &nanopir4s.NanoPiR4S{} + case constants.BoardODroidHC4: + b = &odroidhc4.ODroidHC4{} default: return nil, fmt.Errorf("unsupported board: %q", board) } diff --git a/internal/app/machined/pkg/runtime/v1alpha1/board/odroid_hc4/odroid_hc4.go b/internal/app/machined/pkg/runtime/v1alpha1/board/odroid_hc4/odroid_hc4.go new file mode 100644 index 00000000000..459cc98e437 --- /dev/null +++ b/internal/app/machined/pkg/runtime/v1alpha1/board/odroid_hc4/odroid_hc4.go @@ -0,0 +1,85 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +// Package odroidhc4 provides the ODroid HC4 board implementation. +package odroidhc4 + +import ( + "log" + "os" + "path/filepath" + + "github.com/siderolabs/go-procfs/procfs" + "golang.org/x/sys/unix" + + "github.com/siderolabs/talos/internal/app/machined/pkg/runtime" + "github.com/siderolabs/talos/pkg/copy" + "github.com/siderolabs/talos/pkg/machinery/constants" +) + +var dtb = "/amlogic/meson-sm1-odroid-hc4.dtb" + +// ODroidHC4 represents the ODroid HC4. +// +// References: +// - https://wiki.odroid.com/odroid-hc4/odroid-hc4 +// - https://wiki.odroid.com/odroid-hc4/software/partition_table +// - https://github.com/u-boot/u-boot/blob/master/doc/board/amlogic/odroid-c4.rst +type ODroidHC4 struct{} + +// Name implements the runtime.Board. +func (b *ODroidHC4) Name() string { + return constants.BoardODroidHC4 +} + +// Install implements the runtime.Board. +func (b *ODroidHC4) Install(disk string) (err error) { + var f *os.File + + if f, err = os.OpenFile(disk, os.O_RDWR|unix.O_CLOEXEC, 0o666); err != nil { + return err + } + //nolint:errcheck + defer f.Close() + + // NB: In the case that the block device is a loopback device, we sync here + // to esure that the file is written before the loopback device is + // unmounted. + err = f.Sync() + if err != nil { + return err + } + + src := "/usr/install/arm64/dtb" + dtb + dst := "/boot/EFI" + dtb + + log.Printf("write %s to %s", src, dst) + + err = os.MkdirAll(filepath.Dir(dst), 0o600) + if err != nil { + return err + } + + err = copy.File(src, dst) + if err != nil { + return err + } + + log.Printf("wrote %s to %s", src, dst) + + return nil +} + +// KernelArgs implements the runtime.Board. +func (b *ODroidHC4) KernelArgs() procfs.Parameters { + return []*procfs.Parameter{ + // https://wiki.odroid.com/odroid-hc4/application_note/misc/dmesg_on_display + procfs.NewParameter("console").Append("tty1").Append("ttyAML0,115200n8"), + } +} + +// PartitionOptions implements the runtime.Board. +func (b *ODroidHC4) PartitionOptions() *runtime.PartitionOptions { + return &runtime.PartitionOptions{PartitionsOffset: 2048} +} diff --git a/internal/app/machined/pkg/runtime/v1alpha1/platform/vmware/vmware_other.go b/internal/app/machined/pkg/runtime/v1alpha1/platform/vmware/vmware_other.go index 7ccb7086c16..f3b7a8e33d3 100644 --- a/internal/app/machined/pkg/runtime/v1alpha1/platform/vmware/vmware_other.go +++ b/internal/app/machined/pkg/runtime/v1alpha1/platform/vmware/vmware_other.go @@ -4,6 +4,7 @@ //go:build !amd64 +// Package vmware provides the VMware platform implementation. package vmware import ( diff --git a/pkg/machinery/constants/constants.go b/pkg/machinery/constants/constants.go index b55c12162dd..73d0c89a79c 100644 --- a/pkg/machinery/constants/constants.go +++ b/pkg/machinery/constants/constants.go @@ -82,6 +82,9 @@ const ( // BoardNanoPiR4S is the name of the Friendlyelec Nano Pi R4S. BoardNanoPiR4S = "nanopi_r4s" + // BoardODroidHC4 is the name of the HardKernel ODroid HC4. + BoardODroidHC4 = "odroid_hc4" + // KernelParamHostname is the kernel parameter name for specifying the // hostname. KernelParamHostname = "talos.hostname" diff --git a/website/content/v1.4/talos-guides/install/single-board-computers/odroid_hc4.md b/website/content/v1.4/talos-guides/install/single-board-computers/odroid_hc4.md new file mode 100644 index 00000000000..e08f95d4ab8 --- /dev/null +++ b/website/content/v1.4/talos-guides/install/single-board-computers/odroid_hc4.md @@ -0,0 +1,94 @@ +--- +title: "ODroid HC4" +description: "Installing Talos on an ODroid HC4 SBC using raw disk image." +aliases: + - ../../../single-board-computers/odroid_hc4 +--- +## Prerequisites + +You will need: + +- `talosctl` +- A microSD card to prepare the unit with +- An additional microSD card, USB stick, or SATA drive to boot Talos from + +Download the latest `talosctl`: + +```shell +curl -Lo /usr/local/bin/talosctl https://github.com/siderolabs/talos/releases/download/v1.4.0/talosctl-$(uname -s | tr "[:upper:]" "[:lower:]")-amd64 + +chmod +x /usr/local/bin/talosctl +``` + +## Download and Write the Image + +Download the image and decompress it: + +```shell +curl -LO https://github.com/siderolabs/talos/releases/download/v1.4.0/metal-odroid_hc4-arm64.img.xz | xz -d - + +xz -d metal-odroid_hc4-arm64.img.xz +``` + +Write the image to the chosen boot media via [BalenaEtcher](https://www.balena.io/etcher) or `dd`. + +## Prepare the Unit + +### Erase factory bootloader + +- Boot device to petitboot (no USB, SDCard, etc.), the default bootloader +- In petitboot menu, select `Exit to shell` +- Run the following: + +```shell +flash_eraseall /dev/mtd0 +flash_eraseall /dev/mtd1 +flash_eraseall /dev/mtd2 +flash_eraseall /dev/mtd3 +``` + +- Power cycle the device + +### Install u-boot to SPI + +- Flash [Armbian](https://www.armbian.com/odroid-hc4/) to a micro SD card with `dd` or [BalenaEtcher](https://www.balena.io/etcher). + **A bootable USB stick or SATA drive will not work for this step** +- Insert the Armbian micro SD card into the unit and power it on. +- Once Armbian is booted, install `crane` via the following commands. + Make sure the unit is connected to the Internet: + +```shell +curl -L https://api.github.com/repos/google/go-containerregistry/releases/latest | + jq -r '.assets[] | select(.name | contains("Linux_arm64")) | .browser_download_url' | + xargs curl -sL | + tar zxvf - && \ + install crane /usr/bin +``` + +- Extract the `u-boot` image from the Talos installer: + +```shell +mkdir _out +crane --platform=linux/arm64 export ghcr.io/siderolabs/u-boot:v1.4.0 - | tar xf - --strip-components=1 -C _out odroid_hc4/u-boot.bin +``` + +- Write `u-boot.bin` to the HC4's SPI/bootloader: + +```shell +dd if=_out/u-boot.bin of=/dev/mtdblock0 conv=fsync status=progress +``` + +- Power off the unit + +## Recover Factory Bootloader + +**Note:** Only perform these steps if you want to use Hardkernel-published distributions. +Performing these actions will render the unit unable to boot Talos unless the steps in this guide are repeated. + +Taken from [the ODroid forums](https://forum.odroid.com/viewtopic.php?t=40906): + +- Download the latest `spiupdate` and `spiboot` archives from [here](http://ppa.linuxfactory.or.kr/images/petitboot/odroidhc4/). +- Flash the `spiupdate` image to a microSD card via `dd` or `dd` or [BalenaEtcher](https://www.balena.io/etcher). +- Decompress the `spiboot` archive and copy the file it contains to the flashed SD card. + Ensure the file is named `spiboot.img`. +- Insert the microSD card into the unit and power it on