Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add ODroid HC4 support #6806

Draft
wants to merge 4 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions internal/app/machined/pkg/runtime/v1alpha1/board/board.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -70,6 +71,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)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -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}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

//go:build !amd64

// Package vmware provides the VMware platform implementation.
package vmware

import (
Expand Down
14 changes: 14 additions & 0 deletions pkg/imager/profile/default.go
Original file line number Diff line number Diff line change
Expand Up @@ -367,4 +367,18 @@ var Default = map[string]Profile{
},
},
},
constants.BoardODroidHC4: {
Arch: "arm64",
Platform: constants.PlatformMetal,
Board: constants.BoardODroidHC4,
SecureBoot: pointer.To(false),
Output: Output{
Kind: OutKindImage,
OutFormat: OutFormatXZ,
ImageOptions: &ImageOptions{
DiskSize: MinRAWDiskSize,
DiskFormat: DiskFormatRaw,
},
},
},
}
3 changes: 3 additions & 0 deletions pkg/machinery/constants/constants.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,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"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
---
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
- A USB keyboard or a UART module to use the serial console

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 off the unit

### 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
- Insert the media that was previously flashed with Talos

After these steps, Talos will boot and enter maintenance mode.
Proceed to [bootstrapping the node](#bootstrapping-the-node).

## Bootstrapping the Node

Wait for the console to show you the instructions for bootstrapping the node.
Following the instructions in the console output to connect to the interactive installer:

```bash
talosctl apply-config --insecure --mode=interactive --nodes <node IP or DNS name>
```

## 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