#!/usr/bin/env bash # SPDX-License-Identifier: (GPL-2.0-only OR MIT) # Copyright (C) 2026 Amlogic, Inc. All rights reserved ################################################################################ # Amlbian ISP Compilation Module # # Purpose: ISP driver compilation with Hook support and aml-comp integration # Provides: ISP driver compilation for S6 and A9 platforms ################################################################################ set -e # Get script directory And Set env SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" AMLBIAN_DIR="$(dirname "$(dirname "${SCRIPT_DIR}")")" BASE_DIR="$(dirname "$(dirname "${AMLBIAN_DIR}")")" # Determine chipset based on BOARD variable if [[ "${BOARD}" == *"a9"* ]]; then ISP_CHIPSET="a9" elif [[ "${BOARD}" == *"s6"* ]]; then ISP_CHIPSET="s6" else ISP_CHIPSET="${ISP_CHIPSET:-s6}" fi # Source common functions if [[ -f "${AMLBIAN_DIR}/lib/function-common.sh" ]]; then source "${AMLBIAN_DIR}/lib/function-common.sh" fi # Source libisp build script if it exists LIBISP_SCRIPT="${SCRIPT_DIR}/build-libisp.sh" if [[ -f "${LIBISP_SCRIPT}" ]]; then display_alert "Loading libisp build script" "${LIBISP_SCRIPT}" "info" source "${LIBISP_SCRIPT}" else display_alert "Libisp build script not found" "${LIBISP_SCRIPT}" "warn" fi # ============================================================================== # Shared Helper Functions # ============================================================================== # ------------------------------------------------------------------------------ # Step 1: Version and Package Information Definition # ------------------------------------------------------------------------------ # Initialize common package metadata for ISP driver function _isp_init_package_info() { local chipset="$1" PKG_MAINTAINER="Armbian Build " PKG_DESCRIPTION="Amlogic ISP driver for ${chipset} platform" PKG_NAME="aml-isp" PKG_VERSION="6.12" PKG_ARCH="${ARCH:-arm64}" CROSS_COMPILE="${CROSS_COMPILE:-aarch64-linux-gnu-}" # Get kernel version for packaging local KERNEL_VERSION=$(make -s -C "${BASE_DIR}/aml-comp/kernel/aml-6.12/build" kernelrelease 2>/dev/null || true) KERNEL_VERSION="${KERNEL_VERSION:-unknown-$(date +%Y%m%d)}" # Source directory SRC_DIR="${BASE_DIR}/aml-comp/hardware/amlogic/arm-isp-6.12" # Check if source exists if [[ ! -d "${SRC_DIR}" ]]; then display_alert "COMPILE-ISP" "ISP driver source code not found. Expected at: ${SRC_DIR}" "err" exit 1 fi display_alert "COMPILE-ISP" "Building Amlogic ISP driver for ${chipset}" "info" display_alert "COMPILE-ISP" "Version: ${PKG_VERSION}, Architecture: ${PKG_ARCH}" "info" display_alert "COMPILE-ISP" "Cross compilation toolchain: ${CROSS_COMPILE}" "info" display_alert "COMPILE-ISP" "Building for kernel: ${KERNEL_VERSION}" "info" # Return values _ISP_CHIPSET="${chipset}" _ISP_PKG_NAME="${PKG_NAME}" _ISP_PKG_VERSION="${PKG_VERSION}" _ISP_ARCH="${PKG_ARCH}" _ISP_KERNEL_VERSION="${KERNEL_VERSION}" _ISP_SRC_DIR="${SRC_DIR}" _ISP_CROSS_COMPILE="${CROSS_COMPILE}" } # ------------------------------------------------------------------------------ # Step 2: Build Directory Structure Setup # ------------------------------------------------------------------------------ # Create layered build directory structure # Parameters: # $1 - base name (e.g. "${PKG_NAME}_${PKG_VERSION}_${PKG_ARCH}") # Sets: TMP_DIR, BASE_BUILD_DIR, SOURCE_DIR, BUILD_DIR, INSTALL_DIR, PATCH_DIR, # DEB_PACKAGE_DIR, DEBIAN_DIR function _isp_create_build_dirs() { local base_name="$1" TMP_DIR="${AMLBIAN_DIR}/.tmp" mkdir -p "${TMP_DIR}" # 基础构建目录 BASE_BUILD_DIR="${TMP_DIR}/${base_name}" rm -rf ${BASE_BUILD_DIR} # 分层目录 SOURCE_DIR="${BASE_BUILD_DIR}/source" # 源码目录 BUILD_DIR="${BASE_BUILD_DIR}/build" # 编译目录 INSTALL_DIR="${BASE_BUILD_DIR}/install" # 安装目录 PATCH_DIR="${BASE_BUILD_DIR}/patch" # 补丁目录 # 创建所有目录 mkdir -p "${SOURCE_DIR}" mkdir -p "${BUILD_DIR}" mkdir -p "${INSTALL_DIR}" mkdir -p "${PATCH_DIR}" # 在BUILD_DIR下创建deb/包名目录 DEB_PACKAGE_DIR="${BUILD_DIR}/deb/${base_name}" mkdir -p "${DEB_PACKAGE_DIR}" # 安装目录的子目录 DEBIAN_DIR="${INSTALL_DIR}/DEBIAN" mkdir -p "${DEBIAN_DIR}" # 模块安装目录(根据bb文件,不在标准模块目录) MODULE_DIR="${INSTALL_DIR}/lib/modules/isp/" mkdir -p "${MODULE_DIR}" # 创建编译日志文件 BUILD_LOG="${BUILD_DIR}/build.log" echo "Build log for ${base_name}" > "${BUILD_LOG}" echo "Started at: $(date)" >> "${BUILD_LOG}" echo "=========================================" >> "${BUILD_LOG}" } # Create standard install subdirectories for ISP driver function _isp_create_install_dirs() { mkdir -p "${INSTALL_DIR}/lib/modules/isp" } # Display build directory info # Parameters: # $1 - log prefix function _isp_display_build_info() { local log_prefix="$1" display_alert "${log_prefix} Source dir: ${SOURCE_DIR}" "info" display_alert "${log_prefix} Build dir: ${BUILD_DIR}" "info" display_alert "${log_prefix} Install dir: ${INSTALL_DIR}" "info" display_alert "${log_prefix} Patch dir: ${PATCH_DIR}" "info" display_alert "${log_prefix} Deb package dir: ${DEB_PACKAGE_DIR}" "info" display_alert "${log_prefix} Build log: ${BUILD_LOG}" "info" } # ------------------------------------------------------------------------------ # Step 3: Debian Packaging Scripts Creation # ------------------------------------------------------------------------------ # Create Debian control file # Parameters: # $1 - package name # $2 - package version # $3 - package architecture # $4 - maintainer # $5 - description # $6 - dependencies (optional) # $7 - conflicts (optional) # $8 - provides (optional) # $9 - section (optional, default "kernel") function _isp_create_control_file() { local pkg_name="$1" local pkg_version="$2" local pkg_arch="$3" local maintainer="$4" local description="$5" local depends="${6:-}" local conflicts="${7:-}" local provides="${8:-}" local section="${9:-kernel}" display_alert "COMPILE-ISP Creating control file DEBIAN/control" "info" cat > "${DEBIAN_DIR}/control" < "${DEBIAN_DIR}/postinst" << EOF #!/bin/bash set -e # Run depmod to update module dependencies if [ -d /lib/modules ]; then for kernel in /lib/modules/*; do if [ -d "\${kernel}" ]; then depmod -a "${_ISP_KERNEL_VERSION}" 2>/dev/null || true fi done fi echo "Amlogic ISP driver installed successfully." EOF chmod 0755 "${DEBIAN_DIR}/postinst" } # Create prerm script for ISP driver function _isp_create_prerm() { display_alert "COMPILE-ISP Creating pre-removal script DEBIAN/prerm" "info" cat > "${DEBIAN_DIR}/prerm" << 'EOF' #!/bin/bash set -e echo "Removing Amlogic ISP driver..." EOF chmod 0755 "${DEBIAN_DIR}/prerm" } # ------------------------------------------------------------------------------ # Step 4: Source File Copying # ------------------------------------------------------------------------------ # Copy ISP source files to source directory function _isp_copy_source_files() { display_alert "COMPILE-ISP Copying source files to source directory" "info" echo "Copying source files to source directory at $(date)" >> "${BUILD_LOG}" cp -r "${_ISP_SRC_DIR}/"* "${SOURCE_DIR}/" 2>&1 >> "${BUILD_LOG}" # 更新SRC_DIR为SOURCE_DIR,使用复制的源码 _ISP_SRC_DIR="${SOURCE_DIR}" # Set up environment variables for build export ARCH="${_ISP_ARCH}" export CROSS_COMPILE="${_ISP_CROSS_COMPILE}" export KERNELDIR="${STAGING_KERNEL_DIR:-${BASE_DIR}/aml-comp/kernel/aml-6.12}" export STAGING_KERNEL_DIR="${KERNELDIR}" export EXT_DRIVER_DIR="common_drivers/drivers" export KOUTPUT_COMMON_DRV_DIR="${KERNELDIR}/${EXT_DRIVER_DIR}" # Check for kernel headers if [[ ! -d "${KERNELDIR}" ]]; then display_alert "COMPILE-ISP" "Kernel headers directory not found at: ${KERNELDIR}" "err" exit 1 fi # Change to source directory cd "${_ISP_SRC_DIR}" } # ------------------------------------------------------------------------------ # Step 5: Kernel Module Building (Platform Specific) # ------------------------------------------------------------------------------ # Build S6 ISP driver function _isp_build_s6() { local SRC_DIR="${_ISP_SRC_DIR}" local KERNELDIR="${KERNELDIR}" local MODULE_DIR="${MODULE_DIR}" local BUILD_DIR="${BUILD_DIR}" # Check for CSI camera directory (S6 specific) if [[ ! -d "${SRC_DIR}/csi_cam" ]]; then display_alert "COMPILE-ISP" "CSI camera source not found at: ${SRC_DIR}/csi_cam" "err" exit 1 fi display_alert "COMPILE-ISP" "Building CSI camera driver for S6" "info" # Create symbolic link ln -sf "${SRC_DIR}/csi_cam" "${KERNELDIR}/${EXT_DRIVER_DIR}/" # Build kernel module display_alert "COMPILE-ISP" "Compiling kernel module with parameters:" "info" display_alert "COMPILE-ISP" " ARCH=${_ISP_ARCH}" "info" display_alert "COMPILE-ISP" " CROSS_COMPILE=${_ISP_CROSS_COMPILE}" "info" display_alert "COMPILE-ISP" " KERNEL_SRC=${KERNELDIR}" "info" make -C "${KERNELDIR}/build" \ M="${SRC_DIR}/csi_cam/driver/" \ KERNEL_SRC="${KERNELDIR}" \ ARCH="${_ISP_ARCH}" \ CROSS_COMPILE="${_ISP_CROSS_COMPILE}" # Remove symbolic link rm "${KERNELDIR}/${EXT_DRIVER_DIR}/csi_cam" # Check if module was built successfully if [[ -f "${SRC_DIR}/csi_cam/driver/amlsens/amlsens.ko" ]]; then display_alert "COMPILE-ISP" "ISP module built successfully: amlsens.ko" "info" # 在BUILD_DIR中保存编译结果(备份) BUILD_MODULE_DIR="${BUILD_DIR}/modules" mkdir -p "${BUILD_MODULE_DIR}" display_alert "COMPILE-ISP" "Saving build result to build directory: ${BUILD_MODULE_DIR}" "info" cp -f "${SRC_DIR}/csi_cam/driver/amlsens/amlsens.ko" "${BUILD_MODULE_DIR}/" # Install module to install directory display_alert "COMPILE-ISP" "Installing module to install directory: ${MODULE_DIR}" "info" install -m 0666 "${SRC_DIR}/csi_cam/driver/amlsens/amlsens.ko" "${MODULE_DIR}/" # Clean build directory display_alert "COMPILE-ISP" "Cleaning build directory" "info" make -C "${KERNELDIR}/build" \ M="${SRC_DIR}/csi_cam/driver/" \ KERNEL_SRC="${KERNELDIR}" \ ARCH="${_ISP_ARCH}" \ CROSS_COMPILE="${_ISP_CROSS_COMPILE}" \ clean else display_alert "COMPILE-ISP" "ISP module build failed. Could not find amlsens.ko" "err" exit 1 fi } function _isp_drv_src_obj() { local dir="$1" if [ -z "$dir" ] || [ ! -d "$dir" ]; then echo "" return 1 fi find "$dir" -maxdepth 2 -name "*.c" \ -printf "%P\n" \ | sed 's/\.c$/.o/' \ | tr '\n' ' ' \ | sed 's/[[:space:]]*$//' } # Build A9 ISP driver function _isp_build_a9() { local SRC_DIR="${_ISP_SRC_DIR}" local KERNELDIR="${KERNELDIR}" local MODULE_DIR="${MODULE_DIR}" local BUILD_DIR="${BUILD_DIR}" # Check for A9 ISP directory if [[ ! -d "${SRC_DIR}/aml_isp5" ]]; then display_alert "COMPILE-ISP" "A9 ISP source not found at: ${SRC_DIR}/aml_isp5" "warn" display_alert "COMPILE-ISP" "Skipping A9 build (source not available)" "warn" display_alert "COMPILE-ISP" "A9 build skipped - source not available" "info" return 0 fi display_alert "COMPILE-ISP" "Building A9 ISP driver" "info" # Create symbolic link ln -sf "${SRC_DIR}/aml_isp5" "${KERNELDIR}/${EXT_DRIVER_DIR}/" # Build kernel modules (multiple modules for A9) display_alert "COMPILE-ISP" "Compiling A9 ISP kernel modules" "info" display_alert "COMPILE-ISP" "KERNEL_SRC=${KERNELDIR}" "info" # Build aml-isp5-adap.ko display_alert "COMPILE-ISP" "Building aml-isp5-adap module" "info" DRV_SRC_OBJ=$(_isp_drv_src_obj "${SRC_DIR}/aml_isp5/driver/adap") make -C "${KERNELDIR}/build" \ M="${SRC_DIR}/aml_isp5/driver/adap" \ KERNEL_SRC="${KERNELDIR}" \ ARCH="${_ISP_ARCH}" \ DRV_SRC_OBJ="${DRV_SRC_OBJ}" \ CROSS_COMPILE="${_ISP_CROSS_COMPILE}" # Build aml-isp5-csi.ko display_alert "COMPILE-ISP" "Building aml-isp5-csi module" "info" DRV_SRC_OBJ=$(_isp_drv_src_obj "${SRC_DIR}/aml_isp5/driver/csi2") make -C "${KERNELDIR}/build" \ M="${SRC_DIR}/aml_isp5/driver/csi2" \ KERNEL_SRC="${KERNELDIR}" \ ARCH="${_ISP_ARCH}" \ DRV_SRC_OBJ="${DRV_SRC_OBJ}" \ CROSS_COMPILE="${_ISP_CROSS_COMPILE}" # Build aml-isp5.ko display_alert "COMPILE-ISP" "Building aml-isp5 module" "info" DRV_SRC_OBJ=$(_isp_drv_src_obj "${SRC_DIR}/aml_isp5/driver/isp5") make -C "${KERNELDIR}/build" \ M="${SRC_DIR}/aml_isp5/driver/isp5" \ KERNEL_SRC="${KERNELDIR}" \ ARCH="${_ISP_ARCH}" \ DRV_SRC_OBJ="${DRV_SRC_OBJ}" \ CROSS_COMPILE="${_ISP_CROSS_COMPILE}" # Build aml-imx290.ko display_alert "COMPILE-ISP" "Building sensor module" "info" DRV_SRC_OBJ=$(_isp_drv_src_obj "${SRC_DIR}/aml_isp5/driver/sensor") make -C "${KERNELDIR}/build" \ M="${SRC_DIR}/aml_isp5/driver/sensor" \ KERNEL_SRC="${KERNELDIR}" \ ARCH="${_ISP_ARCH}" \ DRV_SRC_OBJ="${DRV_SRC_OBJ}" \ CROSS_COMPILE="${_ISP_CROSS_COMPILE}" # Remove symbolic link rm "${KERNELDIR}/${EXT_DRIVER_DIR}/aml_isp5" # Check if modules were built successfully if [[ -f "${SRC_DIR}/aml_isp5/driver/adap/aml-isp5-adap.ko" ]]; then # Install module install -m 0666 "${SRC_DIR}/aml_isp5/driver/adap/aml-isp5-adap.ko" "${MODULE_DIR}/" fi if [[ -f "${SRC_DIR}/aml_isp5/driver/csi2/aml-isp5-csi.ko" ]]; then # Install module install -m 0666 "${SRC_DIR}/aml_isp5/driver/csi2/aml-isp5-csi.ko" "${MODULE_DIR}/" fi if [[ -f "${SRC_DIR}/aml_isp5/driver/isp5/aml-isp5.ko" ]]; then # Install module install -m 0666 "${SRC_DIR}/aml_isp5/driver/isp5/aml-isp5.ko" "${MODULE_DIR}/" fi if [[ -f "${SRC_DIR}/aml_isp5/driver/sensor/aml-imx290.ko" ]]; then # Install module install -m 0666 "${SRC_DIR}/aml_isp5/driver/sensor/aml-imx290.ko" "${MODULE_DIR}/" fi if [[ -f "${SRC_DIR}/aml_isp5/driver/sensor/aml-imx415.ko" ]]; then # Install module install -m 0666 "${SRC_DIR}/aml_isp5/driver/sensor/aml-imx415.ko" "${MODULE_DIR}/" fi # Clean each module directory make -C "${KERNELDIR}/build" \ M="${SRC_DIR}/aml_isp5/driver/adap" \ KERNEL_SRC="${KERNELDIR}" \ ARCH="${_ISP_ARCH}" \ CROSS_COMPILE="${_ISP_CROSS_COMPILE}" \ clean make -C "${KERNELDIR}/build" \ M="${SRC_DIR}/aml_isp5/driver/csi2" \ KERNEL_SRC="${KERNELDIR}" \ ARCH="${_ISP_ARCH}" \ CROSS_COMPILE="${_ISP_CROSS_COMPILE}" \ clean make -C "${KERNELDIR}/build" \ M="${SRC_DIR}/aml_isp5/driver/isp5" \ KERNEL_SRC="${KERNELDIR}" \ ARCH="${_ISP_ARCH}" \ CROSS_COMPILE="${_ISP_CROSS_COMPILE}" \ clean make -C "${KERNELDIR}/build" \ M="${SRC_DIR}/aml_isp5/driver/sensor" \ KERNEL_SRC="${KERNELDIR}" \ ARCH="${_ISP_ARCH}" \ CROSS_COMPILE="${_ISP_CROSS_COMPILE}" \ clean } # ------------------------------------------------------------------------------ # Step 6: Debian Package Building # ------------------------------------------------------------------------------ # Build Debian package from install directory # Parameters: # $1 - log prefix (e.g. "COMPILE-ISP") # $2 - output deb filename (without path) # Sets: OUTPUT_DEB function _isp_build_deb_package() { local log_prefix="$1" local output_deb_name="$2" # 将install目录内容拷贝到deb目录 display_alert "Copying install directory to deb package directory ${log_prefix}" "info" echo "Copying install directory to deb package directory at $(date)" >> "${BUILD_LOG}" cp -r "${INSTALL_DIR}/"* "${DEB_PACKAGE_DIR}/" 2>&1 >> "${BUILD_LOG}" # 基于deb目录打包 display_alert "Building Debian package from deb directory ${log_prefix}" "info" echo "Building Debian package at $(date)" >> "${BUILD_LOG}" dpkg-deb --build "${DEB_PACKAGE_DIR}" 2>&1 >> "${BUILD_LOG}" if [[ $? -ne 0 ]]; then display_alert "${log_prefix} Package build failed" "error" exit 1 fi # Move to output directory OUTPUT_DEB="${SRC}/output/${output_deb_name}" mkdir -p "$(dirname "${OUTPUT_DEB}")" mv "${DEB_PACKAGE_DIR}.deb" "${OUTPUT_DEB}" display_alert "${log_prefix} Package built successfully ${output_deb_name}" "info" display_alert "${log_prefix} Build directory preserved ${BASE_BUILD_DIR}" "info" } # ============================================================================== # Main Build Functions (Entry Points - DO NOT RENAME) # ============================================================================== # ------------------------------------------------------------------------------ # ISP Driver Build for specific chipset # Entry point: amlbian_build_isp # ------------------------------------------------------------------------------ function amlbian_build_isp_driver() { if ! is_unit_enabled "isp"; then echo "[SKIP] >> Isp disable in BUILD_UNITS" return fi local chipset="${ISP_CHIPSET}" # ---- Step 1: Version and Package Information ---- _isp_init_package_info "${chipset}" # amlbian_checkout_toolchain # ---- Step 2: Build Directory Setup ---- _isp_create_build_dirs "${_ISP_PKG_NAME}_${_ISP_PKG_VERSION}_${_ISP_ARCH}" _isp_create_install_dirs # Display info display_alert "COMPILE-ISP Building ISP driver package version ${_ISP_PKG_VERSION} for ${_ISP_ARCH} (${chipset})" "info" _isp_display_build_info "COMPILE-ISP" # ---- Step 3: Debian Packaging Scripts ---- _isp_create_control_file \ "${_ISP_PKG_NAME}" "${_ISP_PKG_VERSION}" "${_ISP_ARCH}" "${PKG_MAINTAINER}" \ "${PKG_DESCRIPTION}" "" "" "" "kernel" _isp_create_postinst _isp_create_prerm # ---- Step 4: Copy Source Files ---- _isp_copy_source_files # ---- Step 5: Build Kernel Modules (Platform Specific) ---- if [[ "${chipset}" == "s6" ]]; then _isp_build_s6 elif [[ "${chipset}" == "a9" ]]; then _isp_build_a9 else display_alert "COMPILE-ISP" "Unsupported chipset: ${chipset}" "err" exit 1 fi # ---- Step 6: Build Debian Package ---- _isp_build_deb_package "COMPILE-ISP" "${_ISP_PKG_NAME}_${_ISP_PKG_VERSION}_${_ISP_ARCH}.deb" display_alert "COMPILE-ISP Build directories preserved:" "info" display_alert "COMPILE-ISP Source: ${SOURCE_DIR}" "info" display_alert "COMPILE-ISP Build: ${BUILD_DIR}" "info" display_alert "COMPILE-ISP Install: ${INSTALL_DIR}" "info" display_alert "COMPILE-ISP ISP driver build for ${chipset} completed successfully" "info" return 0 } function amlbian_build_isp() { if ! is_unit_enabled "isp"; then echo "[SKIP] >> Gpu disable in BUILD_UNITS" return fi amlbian_build_isp_driver amlbian_build_libisp } # Main entry point display_alert "AMLbian ISP Build Script" "Version: ${_ISP_PKG_VERSION:-6.12} CHIPSET: ${ISP_CHIPSET}, ARCH: ${_ISP_ARCH:-arm64}" "info" amlbian_build_isp display_alert "AMLOGIC: ISP build completed" "${OUTPUT_DEB}" "info"