Skip to content
Merged
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
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ This layer depends on:
| dc-roma-fml13v01 | [DC-ROMA RISC-V Mainboard](https://deepcomputing.io/product/dc-roma-risc-v-mainboard/) | Upstream mainline kernel (7.0) with the in-tree `jh7110-deepcomputing-fml13v01` DTS, Framework Laptop 13 compatible mainboard |
| eswin-ebc77 | ESWIN EBC77 | Vendor kernel. Use `eswin-ebc77-mainline` for upstream version |
| eswin-ebc77-mainline | ESWIN EBC77 | |
| k3-pico-itx | [Sipeed K3 Pico-ITX](https://sipeed.com/k3) | Vendor Kernel |
| freedom-u540 | [HiFive Unleashed](https://www.sifive.com/boards/hifive-unleashed) | Discontinued |
| mangopi-mq-pro | [MangoPi MQ Pro](https://mangopi.org/mangopi_mqpro) | |
| milkv-duo | [Milk-V Duo](https://milkv.io/duo) | |
Expand Down
160 changes: 160 additions & 0 deletions classes/k3-vendor-image.bbclass
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
# K3 Image Common Functions
# This file contains shared functions for K3 image recipes

# Create bootfs partition with kernel, env, Initramfs and dtbs
# Layout matches the reference titan image (Bianbu-GNOME-K3)
# Triggered before ext4 rootfs generation and WIC image generation
do_image_wic[depends] += " \
virtual/kernel:do_shared_workdir \
core-image-minimal-initramfs:do_image_complete \
e2fsprogs-native:do_populate_sysroot \
bmaptool-native:do_populate_sysroot \
"
do_image_wic[prefuncs] += "do_create_bootfs"

python do_create_bootfs() {
import subprocess, os, shutil, gzip, math

deploydir = d.getVar('DEPLOY_DIR_IMAGE')
bootfs_dir = os.path.join(deploydir, 'bootfs')
bootfs_img = os.path.join(deploydir, 'bootfs.ext4')
machine = d.getVar('MACHINE')
Comment thread
threexc marked this conversation as resolved.

# Read kernel release (e.g. "6.18.3-k3") from the kernel build's
# kernel-abiversion file. virtual/kernel:do_shared_workdir is a
# dependency of this task so the file is guaranteed to exist.
kabi_path = os.path.join(d.getVar('STAGING_KERNEL_BUILDDIR'),
'kernel-abiversion')
with open(kabi_path) as f:
kver_k3 = f.read().strip()

# 1. Reset and prepare bootfs directory
bb.utils.remove(bootfs_dir, recurse=True)
bb.utils.mkdirhier(bootfs_dir)

# DTB subdirectory: spacemit/<version>/
dtb_subdir = os.path.join(bootfs_dir, 'spacemit', kver_k3)
bb.utils.mkdirhier(dtb_subdir)

# Define helper function for copy logic
def copy_file(src_name, dst_path):
src = os.path.join(deploydir, src_name)
if os.path.exists(src):
shutil.copy2(src, dst_path)
bb.note(f"Copied {src_name} to bootfs")
return True
else:
bb.warn(f"File not found: {src_name}")
return False

# 2. Copy kernel (compressed vmlinuz)
vmlinuz_name = f"vmlinuz-{kver_k3}"
image_path = os.path.join(deploydir, 'Image')
if not os.path.exists(image_path):
bb.fatal("Image not found in DEPLOYDIR")
with open(image_path, 'rb') as f_in:
with gzip.open(os.path.join(bootfs_dir, vmlinuz_name), 'wb',
compresslevel=9) as f_out:
shutil.copyfileobj(f_in, f_out)

# 3. Initramfs (rename to initrd.img-<version>)
Comment thread
threexc marked this conversation as resolved.
initrd_name = f"initrd.img-{kver_k3}"
initramfs = next((f for f in os.listdir(deploydir)
if f.startswith('core-image-minimal-initramfs-') and f.endswith('.cpio.gz')), None)
if initramfs:
copy_file(initramfs, os.path.join(bootfs_dir, initrd_name))
else:
bb.fatal("initramfs not found")

# 4. DTBs -> spacemit/<version>/
dtbs = [f for f in os.listdir(deploydir)
if f.endswith('.dtb') and not os.path.islink(os.path.join(deploydir, f))]
if not dtbs:
bb.warn("No DTB files found")
for dtb in dtbs:
copy_file(dtb, os.path.join(dtb_subdir, dtb))

# 5. Calculate size and generate image (add 15% margin)
total_size_kb = sum(os.path.getsize(os.path.join(root, f))
for root, dirs, files in os.walk(bootfs_dir)
for f in files) / 1024
calc_mb = math.ceil((total_size_kb * 1.15) / 1024) + 1
final_mb = max(int(d.getVar('SDIMG_BOOTFS_SIZE') or 256), calc_mb)

# 6. env_k3.txt (generate to match reference image format)
env_content = f"""knl_name={vmlinuz_name}
ramdisk_name={initrd_name}
dtb_dir=spacemit/{kver_k3}
ramdisk_addr=0x130000000
loglevel=8
commonargs=setenv bootargs plymouth.prefer-fbcon plymouth.ignore-serial-consoles
"""
env_path = os.path.join(bootfs_dir, 'env_k3.txt')
with open(env_path, 'w') as f:
f.write(env_content)

# 7. Call mke2fs to create ext4 image
# Disable orphan_file and metadata_csum_seed: U-Boot 2022.10 ext4 driver
# does not recognize these features and fails to mount the filesystem.
cmd = ['mke2fs', '-F', '-L', 'bootfs', '-t', 'ext4',
'-b', '4096',
'-O', '^orphan_file,^metadata_csum_seed',
'-d', bootfs_dir, bootfs_img, f'{final_mb}M']
r = subprocess.run(cmd, capture_output=True, text=True)
if r.returncode != 0:
bb.fatal(f"mke2fs failed: {r.stderr}")
bb.note(f"bootfs.ext4 ({final_mb}MB) created successfully")
}

# Inject bootinfo into WIC image after WIC generation
do_image_wic[postfuncs] += "write_bootinfo_to_wic"

python write_bootinfo_to_wic() {
import subprocess, os, gzip, shutil

imgdeploydir = d.getVar('IMGDEPLOYDIR')
image_name = d.getVar('IMAGE_NAME')
deploy_dir = d.getVar('DEPLOY_DIR_IMAGE')

bootinfo_path = os.path.join(deploy_dir, 'bootinfo_block.bin')
wic_gz_path = os.path.join(imgdeploydir, image_name + '.wic.gz')
wic_bmap_path = os.path.join(imgdeploydir, image_name + '.wic.bmap')

if not os.path.exists(bootinfo_path):
bb.warn(f"[Post-WIC] bootinfo not found: {bootinfo_path} - skipping")
return

if not os.path.exists(wic_gz_path):
bb.error(f"[Post-WIC] WIC file not found: {wic_gz_path}")
return

tmp_wic = wic_gz_path[:-3] # strip .gz

try:
with gzip.open(wic_gz_path, 'rb') as f_in, open(tmp_wic, 'wb') as f_out:
shutil.copyfileobj(f_in, f_out)

r = subprocess.run(
['dd', f'if={bootinfo_path}', f'of={tmp_wic}',
'bs=1K', 'seek=1024', 'count=128', 'conv=notrunc'],
capture_output=True)
if r.returncode != 0:
bb.error(f"[Post-WIC] dd failed: {r.stderr.decode()}")
return
bb.note("[Post-WIC] Injected bootinfo (128K @ 1M)")

with open(tmp_wic, 'rb') as f_in, gzip.open(wic_gz_path, 'wb', compresslevel=9) as f_out:
shutil.copyfileobj(f_in, f_out)

if os.path.exists(wic_bmap_path):
r = subprocess.run(
['bmaptool', 'create', tmp_wic, '-o', wic_bmap_path],
Comment thread
threexc marked this conversation as resolved.
capture_output=True)
if r.returncode == 0:
bb.note("[Post-WIC] Regenerated bmap")
else:
bb.warn(f"[Post-WIC] bmaptool failed: {r.stderr.decode()}")
finally:
if os.path.exists(tmp_wic):
os.unlink(tmp_wic)
}
30 changes: 30 additions & 0 deletions conf/machine/include/k3-vendor.inc
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
#@TYPE: SOC
#@NAME: Spacemit K3
#@SOC: Spacemit K3
#@DESCRIPTION: SoC configuration for the Spacemit K3 - vendor repo version

require conf/machine/include/riscv-common.inc
require conf/machine/include/soc-family.inc

SOC_FAMILY = "k3"

PREFERRED_PROVIDER_virtual/kernel ?= "linux-k3"
PREFERRED_PROVIDER_virtual/bootloader ?= "u-boot-k3"
PREFERRED_PROVIDER_opensbi ?= "opensbi-k3"

SERIAL_CONSOLES = "115200;ttyS0"

# Add esos-k3 firmware as image dependency
EXTRA_IMAGEDEPENDS += "esos-k3 u-boot-k3 u-boot-spl-k3"

UBOOT_MACHINE = "k3_defconfig"

KERNEL_IMAGETYPE = "Image"

IMAGE_FSTYPES = "ext4 wic.bmap wic.gz"
IMAGE_CLASSES += " k3-vendor-image"
INITRAMFS_FSTYPES = "cpio.gz"
WKS_FILE ?= "spacemit-k3.wks"
WKS_FILE_DEPENDS:append = " u-boot-k3"

MACHINE_FEATURES:append = " usbhost usbgadget"
18 changes: 18 additions & 0 deletions conf/machine/k3-pico-itx.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#@TYPE: Machine
#@NAME: K3 Pico-ITX
#@SOC: Spacemit K3
#@DESCRIPTION: Machine configuration for K3 Pico-ITX development board

require conf/machine/include/k3-vendor.inc

KERNEL_DEVICETREE ?= "spacemit/k3-pico-itx.dtb"

IMAGE_BOOT_FILES += " \
k3-pico-itx.dtb \
"

MACHINE_EXTRA_RRECOMMENDS += "\
linux-firmware-rtl8851 \
linux-firmware-rtl8852 \
linux-firmware-rtl8922 \
"
60 changes: 60 additions & 0 deletions docs/k3-pico-itx.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
K3 Pico-ITX
===========

The K3 Pico-ITX is a 64-bit, RVA23-compliant RISC-V platform based on the
SpacemiT K3 SoC.

How to Build
============

Clone and enable these repositories and enable the below layers:

* bitbake
* openembedded-core
* meta
* meta-riscv

See [the Yocto Project](https://docs.yoctoproject.org/brief-yoctoprojectqs/index.html) manual for details.

Set these variables in a configuration file:

* `MACHINE = "k3-pico-itx"`
* `DISTRO = "poky-altcfg"`
* `EXTRA_IMAGE_FEATURES = "allow-empty-password empty-root-password allow-root-login post-install-logging"`

Build your image:

```
$ bitbake core-image-minimal
```

Flashing the Image
==================

The K3 Pico-ITX does not have a microSD card slot, but it does support NVMe
storage. You can flash your image to an NVMe drive (assuming that it is
connected to a machine using an USB-to-NVMe adapter, or a spare NVMe slot) using `bmaptool`

```
$ sudo bmaptool copy build/tmp/deploy/images/k3-pico-itx/core-image-minimal-k3-pico-itx.rootfs.wic.gz /dev/sdx
```

Boot the Board
==============

Connect a USB to serial dongle to your board and to your PC, and
start your favorite terminal emulator:

```
$ sudo apt install tio
$ tio /dev/ttyUSB0
```

Power the board and you will see it boot to a Linux command line shell.

Resources
=========

* [K3 Pico-ITX User
Guide](https://www.spacemit.com/community/document/info?nodepath=hardware/eco/k3_pico/pico_user_guide.md)
* [Sipeed K3](https://sipeed.com/k3)
20 changes: 20 additions & 0 deletions files/wic/spacemit-k3.wks
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# K3 SD Card Image WIC Configuration
# Boot sequence: FSBL → esos → opensbi → u-boot → kernel
# Bootinfo (128 Kbytes) is injected via image-k3.inc post-processing at offset 1M
# Partition layout matches partition_universal.json

bootloader --ptable gpt

part --part-name env --source rawcopy --sourceparams="file=u-boot-env-default.bin" --fixed-size 64K --align 640

part --part-name fsbl --source rawcopy --sourceparams="file=FSBL.bin" --fixed-size 512K --align 1536

part --part-name esos --source rawcopy --sourceparams="file=esos.itb" --fixed-size 3M --align 4096

part --part-name opensbi --source rawcopy --sourceparams="file=fw_dynamic.itb" --fixed-size 1M --align 7168

part --part-name uboot --source rawcopy --sourceparams="file=u-boot.itb" --fixed-size 4M --align 8192

part --part-name bootfs --source rawcopy --sourceparams="file=bootfs.ext4" --fixed-size 256M --align 12288

part --part-name rootfs --source rootfs --fstype=ext4 --label rootfs --align 274432
24 changes: 24 additions & 0 deletions recipes-bsp/firmware/esos-k3_1.0.0.bb
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
SUMMARY = "K3 ESOS firmware (prebuilt)"
DESCRIPTION = "Prebuilt ESOS firmware (esos.itb) for K3 boot image, loaded by FSBL before U-Boot."
# The spacemit-firmware repository uses a simple copyright notice allowing use
# and redistribution of firmware binaries as-is and without modification, but
# it does not otherwise follow typical open-source licensing terms.
LICENSE = "CLOSED"
Comment thread
threexc marked this conversation as resolved.

inherit deploy

COMPATIBLE_MACHINE = "(k3)"

BRANCH = "master"
SRC_URI = " \
git://github.com/spacemit-com/spacemit-firmware.git;protocol=https;branch=${BRANCH} \
"
Comment thread
threexc marked this conversation as resolved.

SRCREV = "9c550e02f8781e4d287c6b64dd4c0f71a655ac69"

do_deploy() {
install -d ${DEPLOYDIR}
install -m 0644 ${S}/k3/k3-br-v1.0.0/esos.itb ${DEPLOYDIR}/
}

addtask deploy after do_compile
47 changes: 47 additions & 0 deletions recipes-bsp/opensbi/opensbi-k3_1.4.bb
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
SUMMARY = "RISC-V Open Source Supervisor Binary Interface (OpenSBI) for Spacemit K3"
DESCRIPTION = "OpenSBI implementation for Spacemit K3 RISC-V processor"
HOMEPAGE = "https://github.com/riscv/opensbi"
LICENSE = "BSD-2-Clause"
LIC_FILES_CHKSUM = "file://COPYING.BSD;md5=42dd9555eb177f35150cf9aa240b61e5"

require recipes-bsp/opensbi/opensbi-payloads.inc

inherit deploy

COMPATIBLE_MACHINE = "k3"
INHIBIT_PACKAGE_STRIP = "1"

DEPENDS += "u-boot-tools-native dtc-native"

PROVIDES += "opensbi"

SRCREV = "e5fc30394ac18263fa045dcaef52f86f180ed512"
SRC_URI = "git://github.com/spacemit-com/opensbi.git;branch=k3-br-v1.0.y;protocol=https"

RISCV_SBI_PLAT = "generic"
OPENSBI_DEFCONFIG = "k3_defconfig"

EXTRA_OEMAKE += "PLATFORM=${RISCV_SBI_PLAT} I=${D} FW_PIC=y"
EXTRA_OEMAKE += "PLATFORM_DEFCONFIG=${OPENSBI_DEFCONFIG}"
EXTRA_OEMAKE += "CROSS_COMPILE=${TARGET_PREFIX}"

# OpenSBI uses Makefile, not autotools - skip configure
do_configure[noexec] = "1"

# We don't need do_install either, since we're deploying specific files
# ourselves
do_install[noexec] = "1"

do_deploy() {
install -d ${DEPLOYDIR}

BUILD_DIR="${S}/build/platform/${RISCV_SBI_PLAT}/firmware"

for file in fw_dynamic.bin fw_dynamic.elf fw_dynamic.itb; do
if [ -f "${BUILD_DIR}/${file}" ]; then
install -m 0644 "${BUILD_DIR}/${file}" "${DEPLOYDIR}/${file}"
fi
done
}

addtask deploy before do_build after do_install
Loading
Loading