1#!/bin/bash
2# SPDX-License-Identifier: BSD-3-Clause
3# Copyright(c) 2021 Intel Corporation. All rights reserved.
4
5# stop on most errors
6set -e
7
8SOF_TOP=$(cd "$(dirname "$0")" && cd .. && pwd)
9
10SUPPORTED_PLATFORMS=(apl cnl icl tgl-h)
11# Default value, can (and sometimes must) be overridden with -p
12WEST_TOP="${SOF_TOP}"/zephyrproject
13BUILD_JOBS=$(nproc --all)
14RIMAGE_KEY=modules/audio/sof/keys/otc_private_key.pem
15PLATFORMS=()
16
17die()
18{
19	>&2 printf '%s ERROR: ' "$0"
20	# We want die() to be usable exactly like printf
21	# shellcheck disable=SC2059
22	>&2 printf "$@"
23	>&2 printf '\n'
24	exit 1
25}
26
27print_usage()
28{
29    cat <<EOF
30Re-configures and re-builds SOF with Zephyr using a pre-installed Zephyr toolchain and
31the _defconfig file for that platform.
32
33usage: $0 [options] platform(s)
34
35       -a Build all platforms.
36       -j n Set number of make build jobs. Jobs=#cores by default.
37           Infinite when not specified.
38       -k Path to a non-default rimage signing key.
39       -c recursively clones Zephyr inside sof before building.
40          Incompatible with -p.
41       -p Existing Zephyr project directory. Incompatible with -c.  If
42          zephyr-project/modules/audio/sof is missing then a
43          symbolic link pointing to ${SOF_TOP} will automatically be
44          created and west will recognize it as a new sof module.
45          This -p option is always _required_ if the real (not symbolic)
46          sof/ and zephyr-project/ directories are not nested in one
47          another.
48
49This script supports XtensaTools but only when installed in a specific
50directory structure, example:
51
52myXtensa/
53└── install/
54    ├── builds/
55    │   ├── RD-2012.5-linux/
56    │   │   └── Intel_HiFiEP/
57    │   └── RG-2017.8-linux/
58    │       ├── LX4_langwell_audio_17_8/
59    │       └── X4H3I16w2D48w3a_2017_8/
60    └── tools/
61        ├── RD-2012.5-linux/
62        │   └── XtensaTools/
63        └── RG-2017.8-linux/
64            └── XtensaTools/
65
66$ XTENSA_TOOLS_ROOT=/path/to/myXtensa $0 ...
67
68Supported platforms ${SUPPORTED_PLATFORMS[*]}
69
70EOF
71}
72
73# Downloads zephyrproject inside sof/ and create a ../../.. symbolic
74# link back to sof/
75clone()
76{
77	type -p west || die "Install west and a west toolchain following https://docs.zephyrproject.org/latest/getting_started/index.html"
78	type -p git || die "Install git"
79
80	[ -e "$WEST_TOP" ] && die "$WEST_TOP already exists"
81	mkdir -p "$WEST_TOP"
82	git clone --depth=5 https://github.com/zephyrproject-rtos/zephyr \
83	    "$WEST_TOP"/zephyr
84	git -C "$WEST_TOP"/zephyr --no-pager log --oneline --graph \
85	    --decorate --max-count=20
86	west init -l "${WEST_TOP}"/zephyr
87	( cd "${WEST_TOP}"
88	  mkdir -p modules/audio
89	  ln -s ../../.. modules/audio/sof
90	  # Do NOT "west update sof"!!
91	  west update zephyr hal_xtensa
92	)
93}
94
95install_opts()
96{
97    install -D -p "$@"
98}
99
100build()
101{
102	cd "$WEST_TOP"
103	west topdir || {
104	    printf 'SOF_TOP=%s\nWEST_TOP=%s\n' "$SOF_TOP" "$WEST_TOP"
105	    die 'try the -p option?'
106	    # Also note west can get confused by symbolic links, see
107	    # https://github.com/zephyrproject-rtos/west/issues/419
108	}
109
110	local STAGING=build-sof-staging
111	mkdir -p ${STAGING}/sof/ # smex does not use 'install -D'
112
113	for platform in "${PLATFORMS[@]}"; do
114		case "$platform" in
115			apl)
116				PLAT_CONFIG='intel_adsp_cavs15'
117				# XCC build runs out of memory, tracked as
118				# https://github.com/thesofproject/sof/issues/4645
119				unset XTENSA_TOOLS_ROOT
120				#XTENSA_CORE="X4H3I16w2D48w3a_2017_8"
121				#XTENSA_TOOLS_VERSION="RG-2017.8-linux"
122				;;
123			cnl)
124				PLAT_CONFIG='intel_adsp_cavs18'
125				XTENSA_CORE="X6H3CNL_2017_8"
126				XTENSA_TOOLS_VERSION="RG-2017.8-linux"
127				;;
128			icl)
129				PLAT_CONFIG='intel_adsp_cavs20'
130				XTENSA_CORE="X6H3CNL_2017_8"
131				XTENSA_TOOLS_VERSION="RG-2017.8-linux"
132				;;
133			tgl-h)
134				PLAT_CONFIG='intel_adsp_cavs25'
135				XTENSA_CORE="cavs2x_LX6HiFi3_2017_8"
136				XTENSA_TOOLS_VERSION="RG-2017.8-linux"
137				RIMAGE_KEY=modules/audio/sof/keys/otc_private_key_3k.pem
138				;;
139			imx8)
140				PLAT_CONFIG='nxp_adsp_imx8'
141				RIMAGE_KEY='' # no key needed for imx8
142				;;
143			*)
144				echo "Unsupported platform: $platform"
145				exit 1
146				;;
147		esac
148
149		if [ -n "$XTENSA_TOOLS_ROOT" ]
150		then
151			# set variables expected by zephyr/cmake/toolchain/xcc/generic.cmake
152			export ZEPHYR_TOOLCHAIN_VARIANT=xcc
153			export XTENSA_TOOLCHAIN_PATH="$XTENSA_TOOLS_ROOT/install/tools"
154			export TOOLCHAIN_VER="$XTENSA_TOOLS_VERSION"
155			printf 'XTENSA_TOOLCHAIN_PATH=%s\n' "${XTENSA_TOOLCHAIN_PATH}"
156			printf 'TOOLCHAIN_VER=%s\n' "${TOOLCHAIN_VER}"
157
158			# set variables expected by xcc toolchain
159			XTENSA_BUILDS_DIR="$XTENSA_TOOLS_ROOT/install/builds/$XTENSA_TOOLS_VERSION"
160			export XTENSA_SYSTEM=$XTENSA_BUILDS_DIR/$XTENSA_CORE/config
161			printf 'XTENSA_SYSTEM=%s\n' "${XTENSA_SYSTEM}"
162		fi
163
164		local bdir=build-"$platform"
165
166		(
167			 # west can get lost in symbolic links and then
168			 # show a confusing error.
169			/bin/pwd
170			set -x
171			west build --build-dir "$bdir" --board "$PLAT_CONFIG" \
172				zephyr/samples/subsys/audio/sof
173
174			# This should ideally be part of
175			# sof/zephyr/CMakeLists.txt but due to the way
176			# Zephyr works, the SOF library build there does
177			# not seem like it can go further than a
178			# "libmodules_sof.a" file that smex does not
179			# know how to use.
180			"$bdir"/zephyr/smex_ep/build/smex \
181			       -l "$STAGING"/sof/sof-"$platform".ldc \
182			       "$bdir"/zephyr/zephyr.elf
183
184			# Build rimage
185			RIMAGE_DIR=build-rimage
186			cmake -B "$RIMAGE_DIR" -S modules/audio/sof/rimage
187			make -C "$RIMAGE_DIR" -j"$BUILD_JOBS"
188
189			west sign  --build-dir "$bdir" \
190				--tool rimage --tool-path "$RIMAGE_DIR"/rimage \
191				--tool-data modules/audio/sof/rimage/config -- -k "$RIMAGE_KEY"
192		)
193		install_opts -m 0644 "$bdir"/zephyr/zephyr.ri \
194			     "$STAGING"/sof/community/sof-"$platform".ri
195	done
196
197	install_opts -m 0755 "$bdir"/zephyr/sof-logger_ep/build/logger/sof-logger \
198		     "$STAGING"/tools/sof-logger
199
200	tree "$STAGING"
201}
202
203main()
204{
205	local zeproj
206
207	# parse the args
208	while getopts "acj:k:p:" OPTION; do
209		case "$OPTION" in
210			a) PLATFORMS=("${SUPPORTED_PLATFORMS[@]}") ;;
211			c) DO_CLONE=yes ;;
212			j) BUILD_JOBS="$OPTARG" ;;
213			k) RIMAGE_KEY="$OPTARG" ;;
214			p) zeproj="$OPTARG" ;;
215			*) print_usage; exit 1 ;;
216		esac
217	done
218	shift $((OPTIND-1))
219
220	if [ -n "$zeproj" ] && [ x"$DO_CLONE" = xyes ]; then
221	    die 'Cannot use -p with -c, -c supports %s only' "${WEST_TOP}"
222	fi
223
224	if [ -n "$zeproj" ]; then
225
226	    [ -d "$zeproj" ] ||
227		die "$zeproj is not a directory, try -c instead of -p?"
228
229	    ( cd "$zeproj"
230	      test "$(realpath "$(west topdir)")" = "$(/bin/pwd)"
231	    ) || die '%s is not a zephyrproject' "$WEST_TOP"
232
233	    WEST_TOP="$zeproj"
234	fi
235
236	# parse platform args
237	for arg in "$@"; do
238		platform=none
239		for i in "${SUPPORTED_PLATFORMS[@]}"; do
240			if [ x"$i" = x"$arg" ]; then
241				PLATFORMS=("${PLATFORMS[@]}" "$i")
242				platform="$i"
243				shift || true
244				break
245			fi
246		done
247		if [ "$platform" == "none" ]; then
248			echo "Error: Unknown platform specified: $arg"
249			echo "Supported platforms are: ${SUPPORTED_PLATFORMS[*]}"
250			exit 1
251		fi
252	done
253
254	# check target platform(s) have been passed in
255	if [ "${#PLATFORMS[@]}" -eq 0 ]; then
256		echo "Error: No platforms specified. Supported are: " \
257		     "${SUPPORTED_PLATFORMS[*]}"
258		print_usage
259		exit 1
260	fi
261
262	if [ "x$DO_CLONE" == "xyes" ]; then
263		clone
264	else
265		# Symlink zephyr-project to our SOF selves if no sof west module yet
266		test -e "${WEST_TOP}"/modules/audio/sof || {
267		    mkdir -p "${WEST_TOP}"/modules/audio
268		    ln -s "$SOF_TOP" "${WEST_TOP}"/modules/audio/sof
269		}
270
271		# FIXME: remove this hack. Downloading and building
272		# should be kept separate but support for submodules in
273		# west is too recent, cannot rely on it yet.
274		test -e "${WEST_TOP}"/modules/audio/sof/rimage/CMakeLists.txt || (
275		    cd "${WEST_TOP}"/modules/audio/sof
276		    git submodule update --init --recursive
277		)
278	fi
279
280	build
281}
282
283main "$@"
284