Skip to content
Merged
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
4 changes: 3 additions & 1 deletion .github/workflows/pr-build-check.yml
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,8 @@ jobs:
run: |
cmake -H. -Bbuild -DCMAKE_BUILD_TYPE=Release
cmake --build build --target cYAML_test reginfo_test longse_test \
sensors_test anyka_test hal_hisi_test \
sensors_test anyka_test ambarella_test \
hal_hisi_test \
report_test http_test mtd_alias_test \
nand_layout_test upgrade_env_test \
jffs2_test raw_image_test
Expand All @@ -162,6 +163,7 @@ jobs:
./build/reginfo_test
./build/longse_test
./build/anyka_test
./build/ambarella_test
./build/hal_hisi_test
# Run from the tree root: the fingerprint it compares against is
# src/sensors_golden.txt, and a sensor that stopped being identified
Expand Down
10 changes: 10 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,8 @@ CMake knobs worth knowing:
purpose. Same situation as `longse_test` and the same `CHECK` macro: nobody
on the project has an Anyka camera, so this is all the verification that
code gets until a reporter runs it.
- `./build/ambarella_test`: the `/proc/cpuinfo` machine string the Ambarella
HAL parses, same `CHECK` macro and same reason.
- `tools/test_pipeline.sh`: hardware-free end-to-end check of the sensor
driver extraction pipeline (`trace_segment.py` -> `trace_to_driver.py` ->
`gcc -fsyntax-only` -> `trace_diff.py`), plus the `--selftest` of every
Expand Down Expand Up @@ -213,6 +215,14 @@ with. Reading the register is therefore a refinement and never the gate, which
is also what lets detection survive a kernel that will not hand over
`/dev/mem`.

Ambarella (`src/hal/ambarella.c`) stops at the machine string on purpose. The
exact part (S3L33M, S3L55M, S3L66, ...) is a word the DSP firmware writes,
reachable only through `/dev/iav`, so the report says `S3L`. Do not derive
total RAM from the boot log's `IAVMEM` line: Amboot computes it from a
compile-time `DRAM_SIZE`, and #266 has it ending at 512 MiB on a camera
reported as 256 MiB. That Dahua kernel also refuses `execve()` from writable
filesystems, so `/tmp/ipctool` fails there with "Success" and exit code 2.

Sensor I2C addresses in tables are the 8-bit (write) form; the default
`i2c_change_addr` shifts right by one for the kernel, and some HALs install
`i2c_change_plain_addr` instead. Ingenic gates the sensor clock, which is why
Expand Down
9 changes: 8 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ include_directories(./src/)
# directly rather than through the table. Affects libipchw only; the ipctool
# executable is a diagnostic tool and always carries every vendor.
set(IPCHW_OPTIONAL_VENDORS
allwinner anyka bcm fh gm ingenic novatek rockchip sstar tegra xilinx xm)
allwinner ambarella anyka bcm fh gm ingenic novatek rockchip sstar tegra xilinx xm)
set(IPCHW_VENDORS "all" CACHE STRING
"Vendor HALs to compile into libipchw: 'all', 'none', or a ;-separated \
subset of: ${IPCHW_OPTIONAL_VENDORS}")
Expand Down Expand Up @@ -525,6 +525,13 @@ if(NOT ONLY_LIBRARY)
target_include_directories(anyka_test PRIVATE include src)
target_link_libraries(anyka_test m Threads::Threads)

# Same reason as anyka_test: the parser is all that can run off a camera.
add_executable(ambarella_test src/hal/ambarella_test.c src/hal/ambarella.c
src/hal/common.c src/tools.c src/cjson/cJSON.c
${VERSION_OBJ})
target_include_directories(ambarella_test PRIVATE include src)
target_link_libraries(ambarella_test m Threads::Threads)

