-
Notifications
You must be signed in to change notification settings - Fork 3
Open
Description
I'd like to use Docker on the A1 and my best chance of that seems to be using an updated 6.xx mainline kernel.
I'm running headless, so I don't care about GUI stuff.
Things I need to work;
- Cameras
- Wifi
STATUS: builds a 6.xx kernel but the kernel fails to boot.
On the Avaota itself I booted armbian 5.xxx kernel and did:
apt install -y git build-essential ccache wget curl u-boot-tools \
libncurses5-dev libncursesw5-dev bc device-tree-compiler gcc-aarch64-linux-gnu
Create a working directory:
mkdir ~/armbian_build && cd ~/armbian_build
git clone --depth 1 https://github.com/armbian/build.git
cd build
If you have ~20Gb of hard drive space and some time to kill, Save this as fixed.py and run it with python3 fixed.py
#!/usr/bin/env python3
"""
Avaota A1 Armbian Kernel Setup v5.0
Date: 2026-02-27
Strategy:
- DO NOT run this script as root. It will warn and exit if you do.
- Clones Armbian build framework if not present.
- Patches the family/board config files in-place.
- Fetches the chainsx linux-t527 repo for the defconfig + DTS files.
- Applies DTS and defconfig patches into Armbian's userpatches mechanism
so they survive re-runs without corrupting Armbian's source management.
- Armbian's compile.sh then handles all kernel source fetching itself.
"""
import os
import sys
import shutil
import subprocess
import urllib.request
from pathlib import Path
# ---------------------------------------------------------------------------
# Configuration
# ---------------------------------------------------------------------------
VERSION = "5.0"
# Use a known-good stable kernel. 6.12.x is the latest stable LTS as of early 2026.
# Armbian uses its own branch naming; "current" maps to their maintained stable.
# We override to a specific tag via userpatches if needed.
KERNEL_TAG = "v6.12.21" # adjust to latest stable as needed
KERNEL_MAJOR_MINOR = "6.12"
BOARD = "avaota-a1"
BOARDFAMILY = "sun55iw3" # Armbian's family name for the T527/A523 SoC
ARMBIAN_DIR = Path.home() / "armbian"
ARMBIAN_REPO = "https://github.com/armbian/build.git"
CHAIN_DIR = Path.home() / "chainsx-linux-t527"
CHAIN_REPO = "https://github.com/chainsx/linux-t527.git"
CHAIN_COMMIT = "63530030005ef533e470f7a14096bfd363f795af"
# Userpatches dirs — Armbian picks these up automatically
USERPATCHES_DIR = ARMBIAN_DIR / "userpatches"
USERPATCHES_KERNEL_DIR = USERPATCHES_DIR / f"linux-{BOARDFAMILY}-current"
USERPATCHES_CONFIG_DIR = USERPATCHES_DIR / "kernel" / f"linux-{BOARDFAMILY}-current"
# DTS target inside a patch (applied by Armbian during kernel prep)
# We put DTS files into the userpatches overlay so Armbian copies them in.
DTS_OVERLAY_DIR = USERPATCHES_KERNEL_DIR / "arch/arm64/boot/dts/allwinner"
DTS_SOURCES = {
"sun55i-a523.dtsi":
"https://raw.githubusercontent.com/torvalds/linux/master/arch/arm64/boot/dts/allwinner/sun55i-a523.dtsi",
"sun55i-t527-avaota-a1.dts":
"https://raw.githubusercontent.com/torvalds/linux/master/arch/arm64/boot/dts/allwinner/sun55i-t527-avaota-a1.dts",
}
# sun55i-t527.dtsi has no upstream URL yet; we'll copy from chainsx repo
# ---------------------------------------------------------------------------
# Helpers
# ---------------------------------------------------------------------------
def banner(msg):
print(f"\n{'='*60}")
print(f" {msg}")
print('='*60)
def run(cmd, cwd=None, env=None):
print(f" $ {' '.join(str(c) for c in cmd)}")
subprocess.run(cmd, cwd=cwd, check=True, env=env)
def check_not_root():
if os.geteuid() == 0:
print("ERROR: Do not run this script as root or with sudo.")
print("Armbian's compile.sh will call sudo internally as needed.")
sys.exit(1)
def ensure_packages():
banner("Installing host dependencies")
pkgs = [
"git", "curl", "build-essential",
"binutils-aarch64-linux-gnu", "gcc-aarch64-linux-gnu",
"libncurses-dev", "flex", "bison", "libssl-dev",
"bc", "python3-setuptools", "rsync", "whiptail",
]
run(["sudo", "apt-get", "update", "-qq"])
run(["sudo", "apt-get", "install", "-y"] + pkgs)
def fix_host_linker():
"""Armbian cross-compiles for ARM64; make sure ld.bfd symlink is present."""
banner("Checking ARM64 host linker")
target = Path("/usr/bin/aarch64-linux-gnu-ld.bfd")
symlink = Path("/usr/bin/aarch64-linux-gnu-ld")
if target.exists() and not symlink.exists():
run(["sudo", "ln", "-sf", str(target), str(symlink)])
print(f" Created symlink {symlink} -> {target}")
elif symlink.exists():
print(f" Linker OK: {symlink}")
else:
print(" WARNING: aarch64-linux-gnu-ld.bfd not found — install gcc-aarch64-linux-gnu")
def clone_armbian():
banner("Armbian build framework")
if ARMBIAN_DIR.exists():
print(f" Already cloned at {ARMBIAN_DIR}")
return
run(["git", "clone", "--depth=1", ARMBIAN_REPO, str(ARMBIAN_DIR)])
def clone_chainsx():
"""Clone the chainsx linux-t527 repo for defconfig + DTS files."""
banner("chainsx linux-t527 repo")
if CHAIN_DIR.exists():
print(f" Already cloned at {CHAIN_DIR}")
return
run(["git", "clone", CHAIN_REPO, str(CHAIN_DIR)])
run(["git", "checkout", CHAIN_COMMIT], cwd=str(CHAIN_DIR))
def setup_userpatches():
"""
Armbian userpatches/kernel/<family>-<branch>/ holds per-file overlays.
Any file placed here is copied on top of the kernel source before build.
"""
banner("Setting up userpatches")
for d in [USERPATCHES_DIR, USERPATCHES_KERNEL_DIR,
USERPATCHES_CONFIG_DIR, DTS_OVERLAY_DIR]:
d.mkdir(parents=True, exist_ok=True)
# --- Defconfig ---
src_defconfig = CHAIN_DIR / "arch/arm64/configs/sun55i_t527_bsp_defconfig"
dst_defconfig = USERPATCHES_CONFIG_DIR / "t527_defconfig"
if src_defconfig.exists():
shutil.copy(src_defconfig, dst_defconfig)
# Ensure CONFIG_ARM64 is present
content = dst_defconfig.read_text()
if "CONFIG_ARM64=y" not in content:
with dst_defconfig.open("a") as f:
f.write("\nCONFIG_ARM64=y\n")
print(f" Defconfig -> {dst_defconfig}")
else:
print(f" WARNING: chainsx defconfig not found at {src_defconfig}")
# --- DTS files from upstream ---
for filename, url in DTS_SOURCES.items():
dest = DTS_OVERLAY_DIR / filename
try:
urllib.request.urlretrieve(url, dest)
print(f" Downloaded {filename}")
except Exception as e:
print(f" ERROR downloading {filename}: {e}")
# --- sun55i-t527.dtsi from chainsx (no upstream URL yet) ---
chain_dtsi = CHAIN_DIR / "arch/arm64/boot/dts/allwinner/sun55i-t527.dtsi"
if chain_dtsi.exists():
shutil.copy(chain_dtsi, DTS_OVERLAY_DIR / "sun55i-t527.dtsi")
print(f" Copied sun55i-t527.dtsi from chainsx")
else:
print(" WARNING: sun55i-t527.dtsi not found in chainsx repo")
def write_board_config():
"""
Write a minimal CSC board config and family override into Armbian's
config tree. These live in the build repo (not userpatches) but are
safe to write since they're not generated by Armbian itself.
"""
banner("Writing board + family configs")
# Board file
board_dir = ARMBIAN_DIR / "config/boards"
board_dir.mkdir(parents=True, exist_ok=True)
board_file = board_dir / f"{BOARD}.csc"
board_file.write_text(f"""\
# Avaota A1 — Allwinner T527 (sun55iw3)
BOARD_NAME="Avaota A1"
BOARDFAMILY="{BOARDFAMILY}"
KERNEL_TARGET="current"
KERNEL_CONFIG="t527_defconfig"
BOOT_SCENARIO="spl-blobs"
IMAGE_PARTITION_TABLE="gpt"
""")
print(f" Board file: {board_file}")
# Family override — patch the existing sun55iw3.conf if present,
# otherwise create a minimal one.
family_dir = ARMBIAN_DIR / "config/sources/families"
family_dir.mkdir(parents=True, exist_ok=True)
family_file = family_dir / f"{BOARDFAMILY}.conf"
# Only write if it doesn't already exist (don't clobber Armbian's version)
if not family_file.exists():
family_file.write_text(f"""\
LINUXFAMILY="{BOARDFAMILY}"
KERNELSOURCE="https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git"
KERNELBRANCH="tag:{KERNEL_TAG}"
KERNELDIR="linux-{KERNEL_MAJOR_MINOR}"
ARCH="arm64"
KERNEL_CONFIG="t527_defconfig"
ATF_PLAT="sun55iw3p1"
LINUXCONFIG="linux-{BOARDFAMILY}-current"
""")
print(f" Family config created: {family_file}")
else:
print(f" Family config already exists, not overwriting: {family_file}")
print(" (Edit manually if you need to change KERNELBRANCH)")
def print_build_command():
banner("Setup complete")
print("Run the build with:\n")
print(f" cd {ARMBIAN_DIR}")
print(f" ./compile.sh kernel \\")
print(f" BOARD={BOARD} \\")
print(f" BRANCH=current \\")
print(f" KERNEL_ONLY=yes \\")
print(f" KERNEL_BTF=no \\")
print(f" PREFER_DOCKER=no \\")
print(f" VERBOSE=yes")
print()
print("Tips:")
print(" - Armbian will sudo internally as needed — don't sudo compile.sh")
print(" - First run downloads ~1 GB of toolchain + kernel source")
print(f" - Defconfig: {USERPATCHES_CONFIG_DIR}/t527_defconfig")
print(f" - DTS overlays: {DTS_OVERLAY_DIR}")
print()
# ---------------------------------------------------------------------------
# Main
# ---------------------------------------------------------------------------
def main():
print(f"\n Avaota A1 Armbian Kernel Setup v{VERSION}")
check_not_root() # must be first
ensure_packages()
fix_host_linker()
clone_armbian()
clone_chainsx()
setup_userpatches()
write_board_config()
print_build_command()
if __name__ == "__main__":
main()
A script to help keep things clean
#!/usr/bin/env python3
import shutil
from pathlib import Path
# Base directories
BUILD_DIR = Path.home() / "armbian_build/build"
OUTPUT_DIR = BUILD_DIR / "output"
CACHE_DIR = BUILD_DIR / "cache"
# Directories to clean
CLEAN_PATHS = [
CACHE_DIR,
OUTPUT_DIR / "images",
OUTPUT_DIR / "debs",
OUTPUT_DIR / "logs",
OUTPUT_DIR / "tmp"
]
def remove_path(path: Path):
if path.exists():
if path.is_dir():
print(f"Removing directory: {path}")
shutil.rmtree(path)
else:
print(f"Removing file: {path}")
path.unlink()
else:
print(f"Directory not found, skipping: {path}")
def main():
print("\n--- Cleaning old build caches, outputs, and logs ---")
for path in CLEAN_PATHS:
remove_path(path)
print("\n--- Clean complete ---")
print(" Safe deletions: previous kernel images, DEBs, logs, and temporary caches.")
if __name__ == "__main__":
main()
Assuming you build something a script to check it
#!/usr/bin/env python3
import subprocess
from pathlib import Path
KERNEL_VERSION = "6.18.4-legacy-avaota-a1"
MODULES_TO_CHECK = ["gpio", "i2c", "spi", "usbcore"]
INITRAMFS_PATH = Path("/boot/uInitrd")
HEADERS_PATH = Path(f"/lib/modules/{KERNEL_VERSION}/build/include")
def run(cmd, capture_output=True):
try:
result = subprocess.run(cmd, check=True, capture_output=capture_output, text=True)
return result.stdout.strip()
except subprocess.CalledProcessError as e:
return e.stderr.strip()
def check_modules():
print("\n--- Checking modules ---")
for mod in MODULES_TO_CHECK:
cmd = ["sudo", "modprobe", "-n", "-v", mod]
output = run(cmd)
if "FATAL" in output:
print(f" Command failed: {output}")
else:
print(f" Module {mod} available for loading.")
def check_initramfs():
print("\n--- Checking initramfs ---")
if not INITRAMFS_PATH.exists():
print(f"Initramfs not found: {INITRAMFS_PATH}")
return
try:
cmd = ["lsinitramfs", INITRAMFS_PATH]
output = run(cmd)
lines = output.splitlines()
print("Top entries in initramfs:")
for line in lines[:10]:
print(f" {line}")
except Exception as e:
print(f"Failed to read initramfs: {e}")
def check_headers():
print("\n--- Checking kernel config and headers ---")
if HEADERS_PATH.exists():
print(f"Headers found in: {HEADERS_PATH}")
else:
print(f"Headers missing for kernel: {KERNEL_VERSION}")
def check_installed_packages():
print("\n--- Checking installed kernel packages ---")
cmd = ["dpkg-query", "-l", f"*{KERNEL_VERSION}*"]
output = run(cmd)
if output:
print(f"Installed packages for kernel {KERNEL_VERSION}:\n{output}")
else:
print(f"No packages found for kernel {KERNEL_VERSION}")
def main():
print("\n--- Pre-boot kernel checks ---")
check_modules()
check_initramfs()
check_headers()
check_installed_packages()
print("\n--- Pre-boot kernel checks complete ---")
if __name__ == "__main__":
main()
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
No labels