diff options
Diffstat (limited to 'test/dm')
| -rw-r--r-- | test/dm/Makefile | 1 | ||||
| -rw-r--r-- | test/dm/acpi.c | 2 | ||||
| -rw-r--r-- | test/dm/pmbus.c | 242 | ||||
| -rw-r--r-- | test/dm/regulator.c | 38 | ||||
| -rw-r--r-- | test/dm/reset.c | 107 | ||||
| -rw-r--r-- | test/dm/sysinfo.c | 16 |
6 files changed, 405 insertions, 1 deletions
diff --git a/test/dm/Makefile b/test/dm/Makefile index 0e3c63568dd..76aa1fff9ba 100644 --- a/test/dm/Makefile +++ b/test/dm/Makefile @@ -95,6 +95,7 @@ obj-$(CONFIG_PINCONF) += pinmux.o endif obj-$(CONFIG_POWER_DOMAIN) += power-domain.o obj-$(CONFIG_ACPI_PMC) += pmc.o +obj-$(CONFIG_CMD_PMBUS) += pmbus.o obj-$(CONFIG_DM_PMIC) += pmic.o obj-$(CONFIG_DM_PWM) += pwm.o obj-$(CONFIG_ARM_FFA_TRANSPORT) += ffa.o diff --git a/test/dm/acpi.c b/test/dm/acpi.c index 2de7983f9ae..293ea0274b5 100644 --- a/test/dm/acpi.c +++ b/test/dm/acpi.c @@ -136,7 +136,7 @@ static int testacpi_inject_dsdt(const struct udevice *dev, struct acpi_ctx *ctx) return 0; } -struct acpi_ops testacpi_ops = { +static const struct acpi_ops testacpi_ops = { .get_name = testacpi_get_name, .write_tables = testacpi_write_tables, .fill_madt = testacpi_fill_madt, diff --git a/test/dm/pmbus.c b/test/dm/pmbus.c new file mode 100644 index 00000000000..0184b201829 --- /dev/null +++ b/test/dm/pmbus.c @@ -0,0 +1,242 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright 2026 Free Mobile - Vincent Jardin + * + * Unit tests for the PMBus 1.x framework, the generic + * PMBus regulator and the pmbus CLI command. + */ + +#include <dm.h> +#include <i2c.h> +#include <pmbus.h> +#include <dm/test.h> +#include <test/test.h> +#include <test/ut.h> + +/* The line pmbus dev prints when a chip is selected */ +#define PMBUS_ACTIVE_LINE \ + "pmbus: active i2c0:0x70 rail=\"sandbox-pmbus-vout\" " \ + "MFR_ID=\"SANDBOX\" MODEL=\"PMBUS-EMUL\" vendor=(generic)" + +/* The line pmbus list prints for the bound chip */ +#define PMBUS_LIST_LINE \ + " i2c0:0x70 rail=\"sandbox-pmbus-vout\" node=pmbus@70 " \ + "driver=pmbus_generic_regulator" + +/* Select the emulated chip and check the resulting banner line */ +static int pmbus_select(struct unit_test_state *uts) +{ + ut_assertok(run_command("pmbus dev 0:70", 0)); + ut_assert_nextline(PMBUS_ACTIVE_LINE); + return 0; +} + +/* The chip is reachable via UCLASS_REGULATOR (compatible = "pmbus") */ +static int dm_test_pmbus_bind(struct unit_test_state *uts) +{ + struct udevice *dev; + + ut_assertok(uclass_get_device_by_name(UCLASS_REGULATOR, "pmbus@70", + &dev)); + ut_asserteq_str("pmbus_generic_regulator", dev->driver->name); + ut_asserteq(UCLASS_I2C, device_get_uclass_id(dev_get_parent(dev))); + + return 0; +} + +DM_TEST(dm_test_pmbus_bind, UTF_SCAN_FDT); + +/* pmbus dev by <bus>:<addr> and by regulator-name select the chip */ +static int dm_test_pmbus_dev(struct unit_test_state *uts) +{ + ut_assertok(run_command("pmbus dev 0:70", 0)); + ut_assert_nextline(PMBUS_ACTIVE_LINE); + ut_assert_console_end(); + + /* Selecting by DT regulator-name resolves to the same chip */ + ut_assertok(run_command("pmbus dev sandbox-pmbus-vout", 0)); + ut_assert_nextline(PMBUS_ACTIVE_LINE); + ut_assert_console_end(); + + /* pmbus dev with no argument reprints the active chip */ + ut_assertok(run_command("pmbus dev", 0)); + ut_assert_nextline(PMBUS_ACTIVE_LINE); + ut_assert_console_end(); + + return 0; +} + +DM_TEST(dm_test_pmbus_dev, UTF_SCAN_FDT | UTF_CONSOLE); + +/* pmbus list enumerates the bound chip among the UCLASS_REGULATOR devices */ +static int dm_test_pmbus_list(struct unit_test_state *uts) +{ + ut_assertok(run_command("pmbus list", 0)); + ut_assert_skip_to_line(PMBUS_LIST_LINE); + + return 0; +} + +DM_TEST(dm_test_pmbus_list, UTF_SCAN_FDT | UTF_CONSOLE); + +/* pmbus info decodes identification + the detected driver_info */ +static int dm_test_pmbus_info(struct unit_test_state *uts) +{ + ut_assertok(pmbus_select(uts)); + + ut_assertok(run_command("pmbus info", 0)); + ut_assert_nextline("pmbus device i2c0:0x70"); + ut_assert_nextline(" regulator-name: \"sandbox-pmbus-vout\""); + ut_assert_nextline(" MFR_ID : \"SANDBOX\""); + ut_assert_nextline(" MFR_MODEL : \"PMBUS-EMUL\""); + ut_assert_nextline(" MFR_REVISION : \"1.0\" raw=0x312e30"); + ut_assert_nextline(" PMBUS_REVISION: 0x33 (PMBus 1.3)"); + ut_assert_nextline(" vendor : (none)"); + ut_assert_nextline(" driver_info : pages=1"); + ut_assert_nextline(" [VOLTAGE_IN ] format=LINEAR"); + ut_assert_nextline(" [VOLTAGE_OUT ] format=LINEAR"); + ut_assert_nextline(" [CURRENT_IN ] format=LINEAR"); + ut_assert_nextline(" [CURRENT_OUT ] format=LINEAR"); + ut_assert_nextline(" [POWER ] format=LINEAR"); + ut_assert_nextline(" [TEMPERATURE ] format=LINEAR"); + ut_assert_console_end(); + + return 0; +} + +DM_TEST(dm_test_pmbus_info, UTF_SCAN_FDT | UTF_CONSOLE); + +/* + * pmbus telemetry decodes the implemented sensors and prints + * "(not supported)" for the commands the emulator NAKs (READ_IIN, + * READ_POUT). LINEAR11 is used for VIN/IOUT/TEMP, LINEAR16 (with the + * VOUT_MODE 2^-8 exponent) for VOUT. + */ +static int dm_test_pmbus_telemetry(struct unit_test_state *uts) +{ + ut_assertok(pmbus_select(uts)); + + ut_assertok(run_command("pmbus telemetry", 0)); + ut_assert_nextline("pmbus telemetry @ i2c0:0x70"); + ut_assert_nextline(" VIN : raw=0x0abc 1400.000V"); + ut_assert_nextline(" VOUT : raw=0x0200 2.000V"); + ut_assert_nextline(" IIN : (not supported)"); + ut_assert_nextline(" IOUT : raw=0x0123 291.000A"); + ut_assert_nextline(" POUT : (not supported)"); + ut_assert_nextline(" TEMP : raw=0x0019 25.000C"); + ut_assert_console_end(); + + return 0; +} + +DM_TEST(dm_test_pmbus_telemetry, UTF_SCAN_FDT | UTF_CONSOLE); + +/* pmbus status decodes every STATUS_* register; the emulator is clean */ +static int dm_test_pmbus_status(struct unit_test_state *uts) +{ + ut_assertok(pmbus_select(uts)); + + ut_assertok(run_command("pmbus status", 0)); + ut_assert_nextline("pmbus status @ i2c0:0x70"); + ut_assert_nextline(" STATUS_WORD (79h) = 0x0000 [clean]"); + ut_assert_nextline(" STATUS_VOUT (7Ah) = 0x00 [clean]"); + ut_assert_nextline(" STATUS_IOUT (7Bh) = 0x00 [clean]"); + ut_assert_nextline(" STATUS_INPUT (7Ch) = 0x00 [clean]"); + ut_assert_nextline(" STATUS_TEMP (7Dh) = 0x00 [clean]"); + ut_assert_nextline(" STATUS_CML (7Eh) = 0x00 [clean]"); + ut_assert_console_end(); + + return 0; +} + +DM_TEST(dm_test_pmbus_status, UTF_SCAN_FDT | UTF_CONSOLE); + +/* pmbus read/pmbus write raw register access (byte, word, string) */ +static int dm_test_pmbus_read_write(struct unit_test_state *uts) +{ + ut_assertok(pmbus_select(uts)); + + /* Symbolic and numeric register names both resolve */ + ut_assertok(run_command("pmbus read VOUT_MODE", 0)); + ut_assert_nextline(" 20h VOUT_MODE b=0x18"); + ut_assertok(run_command("pmbus read 8b w", 0)); + ut_assert_nextline(" 8bh READ_VOUT w=0x0200"); + ut_assertok(run_command("pmbus read MFR_ID s", 0)); + ut_assert_nextline(" 99h MFR_ID s=\"SANDBOX\""); + + /* A word write is observable on the next read-back */ + ut_assertok(run_command("pmbus write VOUT_COMMAND 123 w", 0)); + ut_assert_nextline("pmbus: wrote 0x123 to 21h (VOUT_COMMAND)"); + ut_assertok(run_command("pmbus read VOUT_COMMAND w", 0)); + ut_assert_nextline(" 21h VOUT_COMMAND w=0x0123"); + ut_assert_console_end(); + + return 0; +} + +DM_TEST(dm_test_pmbus_read_write, UTF_SCAN_FDT | UTF_CONSOLE); + +/* pmbus vout reads back VOUT via the active driver_info decoder */ +static int dm_test_pmbus_vout(struct unit_test_state *uts) +{ + ut_assertok(pmbus_select(uts)); + + ut_assertok(run_command("pmbus vout", 0)); + ut_assert_nextline("pmbus VOUT @ i2c0:0x70 raw=0x0200 2.000V"); + ut_assert_console_end(); + + return 0; +} + +DM_TEST(dm_test_pmbus_vout, UTF_SCAN_FDT | UTF_CONSOLE); + +/* pmbus dump walks every standard register; spot-check one line */ +static int dm_test_pmbus_dump(struct unit_test_state *uts) +{ + ut_assertok(pmbus_select(uts)); + + ut_assertok(run_command("pmbus dump", 0)); + ut_assert_nextline("pmbus dump @ i2c0:0x70 (registers known to <pmbus.h>)"); + ut_assert_skip_to_line(" 20h VOUT_MODE b=0x18"); + + return 0; +} + +DM_TEST(dm_test_pmbus_dump, UTF_SCAN_FDT | UTF_CONSOLE); + +/* pmbus clear [faults] issues CLEAR_FAULTS (03h) */ +static int dm_test_pmbus_clear(struct unit_test_state *uts) +{ + ut_assertok(pmbus_select(uts)); + + ut_assertok(run_command("pmbus clear faults", 0)); + ut_assert_nextline("pmbus: CLEAR_FAULTS (03h) issued (RAM sticky STATUS_* cleared)"); + ut_assert_console_end(); + + return 0; +} + +DM_TEST(dm_test_pmbus_clear, UTF_SCAN_FDT | UTF_CONSOLE); + +/* pmbus scan finds the emulated chip by its MFR_ID block read */ +static int dm_test_pmbus_scan(struct unit_test_state *uts) +{ + ut_assertok(run_command("pmbus scan 0", 0)); + ut_assert_skip_to_line(" i2c0:0x70 MFR_ID=\"SANDBOX\""); + + return 0; +} + +DM_TEST(dm_test_pmbus_scan, UTF_SCAN_FDT | UTF_CONSOLE); + +/* pmbus help lists vendor extensions; none are registered here */ +static int dm_test_pmbus_help(struct unit_test_state *uts) +{ + ut_assertok(run_command("pmbus help", 0)); + ut_assert_nextline("pmbus: no vendor extensions registered."); + ut_assert_skip_to_line(" board hook (boot snapshot) and re run 'pmbus help'."); + + return 0; +} + +DM_TEST(dm_test_pmbus_help, UTF_SCAN_FDT | UTF_CONSOLE); diff --git a/test/dm/regulator.c b/test/dm/regulator.c index 449748ad52f..51007d4079d 100644 --- a/test/dm/regulator.c +++ b/test/dm/regulator.c @@ -28,6 +28,7 @@ enum { BUCK3, LDO1, LDO2, + LDO3, OUTPUT_COUNT, }; @@ -44,6 +45,7 @@ static const char *regulator_names[OUTPUT_COUNT][OUTPUT_NAME_COUNT] = { { SANDBOX_BUCK3_DEVNAME, SANDBOX_BUCK3_PLATNAME }, { SANDBOX_LDO1_DEVNAME, SANDBOX_LDO1_PLATNAME}, { SANDBOX_LDO2_DEVNAME, SANDBOX_LDO2_PLATNAME}, + { SANDBOX_LDO3_DEVNAME, SANDBOX_LDO3_PLATNAME}, }; /* Test regulator get method */ @@ -118,6 +120,42 @@ static int dm_test_power_regulator_set_get_voltage(struct unit_test_state *uts) } DM_TEST(dm_test_power_regulator_set_get_voltage, UTF_SCAN_FDT); +/* Test regulator set Voltage clamp method */ +static int dm_test_power_regulator_set_value_clamp(struct unit_test_state *uts) +{ + struct udevice *dev; + const char *platname; + + /* LDO3 have 'min' 1.8V and 'max' 3.3V */ + platname = regulator_names[LDO3][PLATNAME]; + ut_assertok(regulator_get_by_platname(platname, &dev)); + + /* 'target' in 'min'/'max' range - should not clamp voltage */ + ut_assertok(regulator_set_value_clamp(dev, 1700000, 1800000, 1950000)); + ut_asserteq(1800000, regulator_get_value(dev)); + ut_assertok(regulator_set_value_clamp(dev, 2700000, 3300000, 3600000)); + ut_asserteq(3300000, regulator_get_value(dev)); + + /* 'target' out of 'min'/'max' range - should clamp voltage */ + ut_assertok(regulator_set_value_clamp(dev, 1700000, 1700000, 1950000)); + ut_asserteq(1800000, regulator_get_value(dev)); + ut_assertok(regulator_set_value_clamp(dev, 2700000, 3400000, 3600000)); + ut_asserteq(3300000, regulator_get_value(dev)); + + /* 'min'/'max' out of range - should return -EINVAL */ + ut_asserteq(-EINVAL, + regulator_set_value_clamp(dev, 1200000, 1500000, 1700000)); + ut_asserteq(-EINVAL, + regulator_set_value_clamp(dev, 3500000, 4000000, 5000000)); + + /* 'min' higher than 'max' - should return -EINVAL */ + ut_asserteq(-EINVAL, + regulator_set_value_clamp(dev, 3100000, 3000000, 2900000)); + + return 0; +} +DM_TEST(dm_test_power_regulator_set_value_clamp, UTF_SCAN_FDT); + /* Test regulator set and get Current method */ static int dm_test_power_regulator_set_get_current(struct unit_test_state *uts) { diff --git a/test/dm/reset.c b/test/dm/reset.c index dceb6a1dad3..91fa7ff723b 100644 --- a/test/dm/reset.c +++ b/test/dm/reset.c @@ -19,6 +19,9 @@ /* This is the other reset phandle specifier handled by bulk */ #define OTHER_RESET_ID 2 +/* Line on reset-ctl-fallback (sandbox,reset-ctl-fallback-only); see test.dts */ +#define FALLBACK_RESET_ID 5 + /* Base test of the reset uclass */ static int dm_test_reset_base(struct unit_test_state *uts) { @@ -120,6 +123,110 @@ static int dm_test_reset_devm(struct unit_test_state *uts) } DM_TEST(dm_test_reset_devm, UTF_SCAN_FDT); +static int dm_test_reset_reset(struct unit_test_state *uts) +{ + struct udevice *dev_reset; + struct udevice *dev_test; + + ut_assertok(uclass_get_device_by_name(UCLASS_RESET, "reset-ctl", + &dev_reset)); + ut_asserteq(0, sandbox_reset_query(dev_reset, TEST_RESET_ID)); + + ut_assertok(uclass_get_device_by_name(UCLASS_MISC, "reset-ctl-test", + &dev_test)); + ut_assertok(sandbox_reset_test_get(dev_test)); + + /* Verify reset_count starts at 0 */ + ut_asserteq(0, sandbox_reset_get_count(dev_reset, TEST_RESET_ID)); + + ut_assertok(sandbox_reset_test_assert(dev_test)); + ut_asserteq(1, sandbox_reset_query(dev_reset, TEST_RESET_ID)); + + ut_assertok(sandbox_reset_test_reset(dev_test)); + + /* Verify reset was pulsed (count incremented) */ + ut_asserteq(1, sandbox_reset_get_count(dev_reset, TEST_RESET_ID)); + ut_asserteq(0, sandbox_reset_query(dev_reset, TEST_RESET_ID)); + + ut_assertok(sandbox_reset_test_free(dev_test)); + + return 0; +} +DM_TEST(dm_test_reset_reset, UTF_SCAN_FDT); + +/* + * reset_reset() fallback path: controller has no rst_reset op, so the + * core does assert -> udelay -> deassert. rst_reset-only accounting + * (reset_count) stays zero. Leave the line asserted before reset_reset() + * so we verify the fallback actually pulses it back to deasserted. + */ +static int dm_test_reset_reset_fallback_path(struct unit_test_state *uts) +{ + struct udevice *dev_reset_fb; + struct udevice *dev_test; + struct reset_ctl ctl; + + ut_assertok(uclass_get_device_by_name(UCLASS_RESET, "reset-ctl-fallback", + &dev_reset_fb)); + ut_asserteq(0, sandbox_reset_query(dev_reset_fb, FALLBACK_RESET_ID)); + ut_asserteq(0, sandbox_reset_get_count(dev_reset_fb, FALLBACK_RESET_ID)); + + ut_assertok(uclass_get_device_by_name(UCLASS_MISC, "reset-ctl-test", + &dev_test)); + ut_assertok(reset_get_by_name(dev_test, "fallback", &ctl)); + ut_asserteq_ptr(ctl.dev, dev_reset_fb); + ut_asserteq(FALLBACK_RESET_ID, ctl.id); + + ut_assertok(reset_assert(&ctl)); + ut_asserteq(1, sandbox_reset_query(dev_reset_fb, FALLBACK_RESET_ID)); + ut_asserteq(0, sandbox_reset_get_count(dev_reset_fb, FALLBACK_RESET_ID)); + + ut_assertok(reset_reset(&ctl, 1)); + ut_asserteq(0, sandbox_reset_get_count(dev_reset_fb, FALLBACK_RESET_ID)); + ut_asserteq(0, sandbox_reset_query(dev_reset_fb, FALLBACK_RESET_ID)); + + ut_assertok(reset_free(&ctl)); + + return 0; +} +DM_TEST(dm_test_reset_reset_fallback_path, UTF_SCAN_FDT); + +static int dm_test_reset_reset_bulk(struct unit_test_state *uts) +{ + struct udevice *dev_reset; + struct udevice *dev_test; + + ut_assertok(uclass_get_device_by_name(UCLASS_RESET, "reset-ctl", + &dev_reset)); + ut_asserteq(0, sandbox_reset_query(dev_reset, TEST_RESET_ID)); + ut_asserteq(0, sandbox_reset_query(dev_reset, OTHER_RESET_ID)); + + ut_assertok(uclass_get_device_by_name(UCLASS_MISC, "reset-ctl-test", + &dev_test)); + ut_assertok(sandbox_reset_test_get_bulk(dev_test)); + + /* Verify reset_count starts at 0 */ + ut_asserteq(0, sandbox_reset_get_count(dev_reset, TEST_RESET_ID)); + ut_asserteq(0, sandbox_reset_get_count(dev_reset, OTHER_RESET_ID)); + + ut_assertok(sandbox_reset_test_assert_bulk(dev_test)); + ut_asserteq(1, sandbox_reset_query(dev_reset, TEST_RESET_ID)); + ut_asserteq(1, sandbox_reset_query(dev_reset, OTHER_RESET_ID)); + + ut_assertok(sandbox_reset_test_reset_bulk(dev_test)); + + /* Verify resets were pulsed (counts incremented) */ + ut_asserteq(1, sandbox_reset_get_count(dev_reset, TEST_RESET_ID)); + ut_asserteq(1, sandbox_reset_get_count(dev_reset, OTHER_RESET_ID)); + ut_asserteq(0, sandbox_reset_query(dev_reset, TEST_RESET_ID)); + ut_asserteq(0, sandbox_reset_query(dev_reset, OTHER_RESET_ID)); + + ut_assertok(sandbox_reset_test_release_bulk(dev_test)); + + return 0; +} +DM_TEST(dm_test_reset_reset_bulk, UTF_SCAN_FDT); + static int dm_test_reset_bulk(struct unit_test_state *uts) { struct udevice *dev_reset; diff --git a/test/dm/sysinfo.c b/test/dm/sysinfo.c index 14ebe6b42e7..611f2e98d14 100644 --- a/test/dm/sysinfo.c +++ b/test/dm/sysinfo.c @@ -66,3 +66,19 @@ static int dm_test_sysinfo(struct unit_test_state *uts) return 0; } DM_TEST(dm_test_sysinfo, UTF_SCAN_PDATA | UTF_SCAN_FDT); + +static int dm_test_sysinfo_get_and_detect(struct unit_test_state *uts) +{ + struct udevice *sysinfo; + bool called_detect = false; + + ut_assertok(sysinfo_get_and_detect(&sysinfo)); + ut_assert(sysinfo); + + ut_assertok(sysinfo_get_bool(sysinfo, BOOL_CALLED_DETECT, + &called_detect)); + ut_assert(called_detect); + + return 0; +} +DM_TEST(dm_test_sysinfo_get_and_detect, UTF_SCAN_PDATA | UTF_SCAN_FDT); |