# The body `ipctool upload` sends: part framing, the backup's layout and
# the length that must match it, and openipc.org's answer. Off a camera,
# like the others.
Expand Down
3 changes: 3 additions & 0 deletions src/chipid.c
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,9 @@ static const manufacturers_t manufacturers[] = {
#ifdef IPCHW_VENDOR_FH
{"FH", fh_detect_cpu, VENDOR_FH, fh_setup_hal},
#endif
#ifdef IPCHW_VENDOR_AMBARELLA
{"Ambarella", ambarella_detect_cpu, VENDOR_AMBARELLA, ambarella_setup_hal},
#endif
#ifdef IPCHW_VENDOR_ANYKA
{NULL /* Generic */, anyka_detect_cpu, VENDOR_ANYKA, anyka_setup_hal},
#endif
Expand Down
1 change: 1 addition & 0 deletions src/chipid.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include <stdbool.h>

#define VENDOR_ALLWINNER "Allwinner"
#define VENDOR_AMBARELLA "Ambarella"
#define VENDOR_ANYKA "Anyka"
#define VENDOR_BCM "Broadcom"
#define VENDOR_FH "Fullhan"
Expand Down
54 changes: 54 additions & 0 deletions src/hal/ambarella.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
#include "hal/ambarella.h"

#include <string.h>

#include "hal/common.h"
#include "tools.h"

/* Defaults of the `addr` module parameter across the S3L SDK's VIN drivers,
* the 8-bit form ipctool's tables use. AR0521 is the one part left out: it
* answers on 0x6C, and the onsemi probe runs before the OmniVision one, so
* listing it would have that probe reading an OV4689. */
static unsigned char sony_addrs[] = {0x34, 0};
static unsigned char onsemi_addrs[] = {0x20, 0};
static unsigned char omni_addrs[] = {0x6c, 0};

static sensor_addr_t ambarella_possible_i2c_addrs[] = {
{SENSOR_SONY, sony_addrs},
{SENSOR_ONSEMI, onsemi_addrs},
{SENSOR_OMNIVISION, omni_addrs},
{0, NULL}};

/* Every DT_MACHINE_START in the vendor tree reads "Ambarella <soc> (Flattened
* Device Tree)". These kernels register no UART with /proc/iomem, and S3L
* and S3LM share one machine string: the exact part (33M, 55M, 66, ...) is
* known only to the DSP firmware once it runs, so "S3L" is as far as this
* goes. */
bool ambarella_machine_name(const char *cpuinfo, char *out, size_t outlen) {
if (!outlen)
return false;

if (!line_from_file(cpuinfo, "Hardware.+: Ambarella ([A-Za-z0-9]+)", out,
outlen))
return false;

out[outlen - 1] = '\0';
return true;
}

bool ambarella_detect_cpu(char *chip_name) {
char machine[128];

if (!ambarella_machine_name("/proc/cpuinfo", machine, sizeof(machine)))
return false;
strcpy(chip_name, machine);

/* chip_generation stays 0 on purpose. It keys the pad-mux, clock and boot
* ROM tables, and ipctool has none for Ambarella, so 0 sends those paths to
* their no-table answer and getchipfamily() back to the name. */
return true;
}

void ambarella_setup_hal() {
possible_i2c_addrs = ambarella_possible_i2c_addrs;
}
11 changes: 11 additions & 0 deletions src/hal/ambarella.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#ifndef HAL_AMBARELLA_H
#define HAL_AMBARELLA_H

#include <stdbool.h>
#include <stddef.h>

bool ambarella_machine_name(const char *cpuinfo, char *out, size_t outlen);
bool ambarella_detect_cpu(char *chip_name);
void ambarella_setup_hal();

#endif /* HAL_AMBARELLA_H */
69 changes: 69 additions & 0 deletions src/hal/ambarella_test.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
/* Hardware-free cover for the Ambarella machine-string parser. The strings
* are the DT_MACHINE_START names in the vendor kernel, and the S3L cpuinfo is
* the one from issue #266. */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#include "hal/ambarella.h"

int chip_generation;
char chip_name[128];
const char *getchipfamily() { return chip_name; }

static int failures;

#define CHECK(cond) \
do { \
if (!(cond)) { \
fprintf(stderr, " FAIL %s:%d: %s\n", __FILE__, __LINE__, #cond); \
failures++; \
} \
} while (0)

static bool parse(const char *cpuinfo, char *out, size_t outlen) {
char path[] = "/tmp/ambarella_test.XXXXXX";
int fd = mkstemp(path);

CHECK(fd >= 0);
CHECK(write(fd, cpuinfo, strlen(cpuinfo)) == (ssize_t)strlen(cpuinfo));
close(fd);
bool res = ambarella_machine_name(path, out, outlen);
unlink(path);
return res;
}

int main() {
char buf[128];

CHECK(parse("processor\t: 0\n"
"Hardware\t: Ambarella S3L (Flattened Device Tree)\n"
"Revision\t: 0000\n",
buf, sizeof(buf)));
CHECK(!strcmp(buf, "S3L"));

CHECK(parse("Hardware\t: Ambarella S2L (Flattened Device Tree)\n", buf,
sizeof(buf)));
CHECK(!strcmp(buf, "S2L"));

CHECK(parse("Hardware\t: Ambarella A5S (Flattened Device Tree)\n", buf,
sizeof(buf)));
CHECK(!strcmp(buf, "A5S"));

CHECK(!parse("Hardware\t: SStar Soc (Flattened Device Tree)\n", buf,
sizeof(buf)));
CHECK(!parse("model name\t: ARMv7 Processor rev 1 (v7l)\n", buf,
sizeof(buf)));

/* Nothing may land in the buffer, or just before it. */
char guarded[3] = {'x', 'y', 'z'};
CHECK(!parse("Hardware\t: Ambarella S3L (Flattened Device Tree)\n",
guarded + 1, 0));
CHECK(guarded[0] == 'x' && guarded[1] == 'y' && guarded[2] == 'z');

if (failures)
return EXIT_FAILURE;
puts("ambarella_test: all cases passed");
return EXIT_SUCCESS;
}
1 change: 1 addition & 0 deletions src/hal/common.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

#include "cjson/cJSON.h"
#include "hal/allwinner.h"
#include "hal/ambarella.h"
#include "hal/anyka.h"
#include "hal/bcm.h"
#include "hal/fh.h"
Expand Down
Loading