diff options
author | Jan Dabros <jsd@semihalf.com> | 2020-04-20 14:34:16 +0200 |
---|---|---|
committer | Patrick Georgi <pgeorgi@google.com> | 2020-05-01 06:33:49 +0000 |
commit | a67cc5f5e8d11cd1004faf112193cf368af25f4b (patch) | |
tree | 336ea8b2cf541125b3ea0b8f8eac794fbaab5504 /tests | |
parent | 2d0ee36913a5e0f6c74beb5cdb9f25ea36ea9290 (diff) |
tests: Add device/i2c-test test case
Add unit test for src/device/i2c.c module.
This patch is also used as an example for incorporating Cmocka mocking
feature (-wrap linker flag).
Signed-off-by: Jan Dabros <jsd@semihalf.com>
Change-Id: I2eeb565aacc724ae3b9f5c76ef4b98ef695416d6
Reviewed-on: https://review.coreboot.org/c/coreboot/+/40539
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Julius Werner <jwerner@chromium.org>
Reviewed-by: Paul Fagerburg <pfagerburg@chromium.org>
Diffstat (limited to 'tests')
-rw-r--r-- | tests/device/Makefile.inc | 18 | ||||
-rw-r--r-- | tests/device/i2c-test.c | 183 |
2 files changed, 201 insertions, 0 deletions
diff --git a/tests/device/Makefile.inc b/tests/device/Makefile.inc new file mode 100644 index 0000000000..f23e72fa32 --- /dev/null +++ b/tests/device/Makefile.inc @@ -0,0 +1,18 @@ +## +## This file is part of the coreboot project. +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by +## the Free Software Foundation; version 2 of the License. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## + +tests-y += i2c-test + +i2c-test-srcs += tests/device/i2c-test.c +i2c-test-srcs += src/device/i2c.c +i2c-test-mocks += platform_i2c_transfer diff --git a/tests/device/i2c-test.c b/tests/device/i2c-test.c new file mode 100644 index 0000000000..16e4d0d1ed --- /dev/null +++ b/tests/device/i2c-test.c @@ -0,0 +1,183 @@ +/* + * This file is part of the coreboot project. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <stdarg.h> +#include <stddef.h> +#include <setjmp.h> +#include <limits.h> +#include <cmocka.h> + +#include <device/i2c_simple.h> + +/* Simulate two i2c devices, both on bus 0, each with three uint8_t regs + implemented. */ +typedef struct { + uint8_t reg; + uint8_t data; +} i2c_ex_regs_t; + +typedef struct { + unsigned int bus; + uint8_t slave; + i2c_ex_regs_t regs[3]; +} i2c_ex_devs_t; + +i2c_ex_devs_t i2c_ex_devs[] = { + {.bus = 0, .slave = 0xA, .regs = { + {.reg = 0x0, .data = 0xB}, + {.reg = 0x1, .data = 0x6}, + {.reg = 0x2, .data = 0xF}, + } }, + {.bus = 0, .slave = 0x3, .regs = { + {.reg = 0x0, .data = 0xDE}, + {.reg = 0x1, .data = 0xAD}, + {.reg = 0x2, .data = 0xBE}, + } }, +}; + +int __wrap_platform_i2c_transfer(unsigned int bus, struct i2c_msg *segments, + int count) +{ + int i; + int reg; + struct i2c_msg *tmp = segments; + i2c_ex_devs_t *i2c_dev = NULL; + + check_expected(count); + + for (i = 0; i < count; i++, segments++) { + check_expected_ptr(segments->buf); + check_expected(segments->flags); + } + + reg = tmp->buf[0]; + + /* Find object for requested device */ + for (i = 0; i < ARRAY_SIZE(i2c_ex_devs); i++, i2c_dev++) + if (i2c_ex_devs[i].slave == tmp->slave) { + i2c_dev = &i2c_ex_devs[i]; + break; + } + + if (i2c_dev == NULL) + return -1; + + /* Write commands */ + if (tmp->len > 1) { + i2c_dev->regs[reg].data = tmp->buf[1]; + }; + + /* Read commands */ + for (i = 0; i < count; i++, tmp++) + if (tmp->flags & I2C_M_RD) { + *(tmp->buf) = i2c_dev->regs[reg].data; + }; +} + +static void mock_expect_params_platform_i2c_transfer(void) +{ + unsigned long int expected_flags[] = {0, I2C_M_RD, I2C_M_TEN, + I2C_M_RECV_LEN, I2C_M_NOSTART}; + + /* Flags should always be only within supported range */ + expect_in_set_count(__wrap_platform_i2c_transfer, segments->flags, + expected_flags, -1); + + expect_not_value_count(__wrap_platform_i2c_transfer, segments->buf, + NULL, -1); + + expect_in_range_count(__wrap_platform_i2c_transfer, count, 1, INT_MAX, + -1); +} + +#define MASK 0x3 +#define SHIFT 0x1 + +static void i2c_read_field_test(void **state) +{ + int bus, slave, reg; + int i, j; + uint8_t buf; + + mock_expect_params_platform_i2c_transfer(); + + /* Read particular bits in all registers in all devices, then compare + with expected value. */ + for (i = 0; i < ARRAY_SIZE(i2c_ex_devs); i++) + for (j = 0; j < ARRAY_SIZE(i2c_ex_devs[0].regs); j++) { + i2c_read_field(i2c_ex_devs[i].bus, + i2c_ex_devs[i].slave, + i2c_ex_devs[i].regs[j].reg, + &buf, MASK, SHIFT); + assert_int_equal((i2c_ex_devs[i].regs[j].data & + (MASK << SHIFT)) >> SHIFT, buf); + }; + + /* Read whole registers */ + for (i = 0; i < ARRAY_SIZE(i2c_ex_devs); i++) + for (j = 0; j < ARRAY_SIZE(i2c_ex_devs[0].regs); j++) { + i2c_read_field(i2c_ex_devs[i].bus, + i2c_ex_devs[i].slave, + i2c_ex_devs[i].regs[j].reg, + &buf, 0xFF, 0); + assert_int_equal(i2c_ex_devs[i].regs[j].data, buf); + }; +} + +static void i2c_write_field_test(void **state) +{ + int bus, slave, reg; + int i, j; + uint8_t buf, tmp; + + mock_expect_params_platform_i2c_transfer(); + + /* Clear particular bits in all registers in all devices, then compare + with expected value. */ + for (i = 0; i < ARRAY_SIZE(i2c_ex_devs); i++) + for (j = 0; j < ARRAY_SIZE(i2c_ex_devs[0].regs); j++) { + buf = 0x0; + tmp = i2c_ex_devs[i].regs[j].data; + i2c_write_field(i2c_ex_devs[i].bus, + i2c_ex_devs[i].slave, + i2c_ex_devs[i].regs[j].reg, + buf, MASK, SHIFT); + assert_int_equal(i2c_ex_devs[i].regs[j].data, + (tmp & ~(MASK << SHIFT)) | (buf << SHIFT)); + }; + + /* Set all bits in all registers, this time verify using + i2c_read_field() accessor. */ + for (i = 0; i < ARRAY_SIZE(i2c_ex_devs); i++) + for (j = 0; j < ARRAY_SIZE(i2c_ex_devs[0].regs); j++) { + i2c_write_field(i2c_ex_devs[i].bus, + i2c_ex_devs[i].slave, + i2c_ex_devs[i].regs[j].reg, + 0xFF, 0xFF, 0); + i2c_read_field(i2c_ex_devs[i].bus, + i2c_ex_devs[i].slave, + i2c_ex_devs[i].regs[j].reg, + &buf, 0xFF, 0); + assert_int_equal(buf, 0xFF); + }; +} + +int main(void) +{ + const struct CMUnitTest tests[] = { + cmocka_unit_test(i2c_read_field_test), + cmocka_unit_test(i2c_write_field_test) + }; + + return cmocka_run_group_tests(tests, NULL, NULL); +} |