From 62951e25b3440e547afbc9c374586fce69c031c7 Mon Sep 17 00:00:00 2001 From: Daniel Piers Date: Tue, 13 Oct 2026 10:35:26 -0700 Subject: [PATCH 1/4] Add NT98513 and NA51023 identification on MIPS --- .github/workflows/pr-build-check.yml | 3 +- CMakeLists.txt | 10 ++ src/chipid.c | 7 + src/hal/novatek.c | 28 +++- src/hal/novatek.h | 3 + src/hal/novatek_test.c | 199 +++++++++++++++++++++++++++ 6 files changed, 248 insertions(+), 2 deletions(-) create mode 100644 src/hal/novatek_test.c diff --git a/.github/workflows/pr-build-check.yml b/.github/workflows/pr-build-check.yml index 6b588a53..ee8a46dc 100644 --- a/.github/workflows/pr-build-check.yml +++ b/.github/workflows/pr-build-check.yml @@ -139,7 +139,7 @@ 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 novatek_test hal_hisi_test \ report_test http_test mtd_alias_test \ nand_layout_test ./build/cYAML_test @@ -150,6 +150,7 @@ jobs: ./build/reginfo_test ./build/longse_test ./build/anyka_test + ./build/novatek_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 diff --git a/CMakeLists.txt b/CMakeLists.txt index 19dc363b..140c6f33 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -505,6 +505,16 @@ if(NOT ONLY_LIBRARY) target_include_directories(anyka_test PRIVATE include src) target_link_libraries(anyka_test m Threads::Threads) + # Includes novatek.c so only its hardware file paths are redirected. + add_executable(novatek_test src/hal/novatek_test.c src/hal/common.c + src/sensors.c src/tools.c src/cjson/cJSON.c + ${VERSION_OBJ}) + target_include_directories(novatek_test PRIVATE include src) + target_compile_definitions(novatek_test PRIVATE IPCHW_VENDOR_NOVATEK + STANDALONE_LIBRARY) + target_link_libraries(novatek_test m Threads::Threads + "-Wl,--wrap=open" "-Wl,--wrap=disable_printk") + # 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. diff --git a/src/chipid.c b/src/chipid.c index 87f1153b..ae4b6671 100644 --- a/src/chipid.c +++ b/src/chipid.c @@ -55,6 +55,9 @@ static const manufacturers_t manufacturers[] = { {"isvp", ingenic_detect_cpu, VENDOR_INGENIC, setup_hal_ingenic}, {"ingenic", ingenic_detect_cpu, VENDOR_INGENIC, setup_hal_ingenic}, #endif +#ifdef IPCHW_VENDOR_NOVATEK + {NULL, novatek_detect_cpu, VENDOR_NOVATEK, novatek_setup_hal}, +#endif #endif #ifdef __arm__ #ifdef IPCHW_VENDOR_SSTAR @@ -238,6 +241,10 @@ const char *getchipname() { const char *getchipfamily() { const char *chip_name = getchipname(); switch (chip_generation) { +#ifdef IPCHW_VENDOR_NOVATEK + case CHIP_NA51023: + return "nt9851x"; +#endif #ifdef IPCHW_HISI_V1 case HISI_V1: return "hi3516cv100"; diff --git a/src/hal/novatek.c b/src/hal/novatek.c index 0c99c221..bc4d26c7 100644 --- a/src/hal/novatek.c +++ b/src/hal/novatek.c @@ -65,7 +65,8 @@ bool novatek_detect_cpu(char *chip_name) { if(nvt_get_chip_id()) return true; - if (!line_from_file("/proc/device-tree/model", "Novatek ([A-Z]+[0-9]+)", + if (!line_from_file("/proc/device-tree/model", + "^Novatek ([A-Z]+[0-9]+)([[:space:]]|$)", buf, sizeof(buf))) { /* NA51055 has a pad table and no part name the ID can give; with * no device-tree model either, the die is the name. */ @@ -76,6 +77,18 @@ bool novatek_detect_cpu(char *chip_name) { strcpy(chip_name, buf); + if (!strcmp(buf, "NA51023")) { + /* The NA51023 device-tree model names a die shared by more than + * one part. Only the factory profile in the NT98513 dump names the + * part itself. Parse that declaration as data; never source it. + * Missing/other profiles keep the honest NA51023 family identity. */ + chip_generation = CHIP_NA51023; + if (line_from_file("/etc/profile_prjcfg", + "^export CHIP=\"(98513)\"[[:space:]]*$", buf, + sizeof(buf))) + strcpy(chip_name, "NT98513"); + } + return true; } @@ -118,7 +131,20 @@ static int novatek_open_i2c_fd(int i2c_adapter_nr) { return universal_open_sensor_fd(adapter_name); } +static int novatek_no_sensor_bus(int adapter_nr) { + (void)adapter_nr; + return -1; +} + void novatek_setup_hal() { + /* This MIPS generation delegates media to uITRON. The ARM HDAL memory + * report, sensor I2C bus and register tables below are not its ABI. */ + if (chip_generation == CHIP_NA51023) { + possible_i2c_addrs = NULL; + open_i2c_sensor_fd = novatek_no_sensor_bus; + open_spi_sensor_fd = NULL; + return; + } possible_i2c_addrs = novatek_possible_i2c_addrs; i2c_change_addr = i2c_changenshift_addr; open_i2c_sensor_fd = novatek_open_i2c_fd; diff --git a/src/hal/novatek.h b/src/hal/novatek.h index e23d1c0c..b0f6a90c 100644 --- a/src/hal/novatek.h +++ b/src/hal/novatek.h @@ -22,6 +22,9 @@ void novatek_setup_hal(); /* TOP + 0xF0 bits [31:16], also /proc/nvt_info/nvt_pinmux/chip_id. One ID * per die; the parts cut from a die are told apart by eFuse/OTP words. */ enum CHIP_ID { + /* Software family discriminator, not a TOP chip-ID register value. + * The MIPS SDK supplies a device-tree model but no verified chip_id. */ + CHIP_NA51023 = 0x51023, CHIP_NA51055 = 0x4821, // NT9852x: NT98520, NT98525 CHIP_NA51084 = 0x5021, // NT98528, NT98529 (the 1.2 GHz part, by OTP) CHIP_NA51089 = 0x7021, // NT98562 (64 MB internal RAM), diff --git a/src/hal/novatek_test.c b/src/hal/novatek_test.c new file mode 100644 index 00000000..5768842a --- /dev/null +++ b/src/hal/novatek_test.c @@ -0,0 +1,199 @@ +/* Hardware-free identity checks. The NA51023 model and CHIP profile below + * come from an NT98513 firmware dump; they are not a live /proc capture. + * This test redirects file paths, but uses the real line_from_file parser + * and detector. It must not acquire /dev/mem, an I2C bus or a camera. */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "tools.h" + +static bool fixture_line_from_file(const char *path, const char *re, + char *out, size_t len); +#define line_from_file fixture_line_from_file +#include "novatek.c" +/* Select chipid.c's MIPS routing table on native CI too. All its system and + * project headers have already been read above; architecture macros change + * only while this platform-dispatch source is included. A real MIPS build + * and QEMU run remain separate from this conditional-routing check. */ +#pragma push_macro("__arm__") +#pragma push_macro("__aarch64__") +#pragma push_macro("__mips__") +#undef __arm__ +#undef __aarch64__ +#undef __mips__ +#define __mips__ 1 +#include "../chipid.c" +#pragma pop_macro("__mips__") +#pragma pop_macro("__aarch64__") +#pragma pop_macro("__arm__") +#undef line_from_file +#include "sensors.h" + +static int failures; +static int hardware_opens; +static int printk_disables; +static char fixture_dir[] = "/tmp/novatek_test.XXXXXX"; + +/* The test link wraps these functions. Catch even an attempted device open, + * rather than silently relying on /dev/i2c-N being absent in CI. */ +int __wrap_open(const char *path, int flags, ...) { + (void)path; + (void)flags; + hardware_opens++; + return -1; +} + +void __wrap_disable_printk(void) { printk_disables++; } + +#define CHECK(cond) \ + do { \ + if (!(cond)) { \ + fprintf(stderr, "FAIL %s:%d: %s\n", __FILE__, __LINE__, #cond); \ + failures++; \ + } \ + } while (0) + +static bool fixture_line_from_file(const char *path, const char *re, + char *out, size_t len) { + const char *name = NULL; + if (!strcmp(path, "/proc/nvt_info/nvt_pinmux/chip_id")) + name = "chip_id"; + else if (!strcmp(path, "/proc/device-tree/model")) + name = "model"; + else if (!strcmp(path, "/etc/profile_prjcfg")) + name = "profile"; + else if (!strcmp(path, "/proc/cpuinfo")) + name = "cpuinfo"; + else if (!strcmp(path, "/proc/iomem")) + return false; + if (!name) { + CHECK(!"unexpected hardware file read"); + return false; + } + char file[256]; + snprintf(file, sizeof(file), "%s/%s", fixture_dir, name); + return line_from_file(file, re, out, len); +} + +static void fixture(const char *name, const char *body) { + char file[256]; + snprintf(file, sizeof(file), "%s/%s", fixture_dir, name); + if (!body) { + unlink(file); + return; + } + FILE *fp = fopen(file, "w"); + if (!fp) { + perror(file); + exit(2); + } + fputs(body, fp); + fclose(fp); +} + +static void expect_name(const char *id, const char *model, + const char *profile, const char *want, bool legacy) { + fixture("chip_id", id); + fixture("model", model); + fixture("profile", profile); + chip_generation = 0; + strcpy(chip_name, "unset"); + bool ok = novatek_detect_cpu(chip_name); + CHECK(ok == (want != NULL)); + if (!ok || !want) + return; + CHECK(!strcmp(chip_name, want)); + if (strcmp(chip_name, want)) + fprintf(stderr, " wanted %s, got %s\n", want, chip_name); + + setup_hal_fallback(); + possible_i2c_addrs = NULL; + novatek_setup_hal(); + /* Recognising an RTOS media platform must not enable the ARM HDAL/I2C + * backend. ARM parts must keep their existing sensor probing. */ + CHECK((possible_i2c_addrs == NULL) == legacy); +} + +static void mips_dispatch(void) { + fixture("chip_id", NULL); + fixture("model", "Novatek NA51023 evaluation board"); + fixture("profile", "export CHIP=\"98513\"\n"); + fixture("cpuinfo", "system type\t: NVT NA51023\n" + "machine\t\t: Novatek NA51023 evaluation board\n" + "cpu model\t: MIPS 24KEc V5.5\n"); + chip_generation = 0; + *sysid = '\0'; + const char *name = getchipname(); + CHECK(name && !strcmp(name, "nt98513")); + if (!name) + return; + CHECK(!strcmp(getchipvendor(), "Novatek")); + CHECK(!strcmp(getchipfamily(), "nt9851x")); + CHECK(possible_i2c_addrs == NULL); + + sensor_ctx_t sensor; + hardware_opens = 0; + printk_disables = 0; + CHECK(hal_enable_sensor_clock == NULL); + CHECK(!getsensorid(&sensor)); + CHECK(hardware_opens == 0); + CHECK(printk_disables == 0); + + /* The dump gives us the device-tree model, not a live cpuinfo capture. + * Do not make detection depend on the latter's formatting. */ + fixture("cpuinfo", "system type\t: NVT NA51023\n"); + *sysid = '\0'; + name = getchipname(); + CHECK(name && !strcmp(name, "nt98513")); +} + +int main(void) { + if (!mkdtemp(fixture_dir)) { + perror("mkdtemp"); + return 2; + } + const char *model = "Novatek NA51023 evaluation board"; + const char *profile = "export PLATFORM=\"Linux\"\nexport CHIP=\"98513\"\n"; + expect_name(NULL, model, profile, "NT98513", true); + expect_name(NULL, model, NULL, "NA51023", true); + expect_name(NULL, model, "export CHIP=\"98515\"\n", "NA51023", true); + expect_name(NULL, model, "# export CHIP=\"98513\"\n", "NA51023", true); + expect_name(NULL, model, "export CHIP=\"985130\"\n", "NA51023", true); + expect_name(NULL, model, "export CHIP=\"98513\"; touch /tmp/no\n", + "NA51023", true); + expect_name(NULL, NULL, profile, NULL, false); + expect_name(NULL, "Other vendor NA51023", profile, NULL, false); + expect_name(NULL, "OtherNovatek NA51023 evaluation board", profile, + NULL, false); + expect_name(NULL, "Novatek NA51023A evaluation board", profile, + NULL, false); + expect_name(NULL, "Novatek NA51023", profile, "NT98513", true); + expect_name(NULL, "Novatek NA51023\tboard", profile, "NT98513", true); + expect_name(NULL, "Novatek NA510230 evaluation board", profile, + "NA510230", false); + expect_name(NULL, "Novatek NA51055 evaluation board", profile, + "NA51055", false); + expect_name("7021\n", NULL, profile, "NT98566", false); + expect_name("5021\n", NULL, NULL, "NT98528", false); + expect_name("8B20\n", NULL, NULL, "NT98332G", false); + expect_name("4821\n", NULL, NULL, "NA51055", false); + mips_dispatch(); + fixture("chip_id", NULL); + fixture("model", NULL); + fixture("profile", NULL); + fixture("cpuinfo", NULL); + rmdir(fixture_dir); + if (failures) { + fprintf(stderr, "novatek_test: %d failure(s)\n", failures); + return 1; + } + puts("novatek_test: all cases passed"); + return 0; +} From 4afe7c7e0783055edbe604c1b2066bc440ae2854 Mon Sep 17 00:00:00 2001 From: Daniel Piers Date: Tue, 13 Oct 2026 10:51:16 -0700 Subject: [PATCH 2/4] Restrict MIPS Novatek detection to the verified NA51023 model --- src/chipid.c | 2 +- src/hal/novatek.c | 40 +++++++++++++++++++++++++++++----------- src/hal/novatek.h | 1 + src/hal/novatek_test.c | 38 +++++++++++++++++++++++++++++++++++++- 4 files changed, 68 insertions(+), 13 deletions(-) diff --git a/src/chipid.c b/src/chipid.c index ae4b6671..66bf5b51 100644 --- a/src/chipid.c +++ b/src/chipid.c @@ -56,7 +56,7 @@ static const manufacturers_t manufacturers[] = { {"ingenic", ingenic_detect_cpu, VENDOR_INGENIC, setup_hal_ingenic}, #endif #ifdef IPCHW_VENDOR_NOVATEK - {NULL, novatek_detect_cpu, VENDOR_NOVATEK, novatek_setup_hal}, + {NULL, novatek_detect_mips_cpu, VENDOR_NOVATEK, novatek_setup_hal}, #endif #endif #ifdef __arm__ diff --git a/src/hal/novatek.c b/src/hal/novatek.c index bc4d26c7..68f1bb2c 100644 --- a/src/hal/novatek.c +++ b/src/hal/novatek.c @@ -59,6 +59,33 @@ static bool nvt_get_chip_id() { return true; } +static void nvt_refine_na51023(char *chip_name) { + char buf[16]; + + /* The device-tree model names a die shared by more than one part. + * Parse the factory declaration as data; never source it. Missing or + * different profiles retain the NA51023 identity. */ + chip_generation = CHIP_NA51023; + if (line_from_file("/etc/profile_prjcfg", + "^export CHIP=\"(98513)\"[[:space:]]*$", buf, + sizeof(buf))) + strcpy(chip_name, "NT98513"); +} + +bool novatek_detect_mips_cpu(char *chip_name) { + char buf[16]; + + /* Only this MIPS model has a verified identity and rejecting HAL. + * Other Novatek models and the ARM chip-ID proc ABI must not select + * the existing ARM sensor/HDAL backend through MIPS dispatch. */ + if (!line_from_file("/proc/device-tree/model", + "^Novatek (NA51023)([[:space:]]|$)", buf, sizeof(buf))) + return false; + strcpy(chip_name, buf); + nvt_refine_na51023(chip_name); + return true; +} + bool novatek_detect_cpu(char *chip_name) { char buf[256]; @@ -77,17 +104,8 @@ bool novatek_detect_cpu(char *chip_name) { strcpy(chip_name, buf); - if (!strcmp(buf, "NA51023")) { - /* The NA51023 device-tree model names a die shared by more than - * one part. Only the factory profile in the NT98513 dump names the - * part itself. Parse that declaration as data; never source it. - * Missing/other profiles keep the honest NA51023 family identity. */ - chip_generation = CHIP_NA51023; - if (line_from_file("/etc/profile_prjcfg", - "^export CHIP=\"(98513)\"[[:space:]]*$", buf, - sizeof(buf))) - strcpy(chip_name, "NT98513"); - } + if (!strcmp(buf, "NA51023")) + nvt_refine_na51023(chip_name); return true; } diff --git a/src/hal/novatek.h b/src/hal/novatek.h index b0f6a90c..d58f9537 100644 --- a/src/hal/novatek.h +++ b/src/hal/novatek.h @@ -4,6 +4,7 @@ #include bool novatek_detect_cpu(char *chip_name); +bool novatek_detect_mips_cpu(char *chip_name); unsigned long novatek_totalmem(unsigned long *media_mem); void novatek_setup_hal(); diff --git a/src/hal/novatek_test.c b/src/hal/novatek_test.c index 5768842a..df47c2f9 100644 --- a/src/hal/novatek_test.c +++ b/src/hal/novatek_test.c @@ -39,6 +39,7 @@ static bool fixture_line_from_file(const char *path, const char *re, static int failures; static int hardware_opens; static int printk_disables; +static int arm_chip_id_reads; static char fixture_dir[] = "/tmp/novatek_test.XXXXXX"; /* The test link wraps these functions. Catch even an attempted device open, @@ -63,8 +64,10 @@ void __wrap_disable_printk(void) { printk_disables++; } static bool fixture_line_from_file(const char *path, const char *re, char *out, size_t len) { const char *name = NULL; - if (!strcmp(path, "/proc/nvt_info/nvt_pinmux/chip_id")) + if (!strcmp(path, "/proc/nvt_info/nvt_pinmux/chip_id")) { + arm_chip_id_reads++; name = "chip_id"; + } else if (!strcmp(path, "/proc/device-tree/model")) name = "model"; else if (!strcmp(path, "/etc/profile_prjcfg")) @@ -130,6 +133,7 @@ static void mips_dispatch(void) { "cpu model\t: MIPS 24KEc V5.5\n"); chip_generation = 0; *sysid = '\0'; + arm_chip_id_reads = 0; const char *name = getchipname(); CHECK(name && !strcmp(name, "nt98513")); if (!name) @@ -137,6 +141,7 @@ static void mips_dispatch(void) { CHECK(!strcmp(getchipvendor(), "Novatek")); CHECK(!strcmp(getchipfamily(), "nt9851x")); CHECK(possible_i2c_addrs == NULL); + CHECK(arm_chip_id_reads == 0); sensor_ctx_t sensor; hardware_opens = 0; @@ -152,6 +157,33 @@ static void mips_dispatch(void) { *sysid = '\0'; name = getchipname(); CHECK(name && !strcmp(name, "nt98513")); + + /* This architecture has no verified ARM chip-ID proc ABI. Its detector + * must use the MIPS model even if an unrelated ARM ID file is present. */ + fixture("chip_id", "7021\n"); + chip_generation = 0; + *sysid = '\0'; + arm_chip_id_reads = 0; + name = getchipname(); + CHECK(name && !strcmp(name, "nt98513")); + CHECK(arm_chip_id_reads == 0); + CHECK(possible_i2c_addrs == NULL); +} + +static void mips_reject_unsupported(const char *id, const char *model) { + fixture("chip_id", id); + fixture("model", model); + fixture("profile", "export CHIP=\"98513\"\n"); + fixture("cpuinfo", "machine\t: Novatek\n"); + chip_generation = 0; + *sysid = '\0'; + possible_i2c_addrs = NULL; + arm_chip_id_reads = 0; + CHECK(getchipname() == NULL); + CHECK(chip_generation == 0); + CHECK(possible_i2c_addrs == NULL); + CHECK(open_i2c_sensor_fd != novatek_open_i2c_fd); + CHECK(arm_chip_id_reads == 0); } int main(void) { @@ -185,6 +217,10 @@ int main(void) { expect_name("8B20\n", NULL, NULL, "NT98332G", false); expect_name("4821\n", NULL, NULL, "NA51055", false); mips_dispatch(); + mips_reject_unsupported(NULL, "Novatek NA510230 evaluation board"); + mips_reject_unsupported(NULL, "Novatek NA51055 evaluation board"); + mips_reject_unsupported("7021\n", NULL); + mips_reject_unsupported("7021\n", "Novatek NA51055 evaluation board"); fixture("chip_id", NULL); fixture("model", NULL); fixture("profile", NULL); From b4d92827703dd7bc8353022ef9ffd7e772e31450 Mon Sep 17 00:00:00 2001 From: Daniel Piers Date: Tue, 13 Oct 2026 11:34:01 -0700 Subject: [PATCH 3/4] Limit NT98513 identification changes to MIPS builds --- .github/workflows/pr-build-check.yml | 5 ++- CMakeLists.txt | 12 ++++--- src/chipid.c | 3 +- src/hal/novatek.c | 14 ++++++++ src/hal/novatek.h | 2 ++ src/hal/novatek_test.c | 54 ++++++++++++++++++++++++---- 6 files changed, 78 insertions(+), 12 deletions(-) diff --git a/.github/workflows/pr-build-check.yml b/.github/workflows/pr-build-check.yml index ee8a46dc..fc41044c 100644 --- a/.github/workflows/pr-build-check.yml +++ b/.github/workflows/pr-build-check.yml @@ -139,7 +139,8 @@ jobs: run: | cmake -H. -Bbuild -DCMAKE_BUILD_TYPE=Release cmake --build build --target cYAML_test reginfo_test longse_test \ - sensors_test anyka_test novatek_test hal_hisi_test \ + sensors_test anyka_test novatek_test \ + novatek_arm_test novatek_aarch64_test hal_hisi_test \ report_test http_test mtd_alias_test \ nand_layout_test ./build/cYAML_test @@ -151,6 +152,8 @@ jobs: ./build/longse_test ./build/anyka_test ./build/novatek_test + ./build/novatek_arm_test + ./build/novatek_aarch64_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 diff --git a/CMakeLists.txt b/CMakeLists.txt index 140c6f33..5f9d731e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -506,14 +506,18 @@ if(NOT ONLY_LIBRARY) target_link_libraries(anyka_test m Threads::Threads) # Includes novatek.c so only its hardware file paths are redirected. - add_executable(novatek_test src/hal/novatek_test.c src/hal/common.c + foreach(_nvt_test novatek_test novatek_arm_test novatek_aarch64_test) + add_executable(${_nvt_test} src/hal/novatek_test.c src/hal/common.c src/sensors.c src/tools.c src/cjson/cJSON.c ${VERSION_OBJ}) - target_include_directories(novatek_test PRIVATE include src) - target_compile_definitions(novatek_test PRIVATE IPCHW_VENDOR_NOVATEK + target_include_directories(${_nvt_test} PRIVATE include src) + target_compile_definitions(${_nvt_test} PRIVATE IPCHW_VENDOR_NOVATEK STANDALONE_LIBRARY) - target_link_libraries(novatek_test m Threads::Threads + target_link_libraries(${_nvt_test} m Threads::Threads "-Wl,--wrap=open" "-Wl,--wrap=disable_printk") + endforeach() + target_compile_definitions(novatek_arm_test PRIVATE NOVATEK_TEST_ARM) + target_compile_definitions(novatek_aarch64_test PRIVATE NOVATEK_TEST_AARCH64) # 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, diff --git a/src/chipid.c b/src/chipid.c index 66bf5b51..94c43e27 100644 --- a/src/chipid.c +++ b/src/chipid.c @@ -241,7 +241,8 @@ const char *getchipname() { const char *getchipfamily() { const char *chip_name = getchipname(); switch (chip_generation) { -#ifdef IPCHW_VENDOR_NOVATEK +#if defined(IPCHW_VENDOR_NOVATEK) && \ + (defined(mips) || defined(__mips__) || defined(__mips)) case CHIP_NA51023: return "nt9851x"; #endif diff --git a/src/hal/novatek.c b/src/hal/novatek.c index 68f1bb2c..7442a1dc 100644 --- a/src/hal/novatek.c +++ b/src/hal/novatek.c @@ -59,6 +59,7 @@ static bool nvt_get_chip_id() { return true; } +#if defined(mips) || defined(__mips__) || defined(__mips) static void nvt_refine_na51023(char *chip_name) { char buf[16]; @@ -85,6 +86,7 @@ bool novatek_detect_mips_cpu(char *chip_name) { nvt_refine_na51023(chip_name); return true; } +#endif bool novatek_detect_cpu(char *chip_name) { char buf[256]; @@ -93,7 +95,13 @@ bool novatek_detect_cpu(char *chip_name) { return true; if (!line_from_file("/proc/device-tree/model", +#if defined(mips) || defined(__mips__) || defined(__mips) "^Novatek ([A-Z]+[0-9]+)([[:space:]]|$)", +#else + /* Keep the existing ARM/AArch64 parser unchanged. + * The new MIPS route has its own strict detector. */ + "Novatek ([A-Z]+[0-9]+)", +#endif buf, sizeof(buf))) { /* NA51055 has a pad table and no part name the ID can give; with * no device-tree model either, the die is the name. */ @@ -104,8 +112,10 @@ bool novatek_detect_cpu(char *chip_name) { strcpy(chip_name, buf); +#if defined(mips) || defined(__mips__) || defined(__mips) if (!strcmp(buf, "NA51023")) nvt_refine_na51023(chip_name); +#endif return true; } @@ -149,12 +159,15 @@ static int novatek_open_i2c_fd(int i2c_adapter_nr) { return universal_open_sensor_fd(adapter_name); } +#if defined(mips) || defined(__mips__) || defined(__mips) static int novatek_no_sensor_bus(int adapter_nr) { (void)adapter_nr; return -1; } +#endif void novatek_setup_hal() { +#if defined(mips) || defined(__mips__) || defined(__mips) /* This MIPS generation delegates media to uITRON. The ARM HDAL memory * report, sensor I2C bus and register tables below are not its ABI. */ if (chip_generation == CHIP_NA51023) { @@ -163,6 +176,7 @@ void novatek_setup_hal() { open_spi_sensor_fd = NULL; return; } +#endif possible_i2c_addrs = novatek_possible_i2c_addrs; i2c_change_addr = i2c_changenshift_addr; open_i2c_sensor_fd = novatek_open_i2c_fd; diff --git a/src/hal/novatek.h b/src/hal/novatek.h index d58f9537..de27afd6 100644 --- a/src/hal/novatek.h +++ b/src/hal/novatek.h @@ -4,7 +4,9 @@ #include bool novatek_detect_cpu(char *chip_name); +#if defined(mips) || defined(__mips__) || defined(__mips) bool novatek_detect_mips_cpu(char *chip_name); +#endif unsigned long novatek_totalmem(unsigned long *media_mem); void novatek_setup_hal(); diff --git a/src/hal/novatek_test.c b/src/hal/novatek_test.c index df47c2f9..6fed234c 100644 --- a/src/hal/novatek_test.c +++ b/src/hal/novatek_test.c @@ -13,23 +13,41 @@ #include #include "tools.h" +/* Read all project/system declarations before the synthetic architecture + * selection, especially the native Linux ioctl definitions. */ +#include "chipid.h" +#include "hal/common.h" +#include "sensors.h" static bool fixture_line_from_file(const char *path, const char *re, char *out, size_t len); #define line_from_file fixture_line_from_file -#include "novatek.c" -/* Select chipid.c's MIPS routing table on native CI too. All its system and - * project headers have already been read above; architecture macros change - * only while this platform-dispatch source is included. A real MIPS build - * and QEMU run remain separate from this conditional-routing check. */ +/* Select both the HAL and routing table's architecture on native CI. System + * headers are read above before changing these macros. The default is the + * MIPS fixture; two additional test targets cover the existing ARM routes. + * These selections affect only this test translation unit, not production. + * A real MIPS build/QEMU run remains a separate check. */ #pragma push_macro("__arm__") #pragma push_macro("__aarch64__") #pragma push_macro("__mips__") +#pragma push_macro("__mips") +#pragma push_macro("mips") #undef __arm__ #undef __aarch64__ #undef __mips__ +#undef __mips +#undef mips +#if defined(NOVATEK_TEST_ARM) +#define __arm__ 1 +#elif defined(NOVATEK_TEST_AARCH64) +#define __aarch64__ 1 +#else #define __mips__ 1 +#endif +#include "novatek.c" #include "../chipid.c" +#pragma pop_macro("mips") +#pragma pop_macro("__mips") #pragma pop_macro("__mips__") #pragma pop_macro("__aarch64__") #pragma pop_macro("__arm__") @@ -40,6 +58,7 @@ static int failures; static int hardware_opens; static int printk_disables; static int arm_chip_id_reads; +static int profile_reads; static char fixture_dir[] = "/tmp/novatek_test.XXXXXX"; /* The test link wraps these functions. Catch even an attempted device open, @@ -70,8 +89,10 @@ static bool fixture_line_from_file(const char *path, const char *re, } else if (!strcmp(path, "/proc/device-tree/model")) name = "model"; - else if (!strcmp(path, "/etc/profile_prjcfg")) + else if (!strcmp(path, "/etc/profile_prjcfg")) { + profile_reads++; name = "profile"; + } else if (!strcmp(path, "/proc/cpuinfo")) name = "cpuinfo"; else if (!strcmp(path, "/proc/iomem")) @@ -124,6 +145,7 @@ static void expect_name(const char *id, const char *model, CHECK((possible_i2c_addrs == NULL) == legacy); } +#if !defined(NOVATEK_TEST_ARM) && !defined(NOVATEK_TEST_AARCH64) static void mips_dispatch(void) { fixture("chip_id", NULL); fixture("model", "Novatek NA51023 evaluation board"); @@ -185,6 +207,7 @@ static void mips_reject_unsupported(const char *id, const char *model) { CHECK(open_i2c_sensor_fd != novatek_open_i2c_fd); CHECK(arm_chip_id_reads == 0); } +#endif int main(void) { if (!mkdtemp(fixture_dir)) { @@ -193,6 +216,24 @@ int main(void) { } const char *model = "Novatek NA51023 evaluation board"; const char *profile = "export PLATFORM=\"Linux\"\nexport CHIP=\"98513\"\n"; +#if defined(NOVATEK_TEST_ARM) || defined(NOVATEK_TEST_AARCH64) + /* An ARM build must not refine the MIPS-only model from its profile or + * install the MIPS rejecting HAL. Keep the existing ARM ID/model route. */ + profile_reads = 0; + expect_name(NULL, model, profile, "NA51023", false); + CHECK(chip_generation != CHIP_NA51023); + expect_name(NULL, "Novatek NA51023", profile, "NA51023", false); + /* These generic ARM substring matches are inherited behavior. Strict + * complete-token rejection is a guarantee of the new MIPS route only. */ + expect_name(NULL, "Novatek NA51023A evaluation board", profile, "NA51023", false); + expect_name(NULL, "OtherNovatek NA51023 evaluation board", profile, "NA51023", false); + expect_name(NULL, "Novatek NA51055 evaluation board", profile, "NA51055", false); + expect_name("7021\n", NULL, profile, "NT98566", false); + expect_name("5021\n", NULL, NULL, "NT98528", false); + expect_name("8B20\n", NULL, NULL, "NT98332G", false); + expect_name("4821\n", NULL, NULL, "NA51055", false); + CHECK(profile_reads == 0); +#else expect_name(NULL, model, profile, "NT98513", true); expect_name(NULL, model, NULL, "NA51023", true); expect_name(NULL, model, "export CHIP=\"98515\"\n", "NA51023", true); @@ -221,6 +262,7 @@ int main(void) { mips_reject_unsupported(NULL, "Novatek NA51055 evaluation board"); mips_reject_unsupported("7021\n", NULL); mips_reject_unsupported("7021\n", "Novatek NA51055 evaluation board"); +#endif fixture("chip_id", NULL); fixture("model", NULL); fixture("profile", NULL); From a4526cc0c7531be9b21df4cd4928ca0108581a9b Mon Sep 17 00:00:00 2001 From: AI Dev Date: Tue, 13 Oct 2026 18:48:01 +0000 Subject: [PATCH 4/4] novatek: keep MIPS NA51023 identification out of libipchw The previous commit gates the NA51023 code on __mips__, which keeps it out of arm32 and arm64, but libipchw on MIPS still carries it: a MIPS ipcinfo with IPCHW_VENDORS=all grew by 88 bytes. No camera that ships ipcinfo is a MIPS Novatek, so the library must not pay for one. Every MIPS gate now also requires !STANDALONE_LIBRARY, including the detection row in chipid.c, so ipctool identifies the part and libipchw never compiles it. The novatek tests are built without STANDALONE_LIBRARY, as ipctool is, so they still exercise that code. ipcinfo is byte-identical to master on arm32, mips32 and arm64 with IPCHW_VENDORS=all and none. --- CMakeLists.txt | 5 +++-- src/chipid.c | 4 ++-- src/hal/novatek.c | 15 ++++++++++----- src/hal/novatek.h | 6 +++++- 4 files changed, 20 insertions(+), 10 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 5f9d731e..3a1169aa 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -506,13 +506,14 @@ if(NOT ONLY_LIBRARY) target_link_libraries(anyka_test m Threads::Threads) # Includes novatek.c so only its hardware file paths are redirected. + # Not STANDALONE_LIBRARY: the NA51023 code is ipctool-only, so the test + # is built the way ipctool is. foreach(_nvt_test novatek_test novatek_arm_test novatek_aarch64_test) add_executable(${_nvt_test} src/hal/novatek_test.c src/hal/common.c src/sensors.c src/tools.c src/cjson/cJSON.c ${VERSION_OBJ}) target_include_directories(${_nvt_test} PRIVATE include src) - target_compile_definitions(${_nvt_test} PRIVATE IPCHW_VENDOR_NOVATEK - STANDALONE_LIBRARY) + target_compile_definitions(${_nvt_test} PRIVATE IPCHW_VENDOR_NOVATEK) target_link_libraries(${_nvt_test} m Threads::Threads "-Wl,--wrap=open" "-Wl,--wrap=disable_printk") endforeach() diff --git a/src/chipid.c b/src/chipid.c index 94c43e27..3dc8e828 100644 --- a/src/chipid.c +++ b/src/chipid.c @@ -55,7 +55,7 @@ static const manufacturers_t manufacturers[] = { {"isvp", ingenic_detect_cpu, VENDOR_INGENIC, setup_hal_ingenic}, {"ingenic", ingenic_detect_cpu, VENDOR_INGENIC, setup_hal_ingenic}, #endif -#ifdef IPCHW_VENDOR_NOVATEK +#if defined(IPCHW_VENDOR_NOVATEK) && !defined(STANDALONE_LIBRARY) {NULL, novatek_detect_mips_cpu, VENDOR_NOVATEK, novatek_setup_hal}, #endif #endif @@ -241,7 +241,7 @@ const char *getchipname() { const char *getchipfamily() { const char *chip_name = getchipname(); switch (chip_generation) { -#if defined(IPCHW_VENDOR_NOVATEK) && \ +#if defined(IPCHW_VENDOR_NOVATEK) && !defined(STANDALONE_LIBRARY) && \ (defined(mips) || defined(__mips__) || defined(__mips)) case CHIP_NA51023: return "nt9851x"; diff --git a/src/hal/novatek.c b/src/hal/novatek.c index 7442a1dc..81e98ee9 100644 --- a/src/hal/novatek.c +++ b/src/hal/novatek.c @@ -59,7 +59,8 @@ static bool nvt_get_chip_id() { return true; } -#if defined(mips) || defined(__mips__) || defined(__mips) +#if (defined(mips) || defined(__mips__) || defined(__mips)) && \ + !defined(STANDALONE_LIBRARY) static void nvt_refine_na51023(char *chip_name) { char buf[16]; @@ -95,7 +96,8 @@ bool novatek_detect_cpu(char *chip_name) { return true; if (!line_from_file("/proc/device-tree/model", -#if defined(mips) || defined(__mips__) || defined(__mips) +#if (defined(mips) || defined(__mips__) || defined(__mips)) && \ + !defined(STANDALONE_LIBRARY) "^Novatek ([A-Z]+[0-9]+)([[:space:]]|$)", #else /* Keep the existing ARM/AArch64 parser unchanged. @@ -112,7 +114,8 @@ bool novatek_detect_cpu(char *chip_name) { strcpy(chip_name, buf); -#if defined(mips) || defined(__mips__) || defined(__mips) +#if (defined(mips) || defined(__mips__) || defined(__mips)) && \ + !defined(STANDALONE_LIBRARY) if (!strcmp(buf, "NA51023")) nvt_refine_na51023(chip_name); #endif @@ -159,7 +162,8 @@ static int novatek_open_i2c_fd(int i2c_adapter_nr) { return universal_open_sensor_fd(adapter_name); } -#if defined(mips) || defined(__mips__) || defined(__mips) +#if (defined(mips) || defined(__mips__) || defined(__mips)) && \ + !defined(STANDALONE_LIBRARY) static int novatek_no_sensor_bus(int adapter_nr) { (void)adapter_nr; return -1; @@ -167,7 +171,8 @@ static int novatek_no_sensor_bus(int adapter_nr) { #endif void novatek_setup_hal() { -#if defined(mips) || defined(__mips__) || defined(__mips) +#if (defined(mips) || defined(__mips__) || defined(__mips)) && \ + !defined(STANDALONE_LIBRARY) /* This MIPS generation delegates media to uITRON. The ARM HDAL memory * report, sensor I2C bus and register tables below are not its ABI. */ if (chip_generation == CHIP_NA51023) { diff --git a/src/hal/novatek.h b/src/hal/novatek.h index de27afd6..2e6a7969 100644 --- a/src/hal/novatek.h +++ b/src/hal/novatek.h @@ -4,7 +4,11 @@ #include bool novatek_detect_cpu(char *chip_name); -#if defined(mips) || defined(__mips__) || defined(__mips) +/* NA51023 (MIPS, sold as NT98513) is identified by ipctool alone. No camera + * that carries libipchw is one, so the library must not pay for it: ipcinfo + * ships on boards whose rootfs leaves tens of KB spare. */ +#if (defined(mips) || defined(__mips__) || defined(__mips)) && \ + !defined(STANDALONE_LIBRARY) bool novatek_detect_mips_cpu(char *chip_name); #endif unsigned long novatek_totalmem(unsigned long *media_mem);