Skip to content
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
8 changes: 4 additions & 4 deletions app/boards/intel_adsp/Kconfig.defconfig
Original file line number Diff line number Diff line change
Expand Up @@ -123,8 +123,8 @@ config INTEL_ADSP_TIMER
config MM_DRV
default y

config UAOL
default y if ACE
# config UAOL
# default y if ACE


# # Zephyr / power settings
Expand Down Expand Up @@ -165,8 +165,8 @@ config LOG_FUNC_NAME_PREFIX_INF
config LOG_FUNC_NAME_PREFIX_DBG
default y

config LOG_CORE_ID_PREFIX
default y
# config LOG_CORE_ID_PREFIX
# default y

config LOG_TIMESTAMP_64BIT
default y
Expand Down
40 changes: 40 additions & 0 deletions app/boards/intel_adsp_ace30_ptl_llvm_qemu.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# LLVM Single-Core QEMU Testing Configuration
# Base: intel_adsp_ace30_ptl.conf (applied automatically by board name)
# Purpose: Override settings for single-core LLVM QEMU testing
#
# This config is applied ON TOP of the base intel_adsp_ace30_ptl.conf
# via -DEXTRA_CONF_FILE= to the build system.

# ---- Single core for QEMU (no SMP hangs) ----
CONFIG_CORE_COUNT=1
CONFIG_SMP=n
CONFIG_EVENTS=y

# ---- Disable LLEXT/loadable modules (missing TIE headers in LLVM) ----
CONFIG_LLEXT=n
CONFIG_LIBRARY_MANAGER=n
CONFIG_INTEL_MODULES=n
CONFIG_LIBRARY_AUTH_SUPPORT=n
CONFIG_LIBRARY_BUILD_LIB=n
CONFIG_LIBRARY_DEFAULT_MODULAR=n

# ---- Disable HiFi3-optimized code (missing xt_FP.h in LLVM) ----
CONFIG_FORMAT_CONVERT_HIFI3=n
CONFIG_PCM_CONVERTER_FORMAT_CONVERT_HIFI3=n

# ---- Make all modules static (since LLEXT is off) ----
CONFIG_COMP_TESTER=y
CONFIG_COMP_GOOGLE_RTC_AUDIO_PROCESSING=y

# ---- Logging: use deferred mode matching working build-ptl ----
CONFIG_LOG_MODE_DEFERRED=y

# ---- Disable userspace for simpler single-core boot ----
CONFIG_USERSPACE=n
CONFIG_DYNAMIC_THREAD=n
CONFIG_DYNAMIC_THREAD_ALLOC=n
CONFIG_SOF_USERSPACE_PROXY=n
CONFIG_MAX_THREAD_BYTES=1
CONFIG_SCHED_CPU_MASK=n
CONFIG_PM=n
CONFIG_ADSP_IMR_CONTEXT_SAVE=n
28 changes: 23 additions & 5 deletions scripts/llext_link_helper.py
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,11 @@ def main():

if (s_flags & (SH_FLAGS.SHF_WRITE | SH_FLAGS.SHF_ALLOC) ==
SH_FLAGS.SHF_WRITE | SH_FLAGS.SHF_ALLOC):
# .rodata may be marked writable by the Clang/objcopy LLEXT
# pipeline but should still be placed near .text for l32r reach
if s_name == '.rodata' or s_name.startswith('.rodata.'):
readonly.append(section)
continue
# .data, .bss or other writable sections
writable.append(section)
continue
Expand Down Expand Up @@ -181,17 +186,30 @@ def main():

dram_addr += section.header['sh_size']

start_addr = align_up(text_addr + text_size, 0x1000)

# Place readonly sections BEFORE .text so that Xtensa l32r instructions
# (which can only reach backwards up to 256KB) can access .rodata literals.
readonly_size = 0
for section in readonly:
readonly_size += align_up(section.header['sh_size'], section.header['sh_addralign'])
# Reserve space for readonly before .text
readonly_start = max_alignment(text_addr, 0x1000, 4)
text_addr = align_up(readonly_start + readonly_size, 0x1000)
# Now re-place .text at the updated address
command = [c for c in command if not c.startswith('-Wl,-Ttext=')]
command.append(f'-Wl,-Ttext=0x{text_addr:x}')

