#
# SPDX-License-Identifier: GPL-2.0
#
# Copyright (c) 2013-2023 Igor Pecovnik, igor@armbian.com
#
# This file is a part of the Armbian Build Framework
# https://github.com/armbian/build/
#
declare -g LINUXFAMILY=bcm2711
declare -g ARCH=arm64
declare -g UEFI_FS_LABEL="RPICFG" # Windows/Mac users will see this if they mount the SD card. Configurable, but should be uppercase always
declare -g CPUMIN=500000
declare -g CPUMAX=2900000
declare -g GOVERNOR=ondemand
declare -g INSTALL_ARMBIAN_FIRMWARE=no
declare -g UEFISIZE=256                      # in MiB. Not really UEFI, but partition layout is the same.
declare -g BOOTSIZE=0                        # No separate /boot; instead we have /boot/firmware fat32 partition
declare -g BOOTCONFIG=none                   # We are currently not using U-boot for Raspberry Pi boards
declare -g UEFI_MOUNT_POINT="/boot/firmware" # mount uefi partition at /boot/firmware
declare -g LINUXCONFIG="linux-${LINUXFAMILY}-${BRANCH}"

case "${BRANCH}" in

	legacy)
		declare -g KERNELSOURCE='https://github.com/raspberrypi/linux'
		declare -g KERNEL_MAJOR_MINOR="6.1" # Major and minor versions of this kernel. For mainline caching.
		declare -g KERNELBRANCH="branch:rpi-6.1.y"
		;;

	current)
		declare -g KERNELSOURCE='https://github.com/raspberrypi/linux'
		declare -g KERNEL_MAJOR_MINOR="6.6" # Major and minor versions of this kernel. For mainline caching.
		declare -g KERNELBRANCH="branch:rpi-6.6.y"
		;;

	edge)
		declare -g EXTRAWIFI="no"
		declare -g KERNELSOURCE='https://github.com/raspberrypi/linux'
		declare -g KERNEL_MAJOR_MINOR="6.7" # Major and minor versions of this kernel. For mainline caching.
		declare -g KERNELBRANCH="branch:rpi-6.7.y"
		;;
esac

function post_family_config__mark_bsp_as_firmware_containing() {
	if [[ "${SKIP_ARMBIAN_REPO}" != "yes" ]]; then
		declare -g -r RASPI_FIRMWARE_DIR="/usr/lib/linux-firmware-raspi"
		display_alert "SKIP_ARMBIAN_REPO is set to" "${SKIP_ARMBIAN_REPO} - not adding rpi firmware to bsp" "info"
		return 0
	fi
	display_alert "Marking BSP name as firmware-containing" "bcm2711" "info"
	declare -g EXTRA_BSP_NAME="${EXTRA_BSP_NAME}-raspifw" # Unique bsp name.
	declare -g -r RASPI_FIRMWARE_DIR="/usr/lib/armbian-firmware-raspi"
}

function post_family_config__add_rpi_packages() {
	display_alert "Preparing bcm2711" "${RELEASE}" "info"
	unset BOOTSOURCE                                # To try and convince lib/ to not build or install u-boot.
	declare -g SERIALCON="${RASPI_SERIALCON:-tty1}" # HDMI etc, not serial. most people don't have UART on rpi

	# those older releases are not working as we don't provide binaries for libraspberrypi-bin
	local not_usable_releases="bullseye|buster|focal"

	# if RELEASE is set, make sure it is one of the ones we support.
	if [[ -n "${RELEASE}" ]]; then
		if [[ "$RELEASE" =~ ^(${not_usable_releases})$ ]]; then
			exit_with_target_not_supported_error "Can't use release '${RELEASE}' for ${BOARD}. Invalid releases: '${not_usable_releases}'" "'${RELEASE}' not supported"
		fi
	fi
}

