-
-
Notifications
You must be signed in to change notification settings - Fork 463
196 lines (176 loc) · 8.71 KB
/
Copy pathimage.yml
File metadata and controls
196 lines (176 loc) · 8.71 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
name: image
on:
workflow_run:
workflows: [build]
types: [completed]
workflow_dispatch:
inputs:
build_id:
description: 'Build ID to assemble (e.g. nightly-20260520-887328c). Default: channels.nightly from manifest.'
required: false
permissions:
contents: write
jobs:
toolchain:
name: Image
runs-on: ubuntu-latest
# Run after nightly (schedule) or operator dispatch only — PR builds do
# not produce new release assets, so reassembling images on every PR
# build is wasted compute. Mirrors the gate in manifest.yml.
#
# Publish on success AND on partial-failure: see manifest.yml rationale.
# A flaky board doesn't deny image assembly for the platforms that did
# upload a firmware tgz — firmware_url returns empty for missing ones and
# create() skips them.
#
# First clause: on a mirror the nightly's jobs skip, but the run still
# completes and fires workflow_run, so gate the cron-originated path on
# the canonical repo too — see build.yml's preflight. Dispatch-driven
# reassembly is untouched anywhere.
if: >-
(github.event.workflow_run.event != 'schedule' ||
github.repository == 'OpenIPC/firmware') &&
(github.event_name == 'workflow_dispatch' ||
((github.event.workflow_run.event == 'schedule' ||
github.event.workflow_run.event == 'workflow_dispatch') &&
contains(fromJSON('["success", "failure"]'), github.event.workflow_run.conclusion)))
env:
SIGMASTAR: ssc30kd ssc30kq ssc325 ssc333 ssc335 ssc335de ssc337 ssc337de ssc338q ssc377 ssc377d ssc377de ssc377qe ssc378de ssc378qe
INGENIC: t10 t10l t20 t20l t20x t21n t23n t30a t30a1 t30l t30n t30x t31a t31al t31l t31lc t31n t31x
ALLWINNER: v851s
MANIFEST_URL: https://openipc.github.io/firmware/manifest.json
UBOOT_URL: https://github.com/openipc/firmware/releases/download/latest
steps:
- name: Resolve build_id from manifest
id: resolve
env:
INPUT_BUILD_ID: ${{ inputs.build_id }}
run: |
set -eu
curl -fsSL "$MANIFEST_URL" -o /tmp/manifest.json
if [ -n "$INPUT_BUILD_ID" ]; then
BUILD_ID="$INPUT_BUILD_ID"
else
BUILD_ID=$(jq -r '.channels.nightly // ""' /tmp/manifest.json)
fi
if [ -z "$BUILD_ID" ] || [ "$BUILD_ID" = "null" ]; then
echo "::error::No build_id resolved (manifest channels.nightly empty? input not given?)"
exit 1
fi
# Sanity check: does the manifest actually know this build?
if ! jq -e --arg b "$BUILD_ID" '.builds[] | select(.id==$b)' /tmp/manifest.json >/dev/null; then
echo "::error::build_id $BUILD_ID is not present in manifest at $MANIFEST_URL"
exit 1
fi
echo "build_id=$BUILD_ID" >> "$GITHUB_OUTPUT"
echo "Assembling images for $BUILD_ID"
- name: Prepare
env:
BUILD_ID: ${{ steps.resolve.outputs.build_id }}
run: |
MANIFEST=/tmp/manifest.json
# firmware_url <firmware_soc> <variant>
# -> echoes the .nor URL for ${firmware_soc}_${variant} in
# $BUILD_ID, or nothing if the manifest has no such entry.
firmware_url() {
jq -r --arg b "$BUILD_ID" --arg p "${1}_${2}" \
'.builds[] | select(.id==$b) | .platforms[$p].nor.url // empty' \
"$MANIFEST"
}
# create <uboot_board> <firmware_soc> <variant>
# The two SoC arguments differ for Ingenic: u-boot is per
# board (t31al, t31lc, ...), firmware is per family (t31).
create() {
uboot=u-boot-$1-nor.bin
release=target/openipc-$1-nor-$3.bin
mkdir -p output target
if ! wget -nv "$UBOOT_URL/$uboot" -O "output/$1.bin"; then
echo -e "Download failed: $UBOOT_URL/$uboot\n"
return 0
fi
url=$(firmware_url "$2" "$3")
if [ -z "$url" ]; then
echo -e "Skip: no firmware in $BUILD_ID for ${2}_${3}\n"
return 0
fi
if ! wget -nv "$url" -O "output/$2.tgz"; then
echo -e "Download failed: $url\n"
return 0
fi
tar -xf output/$2.tgz -C output
dd if=/dev/zero bs=1K count=5000 status=none | tr '\000' '\377' > $release
dd if=output/$1.bin of=$release bs=1K seek=0 conv=notrunc status=none
dd if=output/uImage.$2 of=$release bs=1K seek=320 conv=notrunc status=none
dd if=output/rootfs.squashfs.$2 of=$release bs=1K seek=2368 conv=notrunc status=none
rm -rf output
echo -e "Created: $release\n"
}
# create_hisi <uboot_artifact> <firmware_soc> <variant> <release_tag> <fw_off_kib>
# HiSilicon V4/V5: u-boot is published per DDR binning (the
# boot-ROM DDR init table is baked into each boot image), and the
# firmware .tgz holds a single pre-packed kernel+rootfs blob
# (firmware.bin.<soc>) flashed at the SoC's firmware-partition
# offset. So assemble one full NOR image per DDR binning:
# u-boot at 0, firmware.bin at <fw_off_kib>.
create_hisi() {
local uboot="$1" soc="$2" variant="$3" tag="$4" off="$5"
local release="target/openipc-${tag}-nor-${variant}.bin"
mkdir -p output target
if ! wget -nv "$UBOOT_URL/$uboot" -O "output/$uboot"; then
echo -e "Download failed: $UBOOT_URL/$uboot\n"
return 0
fi
url=$(firmware_url "$soc" "$variant")
if [ -z "$url" ]; then
echo -e "Skip: no firmware in $BUILD_ID for ${soc}_${variant}\n"
return 0
fi
if ! wget -nv "$url" -O "output/$soc.tgz"; then
echo -e "Download failed: $url\n"
return 0
fi
tar -xf "output/$soc.tgz" -C output
# 16 MiB NOR, erased (0xff); u-boot at 0, firmware.bin at its
# partition offset (cv6xx MTDPARTS: firmware @ 0x50000 = 320 KiB).
dd if=/dev/zero bs=1K count=16384 status=none | tr '\000' '\377' > "$release"
dd if="output/$uboot" of="$release" bs=1K seek=0 conv=notrunc status=none
dd if="output/firmware.bin.$soc" of="$release" bs=1K seek="$off" conv=notrunc status=none
rm -rf output
echo -e "Created: $release\n"
}
for soc in $SIGMASTAR $ALLWINNER; do
create $soc $soc lite
create $soc $soc ultimate
done
for soc in $INGENIC; do
create $soc ${soc:0:3} lite
create $soc ${soc:0:3} ultimate
done
# HiSilicon Hi3516CV610/CV608 (cv6xx family). The kernel+rootfs blob
# is identical across DDR variants; only the per-binning u-boot (DDR
# init table) differs, so emit one full image per DDR topology.
# cv610 spans three topologies (DDR2-64M / DDR3-128M / DDR3-512M);
# cv608 is a single DDR2-64M part. firmware partition @ 0x50000.
# The 20s/00s u-boots are picked per DDR (their 20g/00g siblings
# carry the same DDR table, differing only in the socmodel env tag).
for variant in ultimate; do
create_hisi boot-hi3516cv610-10b-nor.bin hi3516cv6xx "$variant" hi3516cv610-ddr2-64m 320
create_hisi boot-hi3516cv610-20s-nor.bin hi3516cv6xx "$variant" hi3516cv610-ddr3-128m 320
create_hisi boot-hi3516cv610-00s-nor.bin hi3516cv6xx "$variant" hi3516cv610-ddr3-512m 320
create_hisi boot-hi3516cv608-nor.bin hi3516cv6xx "$variant" hi3516cv608 320
done
# HiSilicon Hi3519DV500 (aarch64 V5). Same scheme: a single shared
# kernel+rootfs blob (firmware.bin.hi3519dv500) plus a per-binning
# u-boot whose baked DDR reg table differs by board layout — dmeb
# (6-layer) and dmebpro (4-layer flyby), both DDR4-2666 2 GB. NOR
# layout (16 MiB): u-boot @0, env @0x80000, firmware @0xC0000 = 768 KiB.
for variant in ultimate; do
create_hisi boot-hi3519dv500-dmeb-nor.bin hi3519dv500 "$variant" hi3519dv500-dmeb 768
create_hisi boot-hi3519dv500-dmebpro-nor.bin hi3519dv500 "$variant" hi3519dv500-dmebpro 768
done
- name: Upload
uses: softprops/action-gh-release@v2
with:
tag_name: image
make_latest: false
files: target/*.bin