ro_addr = readonly_start
for section in readonly:
s_alignment = section.header['sh_addralign']
s_name = section.name

start_addr = align_up(start_addr, s_alignment)
ro_addr = align_up(ro_addr, s_alignment)

command.append(f'-Wl,--section-start={s_name}=0x{start_addr:x}')
command.append(f'-Wl,--section-start={s_name}=0x{ro_addr:x}')

start_addr += section.header['sh_size']
ro_addr += section.header['sh_size']

start_addr = align_up(text_addr + text_size, 0x1000)

start_addr = align_up(start_addr, 0x1000)

Expand Down
204 changes: 200 additions & 4 deletions scripts/xtensa-build-zephyr.py
Original file line number Diff line number Diff line change
Expand Up @@ -412,6 +412,13 @@ def parse_args():
help="Build menuconfig for target")
parser.add_argument("-z", "--zephyrsdk", required=False, action="store_true",
help="Force Build using Zephyr SDK for target")
parser.add_argument("--llvm-clang", required=False, type=pathlib.Path, default=None,
metavar="LLVM_BUILD_DIR",
help="""Use a custom LLVM/Clang build for C/ASM compilation instead of
xt-clang or GCC. Specify the LLVM build directory containing bin/clang.
A wrapper script is auto-generated to handle GCC flag translation,
external assembler usage, and Xtensa target configuration.
Example: --llvm-clang /home/user/llvm-project/build""")

args = parser.parse_args()

Expand Down Expand Up @@ -805,6 +812,166 @@ def rimage_options(platform_dict):
return opts


def generate_clang_wrapper(llvm_build_dir, platform, plat_config, top_dir):
"""Generate a clang wrapper script that translates GCC-only flags and
configures the external assembler for Xtensa targets.

The Zephyr build system passes several GCC-specific flags that clang
does not support. This wrapper filters those out, ensures the external
GCC assembler is used (clang's integrated asm doesn't support the full
Xtensa ISA), and adds the necessary -B/-I paths.

Returns the path to the generated wrapper script.
"""
llvm_build_dir = pathlib.Path(llvm_build_dir).resolve()
clang_bin = llvm_build_dir / "bin" / "clang"
if not clang_bin.exists():
raise FileNotFoundError(f"Clang not found at {clang_bin}")

# Derive the Zephyr SDK cross-compiler name from the board config
# e.g. "intel_adsp/ace30/ptl" -> "xtensa-intel_ace30_ptl_zephyr-elf"
# The Zephyr SDK naming uses the SoC name with underscores
board_parts = plat_config.replace("/", "_")
# Try to find the actual SDK cross-compiler directory
sdk_dir = os.environ.get("ZEPHYR_SDK_INSTALL_DIR", "")
cross_prefix = f"xtensa-{platform_configs[platform].XTENSA_CORE.split('_')[0]}"

# Find the GNU toolchain directory in the Zephyr SDK
gnu_dir = None
if sdk_dir:
sdk_path = pathlib.Path(sdk_dir)
# Look for the xtensa-*_zephyr-elf directory
for d in sdk_path.glob("gnu/xtensa-*_zephyr-elf"):
# Match based on platform name in the directory
if platform in str(d) or board_parts.split("_")[2] in str(d):
gnu_dir = d
break
# Fallback: try exact board-based name
if gnu_dir is None:
# Convert board config to SDK name
# intel_adsp/ace30/ptl -> intel_ace30_ptl
parts = plat_config.split("/")
if len(parts) >= 3:
sdk_name = f"{parts[1]}_{parts[2]}"
else:
sdk_name = parts[-1]
for d in sdk_path.glob(f"gnu/xtensa-*{sdk_name}*"):
gnu_dir = d
break

# Find the HAL SoC directory for core-isa.h
hal_soc_dir = None
modules_hal = top_dir / "modules" / "hal" / "xtensa"
if modules_hal.exists():
parts = plat_config.split("/")
if len(parts) >= 3:
soc_name = f"{parts[0].replace('intel_adsp', 'intel')}_{parts[1]}_{parts[2]}"
else:
soc_name = parts[-1]
for d in modules_hal.glob(f"zephyr/soc/*{parts[1]}*{parts[-1]}*"):
hal_soc_dir = d
break
# Fallback: try matching just the last part
if hal_soc_dir is None:
for d in modules_hal.glob(f"zephyr/soc/*{parts[-1]}*"):
hal_soc_dir = d
break