# Make sure we don't try to install or remove /boot/dtb-$kvers directory
function post_family_tweaks_bsp__add_hooks_to_move_kernel_initrd_and_dtb() {
	run_host_command_logged mkdir -p "${destination}"/etc/kernel/post{inst,rm}.d

	# Copy new files to /boot/firmware; RASPI_FIRMWARE_DIR determines where they come from (at build time only!)
	display_alert "Setting up z50-raspi-firmware" "bcm2711 - from ${RASPI_FIRMWARE_DIR}" "info"
	run_host_command_logged cat <<- z50-raspi-firmware > "${destination}"/etc/kernel/postinst.d/z50-raspi-firmware
		#!/bin/bash -e

		# We are using same name as the debian's raspi-firmware script, but we
		# only need to run this script on ubuntu. Debian's package has a postinst
		# section capable of copying files, but Ubuntu relies on flash-kernel
		[[ -d ${RASPI_FIRMWARE_DIR} ]] || exit 0

		# Play nice when run under debconf.
		exec </dev/null >&2

		# Ensure the target directory exists.
		mkdir -p /boot/firmware

		for file in ${RASPI_FIRMWARE_DIR}/*
		do
			file=\$( basename "\$file" )
			cp "${RASPI_FIRMWARE_DIR}/\$file" "/boot/firmware/\$file"
			sync -f "/boot/firmware/\$file" || true
		done

		exit 0
	z50-raspi-firmware

	# Copy new files to /boot/firmware
	run_host_command_logged cat <<- 'zzz-copy-new-files' > "${destination}"/etc/kernel/postinst.d/zzz-copy-new-files
		#!/bin/bash -e

		# Play nice when run under debconf.
		exec </dev/null >&2

		abi=$1
		target=/boot/firmware
		dtb_dir=/usr/lib/linux-image-$abi/

		cp /boot/vmlinuz-${abi} ${target}/vmlinuz
		cp ${dtb_dir}/broadcom/*.dtb ${target}/
		cp -r ${dtb_dir}/overlays ${target}/
		sync -f ${target}/vmlinuz || true

		exit 0
	zzz-copy-new-files

	# Remove old files from /boot/firmware
	run_host_command_logged cat <<- 'zzz-remove-old-files' > "${destination}"/etc/kernel/postrm.d/zzz-remove-old-files
		#!/bin/bash -e

		# Play nice when run under debconf.
		exec </dev/null >&2

		abi=$1
		target=/boot/firmware

		rm ${target}/vmlinuz
		rm ${target}/*.dtb
		rm -r ${target}/overlays

		exit 0
	zzz-remove-old-files

	run_host_command_logged chmod a+rx "${destination}"/etc/kernel/postinst.d/z50-raspi-firmware
	run_host_command_logged chmod a+rx "${destination}"/etc/kernel/postinst.d/zzz-copy-new-files
	run_host_command_logged chmod a+rx "${destination}"/etc/kernel/postrm.d/zzz-remove-old-files

	run_host_command_logged rm "${destination}"/etc/initramfs/post-update.d/99-uboot

	# copy new initramfs file
	run_host_command_logged cat <<- 'zzz-update-initramfs' > "${destination}"/etc/initramfs/post-update.d/zzz-update-initramfs
		#!/bin/bash -e

		# Play nice when run under debconf.
		exec </dev/null >&2

		abi=$1
		initrd_file=$2
		target=/boot/firmware

		cp ${initrd_file} ${target}/initrd.img
		sync -f ${target}/initrd.img || true

		exit 0
	zzz-update-initramfs

	run_host_command_logged chmod a+x "${destination}"/etc/initramfs/post-update.d/zzz-update-initramfs
}

function post_family_tweaks_bsp__add_x11_config() {
	display_alert "rpi5b" "Adding X11 configuration" "info"
	run_host_command_logged mkdir -p "${destination}"/etc/X11/xorg.conf.d/
	run_host_command_logged cat <<- '99-vc4.conf' > "${destination}"/etc/X11/xorg.conf.d/99-vc4.conf
		Section "OutputClass"
		  Identifier "vc4"
		  MatchDriver "vc4"
		  Driver "modesetting"
		  Option "PrimaryGPU" "true"
		EndSection
	99-vc4.conf
}

function post_family_tweaks__populate_boot_firmware_directory() {
	# We install kernel before we install bsp package. This means hooks present in bsp are not executed.
	# Running the hooks from bsp to populate /boot/firmware directory.
	display_alert "Populating /boot/firmware directory" "bcm2711" "info"
	modules_dir="$(find "${SDCARD}/lib/modules"/ -maxdepth 1 -type d -name "*${IMAGE_INSTALLED_KERNEL_VERSION}*")"
	kern_ver="$(basename "$modules_dir")"
	run_host_command_logged mkdir -p "${SDCARD}"/boot/firmware
	chroot_sdcard /etc/kernel/postinst.d/z50-raspi-firmware "${kern_ver}"
	chroot_sdcard /etc/kernel/postinst.d/zzz-copy-new-files "${kern_ver}"
	display_alert "Populating /boot/firmware directory" "bcm2711 - done" "info"
}

function post_family_tweaks_bsp__rpi_firmware_in_bsp() {
	if [[ "${SKIP_ARMBIAN_REPO}" != "yes" ]]; then
		display_alert "SKIP_ARMBIAN_REPO is set to" "${SKIP_ARMBIAN_REPO} - not adding rpi firmware to bsp" "info"
		return 0
	fi

	display_alert "Using in-BSP firmware files for" "bcm2711::${BOARD}" "info"
	declare firmware_commit_sha1="9cafcd85f8aed1ec0c0f609b98af591fae367ba2" # Keep this inside this file, so hashing detect changes and bumps the version of the bsp package

	declare destdir="${destination}/usr/lib/armbian-firmware-raspi"
	run_host_command_logged mkdir -p "${destdir}"
	# Get the firmware files from the Debian git repo
	fetch_from_repo "https://salsa.debian.org/debian/raspi-firmware.git" "debian-raspi-firmware" "commit:${firmware_commit_sha1}" "yes"
	declare srcdir="${SRC}/cache/sources/debian-raspi-firmware/${firmware_commit_sha1}"
	# Copy the files from the git repo boot dir to the destdir
	run_host_command_logged cp -prv "${srcdir}/boot/"* "${destdir}"/
}

function pre_install_distribution_specific__add_rpi_packages() {
	# If we're skipping the Armbian repo, and on Debian, we'll install Debian version of Wifi/BT-related firmware.
	if [[ "${SKIP_ARMBIAN_REPO}" == "yes" ]]; then
		display_alert "SKIP_ARMBIAN_REPO is set to" "${SKIP_ARMBIAN_REPO} - no Armbian repo packages will be installed" "info"
		if [[ "${DISTRIBUTION}" == "Debian" ]]; then
			display_alert "Installing Debian-sourced Wifi/BT firmware packages" "Debian::bcm2711::${BOARD}" "info"
			do_with_retries 3 chroot_sdcard_apt_get_update
			chroot_sdcard_apt_get_install firmware-brcm80211 firmware-misc-nonfree bluez-firmware bluetooth
		fi
		if [[ "${DISTRIBUTION}" == "Ubuntu" ]]; then
			display_alert "Installing Ubuntu-sourced Wifi/BT firmware packages plus raspi-config and raspi-eeprom" "Ubuntu::bcm2711::${BOARD}" "info"
			do_with_retries 3 chroot_sdcard_apt_get_update
			chroot_sdcard_apt_get_install rpi-eeprom pi-bluetooth busybox raspi-config bluetooth
		fi
	else
		# we store Rpi firmware packages in our repository
		# https://github.com/armbian/os/wiki/Import-3rd-party-packages
		display_alert "Enable Armbian repository to fetch Rpi packages" "" "info"
		mv "${SDCARD}"/etc/apt/sources.list.d/armbian.list.disabled "${SDCARD}"/etc/apt/sources.list.d/armbian.list
		do_with_retries 3 chroot_sdcard_apt_get_update
		chroot_sdcard_apt_get_install rpi-eeprom linux-firmware-raspi pi-bluetooth libraspberrypi-bin busybox raspi-config
		## disable armbian repository
		mv "${SDCARD}"/etc/apt/sources.list.d/armbian.list "${SDCARD}"/etc/apt/sources.list.d/armbian.list.disabled
	fi
}

# Our default paritioning system is leaving esp on. Rpi3 is the only board that have issues with this.
# Removing the ESP flag from the boot partition should allow the image to boot on both the RPi3 and RPi4.
function pre_umount_final_image__remove_esp() {
	display_alert "Removing ESP flag from FAT partition" "rpi4 / rpi3" "info"
	run_host_command_logged parted -s "${LOOP}" set 1 esp off
}

# write the default config.txt config
function pre_umount_final_image__write_raspi_config() {
	cat <<- EOD > "${MOUNT}"/boot/firmware/config.txt
		# For more options and information see
		# http://rptl.io/configtxt
		# Some settings may impact device functionality. See link above for details

		# Uncomment some or all of these to enable the optional hardware interfaces
		#dtparam=i2c_arm=on
		#dtparam=i2s=on
		#dtparam=spi=on

		# Enable audio (loads snd_bcm2835)
		dtparam=audio=on

		# Additional overlays and parameters are documented
		# /boot/firmware/overlays/README

		# Automatically load overlays for detected cameras
		camera_auto_detect=1

		# Automatically load overlays for detected DSI displays
		display_auto_detect=1

		# Automatically load initramfs files, if found
		auto_initramfs=1

		# Enable DRM VC4 V3D driver
		dtoverlay=vc4-kms-v3d
		max_framebuffers=2

		# Don't have the firmware create an initial video= setting in cmdline.txt.
		# Use the kernel's default instead.
		disable_fw_kms_setup=1

		# Disable compensation for displays with overscan
		disable_overscan=1

		# Run as fast as firmware / board allows
		arm_boost=1

		[cm4]
		# Enable host mode on the 2711 built-in XHCI USB controller.
		# This line should be removed if the legacy DWC2 controller is required
		# (e.g. for USB device mode) or if USB support is not required.
		otg_mode=1

		[all]
		kernel=vmlinuz
		initramfs initrd.img followkernel
		arm_64bit=1
	EOD
}

function pre_umount_final_image__write_raspi_cmdline() {
	cat <<- EOD > "${MOUNT}"/boot/firmware/cmdline.txt
		console=serial0,115200 console=tty1 loglevel=1 root=LABEL=${ROOT_FS_LABEL} rootfstype=${ROOTFS_TYPE} fsck.repair=yes rootwait logo.nologo cgroup_enable=cpuset cgroup_memory=1 cgroup_enable=memory
	EOD

	if [[ "${SHOW_DEBUG}" == "yes" ]]; then
		display_alert "Showing /boot/firmware as mounted" "bcm2711" "debug"
		run_host_command_logged tree "${MOUNT}"/boot/firmware
	fi
}
