From 57c043e9b0c67c2563170a73e91ad64cbff67eac Mon Sep 17 00:00:00 2001 From: Dylan Corrales Date: Fri, 6 Nov 2026 18:47:59 -0500 Subject: [PATCH] Add s3l_ultimate_amcrest-ip4m1026e (Ambarella S3L, OV4689) The Amcrest IP4M-1026E (Dahua IPC-HFW1430SN): S3L, OV4689 over MIPI, 32 MiB SPI-NOR, Ethernet only, IR-cut and IR LEDs with an ADC light sensor. - s3l_ultimate with this board's kernel fragment: the SPI-NOR controller, the board DTB appended to the uImage (the Dahua U-Boot passes ATAGs), and a command line whose layout keeps the Dahua boot area, its environment and partition table, puts the kernel at 0xf0000 where its U-Boot reads it, and ends rootfs_data at 0x1a70000. The flash after that stays stock (dahua, ro): the Dahua U-Boot writes a boot-state record into the stock updateflag partition there on every boot. - Majestic as the streamer, with its fonts and web UI, as s3l_ultimate has them. - The customizer names the sensor (it is held in reset until its driver loads), sets the upgrade URL, sets sysbackup=0 in the Dahua U-Boot env, and sets up Majestic's night mode: IR-cut 113/111, IR LEDs on 5, and day/night from the light sensor on ADC channel 1 (which reads higher in light, hence adcInvert). - gpio.conf for the button, IR-cut, IR LEDs and light sensor. - Excludes drop the sensor and video-out modules this board can't use. Tested on the IP4M-1026E with firmware master (35c75dc3): the NOR build fits (uImage 1604K/2048K, rootfs 5072K/8192K) with only ov4689_mipi left of the sensor drivers; netbooted, the customizer writes Majestic's night-mode settings, and /night/on and /night/off move the IR-cut filter and IR LEDs. With Majestic master+f2fa260, it starts preview from a fresh boot and streams H.265 2688x1512 at 30 fps with its 3A; it reads the light sensor (night_mode_source 3), and covering the sensor (ADC ~15) switches to night and uncovering it (~2870) back to day. Flashed over the Dahua U-Boot's TFTP upgrade (every write read back), the NOR build of this profile boots with its own layout: the overlay on rootfs_data, the customizer's settings in fw_env and majestic.yaml, and a test file surviving reboots. From a fresh boot, Majestic (master+e6ba340) streams H.265 2688x1512 at 30 fps and reads the light sensor. An OpenIPC-to-OpenIPC sysupgrade from the profile's archive (--archive, -z) wrote and verified the kernel at 0xf0000 and the rootfs at 0x2f0000 and rebooted into them with the settings, sysbackup=0 and the counter kept. An earlier lite build of the profile also went stock -> OpenIPC -> stock -> OpenIPC. It is the first Ambarella device here, so ci-matrix.py gets it in SMOKE_TARGETS: --self-test requires one target per SoC vendor. sysbackup=0: the Dahua U-Boot counts boots in a byte at 0x1a80000 and, on reading 5, boots its backup system from the stock backupker/backupfs instead of OpenIPC. Stock clears the count after every good boot; OpenIPC does not, so from the factory value (2) it would fall back within a few reboots. sysbackup=0 turns the counting and the backup boot off; U-Boot's TFTP upgrade path does not read it. Tested on the flashed image: with the flash set leaving sysbackup=1 and the count at 0, U-Boot counted the first boot (err_count 00 -> 01), the customizer set sysbackup=0, and over the next three boots U-Boot printed no err_count and the count stayed at 01. --- .github/scripts/ci-matrix.py | 1 + README.md | 1 + .../s3l/fragments/amcrest-ip4m1026e.config | 16 +++++ .../s3l_ultimate_amcrest-ip4m1026e_defconfig | 65 +++++++++++++++++++ .../overlay/usr/share/openipc/customizer.sh | 41 ++++++++++++ .../overlay/usr/share/openipc/gpio.conf | 13 ++++ .../scripts/excludes/s3l_ultimate.list | 17 +++++ 7 files changed, 154 insertions(+) create mode 100644 devices/s3l_ultimate_amcrest-ip4m1026e/br-ext-chip-ambarella/board/s3l/fragments/amcrest-ip4m1026e.config create mode 100644 devices/s3l_ultimate_amcrest-ip4m1026e/br-ext-chip-ambarella/configs/s3l_ultimate_amcrest-ip4m1026e_defconfig create mode 100644 devices/s3l_ultimate_amcrest-ip4m1026e/general/overlay/usr/share/openipc/customizer.sh create mode 100644 devices/s3l_ultimate_amcrest-ip4m1026e/general/overlay/usr/share/openipc/gpio.conf create mode 100644 devices/s3l_ultimate_amcrest-ip4m1026e/general/scripts/excludes/s3l_ultimate.list diff --git a/.github/scripts/ci-matrix.py b/.github/scripts/ci-matrix.py index 245d816a0..4169682e6 100644 --- a/.github/scripts/ci-matrix.py +++ b/.github/scripts/ci-matrix.py @@ -118,6 +118,7 @@ "ssc338q_waybeam_generic", # waybeam, the one build without majestic "gk7205v200_otg_generic", # otg "ssc338q_apfpv", # devices/apfpv + "s3l_ultimate_amcrest-ip4m1026e", # Ambarella ] # LICENSE and README anchored to whole filenames; unanchored they would also diff --git a/README.md b/README.md index 94271f2e8..f37f35120 100644 --- a/README.md +++ b/README.md @@ -15,6 +15,7 @@ _(based on Buildroot)_ ### List of known and supported devices ``` +Amcrest IP4M-1026E S3L OV4689 - NOR_32M testing, video-ok, ircut-ok, day/night-ok Anxinshi ASRIH698T HI3516DV100 IMX291 - NOR_8M video-ok, pan/tilt-ok (pelco-d UART1), zoom/focus-no Aoni EP01J05 T31L ? RTL8188FU_USB NOR_16M new Azarton C1 T20X JXF23 RTL8189FS_SDIO NOR_16M done diff --git a/devices/s3l_ultimate_amcrest-ip4m1026e/br-ext-chip-ambarella/board/s3l/fragments/amcrest-ip4m1026e.config b/devices/s3l_ultimate_amcrest-ip4m1026e/br-ext-chip-ambarella/board/s3l/fragments/amcrest-ip4m1026e.config new file mode 100644 index 000000000..8b722ebeb --- /dev/null +++ b/devices/s3l_ultimate_amcrest-ip4m1026e/br-ext-chip-ambarella/board/s3l/fragments/amcrest-ip4m1026e.config @@ -0,0 +1,16 @@ +# 32 MB W25Q256JV on the SPI-NOR controller; s3l.generic.config is set up for SPI-NAND. +CONFIG_MTD_AMBARELLA_SPI_NOR=y +CONFIG_MTD_BLOCK=y + +# The Dahua U-Boot passes ATAGs, not a device tree: the uImage carries the board DTB. +CONFIG_ARM_APPENDED_DTB=y +CONFIG_AMBARELLA_OPENIPC_DTB="ambarella-s3l-ip4m1026e" + +# The Dahua U-Boot passes its own command line in ATAGs, which an appended-DTB kernel ignores, +# and the board DTS sets no bootargs, so this is the command line. The layout keeps the Dahua +# boot area as it is: MinBoot, U-Boot and the DTB it loads (boot), its environment (env) and the +# table its U-Boot reads at 0xe0000 (partition). The kernel starts where the stock one does, +# 0xf0000, where U-Boot's bootcmd reads it from. rootfs_data ends at 0x1a70000 and the flash after it stays +# stock (dahua): the Dahua U-Boot writes a boot-state record (state, err_count) into the stock updateflag +# partition there on every boot. +CONFIG_CMDLINE="console=ttyS0,115200 panic=20 root=/dev/mtdblock4 rootfstype=squashfs init=/init mtdparts=amba_spinor:768k(boot)ro,128k(env),64k(partition)ro,2048k(kernel),8192k(rootfs),15872k(rootfs_data),-(dahua)ro" diff --git a/devices/s3l_ultimate_amcrest-ip4m1026e/br-ext-chip-ambarella/configs/s3l_ultimate_amcrest-ip4m1026e_defconfig b/devices/s3l_ultimate_amcrest-ip4m1026e/br-ext-chip-ambarella/configs/s3l_ultimate_amcrest-ip4m1026e_defconfig new file mode 100644 index 000000000..cee36a126 --- /dev/null +++ b/devices/s3l_ultimate_amcrest-ip4m1026e/br-ext-chip-ambarella/configs/s3l_ultimate_amcrest-ip4m1026e_defconfig @@ -0,0 +1,65 @@ +# Architecture +BR2_arm=y +BR2_cortex_a9=y +BR2_ARM_EABIHF=y +BR2_ARM_ENABLE_NEON=y +BR2_ARM_ENABLE_VFP=y +BR2_ARM_FPU_NEON=y +BR2_ARM_INSTRUCTIONS_THUMB2=y + +# Toolchain +BR2_TOOLCHAIN_EXTERNAL=y +BR2_TOOLCHAIN_EXTERNAL_CUSTOM=y +BR2_TOOLCHAIN_EXTERNAL_DOWNLOAD=y +BR2_TOOLCHAIN_EXTERNAL_URL="https://github.com/openipc/firmware/releases/download/$(OPENIPC_TOOLCHAIN).tgz" +BR2_TOOLCHAIN_EXTERNAL_CUSTOM_PREFIX="arm-openipc-linux-musleabihf" +BR2_TOOLCHAIN_EXTERNAL_HEADERS_3_10=y +BR2_TOOLCHAIN_EXTERNAL_CUSTOM_MUSL=y +BR2_TOOLCHAIN_EXTERNAL_CXX=y + +# Kernel +# The Dahua U-Boot boots with ATAGs, so the kernel appends the board DTB to the uImage +# (CONFIG_AMBARELLA_OPENIPC_DTB in the fragment). +BR2_LINUX_KERNEL=y +BR2_LINUX_KERNEL_CUSTOM_TARBALL=y +BR2_LINUX_KERNEL_CUSTOM_TARBALL_LOCATION="https://github.com/openipc/linux/archive/$(OPENIPC_KERNEL).tar.gz" +BR2_LINUX_KERNEL_USE_CUSTOM_CONFIG=y +BR2_LINUX_KERNEL_CUSTOM_CONFIG_FILE="$(EXTERNAL_VENDOR)/board/$(OPENIPC_SOC_FAMILY)/s3l.generic.config" +BR2_LINUX_KERNEL_CONFIG_FRAGMENT_FILES="$(EXTERNAL_VENDOR)/board/$(OPENIPC_SOC_FAMILY)/fragments/amcrest-ip4m1026e.config" +BR2_LINUX_KERNEL_UIMAGE=y +BR2_LINUX_KERNEL_XZ=y + +# Filesystem +BR2_PACKAGE_BUSYBOX_CONFIG="$(BR2_EXTERNAL)/package/busybox/busybox.config" +BR2_PACKAGE_UBOOT_TOOLS=y +BR2_PACKAGE_ZLIB=y +# BR2_PACKAGE_IFUPDOWN_SCRIPTS is not set +BR2_TARGET_ROOTFS_SQUASHFS=y +BR2_TARGET_ROOTFS_SQUASHFS4_XZ=y + +# OpenIPC +BR2_OPENIPC_SOC_VENDOR="ambarella" +BR2_OPENIPC_SOC_MODEL="s3l" +BR2_OPENIPC_SOC_FAMILY="s3l" +BR2_OPENIPC_VARIANT="ultimate" +BR2_OPENIPC_FLASH_SIZE="32" + +# Packages +BR2_PACKAGE_AMBARELLA_OSDRV_S3L=y +BR2_PACKAGE_DROPBEAR_OPENIPC=y +BR2_PACKAGE_IPCTOOL=y +BR2_PACKAGE_LIBCURL_OPENIPC=y +BR2_PACKAGE_LIBCURL_OPENIPC_CURL=y +# BR2_PACKAGE_LIBCURL_OPENIPC_PROXY_SUPPORT is not set +# BR2_PACKAGE_LIBCURL_OPENIPC_COOKIES_SUPPORT is not set +# BR2_PACKAGE_LIBCURL_OPENIPC_EXTRA_PROTOCOLS_FEATURES is not set +BR2_PACKAGE_LIBEVENT_OPENIPC=y +BR2_PACKAGE_LIBOGG_OPENIPC=y +BR2_PACKAGE_MAJESTIC=y +BR2_PACKAGE_MAJESTIC_FONTS=y +BR2_PACKAGE_MAJESTIC_WEBUI=y +BR2_PACKAGE_MBEDTLS_OPENIPC=y +BR2_PACKAGE_OPUS_OPENIPC=y +BR2_PACKAGE_OPUS_OPENIPC_FIXED_POINT=y +BR2_PACKAGE_VTUND_OPENIPC=y +BR2_PACKAGE_YAML_CLI=y diff --git a/devices/s3l_ultimate_amcrest-ip4m1026e/general/overlay/usr/share/openipc/customizer.sh b/devices/s3l_ultimate_amcrest-ip4m1026e/general/overlay/usr/share/openipc/customizer.sh new file mode 100644 index 000000000..438b70f57 --- /dev/null +++ b/devices/s3l_ultimate_amcrest-ip4m1026e/general/overlay/usr/share/openipc/customizer.sh @@ -0,0 +1,41 @@ +#!/bin/sh +# +# Perform basic settings on a known IP camera +# +# +# Set custom upgrade url +# +fw_setenv upgrade 'https://github.com/OpenIPC/builder/releases/download/latest/s3l_ultimate_amcrest-ip4m1026e-nor.tgz' +# +# +# The OV4689 is held in reset (GPIO 107) until its driver loads, so load_ambarella +# cannot find it by probing I2C. Name it instead. +# +fw_setenv sensor ov4689 +# +# +# The Dahua U-Boot counts boots (one byte at flash 0x1a80000) and, on reading 5, boots its +# backup system from the stock backupker/backupfs instead. Stock clears the count after +# every good boot; OpenIPC doesn't. sysbackup=0 turns the counting and the backup boot off +# and leaves its TFTP upgrade path alone. +# +fw_setenv sysbackup 0 +# +# +# Night mode: IR-cut on 113 (filter out) and 111 (filter in), IR LEDs on 5. +# +cli -s .nightMode.irCutPin1 113 +cli -s .nightMode.irCutPin2 111 +cli -s .nightMode.backlightPin 5 +# +# Day/night from the light sensor on ADC channel 1. It reads higher in light (lit ~2900, +# covered 15-200), the other way round from what Majestic expects, hence adcInvert. +# +cli -s .nightMode.adcReadout true +cli -s .nightMode.adcChannel 1 +cli -s .nightMode.adcInvert true +cli -s .nightMode.minThreshold 256 +cli -s .nightMode.maxThreshold 672 +cli -s .nightMode.lightMonitor true + +exit 0 diff --git a/devices/s3l_ultimate_amcrest-ip4m1026e/general/overlay/usr/share/openipc/gpio.conf b/devices/s3l_ultimate_amcrest-ip4m1026e/general/overlay/usr/share/openipc/gpio.conf new file mode 100644 index 000000000..932bd5b83 --- /dev/null +++ b/devices/s3l_ultimate_amcrest-ip4m1026e/general/overlay/usr/share/openipc/gpio.conf @@ -0,0 +1,13 @@ +alarm_in=-1 +alarm_out=-1 +button=34 # active low (verified) +ircut1=113 # high 200 ms = filter out (night) (verified) +ircut2=111 # high 200 ms = filter in (day); then both low (verified) +led1=-1 # stock drives 60 and 106 as status LEDs; no visible LED on any level combination +led2=-1 +light_ir=5 # active high (verified); pin also PWM1 +light_wl=-1 +light_sensor=-1 # ADC channel 1 (adcsys adc1), lower = darker: lit room ~2900, covered 15-200 (verified) +mmc_pwr=-1 +speaker=-1 +usb=-1 diff --git a/devices/s3l_ultimate_amcrest-ip4m1026e/general/scripts/excludes/s3l_ultimate.list b/devices/s3l_ultimate_amcrest-ip4m1026e/general/scripts/excludes/s3l_ultimate.list new file mode 100644 index 000000000..1ca0eabdb --- /dev/null +++ b/devices/s3l_ultimate_amcrest-ip4m1026e/general/scripts/excludes/s3l_ultimate.list @@ -0,0 +1,17 @@ +/lib/modules/3.10.104/ambarella/ar0230.ko +/lib/modules/3.10.104/ambarella/ar0237.ko +/lib/modules/3.10.104/ambarella/imx172.ko +/lib/modules/3.10.104/ambarella/imx178.ko +/lib/modules/3.10.104/ambarella/imx226.ko +/lib/modules/3.10.104/ambarella/imx274_mipi.ko +/lib/modules/3.10.104/ambarella/imx290.ko +/lib/modules/3.10.104/ambarella/imx290_mipi.ko +/lib/modules/3.10.104/ambarella/imx326.ko +/lib/modules/3.10.104/ambarella/imx326_mipi.ko +/lib/modules/3.10.104/ambarella/ov2718_mipi.ko +# +/lib/modules/3.10.104/ambarella/adv7441a.ko +/lib/modules/3.10.104/ambarella/ambdbus.ko +/lib/modules/3.10.104/ambarella/ambhdmi.ko +/lib/modules/3.10.104/ambarella/ambtve.ko +/lib/modules/3.10.104/ambarella/it66121.ko