# Build the wrapper script
wrapper_dir = llvm_build_dir / "bin"
wrapper_path = wrapper_dir / f"clang-sof-wrapper-{platform}.sh"

# Determine target triple from GNU dir name
target_triple = ""
if gnu_dir:
# e.g. "xtensa-intel_ace30_ptl_zephyr-elf" from the dir name
target_triple = gnu_dir.name

# GCC compatibility queries must come before arg processing
gcc_compat = ""
if gnu_dir:
gcc_bin = gnu_dir / "bin" / f"{target_triple}-gcc"
gcc_compat = f"""
# GCC compatibility: forward GCC-specific queries to the real GCC.
# Zephyr's cmake toolchain detection calls -dumpfullversion,
# --print-file-name, --print-multi-directory etc. which clang doesn't support.
case "$1" in
-dumpversion|-dumpfullversion|-dumpmachine|\
--print-file-name=*|--print-multi-directory|--print-multi-lib|\
--print-libgcc-file-name|--print-search-dirs|-print-search-dirs|\
-print-multi-directory)
exec {gcc_bin} "$@"
;;
esac
"""

wrapper_content = f"""#!/bin/bash
# Auto-generated clang wrapper for SOF/{platform} builds
# Generated by xtensa-build-zephyr.py --llvm-clang
# Clang: {clang_bin}
# Target: {target_triple}
{gcc_compat}
ARGS=()
HAS_NO_INTEGRATED_AS=0
HAS_TARGET=0
for arg in "$@"; do
case "$arg" in
-fno-reorder-functions) ;; # GCC only
-fno-defer-pop) ;; # GCC only
--param=*) ;; # GCC only
-fstrict-overflow) ;; # deprecated GCC flag
-mlongcalls) ARGS+=("-mlong-calls") ;; # translate
-fno-integrated-as) HAS_NO_INTEGRATED_AS=1; ARGS+=("$arg") ;;
--target=*) HAS_TARGET=1; ARGS+=("$arg") ;;
*) ARGS+=("$arg") ;;
esac
done

# Always use external assembler (clang integrated asm lacks full Xtensa ISA)
if [ "$HAS_NO_INTEGRATED_AS" -eq 0 ]; then
ARGS+=("-fno-integrated-as")
fi
"""

if target_triple:
wrapper_content += f"""
# Set Xtensa target if not already specified
if [ "$HAS_TARGET" -eq 0 ]; then
ARGS+=("--target={target_triple}")
fi
"""

if hal_soc_dir:
core_isa_dir = hal_soc_dir / "xtensa" / "config"
if core_isa_dir.exists():
wrapper_content += f"""
# core-isa.h lives in the SoC-specific HAL overlay, not alongside core.h
ARGS+=("-I{core_isa_dir}")
"""

if gnu_dir:
sysroot_bin = gnu_dir / target_triple / "bin"
gnu_bin = gnu_dir / "bin"
wrapper_content += f"""
# Paths so clang can find the GCC external assembler and linker
ARGS+=("-B{sysroot_bin}")
ARGS+=("-B{gnu_bin}")
"""

wrapper_content += f"""
# Enable FLIX VLIW instruction bundling
ARGS+=("-Xclang" "-target-feature" "-Xclang" "+flix")

exec {clang_bin} "${{ARGS[@]}}"
"""

with open(wrapper_path, "w") as f:
f.write(wrapper_content)
os.chmod(wrapper_path, 0o755)
print(f"Generated clang wrapper: {wrapper_path}")
return str(wrapper_path)


STAGING_DIR = None
def build_platforms():
global west_top, SOF_TOP
Expand Down Expand Up @@ -854,7 +1021,13 @@ def build_platforms():
_dict = dataclasses.asdict(platform_configs[platform])
platform_dict = { k:v for (k,v) in _dict.items() if _dict[k] is not None }

if args.zephyrsdk:
if args.llvm_clang:
print(f"Using LLVM/Clang from {args.llvm_clang}")
xtensa_tools_root_dir = None
# Use llvm toolchain variant for native Clang support with GCC assembler/linker
platf_build_environ["ZEPHYR_TOOLCHAIN_VARIANT"] = "llvm"
platf_build_environ["LLVM_TOOLCHAIN_PATH"] = str(pathlib.Path(args.llvm_clang).resolve())
elif args.zephyrsdk:
print("Using Zephyr SDK for building")
xtensa_tools_root_dir = None
else:
Expand Down Expand Up @@ -920,16 +1093,39 @@ def build_platforms():
if args.cmake_args:
build_cmd += args.cmake_args

# When using LLVM/Clang, the llvm toolchain variant handles:
# - Compiler detection via LLVM_TOOLCHAIN_PATH
# - GCC assembler/linker integration via CROSS_COMPILE
# - FLIX VLIW bundling via TOOLCHAIN_C_FLAGS
# - LLEXT shared library link wrapper
# No wrapper script or CMAKE_C_COMPILER override needed.
if args.llvm_clang:
# Set XTENSA_CORE_ID so cmake/toolchain/llvm/target.cmake
# selects the correct -mcpu for the LLVM backend.
# Platforms that share an SDK toolchain (e.g. NVL uses PTL's
# assembler) need an explicit CPU override for HiFi5 support.
parts = PLAT_CONFIG.split("/")
if len(parts) >= 3:
core_id = f"{parts[1]}_{parts[2]}" # e.g. "ace40_nvl" -> "intel_ace40"
# Map board-level names to LLVM processor names
core_id_map = {
"ace30_ptl": "intel_ace30_ptl",
"ace40_nvl": "intel_ace40",
"ace40_nvls": "intel_ace40",
}
platf_build_environ["XTENSA_CORE_ID"] = core_id_map.get(core_id, "intel_ace30_ptl")

extra_conf_files = [str(item.resolve(True)) for item in args.overlay]
# The '-d' option is a shortcut for '-o path_to_debug_overlay', we are good
# if both are provided, because it's no harm to merge the same overlay twice.
if args.debug:
extra_conf_files.append(str(pathlib.Path(SOF_TOP, "app", "debug_overlay.conf")))

# The xt-cland Cadence toolchain currently cannot link shared
# The xt-clang Cadence toolchain currently cannot link shared
# libraries for Xtensa. Therefore when it's used we switch to
# building relocatable ELF objects.
if platf_build_environ.get("ZEPHYR_TOOLCHAIN_VARIANT") == 'xt-clang':
# building relocatable ELF objects. We do the same for LLVM/Clang
# to match the xt-clang LLEXT format and avoid GOT/PLT overhead.
if platf_build_environ.get("ZEPHYR_TOOLCHAIN_VARIANT") == 'xt-clang' or args.llvm_clang:
extra_conf_files.append(str(pathlib.Path(SOF_TOP, "app", "llext_relocatable.conf")))

if extra_conf_files:
Expand Down
2 changes: 2 additions & 0 deletions src/audio/dai-zephyr.c
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,7 @@ __cold int dai_set_config(struct dai *dai, struct ipc_config_dai *common_config,
cfg.type = DAI_IMX_MICFIL;
cfg_params = &sof_cfg->micfil;
break;
#if 0
case SOF_DAI_INTEL_UAOL:
cfg.type = DAI_INTEL_UAOL;
cfg.channels = common_config->gtw_fmt->channels_count;
Expand All @@ -204,6 +205,7 @@ __cold int dai_set_config(struct dai *dai, struct ipc_config_dai *common_config,
cfg_params = spec_config;
dai_set_link_hda_config(&cfg.link_config, common_config, spec_config);
break;
#endif
default:
return -EINVAL;
}
Expand Down
2 changes: 2 additions & 0 deletions src/lib/dai.c
Original file line number Diff line number Diff line change
Expand Up @@ -210,8 +210,10 @@ static int sof_dai_type_to_zephyr(uint32_t type)
return DAI_INTEL_HDA;
case SOF_DAI_INTEL_ALH:
return DAI_INTEL_ALH;
#if 0
case SOF_DAI_INTEL_UAOL:
return DAI_INTEL_UAOL;
#endif
case SOF_DAI_IMX_SAI:
return DAI_IMX_SAI;
case SOF_DAI_IMX_ESAI:
Expand Down
Loading